diff options
Diffstat (limited to 'source/blender/editors/transform')
-rw-r--r-- | source/blender/editors/transform/CMakeLists.txt | 4 | ||||
-rw-r--r-- | source/blender/editors/transform/SConscript | 3 | ||||
-rw-r--r-- | source/blender/editors/transform/transform.c | 1460 | ||||
-rw-r--r-- | source/blender/editors/transform/transform.h | 28 | ||||
-rw-r--r-- | source/blender/editors/transform/transform_constraints.c | 58 | ||||
-rw-r--r-- | source/blender/editors/transform/transform_conversions.c | 971 | ||||
-rw-r--r-- | source/blender/editors/transform/transform_generics.c | 78 | ||||
-rw-r--r-- | source/blender/editors/transform/transform_manipulator.c | 17 | ||||
-rw-r--r-- | source/blender/editors/transform/transform_ops.c | 53 | ||||
-rw-r--r-- | source/blender/editors/transform/transform_snap.c | 151 |
10 files changed, 1807 insertions, 1016 deletions
diff --git a/source/blender/editors/transform/CMakeLists.txt b/source/blender/editors/transform/CMakeLists.txt index 0c360474b78..0bc38f81dd7 100644 --- a/source/blender/editors/transform/CMakeLists.txt +++ b/source/blender/editors/transform/CMakeLists.txt @@ -55,6 +55,10 @@ if(WITH_INTERNATIONAL) add_definitions(-DWITH_INTERNATIONAL) endif() +if(WITH_LEGACY_DEPSGRAPH) + add_definitions(-DWITH_LEGACY_DEPSGRAPH) +endif() + add_definitions(${GL_DEFINITIONS}) blender_add_lib(bf_editor_transform "${SRC}" "${INC}" "${INC_SYS}") diff --git a/source/blender/editors/transform/SConscript b/source/blender/editors/transform/SConscript index e249856b747..1a2e9ab074a 100644 --- a/source/blender/editors/transform/SConscript +++ b/source/blender/editors/transform/SConscript @@ -50,4 +50,7 @@ defs = env['BF_GL_DEFINITIONS'] if env['WITH_BF_INTERNATIONAL']: defs.append('WITH_INTERNATIONAL') +if env['WITH_BF_LEGACY_DEPSGRAPH']: + defs.append('WITH_LEGACY_DEPSGRAPH') + env.BlenderLib ( 'bf_editors_transform', sources, incs, defs, libtype=['core'], priority=[40] ) diff --git a/source/blender/editors/transform/transform.c b/source/blender/editors/transform/transform.c index 061d00424b8..68d77dec619 100644 --- a/source/blender/editors/transform/transform.c +++ b/source/blender/editors/transform/transform.c @@ -54,6 +54,7 @@ #include "BLI_memarena.h" #include "BKE_nla.h" +#include "BKE_editmesh.h" #include "BKE_editmesh_bvh.h" #include "BKE_context.h" #include "BKE_constraint.h" @@ -98,11 +99,13 @@ static void drawTransformApply(const struct bContext *C, ARegion *ar, void *arg) static void doEdgeSlide(TransInfo *t, float perc); static void doVertSlide(TransInfo *t, float perc); -static void drawEdgeSlide(const struct bContext *C, TransInfo *t); -static void drawVertSlide(const struct bContext *C, TransInfo *t); +static void drawEdgeSlide(TransInfo *t); +static void drawVertSlide(TransInfo *t); static void len_v3_ensure(float v[3], const float length); static void postInputRotation(TransInfo *t, float values[3]); +static void ElementRotation(TransInfo *t, TransData *td, float mat[3][3], short around); + /* Transform Callbacks */ static void initBend(TransInfo *t); @@ -164,6 +167,7 @@ static void applyBoneEnvelope(TransInfo *t, const int mval[2]); static void initBoneRoll(TransInfo *t); static void applyBoneRoll(TransInfo *t, const int mval[2]); +static void initEdgeSlide_ex(TransInfo *t, bool use_double_side); static void initEdgeSlide(TransInfo *t); static eRedrawFlag handleEventEdgeSlide(TransInfo *t, const struct wmEvent *event); static void applyEdgeSlide(TransInfo *t, const int mval[2]); @@ -235,6 +239,38 @@ void setTransformViewMatrices(TransInfo *t) calculateCenter2D(t); } +void setTransformViewAspect(TransInfo *t, float r_aspect[3]) +{ + copy_v3_fl(r_aspect, 1.0f); + + if (t->spacetype == SPACE_IMAGE) { + SpaceImage *sima = t->sa->spacedata.first; + + if (t->options & CTX_MASK) { + ED_space_image_get_aspect(sima, &r_aspect[0], &r_aspect[1]); + } + else if (t->options & CTX_PAINT_CURVE) { + /* pass */ + } + else { + ED_space_image_get_uv_aspect(sima, &r_aspect[0], &r_aspect[1]); + } + } + else if (t->spacetype == SPACE_CLIP) { + SpaceClip *sclip = t->sa->spacedata.first; + + if (t->options & CTX_MOVIECLIP) { + ED_space_clip_get_aspect_dimension_aware(sclip, &r_aspect[0], &r_aspect[1]); + } + else { + ED_space_clip_get_aspect(sclip, &r_aspect[0], &r_aspect[1]); + } + } + else if (t->spacetype == SPACE_IPO) { + /* depemds on context of usage */ + } +} + static void convertViewVec2D(View2D *v2d, float r_vec[3], int dx, int dy) { float divx, divy; @@ -288,25 +324,19 @@ void convertViewVec(TransInfo *t, float r_vec[3], int dx, int dy) } } else if (t->spacetype == SPACE_IMAGE) { - float aspx, aspy; - if (t->options & CTX_MASK) { convertViewVec2D_mask(t->view, r_vec, dx, dy); - ED_space_image_get_aspect(t->sa->spacedata.first, &aspx, &aspy); } else if (t->options & CTX_PAINT_CURVE) { r_vec[0] = dx; r_vec[1] = dy; - - aspx = aspy = 1.0; } else { convertViewVec2D(t->view, r_vec, dx, dy); - ED_space_image_get_uv_aspect(t->sa->spacedata.first, &aspx, &aspy); } - r_vec[0] *= aspx; - r_vec[1] *= aspy; + r_vec[0] *= t->aspect[0]; + r_vec[1] *= t->aspect[1]; } else if (ELEM(t->spacetype, SPACE_IPO, SPACE_NLA)) { convertViewVec2D(t->view, r_vec, dx, dy); @@ -315,8 +345,6 @@ void convertViewVec(TransInfo *t, float r_vec[3], int dx, int dy) convertViewVec2D(&t->ar->v2d, r_vec, dx, dy); } else if (t->spacetype == SPACE_CLIP) { - float aspx, aspy; - if (t->options & CTX_MASK) { convertViewVec2D_mask(t->view, r_vec, dx, dy); } @@ -324,21 +352,8 @@ void convertViewVec(TransInfo *t, float r_vec[3], int dx, int dy) convertViewVec2D(t->view, r_vec, dx, dy); } - if (t->options & CTX_MOVIECLIP) { - ED_space_clip_get_aspect_dimension_aware(t->sa->spacedata.first, &aspx, &aspy); - } - else if (t->options & CTX_MASK) { - /* TODO - NOT WORKING, this isnt so bad since its only display aspect */ - ED_space_clip_get_aspect(t->sa->spacedata.first, &aspx, &aspy); - } - else { - /* should never happen, quiet warnings */ - BLI_assert(0); - aspx = aspy = 1.0f; - } - - r_vec[0] *= aspx; - r_vec[1] *= aspy; + r_vec[0] *= t->aspect[0]; + r_vec[1] *= t->aspect[1]; } else { printf("%s: called in an invalid context\n", __func__); @@ -360,15 +375,10 @@ void projectIntViewEx(TransInfo *t, const float vec[3], int adr[2], const eV3DPr SpaceImage *sima = t->sa->spacedata.first; if (t->options & CTX_MASK) { - float aspx, aspy; float v[2]; - ED_space_image_get_aspect(sima, &aspx, &aspy); - - copy_v2_v2(v, vec); - - v[0] = v[0] / aspx; - v[1] = v[1] / aspy; + v[0] = vec[0] / t->aspect[0]; + v[1] = vec[1] / t->aspect[1]; BKE_mask_coord_to_image(sima->image, &sima->iuser, v, v); @@ -382,11 +392,10 @@ void projectIntViewEx(TransInfo *t, const float vec[3], int adr[2], const eV3DPr adr[1] = vec[1]; } else { - float aspx, aspy, v[2]; + float v[2]; - ED_space_image_get_uv_aspect(t->sa->spacedata.first, &aspx, &aspy); - v[0] = vec[0] / aspx; - v[1] = vec[1] / aspy; + v[0] = vec[0] / t->aspect[0]; + v[1] = vec[1] / t->aspect[1]; UI_view2d_view_to_region(t->view, v[0], v[1], &adr[0], &adr[1]); } @@ -431,15 +440,10 @@ void projectIntViewEx(TransInfo *t, const float vec[3], int adr[2], const eV3DPr MovieClip *clip = ED_space_clip_get_clip(sc); if (clip) { - float aspx, aspy; float v[2]; - ED_space_clip_get_aspect(sc, &aspx, &aspy); - - copy_v2_v2(v, vec); - - v[0] = v[0] / aspx; - v[1] = v[1] / aspy; + v[0] = vec[0] / t->aspect[0]; + v[1] = vec[1] / t->aspect[1]; BKE_mask_coord_to_movieclip(sc->clip, &sc->user, v, v); @@ -454,13 +458,10 @@ void projectIntViewEx(TransInfo *t, const float vec[3], int adr[2], const eV3DPr } } else if (t->options & CTX_MOVIECLIP) { - float v[2], aspx, aspy; - - copy_v2_v2(v, vec); - ED_space_clip_get_aspect_dimension_aware(t->sa->spacedata.first, &aspx, &aspy); + float v[2]; - v[0] /= aspx; - v[1] /= aspy; + v[0] = vec[0] / t->aspect[0]; + v[1] = vec[1] / t->aspect[1]; UI_view2d_view_to_region(t->view, v[0], v[1], &adr[0], &adr[1]); } @@ -516,7 +517,6 @@ void applyAspectRatio(TransInfo *t, float vec[2]) { if ((t->spacetype == SPACE_IMAGE) && (t->mode == TFM_TRANSLATION) && !(t->options & CTX_PAINT_CURVE)) { SpaceImage *sima = t->sa->spacedata.first; - float aspx, aspy; if ((sima->flag & SI_COORDFLOATS) == 0) { int width, height; @@ -526,28 +526,13 @@ void applyAspectRatio(TransInfo *t, float vec[2]) vec[1] *= height; } - ED_space_image_get_uv_aspect(sima, &aspx, &aspy); - vec[0] /= aspx; - vec[1] /= aspy; + vec[0] /= t->aspect[0]; + vec[1] /= t->aspect[1]; } else if ((t->spacetype == SPACE_CLIP) && (t->mode == TFM_TRANSLATION)) { if (t->options & (CTX_MOVIECLIP | CTX_MASK)) { - SpaceClip *sc = t->sa->spacedata.first; - float aspx, aspy; - - - if (t->options & CTX_MOVIECLIP) { - ED_space_clip_get_aspect_dimension_aware(sc, &aspx, &aspy); - - vec[0] /= aspx; - vec[1] /= aspy; - } - else if (t->options & CTX_MASK) { - ED_space_clip_get_aspect(sc, &aspx, &aspy); - - vec[0] /= aspx; - vec[1] /= aspy; - } + vec[0] /= t->aspect[0]; + vec[1] /= t->aspect[1]; } } } @@ -556,7 +541,6 @@ void removeAspectRatio(TransInfo *t, float vec[2]) { if ((t->spacetype == SPACE_IMAGE) && (t->mode == TFM_TRANSLATION)) { SpaceImage *sima = t->sa->spacedata.first; - float aspx, aspy; if ((sima->flag & SI_COORDFLOATS) == 0) { int width, height; @@ -566,24 +550,13 @@ void removeAspectRatio(TransInfo *t, float vec[2]) vec[1] /= height; } - ED_space_image_get_uv_aspect(sima, &aspx, &aspy); - vec[0] *= aspx; - vec[1] *= aspy; + vec[0] *= t->aspect[0]; + vec[1] *= t->aspect[1]; } else if ((t->spacetype == SPACE_CLIP) && (t->mode == TFM_TRANSLATION)) { if (t->options & (CTX_MOVIECLIP | CTX_MASK)) { - SpaceClip *sc = t->sa->spacedata.first; - float aspx = 1.0f, aspy = 1.0f; - - if (t->options & CTX_MOVIECLIP) { - ED_space_clip_get_aspect_dimension_aware(sc, &aspx, &aspy); - } - else if (t->options & CTX_MASK) { - ED_space_clip_get_aspect(sc, &aspx, &aspy); - } - - vec[0] *= aspx; - vec[1] *= aspy; + vec[0] *= t->aspect[0]; + vec[1] *= t->aspect[1]; } } } @@ -729,7 +702,6 @@ static void view_editmove(unsigned short UNUSED(event)) switch (event) { case WHEELUPMOUSE: - if (G.qual & LR_SHIFTKEY) { if (G.qual & LR_ALTKEY) { G.qual &= ~LR_SHIFTKEY; @@ -795,35 +767,38 @@ static void view_editmove(unsigned short UNUSED(event)) /* ************************************************* */ /* NOTE: these defines are saved in keymap files, do not change values but just add new ones */ -#define TFM_MODAL_CANCEL 1 -#define TFM_MODAL_CONFIRM 2 -#define TFM_MODAL_TRANSLATE 3 -#define TFM_MODAL_ROTATE 4 -#define TFM_MODAL_RESIZE 5 -#define TFM_MODAL_SNAP_INV_ON 6 -#define TFM_MODAL_SNAP_INV_OFF 7 -#define TFM_MODAL_SNAP_TOGGLE 8 -#define TFM_MODAL_AXIS_X 9 -#define TFM_MODAL_AXIS_Y 10 -#define TFM_MODAL_AXIS_Z 11 -#define TFM_MODAL_PLANE_X 12 -#define TFM_MODAL_PLANE_Y 13 -#define TFM_MODAL_PLANE_Z 14 -#define TFM_MODAL_CONS_OFF 15 -#define TFM_MODAL_ADD_SNAP 16 -#define TFM_MODAL_REMOVE_SNAP 17 -/* 18 and 19 used by numinput, defined in transform.h - * */ -#define TFM_MODAL_PROPSIZE_UP 20 -#define TFM_MODAL_PROPSIZE_DOWN 21 -#define TFM_MODAL_AUTOIK_LEN_INC 22 -#define TFM_MODAL_AUTOIK_LEN_DEC 23 - -#define TFM_MODAL_EDGESLIDE_UP 24 -#define TFM_MODAL_EDGESLIDE_DOWN 25 +enum { + TFM_MODAL_CANCEL = 1, + TFM_MODAL_CONFIRM = 2, + TFM_MODAL_TRANSLATE = 3, + TFM_MODAL_ROTATE = 4, + TFM_MODAL_RESIZE = 5, + TFM_MODAL_SNAP_INV_ON = 6, + TFM_MODAL_SNAP_INV_OFF = 7, + TFM_MODAL_SNAP_TOGGLE = 8, + TFM_MODAL_AXIS_X = 9, + TFM_MODAL_AXIS_Y = 10, + TFM_MODAL_AXIS_Z = 11, + TFM_MODAL_PLANE_X = 12, + TFM_MODAL_PLANE_Y = 13, + TFM_MODAL_PLANE_Z = 14, + TFM_MODAL_CONS_OFF = 15, + TFM_MODAL_ADD_SNAP = 16, + TFM_MODAL_REMOVE_SNAP = 17, + +/* 18 and 19 used by numinput, defined in transform.h */ + + TFM_MODAL_PROPSIZE_UP = 20, + TFM_MODAL_PROPSIZE_DOWN = 21, + TFM_MODAL_AUTOIK_LEN_INC = 22, + TFM_MODAL_AUTOIK_LEN_DEC = 23, + + TFM_MODAL_EDGESLIDE_UP = 24, + TFM_MODAL_EDGESLIDE_DOWN = 25, /* for analog input, like trackpad */ -#define TFM_MODAL_PROPSIZE 26 + TFM_MODAL_PROPSIZE = 26, +}; /* called in transform_ops.c, on each regeneration of keymaps */ wmKeyMap *transform_modal_keymap(wmKeyConfig *keyconf) @@ -868,8 +843,8 @@ wmKeyMap *transform_modal_keymap(wmKeyConfig *keyconf) /* items for modal map */ WM_modalkeymap_add_item(keymap, ESCKEY, KM_PRESS, KM_ANY, 0, TFM_MODAL_CANCEL); WM_modalkeymap_add_item(keymap, LEFTMOUSE, KM_PRESS, KM_ANY, 0, TFM_MODAL_CONFIRM); - WM_modalkeymap_add_item(keymap, RETKEY, KM_PRESS, KM_ANY, 0, TFM_MODAL_CONFIRM); - WM_modalkeymap_add_item(keymap, PADENTER, KM_PRESS, KM_ANY, 0, TFM_MODAL_CONFIRM); + WM_modalkeymap_add_item(keymap, RETKEY, KM_PRESS, KM_ANY, 0, TFM_MODAL_CONFIRM); + WM_modalkeymap_add_item(keymap, PADENTER, KM_PRESS, KM_ANY, 0, TFM_MODAL_CONFIRM); WM_modalkeymap_add_item(keymap, GKEY, KM_PRESS, 0, 0, TFM_MODAL_TRANSLATE); WM_modalkeymap_add_item(keymap, RKEY, KM_PRESS, 0, 0, TFM_MODAL_ROTATE); @@ -888,8 +863,12 @@ wmKeyMap *transform_modal_keymap(wmKeyConfig *keyconf) WM_modalkeymap_add_item(keymap, PAGEUPKEY, KM_PRESS, 0, 0, TFM_MODAL_PROPSIZE_UP); WM_modalkeymap_add_item(keymap, PAGEDOWNKEY, KM_PRESS, 0, 0, TFM_MODAL_PROPSIZE_DOWN); + WM_modalkeymap_add_item(keymap, PAGEUPKEY, KM_PRESS, KM_SHIFT, 0, TFM_MODAL_PROPSIZE_UP); + WM_modalkeymap_add_item(keymap, PAGEDOWNKEY, KM_PRESS, KM_SHIFT, 0, TFM_MODAL_PROPSIZE_DOWN); WM_modalkeymap_add_item(keymap, WHEELDOWNMOUSE, KM_PRESS, 0, 0, TFM_MODAL_PROPSIZE_UP); WM_modalkeymap_add_item(keymap, WHEELUPMOUSE, KM_PRESS, 0, 0, TFM_MODAL_PROPSIZE_DOWN); + WM_modalkeymap_add_item(keymap, WHEELDOWNMOUSE, KM_PRESS, KM_SHIFT, 0, TFM_MODAL_PROPSIZE_UP); + WM_modalkeymap_add_item(keymap, WHEELUPMOUSE, KM_PRESS, KM_SHIFT, 0, TFM_MODAL_PROPSIZE_DOWN); WM_modalkeymap_add_item(keymap, MOUSEPAN, 0, 0, 0, TFM_MODAL_PROPSIZE); WM_modalkeymap_add_item(keymap, WHEELDOWNMOUSE, KM_PRESS, KM_ALT, 0, TFM_MODAL_EDGESLIDE_UP); @@ -907,7 +886,7 @@ static void transform_event_xyz_constraint(TransInfo *t, short key_type, char cm { if (!(t->flag & T_NO_CONSTRAINT)) { int constraint_axis, constraint_plane; - int edit_2d = (t->flag & T_2D_EDIT); + const bool edit_2d = (t->flag & T_2D_EDIT) != 0; const char *msg1 = "", *msg2 = "", *msg3 = ""; char axis; @@ -1230,7 +1209,7 @@ int transformEvent(TransInfo *t, const wmEvent *event) break; case TFM_MODAL_PROPSIZE_UP: if (t->flag & T_PROP_EDIT) { - t->prop_size *= 1.1f; + t->prop_size *= (t->modifiers & MOD_PRECISION) ? 1.01f : 1.1f; if (t->spacetype == SPACE_VIEW3D && t->persp != RV3D_ORTHO) t->prop_size = min_ff(t->prop_size, ((View3D *)t->view)->far); calculatePropRatio(t); @@ -1240,17 +1219,12 @@ int transformEvent(TransInfo *t, const wmEvent *event) break; case TFM_MODAL_PROPSIZE_DOWN: if (t->flag & T_PROP_EDIT) { - t->prop_size *= 0.90909090f; + t->prop_size /= (t->modifiers & MOD_PRECISION) ? 1.01f : 1.1f; calculatePropRatio(t); t->redraw |= TREDRAW_HARD; handled = true; } break; - case TFM_MODAL_EDGESLIDE_UP: - case TFM_MODAL_EDGESLIDE_DOWN: - t->redraw |= TREDRAW_HARD; - handled = true; - break; case TFM_MODAL_AUTOIK_LEN_INC: if (t->flag & T_AUTOIK) { transform_autoik_update(t, 1); @@ -1265,6 +1239,9 @@ int transformEvent(TransInfo *t, const wmEvent *event) handled = true; } break; + /* Those two are only handled in transform's own handler, see T44634! */ + case TFM_MODAL_EDGESLIDE_UP: + case TFM_MODAL_EDGESLIDE_DOWN: default: break; } @@ -1413,7 +1390,7 @@ int transformEvent(TransInfo *t, const wmEvent *event) break; case PADPLUSKEY: if (event->alt && t->flag & T_PROP_EDIT) { - t->prop_size *= 1.1f; + t->prop_size *= (t->modifiers & MOD_PRECISION) ? 1.01f : 1.1f; if (t->spacetype == SPACE_VIEW3D && t->persp != RV3D_ORTHO) t->prop_size = min_ff(t->prop_size, ((View3D *)t->view)->far); calculatePropRatio(t); @@ -1434,7 +1411,7 @@ int transformEvent(TransInfo *t, const wmEvent *event) break; case PADMINUS: if (event->alt && t->flag & T_PROP_EDIT) { - t->prop_size *= 0.90909090f; + t->prop_size /= (t->modifiers & MOD_PRECISION) ? 1.01f : 1.1f; calculatePropRatio(t); t->redraw = TREDRAW_HARD; handled = true; @@ -1571,7 +1548,7 @@ bool calculateTransformCenter(bContext *C, int centerMode, float cent3d[3], floa if (cent3d) { // Copy center from constraint center. Transform center can be local - copy_v3_v3(cent3d, t->con.center); + copy_v3_v3(cent3d, t->center_global); } } @@ -1824,8 +1801,8 @@ static void drawTransformView(const struct bContext *C, ARegion *UNUSED(ar), voi drawSnapping(C, t); /* edge slide, vert slide */ - drawEdgeSlide(C, t); - drawVertSlide(C, t); + drawEdgeSlide(t); + drawVertSlide(t); } /* just draw a little warning message in the top-right corner of the viewport to warn that autokeying is enabled */ @@ -1934,7 +1911,11 @@ void saveTransform(bContext *C, TransInfo *t, wmOperator *op) if ((prop = RNA_struct_find_property(op->ptr, "proportional")) && !RNA_property_is_set(op->ptr, prop)) { - if (t->obedit) + if (t->spacetype == SPACE_IPO) + ts->proportional_fcurve = proportional; + else if (t->spacetype == SPACE_ACTION) + ts->proportional_action = proportional; + else if (t->obedit) ts->proportional = proportional; else if (t->options & CTX_MASK) ts->proportional_mask = (proportional != PROP_EDIT_OFF); @@ -1985,7 +1966,7 @@ void saveTransform(bContext *C, TransInfo *t, wmOperator *op) } if ((prop = RNA_struct_find_property(op->ptr, "mirror"))) { - RNA_property_boolean_set(op->ptr, prop, t->flag & T_MIRROR); + RNA_property_boolean_set(op->ptr, prop, (t->flag & T_MIRROR) != 0); } if ((prop = RNA_struct_find_property(op->ptr, "constraint_axis"))) { @@ -2013,6 +1994,18 @@ void saveTransform(bContext *C, TransInfo *t, wmOperator *op) RNA_property_boolean_set_array(op->ptr, prop, constraint_axis); } + + { + const char *prop_id = NULL; + if (t->mode == TFM_SHRINKFATTEN) { + prop_id = "use_even_offset"; + } + + if (prop_id && (prop = RNA_struct_find_property(op->ptr, prop_id))) { + + RNA_property_boolean_set(op->ptr, prop, (t->flag & T_ALT_TRANSFORM) != 0); + } + } } /* note: caller needs to free 't' on a 0 return */ @@ -2085,6 +2078,18 @@ 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 if (t->spacetype == SPACE_ACTION) { + 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); @@ -2184,18 +2189,28 @@ bool initTransform(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve case TFM_BONESIZE: { /* used for both B-Bone width (bonesize) as for deform-dist (envelope) */ bArmature *arm = t->poseobj->data; - if (arm->drawtype == ARM_ENVELOPE) + if (arm->drawtype == ARM_ENVELOPE) { initBoneEnvelope(t); - else + t->mode = TFM_BONE_ENVELOPE_DIST; + } + else { initBoneSize(t); + } break; } case TFM_BONE_ENVELOPE: initBoneEnvelope(t); break; + case TFM_BONE_ENVELOPE_DIST: + initBoneEnvelope(t); + t->mode = TFM_BONE_ENVELOPE_DIST; + break; case TFM_EDGE_SLIDE: - initEdgeSlide(t); + { + const bool use_double_side = (op ? !RNA_boolean_get(op->ptr, "single_side") : true); + initEdgeSlide_ex(t, use_double_side); break; + } case TFM_VERT_SLIDE: initVertSlide(t); break; @@ -2254,7 +2269,6 @@ bool initTransform(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve return 0; } - /* overwrite initial values if operator supplied a non-null vector */ if ((prop = RNA_struct_find_property(op->ptr, "value")) && RNA_property_is_set(op->ptr, prop)) { float values[4] = {0}; /* in case value isn't length 4, avoid uninitialized memory */ @@ -2512,8 +2526,8 @@ static void protectedQuaternionBits(short protectflag, float quat[4], const floa static void constraintTransLim(TransInfo *t, TransData *td) { if (td->con) { - bConstraintTypeInfo *ctiLoc = BKE_constraint_typeinfo_from_type(CONSTRAINT_TYPE_LOCLIMIT); - bConstraintTypeInfo *ctiDist = BKE_constraint_typeinfo_from_type(CONSTRAINT_TYPE_DISTLIMIT); + const bConstraintTypeInfo *ctiLoc = BKE_constraint_typeinfo_from_type(CONSTRAINT_TYPE_LOCLIMIT); + const bConstraintTypeInfo *ctiDist = BKE_constraint_typeinfo_from_type(CONSTRAINT_TYPE_DISTLIMIT); bConstraintOb cob = {NULL}; bConstraint *con; @@ -2528,7 +2542,7 @@ static void constraintTransLim(TransInfo *t, TransData *td) /* Evaluate valid constraints */ for (con = td->con; con; con = con->next) { - bConstraintTypeInfo *cti = NULL; + const bConstraintTypeInfo *cti = NULL; ListBase targets = {NULL, NULL}; /* only consider constraint if enabled */ @@ -2615,7 +2629,7 @@ static void constraintob_from_transdata(bConstraintOb *cob, TransData *td) static void constraintRotLim(TransInfo *UNUSED(t), TransData *td) { if (td->con) { - bConstraintTypeInfo *cti = BKE_constraint_typeinfo_from_type(CONSTRAINT_TYPE_ROTLIMIT); + const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_from_type(CONSTRAINT_TYPE_ROTLIMIT); bConstraintOb cob; bConstraint *con; bool do_limit = false; @@ -2682,7 +2696,7 @@ static void constraintRotLim(TransInfo *UNUSED(t), TransData *td) static void constraintSizeLim(TransInfo *t, TransData *td) { if (td->con && td->ext) { - bConstraintTypeInfo *cti = BKE_constraint_typeinfo_from_type(CONSTRAINT_TYPE_SIZELIMIT); + const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_from_type(CONSTRAINT_TYPE_SIZELIMIT); bConstraintOb cob = {NULL}; bConstraint *con; float size_sign[3], size_abs[3]; @@ -2806,10 +2820,11 @@ static void initBend(TransInfo *t) t->num.unit_type[0] = B_UNIT_ROTATION; t->num.unit_type[1] = B_UNIT_LENGTH; - t->flag |= T_NO_CONSTRAINT; + t->flag |= T_NO_CONSTRAINT | T_FREE_CUSTOMDATA; //copy_v3_v3(t->center, ED_view3d_cursor3d_get(t->scene, t->view)); calculateCenterCursor(t, t->center); + calculateCenterGlobal(t); t->val = 0.0f; @@ -2884,6 +2899,8 @@ static void Bend(TransInfo *t, const int UNUSED(mval[2])) values.scale = values.scale / data->warp_init_dist; } + copy_v2_v2(t->values, values.vector); + /* header print for NumInput */ if (hasNumInput(&t->num)) { char c[NUM_STR_REP_LEN * 2]; @@ -2901,8 +2918,6 @@ static void Bend(TransInfo *t, const int UNUSED(mval[2])) WM_bool_as_string(is_clamp)); } - copy_v2_v2(t->values, values.vector); - values.angle *= -1.0f; values.scale *= data->warp_init_dist; @@ -2957,6 +2972,13 @@ static void Bend(TransInfo *t, const int UNUSED(mval[2])) add_v3_v3(vec, pivot); mul_m3_v3(td->smtx, vec); + + /* rotation */ + if ((t->flag & T_POINTS) == 0) { + ElementRotation(t, td, mat, V3D_LOCAL); + } + + /* location */ copy_v3_v3(td->loc, vec); } @@ -3052,6 +3074,8 @@ static void applyShear(TransInfo *t, const int UNUSED(mval[2])) applyNumInput(&t->num, &value); + t->values[0] = value; + /* header print for NumInput */ if (hasNumInput(&t->num)) { char c[NUM_STR_REP_LEN]; @@ -3065,8 +3089,6 @@ static void applyShear(TransInfo *t, const int UNUSED(mval[2])) BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Shear: %.3f %s (Press X or Y to set shear axis)"), value, t->proptext); } - t->values[0] = value; - unit_m3(smat); // Custom data signals shear direction @@ -3329,7 +3351,7 @@ static void applyResize(TransInfo *t, const int mval[2]) ratio = t->values[0]; } - size[0] = size[1] = size[2] = ratio; + copy_v3_fl(size, ratio); snapGridIncrement(t, size); @@ -3435,12 +3457,10 @@ static void applySkinResize(TransInfo *t, const int UNUSED(mval[2])) { TransData *td; float size[3], mat[3][3]; - float ratio; int i; char str[MAX_INFO_LEN]; - ratio = t->values[0]; - size[0] = size[1] = size[2] = ratio; + copy_v3_fl(size, t->values[0]); snapGridIncrement(t, size); @@ -3545,10 +3565,7 @@ static void applyToSphere(TransInfo *t, const int UNUSED(mval[2])) applyNumInput(&t->num, &ratio); - if (ratio < 0) - ratio = 0.0f; - else if (ratio > 1) - ratio = 1.0f; + CLAMP(ratio, 0.0f, 1.0f); t->values[0] = ratio; @@ -3917,6 +3934,8 @@ static void applyRotation(TransInfo *t, const int UNUSED(mval[2])) final = angle_wrap_rad(final); } + t->values[0] = final; + if (hasNumInput(&t->num)) { char c[NUM_STR_REP_LEN]; @@ -3933,8 +3952,6 @@ static void applyRotation(TransInfo *t, const int UNUSED(mval[2])) ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, IFACE_(" Proportional size: %.2f"), t->prop_size); } - t->values[0] = final; - applyRotationValue(t, final, t->axis); recalcData(t); @@ -4006,7 +4023,9 @@ static void applyTrackball(TransInfo *t, const int UNUSED(mval[2])) char str[MAX_INFO_LEN]; size_t ofs = 0; float axis1[3], axis2[3]; +#if 0 /* UNUSED */ float mat[3][3], totmat[3][3], smat[3][3]; +#endif float phi[2]; copy_v3_v3(axis1, t->persinv[0]); @@ -4014,13 +4033,14 @@ static void applyTrackball(TransInfo *t, const int UNUSED(mval[2])) normalize_v3(axis1); normalize_v3(axis2); - phi[0] = t->values[0]; - phi[1] = t->values[1]; + copy_v2_v2(phi, t->values); snapGridIncrement(t, phi); applyNumInput(&t->num, phi); + copy_v2_v2(t->values, phi); + if (hasNumInput(&t->num)) { char c[NUM_STR_REP_LEN * 2]; @@ -4038,6 +4058,7 @@ static void applyTrackball(TransInfo *t, const int UNUSED(mval[2])) ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, IFACE_(" Proportional size: %.2f"), t->prop_size); } +#if 0 /* UNUSED */ axis_angle_normalized_to_mat3(smat, axis1, phi[0]); axis_angle_normalized_to_mat3(totmat, axis2, phi[1]); @@ -4045,6 +4066,7 @@ static void applyTrackball(TransInfo *t, const int UNUSED(mval[2])) // TRANSFORM_FIX_ME //copy_m3_m3(t->mat, mat); // used in manipulator +#endif applyTrackballValue(t, axis1, axis2, phi); @@ -4370,6 +4392,8 @@ static void applyShrinkFatten(TransInfo *t, const int UNUSED(mval[2])) applyNumInput(&t->num, &distance); + t->values[0] = -distance; + /* header print for NumInput */ ofs += BLI_strncpy_rlen(str + ofs, IFACE_("Shrink/Fatten:"), MAX_INFO_LEN - ofs); if (hasNumInput(&t->num)) { @@ -4397,9 +4421,6 @@ static void applyShrinkFatten(TransInfo *t, const int UNUSED(mval[2])) WM_bool_as_string((t->flag & T_ALT_TRANSFORM) != 0)); /* done with header string */ - - t->values[0] = -distance; - for (i = 0; i < t->total; i++, td++) { float tdistance; /* temp dist */ if (td->flag & TD_NOACTION) @@ -4466,6 +4487,8 @@ static void applyTilt(TransInfo *t, const int UNUSED(mval[2])) applyNumInput(&t->num, &final); + t->values[0] = final; + if (hasNumInput(&t->num)) { char c[NUM_STR_REP_LEN]; @@ -4543,6 +4566,8 @@ static void applyCurveShrinkFatten(TransInfo *t, const int UNUSED(mval[2])) applyNumInput(&t->num, &ratio); + t->values[0] = ratio; + /* header print for NumInput */ if (hasNumInput(&t->num)) { char c[NUM_STR_REP_LEN]; @@ -4621,6 +4646,8 @@ static void applyMaskShrinkFatten(TransInfo *t, const int UNUSED(mval[2])) applyNumInput(&t->num, &ratio); + t->values[0] = ratio; + /* header print for NumInput */ if (hasNumInput(&t->num)) { char c[NUM_STR_REP_LEN]; @@ -4719,6 +4746,8 @@ static void applyGPShrinkFatten(TransInfo *t, const int UNUSED(mval[2])) applyNumInput(&t->num, &ratio); + t->values[0] = ratio; + /* header print for NumInput */ if (hasNumInput(&t->num)) { char c[NUM_STR_REP_LEN]; @@ -4791,6 +4820,8 @@ static void applyPushPull(TransInfo *t, const int UNUSED(mval[2])) applyNumInput(&t->num, &distance); + t->values[0] = distance; + /* header print for NumInput */ if (hasNumInput(&t->num)) { char c[NUM_STR_REP_LEN]; @@ -4804,8 +4835,6 @@ static void applyPushPull(TransInfo *t, const int UNUSED(mval[2])) BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Push/Pull: %.4f%s %s"), distance, t->con.text, t->proptext); } - t->values[0] = distance; - if (t->con.applyRot && t->con.mode & CON_APPLY) { t->con.applyRot(t, NULL, axis, NULL); } @@ -4878,12 +4907,14 @@ static void applyBevelWeight(TransInfo *t, const int UNUSED(mval[2])) weight = t->values[0]; - if (weight > 1.0f) weight = 1.0f; + CLAMP_MAX(weight, 1.0f); snapGridIncrement(t, &weight); applyNumInput(&t->num, &weight); + t->values[0] = weight; + /* header print for NumInput */ if (hasNumInput(&t->num)) { char c[NUM_STR_REP_LEN]; @@ -4956,12 +4987,14 @@ static void applyCrease(TransInfo *t, const int UNUSED(mval[2])) crease = t->values[0]; - if (crease > 1.0f) crease = 1.0f; + CLAMP_MAX(crease, 1.0f); snapGridIncrement(t, &crease); applyNumInput(&t->num, &crease); + t->values[0] = crease; + /* header print for NumInput */ if (hasNumInput(&t->num)) { char c[NUM_STR_REP_LEN]; @@ -5095,7 +5128,7 @@ static void applyBoneSize(TransInfo *t, const int mval[2]) ratio = t->values[0]; } - size[0] = size[1] = size[2] = ratio; + copy_v3_fl(size, ratio); snapGridIncrement(t, size); @@ -5103,6 +5136,8 @@ static void applyBoneSize(TransInfo *t, const int mval[2]) constraintNumInput(t, size); } + copy_v3_v3(t->values, size); + size_to_mat3(mat, size); if (t->con.applySize) { @@ -5169,6 +5204,8 @@ static void applyBoneEnvelope(TransInfo *t, const int UNUSED(mval[2])) applyNumInput(&t->num, &ratio); + t->values[0] = ratio; + /* header print for NumInput */ if (hasNumInput(&t->num)) { char c[NUM_STR_REP_LEN]; @@ -5256,11 +5293,22 @@ static void slide_origdata_create_data_vert( loop_weights = BLI_array_alloca(loop_weights, l_num); for (j = 0; j < l_num; j++) { BMLoop *l = BM_iter_step(&liter); - if (!BLI_ghash_haskey(sod->origfaces, l->f)) { + BMLoop *l_prev, *l_next; + void **val_p; + if (!BLI_ghash_ensure_p(sod->origfaces, l->f, &val_p)) { BMFace *f_copy = BM_face_copy(sod->bm_origfaces, bm, l->f, true, true); - BLI_ghash_insert(sod->origfaces, l->f, f_copy); + *val_p = f_copy; } - loop_weights[j] = BM_loop_calc_face_angle(l); + + if ((l_prev = BM_loop_find_prev_nodouble(l, l->next, FLT_EPSILON)) && + (l_next = BM_loop_find_next_nodouble(l, l_prev, FLT_EPSILON))) + { + loop_weights[j] = angle_v3v3v3(l_prev->v->co, l->v->co, l_next->v->co); + } + else { + loop_weights[j] = 0.0f; + } + } /* store cd_loop_groups */ @@ -5328,6 +5376,13 @@ static void slide_origdata_interp_data_vert( int j, l_num; float *loop_weights; const bool do_loop_weight = (len_squared_v3v3(sv->v->co, sv->co_orig_3d) > FLT_EPSILON); + const float *v_proj_axis = sv->v->no; + /* original (l->prev, l, l->next) projections for each loop ('l' remains unchanged) */ + float v_proj[3][3]; + + if (do_loop_weight) { + project_plane_v3_v3v3(v_proj[1], sv->co_orig_3d, v_proj_axis); + } // BM_ITER_ELEM (l, &liter, sv->v, BM_LOOPS_OF_VERT) { BM_iter_init(&liter, bm, BM_LOOPS_OF_VERT, sv->v); @@ -5348,11 +5403,44 @@ static void slide_origdata_interp_data_vert( /* weight the loop */ if (do_loop_weight) { - const float *v_prev = slide_origdata_orig_vert_co(sod, l->prev->v); - const float *v_next = slide_origdata_orig_vert_co(sod, l->next->v); - const float dist = dist_signed_squared_to_corner_v3v3v3(sv->v->co, v_prev, sv->co_orig_3d, v_next, f_copy->no); - const float eps = 0.00001f; - loop_weights[j] = (dist >= 0.0f) ? 1.0f : ((dist <= -eps) ? 0.0f : (1.0f + (dist / eps))); + const float eps = 1.0e-8f; + const BMLoop *l_prev = l->prev; + const BMLoop *l_next = l->next; + const float *co_prev = slide_origdata_orig_vert_co(sod, l_prev->v); + const float *co_next = slide_origdata_orig_vert_co(sod, l_next->v); + bool co_prev_ok; + bool co_next_ok; + + + /* In the unlikely case that we're next to a zero length edge - walk around the to the next. + * Since we only need to check if the vertex is in this corner, + * its not important _which_ loop - as long as its not overlapping 'sv->co_orig_3d', see: T45096. */ + project_plane_v3_v3v3(v_proj[0], co_prev, v_proj_axis); + while (UNLIKELY(((co_prev_ok = (len_squared_v3v3(v_proj[1], v_proj[0]) > eps)) == false) && + ((l_prev = l_prev->prev) != l->next))) + { + co_prev = slide_origdata_orig_vert_co(sod, l_prev->v); + project_plane_v3_v3v3(v_proj[0], co_prev, v_proj_axis); + } + project_plane_v3_v3v3(v_proj[2], co_next, v_proj_axis); + while (UNLIKELY(((co_next_ok = (len_squared_v3v3(v_proj[1], v_proj[2]) > eps)) == false) && + ((l_next = l_next->next) != l->prev))) + { + co_next = slide_origdata_orig_vert_co(sod, l_next->v); + project_plane_v3_v3v3(v_proj[2], co_next, v_proj_axis); + } + + if (co_prev_ok && co_next_ok) { + const float dist = dist_signed_squared_to_corner_v3v3v3(sv->v->co, UNPACK3(v_proj), v_proj_axis); + + loop_weights[j] = (dist >= 0.0f) ? 1.0f : ((dist <= -eps) ? 0.0f : (1.0f + (dist / eps))); + if (UNLIKELY(!isfinite(loop_weights[j]))) { + loop_weights[j] = 0.0f; + } + } + else { + loop_weights[j] = 0.0f; + } } } @@ -5423,6 +5511,19 @@ static void slide_origdata_free_date( /** \name Transform Edge Slide * \{ */ +static void calcEdgeSlideCustomPoints(struct TransInfo *t) +{ + EdgeSlideData *sld = t->customData; + + setCustomPoints(t, &t->mouse, sld->mval_end, sld->mval_start); + + /* setCustomPoints isn't normally changing as the mouse moves, + * in this case apply mouse input immediatly so we don't refresh + * with the value from the previous points */ + applyMouseInput(t, &t->mouse, t->mval, t->values); +} + + static BMEdge *get_other_edge(BMVert *v, BMEdge *e) { BMIter iter; @@ -5438,7 +5539,7 @@ static BMEdge *get_other_edge(BMVert *v, BMEdge *e) } /* interpoaltes along a line made up of 2 segments (used for edge slide) */ -static void interp_line_v3_v3v3v3(float p[3], const float v1[3], const float v2[3], const float v3[3], const float t) +static void interp_line_v3_v3v3v3(float p[3], const float v1[3], const float v2[3], const float v3[3], float t) { float t_mid, t_delta; @@ -5446,17 +5547,28 @@ static void interp_line_v3_v3v3v3(float p[3], const float v1[3], const float v2[ t_mid = line_point_factor_v3(v2, v1, v3); t_delta = t - t_mid; - if (fabsf(t_delta) < FLT_EPSILON) { - copy_v3_v3(p, v2); - } - else if (t_delta < 0.0f) { - interp_v3_v3v3(p, v1, v2, t / t_mid); + if (t_delta < 0.0f) { + if (UNLIKELY(fabsf(t_mid) < FLT_EPSILON)) { + copy_v3_v3(p, v2); + } + else { + interp_v3_v3v3(p, v1, v2, t / t_mid); + } } else { - interp_v3_v3v3(p, v2, v3, (t - t_mid) / (1.0f - t_mid)); + t = t - t_mid; + t_mid = 1.0f - t_mid; + + if (UNLIKELY(fabsf(t_mid) < FLT_EPSILON)) { + copy_v3_v3(p, v3); + } + else { + interp_v3_v3v3(p, v2, v3, t / t_mid); + } } } + static void len_v3_ensure(float v[3], const float length) { normalize_v3(v); @@ -5601,7 +5713,171 @@ static BMLoop *get_next_loop(BMVert *v, BMLoop *l, return NULL; } -static void calcNonProportionalEdgeSlide(TransInfo *t, EdgeSlideData *sld, const float mval[2]) +/** + * Calculate screenspace `mval_start` / `mval_end`, optionally slide direction. + */ +static void calcEdgeSlide_mval_range( + TransInfo *t, EdgeSlideData *sld, const int *sv_table, const int loop_nr, + const float mval[2], const bool use_btree_disp, const bool use_calc_direction) +{ + TransDataEdgeSlideVert *sv_array = sld->sv; + BMEditMesh *em = BKE_editmesh_from_object(t->obedit); + BMesh *bm = em->bm; + ARegion *ar = t->ar; + View3D *v3d = NULL; + RegionView3D *rv3d = NULL; + float projectMat[4][4]; + BMBVHTree *btree; + + /* only for use_calc_direction */ + float (*loop_dir)[3] = NULL, *loop_maxdist = NULL; + + float mval_start[2], mval_end[2]; + float mval_dir[3], dist_best_sq; + BMIter iter; + BMEdge *e; + + if (t->spacetype == SPACE_VIEW3D) { + /* background mode support */ + v3d = t->sa ? t->sa->spacedata.first : NULL; + rv3d = t->ar ? t->ar->regiondata : NULL; + } + + if (!rv3d) { + /* ok, let's try to survive this */ + unit_m4(projectMat); + } + else { + ED_view3d_ob_project_mat_get(rv3d, t->obedit, projectMat); + } + + if (use_btree_disp) { + btree = BKE_bmbvh_new_from_editmesh(em, BMBVH_RESPECT_HIDDEN, NULL, false); + } + else { + btree = NULL; + } + + /* find mouse vectors, the global one, and one per loop in case we have + * multiple loops selected, in case they are oriented different */ + zero_v3(mval_dir); + dist_best_sq = -1.0f; + + if (use_calc_direction) { + loop_dir = MEM_callocN(sizeof(float[3]) * loop_nr, "sv loop_dir"); + loop_maxdist = MEM_mallocN(sizeof(float) * loop_nr, "sv loop_maxdist"); + copy_vn_fl(loop_maxdist, loop_nr, -1.0f); + } + + BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) { + if (BM_elem_flag_test(e, BM_ELEM_SELECT)) { + int i; + + /* search cross edges for visible edge to the mouse cursor, + * then use the shared vertex to calculate screen vector*/ + for (i = 0; i < 2; i++) { + BMIter iter_other; + BMEdge *e_other; + + BMVert *v = i ? e->v1 : e->v2; + BM_ITER_ELEM (e_other, &iter_other, v, BM_EDGES_OF_VERT) { + /* screen-space coords */ + float sco_a[3], sco_b[3]; + float dist_sq; + int j, l_nr; + + if (BM_elem_flag_test(e_other, BM_ELEM_SELECT)) + continue; + + /* This test is only relevant if object is not wire-drawn! See [#32068]. */ + if (use_btree_disp && !BMBVH_EdgeVisible(btree, e_other, ar, v3d, t->obedit)) { + continue; + } + + BLI_assert(sv_table[BM_elem_index_get(v)] != -1); + j = sv_table[BM_elem_index_get(v)]; + + if (sv_array[j].v_side[1]) { + ED_view3d_project_float_v3_m4(ar, sv_array[j].v_side[1]->co, sco_b, projectMat); + } + else { + add_v3_v3v3(sco_b, v->co, sv_array[j].dir_side[1]); + ED_view3d_project_float_v3_m4(ar, sco_b, sco_b, projectMat); + } + + if (sv_array[j].v_side[0]) { + ED_view3d_project_float_v3_m4(ar, sv_array[j].v_side[0]->co, sco_a, projectMat); + } + else { + add_v3_v3v3(sco_a, v->co, sv_array[j].dir_side[0]); + ED_view3d_project_float_v3_m4(ar, sco_a, sco_a, projectMat); + } + + /* global direction */ + dist_sq = dist_squared_to_line_segment_v2(mval, sco_b, sco_a); + if ((dist_best_sq == -1.0f) || + /* intentionally use 2d size on 3d vector */ + (dist_sq < dist_best_sq && (len_squared_v2v2(sco_b, sco_a) > 0.1f))) + { + dist_best_sq = dist_sq; + sub_v3_v3v3(mval_dir, sco_b, sco_a); + } + + if (use_calc_direction) { + /* per loop direction */ + l_nr = sv_array[j].loop_nr; + if (loop_maxdist[l_nr] == -1.0f || dist_sq < loop_maxdist[l_nr]) { + loop_maxdist[l_nr] = dist_sq; + sub_v3_v3v3(loop_dir[l_nr], sco_b, sco_a); + } + } + } + } + } + } + + if (use_calc_direction) { + int i; + sv_array = sld->sv; + for (i = 0; i < sld->totsv; i++, sv_array++) { + /* switch a/b if loop direction is different from global direction */ + int l_nr = sv_array->loop_nr; + if (dot_v3v3(loop_dir[l_nr], mval_dir) < 0.0f) { + swap_v3_v3(sv_array->dir_side[0], sv_array->dir_side[1]); + SWAP(BMVert *, sv_array->v_side[0], sv_array->v_side[1]); + } + } + + MEM_freeN(loop_dir); + MEM_freeN(loop_maxdist); + } + + /* possible all of the edge loops are pointing directly at the view */ + if (UNLIKELY(len_squared_v2(mval_dir) < 0.1f)) { + mval_dir[0] = 0.0f; + mval_dir[1] = 100.0f; + } + + /* zero out start */ + zero_v2(mval_start); + + /* dir holds a vector along edge loop */ + copy_v2_v2(mval_end, mval_dir); + mul_v2_fl(mval_end, 0.5f); + + sld->mval_start[0] = t->mval[0] + mval_start[0]; + sld->mval_start[1] = t->mval[1] + mval_start[1]; + + sld->mval_end[0] = t->mval[0] + mval_end[0]; + sld->mval_end[1] = t->mval[1] + mval_end[1]; + + if (btree) { + BKE_bmbvh_free(btree); + } +} + +static void calcEdgeSlide_non_proportional( + TransInfo *t, EdgeSlideData *sld, const float mval[2]) { TransDataEdgeSlideVert *sv = sld->sv; @@ -5631,7 +5907,7 @@ static void calcNonProportionalEdgeSlide(TransInfo *t, EdgeSlideData *sld, const for (i = 0; i < sld->totsv; i++, sv++) { /* Set length */ - sv->edge_len = len_v3v3(sv->dir_a, sv->dir_b); + sv->edge_len = len_v3v3(sv->dir_side[0], sv->dir_side[1]); ED_view3d_project_float_v2_m4(ar, sv->v->co, v_proj, projectMat); dist_sq = len_squared_v2v2(mval, v_proj); @@ -5646,7 +5922,7 @@ static void calcNonProportionalEdgeSlide(TransInfo *t, EdgeSlideData *sld, const } } -static bool createEdgeSlideVerts(TransInfo *t) +static bool createEdgeSlideVerts_double_side(TransInfo *t) { BMEditMesh *em = BKE_editmesh_from_object(t->obedit); BMesh *bm = em->bm; @@ -5655,24 +5931,13 @@ static bool createEdgeSlideVerts(TransInfo *t) BMVert *v; TransDataEdgeSlideVert *sv_array; int sv_tot; - BMBVHTree *btree; int *sv_table; /* BMVert -> sv_array index */ EdgeSlideData *sld = MEM_callocN(sizeof(*sld), "sld"); + float mval[2] = {(float)t->mval[0], (float)t->mval[1]}; + int numsel, i, j, loop_nr; + bool use_btree_disp = false; View3D *v3d = NULL; RegionView3D *rv3d = NULL; - ARegion *ar = t->ar; - float projectMat[4][4]; - float mval[2] = {(float)t->mval[0], (float)t->mval[1]}; - float mval_start[2], mval_end[2]; - float mval_dir[3], maxdist, (*loop_dir)[3], *loop_maxdist; - int numsel, i, j, loop_nr, l_nr; - int use_btree_disp; - - if (t->spacetype == SPACE_VIEW3D) { - /* background mode support */ - v3d = t->sa ? t->sa->spacedata.first : NULL; - rv3d = t->ar ? t->ar->regiondata : NULL; - } slide_origdata_init_flag(t, &sld->orig_data); @@ -5680,14 +5945,6 @@ static bool createEdgeSlideVerts(TransInfo *t) sld->curr_sv_index = 0; sld->flipped_vtx = false; - if (!rv3d) { - /* ok, let's try to survive this */ - unit_m4(projectMat); - } - else { - ED_view3d_ob_project_mat_get(rv3d, t->obedit, projectMat); - } - /*ensure valid selection*/ BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) { if (BM_elem_flag_test(v, BM_ELEM_SELECT)) { @@ -5859,14 +6116,14 @@ static bool createEdgeSlideVerts(TransInfo *t) if (l_a || l_a_prev) { BMLoop *l_tmp = BM_loop_other_edge_loop(l_a ? l_a : l_a_prev, v); - sv->v_a = BM_edge_other_vert(l_tmp->e, v); - copy_v3_v3(sv->dir_a, vec_a); + sv->v_side[0] = BM_edge_other_vert(l_tmp->e, v); + copy_v3_v3(sv->dir_side[0], vec_a); } if (l_b || l_b_prev) { BMLoop *l_tmp = BM_loop_other_edge_loop(l_b ? l_b : l_b_prev, v); - sv->v_b = BM_edge_other_vert(l_tmp->e, v); - copy_v3_v3(sv->dir_b, vec_b); + sv->v_side[1] = BM_edge_other_vert(l_tmp->e, v); + copy_v3_v3(sv->dir_side[1], vec_b); } v_prev = v; @@ -5885,23 +6142,23 @@ static bool createEdgeSlideVerts(TransInfo *t) if (l_a) { BMLoop *l_tmp = BM_loop_other_edge_loop(l_a, v); - sv->v_a = BM_edge_other_vert(l_tmp->e, v); + sv->v_side[0] = BM_edge_other_vert(l_tmp->e, v); if (EDGESLIDE_VERT_IS_INNER(v, l_tmp->e)) { - get_next_loop(v, l_a, e_prev, l_tmp->e, sv->dir_a); + get_next_loop(v, l_a, e_prev, l_tmp->e, sv->dir_side[0]); } else { - sub_v3_v3v3(sv->dir_a, BM_edge_other_vert(l_tmp->e, v)->co, v->co); + sub_v3_v3v3(sv->dir_side[0], sv->v_side[0]->co, v->co); } } if (l_b) { BMLoop *l_tmp = BM_loop_other_edge_loop(l_b, v); - sv->v_b = BM_edge_other_vert(l_tmp->e, v); + sv->v_side[1] = BM_edge_other_vert(l_tmp->e, v); if (EDGESLIDE_VERT_IS_INNER(v, l_tmp->e)) { - get_next_loop(v, l_b, e_prev, l_tmp->e, sv->dir_b); + get_next_loop(v, l_b, e_prev, l_tmp->e, sv->dir_side[1]); } else { - sub_v3_v3v3(sv->dir_b, BM_edge_other_vert(l_tmp->e, v)->co, v->co); + sub_v3_v3v3(sv->dir_side[1], sv->v_side[1]->co, v->co); } } @@ -5972,142 +6229,228 @@ static bool createEdgeSlideVerts(TransInfo *t) #undef EDGESLIDE_VERT_IS_INNER } - /* use for visibility checks */ - use_btree_disp = (v3d && t->obedit->dt > OB_WIRE && v3d->drawtype > OB_WIRE); + /* EDBM_flag_disable_all(em, BM_ELEM_SELECT); */ - if (use_btree_disp) { - btree = BKE_bmbvh_new_from_editmesh(em, BMBVH_RESPECT_HIDDEN, NULL, false); - } - else { - btree = NULL; + sld->sv = sv_array; + sld->totsv = sv_tot; + + /* use for visibility checks */ + if (t->spacetype == SPACE_VIEW3D) { + v3d = t->sa ? t->sa->spacedata.first : NULL; + rv3d = t->ar ? t->ar->regiondata : NULL; + use_btree_disp = (v3d && t->obedit->dt > OB_WIRE && v3d->drawtype > OB_WIRE); } + calcEdgeSlide_mval_range(t, sld, sv_table, loop_nr, mval, use_btree_disp, true); - /* EDBM_flag_disable_all(em, BM_ELEM_SELECT); */ + /* create copies of faces for customdata projection */ + bmesh_edit_begin(bm, BMO_OPTYPE_FLAG_UNTAN_MULTIRES); + slide_origdata_init_data(t, &sld->orig_data); + slide_origdata_create_data(t, &sld->orig_data, (TransDataGenericSlideVert *)sld->sv, sizeof(*sld->sv), sld->totsv); - sld->sv = sv_array; - sld->totsv = sv_tot; + if (rv3d) { + calcEdgeSlide_non_proportional(t, sld, mval); + } + + sld->em = em; - /* find mouse vectors, the global one, and one per loop in case we have - * multiple loops selected, in case they are oriented different */ - zero_v3(mval_dir); - maxdist = -1.0f; + sld->perc = 0.0f; + + t->customData = sld; + + MEM_freeN(sv_table); - loop_dir = MEM_callocN(sizeof(float) * 3 * loop_nr, "sv loop_dir"); - loop_maxdist = MEM_mallocN(sizeof(float) * loop_nr, "sv loop_maxdist"); - fill_vn_fl(loop_maxdist, loop_nr, -1.0f); + return true; +} - BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) { - if (BM_elem_flag_test(e, BM_ELEM_SELECT)) { - BMIter iter2; - BMEdge *e2; - float d; +/** + * A simple version of #createEdgeSlideVerts + * Which assumes the longest unselected. + */ +static bool createEdgeSlideVerts_single_side(TransInfo *t) +{ + BMEditMesh *em = BKE_editmesh_from_object(t->obedit); + BMesh *bm = em->bm; + BMIter iter; + BMEdge *e; + BMVert *v; + TransDataEdgeSlideVert *sv_array; + int sv_tot; + int *sv_table; /* BMVert -> sv_array index */ + EdgeSlideData *sld = MEM_callocN(sizeof(*sld), "sld"); + float mval[2] = {(float)t->mval[0], (float)t->mval[1]}; + int i, j, loop_nr; + bool use_btree_disp = false; + View3D *v3d = NULL; + RegionView3D *rv3d = NULL; - /* search cross edges for visible edge to the mouse cursor, - * then use the shared vertex to calculate screen vector*/ - for (i = 0; i < 2; i++) { - v = i ? e->v1 : e->v2; - BM_ITER_ELEM (e2, &iter2, v, BM_EDGES_OF_VERT) { - /* screen-space coords */ - float sco_a[3], sco_b[3]; + if (t->spacetype == SPACE_VIEW3D) { + /* background mode support */ + v3d = t->sa ? t->sa->spacedata.first : NULL; + rv3d = t->ar ? t->ar->regiondata : NULL; + } - if (BM_elem_flag_test(e2, BM_ELEM_SELECT)) - continue; + slide_origdata_init_flag(t, &sld->orig_data); - /* This test is only relevant if object is not wire-drawn! See [#32068]. */ - if (use_btree_disp && !BMBVH_EdgeVisible(btree, e2, ar, v3d, t->obedit)) { - continue; + sld->is_proportional = true; + sld->curr_sv_index = 0; + /* heppans to be best for single-sided */ + sld->flipped_vtx = true; + + /* ensure valid selection */ + j = 0; + BM_ITER_MESH_INDEX (v, &iter, bm, BM_VERTS_OF_MESH, i) { + if (BM_elem_flag_test(v, BM_ELEM_SELECT)) { + float len_sq_max = -1.0f; + BMIter iter2; + BM_ITER_ELEM (e, &iter2, v, BM_EDGES_OF_VERT) { + if (!BM_elem_flag_test(e, BM_ELEM_SELECT)) { + float len_sq = BM_edge_calc_length_squared(e); + if (len_sq > len_sq_max) { + len_sq_max = len_sq; + v->e = e; } + } + } - BLI_assert(sv_table[BM_elem_index_get(v)] != -1); - j = sv_table[BM_elem_index_get(v)]; + if (len_sq_max != -1.0f) { + j++; + } + } + BM_elem_index_set(v, i); /* set_inline */ + } + bm->elem_index_dirty &= ~BM_VERT; - if (sv_array[j].v_b) { - ED_view3d_project_float_v3_m4(ar, sv_array[j].v_b->co, sco_b, projectMat); - } - else { - add_v3_v3v3(sco_b, v->co, sv_array[j].dir_b); - ED_view3d_project_float_v3_m4(ar, sco_b, sco_b, projectMat); - } - - if (sv_array[j].v_a) { - ED_view3d_project_float_v3_m4(ar, sv_array[j].v_a->co, sco_a, projectMat); + if (!j) { + return false; + } + + + sv_tot = j; + BLI_assert(sv_tot != 0); + /* over alloc */ + sv_array = MEM_callocN(sizeof(TransDataEdgeSlideVert) * bm->totvertsel, "sv_array"); + + /* same loop for all loops, weak but we dont connect loops in this case */ + loop_nr = 1; + + sv_table = MEM_mallocN(sizeof(*sv_table) * bm->totvert, __func__); + + j = 0; + BM_ITER_MESH_INDEX (v, &iter, bm, BM_VERTS_OF_MESH, i) { + sv_table[i] = -1; + if ((v->e != NULL) && (BM_elem_flag_test(v, BM_ELEM_SELECT))) { + if (BM_elem_flag_test(v->e, BM_ELEM_SELECT) == 0) { + TransDataEdgeSlideVert *sv; + sv = &sv_array[j]; + sv->v = v; + copy_v3_v3(sv->v_co_orig, v->co); + sv->v_side[0] = BM_edge_other_vert(v->e, v); + sub_v3_v3v3(sv->dir_side[0], sv->v_side[0]->co, v->co); + sv->loop_nr = 0; + sv_table[i] = j; + j += 1; + } + } + } + + /* check for wire vertices, + * interpolate the directions of wire verts between non-wire verts */ + if (sv_tot != bm->totvert) { + const int sv_tot_nowire = sv_tot; + TransDataEdgeSlideVert *sv_iter = sv_array; + int i; + for (i = 0; i < sv_tot_nowire; i++, sv_iter++) { + BMIter eiter; + BM_ITER_ELEM (e, &eiter, sv_iter->v, BM_EDGES_OF_VERT) { + /* walk over wire */ + TransDataEdgeSlideVert *sv_end = NULL; + BMEdge *e_step = e; + BMVert *v = sv_iter->v; + + j = sv_tot; + + while (1) { + BMVert *v_other = BM_edge_other_vert(e_step, v); + int endpoint = ( + (sv_table[BM_elem_index_get(v_other)] != -1) + + (BM_vert_is_edge_pair(v_other) == false)); + + if ((BM_elem_flag_test(e_step, BM_ELEM_SELECT) && + BM_elem_flag_test(v_other, BM_ELEM_SELECT)) && + (endpoint == 0)) + { + /* scan down the list */ + TransDataEdgeSlideVert *sv; + BLI_assert(sv_table[BM_elem_index_get(v_other)] == -1); + sv_table[BM_elem_index_get(v_other)] = j; + sv = &sv_array[j]; + sv->v = v_other; + copy_v3_v3(sv->v_co_orig, v_other->co); + copy_v3_v3(sv->dir_side[0], sv_iter->dir_side[0]); + j++; + + /* advance! */ + v = v_other; + e_step = BM_DISK_EDGE_NEXT(e_step, v_other); } else { - add_v3_v3v3(sco_a, v->co, sv_array[j].dir_a); - ED_view3d_project_float_v3_m4(ar, sco_a, sco_a, projectMat); - } - - /* global direction */ - d = dist_to_line_segment_v2(mval, sco_b, sco_a); - if ((maxdist == -1.0f) || - /* intentionally use 2d size on 3d vector */ - (d < maxdist && (len_squared_v2v2(sco_b, sco_a) > 0.1f))) - { - maxdist = d; - sub_v3_v3v3(mval_dir, sco_b, sco_a); + if ((endpoint == 2) && (sv_tot != j)) { + BLI_assert(BM_elem_index_get(v_other) != -1); + sv_end = &sv_array[sv_table[BM_elem_index_get(v_other)]]; + } + break; } + } - /* per loop direction */ - l_nr = sv_array[j].loop_nr; - if (loop_maxdist[l_nr] == -1.0f || d < loop_maxdist[l_nr]) { - loop_maxdist[l_nr] = d; - sub_v3_v3v3(loop_dir[l_nr], sco_b, sco_a); + if (sv_end) { + int sv_tot_prev = sv_tot; + const float *co_src = sv_iter->v->co; + const float *co_dst = sv_end->v->co; + const float *dir_src = sv_iter->dir_side[0]; + const float *dir_dst = sv_end->dir_side[0]; + sv_tot = j; + + while (j-- != sv_tot_prev) { + float factor; + factor = line_point_factor_v3(sv_array[j].v->co, co_src, co_dst); + interp_v3_v3v3(sv_array[j].dir_side[0], dir_src, dir_dst, factor); } } } } } - /* possible all of the edge loops are pointing directly at the view */ - if (UNLIKELY(len_squared_v2(mval_dir) < 0.1f)) { - mval_dir[0] = 0.0f; - mval_dir[1] = 100.0f; + /* EDBM_flag_disable_all(em, BM_ELEM_SELECT); */ + + sld->sv = sv_array; + sld->totsv = sv_tot; + + /* use for visibility checks */ + if (t->spacetype == SPACE_VIEW3D) { + v3d = t->sa ? t->sa->spacedata.first : NULL; + rv3d = t->ar ? t->ar->regiondata : NULL; + use_btree_disp = (v3d && t->obedit->dt > OB_WIRE && v3d->drawtype > OB_WIRE); } + calcEdgeSlide_mval_range(t, sld, sv_table, loop_nr, mval, use_btree_disp, false); + + /* create copies of faces for customdata projection */ bmesh_edit_begin(bm, BMO_OPTYPE_FLAG_UNTAN_MULTIRES); slide_origdata_init_data(t, &sld->orig_data); slide_origdata_create_data(t, &sld->orig_data, (TransDataGenericSlideVert *)sld->sv, sizeof(*sld->sv), sld->totsv); - /*create copies of faces for customdata projection*/ - sv_array = sld->sv; - for (i = 0; i < sld->totsv; i++, sv_array++) { - /* switch a/b if loop direction is different from global direction */ - l_nr = sv_array->loop_nr; - if (dot_v3v3(loop_dir[l_nr], mval_dir) < 0.0f) { - swap_v3_v3(sv_array->dir_a, sv_array->dir_b); - SWAP(BMVert *, sv_array->v_a, sv_array->v_b); - } + if (rv3d) { + calcEdgeSlide_non_proportional(t, sld, mval); } - if (rv3d) - calcNonProportionalEdgeSlide(t, sld, mval); - sld->em = em; - /*zero out start*/ - zero_v2(mval_start); - - /*dir holds a vector along edge loop*/ - copy_v2_v2(mval_end, mval_dir); - mul_v2_fl(mval_end, 0.5f); - - sld->mval_start[0] = t->mval[0] + mval_start[0]; - sld->mval_start[1] = t->mval[1] + mval_start[1]; - - sld->mval_end[0] = t->mval[0] + mval_end[0]; - sld->mval_end[1] = t->mval[1] + mval_end[1]; - sld->perc = 0.0f; - + t->customData = sld; - + MEM_freeN(sv_table); - if (btree) { - BKE_bmbvh_free(btree); - } - MEM_freeN(loop_dir); - MEM_freeN(loop_maxdist); return true; } @@ -6148,15 +6491,23 @@ void freeEdgeSlideVerts(TransInfo *t) recalcData(t); } -static void initEdgeSlide(TransInfo *t) +static void initEdgeSlide_ex(TransInfo *t, bool use_double_side) { EdgeSlideData *sld; + bool ok; t->mode = TFM_EDGE_SLIDE; t->transform = applyEdgeSlide; t->handleEvent = handleEventEdgeSlide; - if (!createEdgeSlideVerts(t)) { + if (use_double_side) { + ok = createEdgeSlideVerts_double_side(t); + } + else { + ok = createEdgeSlideVerts_single_side(t); + } + + if (!ok) { t->state = TRANS_CANCEL; return; } @@ -6169,7 +6520,7 @@ static void initEdgeSlide(TransInfo *t) t->customFree = freeEdgeSlideVerts; /* set custom point first if you want value to be initialized by init */ - setCustomPoints(t, &t->mouse, sld->mval_end, sld->mval_start); + calcEdgeSlideCustomPoints(t); initMouseInputMode(t, &t->mouse, INPUT_CUSTOM_RATIO_FLIP); t->idx_max = 0; @@ -6185,6 +6536,11 @@ static void initEdgeSlide(TransInfo *t) t->flag |= T_NO_CONSTRAINT | T_NO_PROJECT; } +static void initEdgeSlide(TransInfo *t) +{ + initEdgeSlide_ex(t, true); +} + static eRedrawFlag handleEventEdgeSlide(struct TransInfo *t, const struct wmEvent *event) { if (t->mode == TFM_EDGE_SLIDE) { @@ -6195,35 +6551,40 @@ static eRedrawFlag handleEventEdgeSlide(struct TransInfo *t, const struct wmEven case EKEY: if (event->val == KM_PRESS) { sld->is_proportional = !sld->is_proportional; + calcEdgeSlideCustomPoints(t); return TREDRAW_HARD; } break; case FKEY: - { if (event->val == KM_PRESS) { if (sld->is_proportional == false) { sld->flipped_vtx = !sld->flipped_vtx; } + calcEdgeSlideCustomPoints(t); + return TREDRAW_HARD; + } + break; + case CKEY: + /* use like a modifier key */ + if (event->val == KM_PRESS) { + t->flag ^= T_ALT_TRANSFORM; + calcEdgeSlideCustomPoints(t); return TREDRAW_HARD; } break; - } case EVT_MODAL_MAP: - { switch (event->val) { case TFM_MODAL_EDGESLIDE_DOWN: - { sld->curr_sv_index = ((sld->curr_sv_index - 1) + sld->totsv) % sld->totsv; - break; - } + return TREDRAW_HARD; case TFM_MODAL_EDGESLIDE_UP: - { sld->curr_sv_index = (sld->curr_sv_index + 1) % sld->totsv; - break; - } + return TREDRAW_HARD; } break; - } + case MOUSEMOVE: + calcEdgeSlideCustomPoints(t); + break; default: break; } @@ -6232,23 +6593,16 @@ static eRedrawFlag handleEventEdgeSlide(struct TransInfo *t, const struct wmEven return TREDRAW_NOTHING; } -static void drawEdgeSlide(const struct bContext *C, TransInfo *t) +static void drawEdgeSlide(TransInfo *t) { - if (t->mode == TFM_EDGE_SLIDE) { - EdgeSlideData *sld = (EdgeSlideData *)t->customData; + if ((t->mode == TFM_EDGE_SLIDE) && t->customData) { + EdgeSlideData *sld = t->customData; + const bool is_clamp = !(t->flag & T_ALT_TRANSFORM); + /* Non-Prop mode */ - if (sld && sld->is_proportional == false) { - View3D *v3d = CTX_wm_view3d(C); - float co_a[3], co_b[3], co_mark[3]; - TransDataEdgeSlideVert *curr_sv = &sld->sv[sld->curr_sv_index]; - const float fac = (sld->perc + 1.0f) / 2.0f; - const float ctrl_size = UI_GetThemeValuef(TH_FACEDOT_SIZE) + 1.5f; - const float guide_size = ctrl_size - 0.5f; + if ((sld->is_proportional == false) || (is_clamp == false)) { + View3D *v3d = t->view; const float line_size = UI_GetThemeValuef(TH_OUTLINE_WIDTH) + 0.5f; - const int alpha_shade = -30; - - add_v3_v3v3(co_a, curr_sv->v_co_orig, curr_sv->dir_a); - add_v3_v3v3(co_b, curr_sv->v_co_orig, curr_sv->dir_b); if (v3d && v3d->zbuf) glDisable(GL_DEPTH_TEST); @@ -6261,42 +6615,88 @@ static void drawEdgeSlide(const struct bContext *C, TransInfo *t) glMultMatrixf(t->obedit->obmat); - glLineWidth(line_size); - UI_ThemeColorShadeAlpha(TH_EDGE_SELECT, 80, alpha_shade); - glBegin(GL_LINES); - if (curr_sv->v_a) { - glVertex3fv(curr_sv->v_a->co); - glVertex3fv(curr_sv->v_co_orig); - } - if (curr_sv->v_b) { - glVertex3fv(curr_sv->v_b->co); - glVertex3fv(curr_sv->v_co_orig); - } - bglEnd(); + if (sld->is_proportional == false) { + float co_a[3], co_b[3], co_mark[3]; + TransDataEdgeSlideVert *curr_sv = &sld->sv[sld->curr_sv_index]; + const float fac = (sld->perc + 1.0f) / 2.0f; + const float ctrl_size = UI_GetThemeValuef(TH_FACEDOT_SIZE) + 1.5f; + const float guide_size = ctrl_size - 0.5f; + const int alpha_shade = -30; + + add_v3_v3v3(co_a, curr_sv->v_co_orig, curr_sv->dir_side[0]); + add_v3_v3v3(co_b, curr_sv->v_co_orig, curr_sv->dir_side[1]); + + glLineWidth(line_size); + UI_ThemeColorShadeAlpha(TH_EDGE_SELECT, 80, alpha_shade); + glBegin(GL_LINES); + if (curr_sv->v_side[0]) { + glVertex3fv(curr_sv->v_side[0]->co); + glVertex3fv(curr_sv->v_co_orig); + } + if (curr_sv->v_side[1]) { + glVertex3fv(curr_sv->v_side[1]->co); + glVertex3fv(curr_sv->v_co_orig); + } + glEnd(); + UI_ThemeColorShadeAlpha(TH_SELECT, -30, alpha_shade); + glPointSize(ctrl_size); + bglBegin(GL_POINTS); + if (sld->flipped_vtx) { + if (curr_sv->v_side[1]) bglVertex3fv(curr_sv->v_side[1]->co); + } + else { + if (curr_sv->v_side[0]) bglVertex3fv(curr_sv->v_side[0]->co); + } + bglEnd(); - UI_ThemeColorShadeAlpha(TH_SELECT, -30, alpha_shade); - glPointSize(ctrl_size); - bglBegin(GL_POINTS); - if (sld->flipped_vtx) { - if (curr_sv->v_b) bglVertex3fv(curr_sv->v_b->co); + UI_ThemeColorShadeAlpha(TH_SELECT, 255, alpha_shade); + glPointSize(guide_size); + bglBegin(GL_POINTS); +#if 0 + interp_v3_v3v3(co_mark, co_b, co_a, fac); + bglVertex3fv(co_mark); +#endif + interp_line_v3_v3v3v3(co_mark, co_b, curr_sv->v_co_orig, co_a, fac); + bglVertex3fv(co_mark); + bglEnd(); } else { - if (curr_sv->v_a) bglVertex3fv(curr_sv->v_a->co); - } - bglEnd(); + if (is_clamp == false) { + const int side_index = sld->curr_side_unclamp; + TransDataEdgeSlideVert *sv; + int i; + const int alpha_shade = -160; + + glLineWidth(line_size); + UI_ThemeColorShadeAlpha(TH_EDGE_SELECT, 80, alpha_shade); + glBegin(GL_LINES); + + sv = sld->sv; + for (i = 0; i < sld->totsv; i++, sv++) { + float a[3], b[3]; + + if (!is_zero_v3(sv->dir_side[side_index])) { + copy_v3_v3(a, sv->dir_side[side_index]); + } + else { + copy_v3_v3(a, sv->dir_side[!side_index]); + } - UI_ThemeColorShadeAlpha(TH_SELECT, 255, alpha_shade); - glPointSize(guide_size); - bglBegin(GL_POINTS); -#if 0 - interp_v3_v3v3(co_mark, co_b, co_a, fac); - bglVertex3fv(co_mark); -#endif - interp_line_v3_v3v3v3(co_mark, co_b, curr_sv->v_co_orig, co_a, fac); - bglVertex3fv(co_mark); - bglEnd(); + mul_v3_fl(a, 100.0f); + negate_v3_v3(b, a); + add_v3_v3(a, sv->v_co_orig); + add_v3_v3(b, sv->v_co_orig); + glVertex3fv(a); + glVertex3fv(b); + } + glEnd(); + } + else { + BLI_assert(0); + } + } glPopMatrix(); glPopAttrib(); @@ -6319,17 +6719,30 @@ static void doEdgeSlide(TransInfo *t, float perc) sv = svlist; if (sld->is_proportional == true) { - for (i = 0; i < sld->totsv; i++, sv++) { - float vec[3]; - if (perc > 0.0f) { - copy_v3_v3(vec, sv->dir_a); - mul_v3_fl(vec, perc); - add_v3_v3v3(sv->v->co, sv->v_co_orig, vec); + const bool is_clamp = !(t->flag & T_ALT_TRANSFORM); + if (is_clamp) { + const int side_index = (perc < 0.0f); + const float perc_final = fabsf(perc); + for (i = 0; i < sld->totsv; i++, sv++) { + madd_v3_v3v3fl(sv->v->co, sv->v_co_orig, sv->dir_side[side_index], perc_final); } - else { - copy_v3_v3(vec, sv->dir_b); - mul_v3_fl(vec, -perc); - add_v3_v3v3(sv->v->co, sv->v_co_orig, vec); + + sld->curr_side_unclamp = side_index; + } + else { + const int side_index = sld->curr_side_unclamp; + const float perc_init = fabsf(perc) * ((sld->curr_side_unclamp == (perc < 0.0f)) ? 1 : -1); + for (i = 0; i < sld->totsv; i++, sv++) { + float dir_flip[3]; + float perc_final = perc_init; + if (!is_zero_v3(sv->dir_side[side_index])) { + copy_v3_v3(dir_flip, sv->dir_side[side_index]); + } + else { + copy_v3_v3(dir_flip, sv->dir_side[!side_index]); + perc_final *= -1; + } + madd_v3_v3v3fl(sv->v->co, sv->v_co_orig, dir_flip, perc_final); } } } @@ -6339,7 +6752,7 @@ static void doEdgeSlide(TransInfo *t, float perc) * a/b verts, this could be changed/improved so the distance is still met but the verts are moved along * their original path (which may not be straight), however how it works now is OK and matches 2.4x - Campbell * - * \note len_v3v3(curr_sv->dir_a, curr_sv->dir_b) + * \note len_v3v3(curr_sv->dir_side[0], curr_sv->dir_side[1]) * is the same as the distance between the original vert locations, same goes for the lines below. */ TransDataEdgeSlideVert *curr_sv = &sld->sv[sld->curr_sv_index]; @@ -6352,8 +6765,8 @@ static void doEdgeSlide(TransInfo *t, float perc) if (sv->edge_len > FLT_EPSILON) { const float fac = min_ff(sv->edge_len, curr_length_perc) / sv->edge_len; - add_v3_v3v3(co_a, sv->v_co_orig, sv->dir_a); - add_v3_v3v3(co_b, sv->v_co_orig, sv->dir_b); + add_v3_v3v3(co_a, sv->v_co_orig, sv->dir_side[0]); + add_v3_v3v3(co_b, sv->v_co_orig, sv->dir_side[1]); if (sld->flipped_vtx) { interp_line_v3_v3v3v3(sv->v->co, co_b, sv->v_co_orig, co_a, fac); @@ -6371,46 +6784,43 @@ static void doEdgeSlide(TransInfo *t, float perc) static void applyEdgeSlide(TransInfo *t, const int UNUSED(mval[2])) { char str[MAX_INFO_LEN]; + size_t ofs = 0; float final; EdgeSlideData *sld = t->customData; bool flipped = sld->flipped_vtx; bool is_proportional = sld->is_proportional; + const bool is_clamp = !(t->flag & T_ALT_TRANSFORM); + const bool is_constrained = !(is_clamp == false || hasNumInput(&t->num)); final = t->values[0]; snapGridIncrement(t, &final); /* only do this so out of range values are not displayed */ - CLAMP(final, -1.0f, 1.0f); + if (is_constrained) { + CLAMP(final, -1.0f, 1.0f); + } applyNumInput(&t->num, &final); + t->values[0] = final; + + /* header string */ + ofs += BLI_strncpy_rlen(str + ofs, IFACE_("Edge Slide: "), MAX_INFO_LEN - ofs); if (hasNumInput(&t->num)) { char c[NUM_STR_REP_LEN]; - outputNumInput(&(t->num), c, &t->scene->unit); - - if (is_proportional) { - BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Edge Slide: %s (E)ven: %s"), - &c[0], WM_bool_as_string(!is_proportional)); - } - else { - BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Edge Slide: %s (E)ven: %s, (F)lipped: %s"), - &c[0], WM_bool_as_string(!is_proportional), WM_bool_as_string(flipped)); - } - } - else if (is_proportional) { - BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Edge Slide: %.4f (E)ven: %s"), - final, WM_bool_as_string(!is_proportional)); + ofs += BLI_strncpy_rlen(str + ofs, &c[0], MAX_INFO_LEN - ofs); } else { - BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Edge Slide: %.4f (E)ven: %s, (F)lipped: %s"), - final, WM_bool_as_string(!is_proportional), WM_bool_as_string(flipped)); + ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, "%.4f ", final); } - - CLAMP(final, -1.0f, 1.0f); - - t->values[0] = final; + ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, IFACE_("(E)ven: %s, "), WM_bool_as_string(!is_proportional)); + if (!is_proportional) { + ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, IFACE_("(F)lipped: %s, "), WM_bool_as_string(flipped)); + } + ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, IFACE_("Alt or (C)lamp: %s"), WM_bool_as_string(is_clamp)); + /* done with header string */ /* do stuff here */ doEdgeSlide(t, final); @@ -6432,10 +6842,20 @@ static void calcVertSlideCustomPoints(struct TransInfo *t) { VertSlideData *sld = t->customData; TransDataVertSlideVert *sv = &sld->sv[sld->curr_sv_index]; - const float *co_orig = sv->co_orig_2d; - const float *co_curr = sv->co_link_orig_2d[sv->co_link_curr]; - const int mval_start[2] = {co_orig[0], co_orig[1]}; - const int mval_end[2] = {co_curr[0], co_curr[1]}; + + const float *co_orig_3d = sv->co_orig_3d; + const float *co_curr_3d = sv->co_link_orig_3d[sv->co_link_curr]; + + float co_curr_2d[2], co_orig_2d[2]; + + int mval_ofs[2], mval_start[2], mval_end[2]; + + ED_view3d_project_float_v2_m4(t->ar, co_orig_3d, co_orig_2d, sld->proj_mat); + ED_view3d_project_float_v2_m4(t->ar, co_curr_3d, co_curr_2d, sld->proj_mat); + + ARRAY_SET_ITEMS(mval_ofs, t->imval[0] - co_orig_2d[0], t->imval[1] - co_orig_2d[1]); + ARRAY_SET_ITEMS(mval_start, co_orig_2d[0] + mval_ofs[0], co_orig_2d[1] + mval_ofs[1]); + ARRAY_SET_ITEMS(mval_end, co_curr_2d[0] + mval_ofs[0], co_curr_2d[1] + mval_ofs[1]); if (sld->flipped_vtx && sld->is_proportional == false) { setCustomPoints(t, &t->mouse, mval_start, mval_end); @@ -6443,6 +6863,11 @@ static void calcVertSlideCustomPoints(struct TransInfo *t) else { setCustomPoints(t, &t->mouse, mval_end, mval_start); } + + /* setCustomPoints isn't normally changing as the mouse moves, + * in this case apply mouse input immediatly so we don't refresh + * with the value from the previous points */ + applyMouseInput(t, &t->mouse, t->mval, t->values); } /** @@ -6460,28 +6885,39 @@ static void calcVertSlideMouseActiveVert(struct TransInfo *t, const int mval[2]) int i; for (i = 0, sv = sld->sv; i < sld->totsv; i++, sv++) { - dist_sq = len_squared_v2v2(mval_fl, sv->co_orig_2d); + float co_2d[2]; + + ED_view3d_project_float_v2_m4(t->ar, sv->co_orig_3d, co_2d, sld->proj_mat); + + dist_sq = len_squared_v2v2(mval_fl, co_2d); if (dist_sq < dist_min_sq) { dist_min_sq = dist_sq; sld->curr_sv_index = i; } } } + /** * Run while moving the mouse to slide along the edge matching the mouse direction */ static void calcVertSlideMouseActiveEdges(struct TransInfo *t, const int mval[2]) { VertSlideData *sld = t->customData; - float mval_fl[2] = {UNPACK2(mval)}; + float imval_fl[2] = {UNPACK2(t->imval)}; + float mval_fl[2] = {UNPACK2(mval)}; - float dir[2]; + float dir[3]; TransDataVertSlideVert *sv; int i; - /* first get the direction of the original vertex */ - sub_v2_v2v2(dir, sld->sv[sld->curr_sv_index].co_orig_2d, mval_fl); - normalize_v2(dir); + /* first get the direction of the original mouse position */ + sub_v2_v2v2(dir, imval_fl, mval_fl); + ED_view3d_win_to_delta(t->ar, dir, dir, t->zfac); + + invert_m4_m4(t->obedit->imat, t->obedit->obmat); + mul_mat3_m4_v3(t->obedit->imat, dir); + + normalize_v3(dir); for (i = 0, sv = sld->sv; i < sld->totsv; i++, sv++) { if (sv->co_link_tot > 1) { @@ -6490,11 +6926,14 @@ static void calcVertSlideMouseActiveEdges(struct TransInfo *t, const int mval[2] int j; for (j = 0; j < sv->co_link_tot; j++) { - float tdir[2]; + float tdir[3]; float dir_dot; - sub_v2_v2v2(tdir, sv->co_orig_2d, sv->co_link_orig_2d[j]); - normalize_v2(tdir); - dir_dot = dot_v2v2(dir, tdir); + + sub_v3_v3v3(tdir, sv->co_orig_3d, sv->co_link_orig_3d[j]); + project_plane_v3_v3v3(tdir, tdir, t->viewinv[2]); + + normalize_v3(tdir); + dir_dot = dot_v3v3(dir, tdir); if (dir_dot > dir_dot_best) { dir_dot_best = dir_dot; co_link_curr_best = j; @@ -6518,32 +6957,14 @@ static bool createVertSlideVerts(TransInfo *t) BMVert *v; TransDataVertSlideVert *sv_array; VertSlideData *sld = MEM_callocN(sizeof(*sld), "sld"); -// View3D *v3d = NULL; - RegionView3D *rv3d = NULL; - ARegion *ar = t->ar; - float projectMat[4][4]; int j; - if (t->spacetype == SPACE_VIEW3D) { - /* background mode support */ -// v3d = t->sa ? t->sa->spacedata.first : NULL; - rv3d = ar ? ar->regiondata : NULL; - } - slide_origdata_init_flag(t, &sld->orig_data); sld->is_proportional = true; sld->curr_sv_index = 0; sld->flipped_vtx = false; - if (!rv3d) { - /* ok, let's try to survive this */ - unit_m4(projectMat); - } - else { - ED_view3d_ob_project_mat_get(rv3d, t->obedit, projectMat); - } - j = 0; BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) { bool ok = false; @@ -6587,7 +7008,6 @@ static bool createVertSlideVerts(TransInfo *t) } sv_array[j].co_link_orig_3d = MEM_mallocN(sizeof(*sv_array[j].co_link_orig_3d) * k, __func__); - sv_array[j].co_link_orig_2d = MEM_mallocN(sizeof(*sv_array[j].co_link_orig_2d) * k, __func__); sv_array[j].co_link_tot = k; k = 0; @@ -6595,31 +7015,9 @@ static bool createVertSlideVerts(TransInfo *t) if (!BM_elem_flag_test(e, BM_ELEM_HIDDEN)) { BMVert *v_other = BM_edge_other_vert(e, v); copy_v3_v3(sv_array[j].co_link_orig_3d[k], v_other->co); - if (ar) { - ED_view3d_project_float_v2_m4(ar, - sv_array[j].co_link_orig_3d[k], - sv_array[j].co_link_orig_2d[k], - projectMat); - } - else { - copy_v2_v2(sv_array[j].co_link_orig_2d[k], - sv_array[j].co_link_orig_3d[k]); - } k++; } } - - if (ar) { - ED_view3d_project_float_v2_m4(ar, - sv_array[j].co_orig_3d, - sv_array[j].co_orig_2d, - projectMat); - } - else { - copy_v2_v2(sv_array[j].co_orig_2d, - sv_array[j].co_orig_3d); - } - j++; } } @@ -6637,7 +7035,19 @@ static bool createVertSlideVerts(TransInfo *t) t->customData = sld; - if (rv3d) { + /* most likely will be set below */ + unit_m4(sld->proj_mat); + + if (t->spacetype == SPACE_VIEW3D) { + /* view vars */ + RegionView3D *rv3d = NULL; + ARegion *ar = t->ar; + + rv3d = ar ? ar->regiondata : NULL; + if (rv3d) { + ED_view3d_ob_project_mat_get(rv3d, t->obedit, sld->proj_mat); + } + calcVertSlideMouseActiveVert(t, t->mval); calcVertSlideMouseActiveEdges(t, t->mval); } @@ -6677,7 +7087,6 @@ void freeVertSlideVerts(TransInfo *t) TransDataVertSlideVert *sv = sld->sv; int i = 0; for (i = 0; i < sld->totsv; i++, sv++) { - MEM_freeN(sv->co_link_orig_2d); MEM_freeN(sv->co_link_orig_3d); } } @@ -6744,16 +7153,13 @@ static eRedrawFlag handleEventVertSlide(struct TransInfo *t, const struct wmEven } break; case FKEY: - { if (event->val == KM_PRESS) { sld->flipped_vtx = !sld->flipped_vtx; calcVertSlideCustomPoints(t); return TREDRAW_HARD; } break; - } case CKEY: - { /* use like a modifier key */ if (event->val == KM_PRESS) { t->flag ^= T_ALT_TRANSFORM; @@ -6761,23 +7167,17 @@ static eRedrawFlag handleEventVertSlide(struct TransInfo *t, const struct wmEven return TREDRAW_HARD; } break; - } #if 0 case EVT_MODAL_MAP: - { switch (event->val) { case TFM_MODAL_EDGESLIDE_DOWN: - { sld->curr_sv_index = ((sld->curr_sv_index - 1) + sld->totsv) % sld->totsv; break; - } case TFM_MODAL_EDGESLIDE_UP: - { sld->curr_sv_index = (sld->curr_sv_index + 1) % sld->totsv; break; - } } - } + break; #endif case MOUSEMOVE: { @@ -6797,19 +7197,20 @@ static eRedrawFlag handleEventVertSlide(struct TransInfo *t, const struct wmEven return TREDRAW_NOTHING; } -static void drawVertSlide(const struct bContext *C, TransInfo *t) +static void drawVertSlide(TransInfo *t) { - if (t->mode == TFM_VERT_SLIDE) { - VertSlideData *sld = (VertSlideData *)t->customData; + if ((t->mode == TFM_VERT_SLIDE) && t->customData) { + VertSlideData *sld = t->customData; + const bool is_clamp = !(t->flag & T_ALT_TRANSFORM); + /* Non-Prop mode */ - if (sld) { - View3D *v3d = CTX_wm_view3d(C); + { + View3D *v3d = t->view; TransDataVertSlideVert *curr_sv = &sld->sv[sld->curr_sv_index]; TransDataVertSlideVert *sv; const float ctrl_size = UI_GetThemeValuef(TH_FACEDOT_SIZE) + 1.5f; const float line_size = UI_GetThemeValuef(TH_OUTLINE_WIDTH) + 0.5f; const int alpha_shade = -160; - const bool is_clamp = !(t->flag & T_ALT_TRANSFORM); int i; if (v3d && v3d->zbuf) @@ -6857,11 +7258,40 @@ static void drawVertSlide(const struct bContext *C, TransInfo *t) curr_sv->co_orig_3d); bglEnd(); + glDisable(GL_BLEND); + + /* direction from active vertex! */ + if ((t->mval[0] != t->imval[0]) || + (t->mval[1] != t->imval[1])) + { + float zfac = ED_view3d_calc_zfac(t->ar->regiondata, curr_sv->co_orig_3d, NULL); + float mval_ofs[2]; + float co_dest_3d[3]; + + mval_ofs[0] = t->mval[0] - t->imval[0]; + mval_ofs[1] = t->mval[1] - t->imval[1]; + + ED_view3d_win_to_delta(t->ar, mval_ofs, co_dest_3d, zfac); + + invert_m4_m4(t->obedit->imat, t->obedit->obmat); + mul_mat3_m4_v3(t->obedit->imat, co_dest_3d); + + add_v3_v3(co_dest_3d, curr_sv->co_orig_3d); + + glLineWidth(1); + setlinestyle(1); + + cpack(0xffffff); + glBegin(GL_LINES); + glVertex3fv(curr_sv->co_orig_3d); + glVertex3fv(co_dest_3d); + + glEnd(); + } + glPopMatrix(); glPopAttrib(); - glDisable(GL_BLEND); - if (v3d && v3d->zbuf) glEnable(GL_DEPTH_TEST); } @@ -6933,6 +7363,8 @@ static void applyVertSlide(TransInfo *t, const int UNUSED(mval[2])) applyNumInput(&t->num, &final); + t->values[0] = final; + /* header string */ ofs += BLI_strncpy_rlen(str + ofs, IFACE_("Vert Slide: "), MAX_INFO_LEN - ofs); if (hasNumInput(&t->num)) { @@ -7001,6 +7433,8 @@ static void applyBoneRoll(TransInfo *t, const int UNUSED(mval[2])) applyNumInput(&t->num, &final); + t->values[0] = final; + if (hasNumInput(&t->num)) { char c[NUM_STR_REP_LEN]; @@ -7273,7 +7707,7 @@ static void initSeqSlide(TransInfo *t) t->num.idx_max = t->idx_max; t->snap[0] = 0.0f; - t->snap[1] = floor(t->scene->r.frs_sec / t->scene->r.frs_sec_base); + t->snap[1] = floorf(t->scene->r.frs_sec / t->scene->r.frs_sec_base); t->snap[2] = 10.0f; copy_v3_fl(t->num.val_inc, t->snap[1]); @@ -7307,40 +7741,28 @@ static void headerSeqSlide(TransInfo *t, const float val[2], char str[MAX_INFO_L WM_bool_as_string((t->flag & T_ALT_TRANSFORM) != 0)); } -static void applySeqSlideValue(TransInfo *t, const float val[2], int frame) +static void applySeqSlideValue(TransInfo *t, const float val[2]) { TransData *td = t->data; int i; - TransSeq *ts = t->customData; for (i = 0; i < t->total; i++, td++) { - float tvec[2]; - if (td->flag & TD_NOACTION) break; if (td->flag & TD_SKIP) continue; - copy_v2_v2(tvec, val); - - mul_v2_fl(tvec, td->factor); - - if (t->modifiers & MOD_SNAP_INVERT) { - td->loc[0] = frame + td->factor * (td->iloc[0] - ts->min); - } - else { - td->loc[0] = td->iloc[0] + tvec[0]; - } - - td->loc[1] = td->iloc[1] + tvec[1]; + madd_v2_v2v2fl(td->loc, td->iloc, val, td->factor); } } static void applySeqSlide(TransInfo *t, const int mval[2]) { char str[MAX_INFO_LEN]; - int snap_frame = 0; + + snapSequenceBounds(t, mval); + if (t->con.mode & CON_APPLY) { float pvec[3] = {0.0f, 0.0f, 0.0f}; float tvec[3]; @@ -7348,16 +7770,15 @@ static void applySeqSlide(TransInfo *t, const int mval[2]) copy_v3_v3(t->values, tvec); } else { - snap_frame = snapSequenceBounds(t, mval); // snapGridIncrement(t, t->values); applyNumInput(&t->num, t->values); } - t->values[0] = floor(t->values[0] + 0.5f); - t->values[1] = floor(t->values[1] + 0.5f); + t->values[0] = floorf(t->values[0] + 0.5f); + t->values[1] = floorf(t->values[1] + 0.5f); headerSeqSlide(t, t->values, str); - applySeqSlideValue(t, t->values, snap_frame); + applySeqSlideValue(t, t->values); recalcData(t); @@ -7520,6 +7941,7 @@ static void initTimeTranslate(TransInfo *t) static void headerTimeTranslate(TransInfo *t, char str[MAX_INFO_LEN]) { char tvec[NUM_STR_REP_LEN * 3]; + int ofs = 0; /* if numeric input is active, use results from that, otherwise apply snapping to result */ if (hasNumInput(&t->num)) { @@ -7555,10 +7977,14 @@ static void headerTimeTranslate(TransInfo *t, char str[MAX_INFO_LEN]) BLI_snprintf(&tvec[0], NUM_STR_REP_LEN, "%.4f", val); } - BLI_snprintf(str, MAX_INFO_LEN, IFACE_("DeltaX: %s"), &tvec[0]); + ofs += BLI_snprintf(str, MAX_INFO_LEN, IFACE_("DeltaX: %s"), &tvec[0]); + + if (t->flag & T_PROP_EDIT_ALL) { + ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, IFACE_(" Proportional size: %.2f"), t->prop_size); + } } -static void applyTimeTranslateValue(TransInfo *t, float UNUSED(sval)) +static void applyTimeTranslateValue(TransInfo *t) { TransData *td = t->data; TransData2D *td2d = t->data2d; @@ -7588,11 +8014,11 @@ static void applyTimeTranslateValue(TransInfo *t, float UNUSED(sval)) deltax = (float)(floor(((double)deltax / secf) + 0.5) * secf); } else if (autosnap == SACTSNAP_STEP) { - deltax = (float)(floor(deltax + 0.5f)); + deltax = floorf(deltax + 0.5f); } val = BKE_nla_tweakedit_remap(adt, td->ival, NLATIME_CONVERT_MAP); - val += deltax; + val += deltax * td->factor; *(td->val) = BKE_nla_tweakedit_remap(adt, val, NLATIME_CONVERT_UNMAP); } else { @@ -7602,7 +8028,7 @@ static void applyTimeTranslateValue(TransInfo *t, float UNUSED(sval)) val = (float)(floor(((double)deltax / secf) + 0.5) * secf); } else if (autosnap == SACTSNAP_STEP) { - val = (float)(floor(val + 0.5f)); + val = floorf(val + 0.5f); } *(td->val) = td->ival + val; @@ -7616,15 +8042,17 @@ static void applyTimeTranslateValue(TransInfo *t, float UNUSED(sval)) static void applyTimeTranslate(TransInfo *t, const int mval[2]) { View2D *v2d = (View2D *)t->view; - float cval[2], sval[2]; char str[MAX_INFO_LEN]; /* calculate translation amount from mouse movement - in 'time-grid space' */ - UI_view2d_region_to_view(v2d, mval[0], mval[0], &cval[0], &cval[1]); - UI_view2d_region_to_view(v2d, t->imval[0], t->imval[0], &sval[0], &sval[1]); + if (t->flag & T_MODAL) { + float cval[2], sval[2]; + UI_view2d_region_to_view(v2d, mval[0], mval[0], &cval[0], &cval[1]); + UI_view2d_region_to_view(v2d, t->imval[0], t->imval[0], &sval[0], &sval[1]); - /* we only need to calculate effect for time (applyTimeTranslate only needs that) */ - t->values[0] = cval[0] - sval[0]; + /* we only need to calculate effect for time (applyTimeTranslate only needs that) */ + t->values[0] = cval[0] - sval[0]; + } /* handle numeric-input stuff */ t->vec[0] = t->values[0]; @@ -7632,7 +8060,7 @@ static void applyTimeTranslate(TransInfo *t, const int mval[2]) t->values[0] = t->vec[0]; headerTimeTranslate(t, str); - applyTimeTranslateValue(t, sval[0]); + applyTimeTranslateValue(t); recalcData(t); @@ -7765,7 +8193,7 @@ static void applyTimeSlide(TransInfo *t, const int mval[2]) /* t->values[0] stores cval[0], which is the current mouse-pointer location (in frames) */ // XXX Need to be able to repeat this - t->values[0] = cval[0]; + /* t->values[0] = cval[0]; */ /* UNUSED (reset again later). */ /* handle numeric-input stuff */ t->vec[0] = 2.0f * (cval[0] - sval[0]) / (maxx - minx); @@ -7866,7 +8294,7 @@ static void applyTimeScaleValue(TransInfo *t) fac = (float)(floor((double)fac / secf + 0.5) * secf); } else if (autosnap == SACTSNAP_STEP) { - fac = (float)(floor(fac + 0.5f)); + fac = floorf(fac + 0.5f); } /* check if any need to apply nla-mapping */ diff --git a/source/blender/editors/transform/transform.h b/source/blender/editors/transform/transform.h index 8d6c693b14a..8863d337cff 100644 --- a/source/blender/editors/transform/transform.h +++ b/source/blender/editors/transform/transform.h @@ -39,9 +39,6 @@ #include "DNA_listBase.h" -#include "BLI_smallhash.h" -#include "BKE_editmesh.h" - /* ************************** Types ***************************** */ struct TransInfo; @@ -107,8 +104,6 @@ typedef struct TransCon { float mtx[3][3]; /* Matrix of the Constraint space */ float imtx[3][3]; /* Inverse Matrix of the Constraint space */ float pmtx[3][3]; /* Projection Constraint Matrix (same as imtx with some axis == 0) */ - float center[3]; /* transformation center to define where to draw the view widget - * ALWAYS in global space. Unlike the transformation center */ int imval[2]; /* initial mouse value for visual calculation */ /* the one in TransInfo is not garanty to stay the same (Rotates change it) */ int mode; /* Mode flags of the Constraint */ @@ -216,10 +211,10 @@ typedef struct TransDataEdgeSlideVert { float edge_len; - struct BMVert *v_a, *v_b; + struct BMVert *v_side[2]; /* add origvert.co to get the original locations */ - float dir_a[3], dir_b[3]; + float dir_side[2][3]; int loop_nr; } TransDataEdgeSlideVert; @@ -256,19 +251,20 @@ typedef struct EdgeSlideData { bool flipped_vtx; int curr_sv_index; + + /** when un-clamped - use this index: #TransDataEdgeSlideVert.dir_side */ + int curr_side_unclamp; } EdgeSlideData; typedef struct TransDataVertSlideVert { /* TransDataGenericSlideVert */ - BMVert *v; + struct BMVert *v; struct LinkNode **cd_loop_groups; float co_orig_3d[3]; /* end generic */ - float co_orig_2d[2]; float (*co_link_orig_3d)[3]; - float (*co_link_orig_2d)[2]; int co_link_tot; int co_link_curr; } TransDataVertSlideVert; @@ -287,6 +283,9 @@ typedef struct VertSlideData { bool flipped_vtx; int curr_sv_index; + + /* result of ED_view3d_ob_project_mat_get */ + float proj_mat[4][4]; } VertSlideData; typedef struct BoneInitData { @@ -356,7 +355,10 @@ typedef struct TransInfo { eRedrawFlag redraw; /* redraw flag */ float prop_size; /* proportional circle radius */ char proptext[20]; /* proportional falloff text */ - float center[3]; /* center of transformation */ + float aspect[3]; /* spaces using non 1:1 aspect, (uv's, f-curve, movie-clip... etc) + * use for conversion and snapping. */ + float center[3]; /* center of transformation (in local-space) */ + float center_global[3]; /* center of transformation (in global-space) */ float center2d[2]; /* center in screen coordinates */ int imval[2]; /* initial mouse position */ short event_type; /* event->type used to invoke transform */ @@ -541,6 +543,7 @@ void transformApply(struct bContext *C, TransInfo *t); int transformEnd(struct bContext *C, TransInfo *t); void setTransformViewMatrices(TransInfo *t); +void setTransformViewAspect(TransInfo *t, float r_aspect[3]); void convertViewVec(TransInfo *t, float r_vec[3], int dx, int dy); void projectIntViewEx(TransInfo *t, const float vec[3], int adr[2], const eV3DProjTest flag); void projectIntView(TransInfo *t, const float vec[3], int adr[2]); @@ -626,7 +629,7 @@ typedef enum { void snapGridIncrement(TransInfo *t, float *val); void snapGridIncrementAction(TransInfo *t, float *val, GearsType action); -int snapSequenceBounds(TransInfo *t, const int mval[2]); +void snapSequenceBounds(TransInfo *t, const int mval[2]); bool activeSnap(TransInfo *t); bool validSnap(TransInfo *t); @@ -690,6 +693,7 @@ void restoreTransObjects(TransInfo *t); void recalcData(TransInfo *t); void calculateCenter2D(TransInfo *t); +void calculateCenterGlobal(TransInfo *t); void calculateCenter(TransInfo *t); diff --git a/source/blender/editors/transform/transform_constraints.c b/source/blender/editors/transform/transform_constraints.c index ccb81c7342b..3063ee22c55 100644 --- a/source/blender/editors/transform/transform_constraints.c +++ b/source/blender/editors/transform/transform_constraints.c @@ -46,6 +46,7 @@ #include "BLI_math.h" #include "BLI_utildefines.h" #include "BLI_string.h" +#include "BLI_rect.h" #include "BKE_context.h" @@ -202,7 +203,7 @@ static void axisProjection(TransInfo *t, const float axis[3], const float in[3], return; } - copy_v3_v3(t_con_center, t->con.center); + copy_v3_v3(t_con_center, t->center_global); /* checks for center being too close to the view center */ viewAxisCorrectCenter(t, t_con_center); @@ -276,7 +277,7 @@ static void planeProjection(TransInfo *t, const float in[3], float out[3]) { float vec[3], factor, norm[3]; - add_v3_v3v3(vec, in, t->con.center); + add_v3_v3v3(vec, in, t->center_global); getViewVector(t, vec, norm); sub_v3_v3v3(vec, out, in); @@ -309,7 +310,7 @@ static void applyAxisConstraintVec(TransInfo *t, TransData *td, const float in[3 mul_m3_v3(t->con.pmtx, out); // With snap, a projection is alright, no need to correct for view alignment - if (!(t->tsnap.mode != SCE_SNAP_MODE_INCREMENT && activeSnap(t))) { + if (ELEM(t->tsnap.mode, SCE_SNAP_MODE_INCREMENT, SCE_SNAP_MODE_GRID) || activeSnap(t)) { if (getConstraintSpaceDimension(t) == 2) { if (out[0] != 0.0f || out[1] != 0.0f || out[2] != 0.0f) { planeProjection(t, in, out); @@ -687,11 +688,11 @@ void drawConstraint(TransInfo *t) int depth_test_enabled; convertViewVec(t, vec, (t->mval[0] - t->con.imval[0]), (t->mval[1] - t->con.imval[1])); - add_v3_v3(vec, tc->center); + add_v3_v3(vec, t->center_global); - drawLine(t, tc->center, tc->mtx[0], 'X', 0); - drawLine(t, tc->center, tc->mtx[1], 'Y', 0); - drawLine(t, tc->center, tc->mtx[2], 'Z', 0); + drawLine(t, t->center_global, tc->mtx[0], 'X', 0); + drawLine(t, t->center_global, tc->mtx[1], 'Y', 0); + drawLine(t, t->center_global, tc->mtx[2], 'Z', 0); glColor3ubv((GLubyte *)col2); @@ -701,7 +702,7 @@ void drawConstraint(TransInfo *t) setlinestyle(1); glBegin(GL_LINE_STRIP); - glVertex3fv(tc->center); + glVertex3fv(t->center_global); glVertex3fv(vec); glEnd(); setlinestyle(0); @@ -711,13 +712,13 @@ void drawConstraint(TransInfo *t) } if (tc->mode & CON_AXIS0) { - drawLine(t, tc->center, tc->mtx[0], 'X', DRAWLIGHT); + drawLine(t, t->center_global, tc->mtx[0], 'X', DRAWLIGHT); } if (tc->mode & CON_AXIS1) { - drawLine(t, tc->center, tc->mtx[1], 'Y', DRAWLIGHT); + drawLine(t, t->center_global, tc->mtx[1], 'Y', DRAWLIGHT); } if (tc->mode & CON_AXIS2) { - drawLine(t, tc->center, tc->mtx[2], 'Z', DRAWLIGHT); + drawLine(t, t->center_global, tc->mtx[2], 'Z', DRAWLIGHT); } } } @@ -728,7 +729,6 @@ void drawPropCircle(const struct bContext *C, TransInfo *t) if (t->flag & T_PROP_EDIT) { RegionView3D *rv3d = CTX_wm_region_view3d(C); float tmat[4][4], imat[4][4]; - float center[3]; int depth_test_enabled; UI_ThemeColor(TH_GRID); @@ -744,25 +744,21 @@ void drawPropCircle(const struct bContext *C, TransInfo *t) glPushMatrix(); - copy_v3_v3(center, t->center); - - if ((t->spacetype == SPACE_VIEW3D) && t->obedit) { - mul_m4_v3(t->obedit->obmat, center); /* because t->center is in local space */ + if (t->spacetype == SPACE_VIEW3D) { + /* pass */ } else if (t->spacetype == SPACE_IMAGE) { - float aspx, aspy; - - if (t->options & CTX_MASK) { - /* untested - mask aspect is TODO */ - ED_space_image_get_aspect(t->sa->spacedata.first, &aspx, &aspy); - } - else if (t->options & CTX_PAINT_CURVE) { - aspx = aspy = 1.0; - } - 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 / t->aspect[0], 1.0f / t->aspect[1], 1.0f); + } + else if (ELEM(t->spacetype, SPACE_IPO, SPACE_ACTION)) { + /* 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); @@ -770,7 +766,7 @@ void drawPropCircle(const struct bContext *C, TransInfo *t) glDisable(GL_DEPTH_TEST); set_inverted_drawing(1); - drawcircball(GL_LINE_LOOP, center, t->prop_size, imat); + drawcircball(GL_LINE_LOOP, t->center_global, t->prop_size, imat); set_inverted_drawing(0); if (depth_test_enabled) @@ -961,7 +957,7 @@ static void setNearestAxis3d(TransInfo *t) mul_v3_fl(axis, zfac); /* now we can project to get window coordinate */ - add_v3_v3(axis, t->con.center); + add_v3_v3(axis, t->center_global); projectFloatView(t, axis, axis_2d); sub_v2_v2v2(axis, axis_2d, t->center2d); diff --git a/source/blender/editors/transform/transform_conversions.c b/source/blender/editors/transform/transform_conversions.c index b50f56aae3e..c9e7e085a96 100644 --- a/source/blender/editors/transform/transform_conversions.c +++ b/source/blender/editors/transform/transform_conversions.c @@ -31,6 +31,7 @@ #include <string.h> #include <math.h> +#include <limits.h> #include "DNA_anim_types.h" #include "DNA_brush_types.h" @@ -58,6 +59,7 @@ #include "BLI_linklist_stack.h" #include "BLI_string.h" #include "BLI_bitmap.h" +#include "BLI_rect.h" #include "BKE_DerivedMesh.h" #include "BKE_action.h" @@ -340,20 +342,20 @@ static void createTransEdge(TransInfo *t) BMIter iter; float mtx[3][3], smtx[3][3]; int count = 0, countsel = 0; - int propmode = t->flag & T_PROP_EDIT; + const bool is_prop_edit = (t->flag & T_PROP_EDIT) != 0; int cd_edge_float_offset; BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) { if (!BM_elem_flag_test(eed, BM_ELEM_HIDDEN)) { if (BM_elem_flag_test(eed, BM_ELEM_SELECT)) countsel++; - if (propmode) count++; + if (is_prop_edit) count++; } } if (countsel == 0) return; - if (propmode) { + if (is_prop_edit) { t->total = count; } else { @@ -379,7 +381,7 @@ static void createTransEdge(TransInfo *t) BLI_assert(cd_edge_float_offset != -1); BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) { - if (!BM_elem_flag_test(eed, BM_ELEM_HIDDEN) && (BM_elem_flag_test(eed, BM_ELEM_SELECT) || propmode)) { + if (!BM_elem_flag_test(eed, BM_ELEM_HIDDEN) && (BM_elem_flag_test(eed, BM_ELEM_SELECT) || is_prop_edit)) { float *fl_ptr; /* need to set center for center calculations */ mid_v3_v3v3(td->center, eed->v1->co, eed->v2->co); @@ -627,10 +629,10 @@ static void add_pose_transdata(TransInfo *t, bPoseChannel *pchan, Object *ob, Tr mul_m3_m3m3(td->axismtx, omat, pmat); normalize_m3(td->axismtx); - if (t->mode == TFM_BONESIZE) { + if (ELEM(t->mode, TFM_BONESIZE, TFM_BONE_ENVELOPE_DIST)) { bArmature *arm = t->poseobj->data; - if (arm->drawtype == ARM_ENVELOPE) { + if ((t->mode == TFM_BONE_ENVELOPE_DIST) || (arm->drawtype == ARM_ENVELOPE)) { td->loc = NULL; td->val = &bone->dist; td->ival = bone->dist; @@ -717,7 +719,7 @@ int count_set_pose_transflags(int *out_mode, short around, Object *ob) /* make sure no bone can be transformed when a parent is transformed */ /* since pchans are depsgraph sorted, the parents are in beginning of list */ - if (mode != TFM_BONESIZE) { + if (!ELEM(mode, TFM_BONESIZE, TFM_BONE_ENVELOPE_DIST)) { for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) { bone = pchan->bone; if (bone->flag & BONE_TRANSFORM) @@ -1124,7 +1126,7 @@ static void createTransArmatureVerts(TransInfo *t) oldtot = t->total; if (EBONE_VISIBLE(arm, ebo) && !(ebo->flag & BONE_EDITMODE_LOCKED)) { - if (t->mode == TFM_BONESIZE) { + if (ELEM(t->mode, TFM_BONESIZE, TFM_BONE_ENVELOPE_DIST)) { if (ebo->flag & BONE_SELECTED) t->total++; } @@ -1202,9 +1204,9 @@ static void createTransArmatureVerts(TransInfo *t) } } - else if (t->mode == TFM_BONESIZE) { + else if (ELEM(t->mode, TFM_BONESIZE, TFM_BONE_ENVELOPE_DIST)) { if (ebo->flag & BONE_SELECTED) { - if (arm->drawtype == ARM_ENVELOPE) { + if ((t->mode == TFM_BONE_ENVELOPE_DIST) || (arm->drawtype == ARM_ENVELOPE)) { td->loc = NULL; td->val = &ebo->dist; td->ival = ebo->dist; @@ -1329,18 +1331,18 @@ static void createTransMBallVerts(TransInfo *t) TransDataExtension *tx; float mtx[3][3], smtx[3][3]; int count = 0, countsel = 0; - int propmode = t->flag & T_PROP_EDIT; + const bool is_prop_edit = (t->flag & T_PROP_EDIT) != 0; /* count totals */ for (ml = mb->editelems->first; ml; ml = ml->next) { if (ml->flag & SELECT) countsel++; - if (propmode) count++; + if (is_prop_edit) count++; } /* note: in prop mode we need at least 1 selected */ if (countsel == 0) return; - if (propmode) t->total = count; + if (is_prop_edit) t->total = count; else t->total = countsel; td = t->data = MEM_callocN(t->total * sizeof(TransData), "TransObData(MBall EditMode)"); @@ -1350,7 +1352,7 @@ static void createTransMBallVerts(TransInfo *t) pseudoinverse_m3_m3(smtx, mtx, PSEUDOINVERSE_EPSILON); for (ml = mb->editelems->first; ml; ml = ml->next) { - if (propmode || (ml->flag & SELECT)) { + if (is_prop_edit || (ml->flag & SELECT)) { td->loc = &ml->x; copy_v3_v3(td->iloc, td->loc); copy_v3_v3(td->center, td->loc); @@ -1463,7 +1465,7 @@ static void createTransCurveVerts(TransInfo *t) float mtx[3][3], smtx[3][3]; int a; int count = 0, countsel = 0; - int propmode = t->flag & T_PROP_EDIT; + const bool is_prop_edit = (t->flag & T_PROP_EDIT) != 0; short hide_handles = (cu->drawflag & CU_HIDE_HANDLES); ListBase *nurbs; @@ -1478,13 +1480,13 @@ static void createTransCurveVerts(TransInfo *t) if (bezt->hide == 0) { if (hide_handles) { if (bezt->f2 & SELECT) countsel += 3; - if (propmode) count += 3; + if (is_prop_edit) count += 3; } else { if (bezt->f1 & SELECT) countsel++; if (bezt->f2 & SELECT) countsel++; if (bezt->f3 & SELECT) countsel++; - if (propmode) count += 3; + if (is_prop_edit) count += 3; } } } @@ -1492,7 +1494,7 @@ static void createTransCurveVerts(TransInfo *t) else { for (a = nu->pntsu * nu->pntsv, bp = nu->bp; a > 0; a--, bp++) { if (bp->hide == 0) { - if (propmode) count++; + if (is_prop_edit) count++; if (bp->f1 & SELECT) countsel++; } } @@ -1501,7 +1503,7 @@ static void createTransCurveVerts(TransInfo *t) /* note: in prop mode we need at least 1 selected */ if (countsel == 0) return; - if (propmode) t->total = count; + if (is_prop_edit) t->total = count; else t->total = countsel; t->data = MEM_callocN(t->total * sizeof(TransData), "TransObData(Curve EditMode)"); @@ -1536,7 +1538,7 @@ static void createTransCurveVerts(TransInfo *t) } } - if (propmode || + if (is_prop_edit || ((bezt->f2 & SELECT) && hide_handles) || ((bezt->f1 & SELECT) && hide_handles == 0)) { @@ -1570,7 +1572,7 @@ static void createTransCurveVerts(TransInfo *t) } /* This is the Curve Point, the other two are handles */ - if (propmode || (bezt->f2 & SELECT)) { + if (is_prop_edit || (bezt->f2 & SELECT)) { copy_v3_v3(td->iloc, bezt->vec[1]); td->loc = bezt->vec[1]; copy_v3_v3(td->center, td->loc); @@ -1606,7 +1608,7 @@ static void createTransCurveVerts(TransInfo *t) count++; tail++; } - if (propmode || + if (is_prop_edit || ((bezt->f2 & SELECT) && hide_handles) || ((bezt->f3 & SELECT) && hide_handles == 0)) { @@ -1643,12 +1645,12 @@ static void createTransCurveVerts(TransInfo *t) (void)hdata; /* quiet warning */ } - else if (propmode && head != tail) { + else if (is_prop_edit && head != tail) { calc_distanceCurveVerts(head, tail - 1); head = tail; } } - if (propmode && head != tail) + if (is_prop_edit && head != tail) calc_distanceCurveVerts(head, tail - 1); /* TODO - in the case of tilt and radius we can also avoid allocating the initTransDataCurveHandles @@ -1663,7 +1665,7 @@ static void createTransCurveVerts(TransInfo *t) head = tail = td; for (a = nu->pntsu * nu->pntsv, bp = nu->bp; a > 0; a--, bp++) { if (bp->hide == 0) { - if (propmode || (bp->f1 & SELECT)) { + if (is_prop_edit || (bp->f1 & SELECT)) { copy_v3_v3(td->iloc, bp->vec); td->loc = bp->vec; copy_v3_v3(td->center, td->loc); @@ -1688,12 +1690,12 @@ static void createTransCurveVerts(TransInfo *t) tail++; } } - else if (propmode && head != tail) { + else if (is_prop_edit && head != tail) { calc_distanceCurveVerts(head, tail - 1); head = tail; } } - if (propmode && head != tail) + if (is_prop_edit && head != tail) calc_distanceCurveVerts(head, tail - 1); } } @@ -1709,14 +1711,14 @@ static void createTransLatticeVerts(TransInfo *t) float mtx[3][3], smtx[3][3]; int a; int count = 0, countsel = 0; - int propmode = t->flag & T_PROP_EDIT; + const bool is_prop_edit = (t->flag & T_PROP_EDIT) != 0; bp = latt->def; a = latt->pntsu * latt->pntsv * latt->pntsw; while (a--) { if (bp->hide == 0) { if (bp->f1 & SELECT) countsel++; - if (propmode) count++; + if (is_prop_edit) count++; } bp++; } @@ -1724,7 +1726,7 @@ static void createTransLatticeVerts(TransInfo *t) /* note: in prop mode we need at least 1 selected */ if (countsel == 0) return; - if (propmode) t->total = count; + if (is_prop_edit) t->total = count; else t->total = countsel; t->data = MEM_callocN(t->total * sizeof(TransData), "TransObData(Lattice EditMode)"); @@ -1735,7 +1737,7 @@ static void createTransLatticeVerts(TransInfo *t) bp = latt->def; a = latt->pntsu * latt->pntsv * latt->pntsw; while (a--) { - if (propmode || (bp->f1 & SELECT)) { + if (is_prop_edit || (bp->f1 & SELECT)) { if (bp->hide == 0) { copy_v3_v3(td->iloc, bp->vec); td->loc = bp->vec; @@ -1776,7 +1778,7 @@ static void createTransParticleVerts(bContext *C, TransInfo *t) float mat[4][4]; int i, k, transformparticle; int count = 0, hasselected = 0; - int propmode = t->flag & T_PROP_EDIT; + const bool is_prop_edit = (t->flag & T_PROP_EDIT) != 0; if (edit == NULL || t->settings->particle.selectmode == SCE_SELECT_PATH) return; @@ -1798,7 +1800,7 @@ static void createTransParticleVerts(bContext *C, TransInfo *t) hasselected = 1; transformparticle = 1; } - else if (propmode) + else if (is_prop_edit) transformparticle = 1; } } @@ -1848,7 +1850,7 @@ static void createTransParticleVerts(bContext *C, TransInfo *t) if (key->flag & PEK_SELECT) td->flag |= TD_SELECTED; - else if (!propmode) + else if (!is_prop_edit) td->flag |= TD_SKIP; unit_m3(td->mtx); @@ -1877,7 +1879,7 @@ static void createTransParticleVerts(bContext *C, TransInfo *t) tx++; tail++; } - if (propmode && head != tail) + if (is_prop_edit && head != tail) calc_distanceCurveVerts(head, tail - 1); } } @@ -1893,7 +1895,8 @@ void flushTransParticles(TransInfo *t) PTCacheEditKey *key; TransData *td; float mat[4][4], imat[4][4], co[3]; - int i, k, propmode = t->flag & T_PROP_EDIT; + int i, k; + const bool is_prop_edit = (t->flag & T_PROP_EDIT) != 0; if (psys) psmd = psys_get_modifier(ob, psys); @@ -1914,7 +1917,7 @@ void flushTransParticles(TransInfo *t) /* optimization for proportional edit */ - if (!propmode || !compare_v3v3(key->co, co, 0.0001f)) { + if (!is_prop_edit || !compare_v3v3(key->co, co, 0.0001f)) { copy_v3_v3(key->co, co); point->flag |= PEP_EDIT_RECALC; } @@ -1972,17 +1975,19 @@ static void editmesh_set_connectivity_distance(BMesh *bm, float mtx[3][3], float int i; BM_ITER_MESH_INDEX (v, &viter, bm, BM_VERTS_OF_MESH, i) { + float dist; BM_elem_index_set(v, i); /* set_inline */ BM_elem_flag_disable(v, BM_ELEM_TAG); if (BM_elem_flag_test(v, BM_ELEM_SELECT) == 0 || BM_elem_flag_test(v, BM_ELEM_HIDDEN)) { - dists[i] = FLT_MAX; + dist = FLT_MAX; } else { BLI_LINKSTACK_PUSH(queue, v); - - dists[i] = 0.0f; + dist = 0.0f; } + + dists[i] = dists_prev[i] = dist; } bm->elem_index_dirty &= ~BM_VERT; } @@ -1991,55 +1996,77 @@ static void editmesh_set_connectivity_distance(BMesh *bm, float mtx[3][3], float BMVert *v; LinkNode *lnk; + /* this is correct but slow to do each iteration, + * instead sync the dist's while clearing BM_ELEM_TAG (below) */ +#if 0 memcpy(dists_prev, dists, sizeof(float) * bm->totvert); +#endif while ((v = BLI_LINKSTACK_POP(queue))) { - /* quick checks */ - bool has_edges = (v->e != NULL); - bool has_faces = false; + BLI_assert(dists[BM_elem_index_get(v)] != FLT_MAX); /* connected edge-verts */ - if (has_edges) { - BMIter iter; - BMEdge *e; + if (v->e != NULL) { + BMEdge *e_iter, *e_first; + + e_iter = e_first = v->e; - BM_ITER_ELEM (e, &iter, v, BM_EDGES_OF_VERT) { - has_faces |= (BM_edge_is_wire(e) == false); + /* would normally use BM_EDGES_OF_VERT, but this runs so often, + * its faster to iterate on the data directly */ + do { - if (BM_elem_flag_test(e, BM_ELEM_HIDDEN) == 0) { - BMVert *v_other = BM_edge_other_vert(e, v); + if (BM_elem_flag_test(e_iter, BM_ELEM_HIDDEN) == 0) { + + /* edge distance */ + BMVert *v_other = BM_edge_other_vert(e_iter, v); if (bmesh_test_dist_add(v, v_other, dists, dists_prev, mtx)) { if (BM_elem_flag_test(v_other, BM_ELEM_TAG) == 0) { BM_elem_flag_enable(v_other, BM_ELEM_TAG); BLI_LINKSTACK_PUSH(queue_next, v_other); } } - } - } - } - - /* imaginary edge diagonally across quad */ - if (has_faces) { - BMIter iter; - BMLoop *l; - BM_ITER_ELEM (l, &iter, v, BM_LOOPS_OF_VERT) { - if ((BM_elem_flag_test(l->f, BM_ELEM_HIDDEN) == 0) && (l->f->len == 4)) { - BMVert *v_other = l->next->next->v; - if (bmesh_test_dist_add(v, v_other, dists, dists_prev, mtx)) { - if (BM_elem_flag_test(v_other, BM_ELEM_TAG) == 0) { - BM_elem_flag_enable(v_other, BM_ELEM_TAG); - BLI_LINKSTACK_PUSH(queue_next, v_other); - } + /* face distance */ + if (e_iter->l) { + BMLoop *l_iter_radial, *l_first_radial; + /** + * imaginary edge diagonally across quad, + * \note, this takes advantage of the rules of winding that we + * know 2 or more of a verts edges wont reference the same face twice. + * Also, if the edge is hidden, the face will be hidden too. + */ + l_iter_radial = l_first_radial = e_iter->l; + + do { + if ((l_iter_radial->v == v) && + (l_iter_radial->f->len == 4) && + (BM_elem_flag_test(l_iter_radial->f, BM_ELEM_HIDDEN) == 0)) + { + BMVert *v_other = l_iter_radial->next->next->v; + if (bmesh_test_dist_add(v, v_other, dists, dists_prev, mtx)) { + if (BM_elem_flag_test(v_other, BM_ELEM_TAG) == 0) { + BM_elem_flag_enable(v_other, BM_ELEM_TAG); + BLI_LINKSTACK_PUSH(queue_next, v_other); + } + } + } + } while ((l_iter_radial = l_iter_radial->radial_next) != l_first_radial); } } - } + } while ((e_iter = BM_DISK_EDGE_NEXT(e_iter, v)) != e_first); } } + /* clear for the next loop */ for (lnk = queue_next; lnk; lnk = lnk->next) { - BM_elem_flag_disable((BMVert *)lnk->link, BM_ELEM_TAG); + BMVert *v = lnk->link; + const int i = BM_elem_index_get(v); + + BM_elem_flag_disable(v, BM_ELEM_TAG); + + /* keep in sync, avoid having to do full memcpy each iteration */ + dists_prev[i] = dists[i]; } BLI_LINKSTACK_SWAP(queue, queue_next); @@ -2097,7 +2124,7 @@ static struct TransIslandData *editmesh_islands_info_calc(BMEditMesh *em, int *r vert_map = MEM_mallocN(sizeof(*vert_map) * bm->totvert, __func__); /* we shouldn't need this, but with incorrect selection flushing * its possible we have a selected vertex thats not in a face, for now best not crash in that case. */ - fill_vn_i(vert_map, bm->totvert, -1); + copy_vn_i(vert_map, bm->totvert, -1); BM_mesh_elem_table_ensure(bm, htype); ele_array = (htype == BM_FACE) ? (void **)bm->ftable : (void **)bm->etable; @@ -2257,7 +2284,7 @@ static void createTransEditVerts(TransInfo *t) float mtx[3][3], smtx[3][3], (*defmats)[3][3] = NULL, (*defcos)[3] = NULL; float *dists = NULL; int a; - int propmode = (t->flag & T_PROP_EDIT) ? (t->flag & T_PROP_EDIT_ALL) : 0; + const int prop_mode = (t->flag & T_PROP_EDIT) ? (t->flag & T_PROP_EDIT_ALL) : 0; int mirror = 0; int cd_vert_bweight_offset = -1; bool use_topology = (me->editflag & ME_EDIT_MIRROR_TOPO) != 0; @@ -2297,7 +2324,7 @@ static void createTransEditVerts(TransInfo *t) cd_vert_bweight_offset = CustomData_get_offset(&bm->vdata, CD_BWEIGHT); } - if (propmode) { + if (prop_mode) { unsigned int count = 0; BM_ITER_MESH (eve, &iter, bm, BM_VERTS_OF_MESH) { if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) { @@ -2308,7 +2335,7 @@ static void createTransEditVerts(TransInfo *t) t->total = count; /* allocating scratch arrays */ - if (propmode & T_PROP_CONNECTED) + if (prop_mode & T_PROP_CONNECTED) dists = MEM_mallocN(em->bm->totvert * sizeof(float), "scratch nears"); } else { @@ -2330,7 +2357,7 @@ static void createTransEditVerts(TransInfo *t) * matrix inversion still works and we can still moving along the other */ pseudoinverse_m3_m3(smtx, mtx, PSEUDOINVERSE_EPSILON); - if (propmode & T_PROP_CONNECTED) { + if (prop_mode & T_PROP_CONNECTED) { editmesh_set_connectivity_distance(em->bm, mtx, dists); } @@ -2359,7 +2386,7 @@ static void createTransEditVerts(TransInfo *t) { mappedcos = BKE_crazyspace_get_mapped_editverts(t->scene, t->obedit); quats = MEM_mallocN(em->bm->totvert * sizeof(*quats), "crazy quats"); - BKE_crazyspace_set_quats_editmesh(em, defcos, mappedcos, quats, !propmode); + BKE_crazyspace_set_quats_editmesh(em, defcos, mappedcos, quats, !prop_mode); if (mappedcos) MEM_freeN(mappedcos); } @@ -2384,7 +2411,7 @@ static void createTransEditVerts(TransInfo *t) BM_ITER_MESH_INDEX (eve, &iter, bm, BM_VERTS_OF_MESH, a) { if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) { - if (propmode || BM_elem_flag_test(eve, BM_ELEM_SELECT)) { + if (prop_mode || BM_elem_flag_test(eve, BM_ELEM_SELECT)) { struct TransIslandData *v_island = (island_info && island_vert_map[a] != -1) ? &island_info[island_vert_map[a]] : NULL; float *bweight = (cd_vert_bweight_offset != -1) ? BM_ELEM_CD_GET_VOID_P(eve, cd_vert_bweight_offset) : NULL; @@ -2397,8 +2424,8 @@ static void createTransEditVerts(TransInfo *t) if (BM_elem_flag_test(eve, BM_ELEM_SELECT)) tob->flag |= TD_SELECTED; - if (propmode) { - if (propmode & T_PROP_CONNECTED) { + if (prop_mode) { + if (prop_mode & T_PROP_CONNECTED) { tob->dist = dists[a]; } else { @@ -2650,24 +2677,23 @@ void flushTransSeq(TransInfo *t) /* ********************* UV ****************** */ -static void UVsToTransData(SpaceImage *sima, TransData *td, TransData2D *td2d, float *uv, int selected) +static void UVsToTransData( + const float aspect[2], TransData *td, TransData2D *td2d, + float *uv, const float *center, bool selected) { - float aspx, aspy; - - ED_space_image_get_uv_aspect(sima, &aspx, &aspy); - /* uv coords are scaled by aspects. this is needed for rotations and * proportional editing to be consistent with the stretched uv coords * that are displayed. this also means that for display and numinput, * and when the uv coords are flushed, these are converted each time */ - td2d->loc[0] = uv[0] * aspx; - td2d->loc[1] = uv[1] * aspy; + td2d->loc[0] = uv[0] * aspect[0]; + td2d->loc[1] = uv[1] * aspect[1]; td2d->loc[2] = 0.0f; td2d->loc2d = uv; td->flag = 0; td->loc = td2d->loc; - copy_v3_v3(td->center, td->loc); + copy_v2_v2(td->center, center ? center : td->loc); + td->center[2] = 0.0f; copy_v3_v3(td->iloc, td->loc); memset(td->axismtx, 0, sizeof(td->axismtx)); @@ -2694,36 +2720,43 @@ static void createTransUVs(bContext *C, TransInfo *t) ToolSettings *ts = CTX_data_tool_settings(C); TransData *td = NULL; TransData2D *td2d = NULL; - MTexPoly *tf; - MLoopUV *luv; BMEditMesh *em = BKE_editmesh_from_object(t->obedit); BMFace *efa; - BMLoop *l; BMIter iter, liter; UvElementMap *elementmap = NULL; BLI_bitmap *island_enabled = NULL; + struct { float co[2]; int co_num; } *island_center = NULL; int count = 0, countsel = 0, count_rejected = 0; - const bool propmode = (t->flag & T_PROP_EDIT) != 0; - const bool propconnected = (t->flag & T_PROP_CONNECTED) != 0; - + const bool is_prop_edit = (t->flag & T_PROP_EDIT) != 0; + const bool is_prop_connected = (t->flag & T_PROP_CONNECTED) != 0; + const bool is_island_center = (t->around == V3D_LOCAL); const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); + const int cd_poly_tex_offset = CustomData_get_offset(&em->bm->pdata, CD_MTEXPOLY); - if (!ED_space_image_show_uvedit(sima, t->obedit)) return; + if (!ED_space_image_show_uvedit(sima, t->obedit)) + return; /* count */ - if (propconnected) { + if (is_prop_connected || is_island_center) { /* create element map with island information */ - if (ts->uv_flag & UV_SYNC_SELECTION) { - elementmap = BM_uv_element_map_create(em->bm, false, true); + const bool use_facesel = (ts->uv_flag & UV_SYNC_SELECTION) == 0; + elementmap = BM_uv_element_map_create(em->bm, use_facesel, false, true); + if (elementmap == NULL) { + return; } - else { - elementmap = BM_uv_element_map_create(em->bm, true, true); + + if (is_prop_connected) { + island_enabled = BLI_BITMAP_NEW(elementmap->totalIslands, "TransIslandData(UV Editing)"); + } + + if (is_island_center) { + island_center = MEM_callocN(sizeof(*island_center) * elementmap->totalIslands, __func__); } - island_enabled = BLI_BITMAP_NEW(elementmap->totalIslands, "TransIslandData(UV Editing)"); } BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - tf = CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY); + MTexPoly *tf = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset); + BMLoop *l; if (!uvedit_face_visible_test(scene, ima, efa, tf)) { BM_elem_flag_disable(efa, BM_ELEM_TAG); @@ -2735,14 +2768,25 @@ static void createTransUVs(bContext *C, TransInfo *t) if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) { countsel++; - if (propconnected) { + if (is_prop_connected || island_center) { UvElement *element = BM_uv_element_get(elementmap, efa, l); - BLI_BITMAP_ENABLE(island_enabled, element->island); - } + if (is_prop_connected) { + BLI_BITMAP_ENABLE(island_enabled, element->island); + } + + if (is_island_center) { + if (element->flag == false) { + MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); + add_v2_v2(island_center[element->island].co, luv->uv); + island_center[element->island].co_num++; + element->flag = true; + } + } + } } - if (propmode) { + if (is_prop_edit) { count++; } } @@ -2750,13 +2794,19 @@ static void createTransUVs(bContext *C, TransInfo *t) /* note: in prop mode we need at least 1 selected */ if (countsel == 0) { - if (propconnected) { - MEM_freeN(island_enabled); + goto finally; + } + + if (is_island_center) { + int i; + + for (i = 0; i < elementmap->totalIslands; i++) { + mul_v2_fl(island_center[i].co, 1.0f / island_center[i].co_num); + mul_v2_v2(island_center[i].co, t->aspect); } - return; } - t->total = (propmode) ? count : countsel; + t->total = (is_prop_edit) ? count : countsel; t->data = MEM_callocN(t->total * sizeof(TransData), "TransObData(UV Editing)"); /* for each 2d uv coord a 3d vector is allocated, so that they can be * treated just as if they were 3d verts */ @@ -2769,56 +2819,88 @@ static void createTransUVs(bContext *C, TransInfo *t) td2d = t->data2d; BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { + BMLoop *l; + if (!BM_elem_flag_test(efa, BM_ELEM_TAG)) continue; BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { - if (!propmode && !uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) + const bool selected = uvedit_uv_select_test(scene, l, cd_loop_uv_offset); + MLoopUV *luv; + const float *center = NULL; + + if (!is_prop_edit && !selected) continue; - if (propconnected) { + if (is_prop_connected || is_island_center) { UvElement *element = BM_uv_element_get(elementmap, efa, l); - if (!BLI_BITMAP_TEST(island_enabled, element->island)) { - count_rejected++; - continue; + + if (is_prop_connected) { + if (!BLI_BITMAP_TEST(island_enabled, element->island)) { + count_rejected++; + continue; + } + } + + if (is_island_center) { + center = island_center[element->island].co; } } + BM_elem_flag_enable(l, BM_ELEM_TAG); luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); - UVsToTransData(sima, td++, td2d++, luv->uv, uvedit_uv_select_test(scene, l, cd_loop_uv_offset)); + UVsToTransData(t->aspect, td++, td2d++, luv->uv, center, selected); } } - if (propconnected) { + if (is_prop_connected) { t->total -= count_rejected; - BM_uv_element_map_free(elementmap); - MEM_freeN(island_enabled); } if (sima->flag & SI_LIVE_UNWRAP) ED_uvedit_live_unwrap_begin(t->scene, t->obedit); + + +finally: + if (is_prop_connected || is_island_center) { + BM_uv_element_map_free(elementmap); + + if (is_prop_connected) { + MEM_freeN(island_enabled); + } + + if (island_center) { + MEM_freeN(island_center); + } + } } void flushTransUVs(TransInfo *t) { SpaceImage *sima = t->sa->spacedata.first; TransData2D *td; - int a, width, height; - float aspx, aspy, invx, invy; + int a; + float aspect_inv[2], size[2]; + const bool use_pixel_snap = ((sima->flag & SI_PIXELSNAP) && (t->state != TRANS_CANCEL)); - ED_space_image_get_uv_aspect(sima, &aspx, &aspy); - ED_space_image_get_size(sima, &width, &height); - invx = 1.0f / aspx; - invy = 1.0f / aspy; + aspect_inv[0] = 1.0f / t->aspect[0]; + aspect_inv[1] = 1.0f / t->aspect[1]; + + if (use_pixel_snap) { + int size_i[2]; + ED_space_image_get_size(sima, &size_i[0], &size_i[1]); + size[0] = size_i[0]; + size[1] = size_i[1]; + } /* flush to 2d vector from internally used 3d vector */ for (a = 0, td = t->data2d; a < t->total; a++, td++) { - td->loc2d[0] = td->loc[0] * invx; - td->loc2d[1] = td->loc[1] * invy; + td->loc2d[0] = td->loc[0] * aspect_inv[0]; + td->loc2d[1] = td->loc[1] * aspect_inv[1]; - if ((sima->flag & SI_PIXELSNAP) && (t->state != TRANS_CANCEL)) { - td->loc2d[0] = roundf(width * td->loc2d[0]) / width; - td->loc2d[1] = roundf(height * td->loc2d[1]) / height; + if (use_pixel_snap) { + td->loc2d[0] = roundf(td->loc2d[0] * size[0]) / size[0]; + td->loc2d[1] = roundf(td->loc2d[1] * size[1]) / size[1]; } } } @@ -2826,44 +2908,45 @@ void flushTransUVs(TransInfo *t) bool clipUVTransform(TransInfo *t, float vec[2], const bool resize) { TransData *td; - int a, clipx = 1, clipy = 1; - float aspx, aspy, min[2], max[2]; + int a; + bool clipx = true, clipy = true; + float min[2], max[2]; - ED_space_image_get_uv_aspect(t->sa->spacedata.first, &aspx, &aspy); min[0] = min[1] = 0.0f; - max[0] = aspx; max[1] = aspy; + max[0] = t->aspect[0]; + max[1] = t->aspect[1]; for (a = 0, td = t->data; a < t->total; a++, td++) { minmax_v2v2_v2(min, max, td->loc); } if (resize) { - if (min[0] < 0.0f && t->center[0] > 0.0f && t->center[0] < aspx * 0.5f) + if (min[0] < 0.0f && t->center[0] > 0.0f && t->center[0] < t->aspect[0] * 0.5f) vec[0] *= t->center[0] / (t->center[0] - min[0]); - else if (max[0] > aspx && t->center[0] < aspx) - vec[0] *= (t->center[0] - aspx) / (t->center[0] - max[0]); + else if (max[0] > t->aspect[0] && t->center[0] < t->aspect[0]) + vec[0] *= (t->center[0] - t->aspect[0]) / (t->center[0] - max[0]); else clipx = 0; - if (min[1] < 0.0f && t->center[1] > 0.0f && t->center[1] < aspy * 0.5f) + if (min[1] < 0.0f && t->center[1] > 0.0f && t->center[1] < t->aspect[1] * 0.5f) vec[1] *= t->center[1] / (t->center[1] - min[1]); - else if (max[1] > aspy && t->center[1] < aspy) - vec[1] *= (t->center[1] - aspy) / (t->center[1] - max[1]); + else if (max[1] > t->aspect[1] && t->center[1] < t->aspect[1]) + vec[1] *= (t->center[1] - t->aspect[1]) / (t->center[1] - max[1]); else clipy = 0; } else { if (min[0] < 0.0f) vec[0] -= min[0]; - else if (max[0] > aspx) - vec[0] -= max[0] - aspx; + else if (max[0] > t->aspect[0]) + vec[0] -= max[0] - t->aspect[0]; else clipx = 0; if (min[1] < 0.0f) vec[1] -= min[1]; - else if (max[1] > aspy) - vec[1] -= max[1] - aspy; + else if (max[1] > t->aspect[1]) + vec[1] -= max[1] - t->aspect[1]; else clipy = 0; } @@ -2875,9 +2958,6 @@ void clipUVData(TransInfo *t) { TransData *td = NULL; int a; - float aspx, aspy; - - ED_space_image_get_uv_aspect(t->sa->spacedata.first, &aspx, &aspy); for (a = 0, td = t->data; a < t->total; a++, td++) { if (td->flag & TD_NOACTION) @@ -2886,8 +2966,8 @@ void clipUVData(TransInfo *t) if ((td->flag & TD_SKIP) || (!td->loc)) continue; - td->loc[0] = min_ff(max_ff(0.0f, td->loc[0]), aspx); - td->loc[1] = min_ff(max_ff(0.0f, td->loc[1]), aspy); + td->loc[0] = min_ff(max_ff(0.0f, td->loc[0]), t->aspect[0]); + td->loc[1] = min_ff(max_ff(0.0f, td->loc[1]), t->aspect[1]); } } @@ -3161,7 +3241,7 @@ static void posttrans_gpd_clean(bGPdata *gpd) bGPDframe *gpf, *gpfn; bool is_double = false; - BLI_listbase_sort_r(&gpl->frames, &is_double, gpf_cmp_frame); + BLI_listbase_sort_r(&gpl->frames, gpf_cmp_frame, &is_double); if (is_double) { for (gpf = gpl->frames.first; gpf; gpf = gpfn) { @@ -3188,7 +3268,7 @@ static void posttrans_mask_clean(Mask *mask) MaskLayerShape *masklay_shape, *masklay_shape_next; bool is_double = false; - BLI_listbase_sort_r(&masklay->splines_shapes, &is_double, masklay_shape_cmp_frame); + BLI_listbase_sort_r(&masklay->splines_shapes, masklay_shape_cmp_frame, &is_double); if (is_double) { for (masklay_shape = masklay->splines_shapes.first; masklay_shape; masklay_shape = masklay_shape_next) { @@ -3304,76 +3384,90 @@ static void posttrans_action_clean(bAnimContext *ac, bAction *act) /* ----------------------------- */ /* fully select selected beztriples, but only include if it's on the right side of cfra */ -static int count_fcurve_keys(FCurve *fcu, char side, float cfra) +static int count_fcurve_keys(FCurve *fcu, char side, float cfra, bool is_prop_edit) { BezTriple *bezt; - int i, count = 0; + int i, count = 0, count_all = 0; if (ELEM(NULL, fcu, fcu->bezt)) return count; /* only include points that occur on the right side of cfra */ for (i = 0, bezt = fcu->bezt; i < fcu->totvert; i++, bezt++) { - if (bezt->f2 & SELECT) { + if (FrameOnMouseSide(side, bezt->vec[1][0], cfra)) { /* no need to adjust the handle selection since they are assumed * selected (like graph editor with SIPO_NOHANDLES) */ - if (FrameOnMouseSide(side, bezt->vec[1][0], cfra)) { - count += 1; - } + if (bezt->f2 & SELECT) + count++; + + count_all++; } } - return count; + if (is_prop_edit && count > 0) + return count_all; + else return count; } /* fully select selected beztriples, but only include if it's on the right side of cfra */ -static int count_gplayer_frames(bGPDlayer *gpl, char side, float cfra) +static int count_gplayer_frames(bGPDlayer *gpl, char side, float cfra, bool is_prop_edit) { bGPDframe *gpf; - int count = 0; + int count = 0, count_all = 0; if (gpl == NULL) return count; /* only include points that occur on the right side of cfra */ for (gpf = gpl->frames.first; gpf; gpf = gpf->next) { - if (gpf->flag & GP_FRAME_SELECT) { - if (FrameOnMouseSide(side, (float)gpf->framenum, cfra)) + if (FrameOnMouseSide(side, (float)gpf->framenum, cfra)) { + if (gpf->flag & GP_FRAME_SELECT) count++; + count_all++; } } - return count; + if (is_prop_edit && count > 0) + return count_all; + else + return count; } /* fully select selected beztriples, but only include if it's on the right side of cfra */ -static int count_masklayer_frames(MaskLayer *masklay, char side, float cfra) +static int count_masklayer_frames(MaskLayer *masklay, char side, float cfra, bool is_prop_edit) { MaskLayerShape *masklayer_shape; - int count = 0; + int count = 0, count_all = 0; if (masklay == NULL) return count; /* only include points that occur on the right side of cfra */ for (masklayer_shape = masklay->splines_shapes.first; masklayer_shape; masklayer_shape = masklayer_shape->next) { - if (masklayer_shape->flag & MASK_SHAPE_SELECT) { - if (FrameOnMouseSide(side, (float)masklayer_shape->frame, cfra)) + if (FrameOnMouseSide(side, (float)masklayer_shape->frame, cfra)) { + if (masklayer_shape->flag & MASK_SHAPE_SELECT) count++; + count_all++; } } - return count; + if (is_prop_edit && count > 0) + return count_all; + else + return count; } /* This function assigns the information to transdata */ -static void TimeToTransData(TransData *td, float *time, AnimData *adt) +static void TimeToTransData(TransData *td, float *time, AnimData *adt, float ypos) { /* memory is calloc'ed, so that should zero everything nicely for us */ td->val = time; td->ival = *(time); + td->center[0] = td->ival; + td->center[1] = ypos; + /* store the AnimData where this keyframe exists as a keyframe of the * active action as td->extra. */ @@ -3387,7 +3481,7 @@ static void TimeToTransData(TransData *td, float *time, AnimData *adt) * The 'side' argument is needed for the extend mode. 'B' = both sides, 'R'/'L' mean only data * on the named side are used. */ -static TransData *ActionFCurveToTransData(TransData *td, TransData2D **td2dv, FCurve *fcu, AnimData *adt, char side, float cfra) +static TransData *ActionFCurveToTransData(TransData *td, TransData2D **td2dv, FCurve *fcu, AnimData *adt, char side, float cfra, bool is_prop_edit, float ypos) { BezTriple *bezt; TransData2D *td2d = *td2dv; @@ -3398,11 +3492,14 @@ static TransData *ActionFCurveToTransData(TransData *td, TransData2D **td2dv, FC for (i = 0, bezt = fcu->bezt; i < fcu->totvert; i++, bezt++) { /* only add selected keyframes (for now, proportional edit is not enabled) */ - if (bezt->f2 & SELECT) { /* note this MUST match count_fcurve_keys(), so can't use BEZSELECTED() macro */ + if (is_prop_edit || (bezt->f2 & SELECT)) { /* note this MUST match count_fcurve_keys(), so can't use BEZSELECTED() macro */ /* only add if on the right 'side' of the current frame */ if (FrameOnMouseSide(side, bezt->vec[1][0], cfra)) { - TimeToTransData(td, bezt->vec[1], adt); + TimeToTransData(td, bezt->vec[1], adt, ypos); + if (bezt->f2 & SELECT) + td->flag |= TD_SELECTED; + /*set flags to move handles as necessary*/ td->flag |= TD_MOVEHANDLE1 | TD_MOVEHANDLE2; td2d->h1 = bezt->vec[0]; @@ -3453,19 +3550,22 @@ void flushTransIntFrameActionData(TransInfo *t) * The 'side' argument is needed for the extend mode. 'B' = both sides, 'R'/'L' mean only data * on the named side are used. */ -static int GPLayerToTransData(TransData *td, tGPFtransdata *tfd, bGPDlayer *gpl, char side, float cfra) +static int GPLayerToTransData(TransData *td, tGPFtransdata *tfd, bGPDlayer *gpl, char side, float cfra, bool is_prop_edit, float ypos) { bGPDframe *gpf; int count = 0; /* check for select frames on right side of current frame */ for (gpf = gpl->frames.first; gpf; gpf = gpf->next) { - if (gpf->flag & GP_FRAME_SELECT) { + if (is_prop_edit || (gpf->flag & GP_FRAME_SELECT)) { if (FrameOnMouseSide(side, (float)gpf->framenum, cfra)) { /* memory is calloc'ed, so that should zero everything nicely for us */ td->val = &tfd->val; td->ival = (float)gpf->framenum; + td->center[0] = td->ival; + td->center[1] = ypos; + tfd->val = (float)gpf->framenum; tfd->sdata = &gpf->framenum; @@ -3481,19 +3581,22 @@ static int GPLayerToTransData(TransData *td, tGPFtransdata *tfd, bGPDlayer *gpl, } /* refer to comment above #GPLayerToTransData, this is the same but for masks */ -static int MaskLayerToTransData(TransData *td, tGPFtransdata *tfd, MaskLayer *masklay, char side, float cfra) +static int MaskLayerToTransData(TransData *td, tGPFtransdata *tfd, MaskLayer *masklay, char side, float cfra, bool is_prop_edit, float ypos) { MaskLayerShape *masklay_shape; int count = 0; /* check for select frames on right side of current frame */ for (masklay_shape = masklay->splines_shapes.first; masklay_shape; masklay_shape = masklay_shape->next) { - if (masklay_shape->flag & MASK_SHAPE_SELECT) { + if (is_prop_edit || (masklay_shape->flag & MASK_SHAPE_SELECT)) { if (FrameOnMouseSide(side, (float)masklay_shape->frame, cfra)) { /* memory is calloc'ed, so that should zero everything nicely for us */ td->val = &tfd->val; td->ival = (float)masklay_shape->frame; + td->center[0] = td->ival; + td->center[1] = ypos; + tfd->val = (float)masklay_shape->frame; tfd->sdata = &masklay_shape->frame; @@ -3515,15 +3618,25 @@ static void createTransActionData(bContext *C, TransInfo *t) TransData *td = NULL; TransData2D *td2d = NULL; tGPFtransdata *tfd = NULL; - + + 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); + bAnimContext ac; ListBase anim_data = {NULL, NULL}; bAnimListElem *ale; int filter; - + const bool is_prop_edit = (t->flag & T_PROP_EDIT) != 0; + int count = 0; float cfra; - + float ypos = 1.0f / ((ysize / xsize) * (xmask / ymask)) * BLI_rctf_cent_y(&t->ar->v2d.cur); + /* determine what type of data we are operating on */ if (ANIM_animdata_get_context(C, &ac) == 0) return; @@ -3551,7 +3664,7 @@ static void createTransActionData(bContext *C, TransInfo *t) /* loop 1: fully select ipo-keys and count how many BezTriples are selected */ for (ale = anim_data.first; ale; ale = ale->next) { AnimData *adt = ANIM_nla_mapping_get(&ac, ale); - + int adt_count = 0; /* convert current-frame to action-time (slightly less accurate, especially under * higher scaling ratios, but is faster than converting all points) */ @@ -3560,14 +3673,19 @@ static void createTransActionData(bContext *C, TransInfo *t) else cfra = (float)CFRA; - if (ale->type == ANIMTYPE_FCURVE) - count += count_fcurve_keys(ale->key_data, t->frame_side, cfra); + if (ELEM(ale->type, ANIMTYPE_FCURVE, ANIMTYPE_NLACURVE)) + adt_count = count_fcurve_keys(ale->key_data, t->frame_side, cfra, is_prop_edit); else if (ale->type == ANIMTYPE_GPLAYER) - count += count_gplayer_frames(ale->data, t->frame_side, cfra); + adt_count = count_gplayer_frames(ale->data, t->frame_side, cfra, is_prop_edit); else if (ale->type == ANIMTYPE_MASKLAYER) - count += count_masklayer_frames(ale->data, t->frame_side, cfra); + adt_count = count_masklayer_frames(ale->data, t->frame_side, cfra, is_prop_edit); else BLI_assert(0); + + if (adt_count > 0) { + count += adt_count; + ale->tag = true; + } } /* stop if trying to build list if nothing selected */ @@ -3604,11 +3722,22 @@ static void createTransActionData(bContext *C, TransInfo *t) /* loop 2: build transdata array */ for (ale = anim_data.first; ale; ale = ale->next) { + AnimData *adt; + + if (is_prop_edit && !ale->tag) + continue; + + adt = ANIM_nla_mapping_get(&ac, ale); + if (adt) + cfra = BKE_nla_tweakedit_remap(adt, (float)CFRA, NLATIME_CONVERT_UNMAP); + else + cfra = (float)CFRA; + if (ale->type == ANIMTYPE_GPLAYER) { bGPDlayer *gpl = (bGPDlayer *)ale->data; int i; - i = GPLayerToTransData(td, tfd, gpl, t->frame_side, cfra); + i = GPLayerToTransData(td, tfd, gpl, t->frame_side, cfra, is_prop_edit, ypos); td += i; tfd += i; } @@ -3616,7 +3745,7 @@ static void createTransActionData(bContext *C, TransInfo *t) MaskLayer *masklay = (MaskLayer *)ale->data; int i; - i = MaskLayerToTransData(td, tfd, masklay, t->frame_side, cfra); + i = MaskLayerToTransData(td, tfd, masklay, t->frame_side, cfra, is_prop_edit, ypos); td += i; tfd += i; } @@ -3624,15 +3753,7 @@ static void createTransActionData(bContext *C, TransInfo *t) AnimData *adt = ANIM_nla_mapping_get(&ac, ale); FCurve *fcu = (FCurve *)ale->key_data; - /* 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; - - td = ActionFCurveToTransData(td, &td2d, fcu, adt, t->frame_side, cfra); + td = ActionFCurveToTransData(td, &td2d, fcu, adt, t->frame_side, cfra, is_prop_edit, ypos); } } @@ -3661,6 +3782,109 @@ static void createTransActionData(bContext *C, TransInfo *t) *((float *)(t->customData) + 1) = max; } + /* calculate distances for proportional editing */ + if (is_prop_edit) { + td = t->data; + + for (ale = anim_data.first; ale; ale = ale->next) { + AnimData *adt; + + /* F-Curve may not have any keyframes */ + if (!ale->tag) + continue; + + adt = ANIM_nla_mapping_get(&ac, ale); + if (adt) + cfra = BKE_nla_tweakedit_remap(adt, (float)CFRA, NLATIME_CONVERT_UNMAP); + else + cfra = (float)CFRA; + + if (ale->type == ANIMTYPE_GPLAYER) { + bGPDlayer *gpl = (bGPDlayer *)ale->data; + bGPDframe *gpf; + + for (gpf = gpl->frames.first; gpf; gpf = gpf->next) { + if (gpf->flag & GP_FRAME_SELECT) { + td->dist = td->rdist = 0.0f; + } + else { + bGPDframe *gpf_iter; + int min = INT_MAX; + for (gpf_iter = gpl->frames.first; gpf_iter; gpf_iter = gpf->next) { + if (gpf_iter->flag & GP_FRAME_SELECT) { + if (FrameOnMouseSide(t->frame_side, (float)gpf_iter->framenum, cfra)) { + int val = abs(gpf->framenum - gpf_iter->framenum); + if (val < min) { + min = val; + } + } + } + } + td->dist = td->rdist = min; + } + td++; + } + } + else if (ale->type == ANIMTYPE_MASKLAYER) { + MaskLayer *masklay = (MaskLayer *)ale->data; + MaskLayerShape *masklay_shape; + + for (masklay_shape = masklay->splines_shapes.first; masklay_shape; masklay_shape = masklay_shape->next) { + if (FrameOnMouseSide(t->frame_side, (float)masklay_shape->frame, cfra)) { + if (masklay_shape->flag & MASK_SHAPE_SELECT) { + td->dist = td->rdist = 0.0f; + } + else { + MaskLayerShape *masklay_iter; + int min = INT_MAX; + for (masklay_iter = masklay->splines_shapes.first; masklay_iter; masklay_iter = masklay_iter->next) { + if (masklay_iter->flag & MASK_SHAPE_SELECT) { + if (FrameOnMouseSide(t->frame_side, (float)masklay_iter->frame, cfra)) { + int val = abs(masklay_shape->frame - masklay_iter->frame); + if (val < min) { + min = val; + } + } + } + } + td->dist = td->rdist = min; + } + td++; + } + } + } + else { + FCurve *fcu = (FCurve *)ale->key_data; + BezTriple *bezt; + int i; + + for (i = 0, bezt = fcu->bezt; i < fcu->totvert; i++, bezt++) { + if (FrameOnMouseSide(t->frame_side, bezt->vec[1][0], cfra)) { + if (bezt->f2 & SELECT) { + td->dist = td->rdist = 0.0f; + } + else { + BezTriple *bezt_iter; + int j; + float min = FLT_MAX; + for (j = 0, bezt_iter = fcu->bezt; j < fcu->totvert; j++, bezt_iter++) { + if (bezt_iter->f2 & SELECT) { + if (FrameOnMouseSide(t->frame_side, (float)bezt_iter->vec[1][0], cfra)) { + float val = fabs(bezt->vec[1][0] - bezt_iter->vec[1][0]); + if (val < min) + min = val; + } + } + } + td->dist = td->rdist = min; + } + td++; + } + } + } + } + } + /* cleanup temp list */ ANIM_animdata_freelist(&anim_data); } @@ -3669,6 +3893,7 @@ static void createTransActionData(bContext *C, TransInfo *t) typedef struct TransDataGraph { float unit_scale; + float offset; } TransDataGraph; /* Helper function for createTransGraphEditData, which is responsible for associating @@ -3677,7 +3902,7 @@ typedef struct TransDataGraph { static void bezt_to_transdata(TransData *td, TransData2D *td2d, TransDataGraph *tdg, AnimData *adt, BezTriple *bezt, int bi, bool selected, bool ishandle, bool intvals, - float mtx[3][3], float smtx[3][3], float unit_scale) + float mtx[3][3], float smtx[3][3], float unit_scale, float offset) { float *loc = bezt->vec[bi]; const float *cent = bezt->vec[1]; @@ -3691,26 +3916,26 @@ static void bezt_to_transdata(TransData *td, TransData2D *td2d, TransDataGraph * if (adt) { td2d->loc[0] = BKE_nla_tweakedit_remap(adt, loc[0], NLATIME_CONVERT_MAP); - td2d->loc[1] = loc[1] * unit_scale; + td2d->loc[1] = (loc[1] + offset) * unit_scale; td2d->loc[2] = 0.0f; td2d->loc2d = loc; td->loc = td2d->loc; td->center[0] = BKE_nla_tweakedit_remap(adt, cent[0], NLATIME_CONVERT_MAP); - td->center[1] = cent[1] * unit_scale; + td->center[1] = (cent[1] + offset) * unit_scale; td->center[2] = 0.0f; copy_v3_v3(td->iloc, td->loc); } else { td2d->loc[0] = loc[0]; - td2d->loc[1] = loc[1] * unit_scale; + td2d->loc[1] = (loc[1] + offset) * unit_scale; td2d->loc[2] = 0.0f; td2d->loc2d = loc; td->loc = td2d->loc; copy_v3_v3(td->center, cent); - td->center[1] *= unit_scale; + td->center[1] = (td->center[1] + offset) * unit_scale; copy_v3_v3(td->iloc, td->loc); } @@ -3750,6 +3975,7 @@ static void bezt_to_transdata(TransData *td, TransData2D *td2d, TransDataGraph * copy_m3_m3(td->smtx, smtx); tdg->unit_scale = unit_scale; + tdg->offset = offset; } static bool graph_edit_is_translation_mode(TransInfo *t) @@ -3762,6 +3988,29 @@ 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(TransInfo *t, FCurve *fcu, TransData *td_start, TransData *td, int cfra, 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; + 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 || sel3) { + td->dist = td->rdist = 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; @@ -3784,6 +4033,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 is_prop_edit = (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 */ @@ -3815,6 +4065,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) @@ -3835,20 +4087,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 (is_prop_edit) { + 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 (is_prop_edit) { + if (selected) { + count += curvecount; + ale->tag = true; } } } @@ -3897,11 +4163,11 @@ static void createTransGraphEditData(bContext *C, TransInfo *t) AnimData *adt = ANIM_nla_mapping_get(&ac, ale); FCurve *fcu = (FCurve *)ale->key_data; bool intvals = (fcu->flag & FCURVE_INT_VALUES) != 0; - float unit_scale; + float unit_scale, offset; float cfra; /* F-Curve may not have any keyframes */ - if (fcu->bezt == NULL) + if (fcu->bezt == NULL || (is_prop_edit && ale->tag == 0)) continue; /* convert current-frame to action-time (slightly less accurate, especially under @@ -3912,7 +4178,7 @@ static void createTransGraphEditData(bContext *C, TransInfo *t) else cfra = (float)CFRA; - unit_scale = ANIM_unit_mapping_get_factor(ac.scene, ale->id, ale->key_data, anim_map_flag); + unit_scale = ANIM_unit_mapping_get_factor(ac.scene, ale->id, ale->key_data, anim_map_flag, &offset); /* 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++) { @@ -3924,66 +4190,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 (is_prop_edit) { + 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, offset); + initTransDataCurveHandles(td, bezt); + bezt_to_transdata(td++, td2d++, tdg++, adt, bezt, 1, is_sel, false, intvals, mtx, smtx, unit_scale, offset); + initTransDataCurveHandles(td, bezt); + bezt_to_transdata(td++, td2d++, tdg++, adt, bezt, 2, is_sel, true, intvals, mtx, smtx, unit_scale, offset); + } + 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, offset); + } + 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, offset); + } + 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, offset); + } - - 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 (is_prop_edit) { + /* 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 = td->rdist = 0.0f; } else { - /* h2 = 0; */ /* UNUSED */ + graph_key_shortest_dist(t, fcu, td_start, td, cfra, 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 = td->rdist = 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(t, fcu, td_start, td, cfra, 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 = td->rdist = 0.0f; + } + else { + graph_key_shortest_dist(t, fcu, td_start, td, cfra, use_handle); } + td++; } } } - - /* Sets handles based on the selection */ - testhandles_fcurve(fcu, use_handle); } - + /* cleanup temp list */ ANIM_animdata_freelist(&anim_data); } @@ -4267,7 +4602,7 @@ void flushTransGraphData(TransInfo *t) if (td->flag & TD_INTVALUES) td2d->loc2d[1] = floorf(td2d->loc[1] + 0.5f); else - td2d->loc2d[1] = td2d->loc[1] * inv_unit_scale; + td2d->loc2d[1] = td2d->loc[1] * inv_unit_scale - tdg->offset; if ((td->flag & TD_MOVEHANDLE1) && td2d->h1) { td2d->h1[0] = td2d->ih1[0] + td->loc[0] - td->iloc[0]; @@ -5080,7 +5415,9 @@ static void set_trans_object_base_flags(TransInfo *t) } /* all recalc flags get flushed to all layers, so a layer flip later on works fine */ +#ifdef WITH_LEGACY_DEPSGRAPH DAG_scene_flush_update(G.main, t->scene, -1, 0); +#endif /* and we store them temporal in base (only used for transform code) */ /* this because after doing updates, the object->recalc is cleared */ @@ -5157,7 +5494,9 @@ static int count_proportional_objects(TransInfo *t) /* all recalc flags get flushed to all layers, so a layer flip later on works fine */ DAG_scene_relations_update(G.main, t->scene); +#ifdef WITH_LEGACY_DEPSGRAPH DAG_scene_flush_update(G.main, t->scene, -1, 0); +#endif /* and we store them temporal in base (only used for transform code) */ /* this because after doing updates, the object->recalc is cleared */ @@ -6039,7 +6378,7 @@ static void createTransObject(bContext *C, TransInfo *t) TransData *td = NULL; TransDataExtension *tx; - int propmode = t->flag & T_PROP_EDIT; + const bool is_prop_edit = (t->flag & T_PROP_EDIT) != 0; set_trans_object_base_flags(t); @@ -6052,7 +6391,7 @@ static void createTransObject(bContext *C, TransInfo *t) return; } - if (propmode) { + if (is_prop_edit) { t->total += count_proportional_objects(t); } @@ -6085,7 +6424,7 @@ static void createTransObject(bContext *C, TransInfo *t) } CTX_DATA_END; - if (propmode) { + if (is_prop_edit) { View3D *v3d = t->view; Base *base; @@ -6239,22 +6578,22 @@ typedef struct TransDataTracking { static void markerToTransDataInit(TransData *td, TransData2D *td2d, TransDataTracking *tdt, MovieTrackingTrack *track, MovieTrackingMarker *marker, - int area, float loc[2], float rel[2], const float off[2], float aspx, float aspy) + int area, float loc[2], float rel[2], const float off[2], const float aspect[2]) { int anchor = area == TRACK_AREA_POINT && off; tdt->mode = transDataTracking_ModeTracks; if (anchor) { - td2d->loc[0] = rel[0] * aspx; /* hold original location */ - td2d->loc[1] = rel[1] * aspy; + td2d->loc[0] = rel[0] * aspect[0]; /* hold original location */ + td2d->loc[1] = rel[1] * aspect[1]; tdt->loc = loc; td2d->loc2d = loc; /* current location */ } else { - td2d->loc[0] = loc[0] * aspx; /* hold original location */ - td2d->loc[1] = loc[1] * aspy; + td2d->loc[0] = loc[0] * aspect[0]; /* hold original location */ + td2d->loc[1] = loc[1] * aspect[1]; td2d->loc2d = loc; /* current location */ } @@ -6269,8 +6608,8 @@ static void markerToTransDataInit(TransData *td, TransData2D *td2d, TransDataTra if (rel) { if (!anchor) { - td2d->loc[0] += rel[0] * aspx; - td2d->loc[1] += rel[1] * aspy; + td2d->loc[0] += rel[0] * aspect[0]; + td2d->loc[1] += rel[1] * aspect[1]; } copy_v2_v2(tdt->srelative, rel); @@ -6285,8 +6624,8 @@ static void markerToTransDataInit(TransData *td, TransData2D *td2d, TransDataTra //copy_v3_v3(td->center, td->loc); td->flag |= TD_INDIVIDUAL_SCALE; - td->center[0] = marker->pos[0] * aspx; - td->center[1] = marker->pos[1] * aspy; + td->center[0] = marker->pos[0] * aspect[0]; + td->center[1] = marker->pos[1] * aspect[1]; memset(td->axismtx, 0, sizeof(td->axismtx)); td->axismtx[2][2] = 1.0f; @@ -6301,8 +6640,9 @@ static void markerToTransDataInit(TransData *td, TransData2D *td2d, TransDataTra unit_m3(td->smtx); } -static void trackToTransData(const int framenr, TransData *td, TransData2D *td2d, - TransDataTracking *tdt, MovieTrackingTrack *track, float aspx, float aspy) +static void trackToTransData( + const int framenr, TransData *td, TransData2D *td2d, + TransDataTracking *tdt, MovieTrackingTrack *track, const float aspect[2]) { MovieTrackingMarker *marker = BKE_tracking_marker_ensure(track, framenr); @@ -6310,11 +6650,11 @@ static void trackToTransData(const int framenr, TransData *td, TransData2D *td2d marker->flag &= ~(MARKER_DISABLED | MARKER_TRACKED); markerToTransDataInit(td++, td2d++, tdt++, track, marker, TRACK_AREA_POINT, - track->offset, marker->pos, track->offset, aspx, aspy); + track->offset, marker->pos, track->offset, aspect); if (track->flag & SELECT) { markerToTransDataInit(td++, td2d++, tdt++, track, marker, TRACK_AREA_POINT, - marker->pos, NULL, NULL, aspx, aspy); + marker->pos, NULL, NULL, aspect); } if (track->pat_flag & SELECT) { @@ -6322,28 +6662,28 @@ static void trackToTransData(const int framenr, TransData *td, TransData2D *td2d for (a = 0; a < 4; a++) { markerToTransDataInit(td++, td2d++, tdt++, track, marker, TRACK_AREA_PAT, - marker->pattern_corners[a], marker->pos, NULL, aspx, aspy); + marker->pattern_corners[a], marker->pos, NULL, aspect); } } if (track->search_flag & SELECT) { markerToTransDataInit(td++, td2d++, tdt++, track, marker, TRACK_AREA_SEARCH, - marker->search_min, marker->pos, NULL, aspx, aspy); + marker->search_min, marker->pos, NULL, aspect); markerToTransDataInit(td++, td2d++, tdt++, track, marker, TRACK_AREA_SEARCH, - marker->search_max, marker->pos, NULL, aspx, aspy); + marker->search_max, marker->pos, NULL, aspect); } } static void planeMarkerToTransDataInit(TransData *td, TransData2D *td2d, TransDataTracking *tdt, MovieTrackingPlaneTrack *plane_track, float corner[2], - float aspx, float aspy) + const float aspect[2]) { tdt->mode = transDataTracking_ModePlaneTracks; tdt->plane_track = plane_track; - td2d->loc[0] = corner[0] * aspx; /* hold original location */ - td2d->loc[1] = corner[1] * aspy; + td2d->loc[0] = corner[0] * aspect[0]; /* hold original location */ + td2d->loc[1] = corner[1] * aspect[1]; td2d->loc2d = corner; /* current location */ td2d->loc[2] = 0.0f; @@ -6368,7 +6708,7 @@ static void planeMarkerToTransDataInit(TransData *td, TransData2D *td2d, TransDa static void planeTrackToTransData(const int framenr, TransData *td, TransData2D *td2d, TransDataTracking *tdt, MovieTrackingPlaneTrack *plane_track, - float aspx, float aspy) + const float aspect[2]) { MovieTrackingPlaneMarker *plane_marker = BKE_tracking_plane_marker_ensure(plane_track, framenr); int i; @@ -6377,7 +6717,7 @@ static void planeTrackToTransData(const int framenr, TransData *td, TransData2D plane_marker->flag &= ~PLANE_MARKER_TRACKED; for (i = 0; i < 4; i++) { - planeMarkerToTransDataInit(td++, td2d++, tdt++, plane_track, plane_marker->corners[i], aspx, aspy); + planeMarkerToTransDataInit(td++, td2d++, tdt++, plane_track, plane_marker->corners[i], aspect); } } @@ -6406,7 +6746,6 @@ static void createTransTrackingTracksData(bContext *C, TransInfo *t) MovieTrackingPlaneTrack *plane_track; TransDataTracking *tdt; int framenr = ED_space_clip_get_clip_frame_number(sc); - float aspx, aspy; /* count */ t->total = 0; @@ -6441,8 +6780,6 @@ static void createTransTrackingTracksData(bContext *C, TransInfo *t) if (t->total == 0) return; - ED_space_clip_get_aspect_dimension_aware(sc, &aspx, &aspy); - td = t->data = MEM_callocN(t->total * sizeof(TransData), "TransTracking TransData"); td2d = t->data2d = MEM_callocN(t->total * sizeof(TransData2D), "TransTracking TransData2D"); tdt = t->customData = MEM_callocN(t->total * sizeof(TransDataTracking), "TransTracking TransDataTracking"); @@ -6453,7 +6790,7 @@ static void createTransTrackingTracksData(bContext *C, TransInfo *t) track = tracksbase->first; while (track) { if (TRACK_VIEW_SELECTED(sc, track) && (track->flag & TRACK_LOCKED) == 0) { - trackToTransData(framenr, td, td2d, tdt, track, aspx, aspy); + trackToTransData(framenr, td, td2d, tdt, track, t->aspect); /* offset */ td++; @@ -6487,7 +6824,7 @@ static void createTransTrackingTracksData(bContext *C, TransInfo *t) plane_track = plane_track->next) { if (PLANE_TRACK_VIEW_SELECTED(plane_track)) { - planeTrackToTransData(framenr, td, td2d, tdt, plane_track, aspx, aspy); + planeTrackToTransData(framenr, td, td2d, tdt, plane_track, t->aspect); td += 4; td2d += 4; tdt += 4; @@ -6699,14 +7036,10 @@ static void cancelTransTracking(TransInfo *t) void flushTransTracking(TransInfo *t) { - SpaceClip *sc = t->sa->spacedata.first; TransData *td; TransData2D *td2d; TransDataTracking *tdt; int a; - float aspx, aspy; - - ED_space_clip_get_aspect_dimension_aware(sc, &aspx, &aspy); if (t->state == TRANS_CANCEL) cancelTransTracking(t); @@ -6720,8 +7053,8 @@ void flushTransTracking(TransInfo *t) continue; } - loc2d[0] = td2d->loc[0] / aspx; - loc2d[1] = td2d->loc[1] / aspy; + loc2d[0] = td2d->loc[0] / t->aspect[0]; + loc2d[1] = td2d->loc[1] / t->aspect[1]; if (t->flag & T_ALT_TRANSFORM) { if (t->mode == TFM_RESIZE) { @@ -6763,8 +7096,8 @@ void flushTransTracking(TransInfo *t) td2d->loc2d[tdt->coord] = tdt->prev_pos[tdt->coord] + td2d->loc[1] * tdt->scale; } else if (tdt->mode == transDataTracking_ModePlaneTracks) { - td2d->loc2d[0] = td2d->loc[0] / aspx; - td2d->loc2d[1] = td2d->loc[1] / aspy; + td2d->loc2d[0] = td2d->loc[0] / t->aspect[0]; + td2d->loc2d[1] = td2d->loc[1] / t->aspect[1]; } } } @@ -6842,9 +7175,10 @@ static void MaskHandleToTransData(MaskSplinePoint *point, eMaskWhichHandle which } } -static void MaskPointToTransData(Scene *scene, MaskSplinePoint *point, - TransData *td, TransData2D *td2d, TransDataMasking *tdm, - const int propmode, const float asp[2]) +static void MaskPointToTransData( + Scene *scene, MaskSplinePoint *point, + TransData *td, TransData2D *td2d, TransDataMasking *tdm, + const bool is_prop_edit, const float asp[2]) { BezTriple *bezt = &point->bezt; const bool is_sel_point = MASKPOINT_ISSEL_KNOT(point); @@ -6854,7 +7188,7 @@ static void MaskPointToTransData(Scene *scene, MaskSplinePoint *point, BKE_mask_point_parent_matrix_get(point, CFRA, parent_matrix); invert_m3_m3(parent_inverse_matrix, parent_matrix); - if (propmode || is_sel_point) { + if (is_prop_edit || is_sel_point) { int i; tdm->point = point; @@ -6974,7 +7308,7 @@ static void createTransMaskingData(bContext *C, TransInfo *t) TransData2D *td2d = NULL; TransDataMasking *tdm = NULL; int count = 0, countsel = 0; - int propmode = t->flag & T_PROP_EDIT; + const bool is_prop_edit = (t->flag & T_PROP_EDIT); float asp[2]; t->total = 0; @@ -7024,7 +7358,7 @@ static void createTransMaskingData(bContext *C, TransInfo *t) } } - if (propmode) + if (is_prop_edit) count += 3; } } @@ -7037,7 +7371,7 @@ static void createTransMaskingData(bContext *C, TransInfo *t) ED_mask_get_aspect(t->sa, t->ar, &asp[0], &asp[1]); - t->total = (propmode) ? count : countsel; + t->total = (is_prop_edit) ? count : countsel; td = t->data = MEM_callocN(t->total * sizeof(TransData), "TransObData(Mask Editing)"); /* for each 2d uv coord a 3d vector is allocated, so that they can be * treated just as if they were 3d verts */ @@ -7060,10 +7394,10 @@ static void createTransMaskingData(bContext *C, TransInfo *t) for (i = 0; i < spline->tot_point; i++) { MaskSplinePoint *point = &spline->points[i]; - if (propmode || MASKPOINT_ISSEL_ANY(point)) { - MaskPointToTransData(scene, point, td, td2d, tdm, propmode, asp); + if (is_prop_edit || MASKPOINT_ISSEL_ANY(point)) { + MaskPointToTransData(scene, point, td, td2d, tdm, is_prop_edit, asp); - if (propmode || MASKPOINT_ISSEL_KNOT(point)) { + if (is_prop_edit || MASKPOINT_ISSEL_KNOT(point)) { td += 3; td2d += 3; tdm += 3; @@ -7306,8 +7640,8 @@ static void createTransGPencil(bContext *C, TransInfo *t) const Scene *scene = CTX_data_scene(C); const int cfra = CFRA; - const int propedit = (t->flag & T_PROP_EDIT); - const int propedit_connected = (t->flag & T_PROP_CONNECTED); + const bool is_prop_edit = (t->flag & T_PROP_EDIT) != 0; + const bool is_prop_edit_connected = (t->flag & T_PROP_CONNECTED) != 0; /* == Grease Pencil Strokes to Transform Data == @@ -7338,9 +7672,9 @@ static void createTransGPencil(bContext *C, TransInfo *t) continue; } - if (propedit) { + if (is_prop_edit) { /* Proportional Editing... */ - if (propedit_connected) { + if (is_prop_edit_connected) { /* connected only - so only if selected */ if (gps->flag & GP_STROKE_SELECT) t->total += gps->totpoints; @@ -7447,8 +7781,8 @@ static void createTransGPencil(bContext *C, TransInfo *t) } /* What we need to include depends on proportional editing settings... */ - if (propedit) { - if (propedit_connected) { + if (is_prop_edit) { + if (is_prop_edit_connected) { /* A) "Connected" - Only those in selected strokes */ stroke_ok = (gps->flag & GP_STROKE_SELECT) != 0; } @@ -7467,7 +7801,7 @@ static void createTransGPencil(bContext *C, TransInfo *t) bGPDspoint *pt; int i; -#if 0 /* XXX: this isn't needed anymore; cannot calculate center this way or propedit breaks */ +#if 0 /* XXX: this isn't needed anymore; cannot calculate center this way or is_prop_edit breaks */ const float ninv = 1.0f / gps->totpoints; float center[3] = {0.0f}; @@ -7482,7 +7816,7 @@ static void createTransGPencil(bContext *C, TransInfo *t) bool point_ok; /* include point? */ - if (propedit) { + if (is_prop_edit) { /* Always all points in strokes that get included */ point_ok = true; } @@ -7525,7 +7859,7 @@ static void createTransGPencil(bContext *C, TransInfo *t) } /* March over these points, and calculate the proportional editing distances */ - if (propedit && (head != tail)) { + if (is_prop_edit && (head != tail)) { /* XXX: for now, we are similar enough that this works... */ calc_distanceCurveVerts(head, tail - 1); } @@ -7594,6 +7928,12 @@ void createTransData(bContext *C, TransInfo *t) else if (t->spacetype == SPACE_ACTION) { t->flag |= T_POINTS | T_2D_EDIT; createTransActionData(C, t); + + if (t->data && (t->flag & T_PROP_EDIT)) { + sort_trans_data(t); // makes selected become first in array + //set_prop_dist(t, false); /* don't do that, distance has been set in createTransActionData already */ + sort_trans_data_dist(t); + } } else if (t->spacetype == SPACE_NLA) { t->flag |= T_POINTS | T_2D_EDIT; @@ -7607,13 +7947,12 @@ 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)) { sort_trans_data(t); // makes selected become first in array - set_prop_dist(t, 1); + set_prop_dist(t, false); /* don't do that, distance has been set in createTransGraphEditData already */ sort_trans_data_dist(t); } -#endif } else if (t->spacetype == SPACE_NODE) { t->flag |= T_POINTS | T_2D_EDIT; diff --git a/source/blender/editors/transform/transform_generics.c b/source/blender/editors/transform/transform_generics.c index 5f02fa1b05f..90c806a2d05 100644 --- a/source/blender/editors/transform/transform_generics.c +++ b/source/blender/editors/transform/transform_generics.c @@ -80,6 +80,7 @@ #include "BKE_editmesh.h" #include "BKE_tracking.h" #include "BKE_mask.h" +#include "BKE_utildefines.h" #include "ED_anim_api.h" #include "ED_armature.h" @@ -808,10 +809,14 @@ static void recalcData_objects(TransInfo *t) ebo->rad_head *= ebo->length / ebo->oldlength; ebo->rad_tail *= ebo->length / ebo->oldlength; ebo->oldlength = ebo->length; + + if (ebo_parent) { + ebo_parent->rad_tail = ebo->rad_head; + } } } - if (!ELEM(t->mode, TFM_BONE_ROLL, TFM_BONE_ENVELOPE, TFM_BONESIZE)) { + if (!ELEM(t->mode, TFM_BONE_ROLL, TFM_BONE_ENVELOPE, TFM_BONE_ENVELOPE_DIST, TFM_BONESIZE)) { /* fix roll */ for (i = 0; i < t->total; i++, td++) { if (td->extra) { @@ -1065,6 +1070,8 @@ static int initTransInfo_edit_pet_to_flag(const int proportional) * Setup internal data, mouse, vectors * * \note \a op and \a event can be NULL + * + * \see #saveTransform does the reverse. */ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *event) { @@ -1121,6 +1128,7 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve zero_v3(t->vec); zero_v3(t->center); + zero_v3(t->center_global); unit_m3(t->mat); @@ -1156,6 +1164,19 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve t->spacetype = sa->spacetype; } + /* handle T_ALT_TRANSFORM initialization, we may use for different operators */ + if (op) { + const char *prop_id = NULL; + if (t->mode == TFM_SHRINKFATTEN) { + prop_id = "use_even_offset"; + } + + if (prop_id && (prop = RNA_struct_find_property(op->ptr, prop_id)) && + RNA_property_is_set(op->ptr, prop)) + { + BKE_BIT_TEST_SET(t->flag, RNA_property_boolean_get(op->ptr, prop), T_ALT_TRANSFORM); + } + } if (t->spacetype == SPACE_VIEW3D) { View3D *v3d = sa->spacedata.first; @@ -1316,7 +1337,13 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve /* use settings from scene only if modal */ if (t->flag & T_MODAL) { if ((t->options & CTX_NO_PET) == 0) { - if (t->obedit) { + if (t->spacetype == SPACE_IPO) { + t->flag |= initTransInfo_edit_pet_to_flag(ts->proportional_fcurve); + } + else if (t->spacetype == SPACE_ACTION) { + t->flag |= initTransInfo_edit_pet_to_flag(ts->proportional_action); + } + else if (t->obedit) { t->flag |= initTransInfo_edit_pet_to_flag(ts->proportional); } else if (t->options & CTX_GPENCIL_STROKES) { @@ -1375,6 +1402,7 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve #endif setTransformViewMatrices(t); + setTransformViewAspect(t, t->aspect); initNumInput(&t->num); } @@ -1541,6 +1569,19 @@ void calculateCenter2D(TransInfo *t) } } +void calculateCenterGlobal(TransInfo *t) +{ + /* setting constraint center */ + /* note, init functions may over-ride t->center */ + if (t->flag & (T_EDIT | T_POSE)) { + Object *ob = t->obedit ? t->obedit : t->poseobj; + mul_v3_m4v3(t->center_global, ob->obmat, t->center); + } + else { + copy_v3_v3(t->center_global, t->center); + } +} + void calculateCenterCursor(TransInfo *t, float r_center[3]) { const float *cursor; @@ -1569,30 +1610,17 @@ void calculateCenterCursor(TransInfo *t, float r_center[3]) void calculateCenterCursor2D(TransInfo *t, float r_center[2]) { - float aspx = 1.0, aspy = 1.0; const float *cursor = NULL; if (t->spacetype == SPACE_IMAGE) { SpaceImage *sima = (SpaceImage *)t->sa->spacedata.first; - if (t->options & CTX_MASK) { - ED_space_image_get_aspect(sima, &aspx, &aspy); - } - else { - ED_space_image_get_uv_aspect(sima, &aspx, &aspy); - } cursor = sima->cursor; } else if (t->spacetype == SPACE_CLIP) { SpaceClip *space_clip = (SpaceClip *) t->sa->spacedata.first; - if (t->options & CTX_MOVIECLIP) { - ED_space_clip_get_aspect_dimension_aware(space_clip, &aspx, &aspy); - } - else { - ED_space_clip_get_aspect(space_clip, &aspx, &aspy); - } cursor = space_clip->cursor; } - + if (cursor) { if (t->options & CTX_MASK) { float co[2]; @@ -1609,8 +1637,8 @@ void calculateCenterCursor2D(TransInfo *t, float r_center[2]) BLI_assert(!"Shall not happen"); } - r_center[0] = co[0] * aspx; - r_center[1] = co[1] * aspy; + r_center[0] = co[0] * t->aspect[0]; + r_center[1] = co[1] * t->aspect[1]; } else if (t->options & CTX_PAINT_CURVE) { if (t->spacetype == SPACE_IMAGE) { @@ -1619,8 +1647,8 @@ void calculateCenterCursor2D(TransInfo *t, float r_center[2]) } } else { - r_center[0] = cursor[0] * aspx; - r_center[1] = cursor[1] * aspy; + r_center[0] = cursor[0] * t->aspect[0]; + r_center[1] = cursor[1] * t->aspect[1]; } } } @@ -1755,14 +1783,8 @@ void calculateCenter(TransInfo *t) } calculateCenter2D(t); + calculateCenterGlobal(t); - /* setting constraint center */ - copy_v3_v3(t->con.center, t->center); - if (t->flag & (T_EDIT | T_POSE)) { - Object *ob = t->obedit ? t->obedit : t->poseobj; - mul_m4_v3(ob->obmat, t->con.center); - } - /* for panning from cameraview */ if (t->flag & T_OBJECT) { if (t->spacetype == SPACE_VIEW3D && t->ar && t->ar->regiontype == RGN_TYPE_WINDOW) { @@ -1783,7 +1805,7 @@ void calculateCenter(TransInfo *t) /* rotate only needs correct 2d center, grab needs ED_view3d_calc_zfac() value */ if (t->mode == TFM_TRANSLATION) { copy_v3_v3(t->center, axis); - copy_v3_v3(t->con.center, t->center); + copy_v3_v3(t->center_global, t->center); } } } diff --git a/source/blender/editors/transform/transform_manipulator.c b/source/blender/editors/transform/transform_manipulator.c index fc8e6cd0286..acc6108f264 100644 --- a/source/blender/editors/transform/transform_manipulator.c +++ b/source/blender/editors/transform/transform_manipulator.c @@ -512,7 +512,7 @@ static int calc_manipulator_stats(const bContext *C) for (k = 0, ek = point->keys; k < point->totkey; k++, ek++) { if (ek->flag & PEK_SELECT) { - calc_tw_center(scene, ek->flag & PEK_USE_WCO ? ek->world_co : ek->co); + calc_tw_center(scene, (ek->flag & PEK_USE_WCO) ? ek->world_co : ek->co); totsel++; } } @@ -895,6 +895,11 @@ static void postOrtho(const bool ortho) } } +BLI_INLINE bool manipulator_rotate_is_visible(const int drawflags) +{ + return (drawflags & (MAN_ROT_X | MAN_ROT_Y | MAN_ROT_Z)); +} + static void draw_manipulator_rotate( View3D *v3d, RegionView3D *rv3d, const int drawflags, const int combo, const bool is_moving, const bool is_picksel) @@ -908,8 +913,8 @@ static void draw_manipulator_rotate( const int colcode = (is_moving) ? MAN_MOVECOL : MAN_RGB; bool ortho; - /* when called while moving in mixed mode, do not draw when... */ - if ((drawflags & MAN_ROT_C) == 0) return; + /* skip drawing if all axes are locked */ + if (manipulator_rotate_is_visible(drawflags) == false) return; /* Init stuff */ glDisable(GL_DEPTH_TEST); @@ -1051,8 +1056,6 @@ static void draw_manipulator_rotate( glRotatef(90.0, 1.0, 0.0, 0.0); postOrtho(ortho); } - - if (arcs) glDisable(GL_CLIP_PLANE0); } // donut arcs if (arcs) { @@ -1448,8 +1451,8 @@ static void draw_manipulator_rotate_cyl( int axis_order[3] = {2, 0, 1}; int i; - /* when called while moving in mixed mode, do not draw when... */ - if ((drawflags & MAN_ROT_C) == 0) return; + /* skip drawing if all axes are locked */ + if (manipulator_rotate_is_visible(drawflags) == false) return; manipulator_axis_order(rv3d, axis_order); diff --git a/source/blender/editors/transform/transform_ops.c b/source/blender/editors/transform/transform_ops.c index e33bc19fc92..013e47886eb 100644 --- a/source/blender/editors/transform/transform_ops.c +++ b/source/blender/editors/transform/transform_ops.c @@ -38,6 +38,7 @@ #include "BKE_context.h" #include "BKE_global.h" #include "BKE_report.h" +#include "BKE_editmesh.h" #include "RNA_access.h" #include "RNA_define.h" @@ -63,23 +64,23 @@ typedef struct TransformModeItem { static const float VecOne[3] = {1, 1, 1}; -static char OP_TRANSLATION[] = "TRANSFORM_OT_translate"; -static char OP_ROTATION[] = "TRANSFORM_OT_rotate"; -static char OP_TOSPHERE[] = "TRANSFORM_OT_tosphere"; -static char OP_RESIZE[] = "TRANSFORM_OT_resize"; -static char OP_SKIN_RESIZE[] = "TRANSFORM_OT_skin_resize"; -static char OP_SHEAR[] = "TRANSFORM_OT_shear"; -static char OP_BEND[] = "TRANSFORM_OT_bend"; -static char OP_SHRINK_FATTEN[] = "TRANSFORM_OT_shrink_fatten"; -static char OP_PUSH_PULL[] = "TRANSFORM_OT_push_pull"; -static char OP_TILT[] = "TRANSFORM_OT_tilt"; -static char OP_TRACKBALL[] = "TRANSFORM_OT_trackball"; -static char OP_MIRROR[] = "TRANSFORM_OT_mirror"; -static char OP_EDGE_SLIDE[] = "TRANSFORM_OT_edge_slide"; -static char OP_VERT_SLIDE[] = "TRANSFORM_OT_vert_slide"; -static char OP_EDGE_CREASE[] = "TRANSFORM_OT_edge_crease"; -static char OP_EDGE_BWEIGHT[] = "TRANSFORM_OT_edge_bevelweight"; -static char OP_SEQ_SLIDE[] = "TRANSFORM_OT_seq_slide"; +static const char OP_TRANSLATION[] = "TRANSFORM_OT_translate"; +static const char OP_ROTATION[] = "TRANSFORM_OT_rotate"; +static const char OP_TOSPHERE[] = "TRANSFORM_OT_tosphere"; +static const char OP_RESIZE[] = "TRANSFORM_OT_resize"; +static const char OP_SKIN_RESIZE[] = "TRANSFORM_OT_skin_resize"; +static const char OP_SHEAR[] = "TRANSFORM_OT_shear"; +static const char OP_BEND[] = "TRANSFORM_OT_bend"; +static const char OP_SHRINK_FATTEN[] = "TRANSFORM_OT_shrink_fatten"; +static const char OP_PUSH_PULL[] = "TRANSFORM_OT_push_pull"; +static const char OP_TILT[] = "TRANSFORM_OT_tilt"; +static const char OP_TRACKBALL[] = "TRANSFORM_OT_trackball"; +static const char OP_MIRROR[] = "TRANSFORM_OT_mirror"; +static const char OP_EDGE_SLIDE[] = "TRANSFORM_OT_edge_slide"; +static const char OP_VERT_SLIDE[] = "TRANSFORM_OT_vert_slide"; +static const char OP_EDGE_CREASE[] = "TRANSFORM_OT_edge_crease"; +static const char OP_EDGE_BWEIGHT[] = "TRANSFORM_OT_edge_bevelweight"; +static const char OP_SEQ_SLIDE[] = "TRANSFORM_OT_seq_slide"; static void TRANSFORM_OT_translate(struct wmOperatorType *ot); static void TRANSFORM_OT_rotate(struct wmOperatorType *ot); @@ -140,6 +141,7 @@ EnumPropertyItem transform_mode_types[] = {TFM_MIRROR, "MIRROR", 0, "Mirror", ""}, {TFM_BONESIZE, "BONE_SIZE", 0, "Bonesize", ""}, {TFM_BONE_ENVELOPE, "BONE_ENVELOPE", 0, "Bone_Envelope", ""}, + {TFM_BONE_ENVELOPE_DIST, "BONE_ENVELOPE_DIST", 0, "Bone_Envelope_Distance", ""}, {TFM_CURVE_SHRINKFATTEN, "CURVE_SHRINKFATTEN", 0, "Curve_Shrinkfatten", ""}, {TFM_MASK_SHRINKFATTEN, "MASK_SHRINKFATTEN", 0, "Mask_Shrinkfatten", ""}, {TFM_GPENCIL_SHRINKFATTEN, "GPENCIL_SHRINKFATTEN", 0, "GPencil_Shrinkfatten", ""}, @@ -488,7 +490,7 @@ static int transform_invoke(bContext *C, wmOperator *op, const wmEvent *event) /* add temp handler */ WM_event_add_modal_handler(C, op); - op->flag |= OP_GRAB_POINTER; // XXX maybe we want this with the manipulator only? + op->flag |= OP_IS_MODAL_GRAB_CURSOR; // XXX maybe we want this with the manipulator only? return OPERATOR_RUNNING_MODAL; } } @@ -790,6 +792,8 @@ static void TRANSFORM_OT_shrink_fatten(struct wmOperatorType *ot) RNA_def_float(ot->srna, "value", 0, -FLT_MAX, FLT_MAX, "Offset", "", -FLT_MAX, FLT_MAX); + RNA_def_boolean(ot->srna, "use_even_offset", true, "Offset Even", "Scale the offset to give more even thickness"); + Transform_Properties(ot, P_PROPORTIONAL | P_MIRROR | P_SNAP); } @@ -834,6 +838,8 @@ static void TRANSFORM_OT_mirror(struct wmOperatorType *ot) static void TRANSFORM_OT_edge_slide(struct wmOperatorType *ot) { + PropertyRNA *prop; + /* identifiers */ ot->name = "Edge Slide"; ot->description = "Slide an edge loop along a mesh"; @@ -845,9 +851,12 @@ static void TRANSFORM_OT_edge_slide(struct wmOperatorType *ot) ot->exec = transform_exec; ot->modal = transform_modal; ot->cancel = transform_cancel; - ot->poll = ED_operator_editmesh; + ot->poll = ED_operator_editmesh_region_view3d; - RNA_def_float_factor(ot->srna, "value", 0, -1.0f, 1.0f, "Factor", "", -1.0f, 1.0f); + RNA_def_float_factor(ot->srna, "value", 0, -10.0f, 10.0f, "Factor", "", -1.0f, 1.0f); + + prop = RNA_def_boolean(ot->srna, "single_side", false, "Single Side", ""); + RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); Transform_Properties(ot, P_MIRROR | P_SNAP | P_CORRECT_UV); } @@ -865,7 +874,7 @@ static void TRANSFORM_OT_vert_slide(struct wmOperatorType *ot) ot->exec = transform_exec; ot->modal = transform_modal; ot->cancel = transform_cancel; - ot->poll = ED_operator_editmesh; + ot->poll = ED_operator_editmesh_region_view3d; RNA_def_float_factor(ot->srna, "value", 0, -10.0f, 10.0f, "Factor", "", -1.0f, 1.0f); @@ -1118,7 +1127,7 @@ void transform_keymap_for_space(wmKeyConfig *keyconf, wmKeyMap *keymap, int spac kmi = WM_keymap_add_item(keymap, "WM_OT_context_toggle", TABKEY, KM_PRESS, KM_SHIFT, 0); RNA_string_set(kmi->ptr, "data_path", "tool_settings.use_snap"); kmi = WM_keymap_add_item(keymap, "WM_OT_context_menu_enum", TABKEY, KM_PRESS, KM_SHIFT | KM_CTRL, 0); - RNA_string_set(kmi->ptr, "data_path", "tool_settings.snap_element"); + RNA_string_set(kmi->ptr, "data_path", "tool_settings.snap_node_element"); break; case SPACE_SEQ: WM_keymap_add_item(keymap, OP_SEQ_SLIDE, GKEY, KM_PRESS, 0, 0); diff --git a/source/blender/editors/transform/transform_snap.c b/source/blender/editors/transform/transform_snap.c index 4a2927ace00..1b0256bdeed 100644 --- a/source/blender/editors/transform/transform_snap.c +++ b/source/blender/editors/transform/transform_snap.c @@ -454,7 +454,7 @@ void applySnapping(TransInfo *t, float *vec) t->tsnap.applySnap(t, vec); } - else if ((t->tsnap.mode != SCE_SNAP_MODE_INCREMENT) && activeSnap(t)) { + else if (!ELEM(t->tsnap.mode, SCE_SNAP_MODE_INCREMENT, SCE_SNAP_MODE_GRID) && activeSnap(t)) { double current = PIL_check_seconds_timer(); // Time base quirky code to go around findnearest slowness @@ -577,6 +577,10 @@ static void initSnappingMode(TransInfo *t) t->tsnap.mode = SCE_SNAP_MODE_INCREMENT; } } + else if (t->spacetype == SPACE_SEQ) { + /* We do our own snapping currently, so nothing here */ + t->tsnap.mode = SCE_SNAP_MODE_GRID; /* Dummy, should we rather add a NOP mode? */ + } else { /* Always grid outside of 3D view */ t->tsnap.mode = SCE_SNAP_MODE_INCREMENT; @@ -837,16 +841,10 @@ static float TranslationBetween(TransInfo *UNUSED(t), const float p1[3], const f static float RotationBetween(TransInfo *t, const float p1[3], const float p2[3]) { - float angle, start[3], end[3], center[3]; - - copy_v3_v3(center, t->center); - if (t->flag & (T_EDIT | T_POSE)) { - Object *ob = t->obedit ? t->obedit : t->poseobj; - mul_m4_v3(ob->obmat, center); - } + float angle, start[3], end[3]; - sub_v3_v3v3(start, p1, center); - sub_v3_v3v3(end, p2, center); + sub_v3_v3v3(start, p1, t->center_global); + sub_v3_v3v3(end, p2, t->center_global); // Angle around a constraint axis (error prone, will need debug) if (t->con.applyRot != NULL && (t->con.mode & CON_APPLY)) { @@ -893,16 +891,10 @@ static float RotationBetween(TransInfo *t, const float p1[3], const float p2[3]) static float ResizeBetween(TransInfo *t, const float p1[3], const float p2[3]) { - float d1[3], d2[3], center[3], len_d1; - - copy_v3_v3(center, t->center); - if (t->flag & (T_EDIT | T_POSE)) { - Object *ob = t->obedit ? t->obedit : t->poseobj; - mul_m4_v3(ob->obmat, center); - } + float d1[3], d2[3], len_d1; - sub_v3_v3v3(d1, p1, center); - sub_v3_v3v3(d2, p2, center); + sub_v3_v3v3(d1, p1, t->center_global); + sub_v3_v3v3(d2, p2, t->center_global); if (t->con.applyRot != NULL && (t->con.mode & CON_APPLY)) { mul_m3_v3(t->con.pmtx, d1); @@ -949,9 +941,9 @@ static void CalcSnapGeometry(TransInfo *t, float *UNUSED(vec)) // last_p = LAST_SNAP_POINT; // } // else -// { + { last_p = t->tsnap.snapPoint; -// } + } for (p1 = depth_peels.first; p1; p1 = p1->next) { @@ -1041,14 +1033,13 @@ static void CalcSnapGeometry(TransInfo *t, float *UNUSED(vec)) else if (t->spacetype == SPACE_IMAGE && t->obedit != NULL && t->obedit->type == OB_MESH) { /* same as above but for UV's */ Image *ima = ED_space_image(t->sa->spacedata.first); - float aspx, aspy, co[2]; + float co[2]; UI_view2d_region_to_view(&t->ar->v2d, t->mval[0], t->mval[1], &co[0], &co[1]); if (ED_uvedit_nearest_uv(t->scene, t->obedit, ima, co, t->tsnap.snapPoint)) { - ED_space_image_get_uv_aspect(t->sa->spacedata.first, &aspx, &aspy); - t->tsnap.snapPoint[0] *= aspx; - t->tsnap.snapPoint[1] *= aspy; + t->tsnap.snapPoint[0] *= t->aspect[0]; + t->tsnap.snapPoint[1] *= t->aspect[1]; t->tsnap.status |= POINT_INIT; } @@ -1109,13 +1100,7 @@ static void TargetSnapCenter(TransInfo *t) { /* Only need to calculate once */ if ((t->tsnap.status & TARGET_INIT) == 0) { - copy_v3_v3(t->tsnap.snapTarget, t->center); - - if (t->flag & (T_EDIT | T_POSE)) { - Object *ob = t->obedit ? t->obedit : t->poseobj; - mul_m4_v3(ob->obmat, t->tsnap.snapTarget); - } - + copy_v3_v3(t->tsnap.snapTarget, t->center_global); TargetSnapOffset(t, NULL); t->tsnap.status |= TARGET_INIT; @@ -1396,11 +1381,8 @@ static bool snapArmature(short snap_mode, ARegion *ar, Object *ob, bArmature *ar invert_m4_m4(imat, obmat); - copy_v3_v3(ray_start_local, ray_start); - copy_v3_v3(ray_normal_local, ray_normal); - - mul_m4_v3(imat, ray_start_local); - mul_mat3_m4_v3(imat, ray_normal_local); + mul_v3_m4v3(ray_start_local, imat, ray_start); + mul_v3_mat3_m4v3(ray_normal_local, imat, ray_normal); if (arm->edbo) { EditBone *eBone; @@ -1758,11 +1740,8 @@ static bool snapEmpty(short snap_mode, ARegion *ar, Object *ob, float obmat[4][4 invert_m4_m4(imat, obmat); - copy_v3_v3(ray_start_local, ray_start); - copy_v3_v3(ray_normal_local, ray_normal); - - mul_m4_v3(imat, ray_start_local); - mul_mat3_m4_v3(imat, ray_normal_local); + mul_v3_m4v3(ray_start_local, imat, ray_start); + mul_v3_mat3_m4v3(ray_normal_local, imat, ray_normal); switch (snap_mode) { case SCE_SNAP_MODE_VERTEX: @@ -2107,12 +2086,8 @@ static bool peelDerivedMesh(Object *ob, DerivedMesh *dm, float obmat[4][4], transpose_m3_m4(timat, imat); - copy_v3_v3(ray_start_local, ray_start); - copy_v3_v3(ray_normal_local, ray_normal); - - mul_m4_v3(imat, ray_start_local); - mul_mat3_m4_v3(imat, ray_normal_local); - + mul_v3_m4v3(ray_start_local, imat, ray_start); + mul_v3_mat3_m4v3(ray_normal_local, imat, ray_normal); /* If number of vert is more than an arbitrary limit, * test against boundbox first @@ -2418,8 +2393,8 @@ void snapGridIncrement(TransInfo *t, float *val) { GearsType action; - // Only do something if using Snap to Grid - if (t->tsnap.mode != SCE_SNAP_MODE_INCREMENT) + /* only do something if using absolute or incremental grid snapping */ + if (!ELEM(t->tsnap.mode, SCE_SNAP_MODE_INCREMENT, SCE_SNAP_MODE_GRID)) return; action = activeSnap(t) ? BIG_GEARS : NO_GEARS; @@ -2431,7 +2406,7 @@ void snapGridIncrement(TransInfo *t, float *val) snapGridIncrementAction(t, val, action); } -int snapSequenceBounds(TransInfo *t, const int mval[2]) +void snapSequenceBounds(TransInfo *t, const int mval[2]) { float xmouse, ymouse; int frame; @@ -2439,7 +2414,7 @@ int snapSequenceBounds(TransInfo *t, const int mval[2]) TransSeq *ts = t->customData; /* reuse increment, strictly speaking could be another snap mode, but leave as is */ if (!(t->modifiers & MOD_SNAP_INVERT)) - return 0; + return; /* convert to frame range */ UI_view2d_region_to_view(&t->ar->v2d, mval[0], mval[1], &xmouse, &ymouse); @@ -2450,50 +2425,58 @@ int snapSequenceBounds(TransInfo *t, const int mval[2]) if (!ts->snap_left) frame = frame - (ts->max - ts->min); - return frame; + t->values[0] = frame - ts->min; } static void applyGridIncrement(TransInfo *t, float *val, int max_index, const float fac[3], GearsType action) { + float asp_local[3] = {1, 1, 1}; + const bool use_aspect = ELEM(t->mode, TFM_TRANSLATION); + const float *asp = use_aspect ? t->aspect : asp_local; int i; - float asp[3] = {1.0f, 1.0f, 1.0f}; // TODO: Remove hard coded limit here (3) - if (max_index > 2) { - printf("applyGridIncrement: invalid index %d, clamping\n", max_index); - max_index = 2; - } + BLI_assert(ELEM(t->tsnap.mode, SCE_SNAP_MODE_INCREMENT, SCE_SNAP_MODE_GRID)); + BLI_assert(max_index <= 2); - // Early bailing out if no need to snap - if (fac[action] == 0.0f) + /* Early bailing out if no need to snap */ + if (fac[action] == 0.0f) { return; - - /* evil hack - snapping needs to be adapted for image aspect ratio */ - if ((t->spacetype == SPACE_IMAGE) && (t->mode == TFM_TRANSLATION)) { - if (t->options & CTX_MASK) { - ED_space_image_get_aspect(t->sa->spacedata.first, asp, asp + 1); - } - else if (t->options & CTX_PAINT_CURVE) { - asp[0] = asp[1] = 1.0; - } - else { - ED_space_image_get_uv_aspect(t->sa->spacedata.first, asp, asp + 1); - } } - else if ((t->spacetype == SPACE_IPO) && (t->mode == TFM_TRANSLATION)) { - View2D *v2d = &t->ar->v2d; - View2DGrid *grid; - SpaceIpo *sipo = t->sa->spacedata.first; - int unity = V2D_UNIT_VALUES; - int unitx = (sipo->flag & SIPO_DRAWTIME) ? V2D_UNIT_SECONDS : V2D_UNIT_FRAMESCALE; - /* grid */ - grid = UI_view2d_grid_calc(t->scene, v2d, unitx, V2D_GRID_NOCLAMP, unity, V2D_GRID_NOCLAMP, t->ar->winx, t->ar->winy); + if (use_aspect) { + /* custom aspect for fcurve */ + if (t->spacetype == SPACE_IPO) { + View2D *v2d = &t->ar->v2d; + View2DGrid *grid; + SpaceIpo *sipo = t->sa->spacedata.first; + int unity = V2D_UNIT_VALUES; + int unitx = (sipo->flag & SIPO_DRAWTIME) ? V2D_UNIT_SECONDS : V2D_UNIT_FRAMESCALE; + + /* grid */ + grid = UI_view2d_grid_calc(t->scene, v2d, unitx, V2D_GRID_NOCLAMP, unity, V2D_GRID_NOCLAMP, t->ar->winx, t->ar->winy); + + UI_view2d_grid_size(grid, &asp_local[0], &asp_local[1]); + UI_view2d_grid_free(grid); - UI_view2d_grid_size(grid, &asp[0], &asp[1]); - UI_view2d_grid_free(grid); + asp = asp_local; + } } - for (i = 0; i <= max_index; i++) { - val[i] = fac[action] * asp[i] * floorf(val[i] / (fac[action] * asp[i]) + 0.5f); + /* absolute snapping on grid based on global center */ + if ((t->tsnap.mode == SCE_SNAP_MODE_GRID) && (t->mode == TFM_TRANSLATION)) { + for (i = 0; i <= max_index; i++) { + /* do not let unconstrained axis jump to absolute grid increments */ + if (!(t->con.mode & CON_APPLY) || t->con.mode & (CON_AXIS0 << i)) { + const float iter_fac = fac[action] * asp[i]; + val[i] = iter_fac * roundf((val[i] + t->center_global[i]) / iter_fac) - t->center_global[i]; + } + } + } + else { + /* relative snapping in fixed increments */ + for (i = 0; i <= max_index; i++) { + const float iter_fac = fac[action] * asp[i]; + val[i] = iter_fac * roundf(val[i] / iter_fac); + } } } |