diff options
Diffstat (limited to 'source/blender/editors/transform/transform.c')
-rw-r--r-- | source/blender/editors/transform/transform.c | 1423 |
1 files changed, 930 insertions, 493 deletions
diff --git a/source/blender/editors/transform/transform.c b/source/blender/editors/transform/transform.c index f4cb8f724bb..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); @@ -911,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; @@ -1250,11 +1225,6 @@ int transformEvent(TransInfo *t, const wmEvent *event) 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); @@ -1269,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; } @@ -1575,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); } } @@ -1828,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 */ @@ -1938,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); @@ -1989,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"))) { @@ -2017,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 */ @@ -2089,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); @@ -2188,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; @@ -2258,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 */ @@ -2516,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; @@ -2532,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 */ @@ -2619,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; @@ -2686,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]; @@ -2810,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; @@ -2888,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]; @@ -2905,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; @@ -2961,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); } @@ -3056,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]; @@ -3069,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 @@ -3333,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); @@ -3439,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); @@ -3549,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; @@ -3921,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]; @@ -3937,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); @@ -4010,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]); @@ -4018,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]; @@ -4042,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]); @@ -4049,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); @@ -4374,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)) { @@ -4401,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) @@ -4470,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]; @@ -4547,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]; @@ -4625,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]; @@ -4723,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]; @@ -4795,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]; @@ -4808,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); } @@ -4882,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]; @@ -4960,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]; @@ -5099,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); @@ -5107,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) { @@ -5173,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]; @@ -5260,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; + } + + 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); } - loop_weights[j] = BM_loop_calc_face_angle(l); + else { + loop_weights[j] = 0.0f; + } + } /* store cd_loop_groups */ @@ -5332,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); @@ -5352,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; + } } } @@ -5427,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; @@ -5442,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; @@ -5450,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); @@ -5605,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; @@ -5635,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); @@ -5650,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; @@ -5659,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); @@ -5684,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)) { @@ -5863,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; @@ -5889,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); } } @@ -5976,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; } @@ -6152,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; } @@ -6173,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; @@ -6189,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) { @@ -6199,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; } @@ -6236,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); @@ -6265,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(); @@ -6323,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); } } } @@ -6343,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]; @@ -6356,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); @@ -6375,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); @@ -6436,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); @@ -6447,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); } /** @@ -6464,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) { @@ -6494,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; @@ -6522,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; @@ -6591,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; @@ -6599,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++; } } @@ -6641,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); } @@ -6681,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); } } @@ -6748,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; @@ -6765,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: { @@ -6801,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) @@ -6861,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); } @@ -6937,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)) { @@ -7005,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]; @@ -7277,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]); @@ -7344,8 +7774,8 @@ static void applySeqSlide(TransInfo *t, const int mval[2]) 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); @@ -7511,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)) { @@ -7546,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; @@ -7579,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 { @@ -7593,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; @@ -7607,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]; @@ -7623,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); @@ -7756,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); @@ -7857,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 */ |