diff options
author | YimingWu <xp8110@outlook.com> | 2020-05-16 18:08:40 +0300 |
---|---|---|
committer | YimingWu <xp8110@outlook.com> | 2020-05-16 18:08:40 +0300 |
commit | cd54abd2c1316136753f7bbe227bd762a5f9e7d9 (patch) | |
tree | 69f2a4a1a5013acc78213bb4f3fe888912380ea4 /source/blender/editors/transform | |
parent | f7770cb97bb9d19d0806f67da9377129fd4d09b0 (diff) | |
parent | eaf7d36d66e551c3262d69f472b4028aeccb7e97 (diff) |
Merge remote-tracking branch 'origin/master' into temp-lanpr-review
Diffstat (limited to 'source/blender/editors/transform')
68 files changed, 10399 insertions, 8777 deletions
diff --git a/source/blender/editors/transform/CMakeLists.txt b/source/blender/editors/transform/CMakeLists.txt index 6f39a8c3b9c..afa7b02a1f6 100644 --- a/source/blender/editors/transform/CMakeLists.txt +++ b/source/blender/editors/transform/CMakeLists.txt @@ -65,14 +65,47 @@ set(SRC transform_gizmo_3d.c transform_gizmo_extrude_3d.c transform_input.c + transform_mode.c + transform_mode_align.c + transform_mode_baketime.c + transform_mode_bbone_resize.c + transform_mode_bend.c + transform_mode_boneenvelope.c + transform_mode_boneroll.c + transform_mode_curveshrinkfatten.c + transform_mode_edge_bevelweight.c + transform_mode_edge_crease.c + transform_mode_edge_rotate_normal.c + transform_mode_edge_seq_slide.c + transform_mode_edge_slide.c + transform_mode_gpopacity.c + transform_mode_gpshrinkfatten.c + transform_mode_maskshrinkfatten.c + transform_mode_mirror.c + transform_mode_push_pull.c + transform_mode_resize.c + transform_mode_rotate.c + transform_mode_shear.c + transform_mode_shrink_fatten.c + transform_mode_skin_resize.c + transform_mode_tilt.c + transform_mode_timescale.c + transform_mode_timeslide.c + transform_mode_timetranslate.c + transform_mode_tosphere.c + transform_mode_trackball.c + transform_mode_translate.c + transform_mode_vert_slide.c transform_ops.c transform_orientations.c transform_snap.c transform_snap_object.c transform.h + transform_constraints.h transform_convert.h transform_draw_cursors.h + transform_mode.h transform_snap.h ) diff --git a/source/blender/editors/transform/transform.c b/source/blender/editors/transform/transform.c index ec39b457082..8e3ad55bae1 100644 --- a/source/blender/editors/transform/transform.c +++ b/source/blender/editors/transform/transform.c @@ -22,220 +22,70 @@ */ #include <stdlib.h> -#include <stdio.h> -#include <string.h> -#include <math.h> -#include <float.h> #include "MEM_guardedalloc.h" -#include "DNA_anim_types.h" -#include "DNA_armature_types.h" -#include "DNA_constraint_types.h" +#include "DNA_gpencil_types.h" #include "DNA_mask_types.h" #include "DNA_mesh_types.h" -#include "DNA_movieclip_types.h" -#include "DNA_scene_types.h" /* PET modes */ -#include "DNA_workspace_types.h" -#include "DNA_gpencil_types.h" -#include "BLI_alloca.h" -#include "BLI_utildefines.h" #include "BLI_math.h" #include "BLI_rect.h" -#include "BLI_listbase.h" -#include "BLI_string.h" -#include "BLI_ghash.h" -#include "BLI_utildefines_stack.h" -#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" -#include "BKE_particle.h" -#include "BKE_unit.h" -#include "BKE_scene.h" +#include "BKE_editmesh.h" #include "BKE_mask.h" -#include "BKE_mesh.h" -#include "BKE_report.h" -#include "BKE_workspace.h" - -#include "DEG_depsgraph.h" +#include "BKE_scene.h" -#include "GPU_immediate.h" -#include "GPU_matrix.h" #include "GPU_state.h" +#include "ED_clip.h" +#include "ED_gpencil.h" #include "ED_image.h" #include "ED_keyframing.h" -#include "ED_screen.h" -#include "ED_space_api.h" -#include "ED_view3d.h" -#include "ED_mesh.h" -#include "ED_clip.h" #include "ED_node.h" -#include "ED_gpencil.h" +#include "ED_screen.h" #include "ED_sculpt.h" +#include "ED_space_api.h" -#include "WM_types.h" #include "WM_api.h" +#include "WM_types.h" -#include "UI_view2d.h" -#include "UI_interface.h" #include "UI_interface_icons.h" #include "UI_resources.h" +#include "UI_view2d.h" #include "RNA_access.h" -#include "RNA_define.h" #include "BLF_api.h" #include "BLT_translation.h" #include "transform.h" +#include "transform_constraints.h" #include "transform_convert.h" #include "transform_draw_cursors.h" +#include "transform_mode.h" #include "transform_snap.h" /* Disabling, since when you type you know what you are doing, * and being able to set it to zero is handy. */ // #define USE_NUM_NO_ZERO -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(TransInfo *t); -static void drawVertSlide(TransInfo *t); -static void postInputRotation(TransInfo *t, float values[3]); +static void drawTransformApply(const struct bContext *C, ARegion *region, void *arg); -static void ElementRotation( - TransInfo *t, TransDataContainer *tc, TransData *td, float mat[3][3], const short around); static void initSnapSpatial(TransInfo *t, float r_snap[3]); -static void storeCustomLNorValue(TransDataContainer *t, BMesh *bm); - -/* Transform Callbacks */ -static void initBend(TransInfo *t); -static eRedrawFlag handleEventBend(TransInfo *t, const struct wmEvent *event); -static void Bend(TransInfo *t, const int mval[2]); - -static void initShear(TransInfo *t); -static eRedrawFlag handleEventShear(TransInfo *t, const struct wmEvent *event); -static void applyShear(TransInfo *t, const int mval[2]); - -static void initResize(TransInfo *t); -static void applyResize(TransInfo *t, const int mval[2]); - -static void initSkinResize(TransInfo *t); -static void applySkinResize(TransInfo *t, const int mval[2]); - -static void initTranslation(TransInfo *t); -static void applyTranslation(TransInfo *t, const int mval[2]); - -static void initToSphere(TransInfo *t); -static void applyToSphere(TransInfo *t, const int mval[2]); - -static void initRotation(TransInfo *t); -static void applyRotation(TransInfo *t, const int mval[2]); - -static void initNormalRotation(TransInfo *t); -static void applyNormalRotation(TransInfo *t, const int mval[2]); - -static void initShrinkFatten(TransInfo *t); -static void applyShrinkFatten(TransInfo *t, const int mval[2]); - -static void initTilt(TransInfo *t); -static void applyTilt(TransInfo *t, const int mval[2]); - -static void initCurveShrinkFatten(TransInfo *t); -static void applyCurveShrinkFatten(TransInfo *t, const int mval[2]); - -static void initMaskShrinkFatten(TransInfo *t); -static void applyMaskShrinkFatten(TransInfo *t, const int mval[2]); - -static void initGPShrinkFatten(TransInfo *t); -static void applyGPShrinkFatten(TransInfo *t, const int mval[2]); - -static void initTrackball(TransInfo *t); -static void applyTrackball(TransInfo *t, const int mval[2]); - -static void initPushPull(TransInfo *t); -static void applyPushPull(TransInfo *t, const int mval[2]); - -static void initBevelWeight(TransInfo *t); -static void applyBevelWeight(TransInfo *t, const int mval[2]); - -static void initCrease(TransInfo *t); -static void applyCrease(TransInfo *t, const int mval[2]); - -static void initBoneSize(TransInfo *t); -static void applyBoneSize(TransInfo *t, const int mval[2]); - -static void initBoneEnvelope(TransInfo *t); -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, bool use_even, bool flipped, bool use_clamp); -static void initEdgeSlide(TransInfo *t); -static eRedrawFlag handleEventEdgeSlide(TransInfo *t, const struct wmEvent *event); -static void applyEdgeSlide(TransInfo *t, const int mval[2]); - -static void initVertSlide_ex(TransInfo *t, bool use_even, bool flipped, bool use_clamp); -static void initVertSlide(TransInfo *t); -static eRedrawFlag handleEventVertSlide(TransInfo *t, const struct wmEvent *event); -static void applyVertSlide(TransInfo *t, const int mval[2]); - -static void initTimeTranslate(TransInfo *t); -static void applyTimeTranslate(TransInfo *t, const int mval[2]); - -static void initTimeSlide(TransInfo *t); -static void applyTimeSlide(TransInfo *t, const int mval[2]); - -static void initTimeScale(TransInfo *t); -static void applyTimeScale(TransInfo *t, const int mval[2]); - -static void initBakeTime(TransInfo *t); -static void applyBakeTime(TransInfo *t, const int mval[2]); - -static void initMirror(TransInfo *t); -static void applyMirror(TransInfo *t, const int mval[2]); - -static void initAlign(TransInfo *t); -static void applyAlign(TransInfo *t, const int mval[2]); - -static void initSeqSlide(TransInfo *t); -static void applySeqSlide(TransInfo *t, const int mval[2]); - -static void initGPOpacity(TransInfo *t); -static void applyGPOpacity(TransInfo *t, const int mval[2]); -/* end transform callbacks */ - -static bool transdata_check_local_center(TransInfo *t, short around) -{ - return ((around == V3D_AROUND_LOCAL_ORIGINS) && - ((t->flag & (T_OBJECT | T_POSE)) || - /* implicit: (t->flag & T_EDIT) */ - (ELEM(t->obedit_type, OB_MESH, OB_CURVE, OB_MBALL, OB_ARMATURE, OB_GPENCIL)) || - (t->spacetype == SPACE_GRAPH) || - (t->options & (CTX_MOVIECLIP | CTX_MASK | CTX_PAINT_CURVE)))); -} - bool transdata_check_local_islands(TransInfo *t, short around) { - return ((around == V3D_AROUND_LOCAL_ORIGINS) && ((ELEM(t->obedit_type, OB_MESH)))); + return ((around == V3D_AROUND_LOCAL_ORIGINS) && ((ELEM(t->obedit_type, OB_MESH, OB_GPENCIL)))); } /* ************************** SPACE DEPENDENT CODE **************************** */ void setTransformViewMatrices(TransInfo *t) { - if (t->spacetype == SPACE_VIEW3D && t->ar && t->ar->regiontype == RGN_TYPE_WINDOW) { - RegionView3D *rv3d = t->ar->regiondata; + if (t->spacetype == SPACE_VIEW3D && t->region && t->region->regiontype == RGN_TYPE_WINDOW) { + RegionView3D *rv3d = t->region->regiondata; copy_m4_m4(t->viewmat, rv3d->viewmat); copy_m4_m4(t->viewinv, rv3d->viewinv); @@ -260,7 +110,7 @@ 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; + SpaceImage *sima = t->area->spacedata.first; if (t->options & CTX_MASK) { ED_space_image_get_aspect(sima, &r_aspect[0], &r_aspect[1]); @@ -273,7 +123,7 @@ void setTransformViewAspect(TransInfo *t, float r_aspect[3]) } } else if (t->spacetype == SPACE_CLIP) { - SpaceClip *sclip = t->sa->spacedata.first; + SpaceClip *sclip = t->area->spacedata.first; if (t->options & CTX_MOVIECLIP) { ED_space_clip_get_aspect_dimension_aware(sclip, &r_aspect[0], &r_aspect[1]); @@ -324,14 +174,14 @@ static void convertViewVec2D_mask(View2D *v2d, float r_vec[3], int dx, int dy) void convertViewVec(TransInfo *t, float r_vec[3], double dx, double dy) { - if ((t->spacetype == SPACE_VIEW3D) && (t->ar->regiontype == RGN_TYPE_WINDOW)) { + if ((t->spacetype == SPACE_VIEW3D) && (t->region->regiontype == RGN_TYPE_WINDOW)) { if (t->options & CTX_PAINT_CURVE) { r_vec[0] = dx; r_vec[1] = dy; } else { const float mval_f[2] = {(float)dx, (float)dy}; - ED_view3d_win_to_delta(t->ar, mval_f, r_vec, t->zfac); + ED_view3d_win_to_delta(t->region, mval_f, r_vec, t->zfac); } } else if (t->spacetype == SPACE_IMAGE) { @@ -353,7 +203,7 @@ void convertViewVec(TransInfo *t, float r_vec[3], double dx, double dy) convertViewVec2D(t->view, r_vec, dx, dy); } else if (ELEM(t->spacetype, SPACE_NODE, SPACE_SEQ)) { - convertViewVec2D(&t->ar->v2d, r_vec, dx, dy); + convertViewVec2D(&t->region->v2d, r_vec, dx, dy); } else if (t->spacetype == SPACE_CLIP) { if (t->options & CTX_MASK) { @@ -375,8 +225,8 @@ void convertViewVec(TransInfo *t, float r_vec[3], double dx, double dy) void projectIntViewEx(TransInfo *t, const float vec[3], int adr[2], const eV3DProjTest flag) { if (t->spacetype == SPACE_VIEW3D) { - if (t->ar->regiontype == RGN_TYPE_WINDOW) { - if (ED_view3d_project_int_global(t->ar, vec, adr, flag) != V3D_PROJ_RET_OK) { + if (t->region->regiontype == RGN_TYPE_WINDOW) { + if (ED_view3d_project_int_global(t->region, vec, adr, flag) != V3D_PROJ_RET_OK) { /* this is what was done in 2.64, perhaps we can be smarter? */ adr[0] = (int)2140000000.0f; adr[1] = (int)2140000000.0f; @@ -384,7 +234,7 @@ void projectIntViewEx(TransInfo *t, const float vec[3], int adr[2], const eV3DPr } } else if (t->spacetype == SPACE_IMAGE) { - SpaceImage *sima = t->sa->spacedata.first; + SpaceImage *sima = t->area->spacedata.first; if (t->options & CTX_MASK) { float v[2]; @@ -394,7 +244,7 @@ void projectIntViewEx(TransInfo *t, const float vec[3], int adr[2], const eV3DPr BKE_mask_coord_to_image(sima->image, &sima->iuser, v, v); - ED_image_point_pos__reverse(sima, t->ar, v, v); + ED_image_point_pos__reverse(sima, t->region, v, v); adr[0] = v[0]; adr[1] = v[1]; @@ -415,7 +265,7 @@ void projectIntViewEx(TransInfo *t, const float vec[3], int adr[2], const eV3DPr else if (t->spacetype == SPACE_ACTION) { int out[2] = {0, 0}; #if 0 - SpaceAction *sact = t->sa->spacedata.first; + SpaceAction *sact = t->area->spacedata.first; if (sact->flag & SACTION_DRAWTIME) { //vec[0] = vec[0]/((t->scene->r.frs_sec / t->scene->r.frs_sec_base)); @@ -446,7 +296,7 @@ void projectIntViewEx(TransInfo *t, const float vec[3], int adr[2], const eV3DPr adr[1] = out[1]; } else if (t->spacetype == SPACE_CLIP) { - SpaceClip *sc = t->sa->spacedata.first; + SpaceClip *sc = t->area->spacedata.first; if (t->options & CTX_MASK) { MovieClip *clip = ED_space_clip_get_clip(sc); @@ -459,7 +309,7 @@ void projectIntViewEx(TransInfo *t, const float vec[3], int adr[2], const eV3DPr BKE_mask_coord_to_movieclip(sc->clip, &sc->user, v, v); - ED_clip_point_stable_pos__reverse(sc, t->ar, v, v); + ED_clip_point_stable_pos__reverse(sc, t->region, v, v); adr[0] = v[0]; adr[1] = v[1]; @@ -498,12 +348,12 @@ void projectFloatViewEx(TransInfo *t, const float vec[3], float adr[2], const eV adr[0] = vec[0]; adr[1] = vec[1]; } - else if (t->ar->regiontype == RGN_TYPE_WINDOW) { + else if (t->region->regiontype == RGN_TYPE_WINDOW) { /* allow points behind the view [#33643] */ - if (ED_view3d_project_float_global(t->ar, vec, adr, flag) != V3D_PROJ_RET_OK) { + if (ED_view3d_project_float_global(t->region, vec, adr, flag) != V3D_PROJ_RET_OK) { /* XXX, 2.64 and prior did this, weak! */ - adr[0] = t->ar->winx / 2.0f; - adr[1] = t->ar->winy / 2.0f; + adr[0] = t->region->winx / 2.0f; + adr[1] = t->region->winy / 2.0f; } return; } @@ -527,7 +377,7 @@ 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; + SpaceImage *sima = t->area->spacedata.first; if ((sima->flag & SI_COORDFLOATS) == 0) { int width, height; @@ -551,7 +401,7 @@ void applyAspectRatio(TransInfo *t, float vec[2]) void removeAspectRatio(TransInfo *t, float vec[2]) { if ((t->spacetype == SPACE_IMAGE) && (t->mode == TFM_TRANSLATION)) { - SpaceImage *sima = t->sa->spacedata.first; + SpaceImage *sima = t->area->spacedata.first; if ((sima->flag & SI_COORDFLOATS) == 0) { int width, height; @@ -584,7 +434,7 @@ static void viewRedrawForce(const bContext *C, TransInfo *t) else if (t->spacetype == SPACE_VIEW3D) { if (t->options & CTX_PAINT_CURVE) { wmWindow *window = CTX_wm_window(C); - WM_paint_cursor_tag_redraw(window, t->ar); + WM_paint_cursor_tag_redraw(window, t->region); } else { /* Do we need more refined tags? */ @@ -603,18 +453,18 @@ static void viewRedrawForce(const bContext *C, TransInfo *t) } } else if (t->spacetype == SPACE_ACTION) { - // SpaceAction *saction = (SpaceAction *)t->sa->spacedata.first; + // SpaceAction *saction = (SpaceAction *)t->area->spacedata.first; WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL); } else if (t->spacetype == SPACE_GRAPH) { - // SpaceGraph *sipo = (SpaceGraph *)t->sa->spacedata.first; + // SpaceGraph *sipo = (SpaceGraph *)t->area->spacedata.first; WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL); } else if (t->spacetype == SPACE_NLA) { WM_event_add_notifier(C, NC_ANIMATION | ND_NLA | NA_EDITED, NULL); } else if (t->spacetype == SPACE_NODE) { - // ED_area_tag_redraw(t->sa); + // ED_area_tag_redraw(t->area); WM_event_add_notifier(C, NC_SPACE | ND_SPACE_NODE_VIEW, NULL); } else if (t->spacetype == SPACE_SEQ) { @@ -630,24 +480,24 @@ static void viewRedrawForce(const bContext *C, TransInfo *t) } else if (t->options & CTX_PAINT_CURVE) { wmWindow *window = CTX_wm_window(C); - WM_paint_cursor_tag_redraw(window, t->ar); + WM_paint_cursor_tag_redraw(window, t->region); } else if (t->flag & T_CURSOR) { - ED_area_tag_redraw(t->sa); + ED_area_tag_redraw(t->area); } else { // XXX how to deal with lock? - SpaceImage *sima = (SpaceImage *)t->sa->spacedata.first; + SpaceImage *sima = (SpaceImage *)t->area->spacedata.first; if (sima->lock) { WM_event_add_notifier(C, NC_GEOM | ND_DATA, OBEDIT_FROM_VIEW_LAYER(t->view_layer)->data); } else { - ED_area_tag_redraw(t->sa); + ED_area_tag_redraw(t->area); } } } else if (t->spacetype == SPACE_CLIP) { - SpaceClip *sc = (SpaceClip *)t->sa->spacedata.first; + SpaceClip *sc = (SpaceClip *)t->area->spacedata.first; if (ED_space_clip_check_show_trackedit(sc)) { MovieClip *clip = ED_space_clip_get_clip(sc); @@ -667,7 +517,7 @@ static void viewRedrawForce(const bContext *C, TransInfo *t) static void viewRedrawPost(bContext *C, TransInfo *t) { - ED_area_status_text(t->sa, NULL); + ED_area_status_text(t->area, NULL); if (t->spacetype == SPACE_VIEW3D) { /* if autokeying is enabled, send notifiers that keyframes were added */ @@ -709,7 +559,7 @@ static void viewRedrawPost(bContext *C, TransInfo *t) /* ************************** TRANSFORMATIONS **************************** */ -static void view_editmove(unsigned short UNUSED(event)) +static void view_editmove(ushort UNUSED(event)) { #if 0 // TRANSFORM_FIX_ME int refresh = 0; @@ -797,42 +647,6 @@ 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 */ -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 */ - TFM_MODAL_PROPSIZE = 26, - /* node editor insert offset (aka auto-offset) direction toggle */ - TFM_MODAL_INSERTOFS_TOGGLE_DIR = 27, -}; - static bool transform_modal_item_poll(const wmOperator *op, int value) { const TransInfo *t = op->customdata; @@ -956,17 +770,18 @@ wmKeyMap *transform_modal_keymap(wmKeyConfig *keyconf) {0, NULL, 0, NULL, NULL}, }; - wmKeyMap *keymap = WM_modalkeymap_get(keyconf, "Transform Modal Map"); + wmKeyMap *keymap = WM_modalkeymap_find(keyconf, "Transform Modal Map"); - keymap = WM_modalkeymap_add(keyconf, "Transform Modal Map", modal_items); + keymap = WM_modalkeymap_ensure(keyconf, "Transform Modal Map", modal_items); keymap->poll_modal_item = transform_modal_item_poll; return keymap; } -static void transform_event_xyz_constraint(TransInfo *t, short key_type, char cmode, bool is_plane) +static void transform_event_xyz_constraint(TransInfo *t, short key_type, bool is_plane) { if (!(t->flag & T_NO_CONSTRAINT)) { + char cmode = constraintModeToChar(t); int constraint_axis, constraint_plane; const bool edit_2d = (t->flag & T_2D_EDIT) != 0; const char *msg1 = "", *msg2 = "", *msg3 = ""; @@ -974,21 +789,21 @@ static void transform_event_xyz_constraint(TransInfo *t, short key_type, char cm /* Initialize */ switch (key_type) { - case XKEY: + case EVT_XKEY: msg1 = TIP_("along X"); msg2 = TIP_("along %s X"); msg3 = TIP_("locking %s X"); axis = 'X'; constraint_axis = CON_AXIS0; break; - case YKEY: + case EVT_YKEY: msg1 = TIP_("along Y"); msg2 = TIP_("along %s Y"); msg3 = TIP_("locking %s Y"); axis = 'Y'; constraint_axis = CON_AXIS1; break; - case ZKEY: + case EVT_ZKEY: msg1 = TIP_("along Z"); msg2 = TIP_("along %s Z"); msg3 = TIP_("locking %s Z"); @@ -1001,7 +816,7 @@ static void transform_event_xyz_constraint(TransInfo *t, short key_type, char cm } constraint_plane = ((CON_AXIS0 | CON_AXIS1 | CON_AXIS2) & (~constraint_axis)); - if (edit_2d && (key_type != ZKEY)) { + if (edit_2d && (key_type != EVT_ZKEY)) { if (cmode == axis) { stopConstraint(t); } @@ -1010,34 +825,22 @@ static void transform_event_xyz_constraint(TransInfo *t, short key_type, char cm } } else if (!edit_2d) { - if (cmode != axis) { - /* First press, constraint to an axis. */ - t->orientation.index = 0; - const short *orientation_ptr = t->orientation.types[t->orientation.index]; - const short orientation = orientation_ptr ? *orientation_ptr : V3D_ORIENT_GLOBAL; - if (is_plane == false) { - setUserConstraint(t, orientation, constraint_axis, msg2); - } - else { - setUserConstraint(t, orientation, constraint_plane, msg3); - } - } - else { + if (t->orientation.index == 0 || ELEM(cmode, '\0', axis)) { /* Successive presses on existing axis, cycle orientation modes. */ t->orientation.index = (t->orientation.index + 1) % ARRAY_SIZE(t->orientation.types); + initTransformOrientation(t->context, t, t->orientation.types[t->orientation.index]); + } - if (t->orientation.index == 0) { - stopConstraint(t); + if (t->orientation.index == 0) { + stopConstraint(t); + } + else { + const short orientation = t->orientation.types[t->orientation.index]; + if (is_plane == false) { + setUserConstraint(t, orientation, constraint_axis, msg2); } else { - const short *orientation_ptr = t->orientation.types[t->orientation.index]; - const short orientation = orientation_ptr ? *orientation_ptr : V3D_ORIENT_GLOBAL; - if (is_plane == false) { - setUserConstraint(t, orientation, constraint_axis, msg2); - } - else { - setUserConstraint(t, orientation, constraint_plane, msg3); - } + setUserConstraint(t, orientation, constraint_plane, msg3); } } } @@ -1047,7 +850,6 @@ static void transform_event_xyz_constraint(TransInfo *t, short key_type, char cm int transformEvent(TransInfo *t, const wmEvent *event) { - char cmode = constraintModeToChar(t); bool handled = false; const int modifiers_prev = t->modifiers; const int mode_prev = t->mode; @@ -1103,7 +905,7 @@ int transformEvent(TransInfo *t, const wmEvent *event) restoreTransObjects(t); resetTransModal(t); resetTransRestrictions(t); - initTranslation(t); + transform_mode_init(t, NULL, TFM_TRANSLATION); initSnapping(t, NULL); // need to reinit after mode change t->redraw |= TREDRAW_HARD; handled = true; @@ -1121,21 +923,20 @@ int transformEvent(TransInfo *t, const wmEvent *event) resetTransRestrictions(t); /* first try edge slide */ - initEdgeSlide(t); + transform_mode_init(t, NULL, TFM_EDGE_SLIDE); /* if that fails, do vertex slide */ if (t->state == TRANS_CANCEL) { resetTransModal(t); t->state = TRANS_STARTING; - initVertSlide(t); + transform_mode_init(t, NULL, TFM_VERT_SLIDE); } /* vert slide can fail on unconnected vertices (rare but possible) */ if (t->state == TRANS_CANCEL) { resetTransModal(t); - t->mode = TFM_TRANSLATION; t->state = TRANS_STARTING; restoreTransObjects(t); resetTransRestrictions(t); - initTranslation(t); + transform_mode_init(t, NULL, TFM_TRANSLATION); } initSnapping(t, NULL); // need to reinit after mode change t->redraw |= TREDRAW_HARD; @@ -1168,10 +969,10 @@ int transformEvent(TransInfo *t, const wmEvent *event) resetTransRestrictions(t); if (t->mode == TFM_ROTATION) { - initTrackball(t); + transform_mode_init(t, NULL, TFM_TRACKBALL); } else { - initRotation(t); + transform_mode_init(t, NULL, TFM_ROTATION); } initSnapping(t, NULL); // need to reinit after mode change t->redraw |= TREDRAW_HARD; @@ -1196,7 +997,7 @@ int transformEvent(TransInfo *t, const wmEvent *event) restoreTransObjects(t); resetTransModal(t); resetTransRestrictions(t); - initResize(t); + transform_mode_init(t, NULL, TFM_RESIZE); initSnapping(t, NULL); // need to reinit after mode change t->redraw |= TREDRAW_HARD; handled = true; @@ -1234,42 +1035,42 @@ int transformEvent(TransInfo *t, const wmEvent *event) break; case TFM_MODAL_AXIS_X: if (!(t->flag & T_NO_CONSTRAINT)) { - transform_event_xyz_constraint(t, XKEY, cmode, false); + transform_event_xyz_constraint(t, EVT_XKEY, false); t->redraw |= TREDRAW_HARD; handled = true; } break; case TFM_MODAL_AXIS_Y: if ((t->flag & T_NO_CONSTRAINT) == 0) { - transform_event_xyz_constraint(t, YKEY, cmode, false); + transform_event_xyz_constraint(t, EVT_YKEY, false); t->redraw |= TREDRAW_HARD; handled = true; } break; case TFM_MODAL_AXIS_Z: if ((t->flag & (T_NO_CONSTRAINT)) == 0) { - transform_event_xyz_constraint(t, ZKEY, cmode, false); + transform_event_xyz_constraint(t, EVT_ZKEY, false); t->redraw |= TREDRAW_HARD; handled = true; } break; case TFM_MODAL_PLANE_X: if ((t->flag & (T_NO_CONSTRAINT | T_2D_EDIT)) == 0) { - transform_event_xyz_constraint(t, XKEY, cmode, true); + transform_event_xyz_constraint(t, EVT_XKEY, true); t->redraw |= TREDRAW_HARD; handled = true; } break; case TFM_MODAL_PLANE_Y: if ((t->flag & (T_NO_CONSTRAINT | T_2D_EDIT)) == 0) { - transform_event_xyz_constraint(t, YKEY, cmode, true); + transform_event_xyz_constraint(t, EVT_YKEY, true); t->redraw |= TREDRAW_HARD; handled = true; } break; case TFM_MODAL_PLANE_Z: if ((t->flag & (T_NO_CONSTRAINT | T_2D_EDIT)) == 0) { - transform_event_xyz_constraint(t, ZKEY, cmode, true); + transform_event_xyz_constraint(t, EVT_ZKEY, true); t->redraw |= TREDRAW_HARD; handled = true; } @@ -1347,9 +1148,9 @@ int transformEvent(TransInfo *t, const wmEvent *event) break; case TFM_MODAL_INSERTOFS_TOGGLE_DIR: if (t->spacetype == SPACE_NODE) { - SpaceNode *snode = (SpaceNode *)t->sa->spacedata.first; + SpaceNode *snode = (SpaceNode *)t->area->spacedata.first; - BLI_assert(t->sa->spacetype == t->spacetype); + BLI_assert(t->area->spacetype == t->spacetype); if (snode->insert_ofs_dir == SNODE_INSERTOFS_DIR_RIGHT) { snode->insert_ofs_dir = SNODE_INSERTOFS_DIR_LEFT; @@ -1374,23 +1175,29 @@ int transformEvent(TransInfo *t, const wmEvent *event) /* else do non-mapped events */ else if (event->val == KM_PRESS) { switch (event->type) { + case EVT_ESCKEY: case RIGHTMOUSE: t->state = TRANS_CANCEL; handled = true; break; - /* enforce redraw of transform when modifiers are used */ - case LEFTSHIFTKEY: - case RIGHTSHIFTKEY: - t->modifiers |= MOD_CONSTRAINT_PLANE; - t->redraw |= TREDRAW_HARD; - handled = true; - break; - case SPACEKEY: + case EVT_SPACEKEY: + case EVT_PADENTER: + case EVT_RETKEY: + if (event->is_repeat) { + break; + } t->state = TRANS_CONFIRM; handled = true; break; + /* enforce redraw of transform when modifiers are used */ + case EVT_LEFTSHIFTKEY: + case EVT_RIGHTSHIFTKEY: + t->modifiers |= MOD_CONSTRAINT_PLANE; + t->redraw |= TREDRAW_HARD; + handled = true; + break; case MIDDLEMOUSE: if ((t->flag & T_NO_CONSTRAINT) == 0) { /* exception for switching to dolly, or trackball, in camera view */ @@ -1400,7 +1207,7 @@ int transformEvent(TransInfo *t, const wmEvent *event) } else if (t->mode == TFM_ROTATION) { restoreTransObjects(t); - initTrackball(t); + transform_mode_init(t, NULL, TFM_TRACKBALL); } } else { @@ -1409,17 +1216,7 @@ int transformEvent(TransInfo *t, const wmEvent *event) stopConstraint(t); } else { - if (event->shift) { - /* bit hackish... but it prevents mmb select to print the - * orientation from menu */ - float mati[3][3]; - strcpy(t->spacename, "global"); - unit_m3(mati); - initSelectConstraint(t, mati); - } - else { - initSelectConstraint(t, t->spacemtx); - } + initSelectConstraint(t, event->shift); postSelectConstraint(t); } } @@ -1427,40 +1224,40 @@ int transformEvent(TransInfo *t, const wmEvent *event) handled = true; } break; - case ESCKEY: - t->state = TRANS_CANCEL; - handled = true; - break; - case PADENTER: - case RETKEY: - t->state = TRANS_CONFIRM; - handled = true; - break; - case GKEY: + case EVT_GKEY: + if (event->is_repeat) { + break; + } /* only switch when... */ if (ELEM(t->mode, TFM_ROTATION, TFM_RESIZE, TFM_TRACKBALL)) { restoreTransObjects(t); resetTransModal(t); resetTransRestrictions(t); - initTranslation(t); + transform_mode_init(t, NULL, TFM_TRANSLATION); initSnapping(t, NULL); // need to reinit after mode change t->redraw |= TREDRAW_HARD; handled = true; } break; - case SKEY: + case EVT_SKEY: + if (event->is_repeat) { + break; + } /* only switch when... */ if (ELEM(t->mode, TFM_ROTATION, TFM_TRANSLATION, TFM_TRACKBALL)) { restoreTransObjects(t); resetTransModal(t); resetTransRestrictions(t); - initResize(t); + transform_mode_init(t, NULL, TFM_RESIZE); initSnapping(t, NULL); // need to reinit after mode change t->redraw |= TREDRAW_HARD; handled = true; } break; - case RKEY: + case EVT_RKEY: + if (event->is_repeat) { + break; + } /* only switch when... */ if (!(t->options & CTX_TEXTURE)) { if (ELEM(t->mode, TFM_ROTATION, TFM_RESIZE, TFM_TRACKBALL, TFM_TRANSLATION)) { @@ -1469,10 +1266,10 @@ int transformEvent(TransInfo *t, const wmEvent *event) resetTransRestrictions(t); if (t->mode == TFM_ROTATION) { - initTrackball(t); + transform_mode_init(t, NULL, TFM_TRACKBALL); } else { - initRotation(t); + transform_mode_init(t, NULL, TFM_ROTATION); } initSnapping(t, NULL); // need to reinit after mode change t->redraw |= TREDRAW_HARD; @@ -1480,7 +1277,10 @@ int transformEvent(TransInfo *t, const wmEvent *event) } } break; - case CKEY: + case EVT_CKEY: + if (event->is_repeat) { + break; + } if (event->alt) { if (!(t->options & CTX_NO_PET)) { t->flag ^= T_PROP_CONNECTED; @@ -1491,7 +1291,10 @@ int transformEvent(TransInfo *t, const wmEvent *event) } } break; - case OKEY: + case EVT_OKEY: + if (event->is_repeat) { + break; + } if (t->flag & T_PROP_EDIT && event->shift) { t->prop_mode = (t->prop_mode + 1) % PROP_MODE_MAX; calculatePropRatio(t); @@ -1499,7 +1302,7 @@ int transformEvent(TransInfo *t, const wmEvent *event) handled = true; } break; - case PADPLUSKEY: + case EVT_PADPLUSKEY: if (event->alt && t->flag & T_PROP_EDIT) { t->prop_size *= (t->modifiers & MOD_PRECISION) ? 1.01f : 1.1f; if (t->spacetype == SPACE_VIEW3D && t->persp != RV3D_ORTHO) { @@ -1510,7 +1313,7 @@ int transformEvent(TransInfo *t, const wmEvent *event) handled = true; } break; - case PAGEUPKEY: + case EVT_PAGEUPKEY: case WHEELDOWNMOUSE: if (t->flag & T_AUTOIK) { transform_autoik_update(t, 1); @@ -1521,7 +1324,7 @@ int transformEvent(TransInfo *t, const wmEvent *event) t->redraw = TREDRAW_HARD; handled = true; break; - case PADMINUS: + case EVT_PADMINUS: if (event->alt && t->flag & T_PROP_EDIT) { t->prop_size /= (t->modifiers & MOD_PRECISION) ? 1.01f : 1.1f; calculatePropRatio(t); @@ -1529,7 +1332,7 @@ int transformEvent(TransInfo *t, const wmEvent *event) handled = true; } break; - case PAGEDOWNKEY: + case EVT_PAGEDOWNKEY: case WHEELUPMOUSE: if (t->flag & T_AUTOIK) { transform_autoik_update(t, -1); @@ -1540,21 +1343,24 @@ int transformEvent(TransInfo *t, const wmEvent *event) t->redraw = TREDRAW_HARD; handled = true; break; - case LEFTALTKEY: - case RIGHTALTKEY: + case EVT_LEFTALTKEY: + case EVT_RIGHTALTKEY: if (ELEM(t->spacetype, SPACE_SEQ, SPACE_VIEW3D)) { t->flag |= T_ALT_TRANSFORM; t->redraw |= TREDRAW_HARD; handled = true; } break; - case NKEY: + case EVT_NKEY: + if (event->is_repeat) { + break; + } if (ELEM(t->mode, TFM_ROTATION)) { if ((t->flag & T_EDIT) && t->obedit_type == OB_MESH) { restoreTransObjects(t); resetTransModal(t); resetTransRestrictions(t); - initNormalRotation(t); + transform_mode_init(t, NULL, TFM_NORMAL_ROTATION); t->redraw = TREDRAW_HARD; handled = true; } @@ -1569,8 +1375,8 @@ int transformEvent(TransInfo *t, const wmEvent *event) } else if (event->val == KM_RELEASE) { switch (event->type) { - case LEFTSHIFTKEY: - case RIGHTSHIFTKEY: + case EVT_LEFTSHIFTKEY: + case EVT_RIGHTSHIFTKEY: t->modifiers &= ~MOD_CONSTRAINT_PLANE; t->redraw |= TREDRAW_HARD; handled = true; @@ -1584,8 +1390,8 @@ int transformEvent(TransInfo *t, const wmEvent *event) handled = true; } break; - case LEFTALTKEY: - case RIGHTALTKEY: + case EVT_LEFTALTKEY: + case EVT_RIGHTALTKEY: if (ELEM(t->spacetype, SPACE_SEQ, SPACE_VIEW3D)) { t->flag &= ~T_ALT_TRANSFORM; t->redraw |= TREDRAW_HARD; @@ -1685,17 +1491,17 @@ bool calculateTransformCenter(bContext *C, int centerMode, float cent3d[3], floa return success; } -static bool transinfo_show_overlay(const struct bContext *C, TransInfo *t, ARegion *ar) +static bool transinfo_show_overlay(const struct bContext *C, TransInfo *t, ARegion *region) { /* Don't show overlays when not the active view and when overlay is disabled: T57139 */ bool ok = false; - if (ar == t->ar) { + if (region == t->region) { ok = true; } else { - ScrArea *sa = CTX_wm_area(C); - if (sa->spacetype == SPACE_VIEW3D) { - View3D *v3d = sa->spacedata.first; + ScrArea *area = CTX_wm_area(C); + if (area->spacetype == SPACE_VIEW3D) { + View3D *v3d = area->spacedata.first; if ((v3d->flag2 & V3D_HIDE_OVERLAYS) == 0) { ok = true; } @@ -1704,11 +1510,11 @@ static bool transinfo_show_overlay(const struct bContext *C, TransInfo *t, ARegi return ok; } -static void drawTransformView(const struct bContext *C, ARegion *ar, void *arg) +static void drawTransformView(const struct bContext *C, ARegion *region, void *arg) { TransInfo *t = arg; - if (!transinfo_show_overlay(C, t, ar)) { + if (!transinfo_show_overlay(C, t, region)) { return; } @@ -1718,7 +1524,7 @@ static void drawTransformView(const struct bContext *C, ARegion *ar, void *arg) drawPropCircle(C, t); drawSnapping(C, t); - if (ar == t->ar) { + if (region == t->region) { /* edge slide, vert slide */ drawEdgeSlide(t); drawVertSlide(t); @@ -1730,13 +1536,13 @@ static void drawTransformView(const struct bContext *C, ARegion *ar, void *arg) /* just draw a little warning message in the top-right corner of the viewport * to warn that autokeying is enabled */ -static void drawAutoKeyWarning(TransInfo *UNUSED(t), ARegion *ar) +static void drawAutoKeyWarning(TransInfo *UNUSED(t), ARegion *region) { const char *printable = IFACE_("Auto Keying On"); float printable_size[2]; int xco, yco; - const rcti *rect = ED_region_visible_rect(ar); + const rcti *rect = ED_region_visible_rect(region); const int font_id = BLF_default(); BLF_width_and_height( @@ -1748,7 +1554,7 @@ static void drawAutoKeyWarning(TransInfo *UNUSED(t), ARegion *ar) /* warning text (to clarify meaning of overlays) * - original color was red to match the icon, but that clashes badly with a less nasty border */ - unsigned char color[3]; + uchar color[3]; UI_GetThemeColorShade3ubv(TH_TEXT_HI, -50, color); BLF_color3ubv(font_id, color); #ifdef WITH_INTERNATIONAL @@ -1770,15 +1576,15 @@ static void drawAutoKeyWarning(TransInfo *UNUSED(t), ARegion *ar) GPU_blend(false); } -static void drawTransformPixel(const struct bContext *C, ARegion *ar, void *arg) +static void drawTransformPixel(const struct bContext *C, ARegion *region, void *arg) { TransInfo *t = arg; - if (!transinfo_show_overlay(C, t, ar)) { + if (!transinfo_show_overlay(C, t, region)) { return; } - if (ar == t->ar) { + if (region == t->region) { Scene *scene = t->scene; ViewLayer *view_layer = t->view_layer; Object *ob = OBACT(view_layer); @@ -1789,10 +1595,10 @@ static void drawTransformPixel(const struct bContext *C, ARegion *ar, void *arg) * AND only for the active region (as showing all is too overwhelming) */ if ((U.autokey_flag & AUTOKEY_FLAG_NOWARNING) == 0) { - if (ar == t->ar) { + if (region == t->region) { if (t->flag & (T_OBJECT | T_POSE)) { if (ob && autokeyframe_cfra_can_key(scene, &ob->id)) { - drawAutoKeyWarning(t, ar); + drawAutoKeyWarning(t, region); } } } @@ -1871,18 +1677,6 @@ void saveTransform(bContext *C, TransInfo *t, wmOperator *op) ts->prop_mode = t->prop_mode; } } - - if (t->spacetype == SPACE_VIEW3D) { - if ((prop = RNA_struct_find_property(op->ptr, "orient_type")) && - !RNA_property_is_set(op->ptr, prop) && - (t->orientation.user != V3D_ORIENT_CUSTOM_MATRIX)) { - TransformOrientationSlot *orient_slot = &t->scene->orientation_slots[SCE_ORIENT_DEFAULT]; - orient_slot->type = t->orientation.user; - BLI_assert(((orient_slot->index_custom == -1) && (t->orientation.custom == NULL)) || - (BKE_scene_transform_orientation_get_index(t->scene, t->orientation.custom) == - orient_slot->index_custom)); - } - } } if (t->flag & T_MODAL) { @@ -1909,33 +1703,6 @@ void saveTransform(bContext *C, TransInfo *t, wmOperator *op) RNA_property_boolean_set(op->ptr, prop, (t->flag & T_NO_MIRROR) == 0); } - /* Orientation used for redo. */ - const bool use_orient_axis = (t->orient_matrix_is_set && - (RNA_struct_find_property(op->ptr, "orient_axis") != NULL)); - short orientation; - if (t->con.mode & CON_APPLY) { - orientation = t->con.orientation; - if (orientation == V3D_ORIENT_CUSTOM) { - const int orientation_index_custom = BKE_scene_transform_orientation_get_index( - t->scene, t->orientation.custom); - /* Maybe we need a t->con.custom_orientation? - * Seems like it would always match t->orientation.custom. */ - orientation = V3D_ORIENT_CUSTOM + orientation_index_custom; - BLI_assert(orientation >= V3D_ORIENT_CUSTOM); - } - } - else if ((t->orientation.user == V3D_ORIENT_CUSTOM_MATRIX) && - (prop = RNA_struct_find_property(op->ptr, "orient_matrix_type"))) { - orientation = RNA_property_enum_get(op->ptr, prop); - } - else if (use_orient_axis) { - /* We're not using an orientation, use the fallback. */ - orientation = t->orientation.unset; - } - else { - orientation = V3D_ORIENT_GLOBAL; - } - if ((prop = RNA_struct_find_property(op->ptr, "orient_axis"))) { if (t->flag & T_MODAL) { if (t->con.mode & CON_APPLY) { @@ -1955,56 +1722,40 @@ void saveTransform(bContext *C, TransInfo *t, wmOperator *op) } } - if ((prop = RNA_struct_find_property(op->ptr, "orient_matrix"))) { - if (t->flag & T_MODAL) { - if (orientation != V3D_ORIENT_CUSTOM_MATRIX) { - if (t->flag & T_MODAL) { - RNA_enum_set(op->ptr, "orient_matrix_type", orientation); - } - } - if (t->con.mode & CON_APPLY) { - RNA_float_set_array(op->ptr, "orient_matrix", &t->con.mtx[0][0]); - } - else if (use_orient_axis) { - RNA_float_set_array(op->ptr, "orient_matrix", &t->orient_matrix[0][0]); - } - else { - RNA_float_set_array(op->ptr, "orient_matrix", &t->spacemtx[0][0]); - } - } - } - if ((prop = RNA_struct_find_property(op->ptr, "orient_type"))) { - /* constraint orientation can be global, even if user selects something else - * so use the orientation in the constraint if set */ + short orient_set, orient_cur; + orient_set = RNA_property_is_set(op->ptr, prop) ? RNA_property_enum_get(op->ptr, prop) : -1; + orient_cur = t->orientation.types[t->orientation.index]; - /* Use 'orient_matrix' instead. */ - if (t->flag & T_MODAL) { - if (orientation != V3D_ORIENT_CUSTOM_MATRIX) { - RNA_property_enum_set(op->ptr, prop, orientation); - } + if (!ELEM(orient_cur, orient_set, V3D_ORIENT_CUSTOM_MATRIX)) { + RNA_property_enum_set(op->ptr, prop, orient_cur); + orient_set = orient_cur; + } + + if (((prop = RNA_struct_find_property(op->ptr, "orient_matrix_type")) && + !RNA_property_is_set(op->ptr, prop))) { + /* Set the first time to register on redo. */ + RNA_property_enum_set(op->ptr, prop, orient_set); + RNA_float_set_array(op->ptr, "orient_matrix", &t->spacemtx[0][0]); } } if ((prop = RNA_struct_find_property(op->ptr, "constraint_axis"))) { bool constraint_axis[3] = {false, false, false}; - if (t->flag & T_MODAL) { - /* Only set if needed, so we can hide in the UI when nothing is set. - * See 'transform_poll_property'. */ - if (t->con.mode & CON_APPLY) { - if (t->con.mode & CON_AXIS0) { - constraint_axis[0] = true; - } - if (t->con.mode & CON_AXIS1) { - constraint_axis[1] = true; - } - if (t->con.mode & CON_AXIS2) { - constraint_axis[2] = true; - } + if (t->con.mode & CON_APPLY) { + if (t->con.mode & CON_AXIS0) { + constraint_axis[0] = true; } - if (ELEM(true, UNPACK3(constraint_axis))) { - RNA_property_boolean_set_array(op->ptr, prop, constraint_axis); + if (t->con.mode & CON_AXIS1) { + constraint_axis[1] = true; } + if (t->con.mode & CON_AXIS2) { + constraint_axis[2] = true; + } + RNA_property_boolean_set_array(op->ptr, prop, constraint_axis); + } + else { + RNA_property_unset(op->ptr, prop); } } @@ -2031,6 +1782,43 @@ void saveTransform(bContext *C, TransInfo *t, wmOperator *op) } } +static void initSnapSpatial(TransInfo *t, float r_snap[3]) +{ + if (t->spacetype == SPACE_VIEW3D) { + RegionView3D *rv3d = t->region->regiondata; + + if (rv3d) { + View3D *v3d = t->area->spacedata.first; + r_snap[0] = 0.0f; + r_snap[1] = ED_view3d_grid_view_scale(t->scene, v3d, rv3d, NULL) * 1.0f; + r_snap[2] = r_snap[1] * 0.1f; + } + } + else if (t->spacetype == SPACE_IMAGE) { + r_snap[0] = 0.0f; + r_snap[1] = 0.0625f; + r_snap[2] = 0.03125f; + } + else if (t->spacetype == SPACE_CLIP) { + r_snap[0] = 0.0f; + r_snap[1] = 0.125f; + r_snap[2] = 0.0625f; + } + else if (t->spacetype == SPACE_NODE) { + r_snap[0] = 0.0f; + r_snap[1] = r_snap[2] = ED_node_grid_size(); + } + else if (t->spacetype == SPACE_GRAPH) { + r_snap[0] = 0.0f; + r_snap[1] = 1.0; + r_snap[2] = 0.1f; + } + else { + r_snap[0] = 0.0f; + r_snap[1] = r_snap[2] = 1.0f; + } +} + /** * \note caller needs to free 't' on a 0 return * \warning \a event might be NULL (when tweaking from redo panel) @@ -2093,15 +1881,21 @@ bool initTransform(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve unit_m3(t->spacemtx); initTransInfo(C, t, op, event); - initTransformOrientation(C, t); + + /* Use the custom orientation when it is set. */ + short orientation = t->orientation.types[0] == V3D_ORIENT_CUSTOM_MATRIX ? + V3D_ORIENT_CUSTOM_MATRIX : + t->orientation.types[t->orientation.index]; + + initTransformOrientation(C, t, orientation); if (t->spacetype == SPACE_VIEW3D) { t->draw_handle_apply = ED_region_draw_cb_activate( - t->ar->type, drawTransformApply, t, REGION_DRAW_PRE_VIEW); + t->region->type, drawTransformApply, t, REGION_DRAW_PRE_VIEW); t->draw_handle_view = ED_region_draw_cb_activate( - t->ar->type, drawTransformView, t, REGION_DRAW_POST_VIEW); + t->region->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->region->type, drawTransformPixel, t, REGION_DRAW_POST_PIXEL); t->draw_handle_cursor = WM_paint_cursor_activate(CTX_wm_manager(C), SPACE_TYPE_ANY, RGN_TYPE_ANY, @@ -2111,7 +1905,7 @@ bool initTransform(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve } else if (t->spacetype == SPACE_IMAGE) { t->draw_handle_view = ED_region_draw_cb_activate( - t->ar->type, drawTransformView, t, REGION_DRAW_POST_VIEW); + t->region->type, drawTransformView, t, REGION_DRAW_POST_VIEW); t->draw_handle_cursor = WM_paint_cursor_activate(CTX_wm_manager(C), SPACE_TYPE_ANY, RGN_TYPE_ANY, @@ -2121,7 +1915,7 @@ bool initTransform(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve } else if (t->spacetype == SPACE_CLIP) { t->draw_handle_view = ED_region_draw_cb_activate( - t->ar->type, drawTransformView, t, REGION_DRAW_POST_VIEW); + t->region->type, drawTransformView, t, REGION_DRAW_POST_VIEW); t->draw_handle_cursor = WM_paint_cursor_activate(CTX_wm_manager(C), SPACE_TYPE_ANY, RGN_TYPE_ANY, @@ -2131,7 +1925,7 @@ bool initTransform(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve } else if (t->spacetype == SPACE_NODE) { t->draw_handle_view = ED_region_draw_cb_activate( - t->ar->type, drawTransformView, t, REGION_DRAW_POST_VIEW); + t->region->type, drawTransformView, t, REGION_DRAW_POST_VIEW); t->draw_handle_cursor = WM_paint_cursor_activate(CTX_wm_manager(C), SPACE_TYPE_ANY, RGN_TYPE_ANY, @@ -2141,7 +1935,7 @@ bool initTransform(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve } else if (t->spacetype == SPACE_GRAPH) { t->draw_handle_view = ED_region_draw_cb_activate( - t->ar->type, drawTransformView, t, REGION_DRAW_POST_VIEW); + t->region->type, drawTransformView, t, REGION_DRAW_POST_VIEW); t->draw_handle_cursor = WM_paint_cursor_activate(CTX_wm_manager(C), SPACE_TYPE_ANY, RGN_TYPE_ANY, @@ -2151,7 +1945,7 @@ bool initTransform(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve } else if (t->spacetype == SPACE_ACTION) { t->draw_handle_view = ED_region_draw_cb_activate( - t->ar->type, drawTransformView, t, REGION_DRAW_POST_VIEW); + t->region->type, drawTransformView, t, REGION_DRAW_POST_VIEW); t->draw_handle_cursor = WM_paint_cursor_activate(CTX_wm_manager(C), SPACE_TYPE_ANY, RGN_TYPE_ANY, @@ -2190,10 +1984,10 @@ bool initTransform(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve } if (kmi->propvalue == TFM_MODAL_SNAP_INV_ON && kmi->val == KM_PRESS) { - if ((ELEM(kmi->type, LEFTCTRLKEY, RIGHTCTRLKEY) && event->ctrl) || - (ELEM(kmi->type, LEFTSHIFTKEY, RIGHTSHIFTKEY) && event->shift) || - (ELEM(kmi->type, LEFTALTKEY, RIGHTALTKEY) && event->alt) || - ((kmi->type == OSKEY) && event->oskey)) { + if ((ELEM(kmi->type, EVT_LEFTCTRLKEY, EVT_RIGHTCTRLKEY) && event->ctrl) || + (ELEM(kmi->type, EVT_LEFTSHIFTKEY, EVT_RIGHTSHIFTKEY) && event->shift) || + (ELEM(kmi->type, EVT_LEFTALTKEY, EVT_RIGHTALTKEY) && event->alt) || + ((kmi->type == EVT_OSKEY) && event->oskey)) { t->modifiers |= MOD_SNAP_INVERT; } break; @@ -2218,33 +2012,6 @@ bool initTransform(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve calculatePropRatio(t); calculateCenter(t); - /* Overwrite initial values if operator supplied a non-null vector. - * - * Run before init functions so 'values_modal_offset' can be applied on mouse input. - */ - BLI_assert(is_zero_v4(t->values_modal_offset)); - 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 */ - - if (RNA_property_array_check(prop)) { - RNA_float_get_array(op->ptr, "value", values); - } - else { - values[0] = RNA_float_get(op->ptr, "value"); - } - - copy_v4_v4(t->values, values); - - if (t->flag & T_MODAL) { - copy_v4_v4(t->values_modal_offset, values); - t->redraw = TREDRAW_HARD; - } - else { - copy_v4_v4(t->values, values); - t->flag |= T_INPUT_IS_VALUES_FINAL; - } - } - if (event) { /* Initialize accurate transform to settings requested by keymap. */ bool use_accurate = false; @@ -2257,145 +2024,7 @@ bool initTransform(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve initMouseInput(t, &t->mouse, t->center2d, event->mval, use_accurate); } - switch (mode) { - case TFM_TRANSLATION: - initTranslation(t); - break; - case TFM_ROTATION: - initRotation(t); - break; - case TFM_RESIZE: - initResize(t); - break; - case TFM_SKIN_RESIZE: - initSkinResize(t); - break; - case TFM_TOSPHERE: - initToSphere(t); - break; - case TFM_SHEAR: - initShear(t); - break; - case TFM_BEND: - initBend(t); - break; - case TFM_SHRINKFATTEN: - initShrinkFatten(t); - break; - case TFM_TILT: - initTilt(t); - break; - case TFM_CURVE_SHRINKFATTEN: - initCurveShrinkFatten(t); - break; - case TFM_MASK_SHRINKFATTEN: - initMaskShrinkFatten(t); - break; - case TFM_GPENCIL_SHRINKFATTEN: - initGPShrinkFatten(t); - break; - case TFM_TRACKBALL: - initTrackball(t); - break; - case TFM_PUSHPULL: - initPushPull(t); - break; - case TFM_CREASE: - initCrease(t); - break; - case TFM_BONESIZE: { /* used for both B-Bone width (bonesize) as for deform-dist (envelope) */ - /* Note: we have to pick one, use the active object. */ - TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_OK(t); - bArmature *arm = tc->poseobj->data; - if (arm->drawtype == ARM_ENVELOPE) { - initBoneEnvelope(t); - 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: - case TFM_VERT_SLIDE: { - const bool use_even = (op ? RNA_boolean_get(op->ptr, "use_even") : false); - const bool flipped = (op ? RNA_boolean_get(op->ptr, "flipped") : false); - const bool use_clamp = (op ? RNA_boolean_get(op->ptr, "use_clamp") : true); - if (mode == TFM_EDGE_SLIDE) { - const bool use_double_side = (op ? !RNA_boolean_get(op->ptr, "single_side") : true); - initEdgeSlide_ex(t, use_double_side, use_even, flipped, use_clamp); - } - else { - initVertSlide_ex(t, use_even, flipped, use_clamp); - } - break; - } - case TFM_BONE_ROLL: - initBoneRoll(t); - break; - case TFM_TIME_TRANSLATE: - initTimeTranslate(t); - break; - case TFM_TIME_SLIDE: - initTimeSlide(t); - break; - case TFM_TIME_SCALE: - initTimeScale(t); - break; - case TFM_TIME_DUPLICATE: - /* same as TFM_TIME_EXTEND, but we need the mode info for later - * so that duplicate-culling will work properly - */ - if (ELEM(t->spacetype, SPACE_GRAPH, SPACE_NLA)) { - initTranslation(t); - } - else { - initTimeTranslate(t); - } - t->mode = mode; - break; - case TFM_TIME_EXTEND: - /* now that transdata has been made, do like for TFM_TIME_TRANSLATE (for most Animation - * Editors because they have only 1D transforms for time values) or TFM_TRANSLATION - * (for Graph/NLA Editors only since they uses 'standard' transforms to get 2D movement) - * depending on which editor this was called from - */ - if (ELEM(t->spacetype, SPACE_GRAPH, SPACE_NLA)) { - initTranslation(t); - } - else { - initTimeTranslate(t); - } - break; - case TFM_BAKE_TIME: - initBakeTime(t); - break; - case TFM_MIRROR: - initMirror(t); - break; - case TFM_BWEIGHT: - initBevelWeight(t); - break; - case TFM_ALIGN: - initAlign(t); - break; - case TFM_SEQ_SLIDE: - initSeqSlide(t); - break; - case TFM_NORMAL_ROTATION: - initNormalRotation(t); - break; - case TFM_GPENCIL_OPACITY: - initGPOpacity(t); - break; - } + transform_mode_init(t, op, mode); if (t->state == TRANS_CANCEL) { postTrans(C, t); @@ -2413,38 +2042,8 @@ bool initTransform(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve } /* Constraint init from operator */ - if ((t->flag & T_MODAL) || - /* For mirror operator the constraint axes are effectively the values. */ - (RNA_struct_find_property(op->ptr, "value") == NULL)) { - if ((prop = RNA_struct_find_property(op->ptr, "constraint_axis")) && - RNA_property_is_set(op->ptr, prop)) { - bool constraint_axis[3]; - - RNA_property_boolean_get_array(op->ptr, prop, constraint_axis); - - if (constraint_axis[0] || constraint_axis[1] || constraint_axis[2]) { - t->con.mode |= CON_APPLY; - - if (constraint_axis[0]) { - t->con.mode |= CON_AXIS0; - } - if (constraint_axis[1]) { - t->con.mode |= CON_AXIS1; - } - if (constraint_axis[2]) { - t->con.mode |= CON_AXIS2; - } - - setUserConstraint(t, t->orientation.user, t->con.mode, "%s"); - } - } - } - else { - /* So we can adjust in non global orientation. */ - if (t->orientation.user != V3D_ORIENT_GLOBAL) { - t->con.mode |= CON_APPLY | CON_AXIS0 | CON_AXIS1 | CON_AXIS2; - setUserConstraint(t, t->orientation.user, t->con.mode, "%s"); - } + if (t->con.mode & CON_APPLY) { + setUserConstraint(t, t->orientation.types[t->orientation.index], t->con.mode, "%s"); } /* Don't write into the values when non-modal because they are already set from operator redo @@ -2518,7 +2117,7 @@ void transformApply(bContext *C, TransInfo *t) t->context = NULL; } -static void drawTransformApply(const bContext *C, ARegion *UNUSED(ar), void *arg) +static void drawTransformApply(const bContext *C, ARegion *UNUSED(region), void *arg) { TransInfo *t = arg; @@ -2575,6597 +2174,6 @@ int transformEnd(bContext *C, TransInfo *t) return exit_code; } -/* ************************** TRANSFORM LOCKS **************************** */ - -static void protectedTransBits(short protectflag, float vec[3]) -{ - if (protectflag & OB_LOCK_LOCX) { - vec[0] = 0.0f; - } - if (protectflag & OB_LOCK_LOCY) { - vec[1] = 0.0f; - } - if (protectflag & OB_LOCK_LOCZ) { - vec[2] = 0.0f; - } -} - -static void protectedSizeBits(short protectflag, float size[3]) -{ - if (protectflag & OB_LOCK_SCALEX) { - size[0] = 1.0f; - } - if (protectflag & OB_LOCK_SCALEY) { - size[1] = 1.0f; - } - if (protectflag & OB_LOCK_SCALEZ) { - size[2] = 1.0f; - } -} - -static void protectedRotateBits(short protectflag, float eul[3], const float oldeul[3]) -{ - if (protectflag & OB_LOCK_ROTX) { - eul[0] = oldeul[0]; - } - if (protectflag & OB_LOCK_ROTY) { - eul[1] = oldeul[1]; - } - if (protectflag & OB_LOCK_ROTZ) { - eul[2] = oldeul[2]; - } -} - -/* this function only does the delta rotation */ -/* axis-angle is usually internally stored as quats... */ -static void protectedAxisAngleBits( - short protectflag, float axis[3], float *angle, float oldAxis[3], float oldAngle) -{ - /* check that protection flags are set */ - if ((protectflag & (OB_LOCK_ROTX | OB_LOCK_ROTY | OB_LOCK_ROTZ | OB_LOCK_ROTW)) == 0) { - return; - } - - if (protectflag & OB_LOCK_ROT4D) { - /* axis-angle getting limited as 4D entities that they are... */ - if (protectflag & OB_LOCK_ROTW) { - *angle = oldAngle; - } - if (protectflag & OB_LOCK_ROTX) { - axis[0] = oldAxis[0]; - } - if (protectflag & OB_LOCK_ROTY) { - axis[1] = oldAxis[1]; - } - if (protectflag & OB_LOCK_ROTZ) { - axis[2] = oldAxis[2]; - } - } - else { - /* axis-angle get limited with euler... */ - float eul[3], oldeul[3]; - - axis_angle_to_eulO(eul, EULER_ORDER_DEFAULT, axis, *angle); - axis_angle_to_eulO(oldeul, EULER_ORDER_DEFAULT, oldAxis, oldAngle); - - if (protectflag & OB_LOCK_ROTX) { - eul[0] = oldeul[0]; - } - if (protectflag & OB_LOCK_ROTY) { - eul[1] = oldeul[1]; - } - if (protectflag & OB_LOCK_ROTZ) { - eul[2] = oldeul[2]; - } - - eulO_to_axis_angle(axis, angle, eul, EULER_ORDER_DEFAULT); - - /* When converting to axis-angle, - * we need a special exception for the case when there is no axis. */ - if (IS_EQF(axis[0], axis[1]) && IS_EQF(axis[1], axis[2])) { - /* for now, rotate around y-axis then (so that it simply becomes the roll) */ - axis[1] = 1.0f; - } - } -} - -/* this function only does the delta rotation */ -static void protectedQuaternionBits(short protectflag, float quat[4], const float oldquat[4]) -{ - /* check that protection flags are set */ - if ((protectflag & (OB_LOCK_ROTX | OB_LOCK_ROTY | OB_LOCK_ROTZ | OB_LOCK_ROTW)) == 0) { - return; - } - - if (protectflag & OB_LOCK_ROT4D) { - /* quaternions getting limited as 4D entities that they are... */ - if (protectflag & OB_LOCK_ROTW) { - quat[0] = oldquat[0]; - } - if (protectflag & OB_LOCK_ROTX) { - quat[1] = oldquat[1]; - } - if (protectflag & OB_LOCK_ROTY) { - quat[2] = oldquat[2]; - } - if (protectflag & OB_LOCK_ROTZ) { - quat[3] = oldquat[3]; - } - } - else { - /* quaternions get limited with euler... (compatibility mode) */ - float eul[3], oldeul[3], nquat[4], noldquat[4]; - float qlen; - - qlen = normalize_qt_qt(nquat, quat); - normalize_qt_qt(noldquat, oldquat); - - quat_to_eul(eul, nquat); - quat_to_eul(oldeul, noldquat); - - if (protectflag & OB_LOCK_ROTX) { - eul[0] = oldeul[0]; - } - if (protectflag & OB_LOCK_ROTY) { - eul[1] = oldeul[1]; - } - if (protectflag & OB_LOCK_ROTZ) { - eul[2] = oldeul[2]; - } - - eul_to_quat(quat, eul); - - /* restore original quat size */ - mul_qt_fl(quat, qlen); - - /* quaternions flip w sign to accumulate rotations correctly */ - if ((nquat[0] < 0.0f && quat[0] > 0.0f) || (nquat[0] > 0.0f && quat[0] < 0.0f)) { - mul_qt_fl(quat, -1.0f); - } - } -} - -/* ******************* TRANSFORM LIMITS ********************** */ - -static void constraintTransLim(TransInfo *t, TransData *td) -{ - if (td->con) { - 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; - float ctime = (float)(t->scene->r.cfra); - - /* Make a temporary bConstraintOb for using these limit constraints - * - they only care that cob->matrix is correctly set ;-) - * - current space should be local - */ - unit_m4(cob.matrix); - copy_v3_v3(cob.matrix[3], td->loc); - - /* Evaluate valid constraints */ - for (con = td->con; con; con = con->next) { - const bConstraintTypeInfo *cti = NULL; - ListBase targets = {NULL, NULL}; - - /* only consider constraint if enabled */ - if (con->flag & (CONSTRAINT_DISABLE | CONSTRAINT_OFF)) { - continue; - } - if (con->enforce == 0.0f) { - continue; - } - - /* only use it if it's tagged for this purpose (and the right type) */ - if (con->type == CONSTRAINT_TYPE_LOCLIMIT) { - bLocLimitConstraint *data = con->data; - - if ((data->flag2 & LIMIT_TRANSFORM) == 0) { - continue; - } - cti = ctiLoc; - } - else if (con->type == CONSTRAINT_TYPE_DISTLIMIT) { - bDistLimitConstraint *data = con->data; - - if ((data->flag & LIMITDIST_TRANSFORM) == 0) { - continue; - } - cti = ctiDist; - } - - if (cti) { - /* do space conversions */ - if (con->ownspace == CONSTRAINT_SPACE_WORLD) { - /* just multiply by td->mtx (this should be ok) */ - mul_m4_m3m4(cob.matrix, td->mtx, cob.matrix); - } - else if (con->ownspace != CONSTRAINT_SPACE_LOCAL) { - /* skip... incompatible spacetype */ - continue; - } - - /* get constraint targets if needed */ - BKE_constraint_targets_for_solving_get(t->depsgraph, con, &cob, &targets, ctime); - - /* do constraint */ - cti->evaluate_constraint(con, &cob, &targets); - - /* convert spaces again */ - if (con->ownspace == CONSTRAINT_SPACE_WORLD) { - /* just multiply by td->smtx (this should be ok) */ - mul_m4_m3m4(cob.matrix, td->smtx, cob.matrix); - } - - /* free targets list */ - BLI_freelistN(&targets); - } - } - - /* copy results from cob->matrix */ - copy_v3_v3(td->loc, cob.matrix[3]); - } -} - -static void constraintob_from_transdata(bConstraintOb *cob, TransData *td) -{ - /* Make a temporary bConstraintOb for use by limit constraints - * - they only care that cob->matrix is correctly set ;-) - * - current space should be local - */ - memset(cob, 0, sizeof(bConstraintOb)); - if (td->ext) { - if (td->ext->rotOrder == ROT_MODE_QUAT) { - /* quats */ - /* objects and bones do normalization first too, otherwise - * we don't necessarily end up with a rotation matrix, and - * then conversion back to quat gives a different result */ - float quat[4]; - normalize_qt_qt(quat, td->ext->quat); - quat_to_mat4(cob->matrix, quat); - } - else if (td->ext->rotOrder == ROT_MODE_AXISANGLE) { - /* axis angle */ - axis_angle_to_mat4(cob->matrix, td->ext->rotAxis, *td->ext->rotAngle); - } - else { - /* eulers */ - eulO_to_mat4(cob->matrix, td->ext->rot, td->ext->rotOrder); - } - } -} - -static void constraintRotLim(TransInfo *UNUSED(t), TransData *td) -{ - if (td->con) { - const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_from_type(CONSTRAINT_TYPE_ROTLIMIT); - bConstraintOb cob; - bConstraint *con; - bool do_limit = false; - - /* Evaluate valid constraints */ - for (con = td->con; con; con = con->next) { - /* only consider constraint if enabled */ - if (con->flag & (CONSTRAINT_DISABLE | CONSTRAINT_OFF)) { - continue; - } - if (con->enforce == 0.0f) { - continue; - } - - /* we're only interested in Limit-Rotation constraints */ - if (con->type == CONSTRAINT_TYPE_ROTLIMIT) { - bRotLimitConstraint *data = con->data; - - /* only use it if it's tagged for this purpose */ - if ((data->flag2 & LIMIT_TRANSFORM) == 0) { - continue; - } - - /* skip incompatible spacetypes */ - if (!ELEM(con->ownspace, CONSTRAINT_SPACE_WORLD, CONSTRAINT_SPACE_LOCAL)) { - continue; - } - - /* only do conversion if necessary, to preserve quats and eulers */ - if (do_limit == false) { - constraintob_from_transdata(&cob, td); - do_limit = true; - } - - /* do space conversions */ - if (con->ownspace == CONSTRAINT_SPACE_WORLD) { - /* just multiply by td->mtx (this should be ok) */ - mul_m4_m3m4(cob.matrix, td->mtx, cob.matrix); - } - - /* do constraint */ - cti->evaluate_constraint(con, &cob, NULL); - - /* convert spaces again */ - if (con->ownspace == CONSTRAINT_SPACE_WORLD) { - /* just multiply by td->smtx (this should be ok) */ - mul_m4_m3m4(cob.matrix, td->smtx, cob.matrix); - } - } - } - - if (do_limit) { - /* copy results from cob->matrix */ - if (td->ext->rotOrder == ROT_MODE_QUAT) { - /* quats */ - mat4_to_quat(td->ext->quat, cob.matrix); - } - else if (td->ext->rotOrder == ROT_MODE_AXISANGLE) { - /* axis angle */ - mat4_to_axis_angle(td->ext->rotAxis, td->ext->rotAngle, cob.matrix); - } - else { - /* eulers */ - mat4_to_eulO(td->ext->rot, td->ext->rotOrder, cob.matrix); - } - } - } -} - -static void constraintSizeLim(TransInfo *t, TransData *td) -{ - if (td->con && td->ext) { - const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_from_type(CONSTRAINT_TYPE_SIZELIMIT); - bConstraintOb cob = {NULL}; - bConstraint *con; - float size_sign[3], size_abs[3]; - int i; - - /* Make a temporary bConstraintOb for using these limit constraints - * - they only care that cob->matrix is correctly set ;-) - * - current space should be local - */ - if ((td->flag & TD_SINGLESIZE) && !(t->con.mode & CON_APPLY)) { - /* scale val and reset size */ - return; // TODO: fix this case - } - else { - /* Reset val if SINGLESIZE but using a constraint */ - if (td->flag & TD_SINGLESIZE) { - return; - } - - /* separate out sign to apply back later */ - for (i = 0; i < 3; i++) { - size_sign[i] = signf(td->ext->size[i]); - size_abs[i] = fabsf(td->ext->size[i]); - } - - size_to_mat4(cob.matrix, size_abs); - } - - /* Evaluate valid constraints */ - for (con = td->con; con; con = con->next) { - /* only consider constraint if enabled */ - if (con->flag & (CONSTRAINT_DISABLE | CONSTRAINT_OFF)) { - continue; - } - if (con->enforce == 0.0f) { - continue; - } - - /* we're only interested in Limit-Scale constraints */ - if (con->type == CONSTRAINT_TYPE_SIZELIMIT) { - bSizeLimitConstraint *data = con->data; - - /* only use it if it's tagged for this purpose */ - if ((data->flag2 & LIMIT_TRANSFORM) == 0) { - continue; - } - - /* do space conversions */ - if (con->ownspace == CONSTRAINT_SPACE_WORLD) { - /* just multiply by td->mtx (this should be ok) */ - mul_m4_m3m4(cob.matrix, td->mtx, cob.matrix); - } - else if (con->ownspace != CONSTRAINT_SPACE_LOCAL) { - /* skip... incompatible spacetype */ - continue; - } - - /* do constraint */ - cti->evaluate_constraint(con, &cob, NULL); - - /* convert spaces again */ - if (con->ownspace == CONSTRAINT_SPACE_WORLD) { - /* just multiply by td->smtx (this should be ok) */ - mul_m4_m3m4(cob.matrix, td->smtx, cob.matrix); - } - } - } - - /* copy results from cob->matrix */ - if ((td->flag & TD_SINGLESIZE) && !(t->con.mode & CON_APPLY)) { - /* scale val and reset size */ - return; // TODO: fix this case - } - else { - /* Reset val if SINGLESIZE but using a constraint */ - if (td->flag & TD_SINGLESIZE) { - return; - } - - /* extrace scale from matrix and apply back sign */ - mat4_to_size(td->ext->size, cob.matrix); - mul_v3_v3(td->ext->size, size_sign); - } - } -} - -/* -------------------------------------------------------------------- */ -/* Transform (Bend) */ - -/** \name Transform Bend - * \{ */ - -struct BendCustomData { - /* All values are in global space. */ - float warp_sta[3]; - float warp_end[3]; - - float warp_nor[3]; - float warp_tan[3]; - - /* for applying the mouse distance */ - float warp_init_dist; -}; - -static void initBend(TransInfo *t) -{ - const float mval_fl[2] = {UNPACK2(t->mval)}; - const float *curs; - float tvec[3]; - struct BendCustomData *data; - - t->mode = TFM_BEND; - t->transform = Bend; - t->handleEvent = handleEventBend; - - setInputPostFct(&t->mouse, postInputRotation); - initMouseInputMode(t, &t->mouse, INPUT_ANGLE_SPRING); - - t->idx_max = 1; - t->num.idx_max = 1; - t->snap[0] = 0.0f; - t->snap[1] = SNAP_INCREMENTAL_ANGLE; - t->snap[2] = t->snap[1] * 0.2; - - copy_v3_fl(t->num.val_inc, t->snap[1]); - t->num.unit_sys = t->scene->unit.system; - t->num.unit_use_radians = (t->scene->unit.system_rotation == USER_UNIT_ROT_RADIANS); - t->num.unit_type[0] = B_UNIT_ROTATION; - t->num.unit_type[1] = B_UNIT_LENGTH; - - t->flag |= T_NO_CONSTRAINT; - - // copy_v3_v3(t->center, ED_view3d_cursor3d_get(t->scene, t->view)); - if ((t->flag & T_OVERRIDE_CENTER) == 0) { - calculateCenterCursor(t, t->center_global); - } - calculateCenterLocal(t, t->center_global); - - t->val = 0.0f; - - data = MEM_callocN(sizeof(*data), __func__); - - curs = t->scene->cursor.location; - copy_v3_v3(data->warp_sta, curs); - ED_view3d_win_to_3d(t->sa->spacedata.first, t->ar, curs, mval_fl, data->warp_end); - - copy_v3_v3(data->warp_nor, t->viewinv[2]); - normalize_v3(data->warp_nor); - - /* tangent */ - sub_v3_v3v3(tvec, data->warp_end, data->warp_sta); - cross_v3_v3v3(data->warp_tan, tvec, data->warp_nor); - normalize_v3(data->warp_tan); - - data->warp_init_dist = len_v3v3(data->warp_end, data->warp_sta); - - t->custom.mode.data = data; - t->custom.mode.use_free = true; -} - -static eRedrawFlag handleEventBend(TransInfo *UNUSED(t), const wmEvent *event) -{ - eRedrawFlag status = TREDRAW_NOTHING; - - if (event->type == MIDDLEMOUSE && event->val == KM_PRESS) { - status = TREDRAW_HARD; - } - - return status; -} - -static void Bend(TransInfo *t, const int UNUSED(mval[2])) -{ - float vec[3]; - float pivot_global[3]; - float warp_end_radius_global[3]; - int i; - char str[UI_MAX_DRAW_STR]; - const struct BendCustomData *data = t->custom.mode.data; - const bool is_clamp = (t->flag & T_ALT_TRANSFORM) == 0; - - union { - struct { - float angle, scale; - }; - float vector[2]; - } values; - - /* amount of radians for bend */ - copy_v2_v2(values.vector, t->values); - -#if 0 - snapGrid(t, angle_rad); -#else - /* hrmf, snapping radius is using 'angle' steps, need to convert to something else - * this isnt essential but nicer to give reasonable snapping values for radius */ - if (t->tsnap.mode & SCE_SNAP_MODE_INCREMENT) { - const float radius_snap = 0.1f; - const float snap_hack = (t->snap[1] * data->warp_init_dist) / radius_snap; - values.scale *= snap_hack; - snapGridIncrement(t, values.vector); - values.scale /= snap_hack; - } -#endif - - if (applyNumInput(&t->num, values.vector)) { - values.scale = values.scale / data->warp_init_dist; - } - - copy_v2_v2(t->values_final, values.vector); - - /* header print for NumInput */ - if (hasNumInput(&t->num)) { - char c[NUM_STR_REP_LEN * 2]; - - outputNumInput(&(t->num), c, &t->scene->unit); - - BLI_snprintf(str, - sizeof(str), - TIP_("Bend Angle: %s Radius: %s Alt, Clamp %s"), - &c[0], - &c[NUM_STR_REP_LEN], - WM_bool_as_string(is_clamp)); - } - else { - /* default header print */ - BLI_snprintf(str, - sizeof(str), - TIP_("Bend Angle: %.3f Radius: %.4f, Alt, Clamp %s"), - RAD2DEGF(values.angle), - values.scale * data->warp_init_dist, - WM_bool_as_string(is_clamp)); - } - - values.angle *= -1.0f; - values.scale *= data->warp_init_dist; - - /* calc 'data->warp_end' from 'data->warp_end_init' */ - copy_v3_v3(warp_end_radius_global, data->warp_end); - dist_ensure_v3_v3fl(warp_end_radius_global, data->warp_sta, values.scale); - /* done */ - - /* calculate pivot */ - copy_v3_v3(pivot_global, data->warp_sta); - if (values.angle > 0.0f) { - madd_v3_v3fl(pivot_global, - data->warp_tan, - -values.scale * shell_angle_to_dist((float)M_PI_2 - values.angle)); - } - else { - madd_v3_v3fl(pivot_global, - data->warp_tan, - +values.scale * shell_angle_to_dist((float)M_PI_2 + values.angle)); - } - - /* TODO(campbell): xform, compensate object center. */ - FOREACH_TRANS_DATA_CONTAINER (t, tc) { - TransData *td = tc->data; - - float warp_sta_local[3]; - float warp_end_local[3]; - float warp_end_radius_local[3]; - float pivot_local[3]; - - if (tc->use_local_mat) { - sub_v3_v3v3(warp_sta_local, data->warp_sta, tc->mat[3]); - sub_v3_v3v3(warp_end_local, data->warp_end, tc->mat[3]); - sub_v3_v3v3(warp_end_radius_local, warp_end_radius_global, tc->mat[3]); - sub_v3_v3v3(pivot_local, pivot_global, tc->mat[3]); - } - else { - copy_v3_v3(warp_sta_local, data->warp_sta); - copy_v3_v3(warp_end_local, data->warp_end); - copy_v3_v3(warp_end_radius_local, warp_end_radius_global); - copy_v3_v3(pivot_local, pivot_global); - } - - for (i = 0; i < tc->data_len; i++, td++) { - float mat[3][3]; - float delta[3]; - float fac, fac_scaled; - - if (td->flag & TD_NOACTION) { - break; - } - - if (td->flag & TD_SKIP) { - continue; - } - - if (UNLIKELY(values.angle == 0.0f)) { - copy_v3_v3(td->loc, td->iloc); - continue; - } - - copy_v3_v3(vec, td->iloc); - mul_m3_v3(td->mtx, vec); - - fac = line_point_factor_v3(vec, warp_sta_local, warp_end_radius_local); - if (is_clamp) { - CLAMP(fac, 0.0f, 1.0f); - } - - if (t->options & CTX_GPENCIL_STROKES) { - /* grease pencil multiframe falloff */ - bGPDstroke *gps = (bGPDstroke *)td->extra; - if (gps != NULL) { - fac_scaled = fac * td->factor * gps->runtime.multi_frame_falloff; - } - else { - fac_scaled = fac * td->factor; - } - } - else { - fac_scaled = fac * td->factor; - } - - axis_angle_normalized_to_mat3(mat, data->warp_nor, values.angle * fac_scaled); - interp_v3_v3v3(delta, warp_sta_local, warp_end_radius_local, fac_scaled); - sub_v3_v3(delta, warp_sta_local); - - /* delta is subtracted, rotation adds back this offset */ - sub_v3_v3(vec, delta); - - sub_v3_v3(vec, pivot_local); - mul_m3_v3(mat, vec); - add_v3_v3(vec, pivot_local); - - mul_m3_v3(td->smtx, vec); - - /* rotation */ - if ((t->flag & T_POINTS) == 0) { - ElementRotation(t, tc, td, mat, V3D_AROUND_LOCAL_ORIGINS); - } - - /* location */ - copy_v3_v3(td->loc, vec); - } - } - - recalcData(t); - - ED_area_status_text(t->sa, str); -} -/** \} */ - -/* -------------------------------------------------------------------- */ -/* Transform (Shear) */ - -/** \name Transform Shear - * \{ */ - -static void initShear_mouseInputMode(TransInfo *t) -{ - float dir[3]; - bool dir_flip = false; - copy_v3_v3(dir, t->orient_matrix[t->orient_axis_ortho]); - - /* Needed for axis aligned view gizmo. */ - if (t->orientation.user == V3D_ORIENT_VIEW) { - if (t->orient_axis_ortho == 0) { - if (t->center2d[1] > t->mouse.imval[1]) { - dir_flip = !dir_flip; - } - } - else if (t->orient_axis_ortho == 1) { - if (t->center2d[0] > t->mouse.imval[0]) { - dir_flip = !dir_flip; - } - } - } - - /* Without this, half the gizmo handles move in the opposite direction. */ - if ((t->orient_axis_ortho + 1) % 3 != t->orient_axis) { - dir_flip = !dir_flip; - } - - if (dir_flip) { - negate_v3(dir); - } - - mul_mat3_m4_v3(t->viewmat, dir); - if (normalize_v2(dir) == 0.0f) { - dir[0] = 1.0f; - } - setCustomPointsFromDirection(t, &t->mouse, dir); - - initMouseInputMode(t, &t->mouse, INPUT_CUSTOM_RATIO); -} - -static void initShear(TransInfo *t) -{ - t->mode = TFM_SHEAR; - t->transform = applyShear; - t->handleEvent = handleEventShear; - - if (t->orient_axis == t->orient_axis_ortho) { - t->orient_axis = 2; - t->orient_axis_ortho = 1; - } - - initShear_mouseInputMode(t); - - t->idx_max = 0; - t->num.idx_max = 0; - t->snap[0] = 0.0f; - t->snap[1] = 0.1f; - t->snap[2] = t->snap[1] * 0.1f; - - copy_v3_fl(t->num.val_inc, t->snap[1]); - t->num.unit_sys = t->scene->unit.system; - t->num.unit_type[0] = B_UNIT_NONE; /* Don't think we have any unit here? */ - - t->flag |= T_NO_CONSTRAINT; -} - -static eRedrawFlag handleEventShear(TransInfo *t, const wmEvent *event) -{ - eRedrawFlag status = TREDRAW_NOTHING; - - if (event->type == MIDDLEMOUSE && event->val == KM_PRESS) { - /* Use custom.mode.data pointer to signal Shear direction */ - do { - t->orient_axis_ortho = (t->orient_axis_ortho + 1) % 3; - } while (t->orient_axis_ortho == t->orient_axis); - - initShear_mouseInputMode(t); - - status = TREDRAW_HARD; - } - else if (event->type == XKEY && event->val == KM_PRESS) { - t->orient_axis_ortho = (t->orient_axis + 1) % 3; - initShear_mouseInputMode(t); - - status = TREDRAW_HARD; - } - else if (event->type == YKEY && event->val == KM_PRESS) { - t->orient_axis_ortho = (t->orient_axis + 2) % 3; - initShear_mouseInputMode(t); - - status = TREDRAW_HARD; - } - - return status; -} - -static void applyShear(TransInfo *t, const int UNUSED(mval[2])) -{ - float vec[3]; - float smat[3][3], tmat[3][3], totmat[3][3], axismat[3][3], axismat_inv[3][3]; - float value; - int i; - char str[UI_MAX_DRAW_STR]; - const bool is_local_center = transdata_check_local_center(t, t->around); - - value = t->values[0]; - - snapGridIncrement(t, &value); - - applyNumInput(&t->num, &value); - - t->values_final[0] = value; - - /* header print for NumInput */ - if (hasNumInput(&t->num)) { - char c[NUM_STR_REP_LEN]; - - outputNumInput(&(t->num), c, &t->scene->unit); - - BLI_snprintf(str, sizeof(str), TIP_("Shear: %s %s"), c, t->proptext); - } - else { - /* default header print */ - BLI_snprintf(str, - sizeof(str), - TIP_("Shear: %.3f %s (Press X or Y to set shear axis)"), - value, - t->proptext); - } - - unit_m3(smat); - smat[1][0] = value; - - copy_v3_v3(axismat_inv[0], t->orient_matrix[t->orient_axis_ortho]); - copy_v3_v3(axismat_inv[2], t->orient_matrix[t->orient_axis]); - cross_v3_v3v3(axismat_inv[1], axismat_inv[0], axismat_inv[2]); - invert_m3_m3(axismat, axismat_inv); - - mul_m3_series(totmat, axismat_inv, smat, axismat); - - FOREACH_TRANS_DATA_CONTAINER (t, tc) { - TransData *td = tc->data; - for (i = 0; i < tc->data_len; i++, td++) { - const float *center, *co; - - if (td->flag & TD_NOACTION) { - break; - } - - if (td->flag & TD_SKIP) { - continue; - } - - if (t->flag & T_EDIT) { - mul_m3_series(tmat, td->smtx, totmat, td->mtx); - } - else { - copy_m3_m3(tmat, totmat); - } - - if (is_local_center) { - center = td->center; - co = td->loc; - } - else { - center = tc->center_local; - co = td->center; - } - - sub_v3_v3v3(vec, co, center); - - mul_m3_v3(tmat, vec); - - add_v3_v3(vec, center); - sub_v3_v3(vec, co); - - if (t->options & CTX_GPENCIL_STROKES) { - /* grease pencil multiframe falloff */ - bGPDstroke *gps = (bGPDstroke *)td->extra; - if (gps != NULL) { - mul_v3_fl(vec, td->factor * gps->runtime.multi_frame_falloff); - } - else { - mul_v3_fl(vec, td->factor); - } - } - else { - mul_v3_fl(vec, td->factor); - } - - add_v3_v3v3(td->loc, td->iloc, vec); - } - } - - recalcData(t); - - ED_area_status_text(t->sa, str); -} -/** \} */ - -/* -------------------------------------------------------------------- */ -/* Transform (Resize) */ - -/** \name Transform Resize - * \{ */ - -static void initResize(TransInfo *t) -{ - t->mode = TFM_RESIZE; - t->transform = applyResize; - - initMouseInputMode(t, &t->mouse, INPUT_SPRING_FLIP); - - t->flag |= T_NULL_ONE; - t->num.val_flag[0] |= NUM_NULL_ONE; - t->num.val_flag[1] |= NUM_NULL_ONE; - t->num.val_flag[2] |= NUM_NULL_ONE; - t->num.flag |= NUM_AFFECT_ALL; - if ((t->flag & T_EDIT) == 0) { - t->flag |= T_NO_ZERO; -#ifdef USE_NUM_NO_ZERO - t->num.val_flag[0] |= NUM_NO_ZERO; - t->num.val_flag[1] |= NUM_NO_ZERO; - t->num.val_flag[2] |= NUM_NO_ZERO; -#endif - } - - t->idx_max = 2; - t->num.idx_max = 2; - t->snap[0] = 0.0f; - t->snap[1] = 0.1f; - t->snap[2] = t->snap[1] * 0.1f; - - copy_v3_fl(t->num.val_inc, t->snap[1]); - t->num.unit_sys = t->scene->unit.system; - t->num.unit_type[0] = B_UNIT_NONE; - t->num.unit_type[1] = B_UNIT_NONE; - t->num.unit_type[2] = B_UNIT_NONE; -} - -static void headerResize(TransInfo *t, const float vec[3], char str[UI_MAX_DRAW_STR]) -{ - char tvec[NUM_STR_REP_LEN * 3]; - size_t ofs = 0; - if (hasNumInput(&t->num)) { - outputNumInput(&(t->num), tvec, &t->scene->unit); - } - else { - BLI_snprintf(&tvec[0], NUM_STR_REP_LEN, "%.4f", vec[0]); - BLI_snprintf(&tvec[NUM_STR_REP_LEN], NUM_STR_REP_LEN, "%.4f", vec[1]); - BLI_snprintf(&tvec[NUM_STR_REP_LEN * 2], NUM_STR_REP_LEN, "%.4f", vec[2]); - } - - if (t->con.mode & CON_APPLY) { - switch (t->num.idx_max) { - case 0: - ofs += BLI_snprintf(str + ofs, - UI_MAX_DRAW_STR - ofs, - TIP_("Scale: %s%s %s"), - &tvec[0], - t->con.text, - t->proptext); - break; - case 1: - ofs += BLI_snprintf(str + ofs, - UI_MAX_DRAW_STR - ofs, - TIP_("Scale: %s : %s%s %s"), - &tvec[0], - &tvec[NUM_STR_REP_LEN], - t->con.text, - t->proptext); - break; - case 2: - ofs += BLI_snprintf(str + ofs, - UI_MAX_DRAW_STR - ofs, - TIP_("Scale: %s : %s : %s%s %s"), - &tvec[0], - &tvec[NUM_STR_REP_LEN], - &tvec[NUM_STR_REP_LEN * 2], - t->con.text, - t->proptext); - break; - } - } - else { - if (t->flag & T_2D_EDIT) { - ofs += BLI_snprintf(str + ofs, - UI_MAX_DRAW_STR - ofs, - TIP_("Scale X: %s Y: %s%s %s"), - &tvec[0], - &tvec[NUM_STR_REP_LEN], - t->con.text, - t->proptext); - } - else { - ofs += BLI_snprintf(str + ofs, - UI_MAX_DRAW_STR - ofs, - TIP_("Scale X: %s Y: %s Z: %s%s %s"), - &tvec[0], - &tvec[NUM_STR_REP_LEN], - &tvec[NUM_STR_REP_LEN * 2], - t->con.text, - t->proptext); - } - } - - if (t->flag & T_PROP_EDIT_ALL) { - ofs += BLI_snprintf( - str + ofs, UI_MAX_DRAW_STR - ofs, TIP_(" Proportional size: %.2f"), t->prop_size); - } -} - -/** - * \a smat is reference matrix only. - * - * \note this is a tricky area, before making changes see: T29633, T42444 - */ -static void TransMat3ToSize(float mat[3][3], float smat[3][3], float size[3]) -{ - float rmat[3][3]; - - mat3_to_rot_size(rmat, size, mat); - - /* first tried with dotproduct... but the sign flip is crucial */ - if (dot_v3v3(rmat[0], smat[0]) < 0.0f) { - size[0] = -size[0]; - } - if (dot_v3v3(rmat[1], smat[1]) < 0.0f) { - size[1] = -size[1]; - } - if (dot_v3v3(rmat[2], smat[2]) < 0.0f) { - size[2] = -size[2]; - } -} - -static void ElementResize(TransInfo *t, TransDataContainer *tc, TransData *td, float mat[3][3]) -{ - float tmat[3][3], smat[3][3], center[3]; - float vec[3]; - - if (t->flag & T_EDIT) { - mul_m3_m3m3(smat, mat, td->mtx); - mul_m3_m3m3(tmat, td->smtx, smat); - } - else { - copy_m3_m3(tmat, mat); - } - - if (t->con.applySize) { - t->con.applySize(t, tc, td, tmat); - } - - /* local constraint shouldn't alter center */ - if (transdata_check_local_center(t, t->around)) { - copy_v3_v3(center, td->center); - } - else if (t->options & CTX_MOVIECLIP) { - if (td->flag & TD_INDIVIDUAL_SCALE) { - copy_v3_v3(center, td->center); - } - else { - copy_v3_v3(center, tc->center_local); - } - } - else { - copy_v3_v3(center, tc->center_local); - } - - /* Size checked needed since the 3D cursor only uses rotation fields. */ - if (td->ext && td->ext->size) { - float fsize[3]; - - if ((t->options & CTX_SCULPT) || t->flag & (T_OBJECT | T_TEXTURE | T_POSE)) { - float obsizemat[3][3]; - /* Reorient the size mat to fit the oriented object. */ - mul_m3_m3m3(obsizemat, tmat, td->axismtx); - /* print_m3("obsizemat", obsizemat); */ - TransMat3ToSize(obsizemat, td->axismtx, fsize); - /* print_v3("fsize", fsize); */ - } - else { - mat3_to_size(fsize, tmat); - } - - protectedSizeBits(td->protectflag, fsize); - - if ((t->flag & T_V3D_ALIGN) == 0) { /* align mode doesn't resize objects itself */ - if ((td->flag & TD_SINGLESIZE) && !(t->con.mode & CON_APPLY)) { - /* scale val and reset size */ - *td->val = td->ival * (1 + (fsize[0] - 1) * td->factor); - - td->ext->size[0] = td->ext->isize[0]; - td->ext->size[1] = td->ext->isize[1]; - td->ext->size[2] = td->ext->isize[2]; - } - else { - /* Reset val if SINGLESIZE but using a constraint */ - if (td->flag & TD_SINGLESIZE) { - *td->val = td->ival; - } - - td->ext->size[0] = td->ext->isize[0] * (1 + (fsize[0] - 1) * td->factor); - td->ext->size[1] = td->ext->isize[1] * (1 + (fsize[1] - 1) * td->factor); - td->ext->size[2] = td->ext->isize[2] * (1 + (fsize[2] - 1) * td->factor); - } - } - - constraintSizeLim(t, td); - } - - /* For individual element center, Editmode need to use iloc */ - if (t->flag & T_POINTS) { - sub_v3_v3v3(vec, td->iloc, center); - } - else { - sub_v3_v3v3(vec, td->center, center); - } - - mul_m3_v3(tmat, vec); - - add_v3_v3(vec, center); - if (t->flag & T_POINTS) { - sub_v3_v3(vec, td->iloc); - } - else { - sub_v3_v3(vec, td->center); - } - - /* grease pencil falloff */ - if (t->options & CTX_GPENCIL_STROKES) { - bGPDstroke *gps = (bGPDstroke *)td->extra; - mul_v3_fl(vec, td->factor * gps->runtime.multi_frame_falloff); - - /* scale stroke thickness */ - if (td->val) { - snapGridIncrement(t, t->values_final); - applyNumInput(&t->num, t->values_final); - - float ratio = t->values_final[0]; - *td->val = td->ival * ratio * gps->runtime.multi_frame_falloff; - CLAMP_MIN(*td->val, 0.001f); - } - } - else { - mul_v3_fl(vec, td->factor); - } - - if (t->flag & (T_OBJECT | T_POSE)) { - mul_m3_v3(td->smtx, vec); - } - - protectedTransBits(td->protectflag, vec); - if (td->loc) { - add_v3_v3v3(td->loc, td->iloc, vec); - } - - constraintTransLim(t, td); -} - -static void applyResize(TransInfo *t, const int UNUSED(mval[2])) -{ - float mat[3][3]; - int i; - char str[UI_MAX_DRAW_STR]; - - if (t->flag & T_INPUT_IS_VALUES_FINAL) { - copy_v3_v3(t->values_final, t->values); - } - else { - float ratio = t->values[0]; - - copy_v3_fl(t->values_final, ratio); - - snapGridIncrement(t, t->values_final); - - if (applyNumInput(&t->num, t->values_final)) { - constraintNumInput(t, t->values_final); - } - - applySnapping(t, t->values_final); - } - - size_to_mat3(mat, t->values_final); - if (t->con.mode & CON_APPLY) { - t->con.applySize(t, NULL, NULL, mat); - - /* Only so we have re-usable value with redo. */ - float pvec[3] = {0.0f, 0.0f, 0.0f}; - int j = 0; - for (i = 0; i < 3; i++) { - if (!(t->con.mode & (CON_AXIS0 << i))) { - t->values_final[i] = 1.0f; - } - else { - pvec[j++] = t->values_final[i]; - } - } - headerResize(t, pvec, str); - } - else { - headerResize(t, t->values_final, str); - } - - copy_m3_m3(t->mat, mat); // used in gizmo - - FOREACH_TRANS_DATA_CONTAINER (t, tc) { - TransData *td = tc->data; - for (i = 0; i < tc->data_len; i++, td++) { - if (td->flag & TD_NOACTION) { - break; - } - - if (td->flag & TD_SKIP) { - continue; - } - - ElementResize(t, tc, td, mat); - } - } - - /* evil hack - redo resize if cliping needed */ - if (t->flag & T_CLIP_UV && clipUVTransform(t, t->values_final, 1)) { - size_to_mat3(mat, t->values_final); - - if (t->con.mode & CON_APPLY) { - t->con.applySize(t, NULL, NULL, mat); - } - - FOREACH_TRANS_DATA_CONTAINER (t, tc) { - TransData *td = tc->data; - for (i = 0; i < tc->data_len; i++, td++) { - ElementResize(t, tc, td, mat); - } - - /* In proportional edit it can happen that */ - /* vertices in the radius of the brush end */ - /* outside the clipping area */ - /* XXX HACK - dg */ - if (t->flag & T_PROP_EDIT_ALL) { - clipUVData(t); - } - } - } - - recalcData(t); - - ED_area_status_text(t->sa, str); -} -/** \} */ - -/* -------------------------------------------------------------------- */ -/* Transform (Skin) */ - -/** \name Transform Skin - * \{ */ - -static void initSkinResize(TransInfo *t) -{ - t->mode = TFM_SKIN_RESIZE; - t->transform = applySkinResize; - - initMouseInputMode(t, &t->mouse, INPUT_SPRING_FLIP); - - t->flag |= T_NULL_ONE; - t->num.val_flag[0] |= NUM_NULL_ONE; - t->num.val_flag[1] |= NUM_NULL_ONE; - t->num.val_flag[2] |= NUM_NULL_ONE; - t->num.flag |= NUM_AFFECT_ALL; - if ((t->flag & T_EDIT) == 0) { - t->flag |= T_NO_ZERO; -#ifdef USE_NUM_NO_ZERO - t->num.val_flag[0] |= NUM_NO_ZERO; - t->num.val_flag[1] |= NUM_NO_ZERO; - t->num.val_flag[2] |= NUM_NO_ZERO; -#endif - } - - t->idx_max = 2; - t->num.idx_max = 2; - t->snap[0] = 0.0f; - t->snap[1] = 0.1f; - t->snap[2] = t->snap[1] * 0.1f; - - copy_v3_fl(t->num.val_inc, t->snap[1]); - t->num.unit_sys = t->scene->unit.system; - t->num.unit_type[0] = B_UNIT_NONE; - t->num.unit_type[1] = B_UNIT_NONE; - t->num.unit_type[2] = B_UNIT_NONE; -} - -static void applySkinResize(TransInfo *t, const int UNUSED(mval[2])) -{ - float mat[3][3]; - int i; - char str[UI_MAX_DRAW_STR]; - - if (t->flag & T_INPUT_IS_VALUES_FINAL) { - copy_v3_v3(t->values_final, t->values); - } - else { - copy_v3_fl(t->values_final, t->values[0]); - - snapGridIncrement(t, t->values_final); - - if (applyNumInput(&t->num, t->values_final)) { - constraintNumInput(t, t->values_final); - } - - applySnapping(t, t->values_final); - } - - size_to_mat3(mat, t->values_final); - - headerResize(t, t->values_final, str); - - FOREACH_TRANS_DATA_CONTAINER (t, tc) { - TransData *td = tc->data; - for (i = 0; i < tc->data_len; i++, td++) { - float tmat[3][3], smat[3][3]; - float fsize[3]; - - if (td->flag & TD_NOACTION) { - break; - } - - if (td->flag & TD_SKIP) { - continue; - } - - if (t->flag & T_EDIT) { - mul_m3_m3m3(smat, mat, td->mtx); - mul_m3_m3m3(tmat, td->smtx, smat); - } - else { - copy_m3_m3(tmat, mat); - } - - if (t->con.applySize) { - t->con.applySize(t, NULL, NULL, tmat); - } - - mat3_to_size(fsize, tmat); - td->val[0] = td->ext->isize[0] * (1 + (fsize[0] - 1) * td->factor); - td->val[1] = td->ext->isize[1] * (1 + (fsize[1] - 1) * td->factor); - } - } - - recalcData(t); - - ED_area_status_text(t->sa, str); -} -/** \} */ - -/* -------------------------------------------------------------------- */ -/* Transform (ToSphere) */ - -/** \name Transform ToSphere - * \{ */ - -static void initToSphere(TransInfo *t) -{ - int i; - - t->mode = TFM_TOSPHERE; - t->transform = applyToSphere; - - initMouseInputMode(t, &t->mouse, INPUT_HORIZONTAL_RATIO); - - t->idx_max = 0; - t->num.idx_max = 0; - t->snap[0] = 0.0f; - t->snap[1] = 0.1f; - t->snap[2] = t->snap[1] * 0.1f; - - copy_v3_fl(t->num.val_inc, t->snap[1]); - t->num.unit_sys = t->scene->unit.system; - t->num.unit_type[0] = B_UNIT_NONE; - - t->num.val_flag[0] |= NUM_NULL_ONE | NUM_NO_NEGATIVE; - t->flag |= T_NO_CONSTRAINT; - - // Calculate average radius - FOREACH_TRANS_DATA_CONTAINER (t, tc) { - TransData *td = tc->data; - for (i = 0; i < tc->data_len; i++, td++) { - t->val += len_v3v3(tc->center_local, td->iloc); - } - } - - t->val /= (float)t->data_len_all; -} - -static void applyToSphere(TransInfo *t, const int UNUSED(mval[2])) -{ - float vec[3]; - float ratio, radius; - int i; - char str[UI_MAX_DRAW_STR]; - - ratio = t->values[0]; - - snapGridIncrement(t, &ratio); - - applyNumInput(&t->num, &ratio); - - CLAMP(ratio, 0.0f, 1.0f); - - t->values_final[0] = ratio; - - /* header print for NumInput */ - if (hasNumInput(&t->num)) { - char c[NUM_STR_REP_LEN]; - - outputNumInput(&(t->num), c, &t->scene->unit); - - BLI_snprintf(str, sizeof(str), TIP_("To Sphere: %s %s"), c, t->proptext); - } - else { - /* default header print */ - BLI_snprintf(str, sizeof(str), TIP_("To Sphere: %.4f %s"), ratio, t->proptext); - } - - FOREACH_TRANS_DATA_CONTAINER (t, tc) { - TransData *td = tc->data; - for (i = 0; i < tc->data_len; i++, td++) { - float tratio; - if (td->flag & TD_NOACTION) { - break; - } - - if (td->flag & TD_SKIP) { - continue; - } - - sub_v3_v3v3(vec, td->iloc, tc->center_local); - - radius = normalize_v3(vec); - - tratio = ratio * td->factor; - - mul_v3_fl(vec, radius * (1.0f - tratio) + t->val * tratio); - - add_v3_v3v3(td->loc, tc->center_local, vec); - } - } - - recalcData(t); - - ED_area_status_text(t->sa, str); -} -/** \} */ - -/* -------------------------------------------------------------------- */ -/* Transform (Rotation) */ - -/** \name Transform Rotation - * \{ */ - -static void postInputRotation(TransInfo *t, float values[3]) -{ - float axis_final[3]; - copy_v3_v3(axis_final, t->orient_matrix[t->orient_axis]); - if ((t->con.mode & CON_APPLY) && t->con.applyRot) { - t->con.applyRot(t, NULL, NULL, axis_final, values); - } -} - -static void initRotation(TransInfo *t) -{ - t->mode = TFM_ROTATION; - t->transform = applyRotation; - - setInputPostFct(&t->mouse, postInputRotation); - initMouseInputMode(t, &t->mouse, INPUT_ANGLE); - - t->idx_max = 0; - t->num.idx_max = 0; - t->snap[0] = 0.0f; - t->snap[1] = DEG2RAD(5.0); - t->snap[2] = DEG2RAD(1.0); - - copy_v3_fl(t->num.val_inc, t->snap[2]); - t->num.unit_sys = t->scene->unit.system; - t->num.unit_use_radians = (t->scene->unit.system_rotation == USER_UNIT_ROT_RADIANS); - t->num.unit_type[0] = B_UNIT_ROTATION; - - if (t->flag & T_2D_EDIT) { - t->flag |= T_NO_CONSTRAINT; - } -} - -/* Used by Transform Rotation and Transform Normal Rotation */ -static void headerRotation(TransInfo *t, char str[UI_MAX_DRAW_STR], float final) -{ - size_t ofs = 0; - - if (hasNumInput(&t->num)) { - char c[NUM_STR_REP_LEN]; - - outputNumInput(&(t->num), c, &t->scene->unit); - - ofs += BLI_snprintf( - str + ofs, UI_MAX_DRAW_STR - ofs, TIP_("Rot: %s %s %s"), &c[0], t->con.text, t->proptext); - } - else { - ofs += BLI_snprintf(str + ofs, - UI_MAX_DRAW_STR - ofs, - TIP_("Rot: %.2f%s %s"), - RAD2DEGF(final), - t->con.text, - t->proptext); - } - - if (t->flag & T_PROP_EDIT_ALL) { - ofs += BLI_snprintf( - str + ofs, UI_MAX_DRAW_STR - ofs, TIP_(" Proportional size: %.2f"), t->prop_size); - } -} - -/** - * Applies values of rotation to `td->loc` and `td->ext->quat` - * based on a rotation matrix (mat) and a pivot (center). - * - * Protected axis and other transform settings are taken into account. - */ -static void ElementRotation_ex(TransInfo *t, - TransDataContainer *tc, - TransData *td, - const float mat[3][3], - const float *center) -{ - float vec[3], totmat[3][3], smat[3][3]; - float eul[3], fmat[3][3], quat[4]; - - if (t->flag & T_POINTS) { - mul_m3_m3m3(totmat, mat, td->mtx); - mul_m3_m3m3(smat, td->smtx, totmat); - - /* apply gpencil falloff */ - if (t->options & CTX_GPENCIL_STROKES) { - bGPDstroke *gps = (bGPDstroke *)td->extra; - float sx = smat[0][0]; - float sy = smat[1][1]; - float sz = smat[2][2]; - - mul_m3_fl(smat, gps->runtime.multi_frame_falloff); - /* fix scale */ - smat[0][0] = sx; - smat[1][1] = sy; - smat[2][2] = sz; - } - - sub_v3_v3v3(vec, td->iloc, center); - mul_m3_v3(smat, vec); - - add_v3_v3v3(td->loc, vec, center); - - sub_v3_v3v3(vec, td->loc, td->iloc); - protectedTransBits(td->protectflag, vec); - add_v3_v3v3(td->loc, td->iloc, vec); - - if (td->flag & TD_USEQUAT) { - mul_m3_series(fmat, td->smtx, mat, td->mtx); - mat3_to_quat(quat, fmat); // Actual transform - - if (td->ext->quat) { - mul_qt_qtqt(td->ext->quat, quat, td->ext->iquat); - - /* is there a reason not to have this here? -jahka */ - protectedQuaternionBits(td->protectflag, td->ext->quat, td->ext->iquat); - } - } - } - /** - * HACK WARNING - * - * This is some VERY ugly special case to deal with pose mode. - * - * The problem is that mtx and smtx include each bone orientation. - * - * That is needed to rotate each bone properly, HOWEVER, to calculate - * the translation component, we only need the actual armature object's - * matrix (and inverse). That is not all though. Once the proper translation - * has been computed, it has to be converted back into the bone's space. - */ - else if (t->flag & T_POSE) { - // Extract and invert armature object matrix - - if ((td->flag & TD_NO_LOC) == 0) { - sub_v3_v3v3(vec, td->center, center); - - mul_m3_v3(tc->mat3, vec); // To Global space - mul_m3_v3(mat, vec); // Applying rotation - mul_m3_v3(tc->imat3, vec); // To Local space - - add_v3_v3(vec, center); - /* vec now is the location where the object has to be */ - - sub_v3_v3v3(vec, vec, td->center); // Translation needed from the initial location - - /* special exception, see TD_PBONE_LOCAL_MTX definition comments */ - if (td->flag & TD_PBONE_LOCAL_MTX_P) { - /* do nothing */ - } - else if (td->flag & TD_PBONE_LOCAL_MTX_C) { - mul_m3_v3(tc->mat3, vec); // To Global space - mul_m3_v3(td->ext->l_smtx, vec); // To Pose space (Local Location) - } - else { - mul_m3_v3(tc->mat3, vec); // To Global space - mul_m3_v3(td->smtx, vec); // To Pose space - } - - protectedTransBits(td->protectflag, vec); - - add_v3_v3v3(td->loc, td->iloc, vec); - - constraintTransLim(t, td); - } - - /* rotation */ - /* MORE HACK: as in some cases the matrix to apply location and rot/scale is not the same, - * and ElementRotation() might be called in Translation context (with align snapping), - * we need to be sure to actually use the *rotation* matrix here... - * So no other way than storing it in some dedicated members of td->ext! */ - if ((t->flag & T_V3D_ALIGN) == 0) { /* align mode doesn't rotate objects itself */ - /* euler or quaternion/axis-angle? */ - if (td->ext->rotOrder == ROT_MODE_QUAT) { - mul_m3_series(fmat, td->ext->r_smtx, mat, td->ext->r_mtx); - - mat3_to_quat(quat, fmat); /* Actual transform */ - - mul_qt_qtqt(td->ext->quat, quat, td->ext->iquat); - /* this function works on end result */ - protectedQuaternionBits(td->protectflag, td->ext->quat, td->ext->iquat); - } - else if (td->ext->rotOrder == ROT_MODE_AXISANGLE) { - /* calculate effect based on quats */ - float iquat[4], tquat[4]; - - axis_angle_to_quat(iquat, td->ext->irotAxis, td->ext->irotAngle); - - mul_m3_series(fmat, td->ext->r_smtx, mat, td->ext->r_mtx); - mat3_to_quat(quat, fmat); /* Actual transform */ - mul_qt_qtqt(tquat, quat, iquat); - - quat_to_axis_angle(td->ext->rotAxis, td->ext->rotAngle, tquat); - - /* this function works on end result */ - protectedAxisAngleBits(td->protectflag, - td->ext->rotAxis, - td->ext->rotAngle, - td->ext->irotAxis, - td->ext->irotAngle); - } - else { - float eulmat[3][3]; - - mul_m3_m3m3(totmat, mat, td->ext->r_mtx); - mul_m3_m3m3(smat, td->ext->r_smtx, totmat); - - /* calculate the total rotatation in eulers */ - copy_v3_v3(eul, td->ext->irot); - eulO_to_mat3(eulmat, eul, td->ext->rotOrder); - - /* mat = transform, obmat = bone rotation */ - mul_m3_m3m3(fmat, smat, eulmat); - - mat3_to_compatible_eulO(eul, td->ext->rot, td->ext->rotOrder, fmat); - - /* and apply (to end result only) */ - protectedRotateBits(td->protectflag, eul, td->ext->irot); - copy_v3_v3(td->ext->rot, eul); - } - - constraintRotLim(t, td); - } - } - else { - if ((td->flag & TD_NO_LOC) == 0) { - /* translation */ - sub_v3_v3v3(vec, td->center, center); - mul_m3_v3(mat, vec); - add_v3_v3(vec, center); - /* vec now is the location where the object has to be */ - sub_v3_v3(vec, td->center); - mul_m3_v3(td->smtx, vec); - - protectedTransBits(td->protectflag, vec); - - add_v3_v3v3(td->loc, td->iloc, vec); - } - - constraintTransLim(t, td); - - /* rotation */ - if ((t->flag & T_V3D_ALIGN) == 0) { // align mode doesn't rotate objects itself - /* euler or quaternion? */ - if ((td->ext->rotOrder == ROT_MODE_QUAT) || (td->flag & TD_USEQUAT)) { - /* can be called for texture space translate for example, then opt out */ - if (td->ext->quat) { - mul_m3_series(fmat, td->smtx, mat, td->mtx); - mat3_to_quat(quat, fmat); // Actual transform - - mul_qt_qtqt(td->ext->quat, quat, td->ext->iquat); - /* this function works on end result */ - protectedQuaternionBits(td->protectflag, td->ext->quat, td->ext->iquat); - } - } - else if (td->ext->rotOrder == ROT_MODE_AXISANGLE) { - /* calculate effect based on quats */ - float iquat[4], tquat[4]; - - axis_angle_to_quat(iquat, td->ext->irotAxis, td->ext->irotAngle); - - mul_m3_series(fmat, td->smtx, mat, td->mtx); - mat3_to_quat(quat, fmat); // Actual transform - mul_qt_qtqt(tquat, quat, iquat); - - quat_to_axis_angle(td->ext->rotAxis, td->ext->rotAngle, tquat); - - /* this function works on end result */ - protectedAxisAngleBits(td->protectflag, - td->ext->rotAxis, - td->ext->rotAngle, - td->ext->irotAxis, - td->ext->irotAngle); - } - else { - float obmat[3][3]; - - mul_m3_m3m3(totmat, mat, td->mtx); - mul_m3_m3m3(smat, td->smtx, totmat); - - /* calculate the total rotatation in eulers */ - add_v3_v3v3(eul, td->ext->irot, td->ext->drot); /* correct for delta rot */ - eulO_to_mat3(obmat, eul, td->ext->rotOrder); - /* mat = transform, obmat = object rotation */ - mul_m3_m3m3(fmat, smat, obmat); - - mat3_to_compatible_eulO(eul, td->ext->rot, td->ext->rotOrder, fmat); - - /* correct back for delta rot */ - sub_v3_v3v3(eul, eul, td->ext->drot); - - /* and apply */ - protectedRotateBits(td->protectflag, eul, td->ext->irot); - copy_v3_v3(td->ext->rot, eul); - } - - constraintRotLim(t, td); - } - } -} - -static void ElementRotation( - TransInfo *t, TransDataContainer *tc, TransData *td, float mat[3][3], const short around) -{ - const float *center; - - /* local constraint shouldn't alter center */ - if (transdata_check_local_center(t, around)) { - center = td->center; - } - else { - center = tc->center_local; - } - - ElementRotation_ex(t, tc, td, mat, center); -} - -static float large_rotation_limit(float angle) -{ - /* Limit rotation to 1001 turns max - * (otherwise iterative handling of 'large' rotations would become too slow). */ - const float angle_max = (float)(M_PI * 2000.0); - if (fabsf(angle) > angle_max) { - const float angle_sign = angle < 0.0f ? -1.0f : 1.0f; - angle = angle_sign * (fmodf(fabsf(angle), (float)(M_PI * 2.0)) + angle_max); - } - return angle; -} - -static void applyRotationValue(TransInfo *t, - float angle, - float axis[3], - const bool is_large_rotation) -{ - float mat[3][3]; - int i; - - const float angle_sign = angle < 0.0f ? -1.0f : 1.0f; - /* We cannot use something too close to 180°, or 'continuous' rotation may fail - * due to computing error... */ - const float angle_step = angle_sign * (float)(0.9 * M_PI); - - if (is_large_rotation) { - /* Just in case, calling code should have already done that in practice - * (for UI feedback reasons). */ - angle = large_rotation_limit(angle); - } - - axis_angle_normalized_to_mat3(mat, axis, angle); - /* Counter for needed updates (when we need to update to non-default matrix, - * we also need another update on next iteration to go back to default matrix, - * hence the '2' value used here, instead of a mere boolean). */ - short do_update_matrix = 0; - - FOREACH_TRANS_DATA_CONTAINER (t, tc) { - TransData *td = tc->data; - for (i = 0; i < tc->data_len; i++, td++) { - if (td->flag & TD_NOACTION) { - break; - } - - if (td->flag & TD_SKIP) { - continue; - } - - float angle_final = angle; - if (t->con.applyRot) { - t->con.applyRot(t, tc, td, axis, NULL); - angle_final = angle * td->factor; - /* Even though final angle might be identical to orig value, - * we have to update the rotation matrix in that case... */ - do_update_matrix = 2; - } - else if (t->flag & T_PROP_EDIT) { - angle_final = angle * td->factor; - } - - /* Rotation is very likely to be above 180°, we need to do rotation by steps. - * Note that this is only needed when doing 'absolute' rotation - * (i.e. from initial rotation again, typically when using numinput). - * regular incremental rotation (from mouse/widget/...) will be called often enough, - * hence steps are small enough to be properly handled without that complicated trick. - * Note that we can only do that kind of stepped rotation if we have initial rotation values - * (and access to some actual rotation value storage). - * Otherwise, just assume it's useless (e.g. in case of mesh/UV/etc. editing). - * Also need to be in Euler rotation mode, the others never allow more than one turn anyway. - */ - if (is_large_rotation && td->ext != NULL && td->ext->rotOrder == ROT_MODE_EUL) { - copy_v3_v3(td->ext->rot, td->ext->irot); - for (float angle_progress = angle_step; fabsf(angle_progress) < fabsf(angle_final); - angle_progress += angle_step) { - axis_angle_normalized_to_mat3(mat, axis, angle_progress); - ElementRotation(t, tc, td, mat, t->around); - } - do_update_matrix = 2; - } - else if (angle_final != angle) { - do_update_matrix = 2; - } - - if (do_update_matrix > 0) { - axis_angle_normalized_to_mat3(mat, axis, angle_final); - do_update_matrix--; - } - - ElementRotation(t, tc, td, mat, t->around); - } - } -} - -static void applyRotation(TransInfo *t, const int UNUSED(mval[2])) -{ - char str[UI_MAX_DRAW_STR]; - - float final; - - final = t->values[0]; - - snapGridIncrement(t, &final); - - float axis_final[3]; - copy_v3_v3(axis_final, t->orient_matrix[t->orient_axis]); - - if ((t->con.mode & CON_APPLY) && t->con.applyRot) { - t->con.applyRot(t, NULL, NULL, axis_final, NULL); - } - - applySnapping(t, &final); - - if (applyNumInput(&t->num, &final)) { - /* We have to limit the amount of turns to a reasonable number here, - * to avoid things getting *very* slow, see how applyRotationValue() handles those... */ - final = large_rotation_limit(final); - } - - t->values_final[0] = final; - - headerRotation(t, str, final); - - const bool is_large_rotation = hasNumInput(&t->num); - applyRotationValue(t, final, axis_final, is_large_rotation); - - recalcData(t); - - ED_area_status_text(t->sa, str); -} -/** \} */ - -/* -------------------------------------------------------------------- */ -/* Transform (Rotation - Trackball) */ - -/** \name Transform Rotation - Trackball - * \{ */ - -static void initTrackball(TransInfo *t) -{ - t->mode = TFM_TRACKBALL; - t->transform = applyTrackball; - - initMouseInputMode(t, &t->mouse, INPUT_TRACKBALL); - - t->idx_max = 1; - t->num.idx_max = 1; - t->snap[0] = 0.0f; - t->snap[1] = DEG2RAD(5.0); - t->snap[2] = DEG2RAD(1.0); - - copy_v3_fl(t->num.val_inc, t->snap[2]); - t->num.unit_sys = t->scene->unit.system; - t->num.unit_use_radians = (t->scene->unit.system_rotation == USER_UNIT_ROT_RADIANS); - t->num.unit_type[0] = B_UNIT_ROTATION; - t->num.unit_type[1] = B_UNIT_ROTATION; - - t->flag |= T_NO_CONSTRAINT; -} - -static void applyTrackballValue(TransInfo *t, - const float axis1[3], - const float axis2[3], - const float angles[2]) -{ - float mat[3][3]; - float axis[3]; - float angle; - int i; - - mul_v3_v3fl(axis, axis1, angles[0]); - madd_v3_v3fl(axis, axis2, angles[1]); - angle = normalize_v3(axis); - axis_angle_normalized_to_mat3(mat, axis, angle); - - FOREACH_TRANS_DATA_CONTAINER (t, tc) { - TransData *td = tc->data; - for (i = 0; i < tc->data_len; i++, td++) { - if (td->flag & TD_NOACTION) { - break; - } - - if (td->flag & TD_SKIP) { - continue; - } - - if (t->flag & T_PROP_EDIT) { - axis_angle_normalized_to_mat3(mat, axis, td->factor * angle); - } - - ElementRotation(t, tc, td, mat, t->around); - } - } -} - -static void applyTrackball(TransInfo *t, const int UNUSED(mval[2])) -{ - char str[UI_MAX_DRAW_STR]; - 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]); - copy_v3_v3(axis2, t->persinv[1]); - normalize_v3(axis1); - normalize_v3(axis2); - - copy_v2_v2(phi, t->values); - - snapGridIncrement(t, phi); - - applyNumInput(&t->num, phi); - - copy_v2_v2(t->values_final, phi); - - if (hasNumInput(&t->num)) { - char c[NUM_STR_REP_LEN * 2]; - - outputNumInput(&(t->num), c, &t->scene->unit); - - ofs += BLI_snprintf(str + ofs, - sizeof(str) - ofs, - TIP_("Trackball: %s %s %s"), - &c[0], - &c[NUM_STR_REP_LEN], - t->proptext); - } - else { - ofs += BLI_snprintf(str + ofs, - sizeof(str) - ofs, - TIP_("Trackball: %.2f %.2f %s"), - RAD2DEGF(phi[0]), - RAD2DEGF(phi[1]), - t->proptext); - } - - if (t->flag & T_PROP_EDIT_ALL) { - ofs += BLI_snprintf( - str + ofs, sizeof(str) - ofs, TIP_(" 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]); - - mul_m3_m3m3(mat, smat, totmat); - - // TRANSFORM_FIX_ME - //copy_m3_m3(t->mat, mat); // used in gizmo -#endif - - applyTrackballValue(t, axis1, axis2, phi); - - recalcData(t); - - ED_area_status_text(t->sa, str); -} -/** \} */ - -/* -------------------------------------------------------------------- */ -/* Transform (Normal Rotation) */ - -/** \name Transform Normal Rotation - * \{ */ - -static void storeCustomLNorValue(TransDataContainer *tc, BMesh *bm) -{ - BMLoopNorEditDataArray *lnors_ed_arr = BM_loop_normal_editdata_array_init(bm, false); - // BMLoopNorEditData *lnor_ed = lnors_ed_arr->lnor_editdata; - - tc->custom.mode.data = lnors_ed_arr; - tc->custom.mode.free_cb = freeCustomNormalArray; -} - -void freeCustomNormalArray(TransInfo *t, TransDataContainer *tc, TransCustomData *custom_data) -{ - BMLoopNorEditDataArray *lnors_ed_arr = custom_data->data; - - if (t->state == TRANS_CANCEL) { - BMLoopNorEditData *lnor_ed = lnors_ed_arr->lnor_editdata; - BMEditMesh *em = BKE_editmesh_from_object(tc->obedit); - BMesh *bm = em->bm; - - /* Restore custom loop normal on cancel */ - for (int i = 0; i < lnors_ed_arr->totloop; i++, lnor_ed++) { - BKE_lnor_space_custom_normal_to_data( - bm->lnor_spacearr->lspacearr[lnor_ed->loop_index], lnor_ed->niloc, lnor_ed->clnors_data); - } - } - - BM_loop_normal_editdata_array_free(lnors_ed_arr); - - tc->custom.mode.data = NULL; - tc->custom.mode.free_cb = NULL; -} - -static void initNormalRotation(TransInfo *t) -{ - t->mode = TFM_NORMAL_ROTATION; - t->transform = applyNormalRotation; - - setInputPostFct(&t->mouse, postInputRotation); - initMouseInputMode(t, &t->mouse, INPUT_ANGLE); - - t->idx_max = 0; - t->num.idx_max = 0; - t->snap[0] = 0.0f; - t->snap[1] = DEG2RAD(5.0); - t->snap[2] = DEG2RAD(1.0); - - copy_v3_fl(t->num.val_inc, t->snap[2]); - t->num.unit_sys = t->scene->unit.system; - t->num.unit_use_radians = (t->scene->unit.system_rotation == USER_UNIT_ROT_RADIANS); - t->num.unit_type[0] = B_UNIT_ROTATION; - - FOREACH_TRANS_DATA_CONTAINER (t, tc) { - BMEditMesh *em = BKE_editmesh_from_object(tc->obedit); - BMesh *bm = em->bm; - - BKE_editmesh_ensure_autosmooth(em, tc->obedit->data); - BKE_editmesh_lnorspace_update(em, tc->obedit->data); - - storeCustomLNorValue(tc, bm); - } -} - -/* Works by getting custom normal from clnor_data, transform, then store */ -static void applyNormalRotation(TransInfo *t, const int UNUSED(mval[2])) -{ - char str[UI_MAX_DRAW_STR]; - - float axis_final[3]; - copy_v3_v3(axis_final, t->orient_matrix[t->orient_axis]); - - if ((t->con.mode & CON_APPLY) && t->con.applyRot) { - t->con.applyRot(t, NULL, NULL, axis_final, NULL); - } - - FOREACH_TRANS_DATA_CONTAINER (t, tc) { - BMEditMesh *em = BKE_editmesh_from_object(tc->obedit); - BMesh *bm = em->bm; - - BMLoopNorEditDataArray *lnors_ed_arr = tc->custom.mode.data; - BMLoopNorEditData *lnor_ed = lnors_ed_arr->lnor_editdata; - - float axis[3]; - float mat[3][3]; - float angle = t->values[0]; - copy_v3_v3(axis, axis_final); - - snapGridIncrement(t, &angle); - - applySnapping(t, &angle); - - applyNumInput(&t->num, &angle); - - headerRotation(t, str, angle); - - axis_angle_normalized_to_mat3(mat, axis, angle); - - for (int i = 0; i < lnors_ed_arr->totloop; i++, lnor_ed++) { - mul_v3_m3v3(lnor_ed->nloc, mat, lnor_ed->niloc); - - BKE_lnor_space_custom_normal_to_data( - bm->lnor_spacearr->lspacearr[lnor_ed->loop_index], lnor_ed->nloc, lnor_ed->clnors_data); - } - - t->values_final[0] = angle; - } - - recalcData(t); - - ED_area_status_text(t->sa, str); -} - -/** \} */ - -/* -------------------------------------------------------------------- */ -/* Transform (Translation) */ - -static void initSnapSpatial(TransInfo *t, float r_snap[3]) -{ - if (t->spacetype == SPACE_VIEW3D) { - RegionView3D *rv3d = t->ar->regiondata; - - if (rv3d) { - View3D *v3d = t->sa->spacedata.first; - r_snap[0] = 0.0f; - r_snap[1] = ED_view3d_grid_view_scale(t->scene, v3d, rv3d, NULL) * 1.0f; - r_snap[2] = r_snap[1] * 0.1f; - } - } - else if (t->spacetype == SPACE_IMAGE) { - r_snap[0] = 0.0f; - r_snap[1] = 0.0625f; - r_snap[2] = 0.03125f; - } - else if (t->spacetype == SPACE_CLIP) { - r_snap[0] = 0.0f; - r_snap[1] = 0.125f; - r_snap[2] = 0.0625f; - } - else if (t->spacetype == SPACE_NODE) { - r_snap[0] = 0.0f; - r_snap[1] = r_snap[2] = ED_node_grid_size(); - } - else if (t->spacetype == SPACE_GRAPH) { - r_snap[0] = 0.0f; - r_snap[1] = 1.0; - r_snap[2] = 0.1f; - } - else { - r_snap[0] = 0.0f; - r_snap[1] = r_snap[2] = 1.0f; - } -} - -/** \name Transform Translation - * \{ */ - -static void initTranslation(TransInfo *t) -{ - if (t->spacetype == SPACE_ACTION) { - /* this space uses time translate */ - BKE_report(t->reports, - RPT_ERROR, - "Use 'Time_Translate' transform mode instead of 'Translation' mode " - "for translating keyframes in Dope Sheet Editor"); - t->state = TRANS_CANCEL; - } - - t->mode = TFM_TRANSLATION; - t->transform = applyTranslation; - - initMouseInputMode(t, &t->mouse, INPUT_VECTOR); - - t->idx_max = (t->flag & T_2D_EDIT) ? 1 : 2; - t->num.flag = 0; - t->num.idx_max = t->idx_max; - - copy_v3_v3(t->snap, t->snap_spatial); - - copy_v3_fl(t->num.val_inc, t->snap[1]); - t->num.unit_sys = t->scene->unit.system; - if (t->spacetype == SPACE_VIEW3D) { - /* Handling units makes only sense in 3Dview... See T38877. */ - t->num.unit_type[0] = B_UNIT_LENGTH; - t->num.unit_type[1] = B_UNIT_LENGTH; - t->num.unit_type[2] = B_UNIT_LENGTH; - } - else { - /* SPACE_GRAPH, SPACE_ACTION, etc. could use some time units, when we have them... */ - t->num.unit_type[0] = B_UNIT_NONE; - t->num.unit_type[1] = B_UNIT_NONE; - t->num.unit_type[2] = B_UNIT_NONE; - } -} - -static void headerTranslation(TransInfo *t, const float vec[3], char str[UI_MAX_DRAW_STR]) -{ - size_t ofs = 0; - char tvec[NUM_STR_REP_LEN * 3]; - char distvec[NUM_STR_REP_LEN]; - char autoik[NUM_STR_REP_LEN]; - float dist; - - if (hasNumInput(&t->num)) { - outputNumInput(&(t->num), tvec, &t->scene->unit); - dist = len_v3(t->num.val); - } - else { - float dvec[3]; - - copy_v3_v3(dvec, vec); - applyAspectRatio(t, dvec); - - dist = len_v3(vec); - if (!(t->flag & T_2D_EDIT) && t->scene->unit.system) { - int i; - - for (i = 0; i < 3; i++) { - bUnit_AsString2(&tvec[NUM_STR_REP_LEN * i], - NUM_STR_REP_LEN, - dvec[i] * t->scene->unit.scale_length, - 4, - B_UNIT_LENGTH, - &t->scene->unit, - true); - } - } - else { - BLI_snprintf(&tvec[0], NUM_STR_REP_LEN, "%.4f", dvec[0]); - BLI_snprintf(&tvec[NUM_STR_REP_LEN], NUM_STR_REP_LEN, "%.4f", dvec[1]); - BLI_snprintf(&tvec[NUM_STR_REP_LEN * 2], NUM_STR_REP_LEN, "%.4f", dvec[2]); - } - } - - if (!(t->flag & T_2D_EDIT) && t->scene->unit.system) { - bUnit_AsString2(distvec, - sizeof(distvec), - dist * t->scene->unit.scale_length, - 4, - B_UNIT_LENGTH, - &t->scene->unit, - false); - } - else if (dist > 1e10f || dist < -1e10f) { - /* prevent string buffer overflow */ - BLI_snprintf(distvec, NUM_STR_REP_LEN, "%.4e", dist); - } - else { - BLI_snprintf(distvec, NUM_STR_REP_LEN, "%.4f", dist); - } - - if (t->flag & T_AUTOIK) { - short chainlen = t->settings->autoik_chainlen; - - if (chainlen) { - BLI_snprintf(autoik, NUM_STR_REP_LEN, TIP_("AutoIK-Len: %d"), chainlen); - } - else { - autoik[0] = '\0'; - } - } - else { - autoik[0] = '\0'; - } - - if (t->con.mode & CON_APPLY) { - switch (t->num.idx_max) { - case 0: - ofs += BLI_snprintf(str + ofs, - UI_MAX_DRAW_STR - ofs, - "D: %s (%s)%s %s %s", - &tvec[0], - distvec, - t->con.text, - t->proptext, - autoik); - break; - case 1: - ofs += BLI_snprintf(str + ofs, - UI_MAX_DRAW_STR - ofs, - "D: %s D: %s (%s)%s %s %s", - &tvec[0], - &tvec[NUM_STR_REP_LEN], - distvec, - t->con.text, - t->proptext, - autoik); - break; - case 2: - ofs += BLI_snprintf(str + ofs, - UI_MAX_DRAW_STR - ofs, - "D: %s D: %s D: %s (%s)%s %s %s", - &tvec[0], - &tvec[NUM_STR_REP_LEN], - &tvec[NUM_STR_REP_LEN * 2], - distvec, - t->con.text, - t->proptext, - autoik); - break; - } - } - else { - if (t->flag & T_2D_EDIT) { - ofs += BLI_snprintf(str + ofs, - UI_MAX_DRAW_STR - ofs, - "Dx: %s Dy: %s (%s)%s %s", - &tvec[0], - &tvec[NUM_STR_REP_LEN], - distvec, - t->con.text, - t->proptext); - } - else { - ofs += BLI_snprintf(str + ofs, - UI_MAX_DRAW_STR - ofs, - "Dx: %s Dy: %s Dz: %s (%s)%s %s %s", - &tvec[0], - &tvec[NUM_STR_REP_LEN], - &tvec[NUM_STR_REP_LEN * 2], - distvec, - t->con.text, - t->proptext, - autoik); - } - } - - if (t->flag & T_PROP_EDIT_ALL) { - ofs += BLI_snprintf( - str + ofs, UI_MAX_DRAW_STR - ofs, TIP_(" Proportional size: %.2f"), t->prop_size); - } - - if (t->spacetype == SPACE_NODE) { - SpaceNode *snode = (SpaceNode *)t->sa->spacedata.first; - - if ((snode->flag & SNODE_SKIP_INSOFFSET) == 0) { - const char *str_old = BLI_strdup(str); - const char *str_dir = (snode->insert_ofs_dir == SNODE_INSERTOFS_DIR_RIGHT) ? TIP_("right") : - TIP_("left"); - char str_km[64]; - - WM_modalkeymap_items_to_string( - t->keymap, TFM_MODAL_INSERTOFS_TOGGLE_DIR, true, str_km, sizeof(str_km)); - - ofs += BLI_snprintf(str, - UI_MAX_DRAW_STR, - TIP_("Auto-offset set to %s - press %s to toggle direction | %s"), - str_dir, - str_km, - str_old); - - MEM_freeN((void *)str_old); - } - } -} - -static void applyTranslationValue(TransInfo *t, const float vec[3]) -{ - const bool apply_snap_align_rotation = usingSnappingNormal( - t); // && (t->tsnap.status & POINT_INIT); - float tvec[3]; - - /* The ideal would be "apply_snap_align_rotation" only when a snap point is found - * so, maybe inside this function is not the best place to apply this rotation. - * but you need "handle snapping rotation before doing the translation" (really?) */ - FOREACH_TRANS_DATA_CONTAINER (t, tc) { - - float pivot[3]; - if (apply_snap_align_rotation) { - copy_v3_v3(pivot, t->tsnap.snapTarget); - /* The pivot has to be in local-space (see T49494) */ - if (tc->use_local_mat) { - mul_m4_v3(tc->imat, pivot); - } - } - - TransData *td = tc->data; - for (int i = 0; i < tc->data_len; i++, td++) { - if (td->flag & TD_NOACTION) { - break; - } - - if (td->flag & TD_SKIP) { - continue; - } - - float rotate_offset[3] = {0}; - bool use_rotate_offset = false; - - /* handle snapping rotation before doing the translation */ - if (apply_snap_align_rotation) { - float mat[3][3]; - - if (validSnappingNormal(t)) { - const float *original_normal; - - /* In pose mode, we want to align normals with Y axis of bones... */ - if (t->flag & T_POSE) { - original_normal = td->axismtx[1]; - } - else { - original_normal = td->axismtx[2]; - } - - rotation_between_vecs_to_mat3(mat, original_normal, t->tsnap.snapNormal); - } - else { - unit_m3(mat); - } - - ElementRotation_ex(t, tc, td, mat, pivot); - - if (td->loc) { - use_rotate_offset = true; - sub_v3_v3v3(rotate_offset, td->loc, td->iloc); - } - } - - if (t->con.applyVec) { - float pvec[3]; - t->con.applyVec(t, tc, td, vec, tvec, pvec); - } - else { - copy_v3_v3(tvec, vec); - } - - mul_m3_v3(td->smtx, tvec); - - if (use_rotate_offset) { - add_v3_v3(tvec, rotate_offset); - } - - if (t->options & CTX_GPENCIL_STROKES) { - /* grease pencil multiframe falloff */ - bGPDstroke *gps = (bGPDstroke *)td->extra; - if (gps != NULL) { - mul_v3_fl(tvec, td->factor * gps->runtime.multi_frame_falloff); - } - else { - mul_v3_fl(tvec, td->factor); - } - } - else { - /* proportional editing falloff */ - mul_v3_fl(tvec, td->factor); - } - - protectedTransBits(td->protectflag, tvec); - - if (td->loc) { - add_v3_v3v3(td->loc, td->iloc, tvec); - } - - constraintTransLim(t, td); - } - } -} - -static void applyTranslation(TransInfo *t, const int UNUSED(mval[2])) -{ - char str[UI_MAX_DRAW_STR]; - float values_final[3]; - - if (t->flag & T_INPUT_IS_VALUES_FINAL) { - copy_v3_v3(t->values_final, t->values); - } - else { - copy_v3_v3(t->values_final, t->values); - if ((t->con.mode & CON_APPLY) == 0) { - snapGridIncrement(t, t->values_final); - } - - if (applyNumInput(&t->num, t->values_final)) { - removeAspectRatio(t, t->values_final); - } - - applySnapping(t, t->values_final); - } - copy_v3_v3(values_final, t->values_final); - - if (t->con.mode & CON_APPLY) { - float pvec[3] = {0.0f, 0.0f, 0.0f}; - t->con.applyVec(t, NULL, NULL, t->values_final, values_final, pvec); - headerTranslation(t, pvec, str); - - /* only so we have re-usable value with redo, see T46741. */ - mul_v3_m3v3(t->values_final, t->con.imtx, values_final); - } - else { - headerTranslation(t, t->values_final, str); - copy_v3_v3(values_final, t->values_final); - } - - /* don't use 't->values' now on */ - - applyTranslationValue(t, values_final); - - /* evil hack - redo translation if clipping needed */ - if (t->flag & T_CLIP_UV && clipUVTransform(t, values_final, 0)) { - applyTranslationValue(t, values_final); - - /* In proportional edit it can happen that */ - /* vertices in the radius of the brush end */ - /* outside the clipping area */ - /* XXX HACK - dg */ - if (t->flag & T_PROP_EDIT_ALL) { - clipUVData(t); - } - } - - recalcData(t); - - ED_area_status_text(t->sa, str); -} -/** \} */ - -/* -------------------------------------------------------------------- */ -/* Transform (Shrink-Fatten) */ - -/** \name Transform Shrink-Fatten - * \{ */ - -static void initShrinkFatten(TransInfo *t) -{ - // If not in mesh edit mode, fallback to Resize - if ((t->flag & T_EDIT) == 0 || (t->obedit_type != OB_MESH)) { - initResize(t); - } - else { - t->mode = TFM_SHRINKFATTEN; - t->transform = applyShrinkFatten; - - initMouseInputMode(t, &t->mouse, INPUT_VERTICAL_ABSOLUTE); - - t->idx_max = 0; - t->num.idx_max = 0; - t->snap[0] = 0.0f; - t->snap[1] = 1.0f; - t->snap[2] = t->snap[1] * 0.1f; - - copy_v3_fl(t->num.val_inc, t->snap[1]); - t->num.unit_sys = t->scene->unit.system; - t->num.unit_type[0] = B_UNIT_LENGTH; - - t->flag |= T_NO_CONSTRAINT; - } -} - -static void applyShrinkFatten(TransInfo *t, const int UNUSED(mval[2])) -{ - float distance; - int i; - char str[UI_MAX_DRAW_STR]; - size_t ofs = 0; - - distance = -t->values[0]; - - snapGridIncrement(t, &distance); - - applyNumInput(&t->num, &distance); - - t->values_final[0] = -distance; - - /* header print for NumInput */ - ofs += BLI_strncpy_rlen(str + ofs, TIP_("Shrink/Fatten:"), sizeof(str) - ofs); - if (hasNumInput(&t->num)) { - char c[NUM_STR_REP_LEN]; - outputNumInput(&(t->num), c, &t->scene->unit); - ofs += BLI_snprintf(str + ofs, sizeof(str) - ofs, " %s", c); - } - else { - /* default header print */ - ofs += BLI_snprintf(str + ofs, sizeof(str) - ofs, " %.4f", distance); - } - - if (t->proptext[0]) { - ofs += BLI_snprintf(str + ofs, sizeof(str) - ofs, " %s", t->proptext); - } - ofs += BLI_strncpy_rlen(str + ofs, ", (", sizeof(str) - ofs); - - if (t->keymap) { - wmKeyMapItem *kmi = WM_modalkeymap_find_propvalue(t->keymap, TFM_MODAL_RESIZE); - if (kmi) { - ofs += WM_keymap_item_to_string(kmi, false, str + ofs, sizeof(str) - ofs); - } - } - BLI_snprintf(str + ofs, - sizeof(str) - ofs, - TIP_(" or Alt) Even Thickness %s"), - WM_bool_as_string((t->flag & T_ALT_TRANSFORM) != 0)); - /* done with header string */ - - FOREACH_TRANS_DATA_CONTAINER (t, tc) { - TransData *td = tc->data; - for (i = 0; i < tc->data_len; i++, td++) { - float tdistance; /* temp dist */ - if (td->flag & TD_NOACTION) { - break; - } - - if (td->flag & TD_SKIP) { - continue; - } - - /* get the final offset */ - tdistance = distance * td->factor; - if (td->ext && (t->flag & T_ALT_TRANSFORM) != 0) { - tdistance *= td->ext->isize[0]; /* shell factor */ - } - - madd_v3_v3v3fl(td->loc, td->iloc, td->axismtx[2], tdistance); - } - } - - recalcData(t); - - ED_area_status_text(t->sa, str); -} -/** \} */ - -/* -------------------------------------------------------------------- */ -/* Transform (Tilt) */ - -/** \name Transform Tilt - * \{ */ - -static void initTilt(TransInfo *t) -{ - t->mode = TFM_TILT; - t->transform = applyTilt; - - initMouseInputMode(t, &t->mouse, INPUT_ANGLE); - - t->idx_max = 0; - t->num.idx_max = 0; - t->snap[0] = 0.0f; - t->snap[1] = DEG2RAD(5.0); - t->snap[2] = DEG2RAD(1.0); - - copy_v3_fl(t->num.val_inc, t->snap[2]); - t->num.unit_sys = t->scene->unit.system; - t->num.unit_use_radians = (t->scene->unit.system_rotation == USER_UNIT_ROT_RADIANS); - t->num.unit_type[0] = B_UNIT_ROTATION; - - t->flag |= T_NO_CONSTRAINT | T_NO_PROJECT; -} - -static void applyTilt(TransInfo *t, const int UNUSED(mval[2])) -{ - int i; - char str[UI_MAX_DRAW_STR]; - - float final; - - final = t->values[0]; - - snapGridIncrement(t, &final); - - applyNumInput(&t->num, &final); - - t->values_final[0] = final; - - if (hasNumInput(&t->num)) { - char c[NUM_STR_REP_LEN]; - - outputNumInput(&(t->num), c, &t->scene->unit); - - BLI_snprintf(str, sizeof(str), TIP_("Tilt: %s° %s"), &c[0], t->proptext); - - /* XXX For some reason, this seems needed for this op, else RNA prop is not updated... :/ */ - t->values_final[0] = final; - } - else { - BLI_snprintf(str, sizeof(str), TIP_("Tilt: %.2f° %s"), RAD2DEGF(final), t->proptext); - } - - FOREACH_TRANS_DATA_CONTAINER (t, tc) { - TransData *td = tc->data; - for (i = 0; i < tc->data_len; i++, td++) { - if (td->flag & TD_NOACTION) { - break; - } - - if (td->flag & TD_SKIP) { - continue; - } - - if (td->val) { - *td->val = td->ival + final * td->factor; - } - } - } - - recalcData(t); - - ED_area_status_text(t->sa, str); -} -/** \} */ - -/* -------------------------------------------------------------------- */ -/* Transform (Curve Shrink/Fatten) */ - -/** \name Transform Curve Shrink/Fatten - * \{ */ - -static void initCurveShrinkFatten(TransInfo *t) -{ - t->mode = TFM_CURVE_SHRINKFATTEN; - t->transform = applyCurveShrinkFatten; - - initMouseInputMode(t, &t->mouse, INPUT_SPRING); - - t->idx_max = 0; - t->num.idx_max = 0; - t->snap[0] = 0.0f; - t->snap[1] = 0.1f; - t->snap[2] = t->snap[1] * 0.1f; - - copy_v3_fl(t->num.val_inc, t->snap[1]); - t->num.unit_sys = t->scene->unit.system; - t->num.unit_type[0] = B_UNIT_NONE; - - t->flag |= T_NO_ZERO; -#ifdef USE_NUM_NO_ZERO - t->num.val_flag[0] |= NUM_NO_ZERO; -#endif - - t->flag |= T_NO_CONSTRAINT; -} - -static void applyCurveShrinkFatten(TransInfo *t, const int UNUSED(mval[2])) -{ - float ratio; - int i; - char str[UI_MAX_DRAW_STR]; - - ratio = t->values[0]; - - snapGridIncrement(t, &ratio); - - applyNumInput(&t->num, &ratio); - - t->values_final[0] = ratio; - - /* header print for NumInput */ - if (hasNumInput(&t->num)) { - char c[NUM_STR_REP_LEN]; - - outputNumInput(&(t->num), c, &t->scene->unit); - BLI_snprintf(str, sizeof(str), TIP_("Shrink/Fatten: %s"), c); - } - else { - BLI_snprintf(str, sizeof(str), TIP_("Shrink/Fatten: %3f"), ratio); - } - - FOREACH_TRANS_DATA_CONTAINER (t, tc) { - TransData *td = tc->data; - for (i = 0; i < tc->data_len; i++, td++) { - if (td->flag & TD_NOACTION) { - break; - } - - if (td->flag & TD_SKIP) { - continue; - } - - if (td->val) { - *td->val = td->ival * ratio; - /* apply PET */ - *td->val = (*td->val * td->factor) + ((1.0f - td->factor) * td->ival); - if (*td->val <= 0.0f) { - *td->val = 0.001f; - } - } - } - } - - recalcData(t); - - ED_area_status_text(t->sa, str); -} -/** \} */ - -/* -------------------------------------------------------------------- */ -/* Transform (Mask Shrink/Fatten) */ - -/** \name Transform Mask Shrink/Fatten - * \{ */ - -static void initMaskShrinkFatten(TransInfo *t) -{ - t->mode = TFM_MASK_SHRINKFATTEN; - t->transform = applyMaskShrinkFatten; - - initMouseInputMode(t, &t->mouse, INPUT_SPRING); - - t->idx_max = 0; - t->num.idx_max = 0; - t->snap[0] = 0.0f; - t->snap[1] = 0.1f; - t->snap[2] = t->snap[1] * 0.1f; - - copy_v3_fl(t->num.val_inc, t->snap[1]); - t->num.unit_sys = t->scene->unit.system; - t->num.unit_type[0] = B_UNIT_NONE; - - t->flag |= T_NO_ZERO; -#ifdef USE_NUM_NO_ZERO - t->num.val_flag[0] |= NUM_NO_ZERO; -#endif - - t->flag |= T_NO_CONSTRAINT; -} - -static void applyMaskShrinkFatten(TransInfo *t, const int UNUSED(mval[2])) -{ - float ratio; - int i; - bool initial_feather = false; - char str[UI_MAX_DRAW_STR]; - - ratio = t->values[0]; - - snapGridIncrement(t, &ratio); - - applyNumInput(&t->num, &ratio); - - t->values_final[0] = ratio; - - /* header print for NumInput */ - if (hasNumInput(&t->num)) { - char c[NUM_STR_REP_LEN]; - - outputNumInput(&(t->num), c, &t->scene->unit); - BLI_snprintf(str, sizeof(str), TIP_("Feather Shrink/Fatten: %s"), c); - } - else { - BLI_snprintf(str, sizeof(str), TIP_("Feather Shrink/Fatten: %3f"), ratio); - } - - /* detect if no points have feather yet */ - if (ratio > 1.0f) { - initial_feather = true; - - FOREACH_TRANS_DATA_CONTAINER (t, tc) { - TransData *td = tc->data; - for (i = 0; i < tc->data_len; i++, td++) { - if (td->flag & TD_NOACTION) { - break; - } - - if (td->flag & TD_SKIP) { - continue; - } - - if (td->ival >= 0.001f) { - initial_feather = false; - } - } - } - } - - /* apply shrink/fatten */ - FOREACH_TRANS_DATA_CONTAINER (t, tc) { - TransData *td = tc->data; - for (td = tc->data, i = 0; i < tc->data_len; i++, td++) { - if (td->flag & TD_NOACTION) { - break; - } - - if (td->flag & TD_SKIP) { - continue; - } - - if (td->val) { - if (initial_feather) { - *td->val = td->ival + (ratio - 1.0f) * 0.01f; - } - else { - *td->val = td->ival * ratio; - } - - /* apply PET */ - *td->val = (*td->val * td->factor) + ((1.0f - td->factor) * td->ival); - if (*td->val <= 0.0f) { - *td->val = 0.001f; - } - } - } - } - - recalcData(t); - - ED_area_status_text(t->sa, str); -} -/** \} */ - -/* -------------------------------------------------------------------- */ -/* Transform (GPencil Shrink/Fatten) */ - -/** \name Transform GPencil Strokes Shrink/Fatten - * \{ */ - -static void initGPShrinkFatten(TransInfo *t) -{ - t->mode = TFM_GPENCIL_SHRINKFATTEN; - t->transform = applyGPShrinkFatten; - - initMouseInputMode(t, &t->mouse, INPUT_SPRING); - - t->idx_max = 0; - t->num.idx_max = 0; - t->snap[0] = 0.0f; - t->snap[1] = 0.1f; - t->snap[2] = t->snap[1] * 0.1f; - - copy_v3_fl(t->num.val_inc, t->snap[1]); - t->num.unit_sys = t->scene->unit.system; - t->num.unit_type[0] = B_UNIT_NONE; - - t->flag |= T_NO_ZERO; -#ifdef USE_NUM_NO_ZERO - t->num.val_flag[0] |= NUM_NO_ZERO; -#endif - - t->flag |= T_NO_CONSTRAINT; -} - -static void applyGPShrinkFatten(TransInfo *t, const int UNUSED(mval[2])) -{ - float ratio; - int i; - char str[UI_MAX_DRAW_STR]; - - ratio = t->values[0]; - - snapGridIncrement(t, &ratio); - - applyNumInput(&t->num, &ratio); - - t->values_final[0] = ratio; - - /* header print for NumInput */ - if (hasNumInput(&t->num)) { - char c[NUM_STR_REP_LEN]; - - outputNumInput(&(t->num), c, &t->scene->unit); - BLI_snprintf(str, sizeof(str), TIP_("Shrink/Fatten: %s"), c); - } - else { - BLI_snprintf(str, sizeof(str), TIP_("Shrink/Fatten: %3f"), ratio); - } - - FOREACH_TRANS_DATA_CONTAINER (t, tc) { - TransData *td = tc->data; - for (i = 0; i < tc->data_len; i++, td++) { - if (td->flag & TD_NOACTION) { - break; - } - - if (td->flag & TD_SKIP) { - continue; - } - - if (td->val) { - *td->val = td->ival * ratio; - /* apply PET */ - *td->val = (*td->val * td->factor) + ((1.0f - td->factor) * td->ival); - if (*td->val <= 0.0f) { - *td->val = 0.001f; - } - } - } - } - - ED_area_status_text(t->sa, str); -} -/** \} */ - -/* -------------------------------------------------------------------- */ -/* Transform (GPencil Opacity) */ - -/** \name Transform GPencil Strokes Opacity - * \{ */ - -static void initGPOpacity(TransInfo *t) -{ - t->mode = TFM_GPENCIL_OPACITY; - t->transform = applyGPOpacity; - - initMouseInputMode(t, &t->mouse, INPUT_SPRING); - - t->idx_max = 0; - t->num.idx_max = 0; - t->snap[0] = 0.0f; - t->snap[1] = 0.1f; - t->snap[2] = t->snap[1] * 0.1f; - - copy_v3_fl(t->num.val_inc, t->snap[1]); - t->num.unit_sys = t->scene->unit.system; - t->num.unit_type[0] = B_UNIT_NONE; - - t->flag |= T_NO_ZERO; -#ifdef USE_NUM_NO_ZERO - t->num.val_flag[0] |= NUM_NO_ZERO; -#endif - - t->flag |= T_NO_CONSTRAINT; -} - -static void applyGPOpacity(TransInfo *t, const int UNUSED(mval[2])) -{ - float ratio; - int i; - char str[UI_MAX_DRAW_STR]; - - ratio = t->values[0]; - - snapGridIncrement(t, &ratio); - - applyNumInput(&t->num, &ratio); - - t->values_final[0] = ratio; - - /* header print for NumInput */ - if (hasNumInput(&t->num)) { - char c[NUM_STR_REP_LEN]; - - outputNumInput(&(t->num), c, &t->scene->unit); - BLI_snprintf(str, sizeof(str), TIP_("Opacity: %s"), c); - } - else { - BLI_snprintf(str, sizeof(str), TIP_("Opacity: %3f"), ratio); - } - - FOREACH_TRANS_DATA_CONTAINER (t, tc) { - TransData *td = tc->data; - for (i = 0; i < tc->data_len; i++, td++) { - if (td->flag & TD_NOACTION) { - break; - } - - if (td->flag & TD_SKIP) { - continue; - } - - if (td->val) { - *td->val = td->ival * ratio; - /* apply PET */ - *td->val = (*td->val * td->factor) + ((1.0f - td->factor) * td->ival); - CLAMP(*td->val, 0.0f, 1.0f); - } - } - } - - ED_area_status_text(t->sa, str); -} -/** \} */ - -/* -------------------------------------------------------------------- */ -/* Transform (Push/Pull) */ - -/** \name Transform Push/Pull - * \{ */ - -static void initPushPull(TransInfo *t) -{ - t->mode = TFM_PUSHPULL; - t->transform = applyPushPull; - - initMouseInputMode(t, &t->mouse, INPUT_VERTICAL_ABSOLUTE); - - t->idx_max = 0; - t->num.idx_max = 0; - t->snap[0] = 0.0f; - t->snap[1] = 1.0f; - t->snap[2] = t->snap[1] * 0.1f; - - copy_v3_fl(t->num.val_inc, t->snap[1]); - t->num.unit_sys = t->scene->unit.system; - t->num.unit_type[0] = B_UNIT_LENGTH; -} - -static void applyPushPull(TransInfo *t, const int UNUSED(mval[2])) -{ - float vec[3], axis_global[3]; - float distance; - int i; - char str[UI_MAX_DRAW_STR]; - - distance = t->values[0]; - - snapGridIncrement(t, &distance); - - applyNumInput(&t->num, &distance); - - t->values_final[0] = distance; - - /* header print for NumInput */ - if (hasNumInput(&t->num)) { - char c[NUM_STR_REP_LEN]; - - outputNumInput(&(t->num), c, &t->scene->unit); - - BLI_snprintf(str, sizeof(str), TIP_("Push/Pull: %s%s %s"), c, t->con.text, t->proptext); - } - else { - /* default header print */ - BLI_snprintf( - str, sizeof(str), TIP_("Push/Pull: %.4f%s %s"), distance, t->con.text, t->proptext); - } - - if (t->con.applyRot && t->con.mode & CON_APPLY) { - t->con.applyRot(t, NULL, NULL, axis_global, NULL); - } - - FOREACH_TRANS_DATA_CONTAINER (t, tc) { - TransData *td = tc->data; - for (i = 0; i < tc->data_len; i++, td++) { - if (td->flag & TD_NOACTION) { - break; - } - - if (td->flag & TD_SKIP) { - continue; - } - - sub_v3_v3v3(vec, tc->center_local, td->center); - if (t->con.applyRot && t->con.mode & CON_APPLY) { - float axis[3]; - copy_v3_v3(axis, axis_global); - t->con.applyRot(t, tc, td, axis, NULL); - - mul_m3_v3(td->smtx, axis); - if (isLockConstraint(t)) { - float dvec[3]; - project_v3_v3v3(dvec, vec, axis); - sub_v3_v3(vec, dvec); - } - else { - project_v3_v3v3(vec, vec, axis); - } - } - normalize_v3_length(vec, distance * td->factor); - - add_v3_v3v3(td->loc, td->iloc, vec); - } - } - - recalcData(t); - - ED_area_status_text(t->sa, str); -} -/** \} */ - -/* -------------------------------------------------------------------- */ -/* Transform (Bevel Weight) */ - -/** \name Transform Bevel Weight - * \{ */ - -static void initBevelWeight(TransInfo *t) -{ - t->mode = TFM_BWEIGHT; - t->transform = applyBevelWeight; - - initMouseInputMode(t, &t->mouse, INPUT_SPRING_DELTA); - - t->idx_max = 0; - t->num.idx_max = 0; - t->snap[0] = 0.0f; - t->snap[1] = 0.1f; - t->snap[2] = t->snap[1] * 0.1f; - - copy_v3_fl(t->num.val_inc, t->snap[1]); - t->num.unit_sys = t->scene->unit.system; - t->num.unit_type[0] = B_UNIT_NONE; - - t->flag |= T_NO_CONSTRAINT | T_NO_PROJECT; -} - -static void applyBevelWeight(TransInfo *t, const int UNUSED(mval[2])) -{ - float weight; - int i; - char str[UI_MAX_DRAW_STR]; - - weight = t->values[0]; - - CLAMP_MAX(weight, 1.0f); - - snapGridIncrement(t, &weight); - - applyNumInput(&t->num, &weight); - - t->values_final[0] = weight; - - /* header print for NumInput */ - if (hasNumInput(&t->num)) { - char c[NUM_STR_REP_LEN]; - - outputNumInput(&(t->num), c, &t->scene->unit); - - if (weight >= 0.0f) { - BLI_snprintf(str, sizeof(str), TIP_("Bevel Weight: +%s %s"), c, t->proptext); - } - else { - BLI_snprintf(str, sizeof(str), TIP_("Bevel Weight: %s %s"), c, t->proptext); - } - } - else { - /* default header print */ - if (weight >= 0.0f) { - BLI_snprintf(str, sizeof(str), TIP_("Bevel Weight: +%.3f %s"), weight, t->proptext); - } - else { - BLI_snprintf(str, sizeof(str), TIP_("Bevel Weight: %.3f %s"), weight, t->proptext); - } - } - - FOREACH_TRANS_DATA_CONTAINER (t, tc) { - TransData *td = tc->data; - for (i = 0; i < tc->data_len; i++, td++) { - if (td->flag & TD_NOACTION) { - break; - } - - if (td->val) { - *td->val = td->ival + weight * td->factor; - if (*td->val < 0.0f) { - *td->val = 0.0f; - } - if (*td->val > 1.0f) { - *td->val = 1.0f; - } - } - } - } - - recalcData(t); - - ED_area_status_text(t->sa, str); -} -/** \} */ - -/* -------------------------------------------------------------------- */ -/* Transform (Crease) */ - -/** \name Transform Crease - * \{ */ - -static void initCrease(TransInfo *t) -{ - t->mode = TFM_CREASE; - t->transform = applyCrease; - - initMouseInputMode(t, &t->mouse, INPUT_SPRING_DELTA); - - t->idx_max = 0; - t->num.idx_max = 0; - t->snap[0] = 0.0f; - t->snap[1] = 0.1f; - t->snap[2] = t->snap[1] * 0.1f; - - copy_v3_fl(t->num.val_inc, t->snap[1]); - t->num.unit_sys = t->scene->unit.system; - t->num.unit_type[0] = B_UNIT_NONE; - - t->flag |= T_NO_CONSTRAINT | T_NO_PROJECT; -} - -static void applyCrease(TransInfo *t, const int UNUSED(mval[2])) -{ - float crease; - int i; - char str[UI_MAX_DRAW_STR]; - - crease = t->values[0]; - - CLAMP_MAX(crease, 1.0f); - - snapGridIncrement(t, &crease); - - applyNumInput(&t->num, &crease); - - t->values_final[0] = crease; - - /* header print for NumInput */ - if (hasNumInput(&t->num)) { - char c[NUM_STR_REP_LEN]; - - outputNumInput(&(t->num), c, &t->scene->unit); - - if (crease >= 0.0f) { - BLI_snprintf(str, sizeof(str), TIP_("Crease: +%s %s"), c, t->proptext); - } - else { - BLI_snprintf(str, sizeof(str), TIP_("Crease: %s %s"), c, t->proptext); - } - } - else { - /* default header print */ - if (crease >= 0.0f) { - BLI_snprintf(str, sizeof(str), TIP_("Crease: +%.3f %s"), crease, t->proptext); - } - else { - BLI_snprintf(str, sizeof(str), TIP_("Crease: %.3f %s"), crease, t->proptext); - } - } - - FOREACH_TRANS_DATA_CONTAINER (t, tc) { - TransData *td = tc->data; - for (i = 0; i < tc->data_len; i++, td++) { - if (td->flag & TD_NOACTION) { - break; - } - - if (td->flag & TD_SKIP) { - continue; - } - - if (td->val) { - *td->val = td->ival + crease * td->factor; - if (*td->val < 0.0f) { - *td->val = 0.0f; - } - if (*td->val > 1.0f) { - *td->val = 1.0f; - } - } - } - } - - recalcData(t); - - ED_area_status_text(t->sa, str); -} -/** \} */ - -/* -------------------------------------------------------------------- */ -/* Transform (EditBone (B-bone) width scaling) */ - -/** \name Transform B-bone width scaling - * \{ */ - -static void initBoneSize(TransInfo *t) -{ - t->mode = TFM_BONESIZE; - t->transform = applyBoneSize; - - initMouseInputMode(t, &t->mouse, INPUT_SPRING_FLIP); - - t->idx_max = 2; - t->num.idx_max = 2; - t->num.val_flag[0] |= NUM_NULL_ONE; - t->num.val_flag[1] |= NUM_NULL_ONE; - t->num.val_flag[2] |= NUM_NULL_ONE; - t->num.flag |= NUM_AFFECT_ALL; - t->snap[0] = 0.0f; - t->snap[1] = 0.1f; - t->snap[2] = t->snap[1] * 0.1f; - - copy_v3_fl(t->num.val_inc, t->snap[1]); - t->num.unit_sys = t->scene->unit.system; - t->num.unit_type[0] = B_UNIT_NONE; - t->num.unit_type[1] = B_UNIT_NONE; - t->num.unit_type[2] = B_UNIT_NONE; -} - -static void headerBoneSize(TransInfo *t, const float vec[3], char str[UI_MAX_DRAW_STR]) -{ - char tvec[NUM_STR_REP_LEN * 3]; - if (hasNumInput(&t->num)) { - outputNumInput(&(t->num), tvec, &t->scene->unit); - } - else { - BLI_snprintf(&tvec[0], NUM_STR_REP_LEN, "%.4f", vec[0]); - BLI_snprintf(&tvec[NUM_STR_REP_LEN], NUM_STR_REP_LEN, "%.4f", vec[1]); - BLI_snprintf(&tvec[NUM_STR_REP_LEN * 2], NUM_STR_REP_LEN, "%.4f", vec[2]); - } - - /* hmm... perhaps the y-axis values don't need to be shown? */ - if (t->con.mode & CON_APPLY) { - if (t->num.idx_max == 0) { - BLI_snprintf( - str, UI_MAX_DRAW_STR, TIP_("ScaleB: %s%s %s"), &tvec[0], t->con.text, t->proptext); - } - else { - BLI_snprintf(str, - UI_MAX_DRAW_STR, - TIP_("ScaleB: %s : %s : %s%s %s"), - &tvec[0], - &tvec[NUM_STR_REP_LEN], - &tvec[NUM_STR_REP_LEN * 2], - t->con.text, - t->proptext); - } - } - else { - BLI_snprintf(str, - UI_MAX_DRAW_STR, - TIP_("ScaleB X: %s Y: %s Z: %s%s %s"), - &tvec[0], - &tvec[NUM_STR_REP_LEN], - &tvec[NUM_STR_REP_LEN * 2], - t->con.text, - t->proptext); - } -} - -static void ElementBoneSize(TransInfo *t, TransDataContainer *tc, TransData *td, float mat[3][3]) -{ - float tmat[3][3], smat[3][3], oldy; - float sizemat[3][3]; - - mul_m3_m3m3(smat, mat, td->mtx); - mul_m3_m3m3(tmat, td->smtx, smat); - - if (t->con.applySize) { - t->con.applySize(t, tc, td, tmat); - } - - /* we've tucked the scale in loc */ - oldy = td->iloc[1]; - size_to_mat3(sizemat, td->iloc); - mul_m3_m3m3(tmat, tmat, sizemat); - mat3_to_size(td->loc, tmat); - td->loc[1] = oldy; -} - -static void applyBoneSize(TransInfo *t, const int UNUSED(mval[2])) -{ - float size[3], mat[3][3]; - float ratio = t->values[0]; - int i; - char str[UI_MAX_DRAW_STR]; - - copy_v3_fl(size, ratio); - - snapGridIncrement(t, size); - - if (applyNumInput(&t->num, size)) { - constraintNumInput(t, size); - } - - copy_v3_v3(t->values_final, size); - - size_to_mat3(mat, size); - - if (t->con.applySize) { - t->con.applySize(t, NULL, NULL, mat); - } - - copy_m3_m3(t->mat, mat); // used in gizmo - - headerBoneSize(t, size, str); - - FOREACH_TRANS_DATA_CONTAINER (t, tc) { - TransData *td = tc->data; - for (i = 0; i < tc->data_len; i++, td++) { - if (td->flag & TD_NOACTION) { - break; - } - - if (td->flag & TD_SKIP) { - continue; - } - - ElementBoneSize(t, tc, td, mat); - } - } - - recalcData(t); - - ED_area_status_text(t->sa, str); -} -/** \} */ - -/* -------------------------------------------------------------------- */ -/* Transform (Bone Envelope) */ - -/** \name Transform Bone Envelope - * \{ */ - -static void initBoneEnvelope(TransInfo *t) -{ - t->mode = TFM_BONE_ENVELOPE; - t->transform = applyBoneEnvelope; - - initMouseInputMode(t, &t->mouse, INPUT_SPRING); - - t->idx_max = 0; - t->num.idx_max = 0; - t->snap[0] = 0.0f; - t->snap[1] = 0.1f; - t->snap[2] = t->snap[1] * 0.1f; - - copy_v3_fl(t->num.val_inc, t->snap[1]); - t->num.unit_sys = t->scene->unit.system; - t->num.unit_type[0] = B_UNIT_NONE; - - t->flag |= T_NO_CONSTRAINT | T_NO_PROJECT; -} - -static void applyBoneEnvelope(TransInfo *t, const int UNUSED(mval[2])) -{ - float ratio; - int i; - char str[UI_MAX_DRAW_STR]; - - ratio = t->values[0]; - - snapGridIncrement(t, &ratio); - - applyNumInput(&t->num, &ratio); - - t->values_final[0] = ratio; - - /* header print for NumInput */ - if (hasNumInput(&t->num)) { - char c[NUM_STR_REP_LEN]; - - outputNumInput(&(t->num), c, &t->scene->unit); - BLI_snprintf(str, sizeof(str), TIP_("Envelope: %s"), c); - } - else { - BLI_snprintf(str, sizeof(str), TIP_("Envelope: %3f"), ratio); - } - - FOREACH_TRANS_DATA_CONTAINER (t, tc) { - TransData *td = tc->data; - for (i = 0; i < tc->data_len; i++, td++) { - if (td->flag & TD_NOACTION) { - break; - } - - if (td->flag & TD_SKIP) { - continue; - } - - if (td->val) { - /* if the old/original value was 0.0f, then just use ratio */ - if (td->ival) { - *td->val = td->ival * ratio; - } - else { - *td->val = ratio; - } - } - } - } - - recalcData(t); - - ED_area_status_text(t->sa, str); -} -/** \} */ - -/* -------------------------------------------------------------------- */ -/* Transform (Edge Slide) */ - -/** \name Transform Edge Slide - * \{ */ - -/** - * Get the first valid EdgeSlideData. - * - * Note we cannot trust TRANS_DATA_CONTAINER_FIRST_OK because of multi-object that - * may leave items with invalid custom data in the transform data container. - */ -static EdgeSlideData *edgeSlideFirstGet(TransInfo *t) -{ - FOREACH_TRANS_DATA_CONTAINER (t, tc) { - EdgeSlideData *sld = tc->custom.mode.data; - if (sld == NULL) { - continue; - } - return sld; - } - BLI_assert(!"Should never happen, at least one EdgeSlideData should be valid"); - return NULL; -} - -static void calcEdgeSlideCustomPoints(struct TransInfo *t) -{ - EdgeSlideData *sld = edgeSlideFirstGet(t); - - 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 immediately 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; - BMEdge *e_iter; - - BM_ITER_ELEM (e_iter, &iter, v, BM_EDGES_OF_VERT) { - if (BM_elem_flag_test(e_iter, BM_ELEM_SELECT) && e_iter != e) { - return e_iter; - } - } - - return NULL; -} - -/* 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], float t) -{ - float t_mid, t_delta; - - /* could be pre-calculated */ - t_mid = line_point_factor_v3(v2, v1, v3); - - t_delta = 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 { - 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); - } - } -} - -/** - * Find the closest point on the ngon on the opposite side. - * used to set the edge slide distance for ngons. - */ -static bool bm_loop_calc_opposite_co(BMLoop *l_tmp, const float plane_no[3], float r_co[3]) -{ - /* skip adjacent edges */ - BMLoop *l_first = l_tmp->next; - BMLoop *l_last = l_tmp->prev; - BMLoop *l_iter; - float dist = FLT_MAX; - bool found = false; - - l_iter = l_first; - do { - float tvec[3]; - if (isect_line_plane_v3(tvec, l_iter->v->co, l_iter->next->v->co, l_tmp->v->co, plane_no)) { - const float fac = line_point_factor_v3(tvec, l_iter->v->co, l_iter->next->v->co); - /* allow some overlap to avoid missing the intersection because of float precision */ - if ((fac > -FLT_EPSILON) && (fac < 1.0f + FLT_EPSILON)) { - /* likelihood of multiple intersections per ngon is quite low, - * it would have to loop back on its self, but better support it - * so check for the closest opposite edge */ - const float tdist = len_v3v3(l_tmp->v->co, tvec); - if (tdist < dist) { - copy_v3_v3(r_co, tvec); - dist = tdist; - found = true; - } - } - } - } while ((l_iter = l_iter->next) != l_last); - - return found; -} - -/** - * Given 2 edges and a loop, step over the loops - * and calculate a direction to slide along. - * - * \param r_slide_vec: the direction to slide, - * the length of the vector defines the slide distance. - */ -static BMLoop *get_next_loop( - BMVert *v, BMLoop *l, BMEdge *e_prev, BMEdge *e_next, float r_slide_vec[3]) -{ - BMLoop *l_first; - float vec_accum[3] = {0.0f, 0.0f, 0.0f}; - float vec_accum_len = 0.0f; - int i = 0; - - BLI_assert(BM_edge_share_vert(e_prev, e_next) == v); - BLI_assert(BM_vert_in_edge(l->e, v)); - - l_first = l; - do { - l = BM_loop_other_edge_loop(l, v); - - if (l->e == e_next) { - if (i) { - normalize_v3_length(vec_accum, vec_accum_len / (float)i); - } - else { - /* When there is no edge to slide along, - * we must slide along the vector defined by the face we're attach to */ - BMLoop *l_tmp = BM_face_vert_share_loop(l_first->f, v); - - BLI_assert(ELEM(l_tmp->e, e_prev, e_next) && ELEM(l_tmp->prev->e, e_prev, e_next)); - - if (l_tmp->f->len == 4) { - /* we could use code below, but in this case - * sliding diagonally across the quad works well */ - sub_v3_v3v3(vec_accum, l_tmp->next->next->v->co, v->co); - } - else { - float tdir[3]; - BM_loop_calc_face_direction(l_tmp, tdir); - cross_v3_v3v3(vec_accum, l_tmp->f->no, tdir); -#if 0 - /* rough guess, we can do better! */ - normalize_v3_length(vec_accum, - (BM_edge_calc_length(e_prev) + BM_edge_calc_length(e_next)) / 2.0f); -#else - /* be clever, check the opposite ngon edge to slide into. - * this gives best results */ - { - float tvec[3]; - float dist; - - if (bm_loop_calc_opposite_co(l_tmp, tdir, tvec)) { - dist = len_v3v3(l_tmp->v->co, tvec); - } - else { - dist = (BM_edge_calc_length(e_prev) + BM_edge_calc_length(e_next)) / 2.0f; - } - - normalize_v3_length(vec_accum, dist); - } -#endif - } - } - - copy_v3_v3(r_slide_vec, vec_accum); - return l; - } - else { - /* accumulate the normalized edge vector, - * normalize so some edges don't skew the result */ - float tvec[3]; - sub_v3_v3v3(tvec, BM_edge_other_vert(l->e, v)->co, v->co); - vec_accum_len += normalize_v3(tvec); - add_v3_v3(vec_accum, tvec); - i += 1; - } - - if (BM_loop_other_edge_loop(l, v)->e == e_next) { - if (i) { - normalize_v3_length(vec_accum, vec_accum_len / (float)i); - } - - copy_v3_v3(r_slide_vec, vec_accum); - return BM_loop_other_edge_loop(l, v); - } - - } while ((l != l->radial_next) && ((l = l->radial_next) != l_first)); - - if (i) { - normalize_v3_length(vec_accum, vec_accum_len / (float)i); - } - - copy_v3_v3(r_slide_vec, vec_accum); - - return NULL; -} - -/** - * Calculate screenspace `mval_start` / `mval_end`, optionally slide direction. - */ -static void calcEdgeSlide_mval_range(TransInfo *t, - TransDataContainer *tc, - EdgeSlideData *sld, - const int *sv_table, - const int loop_nr, - const float mval[2], - const bool use_occlude_geometry, - const bool use_calc_direction) -{ - TransDataEdgeSlideVert *sv_array = sld->sv; - BMEditMesh *em = BKE_editmesh_from_object(tc->obedit); - BMesh *bm = em->bm; - ARegion *ar = t->ar; - View3D *v3d = NULL; - RegionView3D *rv3d = NULL; - float projectMat[4][4]; - BMBVHTree *bmbvh; - - /* 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, tc->obedit, projectMat); - } - - if (use_occlude_geometry) { - bmbvh = BKE_bmbvh_new_from_editmesh(em, BMBVH_RESPECT_HIDDEN, NULL, false); - } - else { - bmbvh = 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_occlude_geometry && - !BMBVH_EdgeVisible(bmbvh, e_other, t->depsgraph, ar, v3d, tc->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 (bmbvh) { - BKE_bmbvh_free(bmbvh); - } -} - -static void calcEdgeSlide_even(TransInfo *t, - TransDataContainer *tc, - EdgeSlideData *sld, - const float mval[2]) -{ - TransDataEdgeSlideVert *sv = sld->sv; - - if (sld->totsv > 0) { - ARegion *ar = t->ar; - RegionView3D *rv3d = NULL; - float projectMat[4][4]; - - int i = 0; - - float v_proj[2]; - float dist_sq = 0; - float dist_min_sq = FLT_MAX; - - if (t->spacetype == SPACE_VIEW3D) { - /* background mode support */ - 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, tc->obedit, projectMat); - } - - for (i = 0; i < sld->totsv; i++, sv++) { - /* Set length */ - 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); - if (dist_sq < dist_min_sq) { - dist_min_sq = dist_sq; - sld->curr_sv_index = i; - } - } - } - else { - sld->curr_sv_index = 0; - } -} - -static bool createEdgeSlideVerts_double_side(TransInfo *t, TransDataContainer *tc) -{ - BMEditMesh *em = BKE_editmesh_from_object(tc->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 numsel, i, loop_nr; - bool use_occlude_geometry = false; - View3D *v3d = NULL; - RegionView3D *rv3d = NULL; - - sld->curr_sv_index = 0; - - /*ensure valid selection*/ - BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) { - if (BM_elem_flag_test(v, BM_ELEM_SELECT)) { - BMIter iter2; - numsel = 0; - BM_ITER_ELEM (e, &iter2, v, BM_EDGES_OF_VERT) { - if (BM_elem_flag_test(e, BM_ELEM_SELECT)) { - /* BMESH_TODO: this is probably very evil, - * set v->e to a selected edge*/ - v->e = e; - - numsel++; - } - } - - if (numsel == 0 || numsel > 2) { - MEM_freeN(sld); - return false; /* invalid edge selection */ - } - } - } - - BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) { - if (BM_elem_flag_test(e, BM_ELEM_SELECT)) { - /* note, any edge with loops can work, but we won't get predictable results, so bail out */ - if (!BM_edge_is_manifold(e) && !BM_edge_is_boundary(e)) { - /* can edges with at least once face user */ - MEM_freeN(sld); - return false; - } - } - } - - sv_table = MEM_mallocN(sizeof(*sv_table) * bm->totvert, __func__); - -#define INDEX_UNSET -1 -#define INDEX_INVALID -2 - - { - int j = 0; - BM_ITER_MESH_INDEX (v, &iter, bm, BM_VERTS_OF_MESH, i) { - if (BM_elem_flag_test(v, BM_ELEM_SELECT)) { - BM_elem_flag_enable(v, BM_ELEM_TAG); - sv_table[i] = INDEX_UNSET; - j += 1; - } - else { - BM_elem_flag_disable(v, BM_ELEM_TAG); - sv_table[i] = INDEX_INVALID; - } - BM_elem_index_set(v, i); /* set_inline */ - } - bm->elem_index_dirty &= ~BM_VERT; - - if (!j) { - MEM_freeN(sld); - MEM_freeN(sv_table); - return false; - } - sv_tot = j; - } - - sv_array = MEM_callocN(sizeof(TransDataEdgeSlideVert) * sv_tot, "sv_array"); - loop_nr = 0; - - STACK_DECLARE(sv_array); - STACK_INIT(sv_array, sv_tot); - - while (1) { - float vec_a[3], vec_b[3]; - BMLoop *l_a, *l_b; - BMLoop *l_a_prev, *l_b_prev; - BMVert *v_first; - /* If this succeeds call get_next_loop() - * which calculates the direction to slide based on clever checks. - * - * otherwise we simply use 'e_dir' as an edge-rail. - * (which is better when the attached edge is a boundary, see: T40422) - */ -#define EDGESLIDE_VERT_IS_INNER(v, e_dir) \ - ((BM_edge_is_boundary(e_dir) == false) && (BM_vert_edge_count_nonwire(v) == 2)) - - v = NULL; - BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) { - if (BM_elem_flag_test(v, BM_ELEM_TAG)) { - break; - } - } - - if (!v) { - break; - } - - if (!v->e) { - continue; - } - - v_first = v; - - /*walk along the edge loop*/ - e = v->e; - - /*first, rewind*/ - do { - e = get_other_edge(v, e); - if (!e) { - e = v->e; - break; - } - - if (!BM_elem_flag_test(BM_edge_other_vert(e, v), BM_ELEM_TAG)) { - break; - } - - v = BM_edge_other_vert(e, v); - } while (e != v_first->e); - - BM_elem_flag_disable(v, BM_ELEM_TAG); - - l_a = e->l; - l_b = e->l->radial_next; - - /* regarding e_next, use get_next_loop()'s improved interpolation where possible */ - { - BMEdge *e_next = get_other_edge(v, e); - if (e_next) { - get_next_loop(v, l_a, e, e_next, vec_a); - } - else { - BMLoop *l_tmp = BM_loop_other_edge_loop(l_a, v); - if (EDGESLIDE_VERT_IS_INNER(v, l_tmp->e)) { - get_next_loop(v, l_a, e, l_tmp->e, vec_a); - } - else { - sub_v3_v3v3(vec_a, BM_edge_other_vert(l_tmp->e, v)->co, v->co); - } - } - } - - /* !BM_edge_is_boundary(e); */ - if (l_b != l_a) { - BMEdge *e_next = get_other_edge(v, e); - if (e_next) { - get_next_loop(v, l_b, e, e_next, vec_b); - } - else { - BMLoop *l_tmp = BM_loop_other_edge_loop(l_b, v); - if (EDGESLIDE_VERT_IS_INNER(v, l_tmp->e)) { - get_next_loop(v, l_b, e, l_tmp->e, vec_b); - } - else { - sub_v3_v3v3(vec_b, BM_edge_other_vert(l_tmp->e, v)->co, v->co); - } - } - } - else { - l_b = NULL; - } - - l_a_prev = NULL; - l_b_prev = NULL; - -#define SV_FROM_VERT(v) \ - ((sv_table[BM_elem_index_get(v)] == INDEX_UNSET) ? \ - ((void)(sv_table[BM_elem_index_get(v)] = STACK_SIZE(sv_array)), \ - STACK_PUSH_RET_PTR(sv_array)) : \ - (&sv_array[sv_table[BM_elem_index_get(v)]])) - - /*iterate over the loop*/ - v_first = v; - do { - bool l_a_ok_prev; - bool l_b_ok_prev; - TransDataEdgeSlideVert *sv; - BMVert *v_prev; - BMEdge *e_prev; - - /* XXX, 'sv' will initialize multiple times, this is suspicious. see [#34024] */ - BLI_assert(v != NULL); - BLI_assert(sv_table[BM_elem_index_get(v)] != INDEX_INVALID); - sv = SV_FROM_VERT(v); - sv->v = v; - copy_v3_v3(sv->v_co_orig, v->co); - sv->loop_nr = loop_nr; - - if (l_a || l_a_prev) { - BMLoop *l_tmp = BM_loop_other_edge_loop(l_a ? l_a : l_a_prev, v); - 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_side[1] = BM_edge_other_vert(l_tmp->e, v); - copy_v3_v3(sv->dir_side[1], vec_b); - } - - v_prev = v; - v = BM_edge_other_vert(e, v); - - e_prev = e; - e = get_other_edge(v, e); - - if (!e) { - BLI_assert(v != NULL); - - BLI_assert(sv_table[BM_elem_index_get(v)] != INDEX_INVALID); - sv = SV_FROM_VERT(v); - - sv->v = v; - copy_v3_v3(sv->v_co_orig, v->co); - sv->loop_nr = loop_nr; - - if (l_a) { - BMLoop *l_tmp = BM_loop_other_edge_loop(l_a, 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_side[0]); - } - else { - 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_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_side[1]); - } - else { - sub_v3_v3v3(sv->dir_side[1], sv->v_side[1]->co, v->co); - } - } - - BM_elem_flag_disable(v, BM_ELEM_TAG); - BM_elem_flag_disable(v_prev, BM_ELEM_TAG); - - break; - } - l_a_ok_prev = (l_a != NULL); - l_b_ok_prev = (l_b != NULL); - - l_a_prev = l_a; - l_b_prev = l_b; - - if (l_a) { - l_a = get_next_loop(v, l_a, e_prev, e, vec_a); - } - else { - zero_v3(vec_a); - } - - if (l_b) { - l_b = get_next_loop(v, l_b, e_prev, e, vec_b); - } - else { - zero_v3(vec_b); - } - - if (l_a && l_b) { - /* pass */ - } - else { - if (l_a || l_b) { - /* find the opposite loop if it was missing previously */ - if (l_a == NULL && l_b && (l_b->radial_next != l_b)) { - l_a = l_b->radial_next; - } - else if (l_b == NULL && l_a && (l_a->radial_next != l_a)) { - l_b = l_a->radial_next; - } - } - else if (e->l != NULL) { - /* if there are non-contiguous faces, we can still recover - * the loops of the new edges faces */ - - /* note!, the behavior in this case means edges may move in opposite directions, - * this could be made to work more usefully. */ - - if (l_a_ok_prev) { - l_a = e->l; - l_b = (l_a->radial_next != l_a) ? l_a->radial_next : NULL; - } - else if (l_b_ok_prev) { - l_b = e->l; - l_a = (l_b->radial_next != l_b) ? l_b->radial_next : NULL; - } - } - - if (!l_a_ok_prev && l_a) { - get_next_loop(v, l_a, e, e_prev, vec_a); - } - if (!l_b_ok_prev && l_b) { - get_next_loop(v, l_b, e, e_prev, vec_b); - } - } - - BM_elem_flag_disable(v, BM_ELEM_TAG); - BM_elem_flag_disable(v_prev, BM_ELEM_TAG); - } while ((e != v_first->e) && (l_a || l_b)); - -#undef SV_FROM_VERT -#undef INDEX_UNSET -#undef INDEX_INVALID - - loop_nr++; - -#undef EDGESLIDE_VERT_IS_INNER - } - - /* EDBM_flag_disable_all(em, BM_ELEM_SELECT); */ - - BLI_assert(STACK_SIZE(sv_array) == sv_tot); - - 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_occlude_geometry = (v3d && TRANS_DATA_CONTAINER_FIRST_OK(t)->obedit->dt > OB_WIRE && - !XRAY_ENABLED(v3d)); - } - - calcEdgeSlide_mval_range(t, tc, sld, sv_table, loop_nr, mval, use_occlude_geometry, true); - - if (rv3d) { - calcEdgeSlide_even(t, tc, sld, mval); - } - - tc->custom.mode.data = sld; - - MEM_freeN(sv_table); - - return true; -} - -/** - * A simple version of #createEdgeSlideVerts_double_side - * Which assumes the longest unselected. - */ -static bool createEdgeSlideVerts_single_side(TransInfo *t, TransDataContainer *tc) -{ - BMEditMesh *em = BKE_editmesh_from_object(tc->obedit); - BMesh *bm = em->bm; - BMIter iter; - BMEdge *e; - 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 loop_nr; - bool use_occlude_geometry = false; - View3D *v3d = NULL; - RegionView3D *rv3d = NULL; - - if (t->spacetype == SPACE_VIEW3D) { - /* background mode support */ - v3d = t->sa ? t->sa->spacedata.first : NULL; - rv3d = t->ar ? t->ar->regiondata : NULL; - } - - sld->curr_sv_index = 0; - /* ensure valid selection */ - { - int i = 0, j = 0; - BMVert *v; - - 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; - } - } - } - - if (len_sq_max != -1.0f) { - j++; - } - } - BM_elem_index_set(v, i); /* set_inline */ - } - bm->elem_index_dirty &= ~BM_VERT; - - if (!j) { - MEM_freeN(sld); - 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__); - - { - int i = 0, j = 0; - BMVert *v; - - 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; - - for (int 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; - int j; - - 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 { - 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; - } - } - - 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); - } - } - } - } - } - - /* 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_occlude_geometry = (v3d && TRANS_DATA_CONTAINER_FIRST_OK(t)->obedit->dt > OB_WIRE && - !XRAY_ENABLED(v3d)); - } - - calcEdgeSlide_mval_range(t, tc, sld, sv_table, loop_nr, mval, use_occlude_geometry, false); - - if (rv3d) { - calcEdgeSlide_even(t, tc, sld, mval); - } - - tc->custom.mode.data = sld; - - MEM_freeN(sv_table); - - return true; -} - -void projectEdgeSlideData(TransInfo *t, bool is_final) -{ - FOREACH_TRANS_DATA_CONTAINER (t, tc) { - EdgeSlideData *sld = tc->custom.mode.data; - - if (sld == NULL) { - continue; - } - - trans_mesh_customdata_correction_apply(tc, is_final); - } -} - -void freeEdgeSlideVerts(TransInfo *UNUSED(t), - TransDataContainer *UNUSED(tc), - TransCustomData *custom_data) -{ - EdgeSlideData *sld = custom_data->data; - - if (sld == NULL) { - return; - } - - MEM_freeN(sld->sv); - MEM_freeN(sld); - - custom_data->data = NULL; -} - -static void initEdgeSlide_ex( - TransInfo *t, bool use_double_side, bool use_even, bool flipped, bool use_clamp) -{ - EdgeSlideData *sld; - bool ok = false; - - t->mode = TFM_EDGE_SLIDE; - t->transform = applyEdgeSlide; - t->handleEvent = handleEventEdgeSlide; - - { - EdgeSlideParams *slp = MEM_callocN(sizeof(*slp), __func__); - slp->use_even = use_even; - slp->flipped = flipped; - /* happens to be best for single-sided */ - if (use_double_side == false) { - slp->flipped = !flipped; - } - slp->perc = 0.0f; - - if (!use_clamp) { - t->flag |= T_ALT_TRANSFORM; - } - - t->custom.mode.data = slp; - t->custom.mode.use_free = true; - } - - if (use_double_side) { - FOREACH_TRANS_DATA_CONTAINER (t, tc) { - ok |= createEdgeSlideVerts_double_side(t, tc); - } - } - else { - FOREACH_TRANS_DATA_CONTAINER (t, tc) { - ok |= createEdgeSlideVerts_single_side(t, tc); - } - } - - if (!ok) { - t->state = TRANS_CANCEL; - return; - } - - FOREACH_TRANS_DATA_CONTAINER (t, tc) { - sld = tc->custom.mode.data; - if (!sld) { - continue; - } - tc->custom.mode.free_cb = freeEdgeSlideVerts; - } - - trans_mesh_customdata_correction_init(t); - - /* set custom point first if you want value to be initialized by init */ - calcEdgeSlideCustomPoints(t); - initMouseInputMode(t, &t->mouse, INPUT_CUSTOM_RATIO_FLIP); - - t->idx_max = 0; - t->num.idx_max = 0; - t->snap[0] = 0.0f; - t->snap[1] = 0.1f; - t->snap[2] = t->snap[1] * 0.1f; - - copy_v3_fl(t->num.val_inc, t->snap[1]); - t->num.unit_sys = t->scene->unit.system; - t->num.unit_type[0] = B_UNIT_NONE; - - t->flag |= T_NO_CONSTRAINT | T_NO_PROJECT; -} - -static void initEdgeSlide(TransInfo *t) -{ - initEdgeSlide_ex(t, true, false, false, true); -} - -static eRedrawFlag handleEventEdgeSlide(struct TransInfo *t, const struct wmEvent *event) -{ - if (t->mode == TFM_EDGE_SLIDE) { - EdgeSlideParams *slp = t->custom.mode.data; - - if (slp) { - switch (event->type) { - case EKEY: - if (event->val == KM_PRESS) { - slp->use_even = !slp->use_even; - calcEdgeSlideCustomPoints(t); - return TREDRAW_HARD; - } - break; - case FKEY: - if (event->val == KM_PRESS) { - slp->flipped = !slp->flipped; - 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: -#if 0 - switch (event->val) { - case TFM_MODAL_EDGESLIDE_DOWN: - sld->curr_sv_index = ((sld->curr_sv_index - 1) + sld->totsv) % sld->totsv; - return TREDRAW_HARD; - case TFM_MODAL_EDGESLIDE_UP: - sld->curr_sv_index = (sld->curr_sv_index + 1) % sld->totsv; - return TREDRAW_HARD; - } -#endif - break; - case MOUSEMOVE: - calcEdgeSlideCustomPoints(t); - break; - default: - break; - } - } - } - return TREDRAW_NOTHING; -} - -static void drawEdgeSlide(TransInfo *t) -{ - if ((t->mode == TFM_EDGE_SLIDE) && edgeSlideFirstGet(t)) { - const EdgeSlideParams *slp = t->custom.mode.data; - EdgeSlideData *sld = edgeSlideFirstGet(t); - const bool is_clamp = !(t->flag & T_ALT_TRANSFORM); - - /* Even mode */ - if ((slp->use_even == true) || (is_clamp == false)) { - const float line_size = UI_GetThemeValuef(TH_OUTLINE_WIDTH) + 0.5f; - - GPU_depth_test(false); - - GPU_blend(true); - GPU_blend_set_func_separate( - GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA); - - GPU_matrix_push(); - GPU_matrix_mul(TRANS_DATA_CONTAINER_FIRST_OK(t)->obedit->obmat); - - uint pos = GPU_vertformat_attr_add( - immVertexFormat(), "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT); - - immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR); - - if (slp->use_even == true) { - float co_a[3], co_b[3], co_mark[3]; - TransDataEdgeSlideVert *curr_sv = &sld->sv[sld->curr_sv_index]; - const float fac = (slp->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]); - - GPU_line_width(line_size); - immUniformThemeColorShadeAlpha(TH_EDGE_SELECT, 80, alpha_shade); - immBeginAtMost(GPU_PRIM_LINES, 4); - if (curr_sv->v_side[0]) { - immVertex3fv(pos, curr_sv->v_side[0]->co); - immVertex3fv(pos, curr_sv->v_co_orig); - } - if (curr_sv->v_side[1]) { - immVertex3fv(pos, curr_sv->v_side[1]->co); - immVertex3fv(pos, curr_sv->v_co_orig); - } - immEnd(); - - { - float *co_test = NULL; - if (slp->flipped) { - if (curr_sv->v_side[1]) { - co_test = curr_sv->v_side[1]->co; - } - } - else { - if (curr_sv->v_side[0]) { - co_test = curr_sv->v_side[0]->co; - } - } - - if (co_test != NULL) { - immUniformThemeColorShadeAlpha(TH_SELECT, -30, alpha_shade); - GPU_point_size(ctrl_size); - immBegin(GPU_PRIM_POINTS, 1); - immVertex3fv(pos, co_test); - immEnd(); - } - } - - immUniformThemeColorShadeAlpha(TH_SELECT, 255, alpha_shade); - GPU_point_size(guide_size); - immBegin(GPU_PRIM_POINTS, 1); - interp_line_v3_v3v3v3(co_mark, co_b, curr_sv->v_co_orig, co_a, fac); - immVertex3fv(pos, co_mark); - immEnd(); - } - else { - if (is_clamp == false) { - const int side_index = sld->curr_side_unclamp; - TransDataEdgeSlideVert *sv; - int i; - const int alpha_shade = -160; - - GPU_line_width(line_size); - immUniformThemeColorShadeAlpha(TH_EDGE_SELECT, 80, alpha_shade); - immBegin(GPU_PRIM_LINES, sld->totsv * 2); - - /* TODO(campbell): Loop over all verts */ - 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]); - } - - 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); - - immVertex3fv(pos, a); - immVertex3fv(pos, b); - } - immEnd(); - } - else { - BLI_assert(0); - } - } - - immUnbindProgram(); - - GPU_matrix_pop(); - - GPU_blend(false); - - GPU_depth_test(true); - } - } -} - -static void doEdgeSlide(TransInfo *t, float perc) -{ - EdgeSlideParams *slp = t->custom.mode.data; - EdgeSlideData *sld_active = edgeSlideFirstGet(t); - - slp->perc = perc; - - if (slp->use_even == false) { - 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); - FOREACH_TRANS_DATA_CONTAINER (t, tc) { - EdgeSlideData *sld = tc->custom.mode.data; - - if (sld == NULL) { - continue; - } - - TransDataEdgeSlideVert *sv = sld->sv; - for (int i = 0; i < sld->totsv; i++, sv++) { - madd_v3_v3v3fl(sv->v->co, sv->v_co_orig, sv->dir_side[side_index], perc_final); - } - sld->curr_side_unclamp = side_index; - } - } - else { - const float perc_init = fabsf(perc) * - ((sld_active->curr_side_unclamp == (perc < 0.0f)) ? 1 : -1); - const int side_index = sld_active->curr_side_unclamp; - FOREACH_TRANS_DATA_CONTAINER (t, tc) { - EdgeSlideData *sld = tc->custom.mode.data; - - if (sld == NULL) { - continue; - } - - TransDataEdgeSlideVert *sv = sld->sv; - for (int 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); - } - } - } - } - else { - /** - * Implementation note, even mode ignores the starting positions and uses - * only the 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_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_active->sv[sld_active->curr_sv_index]; - const float curr_length_perc = curr_sv->edge_len * - (((slp->flipped ? perc : -perc) + 1.0f) / 2.0f); - - float co_a[3]; - float co_b[3]; - - FOREACH_TRANS_DATA_CONTAINER (t, tc) { - EdgeSlideData *sld = tc->custom.mode.data; - - if (sld == NULL) { - continue; - } - - TransDataEdgeSlideVert *sv = sld->sv; - for (int i = 0; i < sld->totsv; i++, sv++) { - 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_side[0]); - add_v3_v3v3(co_b, sv->v_co_orig, sv->dir_side[1]); - - if (slp->flipped) { - interp_line_v3_v3v3v3(sv->v->co, co_b, sv->v_co_orig, co_a, fac); - } - else { - interp_line_v3_v3v3v3(sv->v->co, co_a, sv->v_co_orig, co_b, fac); - } - } - } - } - } -} - -static void applyEdgeSlide(TransInfo *t, const int UNUSED(mval[2])) -{ - char str[UI_MAX_DRAW_STR]; - size_t ofs = 0; - float final; - EdgeSlideParams *slp = t->custom.mode.data; - bool flipped = slp->flipped; - bool use_even = slp->use_even; - 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 */ - if (is_constrained) { - CLAMP(final, -1.0f, 1.0f); - } - - applyNumInput(&t->num, &final); - - t->values_final[0] = final; - - /* header string */ - ofs += BLI_strncpy_rlen(str + ofs, TIP_("Edge Slide: "), sizeof(str) - ofs); - if (hasNumInput(&t->num)) { - char c[NUM_STR_REP_LEN]; - outputNumInput(&(t->num), c, &t->scene->unit); - ofs += BLI_strncpy_rlen(str + ofs, &c[0], sizeof(str) - ofs); - } - else { - ofs += BLI_snprintf(str + ofs, sizeof(str) - ofs, "%.4f ", final); - } - ofs += BLI_snprintf( - str + ofs, sizeof(str) - ofs, TIP_("(E)ven: %s, "), WM_bool_as_string(use_even)); - if (use_even) { - ofs += BLI_snprintf( - str + ofs, sizeof(str) - ofs, TIP_("(F)lipped: %s, "), WM_bool_as_string(flipped)); - } - ofs += BLI_snprintf( - str + ofs, sizeof(str) - ofs, TIP_("Alt or (C)lamp: %s"), WM_bool_as_string(is_clamp)); - /* done with header string */ - - /* do stuff here */ - doEdgeSlide(t, final); - - recalcData(t); - - ED_area_status_text(t->sa, str); -} -/** \} */ - -/* -------------------------------------------------------------------- */ -/* Transform (Vert Slide) */ - -/** \name Transform Vert Slide - * \{ */ - -static void calcVertSlideCustomPoints(struct TransInfo *t) -{ - VertSlideParams *slp = t->custom.mode.data; - VertSlideData *sld = TRANS_DATA_CONTAINER_FIRST_OK(t)->custom.mode.data; - TransDataVertSlideVert *sv = &sld->sv[sld->curr_sv_index]; - - 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->mouse.imval[0] - co_orig_2d[0], t->mouse.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 (slp->flipped && slp->use_even) { - setCustomPoints(t, &t->mouse, mval_start, mval_end); - } - else { - setCustomPoints(t, &t->mouse, mval_end, mval_start); - } - - /* setCustomPoints isn't normally changing as the mouse moves, - * in this case apply mouse input immediately so we don't refresh - * with the value from the previous points */ - applyMouseInput(t, &t->mouse, t->mval, t->values); -} - -/** - * Run once when initializing vert slide to find the reference edge - */ -static void calcVertSlideMouseActiveVert(struct TransInfo *t, const int mval[2]) -{ - /* Active object may have no selected vertices. */ - VertSlideData *sld = TRANS_DATA_CONTAINER_FIRST_OK(t)->custom.mode.data; - float mval_fl[2] = {UNPACK2(mval)}; - TransDataVertSlideVert *sv; - - /* set the vertex to use as a reference for the mouse direction 'curr_sv_index' */ - float dist_sq = 0.0f; - float dist_min_sq = FLT_MAX; - int i; - - for (i = 0, sv = sld->sv; i < sld->totsv; i++, sv++) { - 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 = TRANS_DATA_CONTAINER_FIRST_OK(t)->custom.mode.data; - float imval_fl[2] = {UNPACK2(t->mouse.imval)}; - float mval_fl[2] = {UNPACK2(mval)}; - - float dir[3]; - TransDataVertSlideVert *sv; - int i; - - /* note: we could save a matrix-multiply for each vertex - * by finding the closest edge in local-space. - * However this skews the outcome with non-uniform-scale. */ - - /* 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); - normalize_v3(dir); - - for (i = 0, sv = sld->sv; i < sld->totsv; i++, sv++) { - if (sv->co_link_tot > 1) { - float dir_dot_best = -FLT_MAX; - int co_link_curr_best = -1; - int j; - - for (j = 0; j < sv->co_link_tot; j++) { - float tdir[3]; - float dir_dot; - - sub_v3_v3v3(tdir, sv->co_orig_3d, sv->co_link_orig_3d[j]); - mul_mat3_m4_v3(TRANS_DATA_CONTAINER_FIRST_OK(t)->obedit->obmat, tdir); - 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; - } - } - - if (co_link_curr_best != -1) { - sv->co_link_curr = co_link_curr_best; - } - } - } -} - -static bool createVertSlideVerts(TransInfo *t, TransDataContainer *tc) -{ - BMEditMesh *em = BKE_editmesh_from_object(tc->obedit); - BMesh *bm = em->bm; - BMIter iter; - BMIter eiter; - BMEdge *e; - BMVert *v; - TransDataVertSlideVert *sv_array; - VertSlideData *sld = MEM_callocN(sizeof(*sld), "sld"); - int j; - - sld->curr_sv_index = 0; - - j = 0; - BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) { - bool ok = false; - if (BM_elem_flag_test(v, BM_ELEM_SELECT) && v->e) { - BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) { - if (!BM_elem_flag_test(e, BM_ELEM_HIDDEN)) { - ok = true; - break; - } - } - } - - if (ok) { - BM_elem_flag_enable(v, BM_ELEM_TAG); - j += 1; - } - else { - BM_elem_flag_disable(v, BM_ELEM_TAG); - } - } - - if (!j) { - MEM_freeN(sld); - return false; - } - - sv_array = MEM_callocN(sizeof(TransDataVertSlideVert) * j, "sv_array"); - - j = 0; - BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) { - if (BM_elem_flag_test(v, BM_ELEM_TAG)) { - int k; - sv_array[j].v = v; - copy_v3_v3(sv_array[j].co_orig_3d, v->co); - - k = 0; - BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) { - if (!BM_elem_flag_test(e, BM_ELEM_HIDDEN)) { - k++; - } - } - - sv_array[j].co_link_orig_3d = MEM_mallocN(sizeof(*sv_array[j].co_link_orig_3d) * k, - __func__); - sv_array[j].co_link_tot = k; - - k = 0; - BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) { - 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); - k++; - } - } - j++; - } - } - - sld->sv = sv_array; - sld->totsv = j; - - tc->custom.mode.data = sld; - - /* 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, tc->obedit, sld->proj_mat); - } - } - - /* XXX, calc vert slide across all objects */ - if (tc == t->data_container) { - calcVertSlideMouseActiveVert(t, t->mval); - calcVertSlideMouseActiveEdges(t, t->mval); - } - - return true; -} - -void projectVertSlideData(TransInfo *t, bool is_final) -{ - FOREACH_TRANS_DATA_CONTAINER (t, tc) { - trans_mesh_customdata_correction_apply(tc, is_final); - } -} - -void freeVertSlideVerts(TransInfo *UNUSED(t), - TransDataContainer *UNUSED(tc), - TransCustomData *custom_data) -{ - VertSlideData *sld = custom_data->data; - - if (!sld) { - return; - } - - if (sld->totsv > 0) { - TransDataVertSlideVert *sv = sld->sv; - int i = 0; - for (i = 0; i < sld->totsv; i++, sv++) { - MEM_freeN(sv->co_link_orig_3d); - } - } - - MEM_freeN(sld->sv); - MEM_freeN(sld); - - custom_data->data = NULL; -} - -static void initVertSlide_ex(TransInfo *t, bool use_even, bool flipped, bool use_clamp) -{ - - t->mode = TFM_VERT_SLIDE; - t->transform = applyVertSlide; - t->handleEvent = handleEventVertSlide; - - { - VertSlideParams *slp = MEM_callocN(sizeof(*slp), __func__); - slp->use_even = use_even; - slp->flipped = flipped; - slp->perc = 0.0f; - - if (!use_clamp) { - t->flag |= T_ALT_TRANSFORM; - } - - t->custom.mode.data = slp; - t->custom.mode.use_free = true; - } - - bool ok = false; - FOREACH_TRANS_DATA_CONTAINER (t, tc) { - ok |= createVertSlideVerts(t, tc); - VertSlideData *sld = tc->custom.mode.data; - if (sld) { - tc->custom.mode.free_cb = freeVertSlideVerts; - } - } - - if (ok == false) { - t->state = TRANS_CANCEL; - return; - } - - trans_mesh_customdata_correction_init(t); - - /* set custom point first if you want value to be initialized by init */ - calcVertSlideCustomPoints(t); - initMouseInputMode(t, &t->mouse, INPUT_CUSTOM_RATIO); - - t->idx_max = 0; - t->num.idx_max = 0; - t->snap[0] = 0.0f; - t->snap[1] = 0.1f; - t->snap[2] = t->snap[1] * 0.1f; - - copy_v3_fl(t->num.val_inc, t->snap[1]); - t->num.unit_sys = t->scene->unit.system; - t->num.unit_type[0] = B_UNIT_NONE; - - t->flag |= T_NO_CONSTRAINT | T_NO_PROJECT; -} - -static void initVertSlide(TransInfo *t) -{ - initVertSlide_ex(t, false, false, true); -} - -static eRedrawFlag handleEventVertSlide(struct TransInfo *t, const struct wmEvent *event) -{ - if (t->mode == TFM_VERT_SLIDE) { - VertSlideParams *slp = t->custom.mode.data; - - if (slp) { - switch (event->type) { - case EKEY: - if (event->val == KM_PRESS) { - slp->use_even = !slp->use_even; - if (slp->flipped) { - calcVertSlideCustomPoints(t); - } - return TREDRAW_HARD; - } - break; - case FKEY: - if (event->val == KM_PRESS) { - slp->flipped = !slp->flipped; - calcVertSlideCustomPoints(t); - return TREDRAW_HARD; - } - break; - case CKEY: - /* use like a modifier key */ - if (event->val == KM_PRESS) { - t->flag ^= T_ALT_TRANSFORM; - calcVertSlideCustomPoints(t); - 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: { - /* don't recalculate the best edge */ - const bool is_clamp = !(t->flag & T_ALT_TRANSFORM); - if (is_clamp) { - calcVertSlideMouseActiveEdges(t, event->mval); - } - calcVertSlideCustomPoints(t); - break; - } - default: - break; - } - } - } - return TREDRAW_NOTHING; -} - -static void drawVertSlide(TransInfo *t) -{ - if ((t->mode == TFM_VERT_SLIDE) && TRANS_DATA_CONTAINER_FIRST_OK(t)->custom.mode.data) { - const VertSlideParams *slp = t->custom.mode.data; - VertSlideData *sld = TRANS_DATA_CONTAINER_FIRST_OK(t)->custom.mode.data; - const bool is_clamp = !(t->flag & T_ALT_TRANSFORM); - - /* Non-Prop mode */ - { - 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; - int i; - - GPU_depth_test(false); - - GPU_blend(true); - GPU_blend_set_func_separate( - GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA); - - GPU_matrix_push(); - GPU_matrix_mul(TRANS_DATA_CONTAINER_FIRST_OK(t)->obedit->obmat); - - GPU_line_width(line_size); - - const uint shdr_pos = GPU_vertformat_attr_add( - immVertexFormat(), "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT); - - immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR); - immUniformThemeColorShadeAlpha(TH_EDGE_SELECT, 80, alpha_shade); - - immBegin(GPU_PRIM_LINES, sld->totsv * 2); - if (is_clamp) { - sv = sld->sv; - for (i = 0; i < sld->totsv; i++, sv++) { - immVertex3fv(shdr_pos, sv->co_orig_3d); - immVertex3fv(shdr_pos, sv->co_link_orig_3d[sv->co_link_curr]); - } - } - else { - sv = sld->sv; - for (i = 0; i < sld->totsv; i++, sv++) { - float a[3], b[3]; - sub_v3_v3v3(a, sv->co_link_orig_3d[sv->co_link_curr], sv->co_orig_3d); - mul_v3_fl(a, 100.0f); - negate_v3_v3(b, a); - add_v3_v3(a, sv->co_orig_3d); - add_v3_v3(b, sv->co_orig_3d); - - immVertex3fv(shdr_pos, a); - immVertex3fv(shdr_pos, b); - } - } - immEnd(); - - GPU_point_size(ctrl_size); - - immBegin(GPU_PRIM_POINTS, 1); - immVertex3fv(shdr_pos, - (slp->flipped && slp->use_even) ? - curr_sv->co_link_orig_3d[curr_sv->co_link_curr] : - curr_sv->co_orig_3d); - immEnd(); - - immUnbindProgram(); - - /* direction from active vertex! */ - if ((t->mval[0] != t->mouse.imval[0]) || (t->mval[1] != t->mouse.imval[1])) { - float zfac; - float mval_ofs[2]; - float co_orig_3d[3]; - float co_dest_3d[3]; - - mval_ofs[0] = t->mval[0] - t->mouse.imval[0]; - mval_ofs[1] = t->mval[1] - t->mouse.imval[1]; - - mul_v3_m4v3( - co_orig_3d, TRANS_DATA_CONTAINER_FIRST_OK(t)->obedit->obmat, curr_sv->co_orig_3d); - zfac = ED_view3d_calc_zfac(t->ar->regiondata, co_orig_3d, NULL); - - ED_view3d_win_to_delta(t->ar, mval_ofs, co_dest_3d, zfac); - - invert_m4_m4(TRANS_DATA_CONTAINER_FIRST_OK(t)->obedit->imat, - TRANS_DATA_CONTAINER_FIRST_OK(t)->obedit->obmat); - mul_mat3_m4_v3(TRANS_DATA_CONTAINER_FIRST_OK(t)->obedit->imat, co_dest_3d); - - add_v3_v3(co_dest_3d, curr_sv->co_orig_3d); - - GPU_line_width(1.0f); - - immBindBuiltinProgram(GPU_SHADER_3D_LINE_DASHED_UNIFORM_COLOR); - - float viewport_size[4]; - GPU_viewport_size_get_f(viewport_size); - immUniform2f("viewport_size", viewport_size[2], viewport_size[3]); - - immUniform1i("colors_len", 0); /* "simple" mode */ - immUniformColor4f(1.0f, 1.0f, 1.0f, 1.0f); - immUniform1f("dash_width", 6.0f); - immUniform1f("dash_factor", 0.5f); - - immBegin(GPU_PRIM_LINES, 2); - immVertex3fv(shdr_pos, curr_sv->co_orig_3d); - immVertex3fv(shdr_pos, co_dest_3d); - immEnd(); - - immUnbindProgram(); - } - - GPU_matrix_pop(); - - GPU_depth_test(true); - } - } -} - -static void doVertSlide(TransInfo *t, float perc) -{ - VertSlideParams *slp = t->custom.mode.data; - - slp->perc = perc; - - FOREACH_TRANS_DATA_CONTAINER (t, tc) { - VertSlideData *sld = tc->custom.mode.data; - TransDataVertSlideVert *svlist = sld->sv, *sv; - int i; - - sv = svlist; - - if (slp->use_even == false) { - for (i = 0; i < sld->totsv; i++, sv++) { - interp_v3_v3v3(sv->v->co, sv->co_orig_3d, sv->co_link_orig_3d[sv->co_link_curr], perc); - } - } - else { - TransDataVertSlideVert *sv_curr = &sld->sv[sld->curr_sv_index]; - const float edge_len_curr = len_v3v3(sv_curr->co_orig_3d, - sv_curr->co_link_orig_3d[sv_curr->co_link_curr]); - const float tperc = perc * edge_len_curr; - - for (i = 0; i < sld->totsv; i++, sv++) { - float edge_len; - float dir[3]; - - sub_v3_v3v3(dir, sv->co_link_orig_3d[sv->co_link_curr], sv->co_orig_3d); - edge_len = normalize_v3(dir); - - if (edge_len > FLT_EPSILON) { - if (slp->flipped) { - madd_v3_v3v3fl(sv->v->co, sv->co_link_orig_3d[sv->co_link_curr], dir, -tperc); - } - else { - madd_v3_v3v3fl(sv->v->co, sv->co_orig_3d, dir, tperc); - } - } - else { - copy_v3_v3(sv->v->co, sv->co_orig_3d); - } - } - } - } -} - -static void applyVertSlide(TransInfo *t, const int UNUSED(mval[2])) -{ - char str[UI_MAX_DRAW_STR]; - size_t ofs = 0; - float final; - VertSlideParams *slp = t->custom.mode.data; - const bool flipped = slp->flipped; - const bool use_even = slp->use_even; - 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 */ - if (is_constrained) { - CLAMP(final, 0.0f, 1.0f); - } - - applyNumInput(&t->num, &final); - - t->values_final[0] = final; - - /* header string */ - ofs += BLI_strncpy_rlen(str + ofs, TIP_("Vert Slide: "), sizeof(str) - ofs); - if (hasNumInput(&t->num)) { - char c[NUM_STR_REP_LEN]; - outputNumInput(&(t->num), c, &t->scene->unit); - ofs += BLI_strncpy_rlen(str + ofs, &c[0], sizeof(str) - ofs); - } - else { - ofs += BLI_snprintf(str + ofs, sizeof(str) - ofs, "%.4f ", final); - } - ofs += BLI_snprintf( - str + ofs, sizeof(str) - ofs, TIP_("(E)ven: %s, "), WM_bool_as_string(use_even)); - if (use_even) { - ofs += BLI_snprintf( - str + ofs, sizeof(str) - ofs, TIP_("(F)lipped: %s, "), WM_bool_as_string(flipped)); - } - ofs += BLI_snprintf( - str + ofs, sizeof(str) - ofs, TIP_("Alt or (C)lamp: %s"), WM_bool_as_string(is_clamp)); - /* done with header string */ - - /* do stuff here */ - doVertSlide(t, final); - - recalcData(t); - - ED_area_status_text(t->sa, str); -} -/** \} */ - -/* -------------------------------------------------------------------- */ -/* Transform (EditBone Roll) */ - -/** \name Transform EditBone Roll - * \{ */ - -static void initBoneRoll(TransInfo *t) -{ - t->mode = TFM_BONE_ROLL; - t->transform = applyBoneRoll; - - initMouseInputMode(t, &t->mouse, INPUT_ANGLE); - - t->idx_max = 0; - t->num.idx_max = 0; - t->snap[0] = 0.0f; - t->snap[1] = DEG2RAD(5.0); - t->snap[2] = DEG2RAD(1.0); - - copy_v3_fl(t->num.val_inc, t->snap[1]); - t->num.unit_sys = t->scene->unit.system; - t->num.unit_use_radians = (t->scene->unit.system_rotation == USER_UNIT_ROT_RADIANS); - t->num.unit_type[0] = B_UNIT_ROTATION; - - t->flag |= T_NO_CONSTRAINT | T_NO_PROJECT; -} - -static void applyBoneRoll(TransInfo *t, const int UNUSED(mval[2])) -{ - int i; - char str[UI_MAX_DRAW_STR]; - - float final; - - final = t->values[0]; - - snapGridIncrement(t, &final); - - applyNumInput(&t->num, &final); - - t->values_final[0] = final; - - if (hasNumInput(&t->num)) { - char c[NUM_STR_REP_LEN]; - - outputNumInput(&(t->num), c, &t->scene->unit); - - BLI_snprintf(str, sizeof(str), TIP_("Roll: %s"), &c[0]); - } - else { - BLI_snprintf(str, sizeof(str), TIP_("Roll: %.2f"), RAD2DEGF(final)); - } - - /* set roll values */ - FOREACH_TRANS_DATA_CONTAINER (t, tc) { - TransData *td = tc->data; - for (i = 0; i < tc->data_len; i++, td++) { - if (td->flag & TD_NOACTION) { - break; - } - - if (td->flag & TD_SKIP) { - continue; - } - - *(td->val) = td->ival - final; - } - } - - recalcData(t); - - ED_area_status_text(t->sa, str); -} -/** \} */ - -/* -------------------------------------------------------------------- */ -/* Transform (Bake-Time) */ - -/** \name Transform Bake-Time - * \{ */ - -static void initBakeTime(TransInfo *t) -{ - t->transform = applyBakeTime; - initMouseInputMode(t, &t->mouse, INPUT_NONE); - - t->idx_max = 0; - t->num.idx_max = 0; - t->snap[0] = 0.0f; - t->snap[1] = 1.0f; - t->snap[2] = t->snap[1] * 0.1f; - - copy_v3_fl(t->num.val_inc, t->snap[1]); - t->num.unit_sys = t->scene->unit.system; - t->num.unit_type[0] = B_UNIT_NONE; /* Don't think this uses units? */ -} - -static void applyBakeTime(TransInfo *t, const int mval[2]) -{ - float time; - int i; - char str[UI_MAX_DRAW_STR]; - - float fac = 0.1f; - - /* XXX, disable precision for now, - * this isn't even accessible by the user */ -#if 0 - if (t->mouse.precision) { - /* calculate ratio for shiftkey pos, and for total, and blend these for precision */ - time = (float)(t->center2d[0] - t->mouse.precision_mval[0]) * fac; - time += 0.1f * ((float)(t->center2d[0] * fac - mval[0]) - time); - } - else -#endif - { - time = (float)(t->center2d[0] - mval[0]) * fac; - } - - snapGridIncrement(t, &time); - - applyNumInput(&t->num, &time); - - /* header print for NumInput */ - if (hasNumInput(&t->num)) { - char c[NUM_STR_REP_LEN]; - - outputNumInput(&(t->num), c, &t->scene->unit); - - if (time >= 0.0f) { - BLI_snprintf(str, sizeof(str), TIP_("Time: +%s %s"), c, t->proptext); - } - else { - BLI_snprintf(str, sizeof(str), TIP_("Time: %s %s"), c, t->proptext); - } - } - else { - /* default header print */ - if (time >= 0.0f) { - BLI_snprintf(str, sizeof(str), TIP_("Time: +%.3f %s"), time, t->proptext); - } - else { - BLI_snprintf(str, sizeof(str), TIP_("Time: %.3f %s"), time, t->proptext); - } - } - - FOREACH_TRANS_DATA_CONTAINER (t, tc) { - TransData *td = tc->data; - for (i = 0; i < tc->data_len; i++, td++) { - if (td->flag & TD_NOACTION) { - break; - } - - if (td->flag & TD_SKIP) { - continue; - } - - if (td->val) { - *td->val = td->ival + time * td->factor; - if (td->ext->size && *td->val < *td->ext->size) { - *td->val = *td->ext->size; - } - if (td->ext->quat && *td->val > *td->ext->quat) { - *td->val = *td->ext->quat; - } - } - } - } - - recalcData(t); - - ED_area_status_text(t->sa, str); -} -/** \} */ - -/* -------------------------------------------------------------------- */ -/* Transform (Mirror) */ - -/** \name Transform Mirror - * \{ */ - -static void initMirror(TransInfo *t) -{ - t->transform = applyMirror; - initMouseInputMode(t, &t->mouse, INPUT_NONE); - - t->flag |= T_NULL_ONE; - if ((t->flag & T_EDIT) == 0) { - t->flag |= T_NO_ZERO; - } -} - -static void applyMirror(TransInfo *t, const int UNUSED(mval[2])) -{ - float size[3], mat[3][3]; - int i; - char str[UI_MAX_DRAW_STR]; - copy_v3_v3(t->values_final, t->values); - - /* - * OPTIMIZATION: - * This still recalcs transformation on mouse move - * while it should only recalc on constraint change - * */ - - /* if an axis has been selected */ - if (t->con.mode & CON_APPLY) { - size[0] = size[1] = size[2] = -1; - - size_to_mat3(mat, size); - - if (t->con.applySize) { - t->con.applySize(t, NULL, NULL, mat); - } - - BLI_snprintf(str, sizeof(str), TIP_("Mirror%s"), t->con.text); - - FOREACH_TRANS_DATA_CONTAINER (t, tc) { - TransData *td = tc->data; - for (i = 0; i < tc->data_len; i++, td++) { - if (td->flag & TD_NOACTION) { - break; - } - - if (td->flag & TD_SKIP) { - continue; - } - - ElementResize(t, tc, td, mat); - } - } - - recalcData(t); - - ED_area_status_text(t->sa, str); - } - else { - size[0] = size[1] = size[2] = 1; - - size_to_mat3(mat, size); - - FOREACH_TRANS_DATA_CONTAINER (t, tc) { - TransData *td = tc->data; - for (i = 0; i < tc->data_len; i++, td++) { - if (td->flag & TD_NOACTION) { - break; - } - - if (td->flag & TD_SKIP) { - continue; - } - - ElementResize(t, tc, td, mat); - } - } - - recalcData(t); - - if (t->flag & T_2D_EDIT) { - ED_area_status_text(t->sa, TIP_("Select a mirror axis (X, Y)")); - } - else { - ED_area_status_text(t->sa, TIP_("Select a mirror axis (X, Y, Z)")); - } - } -} -/** \} */ - -/* -------------------------------------------------------------------- */ -/* Transform (Align) */ - -/** \name Transform Align - * \{ */ - -static void initAlign(TransInfo *t) -{ - t->flag |= T_NO_CONSTRAINT; - - t->transform = applyAlign; - - initMouseInputMode(t, &t->mouse, INPUT_NONE); -} - -static void applyAlign(TransInfo *t, const int UNUSED(mval[2])) -{ - float center[3]; - int i; - - FOREACH_TRANS_DATA_CONTAINER (t, tc) { - /* saving original center */ - copy_v3_v3(center, tc->center_local); - TransData *td = tc->data; - for (i = 0; i < tc->data_len; i++, td++) { - float mat[3][3], invmat[3][3]; - - if (td->flag & TD_NOACTION) { - break; - } - - if (td->flag & TD_SKIP) { - continue; - } - - /* around local centers */ - if (t->flag & (T_OBJECT | T_POSE)) { - copy_v3_v3(tc->center_local, td->center); - } - else { - if (t->settings->selectmode & SCE_SELECT_FACE) { - copy_v3_v3(tc->center_local, td->center); - } - } - - invert_m3_m3(invmat, td->axismtx); - - mul_m3_m3m3(mat, t->spacemtx, invmat); - - ElementRotation(t, tc, td, mat, t->around); - } - /* restoring original center */ - copy_v3_v3(tc->center_local, center); - } - - recalcData(t); - - ED_area_status_text(t->sa, TIP_("Align")); -} -/** \} */ - -/* -------------------------------------------------------------------- */ -/* Transform (Sequencer Slide) */ - -/** \name Transform Sequencer Slide - * \{ */ - -static void initSeqSlide(TransInfo *t) -{ - t->transform = applySeqSlide; - - initMouseInputMode(t, &t->mouse, INPUT_VECTOR); - - t->idx_max = 1; - t->num.flag = 0; - t->num.idx_max = t->idx_max; - - t->snap[0] = 0.0f; - 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]); - t->num.unit_sys = t->scene->unit.system; - /* Would be nice to have a time handling in units as well - * (supporting frames in addition to "natural" time...). */ - t->num.unit_type[0] = B_UNIT_NONE; - t->num.unit_type[1] = B_UNIT_NONE; -} - -static void headerSeqSlide(TransInfo *t, const float val[2], char str[UI_MAX_DRAW_STR]) -{ - char tvec[NUM_STR_REP_LEN * 3]; - size_t ofs = 0; - - if (hasNumInput(&t->num)) { - outputNumInput(&(t->num), tvec, &t->scene->unit); - } - else { - BLI_snprintf(&tvec[0], NUM_STR_REP_LEN, "%.0f, %.0f", val[0], val[1]); - } - - ofs += BLI_snprintf( - str + ofs, UI_MAX_DRAW_STR - ofs, TIP_("Sequence Slide: %s%s, ("), &tvec[0], t->con.text); - - if (t->keymap) { - wmKeyMapItem *kmi = WM_modalkeymap_find_propvalue(t->keymap, TFM_MODAL_TRANSLATE); - if (kmi) { - ofs += WM_keymap_item_to_string(kmi, false, str + ofs, UI_MAX_DRAW_STR - ofs); - } - } - ofs += BLI_snprintf(str + ofs, - UI_MAX_DRAW_STR - ofs, - TIP_(" or Alt) Expand to fit %s"), - WM_bool_as_string((t->flag & T_ALT_TRANSFORM) != 0)); -} - -static void applySeqSlideValue(TransInfo *t, const float val[2]) -{ - int i; - - FOREACH_TRANS_DATA_CONTAINER (t, tc) { - TransData *td = tc->data; - for (i = 0; i < tc->data_len; i++, td++) { - if (td->flag & TD_NOACTION) { - break; - } - - if (td->flag & TD_SKIP) { - continue; - } - - madd_v2_v2v2fl(td->loc, td->iloc, val, td->factor); - } - } -} - -static void applySeqSlide(TransInfo *t, const int mval[2]) -{ - char str[UI_MAX_DRAW_STR]; - - snapSequenceBounds(t, mval); - - if (t->con.mode & CON_APPLY) { - float pvec[3] = {0.0f, 0.0f, 0.0f}; - float tvec[3]; - t->con.applyVec(t, NULL, NULL, t->values, tvec, pvec); - copy_v3_v3(t->values_final, tvec); - } - else { - // snapGridIncrement(t, t->values); - applyNumInput(&t->num, t->values); - copy_v3_v3(t->values_final, t->values); - } - - t->values_final[0] = floorf(t->values_final[0] + 0.5f); - t->values_final[1] = floorf(t->values_final[1] + 0.5f); - - headerSeqSlide(t, t->values_final, str); - applySeqSlideValue(t, t->values_final); - - recalcData(t); - - ED_area_status_text(t->sa, str); -} -/** \} */ - -/* -------------------------------------------------------------------- */ -/* Animation Editors - Transform Utils - * - * Special Helpers for Various Settings - */ - -/** \name Animation Editor Utils - * \{ */ - -/* This function returns the snapping 'mode' for Animation Editors only - * We cannot use the standard snapping due to NLA-strip scaling complexities. - */ -// XXX these modifier checks should be keymappable -static short getAnimEdit_SnapMode(TransInfo *t) -{ - short autosnap = SACTSNAP_OFF; - - if (t->spacetype == SPACE_ACTION) { - SpaceAction *saction = (SpaceAction *)t->sa->spacedata.first; - - if (saction) { - autosnap = saction->autosnap; - } - } - else if (t->spacetype == SPACE_GRAPH) { - SpaceGraph *sipo = (SpaceGraph *)t->sa->spacedata.first; - - if (sipo) { - autosnap = sipo->autosnap; - } - } - else if (t->spacetype == SPACE_NLA) { - SpaceNla *snla = (SpaceNla *)t->sa->spacedata.first; - - if (snla) { - autosnap = snla->autosnap; - } - } - else { - autosnap = SACTSNAP_OFF; - } - - /* toggle autosnap on/off - * - when toggling on, prefer nearest frame over 1.0 frame increments - */ - if (t->modifiers & MOD_SNAP_INVERT) { - if (autosnap) { - autosnap = SACTSNAP_OFF; - } - else { - autosnap = SACTSNAP_FRAME; - } - } - - return autosnap; -} - -/* This function is used by Animation Editor specific transform functions to do - * the Snap Keyframe to Nearest Frame/Marker - */ -static void doAnimEdit_SnapFrame( - TransInfo *t, TransData *td, TransData2D *td2d, AnimData *adt, short autosnap) -{ - if (ELEM(autosnap, SACTSNAP_FRAME, SACTSNAP_SECOND, SACTSNAP_MARKER)) { - float val; - - /* convert frame to nla-action time (if needed) */ - if (adt) { - val = BKE_nla_tweakedit_remap(adt, *(td->val), NLATIME_CONVERT_MAP); - } - else { - val = *(td->val); - } - - snapFrameTransform(t, autosnap, true, val, &val); - - /* convert frame out of nla-action time */ - if (adt) { - *(td->val) = BKE_nla_tweakedit_remap(adt, val, NLATIME_CONVERT_UNMAP); - } - else { - *(td->val) = val; - } - } - - /* If the handles are to be moved too - * (as side-effect of keyframes moving, to keep the general effect) - * offset them by the same amount so that the general angles are maintained - * (i.e. won't change while handles are free-to-roam and keyframes are snap-locked). - */ - if ((td->flag & TD_MOVEHANDLE1) && td2d->h1) { - td2d->h1[0] = td2d->ih1[0] + *td->val - td->ival; - } - if ((td->flag & TD_MOVEHANDLE2) && td2d->h2) { - td2d->h2[0] = td2d->ih2[0] + *td->val - td->ival; - } -} -/** \} */ - -/* -------------------------------------------------------------------- */ -/* Transform (Animation Translation) */ - -/** \name Transform Animation Translation - * \{ */ - -static void initTimeTranslate(TransInfo *t) -{ - /* this tool is only really available in the Action Editor... */ - if (!ELEM(t->spacetype, SPACE_ACTION, SPACE_SEQ)) { - t->state = TRANS_CANCEL; - } - - t->mode = TFM_TIME_TRANSLATE; - t->transform = applyTimeTranslate; - - initMouseInputMode(t, &t->mouse, INPUT_NONE); - - /* num-input has max of (n-1) */ - t->idx_max = 0; - t->num.flag = 0; - t->num.idx_max = t->idx_max; - - /* initialize snap like for everything else */ - t->snap[0] = 0.0f; - t->snap[1] = t->snap[2] = 1.0f; - - copy_v3_fl(t->num.val_inc, t->snap[1]); - t->num.unit_sys = t->scene->unit.system; - /* No time unit supporting frames currently... */ - t->num.unit_type[0] = B_UNIT_NONE; -} - -static void headerTimeTranslate(TransInfo *t, char str[UI_MAX_DRAW_STR]) -{ - 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)) { - outputNumInput(&(t->num), tvec, &t->scene->unit); - } - else { - const short autosnap = getAnimEdit_SnapMode(t); - float val = t->values_final[0]; - - float snap_val; - snapFrameTransform(t, autosnap, false, val, &snap_val); - - if (autosnap == SACTSNAP_FRAME) { - BLI_snprintf(&tvec[0], NUM_STR_REP_LEN, "%.2f (%.4f)", snap_val, val); - } - else if (autosnap == SACTSNAP_SECOND) { - BLI_snprintf(&tvec[0], NUM_STR_REP_LEN, "%.2f sec (%.4f)", snap_val, val); - } - else if (autosnap == SACTSNAP_TSTEP) { - BLI_snprintf(&tvec[0], NUM_STR_REP_LEN, "%.4f sec", snap_val); - } - else { - BLI_snprintf(&tvec[0], NUM_STR_REP_LEN, "%.4f", snap_val); - } - } - - ofs += BLI_snprintf(str, UI_MAX_DRAW_STR, TIP_("DeltaX: %s"), &tvec[0]); - - if (t->flag & T_PROP_EDIT_ALL) { - ofs += BLI_snprintf( - str + ofs, UI_MAX_DRAW_STR - ofs, TIP_(" Proportional size: %.2f"), t->prop_size); - } -} - -static void applyTimeTranslateValue(TransInfo *t, float value) -{ - Scene *scene = t->scene; - int i; - - const short autosnap = getAnimEdit_SnapMode(t); - const double secf = FPS; - - float deltax, val /* , valprev */; - - FOREACH_TRANS_DATA_CONTAINER (t, tc) { - TransData *td = tc->data; - TransData2D *td2d = tc->data_2d; - /* It doesn't matter whether we apply to t->data or - * t->data2d, but t->data2d is more convenient. */ - for (i = 0; i < tc->data_len; i++, td++, td2d++) { - /* It is assumed that td->extra is a pointer to the AnimData, - * whose active action is where this keyframe comes from. - * (this is only valid when not in NLA) - * (also: masks and gpencil dont have animadata) - */ - AnimData *adt = (t->spacetype != SPACE_NLA) ? td->extra : NULL; - - /* valprev = *td->val; */ /* UNUSED */ - - /* check if any need to apply nla-mapping */ - if (adt && (t->spacetype != SPACE_SEQ)) { - deltax = value; - - if (autosnap == SACTSNAP_TSTEP) { - deltax = (float)(floor(((double)deltax / secf) + 0.5) * secf); - } - else if (autosnap == SACTSNAP_STEP) { - deltax = floorf(deltax + 0.5f); - } - - val = BKE_nla_tweakedit_remap(adt, td->ival, NLATIME_CONVERT_MAP); - val += deltax * td->factor; - *(td->val) = BKE_nla_tweakedit_remap(adt, val, NLATIME_CONVERT_UNMAP); - } - else { - deltax = val = t->values_final[0]; - - if (autosnap == SACTSNAP_TSTEP) { - val = (float)(floor(((double)deltax / secf) + 0.5) * secf); - } - else if (autosnap == SACTSNAP_STEP) { - val = floorf(val + 0.5f); - } - - *(td->val) = td->ival + val * td->factor; - } - - /* apply nearest snapping */ - doAnimEdit_SnapFrame(t, td, td2d, adt, autosnap); - } - } -} - -static void applyTimeTranslate(TransInfo *t, const int mval[2]) -{ - View2D *v2d = (View2D *)t->view; - char str[UI_MAX_DRAW_STR]; - - /* calculate translation amount from mouse movement - in 'time-grid space' */ - 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->mouse.imval[0], t->mouse.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]; - } - - /* handle numeric-input stuff */ - t->vec[0] = t->values[0]; - applyNumInput(&t->num, &t->vec[0]); - t->values_final[0] = t->vec[0]; - headerTimeTranslate(t, str); - - applyTimeTranslateValue(t, t->values_final[0]); - - recalcData(t); - - ED_area_status_text(t->sa, str); -} -/** \} */ - -/* -------------------------------------------------------------------- */ -/* Transform (Animation Time Slide) */ - -/** \name Transform Animation Time Slide - * \{ */ - -static void initTimeSlide(TransInfo *t) -{ - /* this tool is only really available in the Action Editor... */ - if (t->spacetype == SPACE_ACTION) { - SpaceAction *saction = (SpaceAction *)t->sa->spacedata.first; - - /* set flag for drawing stuff */ - saction->flag |= SACTION_MOVING; - } - else { - t->state = TRANS_CANCEL; - } - - t->mode = TFM_TIME_SLIDE; - t->transform = applyTimeSlide; - - initMouseInputMode(t, &t->mouse, INPUT_NONE); - - { - Scene *scene = t->scene; - float *range; - t->custom.mode.data = range = MEM_mallocN(sizeof(float[2]), "TimeSlide Min/Max"); - t->custom.mode.use_free = true; - - float min = 999999999.0f, max = -999999999.0f; - int i; - FOREACH_TRANS_DATA_CONTAINER (t, tc) { - TransData *td = tc->data; - for (i = 0; i < tc->data_len; i++, td++) { - AnimData *adt = (t->spacetype != SPACE_NLA) ? td->extra : NULL; - float val = *(td->val); - - /* strip/action time to global (mapped) time */ - if (adt) { - val = BKE_nla_tweakedit_remap(adt, val, NLATIME_CONVERT_MAP); - } - - if (min > val) { - min = val; - } - if (max < val) { - max = val; - } - } - } - - if (min == max) { - /* just use the current frame ranges */ - min = (float)PSFRA; - max = (float)PEFRA; - } - - range[0] = min; - range[1] = max; - } - - /* num-input has max of (n-1) */ - t->idx_max = 0; - t->num.flag = 0; - t->num.idx_max = t->idx_max; - - /* initialize snap like for everything else */ - t->snap[0] = 0.0f; - t->snap[1] = t->snap[2] = 1.0f; - - copy_v3_fl(t->num.val_inc, t->snap[1]); - t->num.unit_sys = t->scene->unit.system; - /* No time unit supporting frames currently... */ - t->num.unit_type[0] = B_UNIT_NONE; -} - -static void headerTimeSlide(TransInfo *t, const float sval, char str[UI_MAX_DRAW_STR]) -{ - char tvec[NUM_STR_REP_LEN * 3]; - - if (hasNumInput(&t->num)) { - outputNumInput(&(t->num), tvec, &t->scene->unit); - } - else { - const float *range = t->custom.mode.data; - float minx = range[0]; - float maxx = range[1]; - float cval = t->values_final[0]; - float val; - - val = 2.0f * (cval - sval) / (maxx - minx); - CLAMP(val, -1.0f, 1.0f); - - BLI_snprintf(&tvec[0], NUM_STR_REP_LEN, "%.4f", val); - } - - BLI_snprintf(str, UI_MAX_DRAW_STR, TIP_("TimeSlide: %s"), &tvec[0]); -} - -static void applyTimeSlideValue(TransInfo *t, float sval, float cval) -{ - int i; - const float *range = t->custom.mode.data; - float minx = range[0]; - float maxx = range[1]; - - /* set value for drawing black line */ - if (t->spacetype == SPACE_ACTION) { - SpaceAction *saction = (SpaceAction *)t->sa->spacedata.first; - saction->timeslide = cval; - } - - /* It doesn't matter whether we apply to t->data or - * t->data2d, but t->data2d is more convenient. */ - FOREACH_TRANS_DATA_CONTAINER (t, tc) { - TransData *td = tc->data; - for (i = 0; i < tc->data_len; i++, td++) { - /* it is assumed that td->extra is a pointer to the AnimData, - * whose active action is where this keyframe comes from - * (this is only valid when not in NLA) - */ - AnimData *adt = (t->spacetype != SPACE_NLA) ? td->extra : NULL; - - /* only apply to data if in range */ - if ((sval > minx) && (sval < maxx)) { - float cvalc = CLAMPIS(cval, minx, maxx); - float ival = td->ival; - float timefac; - - /* NLA mapping magic here works as follows: - * - "ival" goes from strip time to global time - * - calculation is performed into td->val in global time - * (since sval and min/max are all in global time) - * - "td->val" then gets put back into strip time - */ - if (adt) { - /* strip to global */ - ival = BKE_nla_tweakedit_remap(adt, ival, NLATIME_CONVERT_MAP); - } - - /* left half? */ - if (ival < sval) { - timefac = (sval - ival) / (sval - minx); - *(td->val) = cvalc - timefac * (cvalc - minx); - } - else { - timefac = (ival - sval) / (maxx - sval); - *(td->val) = cvalc + timefac * (maxx - cvalc); - } - - if (adt) { - /* global to strip */ - *(td->val) = BKE_nla_tweakedit_remap(adt, *(td->val), NLATIME_CONVERT_UNMAP); - } - } - } - } -} - -static void applyTimeSlide(TransInfo *t, const int mval[2]) -{ - View2D *v2d = (View2D *)t->view; - float cval[2], sval[2]; - const float *range = t->custom.mode.data; - float minx = range[0]; - float maxx = range[1]; - char str[UI_MAX_DRAW_STR]; - - /* calculate mouse co-ordinates */ - UI_view2d_region_to_view(v2d, mval[0], mval[1], &cval[0], &cval[1]); - UI_view2d_region_to_view(v2d, t->mouse.imval[0], t->mouse.imval[1], &sval[0], &sval[1]); - - /* t->values_final[0] stores cval[0], which is the current mouse-pointer location (in frames) */ - // XXX Need to be able to repeat this - /* t->values_final[0] = cval[0]; */ /* UNUSED (reset again later). */ - - /* handle numeric-input stuff */ - t->vec[0] = 2.0f * (cval[0] - sval[0]) / (maxx - minx); - applyNumInput(&t->num, &t->vec[0]); - t->values_final[0] = (maxx - minx) * t->vec[0] / 2.0f + sval[0]; - - headerTimeSlide(t, sval[0], str); - applyTimeSlideValue(t, sval[0], t->values_final[0]); - - recalcData(t); - - ED_area_status_text(t->sa, str); -} -/** \} */ - -/* -------------------------------------------------------------------- */ -/* Transform (Animation Time Scale) */ - -/** \name Transform Animation Time Scale - * \{ */ - -static void initTimeScale(TransInfo *t) -{ - float center[2]; - - /* this tool is only really available in the Action Editor - * AND NLA Editor (for strip scaling) - */ - if (ELEM(t->spacetype, SPACE_ACTION, SPACE_NLA) == 0) { - t->state = TRANS_CANCEL; - } - - t->mode = TFM_TIME_SCALE; - t->transform = applyTimeScale; - - /* recalculate center2d to use CFRA and mouse Y, since that's - * what is used in time scale */ - if ((t->flag & T_OVERRIDE_CENTER) == 0) { - t->center_global[0] = t->scene->r.cfra; - projectFloatView(t, t->center_global, center); - center[1] = t->mouse.imval[1]; - } - - /* force a reinit with the center2d used here */ - initMouseInput(t, &t->mouse, center, t->mouse.imval, false); - - initMouseInputMode(t, &t->mouse, INPUT_SPRING_FLIP); - - t->flag |= T_NULL_ONE; - t->num.val_flag[0] |= NUM_NULL_ONE; - - /* num-input has max of (n-1) */ - t->idx_max = 0; - t->num.flag = 0; - t->num.idx_max = t->idx_max; - - /* initialize snap like for everything else */ - t->snap[0] = 0.0f; - t->snap[1] = t->snap[2] = 1.0f; - - copy_v3_fl(t->num.val_inc, t->snap[1]); - t->num.unit_sys = t->scene->unit.system; - t->num.unit_type[0] = B_UNIT_NONE; -} - -static void headerTimeScale(TransInfo *t, char str[UI_MAX_DRAW_STR]) -{ - char tvec[NUM_STR_REP_LEN * 3]; - - if (hasNumInput(&t->num)) { - outputNumInput(&(t->num), tvec, &t->scene->unit); - } - else { - BLI_snprintf(&tvec[0], NUM_STR_REP_LEN, "%.4f", t->values_final[0]); - } - - BLI_snprintf(str, UI_MAX_DRAW_STR, TIP_("ScaleX: %s"), &tvec[0]); -} - -static void applyTimeScaleValue(TransInfo *t, float value) -{ - Scene *scene = t->scene; - int i; - - const short autosnap = getAnimEdit_SnapMode(t); - const double secf = FPS; - - FOREACH_TRANS_DATA_CONTAINER (t, tc) { - TransData *td = tc->data; - TransData2D *td2d = tc->data_2d; - for (i = 0; i < tc->data_len; i++, td++, td2d++) { - /* it is assumed that td->extra is a pointer to the AnimData, - * whose active action is where this keyframe comes from - * (this is only valid when not in NLA) - */ - AnimData *adt = (t->spacetype != SPACE_NLA) ? td->extra : NULL; - float startx = CFRA; - float fac = value; - - if (autosnap == SACTSNAP_TSTEP) { - fac = (float)(floor((double)fac / secf + 0.5) * secf); - } - else if (autosnap == SACTSNAP_STEP) { - fac = floorf(fac + 0.5f); - } - - /* take proportional editing into account */ - fac = ((fac - 1.0f) * td->factor) + 1; - - /* check if any need to apply nla-mapping */ - if (adt) { - startx = BKE_nla_tweakedit_remap(adt, startx, NLATIME_CONVERT_UNMAP); - } - - /* now, calculate the new value */ - *(td->val) = ((td->ival - startx) * fac) + startx; - - /* apply nearest snapping */ - doAnimEdit_SnapFrame(t, td, td2d, adt, autosnap); - } - } -} - -static void applyTimeScale(TransInfo *t, const int UNUSED(mval[2])) -{ - char str[UI_MAX_DRAW_STR]; - - /* handle numeric-input stuff */ - t->vec[0] = t->values[0]; - applyNumInput(&t->num, &t->vec[0]); - t->values_final[0] = t->vec[0]; - headerTimeScale(t, str); - - applyTimeScaleValue(t, t->values_final[0]); - - recalcData(t); - - ED_area_status_text(t->sa, str); -} -/** \} */ - /* TODO, move to: transform_query.c */ bool checkUseAxisMatrix(TransInfo *t) { diff --git a/source/blender/editors/transform/transform.h b/source/blender/editors/transform/transform.h index 95506918d98..503e7bd4691 100644 --- a/source/blender/editors/transform/transform.h +++ b/source/blender/editors/transform/transform.h @@ -24,8 +24,8 @@ #ifndef __TRANSFORM_H__ #define __TRANSFORM_H__ -#include "ED_transform.h" #include "ED_numinput.h" +#include "ED_transform.h" #include "ED_view3d.h" #include "RE_engine.h" @@ -270,114 +270,6 @@ typedef struct TransDataNla { int handle; } TransDataNla; -struct LinkNode; - -/* header of TransDataEdgeSlideVert, TransDataEdgeSlideEdge */ -typedef struct TransDataGenericSlideVert { - struct BMVert *v; - struct LinkNode **cd_loop_groups; - float co_orig_3d[3]; -} TransDataGenericSlideVert; - -typedef struct TransDataEdgeSlideVert { - /** #TransDataGenericSlideVert (header) */ - struct BMVert *v; - struct LinkNode **cd_loop_groups; - float v_co_orig[3]; - /* end generic */ - - float edge_len; - - struct BMVert *v_side[2]; - - /* add origvert.co to get the original locations */ - float dir_side[2][3]; - - int loop_nr; -} TransDataEdgeSlideVert; - -typedef struct EdgeSlideData { - TransDataEdgeSlideVert *sv; - int totsv; - - int mval_start[2], mval_end[2]; - int curr_sv_index; - - /** when un-clamped - use this index: #TransDataEdgeSlideVert.dir_side */ - int curr_side_unclamp; -} EdgeSlideData; - -typedef struct EdgeSlideParams { - float perc; - - bool use_even; - bool flipped; -} EdgeSlideParams; - -typedef struct TransDataVertSlideVert { - /** #TransDataGenericSlideVert (header) */ - struct BMVert *v; - struct LinkNode **cd_loop_groups; - float co_orig_3d[3]; - /* end generic */ - - float (*co_link_orig_3d)[3]; - int co_link_tot; - int co_link_curr; -} TransDataVertSlideVert; - -typedef struct VertSlideData { - TransDataVertSlideVert *sv; - int totsv; - int curr_sv_index; - - /* result of ED_view3d_ob_project_mat_get */ - float proj_mat[4][4]; -} VertSlideData; - -typedef struct VertSlideParams { - float perc; - - bool use_even; - bool flipped; -} VertSlideParams; - -typedef struct BoneInitData { - struct EditBone *bone; - float tail[3]; - float rad_head; - float rad_tail; - float roll; - float head[3]; - float dist; - float xwidth; - float zwidth; -} BoneInitData; - -typedef struct PoseInitData_Mirror { - /** Points to the bone which this info is initialized & restored to. - * A NULL value is used to terminate the array. */ - struct bPoseChannel *pchan; - struct { - float loc[3]; - float size[3]; - union { - float eul[3]; - float quat[4]; - float axis_angle[4]; - }; - float curve_in_x; - float curve_out_x; - float roll1; - float roll2; - } orig; - /** - * An extra offset to apply after mirroring. - * Use with #POSE_MIRROR_RELATIVE. - */ - float offset_mtx[4][4]; -} PoseInitData_Mirror; - typedef struct TransData { /** Distance needed to affect element (for Proportionnal Editing). */ float dist; @@ -639,17 +531,12 @@ typedef struct TransInfo { bool is_launch_event_tweak; struct { - /** Orientation type when when we're not constrained. - * nearly always global except for rotate which defaults to screen-space orientation. */ - short unset; - /** Orientation to use when a key is pressed. */ - short user; - /* Used when user is global. */ - short user_alt; short index; - short *types[2]; - /* this gets used when custom_orientation is V3D_ORIENT_CUSTOM */ + short types[3]; + /* this gets used when orientation.type[x] is V3D_ORIENT_CUSTOM */ struct TransformOrientation *custom; + /* this gets used when orientation.type[0] is V3D_ORIENT_CUSTOM_MATRIX */ + float custom_matrix[3][3]; } orientation; /** backup from view3d, to restore on end. */ short gizmo_flag; @@ -674,23 +561,14 @@ typedef struct TransInfo { /** Secondary axis, shear uses this. */ int orient_axis_ortho; - /** Often this matrix has similar usage to #TransInfo.spacemtx however this - * is used to define extra axes to operate on, not necessarily a space. - * - * For example, by default rotation operates on the view (`orient_matrix[2]`), - * even when the current space isn't set to the view. */ - float orient_matrix[3][3]; - /** Don't overwrite when set by operator redo defines the orientation axis. */ - bool orient_matrix_is_set; - /** remove elements if operator is canceled. */ bool remove_on_cancel; void *view; /** Only valid (non null) during an operator called function. */ struct bContext *context; - struct ScrArea *sa; - struct ARegion *ar; + struct ScrArea *area; + struct ARegion *region; struct Depsgraph *depsgraph; struct Scene *scene; struct ViewLayer *view_layer; @@ -785,6 +663,10 @@ enum { T_MODAL_CURSOR_SET = 1 << 26, T_CLNOR_REBUILD = 1 << 27, + + /* Special Aftertrans. */ + T_AUTOMERGE = 1 << 28, + T_AUTOSPLIT = 1 << 29, }; /** #TransInfo.modifiers */ @@ -875,6 +757,43 @@ enum { MULTI_POINTS = 1 << 3, }; +/** keymap modal items */ +/* NOTE: these values are saved in keymap files, do not change then but just add new ones. */ +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 */ + TFM_MODAL_PROPSIZE = 26, + /* node editor insert offset (aka auto-offset) direction toggle */ + TFM_MODAL_INSERTOFS_TOGGLE_DIR = 27, +}; + /* Hard min/max for proportional size. */ #define T_PROP_SIZE_MIN 1e-6f #define T_PROP_SIZE_MAX 1e12f @@ -900,8 +819,6 @@ void projectFloatView(TransInfo *t, const float vec[3], float adr[2]); void applyAspectRatio(TransInfo *t, float vec[2]); void removeAspectRatio(TransInfo *t, float vec[2]); -void drawPropCircle(const struct bContext *C, TransInfo *t); - struct wmKeyMap *transform_modal_keymap(struct wmKeyConfig *keyconf); /*********************** transform_gizmo.c ********** */ @@ -915,32 +832,6 @@ void drawDial3d(const TransInfo *t); /*********************** TransData Creation and General Handling *********** */ bool transdata_check_local_islands(TransInfo *t, short around); -/*********************** Constraints *****************************/ - -void drawConstraint(TransInfo *t); - -void getConstraintMatrix(TransInfo *t); -void setConstraint(TransInfo *t, float space[3][3], int mode, const char text[]); -void setAxisMatrixConstraint(TransInfo *t, int mode, const char text[]); -void setLocalConstraint(TransInfo *t, int mode, const char text[]); -void setUserConstraint(TransInfo *t, short orientation, int mode, const char text[]); - -void constraintNumInput(TransInfo *t, float vec[3]); - -bool isLockConstraint(TransInfo *t); -int getConstraintSpaceDimension(TransInfo *t); -int constraintModeToIndex(const TransInfo *t); -char constraintModeToChar(const TransInfo *t); - -void startConstraint(TransInfo *t); -void stopConstraint(TransInfo *t); - -void initSelectConstraint(TransInfo *t, float mtx[3][3]); -void selectConstraint(TransInfo *t); -void postSelectConstraint(TransInfo *t); - -void setNearestAxis(TransInfo *t); - /********************** Mouse Input ******************************/ typedef enum { @@ -1021,7 +912,7 @@ void transform_data_ext_rotate(TransData *td, float mat[3][3], bool use_drot); /*********************** Transform Orientations ******************************/ -void initTransformOrientation(struct bContext *C, TransInfo *t); +void initTransformOrientation(struct bContext *C, TransInfo *t, short orientation); /* Those two fill in mat and return non-zero on success */ bool createSpaceNormal(float mat[3][3], const float normal[3]); @@ -1052,12 +943,6 @@ int getTransformOrientation(const struct bContext *C, float normal[3], float pla void freeCustomNormalArray(TransInfo *t, TransDataContainer *tc, TransCustomData *custom_data); -void freeEdgeSlideVerts(TransInfo *t, TransDataContainer *tc, TransCustomData *custom_data); -void projectEdgeSlideData(TransInfo *t, bool is_final); - -void freeVertSlideVerts(TransInfo *t, TransDataContainer *tc, TransCustomData *custom_data); -void projectVertSlideData(TransInfo *t, bool is_final); - /* TODO. transform_query.c */ bool checkUseAxisMatrix(TransInfo *t); @@ -1072,14 +957,14 @@ bool checkUseAxisMatrix(TransInfo *t); (BLI_assert((t)->data_container_len == 1), (&(t)->data_container[0])) #define FOREACH_TRANS_DATA_CONTAINER(t, th) \ - for (TransDataContainer *tc = t->data_container, \ - *tc_end = t->data_container + t->data_container_len; \ + for (TransDataContainer *tc = (t)->data_container, \ + *tc_end = (t)->data_container + (t)->data_container_len; \ th != tc_end; \ th++) #define FOREACH_TRANS_DATA_CONTAINER_INDEX(t, th, i) \ - for (TransDataContainer *tc = ((i = 0), t->data_container), \ - *tc_end = t->data_container + t->data_container_len; \ + for (TransDataContainer *tc = ((i = 0), (t)->data_container), \ + *tc_end = (t)->data_container + (t)->data_container_len; \ th != tc_end; \ th++, i++) diff --git a/source/blender/editors/transform/transform_constraints.c b/source/blender/editors/transform/transform_constraints.c index b43e1fec988..b07eb6edf5a 100644 --- a/source/blender/editors/transform/transform_constraints.c +++ b/source/blender/editors/transform/transform_constraints.c @@ -21,10 +21,10 @@ * \ingroup edtransform */ -#include <stdlib.h> +#include <math.h> #include <stdio.h> +#include <stdlib.h> #include <string.h> -#include <math.h> #include "DNA_object_types.h" #include "DNA_scene_types.h" @@ -32,20 +32,17 @@ #include "DNA_space_types.h" #include "DNA_view3d_types.h" -#include "BIF_glutil.h" - #include "GPU_immediate.h" #include "GPU_matrix.h" #include "GPU_state.h" #include "BLI_math.h" -#include "BLI_utildefines.h" -#include "BLI_string.h" #include "BLI_rect.h" +#include "BLI_string.h" +#include "BLI_utildefines.h" #include "BKE_context.h" -#include "ED_image.h" #include "ED_view3d.h" #include "BLT_translation.h" @@ -55,6 +52,9 @@ #include "transform.h" #include "transform_snap.h" +/* Own include. */ +#include "transform_constraints.h" + static void drawObjectConstraint(TransInfo *t); /* ************************** CONSTRAINTS ************************* */ @@ -171,7 +171,7 @@ static void postConstraintChecks(TransInfo *t, float vec[3], float pvec[3]) static void viewAxisCorrectCenter(const TransInfo *t, float t_con_center[3]) { if (t->spacetype == SPACE_VIEW3D) { - // View3D *v3d = t->sa->spacedata.first; + // View3D *v3d = t->area->spacedata.first; const float min_dist = 1.0f; /* v3d->clip_start; */ float dir[3]; float l; @@ -713,7 +713,10 @@ void setUserConstraint(TransInfo *t, short orientation, int mode, const char fte break; case V3D_ORIENT_VIEW: BLI_snprintf(text, sizeof(text), ftext, TIP_("view")); - setConstraint(t, t->spacemtx, mode, text); + float mtx[3][3]; + copy_m3_m3(mtx, t->spacemtx); + negate_v3(mtx[2]); + setConstraint(t, mtx, mode, text); break; case V3D_ORIENT_CURSOR: BLI_snprintf(text, sizeof(text), ftext, TIP_("cursor")); @@ -727,7 +730,9 @@ void setUserConstraint(TransInfo *t, short orientation, int mode, const char fte BLI_snprintf(text, sizeof(text), ftext, TIP_("custom matrix")); setConstraint(t, t->spacemtx, mode, text); break; - case V3D_ORIENT_CUSTOM: { + case V3D_ORIENT_CUSTOM: + default: { + BLI_assert(orientation >= V3D_ORIENT_CUSTOM); char orientation_str[128]; BLI_snprintf(orientation_str, sizeof(orientation_str), @@ -846,8 +851,8 @@ void drawPropCircle(const struct bContext *C, TransInfo *t) } else if (ELEM(t->spacetype, SPACE_GRAPH, SPACE_ACTION)) { /* only scale y */ - rcti *mask = &t->ar->v2d.mask; - rctf *datamask = &t->ar->v2d.cur; + rcti *mask = &t->region->v2d.mask; + rctf *datamask = &t->region->v2d.cur; float xsize = BLI_rctf_size_x(datamask); float ysize = BLI_rctf_size_y(datamask); float xmask = BLI_rcti_size_x(mask); @@ -984,17 +989,22 @@ void getConstraintMatrix(TransInfo *t) /*------------------------- MMB Select -------------------------------*/ -void initSelectConstraint(TransInfo *t, float mtx[3][3]) +void initSelectConstraint(TransInfo *t, bool force_global) { - copy_m3_m3(t->con.mtx, mtx); - t->con.mode |= CON_APPLY; - t->con.mode |= CON_SELECT; + short orientation; + if (force_global) { + orientation = V3D_ORIENT_GLOBAL; + } + else { + if (t->orientation.index == 0) { + t->orientation.index = 1; + initTransformOrientation(t->context, t, t->orientation.types[t->orientation.index]); + } + orientation = t->orientation.types[t->orientation.index]; + } + setUserConstraint(t, orientation, CON_APPLY | CON_SELECT, ""); setNearestAxis(t); - t->con.drawExtra = NULL; - t->con.applyVec = applyAxisConstraintVec; - t->con.applySize = applyAxisConstraintSize; - t->con.applyRot = applyAxisConstraintRot; } void selectConstraint(TransInfo *t) @@ -1055,7 +1065,7 @@ static void setNearestAxis3d(TransInfo *t) * projecting them with ED_view3d_win_to_delta and then get the length of that vector. */ zfac = mul_project_m4_v3_zfac(t->persmat, t->center_global); - zfac = len_v3(t->persinv[0]) * 2.0f / t->ar->winx * zfac * 30.0f; + zfac = len_v3(t->persinv[0]) * 2.0f / t->region->winx * zfac * 30.0f; for (i = 0; i < 3; i++) { float axis[3], axis_2d[2]; diff --git a/source/blender/editors/transform/transform_constraints.h b/source/blender/editors/transform/transform_constraints.h new file mode 100644 index 00000000000..c98234c83da --- /dev/null +++ b/source/blender/editors/transform/transform_constraints.h @@ -0,0 +1,48 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + */ + +/** \file + * \ingroup edtransform + */ + +#ifndef __TRANSFORM_CONSTRAINTS_H__ +#define __TRANSFORM_CONSTRAINTS_H__ + +struct TransInfo; + +void constraintNumInput(TransInfo *t, float vec[3]); +void setConstraint(TransInfo *t, float space[3][3], int mode, const char text[]); +void setAxisMatrixConstraint(TransInfo *t, int mode, const char text[]); +void setLocalConstraint(TransInfo *t, int mode, const char text[]); +void setUserConstraint(TransInfo *t, short orientation, int mode, const char text[]); +void drawConstraint(TransInfo *t); +void drawPropCircle(const struct bContext *C, TransInfo *t); +void startConstraint(TransInfo *t); +void stopConstraint(TransInfo *t); +void getConstraintMatrix(TransInfo *t); +void initSelectConstraint(TransInfo *t, bool force_global); +void selectConstraint(TransInfo *t); +void postSelectConstraint(TransInfo *t); +void setNearestAxis(TransInfo *t); +int constraintModeToIndex(const TransInfo *t); +char constraintModeToChar(const TransInfo *t); +bool isLockConstraint(TransInfo *t); +int getConstraintSpaceDimension(TransInfo *t); + +#endif diff --git a/source/blender/editors/transform/transform_convert.c b/source/blender/editors/transform/transform_convert.c index 869c23de74c..d6875f173e3 100644 --- a/source/blender/editors/transform/transform_convert.c +++ b/source/blender/editors/transform/transform_convert.c @@ -23,51 +23,53 @@ #include "DNA_anim_types.h" #include "DNA_armature_types.h" -#include "DNA_space_types.h" #include "DNA_constraint_types.h" #include "DNA_gpencil_types.h" #include "DNA_mask_types.h" +#include "DNA_space_types.h" #include "MEM_guardedalloc.h" -#include "BLI_math.h" +#include "BLI_kdtree.h" #include "BLI_listbase.h" +#include "BLI_math.h" #include "BLI_string.h" -#include "BLI_kdtree.h" #include "BKE_animsys.h" #include "BKE_armature.h" #include "BKE_context.h" +#include "BKE_editmesh.h" #include "BKE_fcurve.h" #include "BKE_global.h" #include "BKE_gpencil.h" -#include "BKE_layer.h" #include "BKE_key.h" +#include "BKE_layer.h" #include "BKE_main.h" +#include "BKE_mask.h" #include "BKE_modifier.h" #include "BKE_nla.h" #include "BKE_node.h" #include "BKE_pointcache.h" #include "BKE_rigidbody.h" #include "BKE_scene.h" -#include "BKE_editmesh.h" #include "BKE_tracking.h" -#include "BKE_mask.h" #include "BIK_api.h" #include "ED_anim_api.h" #include "ED_armature.h" -#include "ED_particle.h" +#include "ED_clip.h" #include "ED_image.h" -#include "ED_keyframing.h" #include "ED_keyframes_edit.h" -#include "ED_object.h" +#include "ED_keyframing.h" #include "ED_markers.h" +#include "ED_mask.h" #include "ED_mesh.h" #include "ED_node.h" -#include "ED_clip.h" -#include "ED_mask.h" +#include "ED_object.h" +#include "ED_particle.h" + +#include "UI_view2d.h" #include "WM_api.h" /* for WM_event_add_notifier to deal with stabilization nodes */ #include "WM_types.h" @@ -79,6 +81,12 @@ #include "transform.h" #include "transform_convert.h" +#include "transform_mode.h" + +bool transform_mode_use_local_origins(const TransInfo *t) +{ + return ELEM(t->mode, TFM_ROTATION, TFM_RESIZE, TFM_TRACKBALL); +} /** * Transforming around ourselves is no use, fallback to individual origins, @@ -86,14 +94,40 @@ */ void transform_around_single_fallback(TransInfo *t) { - if ((t->data_len_all == 1) && - (ELEM(t->around, V3D_AROUND_CENTER_BOUNDS, V3D_AROUND_CENTER_MEDIAN, V3D_AROUND_ACTIVE)) && - (ELEM(t->mode, TFM_RESIZE, TFM_ROTATION, TFM_TRACKBALL))) { - t->around = V3D_AROUND_LOCAL_ORIGINS; + if ((ELEM(t->around, V3D_AROUND_CENTER_BOUNDS, V3D_AROUND_CENTER_MEDIAN, V3D_AROUND_ACTIVE)) && + transform_mode_use_local_origins(t)) { + + bool is_data_single = false; + if (t->data_len_all == 1) { + is_data_single = true; + } + else if (t->data_len_all == 3) { + if (t->obedit_type == OB_CURVE) { + /* Special case check for curve, if we have a single curve bezier triple selected + * treat */ + FOREACH_TRANS_DATA_CONTAINER (t, tc) { + if (!tc->data_len) { + continue; + } + if (tc->data_len == 3) { + const TransData *td = tc->data; + if ((td[0].loc == td[1].loc) && (td[1].loc == td[2].loc)) { + is_data_single = true; + } + } + break; + } + } + } + if (is_data_single) { + t->around = V3D_AROUND_LOCAL_ORIGINS; + } } } -/* ************************** Functions *************************** */ +/* -------------------------------------------------------------------- */ +/** \name Proportional Editing + * \{ */ static int trans_data_compare_dist(const void *a, const void *b) { @@ -203,8 +237,8 @@ static void set_prop_dist(TransInfo *t, const bool with_dist) const bool use_island = transdata_check_local_islands(t, t->around); if (t->flag & T_PROP_PROJECTED) { - if (t->spacetype == SPACE_VIEW3D && t->ar && t->ar->regiontype == RGN_TYPE_WINDOW) { - RegionView3D *rv3d = t->ar->regiondata; + if (t->spacetype == SPACE_VIEW3D && t->region && t->region->regiontype == RGN_TYPE_WINDOW) { + RegionView3D *rv3d = t->region->regiondata; normalize_v3_v3(_proj_vec, rv3d->viewinv[2]); proj_vec = _proj_vec; } @@ -330,7 +364,11 @@ static void set_prop_dist(TransInfo *t, const bool with_dist) MEM_freeN(td_table); } -/* ********************* pose mode ************* */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Pose Mode + * \{ */ static short apply_targetless_ik(Object *ob) { @@ -368,23 +406,25 @@ static short apply_targetless_ik(Object *ob) } for (; segcount; segcount--) { Bone *bone; - float rmat[4][4] /*, tmat[4][4], imat[4][4]*/; + float mat[4][4]; /* pose_mat(b) = pose_mat(b-1) * offs_bone * channel * constraint * IK */ - /* we put in channel the entire result of rmat = (channel * constraint * IK) */ - /* pose_mat(b) = pose_mat(b-1) * offs_bone * rmat */ - /* rmat = pose_mat(b) * inv(pose_mat(b-1) * offs_bone ) */ + /* we put in channel the entire result of mat = (channel * constraint * IK) */ + /* pose_mat(b) = pose_mat(b-1) * offs_bone * mat */ + /* mat = pose_mat(b) * inv(pose_mat(b-1) * offs_bone ) */ parchan = chanlist[segcount - 1]; bone = parchan->bone; bone->flag |= BONE_TRANSFORM; /* ensures it gets an auto key inserted */ - BKE_armature_mat_pose_to_bone(parchan, parchan->pose_mat, rmat); - + BKE_armature_mat_pose_to_bone(parchan, parchan->pose_mat, mat); /* apply and decompose, doesn't work for constraints or non-uniform scale well */ { float rmat3[3][3], qrmat[3][3], imat3[3][3], smat[3][3]; - copy_m3_m4(rmat3, rmat); + + copy_m3_m4(rmat3, mat); + /* Make sure that our rotation matrix only contains rotation and not scale. */ + normalize_m3(rmat3); /* rotation */ /* [#22409] is partially caused by this, as slight numeric error introduced during @@ -404,7 +444,7 @@ static short apply_targetless_ik(Object *ob) /* causes problems with some constraints (e.g. childof), so disable this */ /* as it is IK shouldn't affect location directly */ - /* copy_v3_v3(parchan->loc, rmat[3]); */ + /* copy_v3_v3(parchan->loc, mat[3]); */ } } @@ -436,12 +476,12 @@ static void bone_children_clear_transflag(int mode, short around, ListBase *lb) } } -/* sets transform flags in the bones - * returns total number of bones with BONE_TRANSFORM */ -int count_set_pose_transflags(Object *ob, - const int mode, - const short around, - bool has_translate_rotate[2]) +/* Sets transform flags in the bones. + * Returns total number of bones with `BONE_TRANSFORM`. */ +int transform_convert_pose_transflags_update(Object *ob, + const int mode, + const short around, + bool has_translate_rotate[2]) { bArmature *arm = ob->data; bPoseChannel *pchan; @@ -450,15 +490,20 @@ int count_set_pose_transflags(Object *ob, for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) { bone = pchan->bone; - bone->flag &= ~(BONE_TRANSFORM | BONE_TRANSFORM_MIRROR); if (PBONE_VISIBLE(arm, bone)) { if ((bone->flag & BONE_SELECTED)) { bone->flag |= BONE_TRANSFORM; } + else { + bone->flag &= ~BONE_TRANSFORM; + } bone->flag &= ~BONE_HINGE_CHILD_TRANSFORM; bone->flag &= ~BONE_TRANSFORM_CHILD; } + else { + bone->flag &= ~BONE_TRANSFORM; + } } /* make sure no bone can be transformed when a parent is transformed */ @@ -503,7 +548,11 @@ int count_set_pose_transflags(Object *ob, return total; } -/* -------- Auto-IK ---------- */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Pose Mode (Auto-IK) + * \{ */ /* adjust pose-channel's auto-ik chainlen */ static bool pchan_autoik_adjust(bPoseChannel *pchan, short chainlen) @@ -628,7 +677,11 @@ static void pose_grab_with_ik_clear(Main *bmain, Object *ob) } } -/* ********************* curve/surface ********* */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Curve Surface + * \{ */ void calc_distanceCurveVerts(TransData *head, TransData *tail) { @@ -698,7 +751,11 @@ TransDataCurveHandleFlags *initTransDataCurveHandles(TransData *td, struct BezTr return hdata; } -/* ********************* UV ****************** */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name UV Coordinates + * \{ */ bool clipUVTransform(TransInfo *t, float vec[2], const bool resize) { @@ -784,7 +841,36 @@ void clipUVData(TransInfo *t) } } -/* ********************* ANIMATION EDITORS (GENERAL) ************************* */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Animation Editors (General) + * \{ */ + +/** + * Used for `TFM_TIME_EXTEND`. + */ +char transform_convert_frame_side_dir_get(TransInfo *t, float cframe) +{ + char r_dir; + float center[2]; + if (t->flag & T_MODAL) { + UI_view2d_region_to_view( + (View2D *)t->view, t->mouse.imval[0], t->mouse.imval[1], ¢er[0], ¢er[1]); + r_dir = (center[0] > cframe) ? 'R' : 'L'; + { + /* XXX: This saves the direction in the "mirror" property to be used for redo! */ + if (r_dir == 'R') { + t->flag |= T_NO_MIRROR; + } + } + } + else { + r_dir = (t->flag & T_NO_MIRROR) ? 'R' : 'L'; + } + + return r_dir; +} /* This function tests if a point is on the "mouse" side of the cursor/frame-marking */ bool FrameOnMouseSide(char side, float frame, float cframe) @@ -803,26 +889,11 @@ bool FrameOnMouseSide(char side, float frame, float cframe) } } -/* ********************* ACTION EDITOR ****************** */ +/** \} */ -static int gpf_cmp_frame(void *thunk, const void *a, const void *b) -{ - const bGPDframe *frame_a = a; - const bGPDframe *frame_b = b; - - if (frame_a->framenum < frame_b->framenum) { - return -1; - } - if (frame_a->framenum > frame_b->framenum) { - return 1; - } - *((bool *)thunk) = true; - /* selected last */ - if ((frame_a->flag & GP_FRAME_SELECT) && ((frame_b->flag & GP_FRAME_SELECT) == 0)) { - return 1; - } - return 0; -} +/* -------------------------------------------------------------------- */ +/** \name Animation Editor + * \{ */ static int masklay_shape_cmp_frame(void *thunk, const void *a, const void *b) { @@ -856,13 +927,13 @@ static void posttrans_gpd_clean(bGPdata *gpd) bGPDframe *gpf, *gpfn; bool is_double = false; - BLI_listbase_sort_r(&gpl->frames, gpf_cmp_frame, &is_double); + BKE_gpencil_layer_frames_sort(gpl, &is_double); if (is_double) { for (gpf = gpl->frames.first; gpf; gpf = gpfn) { gpfn = gpf->next; if (gpfn && gpf->framenum == gpfn->framenum) { - BKE_gpencil_layer_delframe(gpl, gpf); + BKE_gpencil_layer_frame_delete(gpl, gpf); } } } @@ -875,6 +946,8 @@ static void posttrans_gpd_clean(bGPdata *gpd) } /* set cache flag to dirty */ DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY); + + WM_main_add_notifier(NC_GPENCIL | NA_EDITED, gpd); } static void posttrans_mask_clean(Mask *mask) @@ -904,6 +977,8 @@ static void posttrans_mask_clean(Mask *mask) } #endif } + + WM_main_add_notifier(NC_MASK | NA_EDITED, mask); } /* Time + Average value */ @@ -985,7 +1060,7 @@ static void posttrans_fcurve_clean(FCurve *fcu, } else { /* Compute the average values for each retained keyframe */ - for (tRetainedKeyframe *rk = retained_keys.first; rk; rk = rk->next) { + LISTBASE_FOREACH (tRetainedKeyframe *, rk, &retained_keys) { rk->val = rk->val / (float)rk->tot_count; } } @@ -1078,15 +1153,19 @@ static void posttrans_action_clean(bAnimContext *ac, bAction *act) ANIM_animdata_freelist(&anim_data); } -/* ********************* GRAPH EDITOR ************************* */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Graph Editor + * \{ */ /* struct for use in re-sorting BezTriples during Graph Editor transform */ typedef struct BeztMap { BezTriple *bezt; - unsigned int oldIndex; /* index of bezt in fcu->bezt array before sorting */ - unsigned int newIndex; /* index of bezt in fcu->bezt array after sorting */ - short swapHs; /* swap order of handles (-1=clear; 0=not checked, 1=swap) */ - char pipo, cipo; /* interpolation of current and next segments */ + uint oldIndex; /* index of bezt in fcu->bezt array before sorting */ + uint newIndex; /* index of bezt in fcu->bezt array after sorting */ + short swapHs; /* swap order of handles (-1=clear; 0=not checked, 1=swap) */ + char pipo, cipo; /* interpolation of current and next segments */ } BeztMap; /* This function converts an FCurve's BezTriple array to a BeztMap array @@ -1249,6 +1328,12 @@ static void beztmap_to_data(TransInfo *t, FCurve *fcu, BeztMap *bezms, int totve MEM_freeN(adjusted); } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Transform Utilities + * \{ */ + /* This function is called by recalcData during the Transform loop to recalculate * the handles of curves and sort the keyframes so that the curves draw correctly. * It is only called if some keyframes have moved out of order. @@ -1258,7 +1343,7 @@ static void beztmap_to_data(TransInfo *t, FCurve *fcu, BeztMap *bezms, int totve */ void remake_graph_transdata(TransInfo *t, ListBase *anim_data) { - SpaceGraph *sipo = (SpaceGraph *)t->sa->spacedata.first; + SpaceGraph *sipo = (SpaceGraph *)t->area->spacedata.first; bAnimListElem *ale; const bool use_handle = (sipo->flag & SIPO_NOHANDLES) == 0; @@ -1287,8 +1372,6 @@ void remake_graph_transdata(TransInfo *t, ListBase *anim_data) } } -/* *********************** Transform data ******************* */ - /* Little helper function for ObjectToTransData used to give certain * constraints (ChildOf, FollowPath, and others that may be added) * inverse corrections for transform, so that they aren't in CrazySpace. @@ -1374,6 +1457,12 @@ bool constraints_list_needinv(TransInfo *t, ListBase *list) return false; } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Transform (Auto-Keyframing) + * \{ */ + /** * Auto-keyframing feature - for objects * @@ -1395,10 +1484,10 @@ void autokeyframe_object(bContext *C, Scene *scene, ViewLayer *view_layer, Objec KeyingSet *active_ks = ANIM_scene_get_active_keyingset(scene); ListBase dsources = {NULL, NULL}; float cfra = (float)CFRA; // xxx this will do for now - short flag = 0; + eInsertKeyFlags flag = 0; - /* get flags used for inserting keyframes */ - flag = ANIM_get_keyframing_flags(scene, 1); + /* Get flags used for inserting keyframes. */ + flag = ANIM_get_keyframing_flags(scene, true); /* add datasource override for the object */ ANIM_relative_keyingset_add_source(&dsources, id, NULL, NULL); @@ -1417,7 +1506,6 @@ void autokeyframe_object(bContext *C, Scene *scene, ViewLayer *view_layer, Objec if (adt && adt->action) { ListBase nla_cache = {NULL, NULL}; for (fcu = adt->action->curves.first; fcu; fcu = fcu->next) { - fcu->flag &= ~FCURVE_SELECTED; insert_keyframe(bmain, reports, id, @@ -1532,147 +1620,156 @@ void autokeyframe_pose(bContext *C, Scene *scene, Object *ob, int tmode, short t FCurve *fcu; // TODO: this should probably be done per channel instead... - if (autokeyframe_cfra_can_key(scene, id)) { - ReportList *reports = CTX_wm_reports(C); - ToolSettings *ts = scene->toolsettings; - KeyingSet *active_ks = ANIM_scene_get_active_keyingset(scene); - ListBase nla_cache = {NULL, NULL}; - float cfra = (float)CFRA; - short flag = 0; - - /* flag is initialized from UserPref keyframing settings - * - special exception for targetless IK - INSERTKEY_MATRIX keyframes should get - * visual keyframes even if flag not set, as it's not that useful otherwise - * (for quick animation recording) - */ - flag = ANIM_get_keyframing_flags(scene, 1); + if (!autokeyframe_cfra_can_key(scene, id)) { + /* tag channels that should have unkeyed data */ + for (pchan = pose->chanbase.first; pchan; pchan = pchan->next) { + if (pchan->bone->flag & BONE_TRANSFORM) { + /* tag this channel */ + pchan->bone->flag |= BONE_UNKEYED; + } + } + return; + } + + ReportList *reports = CTX_wm_reports(C); + ToolSettings *ts = scene->toolsettings; + KeyingSet *active_ks = ANIM_scene_get_active_keyingset(scene); + ListBase nla_cache = {NULL, NULL}; + float cfra = (float)CFRA; + eInsertKeyFlags flag = 0; - if (targetless_ik) { - flag |= INSERTKEY_MATRIX; + /* flag is initialized from UserPref keyframing settings + * - special exception for targetless IK - INSERTKEY_MATRIX keyframes should get + * visual keyframes even if flag not set, as it's not that useful otherwise + * (for quick animation recording) + */ + flag = ANIM_get_keyframing_flags(scene, true); + + if (targetless_ik) { + flag |= INSERTKEY_MATRIX; + } + + for (pchan = pose->chanbase.first; pchan; pchan = pchan->next) { + if ((pchan->bone->flag & BONE_TRANSFORM) == 0 && + !((pose->flag & POSE_MIRROR_EDIT) && (pchan->bone->flag & BONE_TRANSFORM_MIRROR))) { + continue; } - for (pchan = pose->chanbase.first; pchan; pchan = pchan->next) { - if ((pchan->bone->flag & BONE_TRANSFORM) || - ((pose->flag & POSE_MIRROR_EDIT) && (pchan->bone->flag & BONE_TRANSFORM_MIRROR))) { - ListBase dsources = {NULL, NULL}; - - /* clear any 'unkeyed' flag it may have */ - pchan->bone->flag &= ~BONE_UNKEYED; - - /* add datasource override for the camera object */ - ANIM_relative_keyingset_add_source(&dsources, id, &RNA_PoseBone, pchan); - - /* only insert into active keyingset? */ - if (IS_AUTOKEY_FLAG(scene, ONLYKEYINGSET) && (active_ks)) { - /* run the active Keying Set on the current datasource */ - ANIM_apply_keyingset(C, &dsources, NULL, active_ks, MODIFYKEY_MODE_INSERT, cfra); - } - /* only insert into available channels? */ - else if (IS_AUTOKEY_FLAG(scene, INSERTAVAIL)) { - if (act) { - for (fcu = act->curves.first; fcu; fcu = fcu->next) { - /* only insert keyframes for this F-Curve if it affects the current bone */ - if (strstr(fcu->rna_path, "bones")) { - char *pchanName = BLI_str_quoted_substrN(fcu->rna_path, "bones["); - - /* only if bone name matches too... - * NOTE: this will do constraints too, but those are ok to do here too? - */ - if (pchanName && STREQ(pchanName, pchan->name)) { - insert_keyframe(bmain, - reports, - id, - act, - ((fcu->grp) ? (fcu->grp->name) : (NULL)), - fcu->rna_path, - fcu->array_index, - cfra, - ts->keyframe_type, - &nla_cache, - flag); - } - - if (pchanName) { - MEM_freeN(pchanName); - } - } - } - } - } - /* only insert keyframe if needed? */ - else if (IS_AUTOKEY_FLAG(scene, INSERTNEEDED)) { - bool do_loc = false, do_rot = false, do_scale = false; + ListBase dsources = {NULL, NULL}; - /* Filter the conditions when this happens - * (assume that 'curarea->spacetype == SPACE_VIEW3D'). */ - if (tmode == TFM_TRANSLATION) { - if (targetless_ik) { - do_rot = true; - } - else { - do_loc = true; - } - } - else if (ELEM(tmode, TFM_ROTATION, TFM_TRACKBALL)) { - if (ELEM(scene->toolsettings->transform_pivot_point, - V3D_AROUND_CURSOR, - V3D_AROUND_ACTIVE)) { - do_loc = true; - } + /* clear any 'unkeyed' flag it may have */ + pchan->bone->flag &= ~BONE_UNKEYED; - if ((scene->toolsettings->transform_flag & SCE_XFORM_AXIS_ALIGN) == 0) { - do_rot = true; - } - } - else if (tmode == TFM_RESIZE) { - if (ELEM(scene->toolsettings->transform_pivot_point, - V3D_AROUND_CURSOR, - V3D_AROUND_ACTIVE)) { - do_loc = true; - } + /* add datasource override for the camera object */ + ANIM_relative_keyingset_add_source(&dsources, id, &RNA_PoseBone, pchan); - if ((scene->toolsettings->transform_flag & SCE_XFORM_AXIS_ALIGN) == 0) { - do_scale = true; - } + /* only insert into active keyingset? */ + if (IS_AUTOKEY_FLAG(scene, ONLYKEYINGSET) && (active_ks)) { + /* run the active Keying Set on the current datasource */ + ANIM_apply_keyingset(C, &dsources, NULL, active_ks, MODIFYKEY_MODE_INSERT, cfra); + } + /* only insert into available channels? */ + else if (IS_AUTOKEY_FLAG(scene, INSERTAVAIL)) { + if (act) { + for (fcu = act->curves.first; fcu; fcu = fcu->next) { + /* only insert keyframes for this F-Curve if it affects the current bone */ + if (strstr(fcu->rna_path, "bones") == NULL) { + continue; } + char *pchanName = BLI_str_quoted_substrN(fcu->rna_path, "bones["); - if (do_loc) { - KeyingSet *ks = ANIM_builtin_keyingset_get_named(NULL, ANIM_KS_LOCATION_ID); - ANIM_apply_keyingset(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, cfra); - } - if (do_rot) { - KeyingSet *ks = ANIM_builtin_keyingset_get_named(NULL, ANIM_KS_ROTATION_ID); - ANIM_apply_keyingset(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, cfra); + /* only if bone name matches too... + * NOTE: this will do constraints too, but those are ok to do here too? + */ + if (pchanName && STREQ(pchanName, pchan->name)) { + insert_keyframe(bmain, + reports, + id, + act, + ((fcu->grp) ? (fcu->grp->name) : (NULL)), + fcu->rna_path, + fcu->array_index, + cfra, + ts->keyframe_type, + &nla_cache, + flag); } - if (do_scale) { - KeyingSet *ks = ANIM_builtin_keyingset_get_named(NULL, ANIM_KS_SCALING_ID); - ANIM_apply_keyingset(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, cfra); + + if (pchanName) { + MEM_freeN(pchanName); } } - /* insert keyframe in all (transform) channels */ + } + } + /* only insert keyframe if needed? */ + else if (IS_AUTOKEY_FLAG(scene, INSERTNEEDED)) { + bool do_loc = false, do_rot = false, do_scale = false; + + /* Filter the conditions when this happens + * (assume that 'curarea->spacetype == SPACE_VIEW3D'). */ + if (tmode == TFM_TRANSLATION) { + if (targetless_ik) { + do_rot = true; + } else { - KeyingSet *ks = ANIM_builtin_keyingset_get_named(NULL, ANIM_KS_LOC_ROT_SCALE_ID); - ANIM_apply_keyingset(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, cfra); + do_loc = true; + } + } + else if (ELEM(tmode, TFM_ROTATION, TFM_TRACKBALL)) { + if (ELEM(scene->toolsettings->transform_pivot_point, + V3D_AROUND_CURSOR, + V3D_AROUND_ACTIVE)) { + do_loc = true; } - /* free temp info */ - BLI_freelistN(&dsources); + if ((scene->toolsettings->transform_flag & SCE_XFORM_AXIS_ALIGN) == 0) { + do_rot = true; + } } - } + else if (tmode == TFM_RESIZE) { + if (ELEM(scene->toolsettings->transform_pivot_point, + V3D_AROUND_CURSOR, + V3D_AROUND_ACTIVE)) { + do_loc = true; + } - BKE_animsys_free_nla_keyframing_context_cache(&nla_cache); - } - else { - /* tag channels that should have unkeyed data */ - for (pchan = pose->chanbase.first; pchan; pchan = pchan->next) { - if (pchan->bone->flag & BONE_TRANSFORM) { - /* tag this channel */ - pchan->bone->flag |= BONE_UNKEYED; + if ((scene->toolsettings->transform_flag & SCE_XFORM_AXIS_ALIGN) == 0) { + do_scale = true; + } + } + + if (do_loc) { + KeyingSet *ks = ANIM_builtin_keyingset_get_named(NULL, ANIM_KS_LOCATION_ID); + ANIM_apply_keyingset(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, cfra); + } + if (do_rot) { + KeyingSet *ks = ANIM_builtin_keyingset_get_named(NULL, ANIM_KS_ROTATION_ID); + ANIM_apply_keyingset(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, cfra); + } + if (do_scale) { + KeyingSet *ks = ANIM_builtin_keyingset_get_named(NULL, ANIM_KS_SCALING_ID); + ANIM_apply_keyingset(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, cfra); } } + /* insert keyframe in all (transform) channels */ + else { + KeyingSet *ks = ANIM_builtin_keyingset_get_named(NULL, ANIM_KS_LOC_ROT_SCALE_ID); + ANIM_apply_keyingset(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, cfra); + } + + /* free temp info */ + BLI_freelistN(&dsources); } + + BKE_animsys_free_nla_keyframing_context_cache(&nla_cache); } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Transform (After-Transform Update) + * \{ */ + /* Return if we need to update motion paths, only if they already exist, * and we will insert a keyframe at the end of transform. */ bool motionpath_need_update_pose(Scene *scene, Object *ob) @@ -1686,13 +1783,12 @@ bool motionpath_need_update_pose(Scene *scene, Object *ob) static void special_aftertrans_update__movieclip(bContext *C, TransInfo *t) { - SpaceClip *sc = t->sa->spacedata.first; + SpaceClip *sc = t->area->spacedata.first; MovieClip *clip = ED_space_clip_get_clip(sc); ListBase *plane_tracks_base = BKE_tracking_get_active_plane_tracks(&clip->tracking); const int framenr = ED_space_clip_get_clip_frame_number(sc); /* Update coordinates of modified plane tracks. */ - for (MovieTrackingPlaneTrack *plane_track = plane_tracks_base->first; plane_track; - plane_track = plane_track->next) { + LISTBASE_FOREACH (MovieTrackingPlaneTrack *, plane_track, plane_tracks_base) { bool do_update = false; if (plane_track->flag & PLANE_TRACK_HIDDEN) { continue; @@ -1728,11 +1824,11 @@ static void special_aftertrans_update__mask(bContext *C, TransInfo *t) Mask *mask = NULL; if (t->spacetype == SPACE_CLIP) { - SpaceClip *sc = t->sa->spacedata.first; + SpaceClip *sc = t->area->spacedata.first; mask = ED_space_clip_get_mask(sc); } else if (t->spacetype == SPACE_IMAGE) { - SpaceImage *sima = t->sa->spacedata.first; + SpaceImage *sima = t->area->spacedata.first; mask = ED_space_image_get_mask(sima); } else { @@ -1763,7 +1859,7 @@ static void special_aftertrans_update__node(bContext *C, TransInfo *t) if (canceled && t->remove_on_cancel) { /* remove selected nodes on cancel */ - SpaceNode *snode = (SpaceNode *)t->sa->spacedata.first; + SpaceNode *snode = (SpaceNode *)t->area->spacedata.first; bNodeTree *ntree = snode->edittree; if (ntree) { bNode *node, *node_next; @@ -1779,8 +1875,8 @@ static void special_aftertrans_update__node(bContext *C, TransInfo *t) static void special_aftertrans_update__mesh(bContext *UNUSED(C), TransInfo *t) { - /* so automerge supports mirror */ - if ((t->scene->toolsettings->automerge) && ((t->flag & T_EDIT) && t->obedit_type == OB_MESH)) { + bool use_automerge = (t->flag & (T_AUTOMERGE | T_AUTOSPLIT)) != 0; + if (use_automerge && ((t->flag & T_EDIT) && t->obedit_type == OB_MESH)) { FOREACH_TRANS_DATA_CONTAINER (t, tc) { BMEditMesh *em = BKE_editmesh_from_object(tc->obedit); @@ -1806,14 +1902,12 @@ static void special_aftertrans_update__mesh(bContext *UNUSED(C), TransInfo *t) hflag = BM_ELEM_SELECT; } - if (t->scene->toolsettings->automerge & AUTO_MERGE) { - if (t->scene->toolsettings->automerge & AUTO_MERGE_AND_SPLIT) { - EDBM_automerge_and_split( - tc->obedit, true, true, true, hflag, t->scene->toolsettings->doublimit); - } - else { - EDBM_automerge(tc->obedit, true, hflag, t->scene->toolsettings->doublimit); - } + if (t->flag & T_AUTOSPLIT) { + EDBM_automerge_and_split( + tc->obedit, true, true, true, hflag, t->scene->toolsettings->doublimit); + } + else { + EDBM_automerge(tc->obedit, true, hflag, t->scene->toolsettings->doublimit); } /* Special case, this is needed or faces won't re-select. @@ -1870,13 +1964,9 @@ void special_aftertrans_update(bContext *C, TransInfo *t) } else { if (t->mode == TFM_EDGE_SLIDE) { - EdgeSlideParams *slp = t->custom.mode.data; - slp->perc = 0.0; projectEdgeSlideData(t, false); } else if (t->mode == TFM_VERT_SLIDE) { - EdgeSlideParams *slp = t->custom.mode.data; - slp->perc = 0.0; projectVertSlideData(t, false); } } @@ -1890,7 +1980,7 @@ void special_aftertrans_update(bContext *C, TransInfo *t) /* freeSeqData in transform_conversions.c does this * keep here so the else at the end wont run... */ - SpaceSeq *sseq = (SpaceSeq *)t->sa->spacedata.first; + SpaceSeq *sseq = (SpaceSeq *)t->area->spacedata.first; /* Marker transform, not especially nice but we may want to move markers * at the same time as strips in the Video Sequencer. */ @@ -1916,16 +2006,16 @@ void special_aftertrans_update(bContext *C, TransInfo *t) } } else if (t->spacetype == SPACE_NODE) { - SpaceNode *snode = (SpaceNode *)t->sa->spacedata.first; + SpaceNode *snode = (SpaceNode *)t->area->spacedata.first; special_aftertrans_update__node(C, t); if (canceled == 0) { ED_node_post_apply_transform(C, snode->edittree); - ED_node_link_insert(bmain, t->sa); + ED_node_link_insert(bmain, t->area); } /* clear link line */ - ED_node_link_intersect_test(t->sa, 0); + ED_node_link_intersect_test(t->area, 0); } else if (t->spacetype == SPACE_CLIP) { if (t->options & CTX_MOVIECLIP) { @@ -1936,7 +2026,7 @@ void special_aftertrans_update(bContext *C, TransInfo *t) } } else if (t->spacetype == SPACE_ACTION) { - SpaceAction *saction = (SpaceAction *)t->sa->spacedata.first; + SpaceAction *saction = (SpaceAction *)t->area->spacedata.first; bAnimContext ac; /* initialize relevant anim-context 'context' data */ @@ -2015,15 +2105,24 @@ void special_aftertrans_update(bContext *C, TransInfo *t) * but we made duplicates, so get rid of these */ if ((saction->flag & SACTION_NOTRANSKEYCULL) == 0 && ((canceled == 0) || (duplicate))) { - bGPdata *gpd; + ListBase anim_data = {NULL, NULL}; + const int filter = ANIMFILTER_DATA_VISIBLE; + ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype); - // XXX: BAD! this get gpencil datablocks directly from main db... - // but that's how this currently works :/ - for (gpd = bmain->gpencils.first; gpd; gpd = gpd->id.next) { - if (ID_REAL_USERS(gpd)) { - posttrans_gpd_clean(gpd); + LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) { + if (ale->datatype == ALE_GPFRAME) { + ale->id->tag |= LIB_TAG_DOIT; + } + } + LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) { + if (ale->datatype == ALE_GPFRAME) { + if (ale->id->tag & LIB_TAG_DOIT) { + ale->id->tag &= ~LIB_TAG_DOIT; + posttrans_gpd_clean((bGPdata *)ale->id); + } } } + ANIM_animdata_freelist(&anim_data); } } else if (ac.datatype == ANIMCONT_MASK) { @@ -2037,15 +2136,24 @@ void special_aftertrans_update(bContext *C, TransInfo *t) * User canceled the transform, but we made duplicates, so get rid of these. */ if ((saction->flag & SACTION_NOTRANSKEYCULL) == 0 && ((canceled == 0) || (duplicate))) { - Mask *mask; + ListBase anim_data = {NULL, NULL}; + const int filter = ANIMFILTER_DATA_VISIBLE; + ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype); - // XXX: BAD! this get gpencil datablocks directly from main db... - // but that's how this currently works :/ - for (mask = bmain->masks.first; mask; mask = mask->id.next) { - if (ID_REAL_USERS(mask)) { - posttrans_mask_clean(mask); + LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) { + if (ale->datatype == ALE_MASKLAY) { + ale->id->tag |= LIB_TAG_DOIT; } } + LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) { + if (ale->datatype == ALE_MASKLAY) { + if (ale->id->tag & LIB_TAG_DOIT) { + ale->id->tag &= ~LIB_TAG_DOIT; + posttrans_mask_clean((Mask *)ale->id); + } + } + } + ANIM_animdata_freelist(&anim_data); } } @@ -2074,7 +2182,7 @@ void special_aftertrans_update(bContext *C, TransInfo *t) } /* make sure all F-Curves are set correctly */ - if (!ELEM(ac.datatype, ANIMCONT_GPENCIL, ANIMCONT_MASK)) { + if (!ELEM(ac.datatype, ANIMCONT_GPENCIL)) { ANIM_editkeyframes_refresh(&ac); } @@ -2082,7 +2190,7 @@ void special_aftertrans_update(bContext *C, TransInfo *t) saction->flag &= ~SACTION_MOVING; } else if (t->spacetype == SPACE_GRAPH) { - SpaceGraph *sipo = (SpaceGraph *)t->sa->spacedata.first; + SpaceGraph *sipo = (SpaceGraph *)t->area->spacedata.first; bAnimContext ac; const bool use_handle = (sipo->flag & SIPO_NOHANDLES) == 0; @@ -2171,9 +2279,8 @@ void special_aftertrans_update(bContext *C, TransInfo *t) else if (t->flag & T_EDIT) { if (t->obedit_type == OB_MESH) { FOREACH_TRANS_DATA_CONTAINER (t, tc) { - BMEditMesh *em = BKE_editmesh_from_object(tc->obedit); /* table needs to be created for each edit command, since vertices can move etc */ - ED_mesh_mirror_spatial_table(tc->obedit, em, NULL, NULL, 'e'); + ED_mesh_mirror_spatial_table_end(tc->obedit); /* TODO(campbell): xform: We need support for many mirror objects at once! */ break; } @@ -2208,7 +2315,7 @@ void special_aftertrans_update(bContext *C, TransInfo *t) /* set BONE_TRANSFORM flags for autokey, gizmo draw might have changed them */ if (!canceled && (t->mode != TFM_DUMMY)) { - count_set_pose_transflags(ob, t->mode, t->around, NULL); + transform_convert_pose_transflags_update(ob, t->mode, t->around, NULL); } /* if target-less IK grabbing, we calculate the pchan transforms and clear flag */ @@ -2360,6 +2467,10 @@ int special_transform_moving(TransInfo *t) /** \} */ +/* -------------------------------------------------------------------- */ +/** \name Transform Data Create + * \{ */ + static int countAndCleanTransDataContainer(TransInfo *t) { BLI_assert(ELEM(t->data_len_all, 0, -1)); @@ -2518,7 +2629,7 @@ void createTransData(bContext *C, TransInfo *t) t->obedit_type = -1; t->num.flag |= NUM_NO_FRACTION; /* sequencer has no use for floating point trasnform */ - createTransSeqData(C, t); + createTransSeqData(t); countAndCleanTransDataContainer(t); } else if (t->spacetype == SPACE_GRAPH) { @@ -2659,7 +2770,7 @@ void createTransData(bContext *C, TransInfo *t) /* important that ob_armature can be set even when its not selected [#23412] * lines below just check is also visible */ has_transform_context = false; - Object *ob_armature = modifiers_isDeformedByArmature(ob); + Object *ob_armature = BKE_modifiers_is_deformed_by_armature(ob); if (ob_armature && ob_armature->mode & OB_MODE_POSE) { Base *base_arm = BKE_view_layer_base_find(t->view_layer, ob_armature); if (base_arm) { @@ -2698,9 +2809,11 @@ void createTransData(bContext *C, TransInfo *t) has_transform_context = false; } } - else if ((ob) && - (ELEM( - ob->mode, OB_MODE_PAINT_GPENCIL, OB_MODE_SCULPT_GPENCIL, OB_MODE_WEIGHT_GPENCIL))) { + else if ((ob) && (ELEM(ob->mode, + OB_MODE_PAINT_GPENCIL, + OB_MODE_SCULPT_GPENCIL, + OB_MODE_WEIGHT_GPENCIL, + OB_MODE_VERTEX_GPENCIL))) { /* In grease pencil all transformations must be canceled if not Object or Edit. */ has_transform_context = false; } @@ -2726,16 +2839,16 @@ void createTransData(bContext *C, TransInfo *t) } /* Check if we're transforming the camera from the camera */ - if ((t->spacetype == SPACE_VIEW3D) && (t->ar->regiontype == RGN_TYPE_WINDOW)) { + if ((t->spacetype == SPACE_VIEW3D) && (t->region->regiontype == RGN_TYPE_WINDOW)) { View3D *v3d = t->view; - RegionView3D *rv3d = t->ar->regiondata; + RegionView3D *rv3d = t->region->regiondata; if ((rv3d->persp == RV3D_CAMOB) && v3d->camera) { /* we could have a flag to easily check an object is being transformed */ if (v3d->camera->id.tag & LIB_TAG_DOIT) { t->flag |= T_CAMERA; } } - else if (v3d->ob_centre && v3d->ob_centre->id.tag & LIB_TAG_DOIT) { + else if (v3d->ob_center && v3d->ob_center->id.tag & LIB_TAG_DOIT) { t->flag |= T_CAMERA; } } @@ -2752,3 +2865,5 @@ void createTransData(bContext *C, TransInfo *t) BLI_assert((!(t->flag & T_EDIT)) == (!(t->obedit_type != -1))); } + +/** \} */ diff --git a/source/blender/editors/transform/transform_convert.h b/source/blender/editors/transform/transform_convert.h index 53ff9952d05..e5d758135e2 100644 --- a/source/blender/editors/transform/transform_convert.h +++ b/source/blender/editors/transform/transform_convert.h @@ -19,6 +19,7 @@ /** \file * \ingroup edtransform + * \brief conversion and adaptation of different datablocks to a common struct. */ #ifndef __TRANSFORM_CONVERT_H__ @@ -36,10 +37,10 @@ struct bKinematicConstraint; struct bPoseChannel; /* transform_convert.c */ -int count_set_pose_transflags(Object *ob, - const int mode, - const short around, - bool has_translate_rotate[2]); +int transform_convert_pose_transflags_update(Object *ob, + const int mode, + const short around, + bool has_translate_rotate[2]); void transform_autoik_update(TransInfo *t, short mode); void autokeyframe_object(struct bContext *C, struct Scene *scene, @@ -60,81 +61,111 @@ void clipUVData(TransInfo *t); /* transform_convert_action.c */ void flushTransIntFrameActionData(TransInfo *t); + /* transform_convert_armature.c */ +void pose_transform_mirror_update(TransInfo *t, TransDataContainer *tc, Object *ob); void restoreMirrorPoseBones(TransDataContainer *tc); void restoreBones(TransDataContainer *tc); + /* transform_convert_graph.c */ void flushTransGraphData(TransInfo *t); + /* transform_convert_mask.c */ void flushTransMasking(TransInfo *t); + /* transform_convert_mesh.c */ void flushTransUVs(TransInfo *t); void trans_mesh_customdata_correction_init(TransInfo *t); void trans_mesh_customdata_correction_apply(struct TransDataContainer *tc, bool is_final); + /* transform_convert_node.c */ void flushTransNodes(TransInfo *t); + /* transform_convert_object.c */ void trans_obdata_in_obmode_update_all(struct TransInfo *t); void trans_obchild_in_obmode_update_all(struct TransInfo *t); + /* transform_convert_paintcurve.c */ void flushTransPaintCurve(TransInfo *t); + /* transform_convert_particle.c */ void flushTransParticles(TransInfo *t); + /* transform_convert_sequencer.c */ void flushTransSeq(TransInfo *t); + /* transform_convert_tracking.c */ void flushTransTracking(TransInfo *t); /********************* intern **********************/ /* transform_convert.c */ +bool transform_mode_use_local_origins(const TransInfo *t); void transform_around_single_fallback(TransInfo *t); bool constraints_list_needinv(TransInfo *t, ListBase *list); void calc_distanceCurveVerts(TransData *head, TransData *tail); struct TransDataCurveHandleFlags *initTransDataCurveHandles(TransData *td, struct BezTriple *bezt); +char transform_convert_frame_side_dir_get(TransInfo *t, float cframe); bool FrameOnMouseSide(char side, float frame, float cframe); /* transform_convert_action.c */ void createTransActionData(bContext *C, TransInfo *t); + /* transform_convert_armature.c */ struct bKinematicConstraint *has_targetless_ik(struct bPoseChannel *pchan); void createTransPose(TransInfo *t); void createTransArmatureVerts(TransInfo *t); + /* transform_convert_cursor.c */ void createTransCursor_image(TransInfo *t); void createTransCursor_view3d(TransInfo *t); + /* transform_convert_curve.c */ void createTransCurveVerts(TransInfo *t); + /* transform_convert_graph.c */ void createTransGraphEditData(bContext *C, TransInfo *t); + /* transform_convert_gpencil.c */ void createTransGPencil(bContext *C, TransInfo *t); + /* transform_convert_lattice.c */ void createTransLatticeVerts(TransInfo *t); + /* transform_convert_mask.c */ void createTransMaskingData(bContext *C, TransInfo *t); + /* transform_convert_mball.c */ void createTransMBallVerts(TransInfo *t); + /* transform_convert_mesh.c */ void createTransEditVerts(TransInfo *t); void createTransEdge(TransInfo *t); void createTransUVs(bContext *C, TransInfo *t); + /* transform_convert_nla.c */ void createTransNlaData(bContext *C, TransInfo *t); + /* transform_convert_node.c */ void createTransNodeData(bContext *UNUSED(C), TransInfo *t); + /* transform_convert_object.c */ void clear_trans_object_base_flags(TransInfo *t); void createTransObject(bContext *C, TransInfo *t); void createTransTexspace(TransInfo *t); + /* transform_convert_paintcurve.c */ void createTransPaintCurveVerts(bContext *C, TransInfo *t); + /* transform_convert_particle.c */ void createTransParticleVerts(bContext *C, TransInfo *t); + /* transform_convert_sculpt.c */ void createTransSculpt(TransInfo *t); + /* transform_convert_sequence.c */ -void createTransSeqData(bContext *C, TransInfo *t); +void createTransSeqData(TransInfo *t); + /* transform_convert_tracking.c */ void createTransTrackingData(bContext *C, TransInfo *t); void cancelTransTracking(TransInfo *t); diff --git a/source/blender/editors/transform/transform_convert_action.c b/source/blender/editors/transform/transform_convert_action.c index 0b1d2757435..21ef1539911 100644 --- a/source/blender/editors/transform/transform_convert_action.c +++ b/source/blender/editors/transform/transform_convert_action.c @@ -30,14 +30,12 @@ #include "BLI_math.h" #include "BLI_rect.h" -#include "BKE_nla.h" #include "BKE_context.h" +#include "BKE_nla.h" #include "BKE_report.h" #include "ED_anim_api.h" -#include "UI_view2d.h" - #include "transform.h" #include "transform_convert.h" @@ -299,8 +297,8 @@ void createTransActionData(bContext *C, TransInfo *t) TransData2D *td2d = NULL; tGPFtransdata *tfd = NULL; - rcti *mask = &t->ar->v2d.mask; - rctf *datamask = &t->ar->v2d.cur; + rcti *mask = &t->region->v2d.mask; + rctf *datamask = &t->region->v2d.cur; float xsize = BLI_rctf_size_x(datamask); float ysize = BLI_rctf_size_y(datamask); @@ -315,7 +313,7 @@ void createTransActionData(bContext *C, TransInfo *t) int count = 0; float cfra; - float ypos = 1.0f / ((ysize / xsize) * (xmask / ymask)) * BLI_rctf_cent_y(&t->ar->v2d.cur); + float ypos = 1.0f / ((ysize / xsize) * (xmask / ymask)) * BLI_rctf_cent_y(&t->region->v2d.cur); /* determine what type of data we are operating on */ if (ANIM_animdata_get_context(C, &ac) == 0) { @@ -333,11 +331,7 @@ void createTransActionData(bContext *C, TransInfo *t) /* which side of the current frame should be allowed */ if (t->mode == TFM_TIME_EXTEND) { - /* only side on which mouse is gets transformed */ - float xmouse, ymouse; - - UI_view2d_region_to_view(&ac.ar->v2d, t->mouse.imval[0], t->mouse.imval[1], &xmouse, &ymouse); - t->frame_side = (xmouse > CFRA) ? 'R' : 'L'; // XXX use t->frame_side + t->frame_side = transform_convert_frame_side_dir_get(t, (float)CFRA); } else { /* normal transform - both sides of current frame are considered */ diff --git a/source/blender/editors/transform/transform_convert_armature.c b/source/blender/editors/transform/transform_convert_armature.c index 0edf55ece7e..35bb7e3f0d8 100644 --- a/source/blender/editors/transform/transform_convert_armature.c +++ b/source/blender/editors/transform/transform_convert_armature.c @@ -26,6 +26,7 @@ #include "MEM_guardedalloc.h" +#include "BLI_listbase.h" #include "BLI_math.h" #include "BKE_action.h" @@ -45,23 +46,47 @@ #include "transform.h" #include "transform_convert.h" -bKinematicConstraint *has_targetless_ik(bPoseChannel *pchan) +typedef struct BoneInitData { + struct EditBone *bone; + float tail[3]; + float rad_head; + float rad_tail; + float roll; + float head[3]; + float dist; + float xwidth; + float zwidth; +} BoneInitData; + +static bConstraint *add_temporary_ik_constraint(bPoseChannel *pchan, + bKinematicConstraint *targetless_con) { - bConstraint *con = pchan->constraints.first; + bConstraint *con = BKE_constraint_add_for_pose( + NULL, pchan, "TempConstraint", CONSTRAINT_TYPE_KINEMATIC); - for (; con; con = con->next) { - if (con->type == CONSTRAINT_TYPE_KINEMATIC && (con->enforce != 0.0f)) { - bKinematicConstraint *data = con->data; + /* for draw, but also for detecting while pose solving */ + pchan->constflag |= (PCHAN_HAS_IK | PCHAN_HAS_TARGET); - if (data->tar == NULL) { - return data; - } - if (data->tar->type == OB_ARMATURE && data->subtarget[0] == 0) { - return data; - } - } + bKinematicConstraint *temp_con_data = con->data; + + if (targetless_con) { + /* if exists, use values from last targetless (but disabled) IK-constraint as base */ + *temp_con_data = *targetless_con; } - return NULL; + else { + temp_con_data->flag = CONSTRAINT_IK_TIP; + } + + temp_con_data->flag |= CONSTRAINT_IK_TEMP | CONSTRAINT_IK_AUTO | CONSTRAINT_IK_POS; + + return con; +} + +static void update_deg_with_temporary_ik(Main *bmain, Object *ob) +{ + BIK_clear_data(ob->pose); + /* TODO(sergey): Consider doing partial update only. */ + DEG_relations_tag_update(bmain); } static void add_pose_transdata( @@ -206,8 +231,16 @@ static void add_pose_transdata( } td->loc = data->grabtarget; copy_v3_v3(td->iloc, td->loc); + data->flag |= CONSTRAINT_IK_AUTO; + /* Add a temporary auto IK constraint here, as we will only temporarily active this + * targetless bone during transform. (Targetless IK constraints are treated as if they are + * disabled unless they are transformed). */ + add_temporary_ik_constraint(pchan, data); + Main *bmain = CTX_data_main(t->context); + update_deg_with_temporary_ik(bmain, ob); + /* only object matrix correction */ copy_m3_m3(td->mtx, omat); pseudoinverse_m3_m3(td->smtx, td->mtx, PSEUDOINVERSE_EPSILON); @@ -218,6 +251,30 @@ static void add_pose_transdata( td->con = pchan->constraints.first; } +/* -------------------------------------------------------------------- */ +/** \name Pose Auto-IK + * \{ */ + +bKinematicConstraint *has_targetless_ik(bPoseChannel *pchan) +{ + bConstraint *con = pchan->constraints.first; + + for (; con; con = con->next) { + if (con->type == CONSTRAINT_TYPE_KINEMATIC && (con->flag & CONSTRAINT_OFF) == 0 && + (con->enforce != 0.0f)) { + bKinematicConstraint *data = con->data; + + if (data->tar == NULL) { + return data; + } + if (data->tar->type == OB_ARMATURE && data->subtarget[0] == 0) { + return data; + } + } + } + return NULL; +} + /* adds the IK to pchan - returns if added */ static short pose_grab_with_ik_add(bPoseChannel *pchan) { @@ -232,7 +289,7 @@ static short pose_grab_with_ik_add(bPoseChannel *pchan) /* Rule: not if there's already an IK on this channel */ for (con = pchan->constraints.first; con; con = con->next) { - if (con->type == CONSTRAINT_TYPE_KINEMATIC) { + if (con->type == CONSTRAINT_TYPE_KINEMATIC && (con->flag & CONSTRAINT_OFF) == 0) { data = con->data; if (data->tar == NULL || (data->tar->type == OB_ARMATURE && data->subtarget[0] == '\0')) { @@ -247,22 +304,20 @@ static short pose_grab_with_ik_add(bPoseChannel *pchan) /* if no chain length has been specified, * just make things obey standard rotation locks too */ if (data->rootbone == 0) { - for (; pchan; pchan = pchan->parent) { + for (bPoseChannel *pchan_iter = pchan; pchan_iter; pchan_iter = pchan_iter->parent) { /* here, we set ik-settings for bone from pchan->protectflag */ // XXX: careful with quats/axis-angle rotations where we're locking 4d components - if (pchan->protectflag & OB_LOCK_ROTX) { - pchan->ikflag |= BONE_IK_NO_XDOF_TEMP; + if (pchan_iter->protectflag & OB_LOCK_ROTX) { + pchan_iter->ikflag |= BONE_IK_NO_XDOF_TEMP; } - if (pchan->protectflag & OB_LOCK_ROTY) { - pchan->ikflag |= BONE_IK_NO_YDOF_TEMP; + if (pchan_iter->protectflag & OB_LOCK_ROTY) { + pchan_iter->ikflag |= BONE_IK_NO_YDOF_TEMP; } - if (pchan->protectflag & OB_LOCK_ROTZ) { - pchan->ikflag |= BONE_IK_NO_ZDOF_TEMP; + if (pchan_iter->protectflag & OB_LOCK_ROTZ) { + pchan_iter->ikflag |= BONE_IK_NO_ZDOF_TEMP; } } } - - return 0; } } @@ -272,20 +327,8 @@ static short pose_grab_with_ik_add(bPoseChannel *pchan) } } - con = BKE_constraint_add_for_pose(NULL, pchan, "TempConstraint", CONSTRAINT_TYPE_KINEMATIC); + data = add_temporary_ik_constraint(pchan, targetless)->data; - /* for draw, but also for detecting while pose solving */ - pchan->constflag |= (PCHAN_HAS_IK | PCHAN_HAS_TARGET); - - data = con->data; - if (targetless) { - /* if exists, use values from last targetless (but disabled) IK-constraint as base */ - *data = *targetless; - } - else { - data->flag = CONSTRAINT_IK_TIP; - } - data->flag |= CONSTRAINT_IK_TEMP | CONSTRAINT_IK_AUTO | CONSTRAINT_IK_POS; copy_v3_v3(data->grabtarget, pchan->pose_tail); /* watch-it! has to be 0 here, since we're still on the @@ -398,14 +441,42 @@ static short pose_grab_with_ik(Main *bmain, Object *ob) /* iTaSC needs clear for new IK constraints */ if (tot_ik) { - BIK_clear_data(ob->pose); - /* TODO(sergey): Consider doing partial update only. */ - DEG_relations_tag_update(bmain); + update_deg_with_temporary_ik(bmain, ob); } return (tot_ik) ? 1 : 0; } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Pose Mirror + * \{ */ + +typedef struct PoseInitData_Mirror { + /** Points to the bone which this info is initialized & restored to. + * A NULL value is used to terminate the array. */ + struct bPoseChannel *pchan; + struct { + float loc[3]; + float size[3]; + union { + float eul[3]; + float quat[4]; + float axis_angle[4]; + }; + float curve_in_x; + float curve_out_x; + float roll1; + float roll2; + } orig; + /** + * An extra offset to apply after mirroring. + * Use with #POSE_MIRROR_RELATIVE. + */ + float offset_mtx[4][4]; +} PoseInitData_Mirror; + static void pose_mirror_info_init(PoseInitData_Mirror *pid, bPoseChannel *pchan, bPoseChannel *pchan_orig, @@ -475,6 +546,103 @@ static void pose_mirror_info_restore(const PoseInitData_Mirror *pid) } /** + * if pose bone (partial) selected, copy data. + * context; posemode armature, with mirror editing enabled. + */ +void pose_transform_mirror_update(TransInfo *t, TransDataContainer *tc, Object *ob) +{ + float flip_mtx[4][4]; + unit_m4(flip_mtx); + flip_mtx[0][0] = -1; + + LISTBASE_FOREACH (bPoseChannel *, pchan_orig, &ob->pose->chanbase) { + /* Clear the MIRROR flag from previous runs. */ + pchan_orig->bone->flag &= ~BONE_TRANSFORM_MIRROR; + } + + bPose *pose = ob->pose; + PoseInitData_Mirror *pid = NULL; + if ((t->mode != TFM_BONESIZE) && (pose->flag & POSE_MIRROR_RELATIVE)) { + pid = tc->custom.type.data; + } + + TransData *td = tc->data; + for (int i = tc->data_len; i--; td++) { + bPoseChannel *pchan_orig = td->extra; + BLI_assert(pchan_orig->bone->flag & BONE_TRANSFORM); + /* No layer check, correct mirror is more important. */ + bPoseChannel *pchan = BKE_pose_channel_get_mirrored(pose, pchan_orig->name); + if (pchan == NULL) { + continue; + } + + /* Also do bbone scaling. */ + pchan->bone->xwidth = pchan_orig->bone->xwidth; + pchan->bone->zwidth = pchan_orig->bone->zwidth; + + /* We assume X-axis flipping for now. */ + pchan->curve_in_x = pchan_orig->curve_in_x * -1; + pchan->curve_out_x = pchan_orig->curve_out_x * -1; + pchan->roll1 = pchan_orig->roll1 * -1; // XXX? + pchan->roll2 = pchan_orig->roll2 * -1; // XXX? + + float pchan_mtx_final[4][4]; + BKE_pchan_to_mat4(pchan_orig, pchan_mtx_final); + mul_m4_m4m4(pchan_mtx_final, pchan_mtx_final, flip_mtx); + mul_m4_m4m4(pchan_mtx_final, flip_mtx, pchan_mtx_final); + if (pid) { + mul_m4_m4m4(pchan_mtx_final, pid->offset_mtx, pchan_mtx_final); + } + BKE_pchan_apply_mat4(pchan, pchan_mtx_final, false); + + /* Set flag to let autokeyframe know to keyframe the mirrred bone. */ + pchan->bone->flag |= BONE_TRANSFORM_MIRROR; + + /* In this case we can do target-less IK grabbing. */ + if (t->mode == TFM_TRANSLATION) { + bKinematicConstraint *data = has_targetless_ik(pchan); + if (data == NULL) { + continue; + } + mul_v3_m4v3(data->grabtarget, flip_mtx, td->loc); + if (pid) { + /* TODO(germano): Realitve Mirror support */ + } + data->flag |= CONSTRAINT_IK_AUTO; + /* Add a temporary auto IK constraint here, as we will only temporarily active this + * target-less bone during transform. (Target-less IK constraints are treated as if they are + * disabled unless they are transformed) */ + add_temporary_ik_constraint(pchan, data); + Main *bmain = CTX_data_main(t->context); + update_deg_with_temporary_ik(bmain, ob); + } + + if (pid) { + pid++; + } + } +} + +void restoreMirrorPoseBones(TransDataContainer *tc) +{ + bPose *pose = tc->poseobj->pose; + + if (!(pose->flag & POSE_MIRROR_EDIT)) { + return; + } + + for (PoseInitData_Mirror *pid = tc->custom.type.data; pid->pchan; pid++) { + pose_mirror_info_restore(pid); + } +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Convert Armature + * \{ */ + +/** * When objects array is NULL, use 't->data_container' as is. */ void createTransPose(TransInfo *t) @@ -501,7 +669,9 @@ void createTransPose(TransInfo *t) const bool mirror = ((pose->flag & POSE_MIRROR_EDIT) != 0); /* set flags and count total */ - tc->data_len = count_set_pose_transflags(ob, t->mode, t->around, has_translate_rotate); + tc->data_len = transform_convert_pose_transflags_update( + ob, t->mode, t->around, has_translate_rotate); + if (tc->data_len == 0) { continue; } @@ -516,7 +686,10 @@ void createTransPose(TransInfo *t) if (mirror) { int total_mirrored = 0; - for (bPoseChannel *pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) { + LISTBASE_FOREACH (bPoseChannel *, pchan, &ob->pose->chanbase) { + /* Clear the MIRROR flag from previous runs. */ + pchan->bone->flag &= ~BONE_TRANSFORM_MIRROR; + if ((pchan->bone->flag & BONE_TRANSFORM) && BKE_pose_channel_get_mirrored(ob->pose, pchan->name)) { total_mirrored++; @@ -566,7 +739,7 @@ void createTransPose(TransInfo *t) } if (mirror) { - for (bPoseChannel *pchan = pose->chanbase.first; pchan; pchan = pchan->next) { + LISTBASE_FOREACH (bPoseChannel *, pchan, &pose->chanbase) { if (pchan->bone->flag & BONE_TRANSFORM) { bPoseChannel *pchan_mirror = BKE_pose_channel_get_mirrored(ob->pose, pchan->name); if (pchan_mirror) { @@ -588,7 +761,7 @@ void createTransPose(TransInfo *t) /* use pose channels to fill trans data */ td = tc->data; - for (bPoseChannel *pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) { + LISTBASE_FOREACH (bPoseChannel *, pchan, &ob->pose->chanbase) { if (pchan->bone->flag & BONE_TRANSFORM) { add_pose_transdata(t, pchan, ob, tc, td); td++; @@ -620,19 +793,6 @@ void createTransPose(TransInfo *t) t->flag &= ~T_PROP_EDIT_ALL; } -void restoreMirrorPoseBones(TransDataContainer *tc) -{ - bPose *pose = tc->poseobj->pose; - - if (!(pose->flag & POSE_MIRROR_EDIT)) { - return; - } - - for (PoseInitData_Mirror *pid = tc->custom.type.data; pid->pchan; pid++) { - pose_mirror_info_restore(pid); - } -} - void restoreBones(TransDataContainer *tc) { bArmature *arm; @@ -682,7 +842,6 @@ void restoreBones(TransDataContainer *tc) } } -/* ********************* armature ************** */ void createTransArmatureVerts(TransInfo *t) { t->data_len_all = 0; @@ -936,3 +1095,5 @@ void createTransArmatureVerts(TransInfo *t) } } } + +/** \} */ diff --git a/source/blender/editors/transform/transform_convert_cursor.c b/source/blender/editors/transform/transform_convert_cursor.c index 621f9dd63e2..e6a972bfc7c 100644 --- a/source/blender/editors/transform/transform_convert_cursor.c +++ b/source/blender/editors/transform/transform_convert_cursor.c @@ -44,7 +44,7 @@ void createTransCursor_image(TransInfo *t) { TransData *td; - SpaceImage *sima = t->sa->spacedata.first; + SpaceImage *sima = t->area->spacedata.first; float *cursor_location = sima->cursor; { diff --git a/source/blender/editors/transform/transform_convert_curve.c b/source/blender/editors/transform/transform_convert_curve.c index 487de27aff2..42ffe675dc5 100644 --- a/source/blender/editors/transform/transform_convert_curve.c +++ b/source/blender/editors/transform/transform_convert_curve.c @@ -25,11 +25,11 @@ #include "MEM_guardedalloc.h" +#include "BLI_listbase.h" #include "BLI_math.h" #include "BKE_context.h" #include "BKE_curve.h" -#include "BKE_report.h" #include "transform.h" #include "transform_convert.h" @@ -99,7 +99,7 @@ void createTransCurveVerts(TransInfo *t) /* count total of vertices, check identical as in 2nd loop for making transdata! */ ListBase *nurbs = BKE_curve_editNurbs_get(cu); - for (Nurb *nu = nurbs->first; nu; nu = nu->next) { + LISTBASE_FOREACH (Nurb *, nu, nurbs) { if (nu->type == CU_BEZIER) { for (a = 0, bezt = nu->bezt; a < nu->pntsu; a++, bezt++) { if (bezt->hide == 0) { @@ -167,6 +167,8 @@ void createTransCurveVerts(TransInfo *t) ((v3d->overlay.edit_flag & V3D_OVERLAY_EDIT_CU_HANDLES) == 0) : false; + bool use_around_origins_for_handles_test = ((t->around == V3D_AROUND_LOCAL_ORIGINS) && + transform_mode_use_local_origins(t)); float mtx[3][3], smtx[3][3]; copy_m3_m4(mtx, tc->obedit->obmat); @@ -174,7 +176,7 @@ void createTransCurveVerts(TransInfo *t) TransData *td = tc->data; ListBase *nurbs = BKE_curve_editNurbs_get(cu); - for (Nurb *nu = nurbs->first; nu; nu = nu->next) { + LISTBASE_FOREACH (Nurb *, nu, nurbs) { if (nu->type == CU_BEZIER) { TransData *head, *tail; head = tail = td; @@ -342,7 +344,7 @@ void createTransCurveVerts(TransInfo *t) if (ELEM(t->mode, TFM_CURVE_SHRINKFATTEN, TFM_TILT, TFM_DUMMY) == 0) { /* sets the handles based on their selection, * do this after the data is copied to the TransData */ - BKE_nurb_handles_test(nu, !hide_handles); + BKE_nurb_handles_test(nu, !hide_handles, use_around_origins_for_handles_test); } } else { diff --git a/source/blender/editors/transform/transform_convert_gpencil.c b/source/blender/editors/transform/transform_convert_gpencil.c index 80c0afc3f56..efd7879c8b2 100644 --- a/source/blender/editors/transform/transform_convert_gpencil.c +++ b/source/blender/editors/transform/transform_convert_gpencil.c @@ -30,7 +30,6 @@ #include "BKE_colortools.h" #include "BKE_context.h" #include "BKE_gpencil.h" -#include "BKE_report.h" #include "ED_gpencil.h" @@ -84,6 +83,8 @@ void createTransGPencil(bContext *C, TransInfo *t) const bool is_prop_edit = (t->flag & T_PROP_EDIT) != 0; const bool is_prop_edit_connected = (t->flag & T_PROP_CONNECTED) != 0; + const bool is_scale_thickness = ((t->mode == TFM_GPENCIL_SHRINKFATTEN) || + (ts->gp_sculpt.flag & GP_SCULPT_SETT_FLAG_SCALE_THICKNESS)); TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t); @@ -109,7 +110,7 @@ void createTransGPencil(bContext *C, TransInfo *t) */ for (gpl = gpd->layers.first; gpl; gpl = gpl->next) { /* only editable and visible layers are considered */ - if (gpencil_layer_is_editable(gpl) && (gpl->actframe != NULL)) { + if (BKE_gpencil_layer_is_editable(gpl) && (gpl->actframe != NULL)) { bGPDframe *gpf; bGPDstroke *gps; bGPDframe *init_gpf = gpl->actframe; @@ -181,7 +182,7 @@ void createTransGPencil(bContext *C, TransInfo *t) /* Second Pass: Build transdata array */ for (gpl = gpd->layers.first; gpl; gpl = gpl->next) { /* only editable and visible layers are considered */ - if (gpencil_layer_is_editable(gpl) && (gpl->actframe != NULL)) { + if (BKE_gpencil_layer_is_editable(gpl) && (gpl->actframe != NULL)) { const int cfra = (gpl->flag & GP_LAYER_FRAMELOCK) ? gpl->actframe->framenum : cfra_scene; bGPDframe *gpf = gpl->actframe; bGPDstroke *gps; @@ -197,11 +198,11 @@ void createTransGPencil(bContext *C, TransInfo *t) int f_end = 0; if (use_multiframe_falloff) { - BKE_gpencil_get_range_selected(gpl, &f_init, &f_end); + BKE_gpencil_frame_range_selected(gpl, &f_init, &f_end); } /* calculate difference matrix */ - ED_gpencil_parent_location(depsgraph, obact, gpd, gpl, diff_mat); + BKE_gpencil_parent_matrix_get(depsgraph, obact, gpl, diff_mat); /* undo matrix */ invert_m4_m4(inverse_diff_mat, diff_mat); @@ -227,10 +228,11 @@ void createTransGPencil(bContext *C, TransInfo *t) for (gpf = init_gpf; gpf; gpf = gpf->next) { if ((gpf == gpl->actframe) || ((gpf->flag & GP_FRAME_SELECT) && (is_multiedit))) { - /* if multiframe and falloff, recalculate and save value */ + /* If multi-frame and falloff, recalculate and save value. */ float falloff = 1.0f; /* by default no falloff */ if ((is_multiedit) && (use_multiframe_falloff)) { - /* Faloff depends on distance to active frame (relative to the overall frame range) */ + /* Falloff depends on distance to active frame + * (relative to the overall frame range). */ falloff = BKE_gpencil_multiframe_falloff_calc( gpf, gpl->actframe->framenum, f_init, f_end, ts->gp_sculpt.cur_falloff); } @@ -313,9 +315,9 @@ void createTransGPencil(bContext *C, TransInfo *t) } /* for other transform modes (e.g. shrink-fatten), need to additional data - * but never for scale or mirror + * but never for mirror */ - if ((t->mode != TFM_RESIZE) && (t->mode != TFM_MIRROR)) { + if ((t->mode != TFM_MIRROR) && (is_scale_thickness)) { if (t->mode != TFM_GPENCIL_OPACITY) { td->val = &pt->pressure; td->ival = pt->pressure; diff --git a/source/blender/editors/transform/transform_convert_graph.c b/source/blender/editors/transform/transform_convert_graph.c index f6f982e854a..f6f0dd3c491 100644 --- a/source/blender/editors/transform/transform_convert_graph.c +++ b/source/blender/editors/transform/transform_convert_graph.c @@ -1,4 +1,4 @@ -/* +/* * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 @@ -167,7 +167,7 @@ static void graph_bezt_get_transform_selection(const TransInfo *t, bool *r_key, bool *r_right_handle) { - SpaceGraph *sipo = (SpaceGraph *)t->sa->spacedata.first; + SpaceGraph *sipo = (SpaceGraph *)t->area->spacedata.first; bool key = (bezt->f2 & SELECT) != 0; bool left = use_handle ? ((bezt->f1 & SELECT) != 0) : key; bool right = use_handle ? ((bezt->f3 & SELECT) != 0) : key; @@ -224,10 +224,10 @@ static void graph_key_shortest_dist( */ void createTransGraphEditData(bContext *C, TransInfo *t) { - SpaceGraph *sipo = (SpaceGraph *)t->sa->spacedata.first; + SpaceGraph *sipo = (SpaceGraph *)t->area->spacedata.first; Scene *scene = t->scene; - ARegion *ar = t->ar; - View2D *v2d = &ar->v2d; + ARegion *region = t->region; + View2D *v2d = ®ion->v2d; TransData *td = NULL; TransData2D *td2d = NULL; @@ -261,11 +261,7 @@ void createTransGraphEditData(bContext *C, TransInfo *t) /* which side of the current frame should be allowed */ // XXX we still want this mode, but how to get this using standard transform too? if (t->mode == TFM_TIME_EXTEND) { - /* only side on which mouse is gets transformed */ - float xmouse, ymouse; - - UI_view2d_region_to_view(v2d, t->mouse.imval[0], t->mouse.imval[1], &xmouse, &ymouse); - t->frame_side = (xmouse > CFRA) ? 'R' : 'L'; // XXX use t->frame_side + t->frame_side = transform_convert_frame_side_dir_get(t, (float)CFRA); } else { /* normal transform - both sides of current frame are considered */ @@ -643,7 +639,7 @@ void createTransGraphEditData(bContext *C, TransInfo *t) */ void flushTransGraphData(TransInfo *t) { - SpaceGraph *sipo = (SpaceGraph *)t->sa->spacedata.first; + SpaceGraph *sipo = (SpaceGraph *)t->area->spacedata.first; TransData *td; TransData2D *td2d; TransDataGraph *tdg; diff --git a/source/blender/editors/transform/transform_convert_lattice.c b/source/blender/editors/transform/transform_convert_lattice.c index 15af24090f0..57d0f707971 100644 --- a/source/blender/editors/transform/transform_convert_lattice.c +++ b/source/blender/editors/transform/transform_convert_lattice.c @@ -29,7 +29,6 @@ #include "BLI_math.h" #include "BKE_context.h" -#include "BKE_report.h" #include "transform.h" #include "transform_convert.h" diff --git a/source/blender/editors/transform/transform_convert_mask.c b/source/blender/editors/transform/transform_convert_mask.c index 32152442acf..6c743da3e65 100644 --- a/source/blender/editors/transform/transform_convert_mask.c +++ b/source/blender/editors/transform/transform_convert_mask.c @@ -280,7 +280,7 @@ void createTransMaskingData(bContext *C, TransInfo *t) } if (t->spacetype == SPACE_CLIP) { - SpaceClip *sc = t->sa->spacedata.first; + SpaceClip *sc = t->area->spacedata.first; MovieClip *clip = ED_space_clip_get_clip(sc); if (!clip) { return; @@ -333,7 +333,7 @@ void createTransMaskingData(bContext *C, TransInfo *t) return; } - ED_mask_get_aspect(t->sa, t->ar, &asp[0], &asp[1]); + ED_mask_get_aspect(t->area, t->region, &asp[0], &asp[1]); tc->data_len = (is_prop_edit) ? count : countsel; td = tc->data = MEM_callocN(tc->data_len * sizeof(TransData), "TransObData(Mask Editing)"); @@ -409,7 +409,7 @@ void flushTransMasking(TransInfo *t) TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t); - ED_mask_get_aspect(t->sa, t->ar, &asp[0], &asp[1]); + ED_mask_get_aspect(t->area, t->region, &asp[0], &asp[1]); inv[0] = 1.0f / asp[0]; inv[1] = 1.0f / asp[1]; diff --git a/source/blender/editors/transform/transform_convert_mball.c b/source/blender/editors/transform/transform_convert_mball.c index 5d7e36cc834..447733357d6 100644 --- a/source/blender/editors/transform/transform_convert_mball.c +++ b/source/blender/editors/transform/transform_convert_mball.c @@ -28,7 +28,6 @@ #include "BLI_math.h" #include "BKE_context.h" -#include "BKE_report.h" #include "transform.h" #include "transform_convert.h" diff --git a/source/blender/editors/transform/transform_convert_mesh.c b/source/blender/editors/transform/transform_convert_mesh.c index 5d3d1d936a2..24dda8c8464 100644 --- a/source/blender/editors/transform/transform_convert_mesh.c +++ b/source/blender/editors/transform/transform_convert_mesh.c @@ -29,9 +29,9 @@ #include "BLI_alloca.h" #include "BLI_bitmap.h" +#include "BLI_linklist_stack.h" #include "BLI_math.h" #include "BLI_memarena.h" -#include "BLI_linklist_stack.h" #include "BKE_context.h" #include "BKE_crazyspace.h" @@ -61,8 +61,10 @@ /* when transforming islands */ struct TransIslandData { - float co[3]; - float axismtx[3][3]; + float (*center)[3]; + float (*axismtx)[3][3]; + int island_tot; + int *island_vert_map; }; /* -------------------------------------------------------------------- */ @@ -247,18 +249,19 @@ static void editmesh_set_connectivity_distance(BMesh *bm, } } -static struct TransIslandData *editmesh_islands_info_calc(BMEditMesh *em, - int *r_island_tot, - int **r_island_vert_map, - bool calc_single_islands) +static void editmesh_islands_info_calc(BMEditMesh *em, + const bool calc_single_islands, + const bool calc_island_axismtx, + struct TransIslandData *r_island_data) { BMesh *bm = em->bm; - struct TransIslandData *trans_islands; char htype; char itype; int i; /* group vars */ + float(*center)[3]; + float(*axismtx)[3][3] = NULL; int *groups_array; int(*group_index)[2]; int group_tot; @@ -283,7 +286,11 @@ static struct TransIslandData *editmesh_islands_info_calc(BMEditMesh *em, itype = BM_VERTS_OF_FACE; } - trans_islands = MEM_mallocN(sizeof(*trans_islands) * group_tot, __func__); + center = MEM_mallocN(sizeof(*center) * group_tot, __func__); + + if (calc_island_axismtx) { + axismtx = MEM_mallocN(sizeof(*axismtx) * group_tot, __func__); + } vert_map = MEM_mallocN(sizeof(*vert_map) * bm->totvert, __func__); /* we shouldn't need this, but with incorrect selection flushing @@ -311,7 +318,7 @@ static struct TransIslandData *editmesh_islands_info_calc(BMEditMesh *em, ese.htype = htype; - /* loop on each face in this group: + /* loop on each face or edge in this group: * - assign r_vert_map * - calculate (co, no) */ @@ -321,12 +328,14 @@ static struct TransIslandData *editmesh_islands_info_calc(BMEditMesh *em, ese.ele = ele_array[groups_array[fg_sta + j]]; BM_editselection_center(&ese, tmp_co); - BM_editselection_normal(&ese, tmp_no); - BM_editselection_plane(&ese, tmp_tangent); - add_v3_v3(co, tmp_co); - add_v3_v3(no, tmp_no); - add_v3_v3(tangent, tmp_tangent); + + if (axismtx) { + BM_editselection_normal(&ese, tmp_no); + BM_editselection_plane(&ese, tmp_tangent); + add_v3_v3(no, tmp_no); + add_v3_v3(tangent, tmp_tangent); + } { /* setup vertex map */ @@ -340,18 +349,20 @@ static struct TransIslandData *editmesh_islands_info_calc(BMEditMesh *em, } } - mul_v3_v3fl(trans_islands[i].co, co, 1.0f / (float)fg_len); + mul_v3_v3fl(center[i], co, 1.0f / (float)fg_len); - if (createSpaceNormalTangent(trans_islands[i].axismtx, no, tangent)) { - /* pass */ - } - else { - if (normalize_v3(no) != 0.0f) { - axis_dominant_v3_to_m3(trans_islands[i].axismtx, no); - invert_m3(trans_islands[i].axismtx); + if (axismtx) { + if (createSpaceNormalTangent(axismtx[i], no, tangent)) { + /* pass */ } else { - unit_m3(trans_islands[i].axismtx); + if (normalize_v3(no) != 0.0f) { + axis_dominant_v3_to_m3(axismtx[i], no); + invert_m3(axismtx[i]); + } + else { + unit_m3(axismtx[i]); + } } } } @@ -372,22 +383,24 @@ static struct TransIslandData *editmesh_islands_info_calc(BMEditMesh *em, } if (group_tot_single != 0) { - trans_islands = MEM_reallocN(trans_islands, - sizeof(*trans_islands) * (group_tot + group_tot_single)); + center = MEM_reallocN(center, sizeof(*center) * (group_tot + group_tot_single)); + if (axismtx) { + axismtx = MEM_reallocN(axismtx, sizeof(*axismtx) * (group_tot + group_tot_single)); + } BM_ITER_MESH_INDEX (v, &viter, bm, BM_VERTS_OF_MESH, i) { if (BM_elem_flag_test(v, BM_ELEM_SELECT) && (vert_map[i] == -1)) { - struct TransIslandData *v_island = &trans_islands[group_tot]; vert_map[i] = group_tot; + copy_v3_v3(center[group_tot], v->co); - copy_v3_v3(v_island->co, v->co); - - if (is_zero_v3(v->no) != 0.0f) { - axis_dominant_v3_to_m3(v_island->axismtx, v->no); - invert_m3(v_island->axismtx); - } - else { - unit_m3(v_island->axismtx); + if (axismtx) { + if (is_zero_v3(v->no) != 0.0f) { + axis_dominant_v3_to_m3(axismtx[group_tot], v->no); + invert_m3(axismtx[group_tot]); + } + else { + unit_m3(axismtx[group_tot]); + } } group_tot += 1; @@ -396,10 +409,10 @@ static struct TransIslandData *editmesh_islands_info_calc(BMEditMesh *em, } } - *r_island_tot = group_tot; - *r_island_vert_map = vert_map; - - return trans_islands; + r_island_data->axismtx = axismtx; + r_island_data->center = center; + r_island_data->island_tot = group_tot; + r_island_data->island_vert_map = vert_map; } static bool is_in_quadrant_v3(const float co[3], const int quadrant[3], const float epsilon) @@ -567,7 +580,8 @@ static void VertsToTransData(TransInfo *t, BMEditMesh *em, BMVert *eve, float *bweight, - struct TransIslandData *v_island, + const struct TransIslandData *island_data, + const int island_index, const bool no_island_center) { float *no, _no[3]; @@ -589,14 +603,17 @@ static void VertsToTransData(TransInfo *t, no = eve->no; } - if (v_island) { + if (island_index != -1) { if (no_island_center) { copy_v3_v3(td->center, td->loc); } else { - copy_v3_v3(td->center, v_island->co); + copy_v3_v3(td->center, island_data->center[island_index]); } - copy_m3_m3(td->axismtx, v_island->axismtx); + } + + if ((island_index != -1) && island_data->axismtx) { + copy_m3_m3(td->axismtx, island_data->axismtx[island_index]); } else if (t->around == V3D_AROUND_LOCAL_ORIGINS) { copy_v3_v3(td->center, td->loc); @@ -654,9 +671,7 @@ void createTransEditVerts(TransInfo *t) const int prop_mode = (t->flag & T_PROP_EDIT) ? (t->flag & T_PROP_EDIT_ALL) : 0; int cd_vert_bweight_offset = -1; - struct TransIslandData *island_info = NULL; - int island_info_tot; - int *island_vert_map = NULL; + struct TransIslandData island_data = {NULL}; /* Snap rotation along normal needs a common axis for whole islands, * otherwise one get random crazy results, see T59104. @@ -758,14 +773,17 @@ void createTransEditVerts(TransInfo *t) (t->around == V3D_AROUND_LOCAL_ORIGINS) && (em->selectmode & SCE_SELECT_VERTEX)); - island_info = editmesh_islands_info_calc( - em, &island_info_tot, &island_vert_map, calc_single_islands); + /* The island axismtx is only necessary in some modes. + * TODO(Germano): Extend the list to exclude other modes. */ + const bool calc_island_axismtx = !ELEM(t->mode, TFM_SHRINKFATTEN); + + editmesh_islands_info_calc(em, calc_single_islands, calc_island_axismtx, &island_data); } /* detect CrazySpace [tm] */ - if (modifiers_getCageIndex(t->scene, tc->obedit, NULL, 1) != -1) { + if (BKE_modifiers_get_cage_index(t->scene, tc->obedit, NULL, 1) != -1) { int totleft = -1; - if (modifiers_isCorrectableDeformed(t->scene, tc->obedit)) { + if (BKE_modifiers_is_correctable_deformed(t->scene, tc->obedit)) { BKE_scene_graph_evaluated_ensure(t->depsgraph, CTX_data_main(t->context)); /* Use evaluated state because we need b-bone cache. */ @@ -809,21 +827,19 @@ void createTransEditVerts(TransInfo *t) continue; } if (prop_mode || BM_elem_flag_test(eve, BM_ELEM_SELECT)) { - struct TransIslandData *v_island = NULL; float *bweight = (cd_vert_bweight_offset != -1) ? BM_ELEM_CD_GET_VOID_P(eve, cd_vert_bweight_offset) : NULL; - if (island_info) { + int island_index = -1; + if (island_data.island_vert_map) { const int connected_index = (dists_index && dists_index[a] != -1) ? dists_index[a] : a; - v_island = (island_vert_map[connected_index] != -1) ? - &island_info[island_vert_map[connected_index]] : - NULL; + island_index = island_data.island_vert_map[connected_index]; } /* Do not use the island center in case we are using islands * only to get axis for snap/rotate to normal... */ - VertsToTransData(t, tob, tx, em, eve, bweight, v_island, is_snap_rotate); + VertsToTransData(t, tob, tx, em, eve, bweight, &island_data, island_index, is_snap_rotate); if (tx) { tx++; } @@ -889,9 +905,16 @@ void createTransEditVerts(TransInfo *t) } } - if (island_info) { - MEM_freeN(island_info); - MEM_freeN(island_vert_map); + if (island_data.center) { + MEM_freeN(island_data.center); + } + + if (island_data.axismtx) { + MEM_freeN(island_data.axismtx); + } + + if (island_data.island_vert_map) { + MEM_freeN(island_data.island_vert_map); } cleanup: @@ -1030,7 +1053,15 @@ static void create_trans_vert_customdata_layer(BMVert *v, void trans_mesh_customdata_correction_init(TransInfo *t) { FOREACH_TRANS_DATA_CONTAINER (t, tc) { - BLI_assert(tc->custom.type.data == NULL); + if (tc->custom.type.data) { + if (tc->custom.type.free_cb == trans_mesh_customdata_free_cb) { + /* Custom data correction has initiated before. */ + continue; + } + else { + BLI_assert(false); + } + } int i; BMEditMesh *em = BKE_editmesh_from_object(tc->obedit); @@ -1168,7 +1199,7 @@ static void trans_mesh_customdata_correction_apply_vert(struct TransCustomDataLa BM_loop_interp_from_face(bm, l, f_copy, false, false); /* make sure face-attributes are correct (e.g. #MLoopUV, #MLoopCol) */ - BM_elem_attrs_copy_ex(tcld->bm_origfaces, bm, f_copy, l->f, 0x0, CD_MASK_NORMAL); + BM_elem_attrs_copy_ex(tcld->bm_origfaces, bm, f_copy, l->f, BM_ELEM_SELECT, CD_MASK_NORMAL); /* weight the loop */ if (do_loop_weight) { @@ -1600,7 +1631,7 @@ void createTransUVs(bContext *C, TransInfo *t) void flushTransUVs(TransInfo *t) { - SpaceImage *sima = t->sa->spacedata.first; + SpaceImage *sima = t->area->spacedata.first; const bool use_pixel_snap = ((sima->pixel_snap_mode != SI_PIXEL_SNAP_DISABLED) && (t->state != TRANS_CANCEL)); diff --git a/source/blender/editors/transform/transform_convert_nla.c b/source/blender/editors/transform/transform_convert_nla.c index 114968ec83f..2978c36b15f 100644 --- a/source/blender/editors/transform/transform_convert_nla.c +++ b/source/blender/editors/transform/transform_convert_nla.c @@ -26,17 +26,15 @@ #include "MEM_guardedalloc.h" -#include "BLI_math.h" #include "BLI_listbase.h" +#include "BLI_math.h" -#include "BKE_nla.h" #include "BKE_context.h" +#include "BKE_nla.h" #include "BKE_report.h" #include "ED_anim_api.h" -#include "UI_view2d.h" - #include "transform.h" #include "transform_convert.h" @@ -73,11 +71,7 @@ void createTransNlaData(bContext *C, TransInfo *t) /* which side of the current frame should be allowed */ if (t->mode == TFM_TIME_EXTEND) { - /* only side on which mouse is gets transformed */ - float xmouse, ymouse; - - UI_view2d_region_to_view(&ac.ar->v2d, t->mouse.imval[0], t->mouse.imval[1], &xmouse, &ymouse); - t->frame_side = (xmouse > CFRA) ? 'R' : 'L'; + t->frame_side = transform_convert_frame_side_dir_get(t, (float)CFRA); } else { /* normal transform - both sides of current frame are considered */ diff --git a/source/blender/editors/transform/transform_convert_node.c b/source/blender/editors/transform/transform_convert_node.c index ee4aa053444..d783bfdf40e 100644 --- a/source/blender/editors/transform/transform_convert_node.c +++ b/source/blender/editors/transform/transform_convert_node.c @@ -109,7 +109,7 @@ void createTransNodeData(bContext *UNUSED(C), TransInfo *t) const float dpi_fac = UI_DPI_FAC; TransData *td; TransData2D *td2d; - SpaceNode *snode = t->sa->spacedata.first; + SpaceNode *snode = t->area->spacedata.first; bNode *node; TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t); @@ -188,7 +188,7 @@ void flushTransNodes(TransInfo *t) /* handle intersection with noodles */ if (tc->data_len == 1) { - ED_node_link_intersect_test(t->sa, 1); + ED_node_link_intersect_test(t->area, 1); } } } diff --git a/source/blender/editors/transform/transform_convert_object.c b/source/blender/editors/transform/transform_convert_object.c index 16dfdd35c32..8deba0f7ad0 100644 --- a/source/blender/editors/transform/transform_convert_object.c +++ b/source/blender/editors/transform/transform_convert_object.c @@ -63,12 +63,10 @@ typedef struct TransDataObject { * - The key is object data #Object. * - The value is #XFormObjectSkipChild. */ - struct GHash *obchild_in_obmode_map; + struct XFormObjectSkipChild_Container *xcs; } TransDataObject; -static void trans_obchild_in_obmode_free_all(TransDataObject *tdo); - static void freeTransObjectCustomData(TransInfo *t, TransDataContainer *UNUSED(tc), TransCustomData *custom_data) @@ -81,7 +79,7 @@ static void freeTransObjectCustomData(TransInfo *t, } if (t->options & CTX_OBMODE_XFORM_SKIP_CHILDREN) { - trans_obchild_in_obmode_free_all(tdo); + ED_object_xform_skip_child_container_destroy(tdo->xcs); } MEM_freeN(tdo); } @@ -117,140 +115,19 @@ void trans_obdata_in_obmode_update_all(TransInfo *t) * Don't transform unselected children, this is done using the parent inverse matrix. * * \note The complex logic here is caused by mixed selection within a single selection chain, - * otherwise we only need #OB_SKIP_CHILD_PARENT_IS_XFORM for single objects. + * otherwise we only need #XFORM_OB_SKIP_CHILD_PARENT_IS_XFORM for single objects. * * \{ */ -enum { - /** - * The parent is transformed, this is held in place. - */ - OB_SKIP_CHILD_PARENT_IS_XFORM = 1, - /** - * The same as #OB_SKIP_CHILD_PARENT_IS_XFORM, - * however this objects parent isn't transformed directly. - */ - OB_SKIP_CHILD_PARENT_IS_XFORM_INDIRECT = 3, - /** - * Use the parent invert matrix to apply transformation, - * this is needed, because breaks in the selection chain prevents this from being transformed. - * This is used to add the transform which would have been added - * if there weren't breaks in the parent/child chain. - */ - OB_SKIP_CHILD_PARENT_APPLY_TRANSFORM = 2, -}; - -struct XFormObjectSkipChild { - float obmat_orig[4][4]; - float parent_obmat_orig[4][4]; - float parent_obmat_inv_orig[4][4]; - float parent_recurse_obmat_orig[4][4]; - float parentinv_orig[4][4]; - Object *ob_parent_recurse; - int mode; -}; - -static void trans_obchild_in_obmode_ensure_object(TransDataObject *tdo, - Object *ob, - Object *ob_parent_recurse, - int mode) -{ - if (tdo->obchild_in_obmode_map == NULL) { - tdo->obchild_in_obmode_map = BLI_ghash_ptr_new(__func__); - } - - void **xf_p; - if (!BLI_ghash_ensure_p(tdo->obchild_in_obmode_map, ob, &xf_p)) { - struct XFormObjectSkipChild *xf = MEM_mallocN(sizeof(*xf), __func__); - copy_m4_m4(xf->parentinv_orig, ob->parentinv); - copy_m4_m4(xf->obmat_orig, ob->obmat); - copy_m4_m4(xf->parent_obmat_orig, ob->parent->obmat); - invert_m4_m4(xf->parent_obmat_inv_orig, ob->parent->obmat); - if (ob_parent_recurse) { - copy_m4_m4(xf->parent_recurse_obmat_orig, ob_parent_recurse->obmat); - } - xf->mode = mode; - xf->ob_parent_recurse = ob_parent_recurse; - *xf_p = xf; - } -} - void trans_obchild_in_obmode_update_all(TransInfo *t) { TransDataObject *tdo = t->custom.type.data; - if (tdo->obchild_in_obmode_map == NULL) { + if (tdo->xcs == NULL) { return; } struct Main *bmain = CTX_data_main(t->context); - BKE_scene_graph_evaluated_ensure(t->depsgraph, bmain); - - GHashIterator gh_iter; - GHASH_ITER (gh_iter, tdo->obchild_in_obmode_map) { - Object *ob = BLI_ghashIterator_getKey(&gh_iter); - struct XFormObjectSkipChild *xf = BLI_ghashIterator_getValue(&gh_iter); - - /* The following blocks below assign 'dmat'. */ - float dmat[4][4]; - - if (xf->mode == OB_SKIP_CHILD_PARENT_IS_XFORM) { - /* Parent is transformed, this isn't so compensate. */ - Object *ob_parent_eval = DEG_get_evaluated_object(t->depsgraph, ob->parent); - mul_m4_m4m4(dmat, xf->parent_obmat_inv_orig, ob_parent_eval->obmat); - invert_m4(dmat); - } - else if (xf->mode == OB_SKIP_CHILD_PARENT_IS_XFORM_INDIRECT) { - /* Calculate parent matrix (from the root transform). */ - Object *ob_parent_recurse_eval = DEG_get_evaluated_object(t->depsgraph, - xf->ob_parent_recurse); - float parent_recurse_obmat_inv[4][4]; - invert_m4_m4(parent_recurse_obmat_inv, ob_parent_recurse_eval->obmat); - mul_m4_m4m4(dmat, xf->parent_recurse_obmat_orig, parent_recurse_obmat_inv); - invert_m4(dmat); - float parent_obmat_calc[4][4]; - mul_m4_m4m4(parent_obmat_calc, dmat, xf->parent_obmat_orig); - - /* Apply to the parent inverse matrix. */ - mul_m4_m4m4(dmat, xf->parent_obmat_inv_orig, parent_obmat_calc); - invert_m4(dmat); - } - else { - BLI_assert(xf->mode == OB_SKIP_CHILD_PARENT_APPLY_TRANSFORM); - /* Transform this - without transform data. */ - Object *ob_parent_recurse_eval = DEG_get_evaluated_object(t->depsgraph, - xf->ob_parent_recurse); - float parent_recurse_obmat_inv[4][4]; - invert_m4_m4(parent_recurse_obmat_inv, ob_parent_recurse_eval->obmat); - mul_m4_m4m4(dmat, xf->parent_recurse_obmat_orig, parent_recurse_obmat_inv); - invert_m4(dmat); - float obmat_calc[4][4]; - mul_m4_m4m4(obmat_calc, dmat, xf->obmat_orig); - /* obmat_calc is just obmat. */ - - /* Get the matrices relative to the parent. */ - float obmat_parent_relative_orig[4][4]; - float obmat_parent_relative_calc[4][4]; - float obmat_parent_relative_inv_orig[4][4]; - - mul_m4_m4m4(obmat_parent_relative_orig, xf->parent_obmat_inv_orig, xf->obmat_orig); - mul_m4_m4m4(obmat_parent_relative_calc, xf->parent_obmat_inv_orig, obmat_calc); - invert_m4_m4(obmat_parent_relative_inv_orig, obmat_parent_relative_orig); - - /* Apply to the parent inverse matrix. */ - mul_m4_m4m4(dmat, obmat_parent_relative_calc, obmat_parent_relative_inv_orig); - } - - mul_m4_m4m4(ob->parentinv, dmat, xf->parentinv_orig); - - DEG_id_tag_update(&ob->id, ID_RECALC_TRANSFORM); - } -} - -static void trans_obchild_in_obmode_free_all(TransDataObject *tdo) -{ - if (tdo->obchild_in_obmode_map != NULL) { - BLI_ghash_free(tdo->obchild_in_obmode_map, NULL, MEM_freeN); - } + ED_object_xform_skip_child_container_update_all(tdo->xcs, bmain, t->depsgraph); } /** \} */ @@ -320,7 +197,7 @@ static void ObjectToTransData(TransInfo *t, TransData *td, Object *ob) /* NOTE: This is not really following copy-on-write design and we should not * be re-evaluating the evaluated object. But as the comment above mentioned * this is part of a hack. - * More proper solution would be to make a shallow copy of the object and + * More proper solution would be to make a shallow copy of the object and * evaluate that, and access matrix of that evaluated copy of the object. * Might be more tricky than it sounds, if some logic later on accesses the * object matrix via td->ob->obmat. */ @@ -413,7 +290,7 @@ static void ObjectToTransData(TransInfo *t, TransData *td, Object *ob) static void trans_object_base_deps_flag_prepare(ViewLayer *view_layer) { - for (Base *base = view_layer->object_bases.first; base; base = base->next) { + LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) { base->object->id.tag &= ~LIB_TAG_DOIT; } } @@ -447,7 +324,7 @@ static void trans_object_base_deps_flag_finish(const TransInfo *t, ViewLayer *vi { if ((t->options & CTX_OBMODE_XFORM_OBDATA) == 0) { - for (Base *base = view_layer->object_bases.first; base; base = base->next) { + LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) { if (base->object->id.tag & LIB_TAG_DOIT) { base->flag_legacy |= BA_SNAP_FIX_DEPS_FIASCO; } @@ -478,7 +355,7 @@ static void set_trans_object_base_flags(TransInfo *t) /* Clear all flags we need. It will be used to detect dependencies. */ trans_object_base_deps_flag_prepare(view_layer); /* Traverse all bases and set all possible flags. */ - for (Base *base = view_layer->object_bases.first; base; base = base->next) { + LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) { base->flag_legacy &= ~(BA_WAS_SEL | BA_TRANSFORM_LOCKED_IN_PLACE); if (BASE_SELECTED_EDITABLE(v3d, base)) { Object *ob = base->object; @@ -545,7 +422,7 @@ static int count_proportional_objects(TransInfo *t) if (!((t->around == V3D_AROUND_LOCAL_ORIGINS) && (t->mode == TFM_ROTATION || t->mode == TFM_TRACKBALL))) { /* Mark all parents. */ - for (Base *base = view_layer->object_bases.first; base; base = base->next) { + LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) { if (BASE_SELECTED_EDITABLE(v3d, base) && BASE_SELECTABLE(v3d, base)) { Object *parent = base->object->parent; /* flag all parents */ @@ -556,7 +433,7 @@ static int count_proportional_objects(TransInfo *t) } } /* Mark all children. */ - for (Base *base = view_layer->object_bases.first; base; base = base->next) { + LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) { /* all base not already selected or marked that is editable */ if ((base->object->flag & (BA_TRANSFORM_CHILD | BA_TRANSFORM_PARENT)) == 0 && (base->flag & BASE_SELECTED) == 0 && @@ -566,7 +443,7 @@ static int count_proportional_objects(TransInfo *t) } } /* Flush changed flags to all dependencies. */ - for (Base *base = view_layer->object_bases.first; base; base = base->next) { + LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) { Object *ob = base->object; /* If base is not selected, not a parent of selection or not a child of * selection and it is editable and selectable. @@ -715,7 +592,7 @@ void createTransObject(bContext *C, TransInfo *t) ViewLayer *view_layer = t->view_layer; View3D *v3d = t->view; - for (Base *base = view_layer->object_bases.first; base; base = base->next) { + LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) { Object *ob = base->object; /* if base is not selected, not a parent of selection @@ -746,6 +623,8 @@ void createTransObject(bContext *C, TransInfo *t) if (t->options & CTX_OBMODE_XFORM_SKIP_CHILDREN) { + tdo->xcs = ED_object_xform_skip_child_container_create(); + #define BASE_XFORM_INDIRECT(base) \ ((base->flag_legacy & BA_WAS_SEL) && (base->flag & BASE_SELECTED) == 0) @@ -760,7 +639,7 @@ void createTransObject(bContext *C, TransInfo *t) ViewLayer *view_layer = t->view_layer; - for (Base *base = view_layer->object_bases.first; base; base = base->next) { + LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) { Object *ob = base->object; if (ob->parent != NULL) { if (ob->parent && !BLI_gset_haskey(objects_in_transdata, ob->parent) && @@ -778,8 +657,8 @@ void createTransObject(bContext *C, TransInfo *t) } if (ob_parent_recurse) { - trans_obchild_in_obmode_ensure_object( - tdo, ob, ob_parent_recurse, OB_SKIP_CHILD_PARENT_APPLY_TRANSFORM); + ED_object_xform_skip_child_container_item_ensure( + tdo->xcs, ob, ob_parent_recurse, XFORM_OB_SKIP_CHILD_PARENT_APPLY); BLI_ghash_insert(objects_parent_root, ob, ob_parent_recurse); base->flag_legacy |= BA_TRANSFORM_LOCKED_IN_PLACE; } @@ -790,7 +669,7 @@ void createTransObject(bContext *C, TransInfo *t) } } - for (Base *base = view_layer->object_bases.first; base; base = base->next) { + LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) { Object *ob = base->object; if (BASE_XFORM_INDIRECT(base) || BLI_gset_haskey(objects_in_transdata, ob)) { @@ -801,14 +680,15 @@ void createTransObject(bContext *C, TransInfo *t) if (base_parent) { if (BASE_XFORM_INDIRECT(base_parent) || BLI_gset_haskey(objects_in_transdata, ob->parent)) { - trans_obchild_in_obmode_ensure_object(tdo, ob, NULL, OB_SKIP_CHILD_PARENT_IS_XFORM); + ED_object_xform_skip_child_container_item_ensure( + tdo->xcs, ob, NULL, XFORM_OB_SKIP_CHILD_PARENT_IS_XFORM); base->flag_legacy |= BA_TRANSFORM_LOCKED_IN_PLACE; } else { Object *ob_parent_recurse = BLI_ghash_lookup(objects_parent_root, ob->parent); if (ob_parent_recurse) { - trans_obchild_in_obmode_ensure_object( - tdo, ob, ob_parent_recurse, OB_SKIP_CHILD_PARENT_IS_XFORM_INDIRECT); + ED_object_xform_skip_child_container_item_ensure( + tdo->xcs, ob, ob_parent_recurse, XFORM_OB_SKIP_CHILD_PARENT_IS_XFORM_INDIRECT); } } } diff --git a/source/blender/editors/transform/transform_convert_paintcurve.c b/source/blender/editors/transform/transform_convert_paintcurve.c index 6d46a94214e..4dbe57fc143 100644 --- a/source/blender/editors/transform/transform_convert_paintcurve.c +++ b/source/blender/editors/transform/transform_convert_paintcurve.c @@ -29,7 +29,6 @@ #include "BKE_context.h" #include "BKE_paint.h" -#include "BKE_report.h" #include "transform.h" #include "transform_convert.h" diff --git a/source/blender/editors/transform/transform_convert_particle.c b/source/blender/editors/transform/transform_convert_particle.c index 2a961da018b..4e1fc6ae1fa 100644 --- a/source/blender/editors/transform/transform_convert_particle.c +++ b/source/blender/editors/transform/transform_convert_particle.c @@ -21,15 +21,14 @@ * \ingroup edtransform */ -#include "DNA_particle_types.h" #include "DNA_modifier_types.h" +#include "DNA_particle_types.h" #include "MEM_guardedalloc.h" #include "BLI_math.h" #include "BKE_context.h" -#include "BKE_report.h" #include "BKE_particle.h" #include "BKE_pointcache.h" diff --git a/source/blender/editors/transform/transform_convert_sculpt.c b/source/blender/editors/transform/transform_convert_sculpt.c index 6b584f806b8..55dc36e9693 100644 --- a/source/blender/editors/transform/transform_convert_sculpt.c +++ b/source/blender/editors/transform/transform_convert_sculpt.c @@ -21,16 +21,13 @@ * \ingroup edtransform */ -#include "DNA_space_types.h" - #include "MEM_guardedalloc.h" #include "BLI_math.h" #include "BKE_context.h" -#include "BKE_report.h" -#include "BKE_scene.h" #include "BKE_paint.h" +#include "BKE_report.h" #include "transform.h" #include "transform_convert.h" diff --git a/source/blender/editors/transform/transform_convert_sequencer.c b/source/blender/editors/transform/transform_convert_sequencer.c index 4baf0e8a3cb..0175bf6e673 100644 --- a/source/blender/editors/transform/transform_convert_sequencer.c +++ b/source/blender/editors/transform/transform_convert_sequencer.c @@ -28,8 +28,8 @@ #include "BLI_math.h" #include "BKE_context.h" -#include "BKE_sequencer.h" #include "BKE_report.h" +#include "BKE_sequencer.h" #include "UI_view2d.h" @@ -49,7 +49,7 @@ * seq->depth must be set before running this function so we know if the strips * are root level or not */ -static void SeqTransInfo(TransInfo *t, Sequence *seq, int *recursive, int *count, int *flag) +static void SeqTransInfo(TransInfo *t, Sequence *seq, int *r_recursive, int *r_count, int *r_flag) { /* for extend we need to do some tricks */ if (t->mode == TFM_TIME_EXTEND) { @@ -62,51 +62,51 @@ static void SeqTransInfo(TransInfo *t, Sequence *seq, int *recursive, int *count int right = BKE_sequence_tx_get_final_right(seq, true); if (seq->depth == 0 && ((seq->flag & SELECT) == 0 || (seq->flag & SEQ_LOCK))) { - *recursive = false; - *count = 0; - *flag = 0; + *r_recursive = false; + *r_count = 0; + *r_flag = 0; } else if (seq->type == SEQ_TYPE_META) { /* for meta's we only ever need to extend their children, no matter what depth * just check the meta's are in the bounds */ if (t->frame_side == 'R' && right <= cfra) { - *recursive = false; + *r_recursive = false; } else if (t->frame_side == 'L' && left >= cfra) { - *recursive = false; + *r_recursive = false; } else { - *recursive = true; + *r_recursive = true; } - *count = 1; - *flag = (seq->flag | SELECT) & ~(SEQ_LEFTSEL | SEQ_RIGHTSEL); + *r_count = 1; + *r_flag = (seq->flag | SELECT) & ~(SEQ_LEFTSEL | SEQ_RIGHTSEL); } else { - *recursive = false; /* not a meta, so no thinking here */ - *count = 1; /* unless its set to 0, extend will never set 2 handles at once */ - *flag = (seq->flag | SELECT) & ~(SEQ_LEFTSEL | SEQ_RIGHTSEL); + *r_recursive = false; /* not a meta, so no thinking here */ + *r_count = 1; /* unless its set to 0, extend will never set 2 handles at once */ + *r_flag = (seq->flag | SELECT) & ~(SEQ_LEFTSEL | SEQ_RIGHTSEL); if (t->frame_side == 'R') { if (right <= cfra) { - *count = *flag = 0; + *r_count = *r_flag = 0; } /* ignore */ else if (left > cfra) { } /* keep the selection */ else { - *flag |= SEQ_RIGHTSEL; + *r_flag |= SEQ_RIGHTSEL; } } else { if (left >= cfra) { - *count = *flag = 0; + *r_count = *r_flag = 0; } /* ignore */ else if (right < cfra) { } /* keep the selection */ else { - *flag |= SEQ_LEFTSEL; + *r_flag |= SEQ_LEFTSEL; } } } @@ -123,28 +123,28 @@ static void SeqTransInfo(TransInfo *t, Sequence *seq, int *recursive, int *count /* Non nested strips (resect selection and handles) */ if ((seq->flag & SELECT) == 0 || (seq->flag & SEQ_LOCK)) { - *recursive = false; - *count = 0; - *flag = 0; + *r_recursive = false; + *r_count = 0; + *r_flag = 0; } else { if ((seq->flag & (SEQ_LEFTSEL | SEQ_RIGHTSEL)) == (SEQ_LEFTSEL | SEQ_RIGHTSEL)) { - *flag = seq->flag; - *count = 2; /* we need 2 transdata's */ + *r_flag = seq->flag; + *r_count = 2; /* we need 2 transdata's */ } else { - *flag = seq->flag; - *count = 1; /* selected or with a handle selected */ + *r_flag = seq->flag; + *r_count = 1; /* selected or with a handle selected */ } /* Recursive */ if ((seq->type == SEQ_TYPE_META) && ((seq->flag & (SEQ_LEFTSEL | SEQ_RIGHTSEL)) == 0)) { /* if any handles are selected, don't recurse */ - *recursive = true; + *r_recursive = true; } else { - *recursive = false; + *r_recursive = false; } } } @@ -152,23 +152,23 @@ static void SeqTransInfo(TransInfo *t, Sequence *seq, int *recursive, int *count /* Nested, different rules apply */ #ifdef SEQ_TX_NESTED_METAS - *flag = (seq->flag | SELECT) & ~(SEQ_LEFTSEL | SEQ_RIGHTSEL); - *count = 1; /* ignore the selection for nested */ - *recursive = (seq->type == SEQ_TYPE_META); + *r_flag = (seq->flag | SELECT) & ~(SEQ_LEFTSEL | SEQ_RIGHTSEL); + *r_count = 1; /* ignore the selection for nested */ + *r_recursive = (seq->type == SEQ_TYPE_META); #else if (seq->type == SEQ_TYPE_META) { /* Meta's can only directly be moved between channels since they * don't have their start and length set directly (children affect that) * since this Meta is nested we don't need any of its data in fact. * BKE_sequence_calc() will update its settings when run on the top-level meta. */ - *flag = 0; - *count = 0; - *recursive = true; + *r_flag = 0; + *r_count = 0; + *r_recursive = true; } else { - *flag = (seq->flag | SELECT) & ~(SEQ_LEFTSEL | SEQ_RIGHTSEL); - *count = 1; /* ignore the selection for nested */ - *recursive = false; + *r_flag = (seq->flag | SELECT) & ~(SEQ_LEFTSEL | SEQ_RIGHTSEL); + *r_count = 1; /* ignore the selection for nested */ + *r_recursive = false; } #endif } @@ -381,7 +381,7 @@ static void freeSeqData(TransInfo *t, TransDataContainer *tc, TransCustomData *c } if (overlap) { - const bool use_sync_markers = (((SpaceSeq *)t->sa->spacedata.first)->flag & + const bool use_sync_markers = (((SpaceSeq *)t->area->spacedata.first)->flag & SEQ_MARKER_TRANS) != 0; ListBase *markers = &t->scene->markers; @@ -522,18 +522,16 @@ static void freeSeqData(TransInfo *t, TransDataContainer *tc, TransCustomData *c DEG_id_tag_update(&t->scene->id, ID_RECALC_SEQUENCER_STRIPS); } -void createTransSeqData(bContext *C, TransInfo *t) +void createTransSeqData(TransInfo *t) { #define XXX_DURIAN_ANIM_TX_HACK - View2D *v2d = UI_view2d_fromcontext(C); Scene *scene = t->scene; Editing *ed = BKE_sequencer_editing_get(t->scene, false); TransData *td = NULL; TransData2D *td2d = NULL; TransDataSeq *tdsq = NULL; TransSeq *ts = NULL; - int xmouse; int count = 0; @@ -545,18 +543,7 @@ void createTransSeqData(bContext *C, TransInfo *t) } tc->custom.type.free_cb = freeSeqData; - - xmouse = (int)UI_view2d_region_to_view_x(v2d, t->mouse.imval[0]); - - /* which side of the current frame should be allowed */ - if (t->mode == TFM_TIME_EXTEND) { - /* only side on which mouse is gets transformed */ - t->frame_side = (xmouse > CFRA) ? 'R' : 'L'; - } - else { - /* normal transform - both sides of current frame are considered */ - t->frame_side = 'B'; - } + t->frame_side = transform_convert_frame_side_dir_get(t, (float)CFRA); #ifdef XXX_DURIAN_ANIM_TX_HACK { @@ -598,9 +585,12 @@ void createTransSeqData(bContext *C, TransInfo *t) SeqToTransData_Recursive(t, ed->seqbasep, td, td2d, tdsq); SeqTransDataBounds(t, ed->seqbasep, ts); - /* set the snap mode based on how close the mouse is at the end/start points */ - if (abs(xmouse - ts->max) > abs(xmouse - ts->min)) { - ts->snap_left = true; + if (t->flag & T_MODAL) { + /* set the snap mode based on how close the mouse is at the end/start points */ + int xmouse = (int)UI_view2d_region_to_view_x((View2D *)t->view, t->mouse.imval[0]); + if (abs(xmouse - ts->max) > abs(xmouse - ts->min)) { + ts->snap_left = true; + } } #undef XXX_DURIAN_ANIM_TX_HACK diff --git a/source/blender/editors/transform/transform_convert_tracking.c b/source/blender/editors/transform/transform_convert_tracking.c index b68b79adbd8..6704567a76b 100644 --- a/source/blender/editors/transform/transform_convert_tracking.c +++ b/source/blender/editors/transform/transform_convert_tracking.c @@ -518,7 +518,7 @@ static void createTransTrackingCurvesData(bContext *C, TransInfo *t) void createTransTrackingData(bContext *C, TransInfo *t) { - ARegion *ar = CTX_wm_region(C); + ARegion *region = CTX_wm_region(C); SpaceClip *sc = CTX_wm_space_clip(C); MovieClip *clip = ED_space_clip_get_clip(sc); int width, height; @@ -537,7 +537,7 @@ void createTransTrackingData(bContext *C, TransInfo *t) return; } - if (ar->regiontype == RGN_TYPE_PREVIEW) { + if (region->regiontype == RGN_TYPE_PREVIEW) { /* transformation was called from graph editor */ createTransTrackingCurvesData(C, t); } @@ -549,7 +549,7 @@ void createTransTrackingData(bContext *C, TransInfo *t) void cancelTransTracking(TransInfo *t) { TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t); - SpaceClip *sc = t->sa->spacedata.first; + SpaceClip *sc = t->area->spacedata.first; int i, framenr = ED_space_clip_get_clip_frame_number(sc); TransDataTracking *tdt_array = tc->custom.type.data; diff --git a/source/blender/editors/transform/transform_draw_cursors.c b/source/blender/editors/transform/transform_draw_cursors.c index dc2ebdca56a..95ca5ae0c30 100644 --- a/source/blender/editors/transform/transform_draw_cursors.c +++ b/source/blender/editors/transform/transform_draw_cursors.c @@ -148,9 +148,9 @@ static void drawArc(float angle_start, float angle_end, int segments, float size */ bool transform_draw_cursor_poll(bContext *C) { - ARegion *ar = CTX_wm_region(C); + ARegion *region = CTX_wm_region(C); - if (ar && ar->regiontype == RGN_TYPE_WINDOW) { + if (region && region->regiontype == RGN_TYPE_WINDOW) { return 1; } return 0; @@ -181,8 +181,8 @@ void transform_draw_cursor_draw(bContext *UNUSED(C), int x, int y, void *customd projectFloatViewEx(t, t->center_global, cent, V3D_PROJ_TEST_CLIP_ZERO); /* Offset the values for the area region. */ const float offset[2] = { - t->ar->winrct.xmin, - t->ar->winrct.ymin, + t->region->winrct.xmin, + t->region->winrct.ymin, }; for (int i = 0; i < 2; i++) { @@ -313,7 +313,7 @@ void transform_draw_cursor_draw(bContext *UNUSED(C), int x, int y, void *customd break; } case HLP_TRACKBALL: { - unsigned char col[3], col2[3]; + uchar col[3], col2[3]; UI_GetThemeColor3ubv(TH_GRID, col); GPU_matrix_translate_3fv(mval); diff --git a/source/blender/editors/transform/transform_generics.c b/source/blender/editors/transform/transform_generics.c index 5595c3a0e38..4472facf183 100644 --- a/source/blender/editors/transform/transform_generics.c +++ b/source/blender/editors/transform/transform_generics.c @@ -21,8 +21,8 @@ * \ingroup edtransform */ -#include <string.h> #include <math.h> +#include <string.h> #include "MEM_guardedalloc.h" @@ -34,20 +34,21 @@ #include "DNA_constraint_types.h" #include "DNA_gpencil_types.h" #include "DNA_lattice_types.h" +#include "DNA_mask_types.h" +#include "DNA_mesh_types.h" +#include "DNA_meta_types.h" +#include "DNA_modifier_types.h" +#include "DNA_movieclip_types.h" +#include "DNA_object_types.h" +#include "DNA_scene_types.h" #include "DNA_screen_types.h" #include "DNA_sequence_types.h" #include "DNA_space_types.h" -#include "DNA_scene_types.h" -#include "DNA_object_types.h" -#include "DNA_mesh_types.h" #include "DNA_view3d_types.h" -#include "DNA_modifier_types.h" -#include "DNA_movieclip_types.h" -#include "DNA_mask_types.h" -#include "DNA_meta_types.h" -#include "BLI_math.h" #include "BLI_blenlib.h" +#include "BLI_ghash.h" +#include "BLI_math.h" #include "BLI_rand.h" #include "BLI_utildefines.h" @@ -63,16 +64,16 @@ #include "BIK_api.h" #include "BKE_action.h" -#include "BKE_animsys.h" +#include "BKE_anim_data.h" #include "BKE_armature.h" #include "BKE_context.h" #include "BKE_curve.h" #include "BKE_editmesh.h" #include "BKE_fcurve.h" -#include "BKE_gpencil.h" +#include "BKE_gpencil_geom.h" #include "BKE_lattice.h" #include "BKE_layer.h" -#include "BKE_library.h" +#include "BKE_lib_id.h" #include "BKE_mask.h" #include "BKE_nla.h" #include "BKE_paint.h" @@ -86,24 +87,24 @@ #include "ED_anim_api.h" #include "ED_armature.h" +#include "ED_clip.h" +#include "ED_curve.h" /* for curve_editnurbs */ +#include "ED_gpencil.h" #include "ED_image.h" #include "ED_keyframing.h" #include "ED_markers.h" #include "ED_mesh.h" #include "ED_object.h" #include "ED_particle.h" +#include "ED_screen.h" #include "ED_screen_types.h" +#include "ED_sculpt.h" #include "ED_space_api.h" #include "ED_uvedit.h" #include "ED_view3d.h" -#include "ED_curve.h" /* for curve_editnurbs */ -#include "ED_clip.h" -#include "ED_screen.h" -#include "ED_gpencil.h" -#include "ED_sculpt.h" -#include "WM_types.h" #include "WM_api.h" +#include "WM_types.h" #include "RE_engine.h" @@ -112,6 +113,7 @@ #include "transform.h" #include "transform_convert.h" +#include "transform_mode.h" #include "transform_snap.h" /* ************************** Functions *************************** */ @@ -335,7 +337,7 @@ static void animrecord_check_state(Scene *scene, ID *id, wmTimer *animtimer) static bool fcu_test_selected(FCurve *fcu) { BezTriple *bezt = fcu->bezt; - unsigned int i; + uint i; if (bezt == NULL) { /* ignore baked */ return 0; @@ -354,7 +356,7 @@ static bool fcu_test_selected(FCurve *fcu) static void recalcData_actedit(TransInfo *t) { ViewLayer *view_layer = t->view_layer; - SpaceAction *saction = (SpaceAction *)t->sa->spacedata.first; + SpaceAction *saction = (SpaceAction *)t->area->spacedata.first; bAnimContext ac = {NULL}; ListBase anim_data = {NULL, NULL}; @@ -367,11 +369,11 @@ static void recalcData_actedit(TransInfo *t) ac.scene = t->scene; ac.view_layer = t->view_layer; ac.obact = OBACT(view_layer); - ac.sa = t->sa; - ac.ar = t->ar; - ac.sl = (t->sa) ? t->sa->spacedata.first : NULL; - ac.spacetype = (t->sa) ? t->sa->spacetype : 0; - ac.regiontype = (t->ar) ? t->ar->regiontype : 0; + ac.area = t->area; + ac.region = t->region; + ac.sl = (t->area) ? t->area->spacedata.first : NULL; + ac.spacetype = (t->area) ? t->area->spacetype : 0; + ac.regiontype = (t->region) ? t->region->regiontype : 0; ANIM_animdata_context_getdata(&ac); @@ -404,7 +406,7 @@ static void recalcData_actedit(TransInfo *t) /* helper for recalcData() - for Graph Editor transforms */ static void recalcData_graphedit(TransInfo *t) { - SpaceGraph *sipo = (SpaceGraph *)t->sa->spacedata.first; + SpaceGraph *sipo = (SpaceGraph *)t->area->spacedata.first; ViewLayer *view_layer = t->view_layer; ListBase anim_data = {NULL, NULL}; @@ -420,11 +422,11 @@ static void recalcData_graphedit(TransInfo *t) ac.scene = t->scene; ac.view_layer = t->view_layer; ac.obact = OBACT(view_layer); - ac.sa = t->sa; - ac.ar = t->ar; - ac.sl = (t->sa) ? t->sa->spacedata.first : NULL; - ac.spacetype = (t->sa) ? t->sa->spacetype : 0; - ac.regiontype = (t->ar) ? t->ar->regiontype : 0; + ac.area = t->area; + ac.region = t->region; + ac.sl = (t->area) ? t->area->spacedata.first : NULL; + ac.spacetype = (t->area) ? t->area->spacetype : 0; + ac.regiontype = (t->region) ? t->region->regiontype : 0; ANIM_animdata_context_getdata(&ac); @@ -472,7 +474,7 @@ static void recalcData_graphedit(TransInfo *t) /* helper for recalcData() - for NLA Editor transforms */ static void recalcData_nla(TransInfo *t) { - SpaceNla *snla = (SpaceNla *)t->sa->spacedata.first; + SpaceNla *snla = (SpaceNla *)t->area->spacedata.first; Scene *scene = t->scene; double secf = FPS; int i; @@ -716,7 +718,7 @@ static void recalcData_image(TransInfo *t) flushTransPaintCurve(t); } else if ((t->flag & T_EDIT) && t->obedit_type == OB_MESH) { - SpaceImage *sima = t->sa->spacedata.first; + SpaceImage *sima = t->area->spacedata.first; flushTransUVs(t); if (sima->flag & SI_LIVE_UNWRAP) { @@ -734,7 +736,7 @@ static void recalcData_image(TransInfo *t) /* helper for recalcData() - for Movie Clip transforms */ static void recalcData_spaceclip(TransInfo *t) { - SpaceClip *sc = t->sa->spacedata.first; + SpaceClip *sc = t->area->spacedata.first; if (ED_space_clip_check_show_trackedit(sc)) { MovieClip *clip = ED_space_clip_get_clip(sc); @@ -782,69 +784,6 @@ static void recalcData_spaceclip(TransInfo *t) } } -/** - * if pose bone (partial) selected, copy data. - * context; posemode armature, with mirror editing enabled. - * - * \param pid: Optional, apply relative transform when set (has no effect on mirrored bones). - */ -static void pose_transform_mirror_update(TransInfo *t, - TransDataContainer *tc, - Object *ob, - PoseInitData_Mirror *pid) -{ - float flip_mtx[4][4]; - unit_m4(flip_mtx); - flip_mtx[0][0] = -1; - - TransData *td = tc->data; - for (int i = tc->data_len; i--; td++) { - bPoseChannel *pchan_orig = td->extra; - BLI_assert(pchan_orig->bone->flag & BONE_TRANSFORM); - /* No layer check, correct mirror is more important. */ - bPoseChannel *pchan = BKE_pose_channel_get_mirrored(ob->pose, pchan_orig->name); - if (pchan == NULL) { - continue; - } - - /* Also do bbone scaling. */ - pchan->bone->xwidth = pchan_orig->bone->xwidth; - pchan->bone->zwidth = pchan_orig->bone->zwidth; - - /* We assume X-axis flipping for now. */ - pchan->curve_in_x = pchan_orig->curve_in_x * -1; - pchan->curve_out_x = pchan_orig->curve_out_x * -1; - pchan->roll1 = pchan_orig->roll1 * -1; // XXX? - pchan->roll2 = pchan_orig->roll2 * -1; // XXX? - - float pchan_mtx_final[4][4]; - BKE_pchan_to_mat4(pchan_orig, pchan_mtx_final); - mul_m4_m4m4(pchan_mtx_final, pchan_mtx_final, flip_mtx); - mul_m4_m4m4(pchan_mtx_final, flip_mtx, pchan_mtx_final); - if (pid) { - mul_m4_m4m4(pchan_mtx_final, pid->offset_mtx, pchan_mtx_final); - } - BKE_pchan_apply_mat4(pchan, pchan_mtx_final, false); - - /* In this case we can do target-less IK grabbing. */ - if (t->mode == TFM_TRANSLATION) { - bKinematicConstraint *data = has_targetless_ik(pchan); - if (data == NULL) { - continue; - } - mul_v3_m4v3(data->grabtarget, flip_mtx, td->loc); - if (pid) { - /* TODO(germano): Realitve Mirror support */ - } - data->flag |= CONSTRAINT_IK_AUTO; - } - - if (pid) { - pid++; - } - } -} - /* helper for recalcData() - for object transforms, typically in the 3D view */ static void recalcData_objects(TransInfo *t) { @@ -1057,7 +996,7 @@ static void recalcData_objects(TransInfo *t) DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); bPose *pose = ob->pose; if (arm->flag & ARM_MIRROR_EDIT || pose->flag & POSE_MIRROR_EDIT) { - pose_transform_mirror_update(t, tc, ob, NULL); + pose_transform_mirror_update(t, tc, ob); } } } @@ -1071,11 +1010,7 @@ static void recalcData_objects(TransInfo *t) if (pose->flag & POSE_MIRROR_EDIT) { if (t->state != TRANS_CANCEL) { - PoseInitData_Mirror *pid = NULL; - if (pose->flag & POSE_MIRROR_RELATIVE) { - pid = tc->custom.type.data; - } - pose_transform_mirror_update(t, tc, ob, pid); + pose_transform_mirror_update(t, tc, ob); } else { restoreMirrorPoseBones(tc); @@ -1168,7 +1103,7 @@ static void recalcData_objects(TransInfo *t) if (motionpath_update) { /* Update motion paths once for all transformed objects. */ - ED_objects_recalculate_paths(t->context, t->scene, OBJECT_PATH_CALC_RANGE_CHANGED); + ED_objects_recalculate_paths(t->context, t->scene, OBJECT_PATH_CALC_RANGE_CURRENT_FRAME); } if (t->options & CTX_OBMODE_XFORM_SKIP_CHILDREN) { @@ -1215,14 +1150,19 @@ static void recalcData_sequencer(TransInfo *t) static void recalcData_gpencil_strokes(TransInfo *t) { TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t); + GHash *strokes = BLI_ghash_ptr_new(__func__); TransData *td = tc->data; for (int i = 0; i < tc->data_len; i++, td++) { bGPDstroke *gps = td->extra; - if (gps != NULL) { - gps->flag |= GP_STROKE_RECALC_GEOMETRY; + + if ((gps != NULL) && (!BLI_ghash_haskey(strokes, gps))) { + BLI_ghash_insert(strokes, gps, gps); + /* Calc geometry data. */ + BKE_gpencil_stroke_geometry_update(gps); } } + BLI_ghash_free(strokes, NULL, NULL); } static void recalcData_sculpt(TransInfo *t) @@ -1247,7 +1187,6 @@ void recalcData(TransInfo *t) flushTransPaintCurve(t); } else if (t->options & CTX_GPENCIL_STROKES) { - /* set recalc triangle cache flag */ recalcData_gpencil_strokes(t); } else if (t->options & CTX_SCULPT) { @@ -1282,7 +1221,7 @@ void recalcData(TransInfo *t) void drawLine(TransInfo *t, const float center[3], const float dir[3], char axis, short options) { float v1[3], v2[3], v3[3]; - unsigned char col[3], col2[3]; + uchar col[3], col2[3]; if (t->spacetype == SPACE_VIEW3D) { View3D *v3d = t->view; @@ -1434,8 +1373,8 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve Object *obact = OBACT(view_layer); const eObjectMode object_mode = obact ? obact->mode : OB_MODE_OBJECT; ToolSettings *ts = CTX_data_tool_settings(C); - ARegion *ar = CTX_wm_region(C); - ScrArea *sa = CTX_wm_area(C); + ARegion *region = CTX_wm_region(C); + ScrArea *area = CTX_wm_area(C); bGPdata *gpd = CTX_data_gpencil_data(C); PropertyRNA *prop; @@ -1443,8 +1382,8 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve t->depsgraph = CTX_data_depsgraph_pointer(C); t->scene = sce; t->view_layer = view_layer; - t->sa = sa; - t->ar = ar; + t->area = area; + t->region = region; t->settings = ts; t->reports = op ? op->reports : NULL; @@ -1468,20 +1407,16 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve t->redraw = TREDRAW_HARD; /* redraw first time */ + int mval[2]; if (event) { - t->mouse.imval[0] = event->mval[0]; - t->mouse.imval[1] = event->mval[1]; + copy_v2_v2_int(mval, event->mval); } else { - t->mouse.imval[0] = 0; - t->mouse.imval[1] = 0; + zero_v2_int(mval); } - - t->con.imval[0] = t->mouse.imval[0]; - t->con.imval[1] = t->mouse.imval[1]; - - t->mval[0] = t->mouse.imval[0]; - t->mval[1] = t->mouse.imval[1]; + copy_v2_v2_int(t->mval, mval); + copy_v2_v2_int(t->mouse.imval, mval); + copy_v2_v2_int(t->con.imval, mval); t->transform = NULL; t->handleEvent = NULL; @@ -1495,11 +1430,6 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve unit_m3(t->mat); - unit_m3(t->orient_matrix); - negate_m3(t->orient_matrix); - /* Leave 't->orient_matrix_is_set' to false, - * so we overwrite it when we have a useful value. */ - /* Default to rotate on the Z axis. */ t->orient_axis = 2; t->orient_axis_ortho = 1; @@ -1529,17 +1459,17 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve } /* Assign the space type, some exceptions for running in different mode */ - if (sa == NULL) { + if (area == NULL) { /* background mode */ t->spacetype = SPACE_EMPTY; } - else if ((ar == NULL) && (sa->spacetype == SPACE_VIEW3D)) { + else if ((region == NULL) && (area->spacetype == SPACE_VIEW3D)) { /* running in the text editor */ t->spacetype = SPACE_EMPTY; } else { /* normal operation */ - t->spacetype = sa->spacetype; + t->spacetype = area->spacetype; } /* handle T_ALT_TRANSFORM initialization, we may use for different operators */ @@ -1555,7 +1485,7 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve } if (t->spacetype == SPACE_VIEW3D) { - View3D *v3d = sa->spacedata.first; + View3D *v3d = area->spacedata.first; bScreen *animscreen = ED_screen_animation_playing(CTX_wm_manager(C)); t->view = v3d; @@ -1577,22 +1507,6 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve t->around = V3D_AROUND_CURSOR; } - TransformOrientationSlot *orient_slot = &t->scene->orientation_slots[SCE_ORIENT_DEFAULT]; - t->orientation.unset = V3D_ORIENT_GLOBAL; - t->orientation.user = orient_slot->type; - t->orientation.custom = BKE_scene_transform_orientation_find(t->scene, - orient_slot->index_custom); - - t->orientation.index = 0; - ARRAY_SET_ITEMS(t->orientation.types, &t->orientation.user, NULL); - - /* Make second orientation local if both are global. */ - if (t->orientation.user == V3D_ORIENT_GLOBAL) { - t->orientation.user_alt = V3D_ORIENT_LOCAL; - t->orientation.types[0] = &t->orientation.user_alt; - SWAP(short *, t->orientation.types[0], t->orientation.types[1]); - } - /* exceptional case */ if (t->around == V3D_AROUND_LOCAL_ORIGINS) { if (ELEM(t->mode, TFM_ROTATION, TFM_RESIZE, TFM_TRACKBALL)) { @@ -1628,9 +1542,9 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve } } else if (t->spacetype == SPACE_IMAGE) { - SpaceImage *sima = sa->spacedata.first; + SpaceImage *sima = area->spacedata.first; // XXX for now, get View2D from the active region - t->view = &ar->v2d; + t->view = ®ion->v2d; t->around = sima->around; if (ED_space_image_show_uvedit(sima, OBACT(t->view_layer))) { @@ -1649,17 +1563,17 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve } else if (t->spacetype == SPACE_NODE) { // XXX for now, get View2D from the active region - t->view = &ar->v2d; + t->view = ®ion->v2d; t->around = V3D_AROUND_CENTER_BOUNDS; } else if (t->spacetype == SPACE_GRAPH) { - SpaceGraph *sipo = sa->spacedata.first; - t->view = &ar->v2d; + SpaceGraph *sipo = area->spacedata.first; + t->view = ®ion->v2d; t->around = sipo->around; } else if (t->spacetype == SPACE_CLIP) { - SpaceClip *sclip = sa->spacedata.first; - t->view = &ar->v2d; + SpaceClip *sclip = area->spacedata.first; + t->view = ®ion->v2d; t->around = sclip->around; if (ED_space_clip_check_show_trackedit(sclip)) { @@ -1670,9 +1584,9 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve } } else { - if (ar) { + if (region) { // XXX for now, get View2D from the active region - t->view = &ar->v2d; + t->view = ®ion->v2d; // XXX for now, the center point is the midpoint of the data } else { @@ -1681,49 +1595,138 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve t->around = V3D_AROUND_CENTER_BOUNDS; } - if (op && (prop = RNA_struct_find_property(op->ptr, "orient_axis"))) { - t->orient_axis = RNA_property_enum_get(op->ptr, prop); - } - if (op && (prop = RNA_struct_find_property(op->ptr, "orient_axis_ortho"))) { - t->orient_axis_ortho = RNA_property_enum_get(op->ptr, prop); - } + BLI_assert(is_zero_v4(t->values_modal_offset)); + bool t_values_set_is_array = false; + if (op && (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 */ + if (RNA_property_array_check(prop)) { + RNA_float_get_array(op->ptr, "value", values); + t_values_set_is_array = true; + } + else { + values[0] = RNA_float_get(op->ptr, "value"); + } - if (op && - ((prop = RNA_struct_find_property(op->ptr, "orient_matrix")) && - RNA_property_is_set(op->ptr, prop)) && - ((t->flag & T_MODAL) || - /* When using redo, don't use the custom constraint matrix - * if the user selects a different orientation. */ - (RNA_enum_get(op->ptr, "orient_type") == RNA_enum_get(op->ptr, "orient_matrix_type")))) { - RNA_property_float_get_array(op->ptr, prop, &t->spacemtx[0][0]); - /* Some transform modes use this to operate on an axis. */ - t->orient_matrix_is_set = true; - copy_m3_m3(t->orient_matrix, t->spacemtx); - t->orient_matrix_is_set = true; - t->orientation.user = V3D_ORIENT_CUSTOM_MATRIX; - t->orientation.custom = 0; + copy_v4_v4(t->values, values); if (t->flag & T_MODAL) { - RNA_enum_set(op->ptr, "orient_matrix_type", RNA_enum_get(op->ptr, "orient_type")); + /* Run before init functions so 'values_modal_offset' can be applied on mouse input. */ + copy_v4_v4(t->values_modal_offset, values); + } + else { + copy_v4_v4(t->values, values); + t->flag |= T_INPUT_IS_VALUES_FINAL; + } + } + + if (op && (prop = RNA_struct_find_property(op->ptr, "constraint_axis"))) { + bool constraint_axis[3] = {false, false, false}; + if (RNA_property_is_set(op->ptr, prop)) { + RNA_property_boolean_get_array(op->ptr, prop, constraint_axis); + } + + if (t_values_set_is_array && t->flag & T_INPUT_IS_VALUES_FINAL) { + /* For operators whose `t->values` is array, set contrain so that the + * orientation is more intuitive in the Redo Panel. */ + for (int i = 3; i--;) { + constraint_axis[i] |= t->values[i] != 0.0f; + } + } + + if (constraint_axis[0] || constraint_axis[1] || constraint_axis[2]) { + t->con.mode |= CON_APPLY; + + if (constraint_axis[0]) { + t->con.mode |= CON_AXIS0; + } + if (constraint_axis[1]) { + t->con.mode |= CON_AXIS1; + } + if (constraint_axis[2]) { + t->con.mode |= CON_AXIS2; + } } } - else if (op && ((prop = RNA_struct_find_property(op->ptr, "orient_type")) && - RNA_property_is_set(op->ptr, prop))) { - short orientation = RNA_property_enum_get(op->ptr, prop); + + { + TransformOrientationSlot *orient_slot = &t->scene->orientation_slots[SCE_ORIENT_DEFAULT]; TransformOrientation *custom_orientation = NULL; + short orient_type_set = -1; + short orient_type_matrix_set = -1; + short orient_type_scene = orient_slot->type; + if (orient_type_scene == V3D_ORIENT_CUSTOM) { + const int index_custom = orient_slot->index_custom; + custom_orientation = BKE_scene_transform_orientation_find(t->scene, index_custom); + orient_type_scene += index_custom; + } + + short orient_type_default = V3D_ORIENT_GLOBAL; + short orient_type_constraint[2]; + + if (op && (prop = RNA_struct_find_property(op->ptr, "orient_axis"))) { + t->orient_axis = RNA_property_enum_get(op->ptr, prop); - if (orientation >= V3D_ORIENT_CUSTOM) { - if (orientation >= V3D_ORIENT_CUSTOM + BIF_countTransformOrientation(C)) { - orientation = V3D_ORIENT_GLOBAL; + /* For transfor modes that require "orient_axis" use + * `V3D_ORIENT_VIEW` as default. */ + orient_type_default = V3D_ORIENT_VIEW; + } + if (op && (prop = RNA_struct_find_property(op->ptr, "orient_axis_ortho"))) { + t->orient_axis_ortho = RNA_property_enum_get(op->ptr, prop); + } + + if (op && ((prop = RNA_struct_find_property(op->ptr, "orient_type")) && + RNA_property_is_set(op->ptr, prop))) { + orient_type_set = RNA_property_enum_get(op->ptr, prop); + if (orient_type_set >= V3D_ORIENT_CUSTOM) { + if (orient_type_set >= V3D_ORIENT_CUSTOM + BIF_countTransformOrientation(C)) { + orient_type_set = V3D_ORIENT_GLOBAL; + } + else { + custom_orientation = BKE_scene_transform_orientation_find( + t->scene, orient_type_default - V3D_ORIENT_CUSTOM); + } + } + + /* Change the default orientation to be used when redoing. */ + orient_type_default = orient_type_set; + orient_type_constraint[0] = orient_type_set; + orient_type_constraint[1] = orient_type_scene; + } + else { + orient_type_constraint[0] = orient_type_scene; + orient_type_constraint[1] = orient_type_scene != V3D_ORIENT_GLOBAL ? V3D_ORIENT_GLOBAL : + V3D_ORIENT_LOCAL; + } + + if (op && ((prop = RNA_struct_find_property(op->ptr, "orient_matrix")) && + RNA_property_is_set(op->ptr, prop))) { + RNA_property_float_get_array(op->ptr, prop, &t->orientation.custom_matrix[0][0]); + + if ((prop = RNA_struct_find_property(op->ptr, "orient_matrix_type")) && + RNA_property_is_set(op->ptr, prop)) { + orient_type_matrix_set = RNA_property_enum_get(op->ptr, prop); + } + else if (orient_type_set != -1) { + orient_type_matrix_set = orient_type_set; } else { - custom_orientation = BKE_scene_transform_orientation_find(t->scene, - orientation - V3D_ORIENT_CUSTOM); - orientation = V3D_ORIENT_CUSTOM; + orient_type_matrix_set = orient_type_set = V3D_ORIENT_GLOBAL; + } + + if (orient_type_matrix_set == orient_type_set) { + /* Constraints are forced to use the custom matrix when redoing. */ + orient_type_default = V3D_ORIENT_CUSTOM_MATRIX; } } - t->orientation.user = orientation; + t->orientation.types[0] = orient_type_default; + t->orientation.types[1] = orient_type_constraint[0]; + t->orientation.types[2] = orient_type_constraint[1]; t->orientation.custom = custom_orientation; + + if (t->con.mode & CON_APPLY) { + t->orientation.index = 1; + } } if (op && ((prop = RNA_struct_find_property(op->ptr, "release_confirm")) && @@ -1828,6 +1831,24 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve t->options |= CTX_NO_PET; } + if (t->obedit_type == OB_MESH) { + if (op && (prop = RNA_struct_find_property(op->ptr, "use_automerge_and_split")) && + RNA_property_is_set(op->ptr, prop)) { + if (RNA_property_boolean_get(op->ptr, prop)) { + t->flag |= T_AUTOMERGE | T_AUTOSPLIT; + } + } + else { + char automerge = t->scene->toolsettings->automerge; + if (automerge & AUTO_MERGE) { + t->flag |= T_AUTOMERGE; + if (automerge & AUTO_MERGE_AND_SPLIT) { + t->flag |= T_AUTOSPLIT; + } + } + } + } + // Mirror is not supported with PET, turn it off. #if 0 if (t->flag & T_PROP_EDIT) { @@ -1889,13 +1910,13 @@ void freeTransCustomDataForMode(TransInfo *t) void postTrans(bContext *C, TransInfo *t) { if (t->draw_handle_view) { - ED_region_draw_cb_exit(t->ar->type, t->draw_handle_view); + ED_region_draw_cb_exit(t->region->type, t->draw_handle_view); } if (t->draw_handle_apply) { - ED_region_draw_cb_exit(t->ar->type, t->draw_handle_apply); + ED_region_draw_cb_exit(t->region->type, t->draw_handle_apply); } if (t->draw_handle_pixel) { - ED_region_draw_cb_exit(t->ar->type, t->draw_handle_pixel); + ED_region_draw_cb_exit(t->region->type, t->draw_handle_pixel); } if (t->draw_handle_cursor) { WM_paint_cursor_end(CTX_wm_manager(C), t->draw_handle_cursor); @@ -1941,14 +1962,14 @@ void postTrans(bContext *C, TransInfo *t) /* pass */ } else { - SpaceImage *sima = t->sa->spacedata.first; + SpaceImage *sima = t->area->spacedata.first; if (sima->flag & SI_LIVE_UNWRAP) { ED_uvedit_live_unwrap_end(t->state == TRANS_CANCEL); } } } else if (t->spacetype == SPACE_VIEW3D) { - View3D *v3d = t->sa->spacedata.first; + View3D *v3d = t->area->spacedata.first; /* restore gizmo */ if (t->flag & T_MODAL) { v3d->gizmo_flag = t->gizmo_flag; @@ -2074,10 +2095,10 @@ void calculateCenterCursor(TransInfo *t, float r_center[3]) /* If edit or pose mode, move cursor in local space */ if (t->options & CTX_PAINT_CURVE) { - if (ED_view3d_project_float_global(t->ar, cursor, r_center, V3D_PROJ_TEST_NOP) != + if (ED_view3d_project_float_global(t->region, cursor, r_center, V3D_PROJ_TEST_NOP) != V3D_PROJ_RET_OK) { - r_center[0] = t->ar->winx / 2.0f; - r_center[1] = t->ar->winy / 2.0f; + r_center[0] = t->region->winx / 2.0f; + r_center[1] = t->region->winy / 2.0f; } r_center[2] = 0.0f; } @@ -2088,11 +2109,11 @@ void calculateCenterCursor2D(TransInfo *t, float r_center[2]) const float *cursor = NULL; if (t->spacetype == SPACE_IMAGE) { - SpaceImage *sima = (SpaceImage *)t->sa->spacedata.first; + SpaceImage *sima = (SpaceImage *)t->area->spacedata.first; cursor = sima->cursor; } else if (t->spacetype == SPACE_CLIP) { - SpaceClip *space_clip = (SpaceClip *)t->sa->spacedata.first; + SpaceClip *space_clip = (SpaceClip *)t->area->spacedata.first; cursor = space_clip->cursor; } @@ -2101,11 +2122,11 @@ void calculateCenterCursor2D(TransInfo *t, float r_center[2]) float co[2]; if (t->spacetype == SPACE_IMAGE) { - SpaceImage *sima = (SpaceImage *)t->sa->spacedata.first; + SpaceImage *sima = (SpaceImage *)t->area->spacedata.first; BKE_mask_coord_from_image(sima->image, &sima->iuser, co, cursor); } else if (t->spacetype == SPACE_CLIP) { - SpaceClip *space_clip = (SpaceClip *)t->sa->spacedata.first; + SpaceClip *space_clip = (SpaceClip *)t->area->spacedata.first; BKE_mask_coord_from_movieclip(space_clip->clip, &space_clip->user, co, cursor); } else { @@ -2117,8 +2138,8 @@ void calculateCenterCursor2D(TransInfo *t, float r_center[2]) } else if (t->options & CTX_PAINT_CURVE) { if (t->spacetype == SPACE_IMAGE) { - r_center[0] = UI_view2d_view_to_region_x(&t->ar->v2d, cursor[0]); - r_center[1] = UI_view2d_view_to_region_y(&t->ar->v2d, cursor[1]); + r_center[0] = UI_view2d_view_to_region_x(&t->region->v2d, cursor[0]); + r_center[1] = UI_view2d_view_to_region_y(&t->region->v2d, cursor[1]); } } else { @@ -2130,7 +2151,7 @@ void calculateCenterCursor2D(TransInfo *t, float r_center[2]) void calculateCenterCursorGraph2D(TransInfo *t, float r_center[2]) { - SpaceGraph *sipo = (SpaceGraph *)t->sa->spacedata.first; + SpaceGraph *sipo = (SpaceGraph *)t->area->spacedata.first; Scene *scene = t->scene; /* cursor is combination of current frame, and graph-editor cursor value */ @@ -2300,7 +2321,7 @@ void calculateCenter(TransInfo *t) /* for panning from cameraview */ if ((t->flag & T_OBJECT) && (t->flag & T_OVERRIDE_CENTER) == 0) { - if (t->spacetype == SPACE_VIEW3D && t->ar && t->ar->regiontype == RGN_TYPE_WINDOW) { + if (t->spacetype == SPACE_VIEW3D && t->region && t->region->regiontype == RGN_TYPE_WINDOW) { if (t->flag & T_CAMERA) { float axis[3]; @@ -2333,8 +2354,8 @@ void calculateCenter(TransInfo *t) * We need special case here as well, since ED_view3d_calc_zfac will crash when called * for a region different from RGN_TYPE_WINDOW. */ - if (t->ar->regiontype == RGN_TYPE_WINDOW) { - t->zfac = ED_view3d_calc_zfac(t->ar->regiondata, t->center_global, NULL); + if (t->region->regiontype == RGN_TYPE_WINDOW) { + t->zfac = ED_view3d_calc_zfac(t->region->regiondata, t->center_global, NULL); } else { t->zfac = 0.0f; diff --git a/source/blender/editors/transform/transform_gizmo_2d.c b/source/blender/editors/transform/transform_gizmo_2d.c index 793552865a6..50317d8b395 100644 --- a/source/blender/editors/transform/transform_gizmo_2d.c +++ b/source/blender/editors/transform/transform_gizmo_2d.c @@ -42,15 +42,15 @@ #include "UI_view2d.h" #include "WM_api.h" +#include "WM_message.h" #include "WM_types.h" #include "wm.h" /* XXX */ -#include "WM_message.h" +#include "ED_gizmo_library.h" #include "ED_gizmo_utils.h" #include "ED_image.h" #include "ED_screen.h" #include "ED_uvedit.h" -#include "ED_gizmo_library.h" #include "transform.h" /* own include */ @@ -68,10 +68,10 @@ static bool gizmo2d_generic_poll(const bContext *C, wmGizmoGroupType *gzgt) return false; } - ScrArea *sa = CTX_wm_area(C); - switch (sa->spacetype) { + ScrArea *area = CTX_wm_area(C); + switch (area->spacetype) { case SPACE_IMAGE: { - SpaceImage *sima = sa->spacedata.first; + SpaceImage *sima = area->spacedata.first; Object *obedit = CTX_data_edit_object(C); if (!ED_space_image_show_uvedit(sima, obedit)) { return false; @@ -86,18 +86,18 @@ static void gizmo2d_pivot_point_message_subscribe(struct wmGizmoGroup *gzgroup, struct wmMsgBus *mbus, /* Additional args. */ bScreen *screen, - ScrArea *sa, - ARegion *ar) + ScrArea *area, + ARegion *region) { wmMsgSubscribeValue msg_sub_value_gz_tag_refresh = { - .owner = ar, + .owner = region, .user_data = gzgroup->parent_gzmap, .notify = WM_gizmo_do_msg_notify_tag_refresh, }; - switch (sa->spacetype) { + switch (area->spacetype) { case SPACE_IMAGE: { - SpaceImage *sima = sa->spacedata.first; + SpaceImage *sima = area->spacedata.first; PointerRNA ptr; RNA_pointer_create(&screen->id, &RNA_SpaceImageEditor, sima, &ptr); { @@ -214,10 +214,10 @@ static bool gizmo2d_calc_bounds(const bContext *C, float *r_center, float *r_min r_max = max_buf; } - ScrArea *sa = CTX_wm_area(C); + ScrArea *area = CTX_wm_area(C); bool changed = false; - if (sa->spacetype == SPACE_IMAGE) { - SpaceImage *sima = sa->spacedata.first; + if (area->spacetype == SPACE_IMAGE) { + SpaceImage *sima = area->spacedata.first; Scene *scene = CTX_data_scene(C); ViewLayer *view_layer = CTX_data_view_layer(C); Image *ima = ED_space_image(sima); @@ -241,11 +241,11 @@ static bool gizmo2d_calc_bounds(const bContext *C, float *r_center, float *r_min static bool gizmo2d_calc_center(const bContext *C, float r_center[2]) { - ScrArea *sa = CTX_wm_area(C); + ScrArea *area = CTX_wm_area(C); bool has_select = false; zero_v2(r_center); - if (sa->spacetype == SPACE_IMAGE) { - SpaceImage *sima = sa->spacedata.first; + if (area->spacetype == SPACE_IMAGE) { + SpaceImage *sima = area->spacedata.first; Scene *scene = CTX_data_scene(C); ViewLayer *view_layer = CTX_data_view_layer(C); ED_uvedit_center_from_pivot_ex(sima, scene, view_layer, r_center, sima->around, &has_select); @@ -256,9 +256,9 @@ static bool gizmo2d_calc_center(const bContext *C, float r_center[2]) /** * Convert origin (or any other point) from view to region space. */ -BLI_INLINE void gizmo2d_origin_to_region(ARegion *ar, float *r_origin) +BLI_INLINE void gizmo2d_origin_to_region(ARegion *region, float *r_origin) { - UI_view2d_view_to_region_fl(&ar->v2d, r_origin[0], r_origin[1], &r_origin[0], &r_origin[1]); + UI_view2d_view_to_region_fl(®ion->v2d, r_origin[0], r_origin[1], &r_origin[0], &r_origin[1]); } /** @@ -269,14 +269,14 @@ static int gizmo2d_modal(bContext *C, const wmEvent *UNUSED(event), eWM_GizmoFlagTweak UNUSED(tweak_flag)) { - ARegion *ar = CTX_wm_region(C); + ARegion *region = CTX_wm_region(C); float origin[3]; gizmo2d_calc_center(C, origin); - gizmo2d_origin_to_region(ar, origin); + gizmo2d_origin_to_region(region, origin); WM_gizmo_set_matrix_location(widget, origin); - ED_region_tag_redraw(ar); + ED_region_tag_redraw_editor_overlays(region); return OPERATOR_RUNNING_MODAL; } @@ -300,7 +300,7 @@ static void gizmo2d_xform_setup(const bContext *UNUSED(C), wmGizmoGroup *gzgroup /* set up widget data */ RNA_float_set(gz->ptr, "length", 0.8f); float axis[3] = {0.0f}; - axis[(i + 1) % 2] = 1.0f; + axis[i] = 1.0f; WM_gizmo_set_matrix_rotation_from_z_axis(gz, axis); float offset[3] = {0, 0, 0}; @@ -315,6 +315,11 @@ static void gizmo2d_xform_setup(const bContext *UNUSED(C), wmGizmoGroup *gzgroup WM_gizmo_set_scale(gz, 1.0f); } else { + float color[4], color_hi[4]; + UI_GetThemeColor4fv(TH_GIZMO_VIEW_ALIGN, color); + copy_v4_v4(color_hi, color); + color[3] *= 0.6f; + PropertyRNA *prop = RNA_struct_find_property(gz->ptr, "icon"); RNA_property_enum_set(gz->ptr, prop, ICON_NONE); @@ -322,7 +327,8 @@ static void gizmo2d_xform_setup(const bContext *UNUSED(C), wmGizmoGroup *gzgroup /* Make the center low alpha. */ WM_gizmo_set_line_width(gz, 2.0f); RNA_float_set(gz->ptr, "backdrop_fill_alpha", 0.0); - WM_gizmo_set_color(gz, (const float[4]){1, 1, 1, 0.6}); + WM_gizmo_set_color(gz, color); + WM_gizmo_set_color_highlight(gz, color_hi); WM_gizmo_set_scale(gz, 0.2f); } @@ -330,8 +336,8 @@ static void gizmo2d_xform_setup(const bContext *UNUSED(C), wmGizmoGroup *gzgroup /* Assign operator. */ PointerRNA *ptr = WM_gizmo_operator_set(gz, 0, ot_translate, NULL); if (i < 2) { - bool constraint[3] = {0}; - constraint[(i + 1) % 2] = 1; + bool constraint[3] = {false}; + constraint[i] = true; if (RNA_struct_find_property(ptr, "constraint_axis")) { RNA_boolean_set_array(ptr, "constraint_axis", constraint); } @@ -480,19 +486,19 @@ static void gizmo2d_xform_refresh(const bContext *C, wmGizmoGroup *gzgroup) static void gizmo2d_xform_draw_prepare(const bContext *C, wmGizmoGroup *gzgroup) { - ARegion *ar = CTX_wm_region(C); + ARegion *region = CTX_wm_region(C); GizmoGroup2D *ggd = gzgroup->customdata; float origin[3] = {UNPACK2(ggd->origin), 0.0f}; float origin_aa[3] = {UNPACK2(ggd->origin), 0.0f}; - gizmo2d_origin_to_region(ar, origin); + gizmo2d_origin_to_region(region, origin); for (int i = 0; i < ARRAY_SIZE(ggd->translate_xy); i++) { wmGizmo *gz = ggd->translate_xy[i]; WM_gizmo_set_matrix_location(gz, origin); } - UI_view2d_view_to_region_m4(&ar->v2d, ggd->cage->matrix_space); + UI_view2d_view_to_region_m4(®ion->v2d, ggd->cage->matrix_space); WM_gizmo_set_matrix_offset_location(ggd->cage, origin_aa); ggd->cage->matrix_offset[0][0] = (ggd->max[0] - ggd->min[0]); ggd->cage->matrix_offset[1][1] = (ggd->max[1] - ggd->min[1]); @@ -503,9 +509,9 @@ static void gizmo2d_xform_no_cage_message_subscribe(const struct bContext *C, struct wmMsgBus *mbus) { bScreen *screen = CTX_wm_screen(C); - ScrArea *sa = CTX_wm_area(C); - ARegion *ar = CTX_wm_region(C); - gizmo2d_pivot_point_message_subscribe(gzgroup, mbus, screen, sa, ar); + ScrArea *area = CTX_wm_area(C); + ARegion *region = CTX_wm_region(C); + gizmo2d_pivot_point_message_subscribe(gzgroup, mbus, screen, area, region); } void ED_widgetgroup_gizmo2d_xform_callbacks_set(wmGizmoGroupType *gzgt) @@ -575,7 +581,7 @@ static void gizmo2d_resize_refresh(const bContext *C, wmGizmoGroup *gzgroup) static void gizmo2d_resize_draw_prepare(const bContext *C, wmGizmoGroup *gzgroup) { - ARegion *ar = CTX_wm_region(C); + ARegion *region = CTX_wm_region(C); GizmoGroup_Resize2D *ggd = gzgroup->customdata; float origin[3] = {UNPACK2(ggd->origin), 0.0f}; @@ -589,7 +595,7 @@ static void gizmo2d_resize_draw_prepare(const bContext *C, wmGizmoGroup *gzgroup } } - gizmo2d_origin_to_region(ar, origin); + gizmo2d_origin_to_region(region, origin); for (int i = 0; i < ARRAY_SIZE(ggd->gizmo_xy); i++) { wmGizmo *gz = ggd->gizmo_xy[i]; @@ -629,6 +635,11 @@ static void gizmo2d_resize_setup(const bContext *UNUSED(C), wmGizmoGroup *gzgrou WM_gizmo_set_scale(gz, 1.0f); } else { + float color[4], color_hi[4]; + UI_GetThemeColor4fv(TH_GIZMO_VIEW_ALIGN, color); + copy_v4_v4(color_hi, color); + color[3] *= 0.6f; + PropertyRNA *prop = RNA_struct_find_property(gz->ptr, "icon"); RNA_property_enum_set(gz->ptr, prop, ICON_NONE); @@ -636,7 +647,8 @@ static void gizmo2d_resize_setup(const bContext *UNUSED(C), wmGizmoGroup *gzgrou /* Make the center low alpha. */ WM_gizmo_set_line_width(gz, 2.0f); RNA_float_set(gz->ptr, "backdrop_fill_alpha", 0.0); - WM_gizmo_set_color(gz, (const float[4]){1, 1, 1, 0.6}); + WM_gizmo_set_color(gz, color); + WM_gizmo_set_color_highlight(gz, color_hi); WM_gizmo_set_scale(gz, 1.2f); } @@ -659,9 +671,9 @@ static void gizmo2d_resize_message_subscribe(const struct bContext *C, struct wmMsgBus *mbus) { bScreen *screen = CTX_wm_screen(C); - ScrArea *sa = CTX_wm_area(C); - ARegion *ar = CTX_wm_region(C); - gizmo2d_pivot_point_message_subscribe(gzgroup, mbus, screen, sa, ar); + ScrArea *area = CTX_wm_area(C); + ARegion *region = CTX_wm_region(C); + gizmo2d_pivot_point_message_subscribe(gzgroup, mbus, screen, area, region); } void ED_widgetgroup_gizmo2d_resize_callbacks_set(wmGizmoGroupType *gzgt) @@ -718,7 +730,7 @@ static void gizmo2d_rotate_refresh(const bContext *C, wmGizmoGroup *gzgroup) static void gizmo2d_rotate_draw_prepare(const bContext *C, wmGizmoGroup *gzgroup) { - ARegion *ar = CTX_wm_region(C); + ARegion *region = CTX_wm_region(C); GizmoGroup_Rotate2D *ggd = gzgroup->customdata; float origin[3] = {UNPACK2(ggd->origin), 0.0f}; @@ -732,7 +744,7 @@ static void gizmo2d_rotate_draw_prepare(const bContext *C, wmGizmoGroup *gzgroup } } - gizmo2d_origin_to_region(ar, origin); + gizmo2d_origin_to_region(region, origin); wmGizmo *gz = ggd->gizmo; WM_gizmo_set_matrix_location(gz, origin); @@ -754,6 +766,9 @@ static void gizmo2d_rotate_setup(const bContext *UNUSED(C), wmGizmoGroup *gzgrou WM_gizmo_set_scale(gz, 1.2f); { + float color[4]; + UI_GetThemeColor4fv(TH_GIZMO_VIEW_ALIGN, color); + PropertyRNA *prop = RNA_struct_find_property(gz->ptr, "icon"); RNA_property_enum_set(gz->ptr, prop, ICON_NONE); @@ -761,7 +776,8 @@ static void gizmo2d_rotate_setup(const bContext *UNUSED(C), wmGizmoGroup *gzgrou /* Make the center low alpha. */ WM_gizmo_set_line_width(gz, 2.0f); RNA_float_set(gz->ptr, "backdrop_fill_alpha", 0.0); - WM_gizmo_set_color(gz, (const float[4]){1, 1, 1, 0.6}); + WM_gizmo_set_color(gz, color); + WM_gizmo_set_color_highlight(gz, color); } /* Assign operator. */ @@ -775,9 +791,9 @@ static void gizmo2d_rotate_message_subscribe(const struct bContext *C, struct wmMsgBus *mbus) { bScreen *screen = CTX_wm_screen(C); - ScrArea *sa = CTX_wm_area(C); - ARegion *ar = CTX_wm_region(C); - gizmo2d_pivot_point_message_subscribe(gzgroup, mbus, screen, sa, ar); + ScrArea *area = CTX_wm_area(C); + ARegion *region = CTX_wm_region(C); + gizmo2d_pivot_point_message_subscribe(gzgroup, mbus, screen, area, region); } void ED_widgetgroup_gizmo2d_rotate_callbacks_set(wmGizmoGroupType *gzgt) diff --git a/source/blender/editors/transform/transform_gizmo_3d.c b/source/blender/editors/transform/transform_gizmo_3d.c index b3c1fbd3aad..b575030778f 100644 --- a/source/blender/editors/transform/transform_gizmo_3d.c +++ b/source/blender/editors/transform/transform_gizmo_3d.c @@ -22,58 +22,58 @@ * Used for 3D View */ +#include <float.h> +#include <math.h> #include <stdlib.h> #include <string.h> -#include <math.h> -#include <float.h> #include "DNA_armature_types.h" #include "DNA_curve_types.h" #include "DNA_gpencil_types.h" #include "DNA_lattice_types.h" #include "DNA_meta_types.h" -#include "DNA_screen_types.h" #include "DNA_scene_types.h" +#include "DNA_screen_types.h" #include "DNA_view3d_types.h" #include "BLI_array_utils.h" #include "BLI_listbase.h" #include "BLI_math.h" -#include "BLI_utildefines.h" #include "BLI_string.h" +#include "BLI_utildefines.h" #include "BKE_action.h" #include "BKE_context.h" #include "BKE_curve.h" +#include "BKE_editmesh.h" #include "BKE_global.h" +#include "BKE_gpencil.h" +#include "BKE_lattice.h" #include "BKE_layer.h" +#include "BKE_object.h" +#include "BKE_paint.h" #include "BKE_particle.h" #include "BKE_pointcache.h" -#include "BKE_editmesh.h" -#include "BKE_lattice.h" -#include "BKE_gpencil.h" #include "BKE_scene.h" #include "BKE_workspace.h" -#include "BKE_object.h" -#include "BKE_paint.h" #include "DEG_depsgraph.h" #include "WM_api.h" -#include "WM_types.h" #include "WM_message.h" #include "WM_toolsystem.h" +#include "WM_types.h" #include "wm.h" #include "ED_armature.h" #include "ED_curve.h" +#include "ED_gizmo_library.h" +#include "ED_gizmo_utils.h" +#include "ED_gpencil.h" #include "ED_object.h" #include "ED_particle.h" -#include "ED_view3d.h" -#include "ED_gpencil.h" #include "ED_screen.h" -#include "ED_gizmo_library.h" -#include "ED_gizmo_utils.h" +#include "ED_view3d.h" #include "UI_interface.h" #include "UI_resources.h" @@ -347,7 +347,7 @@ static void gizmo_get_axis_color(const int axis_idx, if (axis_idx >= MAN_AXIS_RANGE_ROT_START && axis_idx < MAN_AXIS_RANGE_ROT_END) { /* Never fade rotation rings. */ /* trackball rotation axis is a special case, we only draw a slight overlay */ - alpha_fac = (axis_idx == MAN_AXIS_ROT_T) ? 0.1f : 1.0f; + alpha_fac = (axis_idx == MAN_AXIS_ROT_T) ? 0.05f : 1.0f; } else { bool is_plane = false; @@ -397,7 +397,7 @@ static void gizmo_get_axis_color(const int axis_idx, case MAN_AXIS_ROT_C: case MAN_AXIS_SCALE_C: case MAN_AXIS_ROT_T: - copy_v4_fl(r_col, 1.0f); + UI_GetThemeColor4fv(TH_GIZMO_VIEW_ALIGN, r_col); break; } @@ -637,11 +637,11 @@ bool gimbal_axis(Object *ob, float gmat[3][3]) void ED_transform_calc_orientation_from_type(const bContext *C, float r_mat[3][3]) { - ARegion *ar = CTX_wm_region(C); + ARegion *region = CTX_wm_region(C); Scene *scene = CTX_data_scene(C); ViewLayer *view_layer = CTX_data_view_layer(C); Object *obedit = CTX_data_edit_object(C); - RegionView3D *rv3d = ar->regiondata; + RegionView3D *rv3d = region->regiondata; Object *ob = OBACT(view_layer); const short orientation_type = scene->orientation_slots[SCE_ORIENT_DEFAULT].type; const short orientation_index_custom = scene->orientation_slots[SCE_ORIENT_DEFAULT].index_custom; @@ -713,7 +713,9 @@ void ED_transform_calc_orientation_from_type_ex(const bContext *C, ok = true; break; } - case V3D_ORIENT_CUSTOM: { + case V3D_ORIENT_CUSTOM: + default: { + BLI_assert(orientation_type >= V3D_ORIENT_CUSTOM); TransformOrientation *custom_orientation = BKE_scene_transform_orientation_find( scene, orientation_index_custom); if (applyTransformOrientation(custom_orientation, r_mat, NULL)) { @@ -734,16 +736,16 @@ int ED_transform_calc_gizmo_stats(const bContext *C, const struct TransformCalcParams *params, struct TransformBounds *tbounds) { - ScrArea *sa = CTX_wm_area(C); - ARegion *ar = CTX_wm_region(C); + ScrArea *area = CTX_wm_area(C); + ARegion *region = CTX_wm_region(C); Scene *scene = CTX_data_scene(C); /* TODO(sergey): This function is used from operator's modal() and from gizmo's refresh(). * Is it fine to possibly evaluate dependency graph here? */ Depsgraph *depsgraph = CTX_data_expect_evaluated_depsgraph(C); ViewLayer *view_layer = CTX_data_view_layer(C); - View3D *v3d = sa->spacedata.first; + View3D *v3d = area->spacedata.first; Object *obedit = CTX_data_edit_object(C); - RegionView3D *rv3d = ar->regiondata; + RegionView3D *rv3d = region->regiondata; Base *base; Object *ob = OBACT(view_layer); bGPdata *gpd = CTX_data_gpencil_data(C); @@ -792,15 +794,15 @@ int ED_transform_calc_gizmo_stats(const bContext *C, if (is_gp_edit) { float diff_mat[4][4]; const bool use_mat_local = true; - for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) { + LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) { /* only editable and visible layers are considered */ - if (gpencil_layer_is_editable(gpl) && (gpl->actframe != NULL)) { + if (BKE_gpencil_layer_is_editable(gpl) && (gpl->actframe != NULL)) { /* calculate difference matrix */ - ED_gpencil_parent_location(depsgraph, ob, gpd, gpl, diff_mat); + BKE_gpencil_parent_matrix_get(depsgraph, ob, gpl, diff_mat); - for (bGPDstroke *gps = gpl->actframe->strokes.first; gps; gps = gps->next) { + LISTBASE_FOREACH (bGPDstroke *, gps, &gpl->actframe->strokes) { /* skip strokes that are invalid for current view */ if (ED_gpencil_stroke_can_use(C, gps) == false) { continue; @@ -883,7 +885,7 @@ int ED_transform_calc_gizmo_stats(const bContext *C, if (use_mat_local) { mul_m4_m4m4(mat_local, obedit->imat, ob_iter->obmat); } - for (EditBone *ebo = arm->edbo->first; ebo; ebo = ebo->next) { + LISTBASE_FOREACH (EditBone *, ebo, arm->edbo) { if (EBONE_VISIBLE(arm, ebo)) { if (ebo->flag & BONE_TIPSEL) { calc_tw_center_with_matrix(tbounds, ebo->tail, use_mat_local, mat_local); @@ -977,7 +979,7 @@ int ED_transform_calc_gizmo_stats(const bContext *C, mul_m4_m4m4(mat_local, obedit->imat, ob_iter->obmat); } - for (MetaElem *ml = mb->editelems->first; ml; ml = ml->next) { + LISTBASE_FOREACH (MetaElem *, ml, mb->editelems) { if (ml->flag & SELECT) { calc_tw_center_with_matrix(tbounds, &ml->x, use_mat_local, mat_local); totsel++; @@ -1033,7 +1035,7 @@ int ED_transform_calc_gizmo_stats(const bContext *C, /* mislead counting bones... bah. We don't know the gizmo mode, could be mixed */ const int mode = TFM_ROTATION; - const int totsel_iter = count_set_pose_transflags( + const int totsel_iter = transform_convert_pose_transflags_update( ob_iter, mode, V3D_AROUND_CENTER_BOUNDS, NULL); if (totsel_iter) { @@ -1244,13 +1246,13 @@ static void gizmo_xform_message_subscribe(wmGizmoGroup *gzgroup, struct wmMsgBus *mbus, Scene *scene, bScreen *screen, - ScrArea *sa, - ARegion *ar, + ScrArea *area, + ARegion *region, const void *type_fn) { /* Subscribe to view properties */ wmMsgSubscribeValue msg_sub_value_gz_tag_refresh = { - .owner = ar, + .owner = region, .user_data = gzgroup->parent_gzmap, .notify = WM_gizmo_do_msg_notify_tag_refresh, }; @@ -1334,7 +1336,7 @@ static void gizmo_xform_message_subscribe(wmGizmoGroup *gzgroup, } PointerRNA view3d_ptr; - RNA_pointer_create(&screen->id, &RNA_SpaceView3D, sa->spacedata.first, &view3d_ptr); + RNA_pointer_create(&screen->id, &RNA_SpaceView3D, area->spacedata.first, &view3d_ptr); if (type_fn == VIEW3D_GGT_xform_gizmo) { GizmoGroup *ggd = gzgroup->customdata; @@ -1369,7 +1371,7 @@ static void gizmo_xform_message_subscribe(wmGizmoGroup *gzgroup, void drawDial3d(const TransInfo *t) { if (t->mode == TFM_ROTATION && t->spacetype == SPACE_VIEW3D) { - wmGizmo *gz = wm_gizmomap_modal_get(t->ar->gizmo_map); + wmGizmo *gz = wm_gizmomap_modal_get(t->region->gizmo_map); if (gz == NULL) { /* We only draw Dial3d if the operator has been called by a gizmo. */ return; @@ -1402,7 +1404,7 @@ void drawDial3d(const TransInfo *t) } else { axis_idx = MAN_AXIS_ROT_C; - negate_v3_v3(mat_basis[2], t->orient_matrix[t->orient_axis]); + negate_v3_v3(mat_basis[2], t->spacemtx[t->orient_axis]); scale *= 1.2f; line_with -= 1.0f; } @@ -1411,7 +1413,7 @@ void drawDial3d(const TransInfo *t) mat_basis[2][3] = -dot_v3v3(mat_basis[2], mat_basis[3]); if (ED_view3d_win_to_3d_on_plane( - t->ar, mat_basis[2], (float[2]){UNPACK2(t->mouse.imval)}, false, mat_basis[1])) { + t->region, mat_basis[2], (float[2]){UNPACK2(t->mouse.imval)}, false, mat_basis[1])) { sub_v3_v3(mat_basis[1], mat_basis[3]); normalize_v3(mat_basis[1]); cross_v3_v3v3(mat_basis[0], mat_basis[1], mat_basis[2]); @@ -1428,7 +1430,7 @@ void drawDial3d(const TransInfo *t) mat_basis[3][3] = 1.0f; copy_m4_m4(mat_final, mat_basis); - scale *= ED_view3d_pixel_size_no_ui_scale(t->ar->regiondata, mat_final[3]); + scale *= ED_view3d_pixel_size_no_ui_scale(t->region->regiondata, mat_final[3]); mul_mat3_m4_fl(mat_final, scale); if (activeSnap(t) && (!transformModeUseSnap(t) || @@ -1554,8 +1556,8 @@ static int gizmo_modal(bContext *C, return OPERATOR_RUNNING_MODAL; } - ARegion *ar = CTX_wm_region(C); - RegionView3D *rv3d = ar->regiondata; + ARegion *region = CTX_wm_region(C); + RegionView3D *rv3d = region->regiondata; struct TransformBounds tbounds; if (ED_transform_calc_gizmo_stats(C, @@ -1567,7 +1569,7 @@ static int gizmo_modal(bContext *C, WM_gizmo_set_matrix_location(widget, rv3d->twmat[3]); } - ED_region_tag_redraw(ar); + ED_region_tag_redraw_editor_overlays(region); return OPERATOR_RUNNING_MODAL; } @@ -1701,8 +1703,8 @@ static void WIDGETGROUP_gizmo_setup(const bContext *C, wmGizmoGroup *gzgroup) gzgroup->customdata = ggd; { - ScrArea *sa = CTX_wm_area(C); - const bToolRef *tref = sa->runtime.tool; + ScrArea *area = CTX_wm_area(C); + const bToolRef *tref = area->runtime.tool; ggd->twtype = 0; if (tref && STREQ(tref->idname, "builtin.move")) { @@ -1737,10 +1739,10 @@ static void WIDGETGROUP_gizmo_refresh(const bContext *C, wmGizmoGroup *gzgroup) { GizmoGroup *ggd = gzgroup->customdata; Scene *scene = CTX_data_scene(C); - ScrArea *sa = CTX_wm_area(C); - View3D *v3d = sa->spacedata.first; - ARegion *ar = CTX_wm_region(C); - RegionView3D *rv3d = ar->regiondata; + ScrArea *area = CTX_wm_area(C); + View3D *v3d = area->spacedata.first; + ARegion *region = CTX_wm_region(C); + RegionView3D *rv3d = region->regiondata; struct TransformBounds tbounds; if (scene->toolsettings->workspace_tool_type == SCE_WORKSPACE_TOOL_FALLBACK) { @@ -1844,25 +1846,26 @@ static void WIDGETGROUP_gizmo_message_subscribe(const bContext *C, { Scene *scene = CTX_data_scene(C); bScreen *screen = CTX_wm_screen(C); - ScrArea *sa = CTX_wm_area(C); - ARegion *ar = CTX_wm_region(C); - gizmo_xform_message_subscribe(gzgroup, mbus, scene, screen, sa, ar, VIEW3D_GGT_xform_gizmo); + ScrArea *area = CTX_wm_area(C); + ARegion *region = CTX_wm_region(C); + gizmo_xform_message_subscribe( + gzgroup, mbus, scene, screen, area, region, VIEW3D_GGT_xform_gizmo); } static void WIDGETGROUP_gizmo_draw_prepare(const bContext *C, wmGizmoGroup *gzgroup) { GizmoGroup *ggd = gzgroup->customdata; - // ScrArea *sa = CTX_wm_area(C); - ARegion *ar = CTX_wm_region(C); - // View3D *v3d = sa->spacedata.first; - RegionView3D *rv3d = ar->regiondata; + // ScrArea *area = CTX_wm_area(C); + ARegion *region = CTX_wm_region(C); + // View3D *v3d = area->spacedata.first; + RegionView3D *rv3d = region->regiondata; float viewinv_m3[3][3]; copy_m3_m4(viewinv_m3, rv3d->viewinv); float idot[3]; /* when looking through a selected camera, the gizmo can be at the * exact same position as the view, skip so we don't break selection */ - if (ggd->all_hidden || fabsf(ED_view3d_pixel_size(rv3d, rv3d->twmat[3])) < 1e-6f) { + if (ggd->all_hidden || fabsf(ED_view3d_pixel_size(rv3d, rv3d->twmat[3])) < 5e-7f) { MAN_ITER_AXES_BEGIN (axis, axis_idx) { WM_gizmo_set_flag(axis, WM_GIZMO_HIDDEN, true); } @@ -1997,13 +2000,13 @@ static bool WIDGETGROUP_gizmo_poll_generic(View3D *v3d) static bool WIDGETGROUP_gizmo_poll_context(const struct bContext *C, struct wmGizmoGroupType *UNUSED(gzgt)) { - ScrArea *sa = CTX_wm_area(C); - View3D *v3d = sa->spacedata.first; + ScrArea *area = CTX_wm_area(C); + View3D *v3d = area->spacedata.first; if (!WIDGETGROUP_gizmo_poll_generic(v3d)) { return false; } - const bToolRef *tref = sa->runtime.tool; + const bToolRef *tref = area->runtime.tool; if (v3d->gizmo_flag & V3D_GIZMO_HIDE_CONTEXT) { return false; } @@ -2025,8 +2028,8 @@ static bool WIDGETGROUP_gizmo_poll_tool(const struct bContext *C, struct wmGizmo return false; } - ScrArea *sa = CTX_wm_area(C); - View3D *v3d = sa->spacedata.first; + ScrArea *area = CTX_wm_area(C); + View3D *v3d = area->spacedata.first; if (!WIDGETGROUP_gizmo_poll_generic(v3d)) { return false; } @@ -2168,8 +2171,8 @@ static void WIDGETGROUP_xform_cage_setup(const bContext *UNUSED(C), wmGizmoGroup static void WIDGETGROUP_xform_cage_refresh(const bContext *C, wmGizmoGroup *gzgroup) { - ARegion *ar = CTX_wm_region(C); - RegionView3D *rv3d = ar->regiondata; + ARegion *region = CTX_wm_region(C); + RegionView3D *rv3d = region->regiondata; Scene *scene = CTX_data_scene(C); struct XFormCageWidgetGroup *xgzgroup = gzgroup->customdata; @@ -2247,9 +2250,9 @@ static void WIDGETGROUP_xform_cage_message_subscribe(const bContext *C, { Scene *scene = CTX_data_scene(C); bScreen *screen = CTX_wm_screen(C); - ScrArea *sa = CTX_wm_area(C); - ARegion *ar = CTX_wm_region(C); - gizmo_xform_message_subscribe(gzgroup, mbus, scene, screen, sa, ar, VIEW3D_GGT_xform_cage); + ScrArea *area = CTX_wm_area(C); + ARegion *region = CTX_wm_region(C); + gizmo_xform_message_subscribe(gzgroup, mbus, scene, screen, area, region, VIEW3D_GGT_xform_cage); } static void WIDGETGROUP_xform_cage_draw_prepare(const bContext *C, wmGizmoGroup *gzgroup) @@ -2384,8 +2387,8 @@ static void WIDGETGROUP_xform_shear_setup(const bContext *UNUSED(C), wmGizmoGrou static void WIDGETGROUP_xform_shear_refresh(const bContext *C, wmGizmoGroup *gzgroup) { Scene *scene = CTX_data_scene(C); - ARegion *ar = CTX_wm_region(C); - RegionView3D *rv3d = ar->regiondata; + ARegion *region = CTX_wm_region(C); + RegionView3D *rv3d = region->regiondata; struct XFormShearWidgetGroup *xgzgroup = gzgroup->customdata; struct TransformBounds tbounds; @@ -2460,9 +2463,10 @@ static void WIDGETGROUP_xform_shear_message_subscribe(const bContext *C, { Scene *scene = CTX_data_scene(C); bScreen *screen = CTX_wm_screen(C); - ScrArea *sa = CTX_wm_area(C); - ARegion *ar = CTX_wm_region(C); - gizmo_xform_message_subscribe(gzgroup, mbus, scene, screen, sa, ar, VIEW3D_GGT_xform_shear); + ScrArea *area = CTX_wm_area(C); + ARegion *region = CTX_wm_region(C); + gizmo_xform_message_subscribe( + gzgroup, mbus, scene, screen, area, region, VIEW3D_GGT_xform_shear); } static void WIDGETGROUP_xform_shear_draw_prepare(const bContext *C, wmGizmoGroup *gzgroup) diff --git a/source/blender/editors/transform/transform_gizmo_extrude_3d.c b/source/blender/editors/transform/transform_gizmo_extrude_3d.c index fb33471cf3f..e6e74668c2c 100644 --- a/source/blender/editors/transform/transform_gizmo_extrude_3d.c +++ b/source/blender/editors/transform/transform_gizmo_extrude_3d.c @@ -18,10 +18,10 @@ * \ingroup edmesh */ -#include "BLI_utildefines.h" #include "BLI_array_utils.h" -#include "BLI_math.h" #include "BLI_listbase.h" +#include "BLI_math.h" +#include "BLI_utildefines.h" #include "BKE_context.h" #include "BKE_global.h" @@ -30,15 +30,15 @@ #include "RNA_define.h" #include "WM_api.h" -#include "WM_types.h" #include "WM_message.h" #include "WM_toolsystem.h" +#include "WM_types.h" +#include "ED_gizmo_library.h" +#include "ED_gizmo_utils.h" #include "ED_screen.h" #include "ED_transform.h" #include "ED_view3d.h" -#include "ED_gizmo_library.h" -#include "ED_gizmo_utils.h" #include "UI_resources.h" @@ -469,11 +469,11 @@ static void gizmo_mesh_extrude_message_subscribe(const bContext *C, struct wmMsgBus *mbus) { GizmoExtrudeGroup *ggd = gzgroup->customdata; - ARegion *ar = CTX_wm_region(C); + ARegion *region = CTX_wm_region(C); /* Subscribe to view properties */ wmMsgSubscribeValue msg_sub_value_gz_tag_refresh = { - .owner = ar, + .owner = region, .user_data = gzgroup->parent_gzmap, .notify = WM_gizmo_do_msg_notify_tag_refresh, }; diff --git a/source/blender/editors/transform/transform_input.c b/source/blender/editors/transform/transform_input.c index 8dc403c45d2..078020e932e 100644 --- a/source/blender/editors/transform/transform_input.c +++ b/source/blender/editors/transform/transform_input.c @@ -18,8 +18,8 @@ * \ingroup edtransform */ -#include <stdlib.h> #include <math.h> +#include <stdlib.h> #include "DNA_screen_types.h" @@ -28,20 +28,24 @@ #include "BLI_math.h" #include "BLI_utildefines.h" -#include "WM_types.h" #include "WM_api.h" +#include "WM_types.h" #include "transform.h" #include "MEM_guardedalloc.h" -/* ************************** INPUT FROM MOUSE *************************** */ +/* -------------------------------------------------------------------- */ +/** \name Callbacks for #MouseInput.apply + * \{ */ +/** Callback for #INPUT_VECTOR */ static void InputVector(TransInfo *t, MouseInput *mi, const double mval[2], float output[3]) { convertViewVec(t, output, mval[0] - mi->imval[0], mval[1] - mi->imval[1]); } +/** Callback for #INPUT_SPRING */ static void InputSpring(TransInfo *UNUSED(t), MouseInput *mi, const double mval[2], @@ -57,6 +61,7 @@ static void InputSpring(TransInfo *UNUSED(t), output[0] = ratio; } +/** Callback for #INPUT_SPRING_FLIP */ static void InputSpringFlip(TransInfo *t, MouseInput *mi, const double mval[2], float output[3]) { InputSpring(t, mi, mval, output); @@ -70,12 +75,14 @@ static void InputSpringFlip(TransInfo *t, MouseInput *mi, const double mval[2], } } +/** Callback for #INPUT_SPRING_DELTA */ static void InputSpringDelta(TransInfo *t, MouseInput *mi, const double mval[2], float output[3]) { InputSpring(t, mi, mval, output); output[0] -= 1.0f; } +/** Callback for #INPUT_TRACKBALL */ static void InputTrackBall(TransInfo *UNUSED(t), MouseInput *mi, const double mval[2], @@ -88,16 +95,18 @@ static void InputTrackBall(TransInfo *UNUSED(t), output[1] *= mi->factor; } +/** Callback for #INPUT_HORIZONTAL_RATIO */ static void InputHorizontalRatio(TransInfo *t, MouseInput *mi, const double mval[2], float output[3]) { - const int winx = t->ar ? t->ar->winx : 1; + const int winx = t->region ? t->region->winx : 1; output[0] = ((mval[0] - mi->imval[0]) / winx) * 2.0f; } +/** Callback for #INPUT_HORIZONTAL_ABSOLUTE */ static void InputHorizontalAbsolute(TransInfo *t, MouseInput *mi, const double mval[2], @@ -113,12 +122,13 @@ static void InputHorizontalAbsolute(TransInfo *t, static void InputVerticalRatio(TransInfo *t, MouseInput *mi, const double mval[2], float output[3]) { - const int winy = t->ar ? t->ar->winy : 1; + const int winy = t->region ? t->region->winy : 1; /* Flip so dragging up increases (matching viewport zoom). */ output[0] = ((mval[1] - mi->imval[1]) / winy) * -2.0f; } +/** Callback for #INPUT_VERTICAL_ABSOLUTE */ static void InputVerticalAbsolute(TransInfo *t, MouseInput *mi, const double mval[2], @@ -133,38 +143,7 @@ static void InputVerticalAbsolute(TransInfo *t, output[0] = dot_v3v3(t->viewinv[1], vec) * -2.0f; } -void setCustomPoints(TransInfo *UNUSED(t), - MouseInput *mi, - const int mval_start[2], - const int mval_end[2]) -{ - int *data; - - mi->data = MEM_reallocN(mi->data, sizeof(int) * 4); - - data = mi->data; - - data[0] = mval_start[0]; - data[1] = mval_start[1]; - data[2] = mval_end[0]; - data[3] = mval_end[1]; -} - -void setCustomPointsFromDirection(TransInfo *t, MouseInput *mi, const float dir[2]) -{ - BLI_ASSERT_UNIT_V2(dir); - const int win_axis = t->ar ? - ((abs((int)(t->ar->winx * dir[0])) + abs((int)(t->ar->winy * dir[1]))) / - 2) : - 1; - const int mval_start[2] = { - mi->imval[0] + dir[0] * win_axis, - mi->imval[1] + dir[1] * win_axis, - }; - const int mval_end[2] = {mi->imval[0], mi->imval[1]}; - setCustomPoints(t, mi, mval_start, mval_end); -} - +/** Callback for #INPUT_CUSTOM_RATIO_FLIP */ static void InputCustomRatioFlip(TransInfo *UNUSED(t), MouseInput *mi, const double mval[2], @@ -191,6 +170,7 @@ static void InputCustomRatioFlip(TransInfo *UNUSED(t), } } +/** Callback for #INPUT_CUSTOM_RATIO */ static void InputCustomRatio(TransInfo *t, MouseInput *mi, const double mval[2], float output[3]) { InputCustomRatioFlip(t, mi, mval, output); @@ -202,6 +182,7 @@ struct InputAngle_Data { double mval_prev[2]; }; +/** Callback for #INPUT_ANGLE */ static void InputAngle(TransInfo *UNUSED(t), MouseInput *mi, const double mval[2], float output[3]) { struct InputAngle_Data *data = mi->data; @@ -270,6 +251,53 @@ static void InputAngleSpring(TransInfo *t, MouseInput *mi, const double mval[2], output[1] = toutput[0]; } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Custom 2D Start/End Coordinate API + * + * - #INPUT_CUSTOM_RATIO + * - #INPUT_CUSTOM_RATIO_FLIP + * \{ */ + +void setCustomPoints(TransInfo *UNUSED(t), + MouseInput *mi, + const int mval_start[2], + const int mval_end[2]) +{ + int *data; + + mi->data = MEM_reallocN(mi->data, sizeof(int) * 4); + + data = mi->data; + + data[0] = mval_start[0]; + data[1] = mval_start[1]; + data[2] = mval_end[0]; + data[3] = mval_end[1]; +} + +void setCustomPointsFromDirection(TransInfo *t, MouseInput *mi, const float dir[2]) +{ + BLI_ASSERT_UNIT_V2(dir); + const int win_axis = t->region ? ((abs((int)(t->region->winx * dir[0])) + + abs((int)(t->region->winy * dir[1]))) / + 2) : + 1; + const int mval_start[2] = { + mi->imval[0] + dir[0] * win_axis, + mi->imval[1] + dir[1] * win_axis, + }; + const int mval_end[2] = {mi->imval[0], mi->imval[1]}; + setCustomPoints(t, mi, mval_start, mval_end); +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Setup & Handle Mouse Input + * \{ */ + void initMouseInput(TransInfo *UNUSED(t), MouseInput *mi, const float center[2], @@ -476,8 +504,8 @@ eRedrawFlag handleMouseInput(TransInfo *t, MouseInput *mi, const wmEvent *event) eRedrawFlag redraw = TREDRAW_NOTHING; switch (event->type) { - case LEFTSHIFTKEY: - case RIGHTSHIFTKEY: + case EVT_LEFTSHIFTKEY: + case EVT_RIGHTSHIFTKEY: if (event->val == KM_PRESS) { t->modifiers |= MOD_PRECISION; /* shift is modifier for higher precision transforn */ @@ -494,3 +522,5 @@ eRedrawFlag handleMouseInput(TransInfo *t, MouseInput *mi, const wmEvent *event) return redraw; } + +/** \} */ diff --git a/source/blender/editors/transform/transform_mode.c b/source/blender/editors/transform/transform_mode.c new file mode 100644 index 00000000000..4c14c3aebd7 --- /dev/null +++ b/source/blender/editors/transform/transform_mode.c @@ -0,0 +1,1264 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + */ + +/** \file + * \ingroup edtransform + */ + +#include <stdlib.h> + +#include "DNA_anim_types.h" +#include "DNA_armature_types.h" +#include "DNA_constraint_types.h" +#include "DNA_gpencil_types.h" +#include "DNA_windowmanager_types.h" + +#include "BLI_listbase.h" +#include "BLI_math.h" +#include "BLI_string.h" + +#include "BKE_constraint.h" +#include "BKE_context.h" +#include "BKE_nla.h" + +#include "RNA_access.h" + +#include "ED_screen.h" + +#include "UI_interface.h" + +#include "BLT_translation.h" + +#include "transform.h" +#include "transform_snap.h" + +/* Own include. */ +#include "transform_mode.h" + +bool transdata_check_local_center(TransInfo *t, short around) +{ + return ((around == V3D_AROUND_LOCAL_ORIGINS) && + ((t->flag & (T_OBJECT | T_POSE)) || + /* implicit: (t->flag & T_EDIT) */ + (ELEM(t->obedit_type, OB_MESH, OB_CURVE, OB_MBALL, OB_ARMATURE, OB_GPENCIL)) || + (t->spacetype == SPACE_GRAPH) || + (t->options & (CTX_MOVIECLIP | CTX_MASK | CTX_PAINT_CURVE)))); +} + +/* -------------------------------------------------------------------- */ +/** \name Transform Locks + * \{ */ + +void protectedTransBits(short protectflag, float vec[3]) +{ + if (protectflag & OB_LOCK_LOCX) { + vec[0] = 0.0f; + } + if (protectflag & OB_LOCK_LOCY) { + vec[1] = 0.0f; + } + if (protectflag & OB_LOCK_LOCZ) { + vec[2] = 0.0f; + } +} + +/* this function only does the delta rotation */ +static void protectedQuaternionBits(short protectflag, float quat[4], const float oldquat[4]) +{ + /* check that protection flags are set */ + if ((protectflag & (OB_LOCK_ROTX | OB_LOCK_ROTY | OB_LOCK_ROTZ | OB_LOCK_ROTW)) == 0) { + return; + } + + if (protectflag & OB_LOCK_ROT4D) { + /* quaternions getting limited as 4D entities that they are... */ + if (protectflag & OB_LOCK_ROTW) { + quat[0] = oldquat[0]; + } + if (protectflag & OB_LOCK_ROTX) { + quat[1] = oldquat[1]; + } + if (protectflag & OB_LOCK_ROTY) { + quat[2] = oldquat[2]; + } + if (protectflag & OB_LOCK_ROTZ) { + quat[3] = oldquat[3]; + } + } + else { + /* quaternions get limited with euler... (compatibility mode) */ + float eul[3], oldeul[3], nquat[4], noldquat[4]; + float qlen; + + qlen = normalize_qt_qt(nquat, quat); + normalize_qt_qt(noldquat, oldquat); + + quat_to_eul(eul, nquat); + quat_to_eul(oldeul, noldquat); + + if (protectflag & OB_LOCK_ROTX) { + eul[0] = oldeul[0]; + } + if (protectflag & OB_LOCK_ROTY) { + eul[1] = oldeul[1]; + } + if (protectflag & OB_LOCK_ROTZ) { + eul[2] = oldeul[2]; + } + + eul_to_quat(quat, eul); + + /* restore original quat size */ + mul_qt_fl(quat, qlen); + + /* quaternions flip w sign to accumulate rotations correctly */ + if ((nquat[0] < 0.0f && quat[0] > 0.0f) || (nquat[0] > 0.0f && quat[0] < 0.0f)) { + mul_qt_fl(quat, -1.0f); + } + } +} + +static void protectedRotateBits(short protectflag, float eul[3], const float oldeul[3]) +{ + if (protectflag & OB_LOCK_ROTX) { + eul[0] = oldeul[0]; + } + if (protectflag & OB_LOCK_ROTY) { + eul[1] = oldeul[1]; + } + if (protectflag & OB_LOCK_ROTZ) { + eul[2] = oldeul[2]; + } +} + +/* this function only does the delta rotation */ +/* axis-angle is usually internally stored as quats... */ +static void protectedAxisAngleBits( + short protectflag, float axis[3], float *angle, float oldAxis[3], float oldAngle) +{ + /* check that protection flags are set */ + if ((protectflag & (OB_LOCK_ROTX | OB_LOCK_ROTY | OB_LOCK_ROTZ | OB_LOCK_ROTW)) == 0) { + return; + } + + if (protectflag & OB_LOCK_ROT4D) { + /* axis-angle getting limited as 4D entities that they are... */ + if (protectflag & OB_LOCK_ROTW) { + *angle = oldAngle; + } + if (protectflag & OB_LOCK_ROTX) { + axis[0] = oldAxis[0]; + } + if (protectflag & OB_LOCK_ROTY) { + axis[1] = oldAxis[1]; + } + if (protectflag & OB_LOCK_ROTZ) { + axis[2] = oldAxis[2]; + } + } + else { + /* axis-angle get limited with euler... */ + float eul[3], oldeul[3]; + + axis_angle_to_eulO(eul, EULER_ORDER_DEFAULT, axis, *angle); + axis_angle_to_eulO(oldeul, EULER_ORDER_DEFAULT, oldAxis, oldAngle); + + if (protectflag & OB_LOCK_ROTX) { + eul[0] = oldeul[0]; + } + if (protectflag & OB_LOCK_ROTY) { + eul[1] = oldeul[1]; + } + if (protectflag & OB_LOCK_ROTZ) { + eul[2] = oldeul[2]; + } + + eulO_to_axis_angle(axis, angle, eul, EULER_ORDER_DEFAULT); + + /* When converting to axis-angle, + * we need a special exception for the case when there is no axis. */ + if (IS_EQF(axis[0], axis[1]) && IS_EQF(axis[1], axis[2])) { + /* for now, rotate around y-axis then (so that it simply becomes the roll) */ + axis[1] = 1.0f; + } + } +} + +static void protectedSizeBits(short protectflag, float size[3]) +{ + if (protectflag & OB_LOCK_SCALEX) { + size[0] = 1.0f; + } + if (protectflag & OB_LOCK_SCALEY) { + size[1] = 1.0f; + } + if (protectflag & OB_LOCK_SCALEZ) { + size[2] = 1.0f; + } +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Transform Limits + * \{ */ + +void constraintTransLim(TransInfo *t, TransData *td) +{ + if (td->con) { + 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; + float ctime = (float)(t->scene->r.cfra); + + /* Make a temporary bConstraintOb for using these limit constraints + * - they only care that cob->matrix is correctly set ;-) + * - current space should be local + */ + unit_m4(cob.matrix); + copy_v3_v3(cob.matrix[3], td->loc); + + /* Evaluate valid constraints */ + for (con = td->con; con; con = con->next) { + const bConstraintTypeInfo *cti = NULL; + ListBase targets = {NULL, NULL}; + + /* only consider constraint if enabled */ + if (con->flag & (CONSTRAINT_DISABLE | CONSTRAINT_OFF)) { + continue; + } + if (con->enforce == 0.0f) { + continue; + } + + /* only use it if it's tagged for this purpose (and the right type) */ + if (con->type == CONSTRAINT_TYPE_LOCLIMIT) { + bLocLimitConstraint *data = (bLocLimitConstraint *)con->data; + + if ((data->flag2 & LIMIT_TRANSFORM) == 0) { + continue; + } + cti = ctiLoc; + } + else if (con->type == CONSTRAINT_TYPE_DISTLIMIT) { + bDistLimitConstraint *data = (bDistLimitConstraint *)con->data; + + if ((data->flag & LIMITDIST_TRANSFORM) == 0) { + continue; + } + cti = ctiDist; + } + + if (cti) { + /* do space conversions */ + if (con->ownspace == CONSTRAINT_SPACE_WORLD) { + /* just multiply by td->mtx (this should be ok) */ + mul_m4_m3m4(cob.matrix, td->mtx, cob.matrix); + } + else if (con->ownspace != CONSTRAINT_SPACE_LOCAL) { + /* skip... incompatible spacetype */ + continue; + } + + /* get constraint targets if needed */ + BKE_constraint_targets_for_solving_get(t->depsgraph, con, &cob, &targets, ctime); + + /* do constraint */ + cti->evaluate_constraint(con, &cob, &targets); + + /* convert spaces again */ + if (con->ownspace == CONSTRAINT_SPACE_WORLD) { + /* just multiply by td->smtx (this should be ok) */ + mul_m4_m3m4(cob.matrix, td->smtx, cob.matrix); + } + + /* free targets list */ + BLI_freelistN(&targets); + } + } + + /* copy results from cob->matrix */ + copy_v3_v3(td->loc, cob.matrix[3]); + } +} + +static void constraintob_from_transdata(bConstraintOb *cob, TransData *td) +{ + /* Make a temporary bConstraintOb for use by limit constraints + * - they only care that cob->matrix is correctly set ;-) + * - current space should be local + */ + memset(cob, 0, sizeof(bConstraintOb)); + if (td->ext) { + if (td->ext->rotOrder == ROT_MODE_QUAT) { + /* quats */ + /* objects and bones do normalization first too, otherwise + * we don't necessarily end up with a rotation matrix, and + * then conversion back to quat gives a different result */ + float quat[4]; + normalize_qt_qt(quat, td->ext->quat); + quat_to_mat4(cob->matrix, quat); + } + else if (td->ext->rotOrder == ROT_MODE_AXISANGLE) { + /* axis angle */ + axis_angle_to_mat4(cob->matrix, td->ext->rotAxis, *td->ext->rotAngle); + } + else { + /* eulers */ + eulO_to_mat4(cob->matrix, td->ext->rot, td->ext->rotOrder); + } + } +} + +static void constraintRotLim(TransInfo *UNUSED(t), TransData *td) +{ + if (td->con) { + const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_from_type(CONSTRAINT_TYPE_ROTLIMIT); + bConstraintOb cob; + bConstraint *con; + bool do_limit = false; + + /* Evaluate valid constraints */ + for (con = td->con; con; con = con->next) { + /* only consider constraint if enabled */ + if (con->flag & (CONSTRAINT_DISABLE | CONSTRAINT_OFF)) { + continue; + } + if (con->enforce == 0.0f) { + continue; + } + + /* we're only interested in Limit-Rotation constraints */ + if (con->type == CONSTRAINT_TYPE_ROTLIMIT) { + bRotLimitConstraint *data = (bRotLimitConstraint *)con->data; + + /* only use it if it's tagged for this purpose */ + if ((data->flag2 & LIMIT_TRANSFORM) == 0) { + continue; + } + + /* skip incompatible spacetypes */ + if (!ELEM(con->ownspace, CONSTRAINT_SPACE_WORLD, CONSTRAINT_SPACE_LOCAL)) { + continue; + } + + /* only do conversion if necessary, to preserve quats and eulers */ + if (do_limit == false) { + constraintob_from_transdata(&cob, td); + do_limit = true; + } + + /* do space conversions */ + if (con->ownspace == CONSTRAINT_SPACE_WORLD) { + /* just multiply by td->mtx (this should be ok) */ + mul_m4_m3m4(cob.matrix, td->mtx, cob.matrix); + } + + /* do constraint */ + cti->evaluate_constraint(con, &cob, NULL); + + /* convert spaces again */ + if (con->ownspace == CONSTRAINT_SPACE_WORLD) { + /* just multiply by td->smtx (this should be ok) */ + mul_m4_m3m4(cob.matrix, td->smtx, cob.matrix); + } + } + } + + if (do_limit) { + /* copy results from cob->matrix */ + if (td->ext->rotOrder == ROT_MODE_QUAT) { + /* quats */ + mat4_to_quat(td->ext->quat, cob.matrix); + } + else if (td->ext->rotOrder == ROT_MODE_AXISANGLE) { + /* axis angle */ + mat4_to_axis_angle(td->ext->rotAxis, td->ext->rotAngle, cob.matrix); + } + else { + /* eulers */ + mat4_to_eulO(td->ext->rot, td->ext->rotOrder, cob.matrix); + } + } + } +} + +static void constraintSizeLim(TransInfo *t, TransData *td) +{ + if (td->con && td->ext) { + const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_from_type(CONSTRAINT_TYPE_SIZELIMIT); + bConstraintOb cob = {NULL}; + bConstraint *con; + float size_sign[3], size_abs[3]; + int i; + + /* Make a temporary bConstraintOb for using these limit constraints + * - they only care that cob->matrix is correctly set ;-) + * - current space should be local + */ + if ((td->flag & TD_SINGLESIZE) && !(t->con.mode & CON_APPLY)) { + /* scale val and reset size */ + return; // TODO: fix this case + } + else { + /* Reset val if SINGLESIZE but using a constraint */ + if (td->flag & TD_SINGLESIZE) { + return; + } + + /* separate out sign to apply back later */ + for (i = 0; i < 3; i++) { + size_sign[i] = signf(td->ext->size[i]); + size_abs[i] = fabsf(td->ext->size[i]); + } + + size_to_mat4(cob.matrix, size_abs); + } + + /* Evaluate valid constraints */ + for (con = td->con; con; con = con->next) { + /* only consider constraint if enabled */ + if (con->flag & (CONSTRAINT_DISABLE | CONSTRAINT_OFF)) { + continue; + } + if (con->enforce == 0.0f) { + continue; + } + + /* we're only interested in Limit-Scale constraints */ + if (con->type == CONSTRAINT_TYPE_SIZELIMIT) { + bSizeLimitConstraint *data = con->data; + + /* only use it if it's tagged for this purpose */ + if ((data->flag2 & LIMIT_TRANSFORM) == 0) { + continue; + } + + /* do space conversions */ + if (con->ownspace == CONSTRAINT_SPACE_WORLD) { + /* just multiply by td->mtx (this should be ok) */ + mul_m4_m3m4(cob.matrix, td->mtx, cob.matrix); + } + else if (con->ownspace != CONSTRAINT_SPACE_LOCAL) { + /* skip... incompatible spacetype */ + continue; + } + + /* do constraint */ + cti->evaluate_constraint(con, &cob, NULL); + + /* convert spaces again */ + if (con->ownspace == CONSTRAINT_SPACE_WORLD) { + /* just multiply by td->smtx (this should be ok) */ + mul_m4_m3m4(cob.matrix, td->smtx, cob.matrix); + } + } + } + + /* copy results from cob->matrix */ + if ((td->flag & TD_SINGLESIZE) && !(t->con.mode & CON_APPLY)) { + /* scale val and reset size */ + return; // TODO: fix this case + } + else { + /* Reset val if SINGLESIZE but using a constraint */ + if (td->flag & TD_SINGLESIZE) { + return; + } + + /* extrace scale from matrix and apply back sign */ + mat4_to_size(td->ext->size, cob.matrix); + mul_v3_v3(td->ext->size, size_sign); + } + } +} + +/* -------------------------------------------------------------------- */ +/* Transform (Rotation Utils) */ + +/** \name Transform Rotation Utils + * \{ */ +/* Used by Transform Rotation and Transform Normal Rotation */ +void headerRotation(TransInfo *t, char str[UI_MAX_DRAW_STR], float final) +{ + size_t ofs = 0; + + if (hasNumInput(&t->num)) { + char c[NUM_STR_REP_LEN]; + + outputNumInput(&(t->num), c, &t->scene->unit); + + ofs += BLI_snprintf( + str + ofs, UI_MAX_DRAW_STR - ofs, TIP_("Rot: %s %s %s"), &c[0], t->con.text, t->proptext); + } + else { + ofs += BLI_snprintf(str + ofs, + UI_MAX_DRAW_STR - ofs, + TIP_("Rot: %.2f%s %s"), + RAD2DEGF(final), + t->con.text, + t->proptext); + } + + if (t->flag & T_PROP_EDIT_ALL) { + ofs += BLI_snprintf( + str + ofs, UI_MAX_DRAW_STR - ofs, TIP_(" Proportional size: %.2f"), t->prop_size); + } +} + +void postInputRotation(TransInfo *t, float values[3]) +{ + float axis_final[3]; + copy_v3_v3(axis_final, t->spacemtx[t->orient_axis]); + if ((t->con.mode & CON_APPLY) && t->con.applyRot) { + t->con.applyRot(t, NULL, NULL, axis_final, values); + } +} + +/** + * Applies values of rotation to `td->loc` and `td->ext->quat` + * based on a rotation matrix (mat) and a pivot (center). + * + * Protected axis and other transform settings are taken into account. + */ +void ElementRotation_ex(TransInfo *t, + TransDataContainer *tc, + TransData *td, + const float mat[3][3], + const float *center) +{ + float vec[3], totmat[3][3], smat[3][3]; + float eul[3], fmat[3][3], quat[4]; + + if (t->flag & T_POINTS) { + mul_m3_m3m3(totmat, mat, td->mtx); + mul_m3_m3m3(smat, td->smtx, totmat); + + /* apply gpencil falloff */ + if (t->options & CTX_GPENCIL_STROKES) { + bGPDstroke *gps = (bGPDstroke *)td->extra; + float sx = smat[0][0]; + float sy = smat[1][1]; + float sz = smat[2][2]; + + mul_m3_fl(smat, gps->runtime.multi_frame_falloff); + /* fix scale */ + smat[0][0] = sx; + smat[1][1] = sy; + smat[2][2] = sz; + } + + sub_v3_v3v3(vec, td->iloc, center); + mul_m3_v3(smat, vec); + + add_v3_v3v3(td->loc, vec, center); + + sub_v3_v3v3(vec, td->loc, td->iloc); + protectedTransBits(td->protectflag, vec); + add_v3_v3v3(td->loc, td->iloc, vec); + + if (td->flag & TD_USEQUAT) { + mul_m3_series(fmat, td->smtx, mat, td->mtx); + mat3_to_quat(quat, fmat); // Actual transform + + if (td->ext->quat) { + mul_qt_qtqt(td->ext->quat, quat, td->ext->iquat); + + /* is there a reason not to have this here? -jahka */ + protectedQuaternionBits(td->protectflag, td->ext->quat, td->ext->iquat); + } + } + } + /** + * HACK WARNING + * + * This is some VERY ugly special case to deal with pose mode. + * + * The problem is that mtx and smtx include each bone orientation. + * + * That is needed to rotate each bone properly, HOWEVER, to calculate + * the translation component, we only need the actual armature object's + * matrix (and inverse). That is not all though. Once the proper translation + * has been computed, it has to be converted back into the bone's space. + */ + else if (t->flag & T_POSE) { + // Extract and invert armature object matrix + + if ((td->flag & TD_NO_LOC) == 0) { + sub_v3_v3v3(vec, td->center, center); + + mul_m3_v3(tc->mat3, vec); // To Global space + mul_m3_v3(mat, vec); // Applying rotation + mul_m3_v3(tc->imat3, vec); // To Local space + + add_v3_v3(vec, center); + /* vec now is the location where the object has to be */ + + sub_v3_v3v3(vec, vec, td->center); // Translation needed from the initial location + + /* special exception, see TD_PBONE_LOCAL_MTX definition comments */ + if (td->flag & TD_PBONE_LOCAL_MTX_P) { + /* do nothing */ + } + else if (td->flag & TD_PBONE_LOCAL_MTX_C) { + mul_m3_v3(tc->mat3, vec); // To Global space + mul_m3_v3(td->ext->l_smtx, vec); // To Pose space (Local Location) + } + else { + mul_m3_v3(tc->mat3, vec); // To Global space + mul_m3_v3(td->smtx, vec); // To Pose space + } + + protectedTransBits(td->protectflag, vec); + + add_v3_v3v3(td->loc, td->iloc, vec); + + constraintTransLim(t, td); + } + + /* rotation */ + /* MORE HACK: as in some cases the matrix to apply location and rot/scale is not the same, + * and ElementRotation() might be called in Translation context (with align snapping), + * we need to be sure to actually use the *rotation* matrix here... + * So no other way than storing it in some dedicated members of td->ext! */ + if ((t->flag & T_V3D_ALIGN) == 0) { /* align mode doesn't rotate objects itself */ + /* euler or quaternion/axis-angle? */ + if (td->ext->rotOrder == ROT_MODE_QUAT) { + mul_m3_series(fmat, td->ext->r_smtx, mat, td->ext->r_mtx); + + mat3_to_quat(quat, fmat); /* Actual transform */ + + mul_qt_qtqt(td->ext->quat, quat, td->ext->iquat); + /* this function works on end result */ + protectedQuaternionBits(td->protectflag, td->ext->quat, td->ext->iquat); + } + else if (td->ext->rotOrder == ROT_MODE_AXISANGLE) { + /* calculate effect based on quats */ + float iquat[4], tquat[4]; + + axis_angle_to_quat(iquat, td->ext->irotAxis, td->ext->irotAngle); + + mul_m3_series(fmat, td->ext->r_smtx, mat, td->ext->r_mtx); + mat3_to_quat(quat, fmat); /* Actual transform */ + mul_qt_qtqt(tquat, quat, iquat); + + quat_to_axis_angle(td->ext->rotAxis, td->ext->rotAngle, tquat); + + /* this function works on end result */ + protectedAxisAngleBits(td->protectflag, + td->ext->rotAxis, + td->ext->rotAngle, + td->ext->irotAxis, + td->ext->irotAngle); + } + else { + float eulmat[3][3]; + + mul_m3_m3m3(totmat, mat, td->ext->r_mtx); + mul_m3_m3m3(smat, td->ext->r_smtx, totmat); + + /* calculate the total rotatation in eulers */ + copy_v3_v3(eul, td->ext->irot); + eulO_to_mat3(eulmat, eul, td->ext->rotOrder); + + /* mat = transform, obmat = bone rotation */ + mul_m3_m3m3(fmat, smat, eulmat); + + mat3_to_compatible_eulO(eul, td->ext->rot, td->ext->rotOrder, fmat); + + /* and apply (to end result only) */ + protectedRotateBits(td->protectflag, eul, td->ext->irot); + copy_v3_v3(td->ext->rot, eul); + } + + constraintRotLim(t, td); + } + } + else { + if ((td->flag & TD_NO_LOC) == 0) { + /* translation */ + sub_v3_v3v3(vec, td->center, center); + mul_m3_v3(mat, vec); + add_v3_v3(vec, center); + /* vec now is the location where the object has to be */ + sub_v3_v3(vec, td->center); + mul_m3_v3(td->smtx, vec); + + protectedTransBits(td->protectflag, vec); + + add_v3_v3v3(td->loc, td->iloc, vec); + } + + constraintTransLim(t, td); + + /* rotation */ + if ((t->flag & T_V3D_ALIGN) == 0) { // align mode doesn't rotate objects itself + /* euler or quaternion? */ + if ((td->ext->rotOrder == ROT_MODE_QUAT) || (td->flag & TD_USEQUAT)) { + /* can be called for texture space translate for example, then opt out */ + if (td->ext->quat) { + mul_m3_series(fmat, td->smtx, mat, td->mtx); + mat3_to_quat(quat, fmat); // Actual transform + + mul_qt_qtqt(td->ext->quat, quat, td->ext->iquat); + /* this function works on end result */ + protectedQuaternionBits(td->protectflag, td->ext->quat, td->ext->iquat); + } + } + else if (td->ext->rotOrder == ROT_MODE_AXISANGLE) { + /* calculate effect based on quats */ + float iquat[4], tquat[4]; + + axis_angle_to_quat(iquat, td->ext->irotAxis, td->ext->irotAngle); + + mul_m3_series(fmat, td->smtx, mat, td->mtx); + mat3_to_quat(quat, fmat); // Actual transform + mul_qt_qtqt(tquat, quat, iquat); + + quat_to_axis_angle(td->ext->rotAxis, td->ext->rotAngle, tquat); + + /* this function works on end result */ + protectedAxisAngleBits(td->protectflag, + td->ext->rotAxis, + td->ext->rotAngle, + td->ext->irotAxis, + td->ext->irotAngle); + } + else { + float obmat[3][3]; + + mul_m3_m3m3(totmat, mat, td->mtx); + mul_m3_m3m3(smat, td->smtx, totmat); + + /* calculate the total rotatation in eulers */ + add_v3_v3v3(eul, td->ext->irot, td->ext->drot); /* correct for delta rot */ + eulO_to_mat3(obmat, eul, td->ext->rotOrder); + /* mat = transform, obmat = object rotation */ + mul_m3_m3m3(fmat, smat, obmat); + + mat3_to_compatible_eulO(eul, td->ext->rot, td->ext->rotOrder, fmat); + + /* correct back for delta rot */ + sub_v3_v3v3(eul, eul, td->ext->drot); + + /* and apply */ + protectedRotateBits(td->protectflag, eul, td->ext->irot); + copy_v3_v3(td->ext->rot, eul); + } + + constraintRotLim(t, td); + } + } +} + +void ElementRotation( + TransInfo *t, TransDataContainer *tc, TransData *td, float mat[3][3], const short around) +{ + const float *center; + + /* local constraint shouldn't alter center */ + if (transdata_check_local_center(t, around)) { + center = td->center; + } + else { + center = tc->center_local; + } + + ElementRotation_ex(t, tc, td, mat, center); +} +/** \} */ + +/* -------------------------------------------------------------------- */ +/* Transform (Resize Utils) */ + +/** \name Transform Resize Utils + * \{ */ +void headerResize(TransInfo *t, const float vec[3], char str[UI_MAX_DRAW_STR]) +{ + char tvec[NUM_STR_REP_LEN * 3]; + size_t ofs = 0; + if (hasNumInput(&t->num)) { + outputNumInput(&(t->num), tvec, &t->scene->unit); + } + else { + BLI_snprintf(&tvec[0], NUM_STR_REP_LEN, "%.4f", vec[0]); + BLI_snprintf(&tvec[NUM_STR_REP_LEN], NUM_STR_REP_LEN, "%.4f", vec[1]); + BLI_snprintf(&tvec[NUM_STR_REP_LEN * 2], NUM_STR_REP_LEN, "%.4f", vec[2]); + } + + if (t->con.mode & CON_APPLY) { + switch (t->num.idx_max) { + case 0: + ofs += BLI_snprintf(str + ofs, + UI_MAX_DRAW_STR - ofs, + TIP_("Scale: %s%s %s"), + &tvec[0], + t->con.text, + t->proptext); + break; + case 1: + ofs += BLI_snprintf(str + ofs, + UI_MAX_DRAW_STR - ofs, + TIP_("Scale: %s : %s%s %s"), + &tvec[0], + &tvec[NUM_STR_REP_LEN], + t->con.text, + t->proptext); + break; + case 2: + ofs += BLI_snprintf(str + ofs, + UI_MAX_DRAW_STR - ofs, + TIP_("Scale: %s : %s : %s%s %s"), + &tvec[0], + &tvec[NUM_STR_REP_LEN], + &tvec[NUM_STR_REP_LEN * 2], + t->con.text, + t->proptext); + break; + } + } + else { + if (t->flag & T_2D_EDIT) { + ofs += BLI_snprintf(str + ofs, + UI_MAX_DRAW_STR - ofs, + TIP_("Scale X: %s Y: %s%s %s"), + &tvec[0], + &tvec[NUM_STR_REP_LEN], + t->con.text, + t->proptext); + } + else { + ofs += BLI_snprintf(str + ofs, + UI_MAX_DRAW_STR - ofs, + TIP_("Scale X: %s Y: %s Z: %s%s %s"), + &tvec[0], + &tvec[NUM_STR_REP_LEN], + &tvec[NUM_STR_REP_LEN * 2], + t->con.text, + t->proptext); + } + } + + if (t->flag & T_PROP_EDIT_ALL) { + ofs += BLI_snprintf( + str + ofs, UI_MAX_DRAW_STR - ofs, TIP_(" Proportional size: %.2f"), t->prop_size); + } +} + +/** + * \a smat is reference matrix only. + * + * \note this is a tricky area, before making changes see: T29633, T42444 + */ +static void TransMat3ToSize(float mat[3][3], float smat[3][3], float size[3]) +{ + float rmat[3][3]; + + mat3_to_rot_size(rmat, size, mat); + + /* first tried with dotproduct... but the sign flip is crucial */ + if (dot_v3v3(rmat[0], smat[0]) < 0.0f) { + size[0] = -size[0]; + } + if (dot_v3v3(rmat[1], smat[1]) < 0.0f) { + size[1] = -size[1]; + } + if (dot_v3v3(rmat[2], smat[2]) < 0.0f) { + size[2] = -size[2]; + } +} + +void ElementResize(TransInfo *t, TransDataContainer *tc, TransData *td, float mat[3][3]) +{ + float tmat[3][3], smat[3][3], center[3]; + float vec[3]; + + if (t->flag & T_EDIT) { + mul_m3_m3m3(smat, mat, td->mtx); + mul_m3_m3m3(tmat, td->smtx, smat); + } + else { + copy_m3_m3(tmat, mat); + } + + if (t->con.applySize) { + t->con.applySize(t, tc, td, tmat); + } + + /* local constraint shouldn't alter center */ + if (transdata_check_local_center(t, t->around)) { + copy_v3_v3(center, td->center); + } + else if (t->options & CTX_MOVIECLIP) { + if (td->flag & TD_INDIVIDUAL_SCALE) { + copy_v3_v3(center, td->center); + } + else { + copy_v3_v3(center, tc->center_local); + } + } + else { + copy_v3_v3(center, tc->center_local); + } + + /* Size checked needed since the 3D cursor only uses rotation fields. */ + if (td->ext && td->ext->size) { + float fsize[3]; + + if ((t->options & CTX_SCULPT) || t->flag & (T_OBJECT | T_TEXTURE | T_POSE)) { + float obsizemat[3][3]; + /* Reorient the size mat to fit the oriented object. */ + mul_m3_m3m3(obsizemat, tmat, td->axismtx); + /* print_m3("obsizemat", obsizemat); */ + TransMat3ToSize(obsizemat, td->axismtx, fsize); + /* print_v3("fsize", fsize); */ + } + else { + mat3_to_size(fsize, tmat); + } + + protectedSizeBits(td->protectflag, fsize); + + if ((t->flag & T_V3D_ALIGN) == 0) { /* align mode doesn't resize objects itself */ + if ((td->flag & TD_SINGLESIZE) && !(t->con.mode & CON_APPLY)) { + /* scale val and reset size */ + *td->val = td->ival * (1 + (fsize[0] - 1) * td->factor); + + td->ext->size[0] = td->ext->isize[0]; + td->ext->size[1] = td->ext->isize[1]; + td->ext->size[2] = td->ext->isize[2]; + } + else { + /* Reset val if SINGLESIZE but using a constraint */ + if (td->flag & TD_SINGLESIZE) { + *td->val = td->ival; + } + + td->ext->size[0] = td->ext->isize[0] * (1 + (fsize[0] - 1) * td->factor); + td->ext->size[1] = td->ext->isize[1] * (1 + (fsize[1] - 1) * td->factor); + td->ext->size[2] = td->ext->isize[2] * (1 + (fsize[2] - 1) * td->factor); + } + } + + constraintSizeLim(t, td); + } + + /* For individual element center, Editmode need to use iloc */ + if (t->flag & T_POINTS) { + sub_v3_v3v3(vec, td->iloc, center); + } + else { + sub_v3_v3v3(vec, td->center, center); + } + + mul_m3_v3(tmat, vec); + + add_v3_v3(vec, center); + if (t->flag & T_POINTS) { + sub_v3_v3(vec, td->iloc); + } + else { + sub_v3_v3(vec, td->center); + } + + /* grease pencil falloff */ + if (t->options & CTX_GPENCIL_STROKES) { + bGPDstroke *gps = (bGPDstroke *)td->extra; + mul_v3_fl(vec, td->factor * gps->runtime.multi_frame_falloff); + + /* scale stroke thickness */ + if (td->val) { + snapGridIncrement(t, t->values_final); + applyNumInput(&t->num, t->values_final); + + float ratio = t->values_final[0]; + *td->val = td->ival * ratio * gps->runtime.multi_frame_falloff; + CLAMP_MIN(*td->val, 0.001f); + } + } + else { + mul_v3_fl(vec, td->factor); + } + + if (t->flag & (T_OBJECT | T_POSE)) { + mul_m3_v3(td->smtx, vec); + } + + protectedTransBits(td->protectflag, vec); + if (td->loc) { + add_v3_v3v3(td->loc, td->iloc, vec); + } + + constraintTransLim(t, td); +} +/** \} */ + +/* -------------------------------------------------------------------- */ +/* Transform (Frame Utils) */ + +/** \name Transform Frame Utils + * \{ */ + +/* This function returns the snapping 'mode' for Animation Editors only + * We cannot use the standard snapping due to NLA-strip scaling complexities. + */ +// XXX these modifier checks should be keymappable +short getAnimEdit_SnapMode(TransInfo *t) +{ + short autosnap = SACTSNAP_OFF; + + if (t->spacetype == SPACE_ACTION) { + SpaceAction *saction = (SpaceAction *)t->area->spacedata.first; + + if (saction) { + autosnap = saction->autosnap; + } + } + else if (t->spacetype == SPACE_GRAPH) { + SpaceGraph *sipo = (SpaceGraph *)t->area->spacedata.first; + + if (sipo) { + autosnap = sipo->autosnap; + } + } + else if (t->spacetype == SPACE_NLA) { + SpaceNla *snla = (SpaceNla *)t->area->spacedata.first; + + if (snla) { + autosnap = snla->autosnap; + } + } + else { + autosnap = SACTSNAP_OFF; + } + + /* toggle autosnap on/off + * - when toggling on, prefer nearest frame over 1.0 frame increments + */ + if (t->modifiers & MOD_SNAP_INVERT) { + if (autosnap) { + autosnap = SACTSNAP_OFF; + } + else { + autosnap = SACTSNAP_FRAME; + } + } + + return autosnap; +} + +/* This function is used by Animation Editor specific transform functions to do + * the Snap Keyframe to Nearest Frame/Marker + */ +void doAnimEdit_SnapFrame( + TransInfo *t, TransData *td, TransData2D *td2d, AnimData *adt, short autosnap) +{ + if (autosnap != SACTSNAP_OFF) { + float val; + + /* convert frame to nla-action time (if needed) */ + if (adt && (t->spacetype != SPACE_SEQ)) { + val = BKE_nla_tweakedit_remap(adt, *(td->val), NLATIME_CONVERT_MAP); + } + else { + val = *(td->val); + } + + snapFrameTransform(t, autosnap, true, val, &val); + + /* convert frame out of nla-action time */ + if (adt && (t->spacetype != SPACE_SEQ)) { + *(td->val) = BKE_nla_tweakedit_remap(adt, val, NLATIME_CONVERT_UNMAP); + } + else { + *(td->val) = val; + } + } + + /* If the handles are to be moved too + * (as side-effect of keyframes moving, to keep the general effect) + * offset them by the same amount so that the general angles are maintained + * (i.e. won't change while handles are free-to-roam and keyframes are snap-locked). + */ + if ((td->flag & TD_MOVEHANDLE1) && td2d->h1) { + td2d->h1[0] = td2d->ih1[0] + *td->val - td->ival; + } + if ((td->flag & TD_MOVEHANDLE2) && td2d->h2) { + td2d->h2[0] = td2d->ih2[0] + *td->val - td->ival; + } +} +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Transform Mode Initialization + * \{ */ + +void transform_mode_init(TransInfo *t, wmOperator *op, const int mode) +{ + t->mode = mode; + + switch (mode) { + case TFM_TRANSLATION: + initTranslation(t); + break; + case TFM_ROTATION: + initRotation(t); + break; + case TFM_RESIZE: + initResize(t); + break; + case TFM_SKIN_RESIZE: + initSkinResize(t); + break; + case TFM_TOSPHERE: + initToSphere(t); + break; + case TFM_SHEAR: + initShear(t); + break; + case TFM_BEND: + initBend(t); + break; + case TFM_SHRINKFATTEN: + initShrinkFatten(t); + break; + case TFM_TILT: + initTilt(t); + break; + case TFM_CURVE_SHRINKFATTEN: + initCurveShrinkFatten(t); + break; + case TFM_MASK_SHRINKFATTEN: + initMaskShrinkFatten(t); + break; + case TFM_GPENCIL_SHRINKFATTEN: + initGPShrinkFatten(t); + break; + case TFM_TRACKBALL: + initTrackball(t); + break; + case TFM_PUSHPULL: + initPushPull(t); + break; + case TFM_CREASE: + initCrease(t); + break; + case TFM_BONESIZE: { /* used for both B-Bone width (bonesize) as for deform-dist (envelope) */ + /* Note: we have to pick one, use the active object. */ + TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_OK(t); + bArmature *arm = tc->poseobj->data; + if (arm->drawtype == ARM_ENVELOPE) { + initBoneEnvelope(t); + 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: + case TFM_VERT_SLIDE: { + const bool use_even = (op ? RNA_boolean_get(op->ptr, "use_even") : false); + const bool flipped = (op ? RNA_boolean_get(op->ptr, "flipped") : false); + const bool use_clamp = (op ? RNA_boolean_get(op->ptr, "use_clamp") : true); + if (mode == TFM_EDGE_SLIDE) { + const bool use_double_side = (op ? !RNA_boolean_get(op->ptr, "single_side") : true); + initEdgeSlide_ex(t, use_double_side, use_even, flipped, use_clamp); + } + else { + initVertSlide_ex(t, use_even, flipped, use_clamp); + } + break; + } + case TFM_BONE_ROLL: + initBoneRoll(t); + break; + case TFM_TIME_TRANSLATE: + initTimeTranslate(t); + break; + case TFM_TIME_SLIDE: + initTimeSlide(t); + break; + case TFM_TIME_SCALE: + initTimeScale(t); + break; + case TFM_TIME_DUPLICATE: + /* same as TFM_TIME_EXTEND, but we need the mode info for later + * so that duplicate-culling will work properly + */ + if (ELEM(t->spacetype, SPACE_GRAPH, SPACE_NLA)) { + initTranslation(t); + } + else { + initTimeTranslate(t); + } + break; + case TFM_TIME_EXTEND: + /* now that transdata has been made, do like for TFM_TIME_TRANSLATE (for most Animation + * Editors because they have only 1D transforms for time values) or TFM_TRANSLATION + * (for Graph/NLA Editors only since they uses 'standard' transforms to get 2D movement) + * depending on which editor this was called from + */ + if (ELEM(t->spacetype, SPACE_GRAPH, SPACE_NLA)) { + initTranslation(t); + } + else { + initTimeTranslate(t); + } + break; + case TFM_BAKE_TIME: + initBakeTime(t); + break; + case TFM_MIRROR: + initMirror(t); + break; + case TFM_BWEIGHT: + initBevelWeight(t); + break; + case TFM_ALIGN: + initAlign(t); + break; + case TFM_SEQ_SLIDE: + initSeqSlide(t); + break; + case TFM_NORMAL_ROTATION: + initNormalRotation(t); + break; + case TFM_GPENCIL_OPACITY: + initGPOpacity(t); + break; + } + + /* TODO(germano): Some of these operations change the `t->mode`. + * This can be bad for Redo. + * BLI_assert(t->mode == mode); */ +} + +/** \} */ diff --git a/source/blender/editors/transform/transform_mode.h b/source/blender/editors/transform/transform_mode.h new file mode 100644 index 00000000000..6180f6d3477 --- /dev/null +++ b/source/blender/editors/transform/transform_mode.h @@ -0,0 +1,160 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + */ + +/** \file + * \ingroup edtransform + * \brief transform modes used by different operators. + */ + +#ifndef __TRANSFORM_MODE_H__ +#define __TRANSFORM_MODE_H__ + +struct AnimData; +struct LinkNode; +struct TransData; +struct TransDataContainer; +struct TransInfo; +struct wmOperator; + +/* header of TransDataEdgeSlideVert, TransDataEdgeSlideEdge */ +typedef struct TransDataGenericSlideVert { + struct BMVert *v; + struct LinkNode **cd_loop_groups; + float co_orig_3d[3]; +} TransDataGenericSlideVert; + +/* transform_mode.c */ +bool transdata_check_local_center(TransInfo *t, short around); +void protectedTransBits(short protectflag, float vec[3]); +void constraintTransLim(TransInfo *t, TransData *td); +void postInputRotation(TransInfo *t, float values[3]); +void headerRotation(TransInfo *t, char *str, float final); +void ElementRotation_ex(TransInfo *t, + TransDataContainer *tc, + TransData *td, + const float mat[3][3], + const float *center); +void ElementRotation( + TransInfo *t, TransDataContainer *tc, TransData *td, float mat[3][3], const short around); +void headerResize(TransInfo *t, const float vec[3], char *str); +void ElementResize(TransInfo *t, TransDataContainer *tc, TransData *td, float mat[3][3]); +short getAnimEdit_SnapMode(TransInfo *t); +void doAnimEdit_SnapFrame( + TransInfo *t, TransData *td, TransData2D *td2d, struct AnimData *adt, short autosnap); +void transform_mode_init(TransInfo *t, struct wmOperator *op, const int mode); + +/* transform_mode_align.c */ +void initAlign(TransInfo *t); + +/* transform_mode_baketime.c */ +void initBakeTime(TransInfo *t); + +/* transform_mode_bbone_resize.c */ +void initBoneSize(TransInfo *t); + +/* transform_mode_bend.c */ +void initBend(TransInfo *t); + +/* transform_mode_boneenvelope.c */ +void initBoneEnvelope(TransInfo *t); + +/* transform_mode_boneroll.c */ +void initBoneRoll(TransInfo *t); + +/* transform_mode_curveshrinkfatten.c */ +void initCurveShrinkFatten(TransInfo *t); + +/* transform_mode_edge_bevelweight.c */ +void initBevelWeight(TransInfo *t); + +/* transform_mode_edge_crease.c */ +void initCrease(TransInfo *t); + +/* transform_mode_edge_rotate_normal.c */ +void initNormalRotation(TransInfo *t); + +/* transform_mode_edge_seq_slide.c */ +void initSeqSlide(TransInfo *t); + +/* transform_mode_edge_slide.c */ +void projectEdgeSlideData(TransInfo *t, bool is_final); +void drawEdgeSlide(TransInfo *t); +void doEdgeSlide(TransInfo *t, float perc); +void initEdgeSlide_ex( + TransInfo *t, bool use_double_side, bool use_even, bool flipped, bool use_clamp); +void initEdgeSlide(TransInfo *t); + +/* transform_mode_gpopacity.c */ +void initGPOpacity(TransInfo *t); + +/* transform_mode_gpshrinkfatten.c */ +void initGPShrinkFatten(TransInfo *t); + +/* transform_mode_maskshrinkfatten.c */ +void initMaskShrinkFatten(TransInfo *t); + +/* transform_mode_mirror.c */ +void initMirror(TransInfo *t); + +/* transform_mode_push_pull.c */ +void initPushPull(TransInfo *t); + +/* transform_mode_resize.c */ +void initResize(TransInfo *t); + +/* transform_mode_rotate.c */ +void initRotation(TransInfo *t); + +/* transform_mode_shear.c */ +void initShear(TransInfo *t); + +/* transform_mode_shrink_fatten.c */ +void initShrinkFatten(TransInfo *t); + +/* transform_mode_skin_resize.c */ +void initSkinResize(TransInfo *t); + +/* transform_mode_tilt.c */ +void initTilt(TransInfo *t); + +/* transform_mode_timescale.c */ +void initTimeScale(TransInfo *t); + +/* transform_mode_timeslide.c */ +void initTimeSlide(TransInfo *t); + +/* transform_mode_timetranslate.c */ +void initTimeTranslate(TransInfo *t); + +/* transform_mode_tosphere.c */ +void initToSphere(TransInfo *t); + +/* transform_mode_trackball.c */ +void initTrackball(TransInfo *t); + +/* transform_mode_translate.c */ +void initTranslation(TransInfo *t); + +/* transform_mode_vert_slide.c */ +void projectVertSlideData(TransInfo *t, bool is_final); +void drawVertSlide(TransInfo *t); +void doVertSlide(TransInfo *t, float perc); +void initVertSlide_ex(TransInfo *t, bool use_even, bool flipped, bool use_clamp); +void initVertSlide(TransInfo *t); +#endif diff --git a/source/blender/editors/transform/transform_mode_align.c b/source/blender/editors/transform/transform_mode_align.c new file mode 100644 index 00000000000..9bce793809b --- /dev/null +++ b/source/blender/editors/transform/transform_mode_align.c @@ -0,0 +1,96 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + */ + +/** \file + * \ingroup edtransform + */ + +#include <stdlib.h> + +#include "BLI_math.h" + +#include "BKE_context.h" + +#include "ED_screen.h" + +#include "BLT_translation.h" + +#include "transform.h" +#include "transform_mode.h" + +/* -------------------------------------------------------------------- */ +/* Transform (Align) */ + +/** \name Transform Align + * \{ */ + +static void applyAlign(TransInfo *t, const int UNUSED(mval[2])) +{ + float center[3]; + int i; + + FOREACH_TRANS_DATA_CONTAINER (t, tc) { + /* saving original center */ + copy_v3_v3(center, tc->center_local); + TransData *td = tc->data; + for (i = 0; i < tc->data_len; i++, td++) { + float mat[3][3], invmat[3][3]; + + if (td->flag & TD_NOACTION) { + break; + } + + if (td->flag & TD_SKIP) { + continue; + } + + /* around local centers */ + if (t->flag & (T_OBJECT | T_POSE)) { + copy_v3_v3(tc->center_local, td->center); + } + else { + if (t->settings->selectmode & SCE_SELECT_FACE) { + copy_v3_v3(tc->center_local, td->center); + } + } + + invert_m3_m3(invmat, td->axismtx); + + mul_m3_m3m3(mat, t->spacemtx, invmat); + + ElementRotation(t, tc, td, mat, t->around); + } + /* restoring original center */ + copy_v3_v3(tc->center_local, center); + } + + recalcData(t); + + ED_area_status_text(t->area, TIP_("Align")); +} + +void initAlign(TransInfo *t) +{ + t->flag |= T_NO_CONSTRAINT; + + t->transform = applyAlign; + + initMouseInputMode(t, &t->mouse, INPUT_NONE); +} +/** \} */ diff --git a/source/blender/editors/transform/transform_mode_baketime.c b/source/blender/editors/transform/transform_mode_baketime.c new file mode 100644 index 00000000000..bb8fd0df13d --- /dev/null +++ b/source/blender/editors/transform/transform_mode_baketime.c @@ -0,0 +1,140 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + */ + +/** \file + * \ingroup edtransform + */ + +#include <stdlib.h> + +#include "BLI_math.h" +#include "BLI_string.h" + +#include "BKE_context.h" +#include "BKE_unit.h" + +#include "ED_screen.h" + +#include "UI_interface.h" + +#include "BLT_translation.h" + +#include "transform.h" +#include "transform_mode.h" +#include "transform_snap.h" + +/* -------------------------------------------------------------------- */ +/* Transform (Bake-Time) */ + +/** \name Transform Bake-Time + * \{ */ + +static void applyBakeTime(TransInfo *t, const int mval[2]) +{ + float time; + int i; + char str[UI_MAX_DRAW_STR]; + + float fac = 0.1f; + + /* XXX, disable precision for now, + * this isn't even accessible by the user */ +#if 0 + if (t->mouse.precision) { + /* calculate ratio for shiftkey pos, and for total, and blend these for precision */ + time = (float)(t->center2d[0] - t->mouse.precision_mval[0]) * fac; + time += 0.1f * ((float)(t->center2d[0] * fac - mval[0]) - time); + } + else +#endif + { + time = (float)(t->center2d[0] - mval[0]) * fac; + } + + snapGridIncrement(t, &time); + + applyNumInput(&t->num, &time); + + /* header print for NumInput */ + if (hasNumInput(&t->num)) { + char c[NUM_STR_REP_LEN]; + + outputNumInput(&(t->num), c, &t->scene->unit); + + if (time >= 0.0f) { + BLI_snprintf(str, sizeof(str), TIP_("Time: +%s %s"), c, t->proptext); + } + else { + BLI_snprintf(str, sizeof(str), TIP_("Time: %s %s"), c, t->proptext); + } + } + else { + /* default header print */ + if (time >= 0.0f) { + BLI_snprintf(str, sizeof(str), TIP_("Time: +%.3f %s"), time, t->proptext); + } + else { + BLI_snprintf(str, sizeof(str), TIP_("Time: %.3f %s"), time, t->proptext); + } + } + + FOREACH_TRANS_DATA_CONTAINER (t, tc) { + TransData *td = tc->data; + for (i = 0; i < tc->data_len; i++, td++) { + if (td->flag & TD_NOACTION) { + break; + } + + if (td->flag & TD_SKIP) { + continue; + } + + if (td->val) { + *td->val = td->ival + time * td->factor; + if (td->ext->size && *td->val < *td->ext->size) { + *td->val = *td->ext->size; + } + if (td->ext->quat && *td->val > *td->ext->quat) { + *td->val = *td->ext->quat; + } + } + } + } + + recalcData(t); + + ED_area_status_text(t->area, str); +} + +void initBakeTime(TransInfo *t) +{ + t->transform = applyBakeTime; + initMouseInputMode(t, &t->mouse, INPUT_NONE); + + t->idx_max = 0; + t->num.idx_max = 0; + t->snap[0] = 0.0f; + t->snap[1] = 1.0f; + t->snap[2] = t->snap[1] * 0.1f; + + copy_v3_fl(t->num.val_inc, t->snap[1]); + t->num.unit_sys = t->scene->unit.system; + t->num.unit_type[0] = B_UNIT_NONE; /* Don't think this uses units? */ +} +/** \} */ diff --git a/source/blender/editors/transform/transform_mode_bbone_resize.c b/source/blender/editors/transform/transform_mode_bbone_resize.c new file mode 100644 index 00000000000..c81049ac379 --- /dev/null +++ b/source/blender/editors/transform/transform_mode_bbone_resize.c @@ -0,0 +1,184 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + */ + +/** \file + * \ingroup edtransform + */ + +#include <stdlib.h> + +#include "BLI_math.h" +#include "BLI_string.h" + +#include "BKE_context.h" +#include "BKE_unit.h" + +#include "ED_screen.h" + +#include "UI_interface.h" + +#include "BLT_translation.h" + +#include "transform.h" +#include "transform_constraints.h" +#include "transform_mode.h" +#include "transform_snap.h" + +/* -------------------------------------------------------------------- */ +/* Transform (EditBone (B-bone) width scaling) */ + +/** \name Transform B-bone width scaling + * \{ */ + +static void headerBoneSize(TransInfo *t, const float vec[3], char str[UI_MAX_DRAW_STR]) +{ + char tvec[NUM_STR_REP_LEN * 3]; + if (hasNumInput(&t->num)) { + outputNumInput(&(t->num), tvec, &t->scene->unit); + } + else { + BLI_snprintf(&tvec[0], NUM_STR_REP_LEN, "%.4f", vec[0]); + BLI_snprintf(&tvec[NUM_STR_REP_LEN], NUM_STR_REP_LEN, "%.4f", vec[1]); + BLI_snprintf(&tvec[NUM_STR_REP_LEN * 2], NUM_STR_REP_LEN, "%.4f", vec[2]); + } + + /* hmm... perhaps the y-axis values don't need to be shown? */ + if (t->con.mode & CON_APPLY) { + if (t->num.idx_max == 0) { + BLI_snprintf( + str, UI_MAX_DRAW_STR, TIP_("ScaleB: %s%s %s"), &tvec[0], t->con.text, t->proptext); + } + else { + BLI_snprintf(str, + UI_MAX_DRAW_STR, + TIP_("ScaleB: %s : %s : %s%s %s"), + &tvec[0], + &tvec[NUM_STR_REP_LEN], + &tvec[NUM_STR_REP_LEN * 2], + t->con.text, + t->proptext); + } + } + else { + BLI_snprintf(str, + UI_MAX_DRAW_STR, + TIP_("ScaleB X: %s Y: %s Z: %s%s %s"), + &tvec[0], + &tvec[NUM_STR_REP_LEN], + &tvec[NUM_STR_REP_LEN * 2], + t->con.text, + t->proptext); + } +} + +static void ElementBoneSize(TransInfo *t, TransDataContainer *tc, TransData *td, float mat[3][3]) +{ + float tmat[3][3], smat[3][3], oldy; + float sizemat[3][3]; + + mul_m3_m3m3(smat, mat, td->mtx); + mul_m3_m3m3(tmat, td->smtx, smat); + + if (t->con.applySize) { + t->con.applySize(t, tc, td, tmat); + } + + /* we've tucked the scale in loc */ + oldy = td->iloc[1]; + size_to_mat3(sizemat, td->iloc); + mul_m3_m3m3(tmat, tmat, sizemat); + mat3_to_size(td->loc, tmat); + td->loc[1] = oldy; +} + +static void applyBoneSize(TransInfo *t, const int UNUSED(mval[2])) +{ + float mat[3][3]; + int i; + char str[UI_MAX_DRAW_STR]; + + if (t->flag & T_INPUT_IS_VALUES_FINAL) { + copy_v3_v3(t->values_final, t->values); + } + else { + float ratio = t->values[0]; + + copy_v3_fl(t->values_final, ratio); + + snapGridIncrement(t, t->values_final); + + if (applyNumInput(&t->num, t->values_final)) { + constraintNumInput(t, t->values_final); + } + } + + size_to_mat3(mat, t->values_final); + + if (t->con.applySize) { + t->con.applySize(t, NULL, NULL, mat); + } + + copy_m3_m3(t->mat, mat); // used in gizmo + + headerBoneSize(t, t->values_final, str); + + FOREACH_TRANS_DATA_CONTAINER (t, tc) { + TransData *td = tc->data; + for (i = 0; i < tc->data_len; i++, td++) { + if (td->flag & TD_NOACTION) { + break; + } + + if (td->flag & TD_SKIP) { + continue; + } + + ElementBoneSize(t, tc, td, mat); + } + } + + recalcData(t); + + ED_area_status_text(t->area, str); +} + +void initBoneSize(TransInfo *t) +{ + t->mode = TFM_BONESIZE; + t->transform = applyBoneSize; + + initMouseInputMode(t, &t->mouse, INPUT_SPRING_FLIP); + + t->idx_max = 2; + t->num.idx_max = 2; + t->num.val_flag[0] |= NUM_NULL_ONE; + t->num.val_flag[1] |= NUM_NULL_ONE; + t->num.val_flag[2] |= NUM_NULL_ONE; + t->num.flag |= NUM_AFFECT_ALL; + t->snap[0] = 0.0f; + t->snap[1] = 0.1f; + t->snap[2] = t->snap[1] * 0.1f; + + copy_v3_fl(t->num.val_inc, t->snap[1]); + t->num.unit_sys = t->scene->unit.system; + t->num.unit_type[0] = B_UNIT_NONE; + t->num.unit_type[1] = B_UNIT_NONE; + t->num.unit_type[2] = B_UNIT_NONE; +} +/** \} */ diff --git a/source/blender/editors/transform/transform_mode_bend.c b/source/blender/editors/transform/transform_mode_bend.c new file mode 100644 index 00000000000..721d226050a --- /dev/null +++ b/source/blender/editors/transform/transform_mode_bend.c @@ -0,0 +1,308 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + */ + +/** \file + * \ingroup edtransform + */ + +#include <stdlib.h> + +#include "MEM_guardedalloc.h" + +#include "DNA_gpencil_types.h" + +#include "BLI_math.h" +#include "BLI_string.h" + +#include "BKE_context.h" +#include "BKE_unit.h" + +#include "ED_screen.h" + +#include "WM_api.h" +#include "WM_types.h" + +#include "UI_interface.h" + +#include "BLT_translation.h" + +#include "transform.h" +#include "transform_mode.h" +#include "transform_snap.h" + +/* -------------------------------------------------------------------- */ +/* Transform (Bend) */ + +/** \name Transform Bend + * \{ */ + +struct BendCustomData { + /* All values are in global space. */ + float warp_sta[3]; + float warp_end[3]; + + float warp_nor[3]; + float warp_tan[3]; + + /* for applying the mouse distance */ + float warp_init_dist; +}; + +static eRedrawFlag handleEventBend(TransInfo *UNUSED(t), const wmEvent *event) +{ + eRedrawFlag status = TREDRAW_NOTHING; + + if (event->type == MIDDLEMOUSE && event->val == KM_PRESS) { + status = TREDRAW_HARD; + } + + return status; +} + +static void Bend(TransInfo *t, const int UNUSED(mval[2])) +{ + float vec[3]; + float pivot_global[3]; + float warp_end_radius_global[3]; + int i; + char str[UI_MAX_DRAW_STR]; + const struct BendCustomData *data = t->custom.mode.data; + const bool is_clamp = (t->flag & T_ALT_TRANSFORM) == 0; + + union { + struct { + float angle, scale; + }; + float vector[2]; + } values; + + /* amount of radians for bend */ + copy_v2_v2(values.vector, t->values); + +#if 0 + snapGrid(t, angle_rad); +#else + /* hrmf, snapping radius is using 'angle' steps, need to convert to something else + * this isnt essential but nicer to give reasonable snapping values for radius */ + if (t->tsnap.mode & SCE_SNAP_MODE_INCREMENT) { + const float radius_snap = 0.1f; + const float snap_hack = (t->snap[1] * data->warp_init_dist) / radius_snap; + values.scale *= snap_hack; + snapGridIncrement(t, values.vector); + values.scale /= snap_hack; + } +#endif + + if (applyNumInput(&t->num, values.vector)) { + values.scale = values.scale / data->warp_init_dist; + } + + copy_v2_v2(t->values_final, values.vector); + + /* header print for NumInput */ + if (hasNumInput(&t->num)) { + char c[NUM_STR_REP_LEN * 2]; + + outputNumInput(&(t->num), c, &t->scene->unit); + + BLI_snprintf(str, + sizeof(str), + TIP_("Bend Angle: %s Radius: %s Alt, Clamp %s"), + &c[0], + &c[NUM_STR_REP_LEN], + WM_bool_as_string(is_clamp)); + } + else { + /* default header print */ + BLI_snprintf(str, + sizeof(str), + TIP_("Bend Angle: %.3f Radius: %.4f, Alt, Clamp %s"), + RAD2DEGF(values.angle), + values.scale * data->warp_init_dist, + WM_bool_as_string(is_clamp)); + } + + values.angle *= -1.0f; + values.scale *= data->warp_init_dist; + + /* calc 'data->warp_end' from 'data->warp_end_init' */ + copy_v3_v3(warp_end_radius_global, data->warp_end); + dist_ensure_v3_v3fl(warp_end_radius_global, data->warp_sta, values.scale); + /* done */ + + /* calculate pivot */ + copy_v3_v3(pivot_global, data->warp_sta); + if (values.angle > 0.0f) { + madd_v3_v3fl(pivot_global, + data->warp_tan, + -values.scale * shell_angle_to_dist((float)M_PI_2 - values.angle)); + } + else { + madd_v3_v3fl(pivot_global, + data->warp_tan, + +values.scale * shell_angle_to_dist((float)M_PI_2 + values.angle)); + } + + /* TODO(campbell): xform, compensate object center. */ + FOREACH_TRANS_DATA_CONTAINER (t, tc) { + TransData *td = tc->data; + + float warp_sta_local[3]; + float warp_end_local[3]; + float warp_end_radius_local[3]; + float pivot_local[3]; + + if (tc->use_local_mat) { + sub_v3_v3v3(warp_sta_local, data->warp_sta, tc->mat[3]); + sub_v3_v3v3(warp_end_local, data->warp_end, tc->mat[3]); + sub_v3_v3v3(warp_end_radius_local, warp_end_radius_global, tc->mat[3]); + sub_v3_v3v3(pivot_local, pivot_global, tc->mat[3]); + } + else { + copy_v3_v3(warp_sta_local, data->warp_sta); + copy_v3_v3(warp_end_local, data->warp_end); + copy_v3_v3(warp_end_radius_local, warp_end_radius_global); + copy_v3_v3(pivot_local, pivot_global); + } + + for (i = 0; i < tc->data_len; i++, td++) { + float mat[3][3]; + float delta[3]; + float fac, fac_scaled; + + if (td->flag & TD_NOACTION) { + break; + } + + if (td->flag & TD_SKIP) { + continue; + } + + if (UNLIKELY(values.angle == 0.0f)) { + copy_v3_v3(td->loc, td->iloc); + continue; + } + + copy_v3_v3(vec, td->iloc); + mul_m3_v3(td->mtx, vec); + + fac = line_point_factor_v3(vec, warp_sta_local, warp_end_radius_local); + if (is_clamp) { + CLAMP(fac, 0.0f, 1.0f); + } + + if (t->options & CTX_GPENCIL_STROKES) { + /* grease pencil multiframe falloff */ + bGPDstroke *gps = (bGPDstroke *)td->extra; + if (gps != NULL) { + fac_scaled = fac * td->factor * gps->runtime.multi_frame_falloff; + } + else { + fac_scaled = fac * td->factor; + } + } + else { + fac_scaled = fac * td->factor; + } + + axis_angle_normalized_to_mat3(mat, data->warp_nor, values.angle * fac_scaled); + interp_v3_v3v3(delta, warp_sta_local, warp_end_radius_local, fac_scaled); + sub_v3_v3(delta, warp_sta_local); + + /* delta is subtracted, rotation adds back this offset */ + sub_v3_v3(vec, delta); + + sub_v3_v3(vec, pivot_local); + mul_m3_v3(mat, vec); + add_v3_v3(vec, pivot_local); + + mul_m3_v3(td->smtx, vec); + + /* rotation */ + if ((t->flag & T_POINTS) == 0) { + ElementRotation(t, tc, td, mat, V3D_AROUND_LOCAL_ORIGINS); + } + + /* location */ + copy_v3_v3(td->loc, vec); + } + } + + recalcData(t); + + ED_area_status_text(t->area, str); +} + +void initBend(TransInfo *t) +{ + const float mval_fl[2] = {UNPACK2(t->mval)}; + const float *curs; + float tvec[3]; + struct BendCustomData *data; + + t->mode = TFM_BEND; + t->transform = Bend; + t->handleEvent = handleEventBend; + + setInputPostFct(&t->mouse, postInputRotation); + initMouseInputMode(t, &t->mouse, INPUT_ANGLE_SPRING); + + t->idx_max = 1; + t->num.idx_max = 1; + t->snap[0] = 0.0f; + t->snap[1] = SNAP_INCREMENTAL_ANGLE; + t->snap[2] = t->snap[1] * 0.2; + + copy_v3_fl(t->num.val_inc, t->snap[1]); + t->num.unit_sys = t->scene->unit.system; + t->num.unit_use_radians = (t->scene->unit.system_rotation == USER_UNIT_ROT_RADIANS); + t->num.unit_type[0] = B_UNIT_ROTATION; + t->num.unit_type[1] = B_UNIT_LENGTH; + + t->flag |= T_NO_CONSTRAINT; + + // copy_v3_v3(t->center, ED_view3d_cursor3d_get(t->scene, t->view)); + if ((t->flag & T_OVERRIDE_CENTER) == 0) { + calculateCenterCursor(t, t->center_global); + } + calculateCenterLocal(t, t->center_global); + + t->val = 0.0f; + + data = MEM_callocN(sizeof(*data), __func__); + + curs = t->scene->cursor.location; + copy_v3_v3(data->warp_sta, curs); + ED_view3d_win_to_3d( + (View3D *)t->area->spacedata.first, t->region, curs, mval_fl, data->warp_end); + + copy_v3_v3(data->warp_nor, t->viewinv[2]); + normalize_v3(data->warp_nor); + + /* tangent */ + sub_v3_v3v3(tvec, data->warp_end, data->warp_sta); + cross_v3_v3v3(data->warp_tan, tvec, data->warp_nor); + normalize_v3(data->warp_tan); + + data->warp_init_dist = len_v3v3(data->warp_end, data->warp_sta); + + t->custom.mode.data = data; + t->custom.mode.use_free = true; +} +/** \} */ diff --git a/source/blender/editors/transform/transform_mode_boneenvelope.c b/source/blender/editors/transform/transform_mode_boneenvelope.c new file mode 100644 index 00000000000..aa20a5ade95 --- /dev/null +++ b/source/blender/editors/transform/transform_mode_boneenvelope.c @@ -0,0 +1,121 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + */ + +/** \file + * \ingroup edtransform + */ + +#include <stdlib.h> + +#include "BLI_math.h" +#include "BLI_string.h" + +#include "BKE_context.h" +#include "BKE_unit.h" + +#include "ED_screen.h" + +#include "UI_interface.h" + +#include "BLT_translation.h" + +#include "transform.h" +#include "transform_mode.h" +#include "transform_snap.h" + +/* -------------------------------------------------------------------- */ +/* Transform (Bone Envelope) */ + +/** \name Transform Bone Envelope + * \{ */ + +static void applyBoneEnvelope(TransInfo *t, const int UNUSED(mval[2])) +{ + float ratio; + int i; + char str[UI_MAX_DRAW_STR]; + + ratio = t->values[0]; + + snapGridIncrement(t, &ratio); + + applyNumInput(&t->num, &ratio); + + t->values_final[0] = ratio; + + /* header print for NumInput */ + if (hasNumInput(&t->num)) { + char c[NUM_STR_REP_LEN]; + + outputNumInput(&(t->num), c, &t->scene->unit); + BLI_snprintf(str, sizeof(str), TIP_("Envelope: %s"), c); + } + else { + BLI_snprintf(str, sizeof(str), TIP_("Envelope: %3f"), ratio); + } + + FOREACH_TRANS_DATA_CONTAINER (t, tc) { + TransData *td = tc->data; + for (i = 0; i < tc->data_len; i++, td++) { + if (td->flag & TD_NOACTION) { + break; + } + + if (td->flag & TD_SKIP) { + continue; + } + + if (td->val) { + /* if the old/original value was 0.0f, then just use ratio */ + if (td->ival) { + *td->val = td->ival * ratio; + } + else { + *td->val = ratio; + } + } + } + } + + recalcData(t); + + ED_area_status_text(t->area, str); +} + +void initBoneEnvelope(TransInfo *t) +{ + t->mode = TFM_BONE_ENVELOPE; + t->transform = applyBoneEnvelope; + + initMouseInputMode(t, &t->mouse, INPUT_SPRING); + + t->idx_max = 0; + t->num.idx_max = 0; + t->snap[0] = 0.0f; + t->snap[1] = 0.1f; + t->snap[2] = t->snap[1] * 0.1f; + + copy_v3_fl(t->num.val_inc, t->snap[1]); + t->num.unit_sys = t->scene->unit.system; + t->num.unit_type[0] = B_UNIT_NONE; + + t->flag |= T_NO_CONSTRAINT | T_NO_PROJECT; +} + +/** \} */ diff --git a/source/blender/editors/transform/transform_mode_boneroll.c b/source/blender/editors/transform/transform_mode_boneroll.c new file mode 100644 index 00000000000..0564a946148 --- /dev/null +++ b/source/blender/editors/transform/transform_mode_boneroll.c @@ -0,0 +1,115 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + */ + +/** \file + * \ingroup edtransform + */ + +#include <stdlib.h> + +#include "BLI_math.h" +#include "BLI_string.h" + +#include "BKE_context.h" +#include "BKE_unit.h" + +#include "ED_screen.h" + +#include "UI_interface.h" + +#include "BLT_translation.h" + +#include "transform.h" +#include "transform_mode.h" +#include "transform_snap.h" + +/* -------------------------------------------------------------------- */ +/* Transform (EditBone Roll) */ + +/** \name Transform EditBone Roll + * \{ */ + +static void applyBoneRoll(TransInfo *t, const int UNUSED(mval[2])) +{ + int i; + char str[UI_MAX_DRAW_STR]; + + float final; + + final = t->values[0]; + + snapGridIncrement(t, &final); + + applyNumInput(&t->num, &final); + + t->values_final[0] = final; + + if (hasNumInput(&t->num)) { + char c[NUM_STR_REP_LEN]; + + outputNumInput(&(t->num), c, &t->scene->unit); + + BLI_snprintf(str, sizeof(str), TIP_("Roll: %s"), &c[0]); + } + else { + BLI_snprintf(str, sizeof(str), TIP_("Roll: %.2f"), RAD2DEGF(final)); + } + + /* set roll values */ + FOREACH_TRANS_DATA_CONTAINER (t, tc) { + TransData *td = tc->data; + for (i = 0; i < tc->data_len; i++, td++) { + if (td->flag & TD_NOACTION) { + break; + } + + if (td->flag & TD_SKIP) { + continue; + } + + *(td->val) = td->ival - final; + } + } + + recalcData(t); + + ED_area_status_text(t->area, str); +} + +void initBoneRoll(TransInfo *t) +{ + t->mode = TFM_BONE_ROLL; + t->transform = applyBoneRoll; + + initMouseInputMode(t, &t->mouse, INPUT_ANGLE); + + t->idx_max = 0; + t->num.idx_max = 0; + t->snap[0] = 0.0f; + t->snap[1] = DEG2RAD(5.0); + t->snap[2] = DEG2RAD(1.0); + + copy_v3_fl(t->num.val_inc, t->snap[1]); + t->num.unit_sys = t->scene->unit.system; + t->num.unit_use_radians = (t->scene->unit.system_rotation == USER_UNIT_ROT_RADIANS); + t->num.unit_type[0] = B_UNIT_ROTATION; + + t->flag |= T_NO_CONSTRAINT | T_NO_PROJECT; +} +/** \} */ diff --git a/source/blender/editors/transform/transform_mode_curveshrinkfatten.c b/source/blender/editors/transform/transform_mode_curveshrinkfatten.c new file mode 100644 index 00000000000..057f13ac068 --- /dev/null +++ b/source/blender/editors/transform/transform_mode_curveshrinkfatten.c @@ -0,0 +1,124 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + */ + +/** \file + * \ingroup edtransform + */ + +#include <stdlib.h> + +#include "BLI_math.h" +#include "BLI_string.h" + +#include "BKE_context.h" +#include "BKE_unit.h" + +#include "ED_screen.h" + +#include "UI_interface.h" + +#include "BLT_translation.h" + +#include "transform.h" +#include "transform_mode.h" +#include "transform_snap.h" + +/* -------------------------------------------------------------------- */ +/* Transform (Curve Shrink/Fatten) */ + +/** \name Transform Curve Shrink/Fatten + * \{ */ + +static void applyCurveShrinkFatten(TransInfo *t, const int UNUSED(mval[2])) +{ + float ratio; + int i; + char str[UI_MAX_DRAW_STR]; + + ratio = t->values[0]; + + snapGridIncrement(t, &ratio); + + applyNumInput(&t->num, &ratio); + + t->values_final[0] = ratio; + + /* header print for NumInput */ + if (hasNumInput(&t->num)) { + char c[NUM_STR_REP_LEN]; + + outputNumInput(&(t->num), c, &t->scene->unit); + BLI_snprintf(str, sizeof(str), TIP_("Shrink/Fatten: %s"), c); + } + else { + BLI_snprintf(str, sizeof(str), TIP_("Shrink/Fatten: %3f"), ratio); + } + + FOREACH_TRANS_DATA_CONTAINER (t, tc) { + TransData *td = tc->data; + for (i = 0; i < tc->data_len; i++, td++) { + if (td->flag & TD_NOACTION) { + break; + } + + if (td->flag & TD_SKIP) { + continue; + } + + if (td->val) { + *td->val = td->ival * ratio; + /* apply PET */ + *td->val = (*td->val * td->factor) + ((1.0f - td->factor) * td->ival); + if (*td->val <= 0.0f) { + *td->val = 0.001f; + } + } + } + } + + recalcData(t); + + ED_area_status_text(t->area, str); +} + +void initCurveShrinkFatten(TransInfo *t) +{ + t->mode = TFM_CURVE_SHRINKFATTEN; + t->transform = applyCurveShrinkFatten; + + initMouseInputMode(t, &t->mouse, INPUT_SPRING); + + t->idx_max = 0; + t->num.idx_max = 0; + t->snap[0] = 0.0f; + t->snap[1] = 0.1f; + t->snap[2] = t->snap[1] * 0.1f; + + copy_v3_fl(t->num.val_inc, t->snap[1]); + t->num.unit_sys = t->scene->unit.system; + t->num.unit_type[0] = B_UNIT_NONE; + + t->flag |= T_NO_ZERO; +#ifdef USE_NUM_NO_ZERO + t->num.val_flag[0] |= NUM_NO_ZERO; +#endif + + t->flag |= T_NO_CONSTRAINT; +} +/** \} */ diff --git a/source/blender/editors/transform/transform_mode_edge_bevelweight.c b/source/blender/editors/transform/transform_mode_edge_bevelweight.c new file mode 100644 index 00000000000..5db7895232c --- /dev/null +++ b/source/blender/editors/transform/transform_mode_edge_bevelweight.c @@ -0,0 +1,130 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + */ + +/** \file + * \ingroup edtransform + */ + +#include <stdlib.h> + +#include "BLI_math.h" +#include "BLI_string.h" + +#include "BKE_context.h" +#include "BKE_unit.h" + +#include "ED_screen.h" + +#include "UI_interface.h" + +#include "BLT_translation.h" + +#include "transform.h" +#include "transform_mode.h" +#include "transform_snap.h" + +/* -------------------------------------------------------------------- */ +/* Transform (Bevel Weight) */ + +/** \name Transform Bevel Weight + * \{ */ + +static void applyBevelWeight(TransInfo *t, const int UNUSED(mval[2])) +{ + float weight; + int i; + char str[UI_MAX_DRAW_STR]; + + weight = t->values[0]; + + CLAMP_MAX(weight, 1.0f); + + snapGridIncrement(t, &weight); + + applyNumInput(&t->num, &weight); + + t->values_final[0] = weight; + + /* header print for NumInput */ + if (hasNumInput(&t->num)) { + char c[NUM_STR_REP_LEN]; + + outputNumInput(&(t->num), c, &t->scene->unit); + + if (weight >= 0.0f) { + BLI_snprintf(str, sizeof(str), TIP_("Bevel Weight: +%s %s"), c, t->proptext); + } + else { + BLI_snprintf(str, sizeof(str), TIP_("Bevel Weight: %s %s"), c, t->proptext); + } + } + else { + /* default header print */ + if (weight >= 0.0f) { + BLI_snprintf(str, sizeof(str), TIP_("Bevel Weight: +%.3f %s"), weight, t->proptext); + } + else { + BLI_snprintf(str, sizeof(str), TIP_("Bevel Weight: %.3f %s"), weight, t->proptext); + } + } + + FOREACH_TRANS_DATA_CONTAINER (t, tc) { + TransData *td = tc->data; + for (i = 0; i < tc->data_len; i++, td++) { + if (td->flag & TD_NOACTION) { + break; + } + + if (td->val) { + *td->val = td->ival + weight * td->factor; + if (*td->val < 0.0f) { + *td->val = 0.0f; + } + if (*td->val > 1.0f) { + *td->val = 1.0f; + } + } + } + } + + recalcData(t); + + ED_area_status_text(t->area, str); +} + +void initBevelWeight(TransInfo *t) +{ + t->mode = TFM_BWEIGHT; + t->transform = applyBevelWeight; + + initMouseInputMode(t, &t->mouse, INPUT_SPRING_DELTA); + + t->idx_max = 0; + t->num.idx_max = 0; + t->snap[0] = 0.0f; + t->snap[1] = 0.1f; + t->snap[2] = t->snap[1] * 0.1f; + + copy_v3_fl(t->num.val_inc, t->snap[1]); + t->num.unit_sys = t->scene->unit.system; + t->num.unit_type[0] = B_UNIT_NONE; + + t->flag |= T_NO_CONSTRAINT | T_NO_PROJECT; +} +/** \} */ diff --git a/source/blender/editors/transform/transform_mode_edge_crease.c b/source/blender/editors/transform/transform_mode_edge_crease.c new file mode 100644 index 00000000000..4a92a57fef6 --- /dev/null +++ b/source/blender/editors/transform/transform_mode_edge_crease.c @@ -0,0 +1,134 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + */ + +/** \file + * \ingroup edtransform + */ + +#include <stdlib.h> + +#include "BLI_math.h" +#include "BLI_string.h" + +#include "BKE_context.h" +#include "BKE_unit.h" + +#include "ED_screen.h" + +#include "UI_interface.h" + +#include "BLT_translation.h" + +#include "transform.h" +#include "transform_mode.h" +#include "transform_snap.h" + +/* -------------------------------------------------------------------- */ +/* Transform (Crease) */ + +/** \name Transform Crease + * \{ */ + +static void applyCrease(TransInfo *t, const int UNUSED(mval[2])) +{ + float crease; + int i; + char str[UI_MAX_DRAW_STR]; + + crease = t->values[0]; + + CLAMP_MAX(crease, 1.0f); + + snapGridIncrement(t, &crease); + + applyNumInput(&t->num, &crease); + + t->values_final[0] = crease; + + /* header print for NumInput */ + if (hasNumInput(&t->num)) { + char c[NUM_STR_REP_LEN]; + + outputNumInput(&(t->num), c, &t->scene->unit); + + if (crease >= 0.0f) { + BLI_snprintf(str, sizeof(str), TIP_("Crease: +%s %s"), c, t->proptext); + } + else { + BLI_snprintf(str, sizeof(str), TIP_("Crease: %s %s"), c, t->proptext); + } + } + else { + /* default header print */ + if (crease >= 0.0f) { + BLI_snprintf(str, sizeof(str), TIP_("Crease: +%.3f %s"), crease, t->proptext); + } + else { + BLI_snprintf(str, sizeof(str), TIP_("Crease: %.3f %s"), crease, t->proptext); + } + } + + FOREACH_TRANS_DATA_CONTAINER (t, tc) { + TransData *td = tc->data; + for (i = 0; i < tc->data_len; i++, td++) { + if (td->flag & TD_NOACTION) { + break; + } + + if (td->flag & TD_SKIP) { + continue; + } + + if (td->val) { + *td->val = td->ival + crease * td->factor; + if (*td->val < 0.0f) { + *td->val = 0.0f; + } + if (*td->val > 1.0f) { + *td->val = 1.0f; + } + } + } + } + + recalcData(t); + + ED_area_status_text(t->area, str); +} + +void initCrease(TransInfo *t) +{ + t->mode = TFM_CREASE; + t->transform = applyCrease; + + initMouseInputMode(t, &t->mouse, INPUT_SPRING_DELTA); + + t->idx_max = 0; + t->num.idx_max = 0; + t->snap[0] = 0.0f; + t->snap[1] = 0.1f; + t->snap[2] = t->snap[1] * 0.1f; + + copy_v3_fl(t->num.val_inc, t->snap[1]); + t->num.unit_sys = t->scene->unit.system; + t->num.unit_type[0] = B_UNIT_NONE; + + t->flag |= T_NO_CONSTRAINT | T_NO_PROJECT; +} +/** \} */ diff --git a/source/blender/editors/transform/transform_mode_edge_rotate_normal.c b/source/blender/editors/transform/transform_mode_edge_rotate_normal.c new file mode 100644 index 00000000000..fde0d5b187e --- /dev/null +++ b/source/blender/editors/transform/transform_mode_edge_rotate_normal.c @@ -0,0 +1,156 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + */ + +/** \file + * \ingroup edtransform + */ + +#include <stdlib.h> + +#include "BLI_math.h" + +#include "BKE_context.h" +#include "BKE_editmesh.h" +#include "BKE_mesh.h" +#include "BKE_unit.h" + +#include "ED_screen.h" + +#include "UI_interface.h" + +#include "transform.h" +#include "transform_mode.h" +#include "transform_snap.h" + +/* -------------------------------------------------------------------- */ +/* Transform (Normal Rotation) */ + +/** \name Transform Normal Rotation + * \{ */ + +static void storeCustomLNorValue(TransDataContainer *tc, BMesh *bm) +{ + BMLoopNorEditDataArray *lnors_ed_arr = BM_loop_normal_editdata_array_init(bm, false); + // BMLoopNorEditData *lnor_ed = lnors_ed_arr->lnor_editdata; + + tc->custom.mode.data = lnors_ed_arr; + tc->custom.mode.free_cb = freeCustomNormalArray; +} + +void freeCustomNormalArray(TransInfo *t, TransDataContainer *tc, TransCustomData *custom_data) +{ + BMLoopNorEditDataArray *lnors_ed_arr = custom_data->data; + + if (t->state == TRANS_CANCEL) { + BMLoopNorEditData *lnor_ed = lnors_ed_arr->lnor_editdata; + BMEditMesh *em = BKE_editmesh_from_object(tc->obedit); + BMesh *bm = em->bm; + + /* Restore custom loop normal on cancel */ + for (int i = 0; i < lnors_ed_arr->totloop; i++, lnor_ed++) { + BKE_lnor_space_custom_normal_to_data( + bm->lnor_spacearr->lspacearr[lnor_ed->loop_index], lnor_ed->niloc, lnor_ed->clnors_data); + } + } + + BM_loop_normal_editdata_array_free(lnors_ed_arr); + + tc->custom.mode.data = NULL; + tc->custom.mode.free_cb = NULL; +} + +/* Works by getting custom normal from clnor_data, transform, then store */ +static void applyNormalRotation(TransInfo *t, const int UNUSED(mval[2])) +{ + char str[UI_MAX_DRAW_STR]; + + float axis_final[3]; + copy_v3_v3(axis_final, t->spacemtx[t->orient_axis]); + + if ((t->con.mode & CON_APPLY) && t->con.applyRot) { + t->con.applyRot(t, NULL, NULL, axis_final, NULL); + } + + FOREACH_TRANS_DATA_CONTAINER (t, tc) { + BMEditMesh *em = BKE_editmesh_from_object(tc->obedit); + BMesh *bm = em->bm; + + BMLoopNorEditDataArray *lnors_ed_arr = tc->custom.mode.data; + BMLoopNorEditData *lnor_ed = lnors_ed_arr->lnor_editdata; + + float axis[3]; + float mat[3][3]; + float angle = t->values[0]; + copy_v3_v3(axis, axis_final); + + snapGridIncrement(t, &angle); + + applySnapping(t, &angle); + + applyNumInput(&t->num, &angle); + + headerRotation(t, str, angle); + + axis_angle_normalized_to_mat3(mat, axis, angle); + + for (int i = 0; i < lnors_ed_arr->totloop; i++, lnor_ed++) { + mul_v3_m3v3(lnor_ed->nloc, mat, lnor_ed->niloc); + + BKE_lnor_space_custom_normal_to_data( + bm->lnor_spacearr->lspacearr[lnor_ed->loop_index], lnor_ed->nloc, lnor_ed->clnors_data); + } + + t->values_final[0] = angle; + } + + recalcData(t); + + ED_area_status_text(t->area, str); +} + +void initNormalRotation(TransInfo *t) +{ + t->mode = TFM_NORMAL_ROTATION; + t->transform = applyNormalRotation; + + setInputPostFct(&t->mouse, postInputRotation); + initMouseInputMode(t, &t->mouse, INPUT_ANGLE); + + t->idx_max = 0; + t->num.idx_max = 0; + t->snap[0] = 0.0f; + t->snap[1] = DEG2RAD(5.0); + t->snap[2] = DEG2RAD(1.0); + + copy_v3_fl(t->num.val_inc, t->snap[2]); + t->num.unit_sys = t->scene->unit.system; + t->num.unit_use_radians = (t->scene->unit.system_rotation == USER_UNIT_ROT_RADIANS); + t->num.unit_type[0] = B_UNIT_ROTATION; + + FOREACH_TRANS_DATA_CONTAINER (t, tc) { + BMEditMesh *em = BKE_editmesh_from_object(tc->obedit); + BMesh *bm = em->bm; + + BKE_editmesh_ensure_autosmooth(em, tc->obedit->data); + BKE_editmesh_lnorspace_update(em, tc->obedit->data); + + storeCustomLNorValue(tc, bm); + } +} +/** \} */ diff --git a/source/blender/editors/transform/transform_mode_edge_seq_slide.c b/source/blender/editors/transform/transform_mode_edge_seq_slide.c new file mode 100644 index 00000000000..ee91459dcdd --- /dev/null +++ b/source/blender/editors/transform/transform_mode_edge_seq_slide.c @@ -0,0 +1,147 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + */ + +/** \file + * \ingroup edtransform + */ + +#include <stdlib.h> + +#include "BLI_math.h" +#include "BLI_string.h" + +#include "BKE_context.h" +#include "BKE_unit.h" + +#include "ED_screen.h" + +#include "WM_api.h" + +#include "UI_interface.h" + +#include "BLT_translation.h" + +#include "transform.h" +#include "transform_mode.h" +#include "transform_snap.h" + +/* -------------------------------------------------------------------- */ +/* Transform (Sequencer Slide) */ + +/** \name Transform Sequencer Slide + * \{ */ + +static void headerSeqSlide(TransInfo *t, const float val[2], char str[UI_MAX_DRAW_STR]) +{ + char tvec[NUM_STR_REP_LEN * 3]; + size_t ofs = 0; + + if (hasNumInput(&t->num)) { + outputNumInput(&(t->num), tvec, &t->scene->unit); + } + else { + BLI_snprintf(&tvec[0], NUM_STR_REP_LEN, "%.0f, %.0f", val[0], val[1]); + } + + ofs += BLI_snprintf( + str + ofs, UI_MAX_DRAW_STR - ofs, TIP_("Sequence Slide: %s%s, ("), &tvec[0], t->con.text); + + if (t->keymap) { + wmKeyMapItem *kmi = WM_modalkeymap_find_propvalue(t->keymap, TFM_MODAL_TRANSLATE); + if (kmi) { + ofs += WM_keymap_item_to_string(kmi, false, str + ofs, UI_MAX_DRAW_STR - ofs); + } + } + ofs += BLI_snprintf(str + ofs, + UI_MAX_DRAW_STR - ofs, + TIP_(" or Alt) Expand to fit %s"), + WM_bool_as_string((t->flag & T_ALT_TRANSFORM) != 0)); +} + +static void applySeqSlideValue(TransInfo *t, const float val[2]) +{ + int i; + + FOREACH_TRANS_DATA_CONTAINER (t, tc) { + TransData *td = tc->data; + for (i = 0; i < tc->data_len; i++, td++) { + if (td->flag & TD_NOACTION) { + break; + } + + if (td->flag & TD_SKIP) { + continue; + } + + madd_v2_v2v2fl(td->loc, td->iloc, val, td->factor); + } + } +} + +static void applySeqSlide(TransInfo *t, const int mval[2]) +{ + char str[UI_MAX_DRAW_STR]; + + snapSequenceBounds(t, mval); + + if (t->con.mode & CON_APPLY) { + float pvec[3] = {0.0f, 0.0f, 0.0f}; + float tvec[3]; + t->con.applyVec(t, NULL, NULL, t->values, tvec, pvec); + copy_v3_v3(t->values_final, tvec); + } + else { + // snapGridIncrement(t, t->values); + applyNumInput(&t->num, t->values); + copy_v3_v3(t->values_final, t->values); + } + + t->values_final[0] = floorf(t->values_final[0] + 0.5f); + t->values_final[1] = floorf(t->values_final[1] + 0.5f); + + headerSeqSlide(t, t->values_final, str); + applySeqSlideValue(t, t->values_final); + + recalcData(t); + + ED_area_status_text(t->area, str); +} + +void initSeqSlide(TransInfo *t) +{ + t->transform = applySeqSlide; + + initMouseInputMode(t, &t->mouse, INPUT_VECTOR); + + t->idx_max = 1; + t->num.flag = 0; + t->num.idx_max = t->idx_max; + + t->snap[0] = 0.0f; + 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]); + t->num.unit_sys = t->scene->unit.system; + /* Would be nice to have a time handling in units as well + * (supporting frames in addition to "natural" time...). */ + t->num.unit_type[0] = B_UNIT_NONE; + t->num.unit_type[1] = B_UNIT_NONE; +} +/** \} */ diff --git a/source/blender/editors/transform/transform_mode_edge_slide.c b/source/blender/editors/transform/transform_mode_edge_slide.c new file mode 100644 index 00000000000..5613a782529 --- /dev/null +++ b/source/blender/editors/transform/transform_mode_edge_slide.c @@ -0,0 +1,1498 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + */ + +/** \file + * \ingroup edtransform + */ + +#include <stdlib.h> + +#include "MEM_guardedalloc.h" + +#include "BLI_math.h" +#include "BLI_string.h" +#include "BLI_utildefines_stack.h" + +#include "BKE_context.h" +#include "BKE_editmesh.h" +#include "BKE_editmesh_bvh.h" +#include "BKE_unit.h" + +#include "GPU_immediate.h" +#include "GPU_matrix.h" +#include "GPU_state.h" + +#include "ED_mesh.h" +#include "ED_screen.h" + +#include "WM_api.h" +#include "WM_types.h" + +#include "UI_interface.h" +#include "UI_resources.h" + +#include "BLT_translation.h" + +#include "transform.h" +#include "transform_convert.h" +#include "transform_mode.h" +#include "transform_snap.h" + +/* -------------------------------------------------------------------- */ +/* Transform (Edge Slide) */ + +/** \name Transform Edge Slide + * \{ */ + +typedef struct TransDataEdgeSlideVert { + /** #TransDataGenericSlideVert (header) */ + struct BMVert *v; + struct LinkNode **cd_loop_groups; + float v_co_orig[3]; + /* end generic */ + + float edge_len; + + struct BMVert *v_side[2]; + + /* add origvert.co to get the original locations */ + float dir_side[2][3]; + + int loop_nr; +} TransDataEdgeSlideVert; + +typedef struct EdgeSlideData { + TransDataEdgeSlideVert *sv; + int totsv; + + int mval_start[2], mval_end[2]; + int curr_sv_index; + + /** when un-clamped - use this index: #TransDataEdgeSlideVert.dir_side */ + int curr_side_unclamp; +} EdgeSlideData; + +typedef struct EdgeSlideParams { + float perc; + + bool use_even; + bool flipped; +} EdgeSlideParams; + +/** + * Get the first valid EdgeSlideData. + * + * Note we cannot trust TRANS_DATA_CONTAINER_FIRST_OK because of multi-object that + * may leave items with invalid custom data in the transform data container. + */ +static EdgeSlideData *edgeSlideFirstGet(TransInfo *t) +{ + FOREACH_TRANS_DATA_CONTAINER (t, tc) { + EdgeSlideData *sld = tc->custom.mode.data; + if (sld == NULL) { + continue; + } + return sld; + } + BLI_assert(!"Should never happen, at least one EdgeSlideData should be valid"); + return NULL; +} + +static void calcEdgeSlideCustomPoints(struct TransInfo *t) +{ + EdgeSlideData *sld = edgeSlideFirstGet(t); + + 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 immediately 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; + BMEdge *e_iter; + + BM_ITER_ELEM (e_iter, &iter, v, BM_EDGES_OF_VERT) { + if (BM_elem_flag_test(e_iter, BM_ELEM_SELECT) && e_iter != e) { + return e_iter; + } + } + + return NULL; +} + +/* 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], float t) +{ + float t_mid, t_delta; + + /* could be pre-calculated */ + t_mid = line_point_factor_v3(v2, v1, v3); + + t_delta = 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 { + 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); + } + } +} + +/** + * Find the closest point on the ngon on the opposite side. + * used to set the edge slide distance for ngons. + */ +static bool bm_loop_calc_opposite_co(BMLoop *l_tmp, const float plane_no[3], float r_co[3]) +{ + /* skip adjacent edges */ + BMLoop *l_first = l_tmp->next; + BMLoop *l_last = l_tmp->prev; + BMLoop *l_iter; + float dist = FLT_MAX; + bool found = false; + + l_iter = l_first; + do { + float tvec[3]; + if (isect_line_plane_v3(tvec, l_iter->v->co, l_iter->next->v->co, l_tmp->v->co, plane_no)) { + const float fac = line_point_factor_v3(tvec, l_iter->v->co, l_iter->next->v->co); + /* allow some overlap to avoid missing the intersection because of float precision */ + if ((fac > -FLT_EPSILON) && (fac < 1.0f + FLT_EPSILON)) { + /* likelihood of multiple intersections per ngon is quite low, + * it would have to loop back on its self, but better support it + * so check for the closest opposite edge */ + const float tdist = len_v3v3(l_tmp->v->co, tvec); + if (tdist < dist) { + copy_v3_v3(r_co, tvec); + dist = tdist; + found = true; + } + } + } + } while ((l_iter = l_iter->next) != l_last); + + return found; +} + +/** + * Given 2 edges and a loop, step over the loops + * and calculate a direction to slide along. + * + * \param r_slide_vec: the direction to slide, + * the length of the vector defines the slide distance. + */ +static BMLoop *get_next_loop( + BMVert *v, BMLoop *l, BMEdge *e_prev, BMEdge *e_next, float r_slide_vec[3]) +{ + BMLoop *l_first; + float vec_accum[3] = {0.0f, 0.0f, 0.0f}; + float vec_accum_len = 0.0f; + int i = 0; + + BLI_assert(BM_edge_share_vert(e_prev, e_next) == v); + BLI_assert(BM_vert_in_edge(l->e, v)); + + l_first = l; + do { + l = BM_loop_other_edge_loop(l, v); + + if (l->e == e_next) { + if (i) { + normalize_v3_length(vec_accum, vec_accum_len / (float)i); + } + else { + /* When there is no edge to slide along, + * we must slide along the vector defined by the face we're attach to */ + BMLoop *l_tmp = BM_face_vert_share_loop(l_first->f, v); + + BLI_assert(ELEM(l_tmp->e, e_prev, e_next) && ELEM(l_tmp->prev->e, e_prev, e_next)); + + if (l_tmp->f->len == 4) { + /* we could use code below, but in this case + * sliding diagonally across the quad works well */ + sub_v3_v3v3(vec_accum, l_tmp->next->next->v->co, v->co); + } + else { + float tdir[3]; + BM_loop_calc_face_direction(l_tmp, tdir); + cross_v3_v3v3(vec_accum, l_tmp->f->no, tdir); +#if 0 + /* rough guess, we can do better! */ + normalize_v3_length(vec_accum, + (BM_edge_calc_length(e_prev) + BM_edge_calc_length(e_next)) / 2.0f); +#else + /* be clever, check the opposite ngon edge to slide into. + * this gives best results */ + { + float tvec[3]; + float dist; + + if (bm_loop_calc_opposite_co(l_tmp, tdir, tvec)) { + dist = len_v3v3(l_tmp->v->co, tvec); + } + else { + dist = (BM_edge_calc_length(e_prev) + BM_edge_calc_length(e_next)) / 2.0f; + } + + normalize_v3_length(vec_accum, dist); + } +#endif + } + } + + copy_v3_v3(r_slide_vec, vec_accum); + return l; + } + else { + /* accumulate the normalized edge vector, + * normalize so some edges don't skew the result */ + float tvec[3]; + sub_v3_v3v3(tvec, BM_edge_other_vert(l->e, v)->co, v->co); + vec_accum_len += normalize_v3(tvec); + add_v3_v3(vec_accum, tvec); + i += 1; + } + + if (BM_loop_other_edge_loop(l, v)->e == e_next) { + if (i) { + normalize_v3_length(vec_accum, vec_accum_len / (float)i); + } + + copy_v3_v3(r_slide_vec, vec_accum); + return BM_loop_other_edge_loop(l, v); + } + + } while ((l != l->radial_next) && ((l = l->radial_next) != l_first)); + + if (i) { + normalize_v3_length(vec_accum, vec_accum_len / (float)i); + } + + copy_v3_v3(r_slide_vec, vec_accum); + + return NULL; +} + +/** + * Calculate screenspace `mval_start` / `mval_end`, optionally slide direction. + */ +static void calcEdgeSlide_mval_range(TransInfo *t, + TransDataContainer *tc, + EdgeSlideData *sld, + const int *sv_table, + const int loop_nr, + const float mval[2], + const bool use_occlude_geometry, + const bool use_calc_direction) +{ + TransDataEdgeSlideVert *sv; + BMEditMesh *em = BKE_editmesh_from_object(tc->obedit); + ARegion *region = t->region; + View3D *v3d = NULL; + RegionView3D *rv3d = NULL; + float projectMat[4][4]; + BMBVHTree *bmbvh; + + /* 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; + + if (t->spacetype == SPACE_VIEW3D) { + /* background mode support */ + v3d = t->area ? t->area->spacedata.first : NULL; + rv3d = t->region ? t->region->regiondata : NULL; + } + + if (!rv3d) { + /* ok, let's try to survive this */ + unit_m4(projectMat); + } + else { + ED_view3d_ob_project_mat_get(rv3d, tc->obedit, projectMat); + } + + if (use_occlude_geometry) { + bmbvh = BKE_bmbvh_new_from_editmesh(em, BMBVH_RESPECT_HIDDEN, NULL, false); + } + else { + bmbvh = 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); + } + + sv = &sld->sv[0]; + for (int i = 0; i < sld->totsv; i++, sv++) { + BMIter iter_other; + BMEdge *e; + BMVert *v = sv->v; + + UNUSED_VARS_NDEBUG(sv_table); /* silence warning */ + BLI_assert(i == sv_table[BM_elem_index_get(v)]); + + /* search cross edges for visible edge to the mouse cursor, + * then use the shared vertex to calculate screen vector*/ + BM_ITER_ELEM (e, &iter_other, v, BM_EDGES_OF_VERT) { + /* screen-space coords */ + float sco_a[3], sco_b[3]; + float dist_sq; + int l_nr; + + if (BM_elem_flag_test(e, BM_ELEM_SELECT)) { + continue; + } + + /* This test is only relevant if object is not wire-drawn! See [#32068]. */ + bool is_visible = !use_occlude_geometry || + BMBVH_EdgeVisible(bmbvh, e, t->depsgraph, region, v3d, tc->obedit); + + if (!is_visible && !use_calc_direction) { + continue; + } + + if (sv->v_side[1]) { + ED_view3d_project_float_v3_m4(region, sv->v_side[1]->co, sco_b, projectMat); + } + else { + add_v3_v3v3(sco_b, v->co, sv->dir_side[1]); + ED_view3d_project_float_v3_m4(region, sco_b, sco_b, projectMat); + } + + if (sv->v_side[0]) { + ED_view3d_project_float_v3_m4(region, sv->v_side[0]->co, sco_a, projectMat); + } + else { + add_v3_v3v3(sco_a, v->co, sv->dir_side[0]); + ED_view3d_project_float_v3_m4(region, sco_a, sco_a, projectMat); + } + + /* global direction */ + dist_sq = dist_squared_to_line_segment_v2(mval, sco_b, sco_a); + if (is_visible) { + 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->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 = &sld->sv[0]; + for (i = 0; i < sld->totsv; i++, sv++) { + /* switch a/b if loop direction is different from global direction */ + int l_nr = sv->loop_nr; + if (dot_v3v3(loop_dir[l_nr], mval_dir) < 0.0f) { + swap_v3_v3(sv->dir_side[0], sv->dir_side[1]); + SWAP(BMVert *, sv->v_side[0], sv->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 (bmbvh) { + BKE_bmbvh_free(bmbvh); + } +} + +static void calcEdgeSlide_even(TransInfo *t, + TransDataContainer *tc, + EdgeSlideData *sld, + const float mval[2]) +{ + TransDataEdgeSlideVert *sv = sld->sv; + + if (sld->totsv > 0) { + ARegion *region = t->region; + RegionView3D *rv3d = NULL; + float projectMat[4][4]; + + int i = 0; + + float v_proj[2]; + float dist_sq = 0; + float dist_min_sq = FLT_MAX; + + if (t->spacetype == SPACE_VIEW3D) { + /* background mode support */ + rv3d = t->region ? t->region->regiondata : NULL; + } + + if (!rv3d) { + /* ok, let's try to survive this */ + unit_m4(projectMat); + } + else { + ED_view3d_ob_project_mat_get(rv3d, tc->obedit, projectMat); + } + + for (i = 0; i < sld->totsv; i++, sv++) { + /* Set length */ + sv->edge_len = len_v3v3(sv->dir_side[0], sv->dir_side[1]); + + ED_view3d_project_float_v2_m4(region, sv->v->co, v_proj, projectMat); + dist_sq = len_squared_v2v2(mval, v_proj); + if (dist_sq < dist_min_sq) { + dist_min_sq = dist_sq; + sld->curr_sv_index = i; + } + } + } + else { + sld->curr_sv_index = 0; + } +} + +static bool createEdgeSlideVerts_double_side(TransInfo *t, TransDataContainer *tc) +{ + BMEditMesh *em = BKE_editmesh_from_object(tc->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 numsel, i, loop_nr; + bool use_occlude_geometry = false; + View3D *v3d = NULL; + RegionView3D *rv3d = NULL; + + sld->curr_sv_index = 0; + + /*ensure valid selection*/ + BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) { + if (BM_elem_flag_test(v, BM_ELEM_SELECT)) { + BMIter iter2; + numsel = 0; + BM_ITER_ELEM (e, &iter2, v, BM_EDGES_OF_VERT) { + if (BM_elem_flag_test(e, BM_ELEM_SELECT)) { + /* BMESH_TODO: this is probably very evil, + * set v->e to a selected edge*/ + v->e = e; + + numsel++; + } + } + + if (numsel == 0 || numsel > 2) { + MEM_freeN(sld); + return false; /* invalid edge selection */ + } + } + } + + BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) { + if (BM_elem_flag_test(e, BM_ELEM_SELECT)) { + /* note, any edge with loops can work, but we won't get predictable results, so bail out */ + if (!BM_edge_is_manifold(e) && !BM_edge_is_boundary(e)) { + /* can edges with at least once face user */ + MEM_freeN(sld); + return false; + } + } + } + + sv_table = MEM_mallocN(sizeof(*sv_table) * bm->totvert, __func__); + +#define INDEX_UNSET -1 +#define INDEX_INVALID -2 + + { + int j = 0; + BM_ITER_MESH_INDEX (v, &iter, bm, BM_VERTS_OF_MESH, i) { + if (BM_elem_flag_test(v, BM_ELEM_SELECT)) { + BM_elem_flag_enable(v, BM_ELEM_TAG); + sv_table[i] = INDEX_UNSET; + j += 1; + } + else { + BM_elem_flag_disable(v, BM_ELEM_TAG); + sv_table[i] = INDEX_INVALID; + } + BM_elem_index_set(v, i); /* set_inline */ + } + bm->elem_index_dirty &= ~BM_VERT; + + if (!j) { + MEM_freeN(sld); + MEM_freeN(sv_table); + return false; + } + sv_tot = j; + } + + sv_array = MEM_callocN(sizeof(TransDataEdgeSlideVert) * sv_tot, "sv_array"); + loop_nr = 0; + + STACK_DECLARE(sv_array); + STACK_INIT(sv_array, sv_tot); + + while (1) { + float vec_a[3], vec_b[3]; + BMLoop *l_a, *l_b; + BMLoop *l_a_prev, *l_b_prev; + BMVert *v_first; + /* If this succeeds call get_next_loop() + * which calculates the direction to slide based on clever checks. + * + * otherwise we simply use 'e_dir' as an edge-rail. + * (which is better when the attached edge is a boundary, see: T40422) + */ +#define EDGESLIDE_VERT_IS_INNER(v, e_dir) \ + ((BM_edge_is_boundary(e_dir) == false) && (BM_vert_edge_count_nonwire(v) == 2)) + + v = NULL; + BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) { + if (BM_elem_flag_test(v, BM_ELEM_TAG)) { + break; + } + } + + if (!v) { + break; + } + + if (!v->e) { + continue; + } + + v_first = v; + + /*walk along the edge loop*/ + e = v->e; + + /*first, rewind*/ + do { + e = get_other_edge(v, e); + if (!e) { + e = v->e; + break; + } + + if (!BM_elem_flag_test(BM_edge_other_vert(e, v), BM_ELEM_TAG)) { + break; + } + + v = BM_edge_other_vert(e, v); + } while (e != v_first->e); + + BM_elem_flag_disable(v, BM_ELEM_TAG); + + l_a = e->l; + l_b = e->l->radial_next; + + /* regarding e_next, use get_next_loop()'s improved interpolation where possible */ + { + BMEdge *e_next = get_other_edge(v, e); + if (e_next) { + get_next_loop(v, l_a, e, e_next, vec_a); + } + else { + BMLoop *l_tmp = BM_loop_other_edge_loop(l_a, v); + if (EDGESLIDE_VERT_IS_INNER(v, l_tmp->e)) { + get_next_loop(v, l_a, e, l_tmp->e, vec_a); + } + else { + sub_v3_v3v3(vec_a, BM_edge_other_vert(l_tmp->e, v)->co, v->co); + } + } + } + + /* !BM_edge_is_boundary(e); */ + if (l_b != l_a) { + BMEdge *e_next = get_other_edge(v, e); + if (e_next) { + get_next_loop(v, l_b, e, e_next, vec_b); + } + else { + BMLoop *l_tmp = BM_loop_other_edge_loop(l_b, v); + if (EDGESLIDE_VERT_IS_INNER(v, l_tmp->e)) { + get_next_loop(v, l_b, e, l_tmp->e, vec_b); + } + else { + sub_v3_v3v3(vec_b, BM_edge_other_vert(l_tmp->e, v)->co, v->co); + } + } + } + else { + l_b = NULL; + } + + l_a_prev = NULL; + l_b_prev = NULL; + +#define SV_FROM_VERT(v) \ + ((sv_table[BM_elem_index_get(v)] == INDEX_UNSET) ? \ + ((void)(sv_table[BM_elem_index_get(v)] = STACK_SIZE(sv_array)), \ + STACK_PUSH_RET_PTR(sv_array)) : \ + (&sv_array[sv_table[BM_elem_index_get(v)]])) + + /*iterate over the loop*/ + v_first = v; + do { + bool l_a_ok_prev; + bool l_b_ok_prev; + TransDataEdgeSlideVert *sv; + BMVert *v_prev; + BMEdge *e_prev; + + /* XXX, 'sv' will initialize multiple times, this is suspicious. see [#34024] */ + BLI_assert(v != NULL); + BLI_assert(sv_table[BM_elem_index_get(v)] != INDEX_INVALID); + sv = SV_FROM_VERT(v); + sv->v = v; + copy_v3_v3(sv->v_co_orig, v->co); + sv->loop_nr = loop_nr; + + if (l_a || l_a_prev) { + BMLoop *l_tmp = BM_loop_other_edge_loop(l_a ? l_a : l_a_prev, v); + 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_side[1] = BM_edge_other_vert(l_tmp->e, v); + copy_v3_v3(sv->dir_side[1], vec_b); + } + + v_prev = v; + v = BM_edge_other_vert(e, v); + + e_prev = e; + e = get_other_edge(v, e); + + if (!e) { + BLI_assert(v != NULL); + + BLI_assert(sv_table[BM_elem_index_get(v)] != INDEX_INVALID); + sv = SV_FROM_VERT(v); + + sv->v = v; + copy_v3_v3(sv->v_co_orig, v->co); + sv->loop_nr = loop_nr; + + if (l_a) { + BMLoop *l_tmp = BM_loop_other_edge_loop(l_a, 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_side[0]); + } + else { + 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_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_side[1]); + } + else { + sub_v3_v3v3(sv->dir_side[1], sv->v_side[1]->co, v->co); + } + } + + BM_elem_flag_disable(v, BM_ELEM_TAG); + BM_elem_flag_disable(v_prev, BM_ELEM_TAG); + + break; + } + l_a_ok_prev = (l_a != NULL); + l_b_ok_prev = (l_b != NULL); + + l_a_prev = l_a; + l_b_prev = l_b; + + if (l_a) { + l_a = get_next_loop(v, l_a, e_prev, e, vec_a); + } + else { + zero_v3(vec_a); + } + + if (l_b) { + l_b = get_next_loop(v, l_b, e_prev, e, vec_b); + } + else { + zero_v3(vec_b); + } + + if (l_a && l_b) { + /* pass */ + } + else { + if (l_a || l_b) { + /* find the opposite loop if it was missing previously */ + if (l_a == NULL && l_b && (l_b->radial_next != l_b)) { + l_a = l_b->radial_next; + } + else if (l_b == NULL && l_a && (l_a->radial_next != l_a)) { + l_b = l_a->radial_next; + } + } + else if (e->l != NULL) { + /* if there are non-contiguous faces, we can still recover + * the loops of the new edges faces */ + + /* note!, the behavior in this case means edges may move in opposite directions, + * this could be made to work more usefully. */ + + if (l_a_ok_prev) { + l_a = e->l; + l_b = (l_a->radial_next != l_a) ? l_a->radial_next : NULL; + } + else if (l_b_ok_prev) { + l_b = e->l; + l_a = (l_b->radial_next != l_b) ? l_b->radial_next : NULL; + } + } + + if (!l_a_ok_prev && l_a) { + get_next_loop(v, l_a, e, e_prev, vec_a); + } + if (!l_b_ok_prev && l_b) { + get_next_loop(v, l_b, e, e_prev, vec_b); + } + } + + BM_elem_flag_disable(v, BM_ELEM_TAG); + BM_elem_flag_disable(v_prev, BM_ELEM_TAG); + } while ((e != v_first->e) && (l_a || l_b)); + +#undef SV_FROM_VERT +#undef INDEX_UNSET +#undef INDEX_INVALID + + loop_nr++; + +#undef EDGESLIDE_VERT_IS_INNER + } + + /* EDBM_flag_disable_all(em, BM_ELEM_SELECT); */ + + BLI_assert(STACK_SIZE(sv_array) == sv_tot); + + sld->sv = sv_array; + sld->totsv = sv_tot; + + /* use for visibility checks */ + if (t->spacetype == SPACE_VIEW3D) { + v3d = t->area ? t->area->spacedata.first : NULL; + rv3d = t->region ? t->region->regiondata : NULL; + use_occlude_geometry = (v3d && TRANS_DATA_CONTAINER_FIRST_OK(t)->obedit->dt > OB_WIRE && + !XRAY_ENABLED(v3d)); + } + + calcEdgeSlide_mval_range(t, tc, sld, sv_table, loop_nr, mval, use_occlude_geometry, true); + + if (rv3d) { + calcEdgeSlide_even(t, tc, sld, mval); + } + + tc->custom.mode.data = sld; + + MEM_freeN(sv_table); + + return true; +} + +/** + * A simple version of #createEdgeSlideVerts_double_side + * Which assumes the longest unselected. + */ +static bool createEdgeSlideVerts_single_side(TransInfo *t, TransDataContainer *tc) +{ + BMEditMesh *em = BKE_editmesh_from_object(tc->obedit); + BMesh *bm = em->bm; + BMIter iter; + BMEdge *e; + 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 loop_nr; + bool use_occlude_geometry = false; + View3D *v3d = NULL; + RegionView3D *rv3d = NULL; + + if (t->spacetype == SPACE_VIEW3D) { + /* background mode support */ + v3d = t->area ? t->area->spacedata.first : NULL; + rv3d = t->region ? t->region->regiondata : NULL; + } + + sld->curr_sv_index = 0; + /* ensure valid selection */ + { + int i = 0, j = 0; + BMVert *v; + + 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; + } + } + } + + if (len_sq_max != -1.0f) { + j++; + } + } + BM_elem_index_set(v, i); /* set_inline */ + } + bm->elem_index_dirty &= ~BM_VERT; + + if (!j) { + MEM_freeN(sld); + 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__); + + { + int i = 0, j = 0; + BMVert *v; + + 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; + + for (int 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; + int j; + + 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 { + 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; + } + } + + 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); + } + } + } + } + } + + /* 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->area ? t->area->spacedata.first : NULL; + rv3d = t->region ? t->region->regiondata : NULL; + use_occlude_geometry = (v3d && TRANS_DATA_CONTAINER_FIRST_OK(t)->obedit->dt > OB_WIRE && + !XRAY_ENABLED(v3d)); + } + + calcEdgeSlide_mval_range(t, tc, sld, sv_table, loop_nr, mval, use_occlude_geometry, false); + + if (rv3d) { + calcEdgeSlide_even(t, tc, sld, mval); + } + + tc->custom.mode.data = sld; + + MEM_freeN(sv_table); + + return true; +} + +void projectEdgeSlideData(TransInfo *t, bool is_final) +{ + FOREACH_TRANS_DATA_CONTAINER (t, tc) { + EdgeSlideData *sld = tc->custom.mode.data; + + if (sld == NULL) { + continue; + } + + trans_mesh_customdata_correction_apply(tc, is_final); + } +} + +static void freeEdgeSlideVerts(TransInfo *UNUSED(t), + TransDataContainer *UNUSED(tc), + TransCustomData *custom_data) +{ + EdgeSlideData *sld = custom_data->data; + + if (sld == NULL) { + return; + } + + MEM_freeN(sld->sv); + MEM_freeN(sld); + + custom_data->data = NULL; +} + +static eRedrawFlag handleEventEdgeSlide(struct TransInfo *t, const struct wmEvent *event) +{ + if (t->mode == TFM_EDGE_SLIDE) { + EdgeSlideParams *slp = t->custom.mode.data; + + if (slp) { + switch (event->type) { + case EVT_EKEY: + if (event->val == KM_PRESS) { + slp->use_even = !slp->use_even; + calcEdgeSlideCustomPoints(t); + return TREDRAW_HARD; + } + break; + case EVT_FKEY: + if (event->val == KM_PRESS) { + slp->flipped = !slp->flipped; + calcEdgeSlideCustomPoints(t); + return TREDRAW_HARD; + } + break; + case EVT_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: +#if 0 + switch (event->val) { + case TFM_MODAL_EDGESLIDE_DOWN: + sld->curr_sv_index = ((sld->curr_sv_index - 1) + sld->totsv) % sld->totsv; + return TREDRAW_HARD; + case TFM_MODAL_EDGESLIDE_UP: + sld->curr_sv_index = (sld->curr_sv_index + 1) % sld->totsv; + return TREDRAW_HARD; + } +#endif + break; + case MOUSEMOVE: + calcEdgeSlideCustomPoints(t); + break; + default: + break; + } + } + } + return TREDRAW_NOTHING; +} + +void drawEdgeSlide(TransInfo *t) +{ + if ((t->mode == TFM_EDGE_SLIDE) && edgeSlideFirstGet(t)) { + const EdgeSlideParams *slp = t->custom.mode.data; + EdgeSlideData *sld = edgeSlideFirstGet(t); + const bool is_clamp = !(t->flag & T_ALT_TRANSFORM); + + /* Even mode */ + if ((slp->use_even == true) || (is_clamp == false)) { + const float line_size = UI_GetThemeValuef(TH_OUTLINE_WIDTH) + 0.5f; + + GPU_depth_test(false); + + GPU_blend(true); + GPU_blend_set_func_separate( + GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA); + + GPU_matrix_push(); + GPU_matrix_mul(TRANS_DATA_CONTAINER_FIRST_OK(t)->obedit->obmat); + + uint pos = GPU_vertformat_attr_add( + immVertexFormat(), "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT); + + immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR); + + if (slp->use_even == true) { + float co_a[3], co_b[3], co_mark[3]; + TransDataEdgeSlideVert *curr_sv = &sld->sv[sld->curr_sv_index]; + const float fac = (slp->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]); + + GPU_line_width(line_size); + immUniformThemeColorShadeAlpha(TH_EDGE_SELECT, 80, alpha_shade); + immBeginAtMost(GPU_PRIM_LINES, 4); + if (curr_sv->v_side[0]) { + immVertex3fv(pos, curr_sv->v_side[0]->co); + immVertex3fv(pos, curr_sv->v_co_orig); + } + if (curr_sv->v_side[1]) { + immVertex3fv(pos, curr_sv->v_side[1]->co); + immVertex3fv(pos, curr_sv->v_co_orig); + } + immEnd(); + + { + float *co_test = NULL; + if (slp->flipped) { + if (curr_sv->v_side[1]) { + co_test = curr_sv->v_side[1]->co; + } + } + else { + if (curr_sv->v_side[0]) { + co_test = curr_sv->v_side[0]->co; + } + } + + if (co_test != NULL) { + immUniformThemeColorShadeAlpha(TH_SELECT, -30, alpha_shade); + GPU_point_size(ctrl_size); + immBegin(GPU_PRIM_POINTS, 1); + immVertex3fv(pos, co_test); + immEnd(); + } + } + + immUniformThemeColorShadeAlpha(TH_SELECT, 255, alpha_shade); + GPU_point_size(guide_size); + immBegin(GPU_PRIM_POINTS, 1); + interp_line_v3_v3v3v3(co_mark, co_b, curr_sv->v_co_orig, co_a, fac); + immVertex3fv(pos, co_mark); + immEnd(); + } + else { + if (is_clamp == false) { + const int side_index = sld->curr_side_unclamp; + TransDataEdgeSlideVert *sv; + int i; + const int alpha_shade = -160; + + GPU_line_width(line_size); + immUniformThemeColorShadeAlpha(TH_EDGE_SELECT, 80, alpha_shade); + immBegin(GPU_PRIM_LINES, sld->totsv * 2); + + /* TODO(campbell): Loop over all verts */ + 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]); + } + + 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); + + immVertex3fv(pos, a); + immVertex3fv(pos, b); + } + immEnd(); + } + else { + BLI_assert(0); + } + } + + immUnbindProgram(); + + GPU_matrix_pop(); + + GPU_blend(false); + + GPU_depth_test(true); + } + } +} + +void doEdgeSlide(TransInfo *t, float perc) +{ + EdgeSlideParams *slp = t->custom.mode.data; + EdgeSlideData *sld_active = edgeSlideFirstGet(t); + + slp->perc = perc; + + if (slp->use_even == false) { + 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); + FOREACH_TRANS_DATA_CONTAINER (t, tc) { + EdgeSlideData *sld = tc->custom.mode.data; + + if (sld == NULL) { + continue; + } + + TransDataEdgeSlideVert *sv = sld->sv; + for (int i = 0; i < sld->totsv; i++, sv++) { + madd_v3_v3v3fl(sv->v->co, sv->v_co_orig, sv->dir_side[side_index], perc_final); + } + sld->curr_side_unclamp = side_index; + } + } + else { + const float perc_init = fabsf(perc) * + ((sld_active->curr_side_unclamp == (perc < 0.0f)) ? 1 : -1); + const int side_index = sld_active->curr_side_unclamp; + FOREACH_TRANS_DATA_CONTAINER (t, tc) { + EdgeSlideData *sld = tc->custom.mode.data; + + if (sld == NULL) { + continue; + } + + TransDataEdgeSlideVert *sv = sld->sv; + for (int 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); + } + } + } + } + else { + /** + * Implementation note, even mode ignores the starting positions and uses + * only the 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_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_active->sv[sld_active->curr_sv_index]; + const float curr_length_perc = curr_sv->edge_len * + (((slp->flipped ? perc : -perc) + 1.0f) / 2.0f); + + float co_a[3]; + float co_b[3]; + + FOREACH_TRANS_DATA_CONTAINER (t, tc) { + EdgeSlideData *sld = tc->custom.mode.data; + + if (sld == NULL) { + continue; + } + + TransDataEdgeSlideVert *sv = sld->sv; + for (int i = 0; i < sld->totsv; i++, sv++) { + 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_side[0]); + add_v3_v3v3(co_b, sv->v_co_orig, sv->dir_side[1]); + + if (slp->flipped) { + interp_line_v3_v3v3v3(sv->v->co, co_b, sv->v_co_orig, co_a, fac); + } + else { + interp_line_v3_v3v3v3(sv->v->co, co_a, sv->v_co_orig, co_b, fac); + } + } + } + } + } +} + +static void applyEdgeSlide(TransInfo *t, const int UNUSED(mval[2])) +{ + char str[UI_MAX_DRAW_STR]; + size_t ofs = 0; + float final; + EdgeSlideParams *slp = t->custom.mode.data; + bool flipped = slp->flipped; + bool use_even = slp->use_even; + 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 */ + if (is_constrained) { + CLAMP(final, -1.0f, 1.0f); + } + + applyNumInput(&t->num, &final); + + t->values_final[0] = final; + + /* header string */ + ofs += BLI_strncpy_rlen(str + ofs, TIP_("Edge Slide: "), sizeof(str) - ofs); + if (hasNumInput(&t->num)) { + char c[NUM_STR_REP_LEN]; + outputNumInput(&(t->num), c, &t->scene->unit); + ofs += BLI_strncpy_rlen(str + ofs, &c[0], sizeof(str) - ofs); + } + else { + ofs += BLI_snprintf(str + ofs, sizeof(str) - ofs, "%.4f ", final); + } + ofs += BLI_snprintf( + str + ofs, sizeof(str) - ofs, TIP_("(E)ven: %s, "), WM_bool_as_string(use_even)); + if (use_even) { + ofs += BLI_snprintf( + str + ofs, sizeof(str) - ofs, TIP_("(F)lipped: %s, "), WM_bool_as_string(flipped)); + } + ofs += BLI_snprintf( + str + ofs, sizeof(str) - ofs, TIP_("Alt or (C)lamp: %s"), WM_bool_as_string(is_clamp)); + /* done with header string */ + + /* do stuff here */ + doEdgeSlide(t, final); + + recalcData(t); + + ED_area_status_text(t->area, str); +} + +void initEdgeSlide_ex( + TransInfo *t, bool use_double_side, bool use_even, bool flipped, bool use_clamp) +{ + EdgeSlideData *sld; + bool ok = false; + + t->mode = TFM_EDGE_SLIDE; + t->transform = applyEdgeSlide; + t->handleEvent = handleEventEdgeSlide; + + { + EdgeSlideParams *slp = MEM_callocN(sizeof(*slp), __func__); + slp->use_even = use_even; + slp->flipped = flipped; + /* happens to be best for single-sided */ + if (use_double_side == false) { + slp->flipped = !flipped; + } + slp->perc = 0.0f; + + if (!use_clamp) { + t->flag |= T_ALT_TRANSFORM; + } + + t->custom.mode.data = slp; + t->custom.mode.use_free = true; + } + + if (use_double_side) { + FOREACH_TRANS_DATA_CONTAINER (t, tc) { + ok |= createEdgeSlideVerts_double_side(t, tc); + } + } + else { + FOREACH_TRANS_DATA_CONTAINER (t, tc) { + ok |= createEdgeSlideVerts_single_side(t, tc); + } + } + + if (!ok) { + t->state = TRANS_CANCEL; + return; + } + + FOREACH_TRANS_DATA_CONTAINER (t, tc) { + sld = tc->custom.mode.data; + if (!sld) { + continue; + } + tc->custom.mode.free_cb = freeEdgeSlideVerts; + } + + trans_mesh_customdata_correction_init(t); + + /* set custom point first if you want value to be initialized by init */ + calcEdgeSlideCustomPoints(t); + initMouseInputMode(t, &t->mouse, INPUT_CUSTOM_RATIO_FLIP); + + t->idx_max = 0; + t->num.idx_max = 0; + t->snap[0] = 0.0f; + t->snap[1] = 0.1f; + t->snap[2] = t->snap[1] * 0.1f; + + copy_v3_fl(t->num.val_inc, t->snap[1]); + t->num.unit_sys = t->scene->unit.system; + t->num.unit_type[0] = B_UNIT_NONE; + + t->flag |= T_NO_CONSTRAINT | T_NO_PROJECT; +} + +void initEdgeSlide(TransInfo *t) +{ + initEdgeSlide_ex(t, true, false, false, true); +} +/** \} */ diff --git a/source/blender/editors/transform/transform_mode_gpopacity.c b/source/blender/editors/transform/transform_mode_gpopacity.c new file mode 100644 index 00000000000..267d297a31c --- /dev/null +++ b/source/blender/editors/transform/transform_mode_gpopacity.c @@ -0,0 +1,120 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + */ + +/** \file + * \ingroup edtransform + */ + +#include <stdlib.h> + +#include "BLI_math.h" +#include "BLI_string.h" + +#include "BKE_context.h" +#include "BKE_unit.h" + +#include "ED_screen.h" + +#include "UI_interface.h" + +#include "BLT_translation.h" + +#include "transform.h" +#include "transform_mode.h" +#include "transform_snap.h" + +/* -------------------------------------------------------------------- */ +/* Transform (GPencil Opacity) */ + +/** \name Transform GPencil Strokes Opacity + * \{ */ + +static void applyGPOpacity(TransInfo *t, const int UNUSED(mval[2])) +{ + float ratio; + int i; + char str[UI_MAX_DRAW_STR]; + + ratio = t->values[0]; + + snapGridIncrement(t, &ratio); + + applyNumInput(&t->num, &ratio); + + t->values_final[0] = ratio; + + /* header print for NumInput */ + if (hasNumInput(&t->num)) { + char c[NUM_STR_REP_LEN]; + + outputNumInput(&(t->num), c, &t->scene->unit); + BLI_snprintf(str, sizeof(str), TIP_("Opacity: %s"), c); + } + else { + BLI_snprintf(str, sizeof(str), TIP_("Opacity: %3f"), ratio); + } + + FOREACH_TRANS_DATA_CONTAINER (t, tc) { + TransData *td = tc->data; + for (i = 0; i < tc->data_len; i++, td++) { + if (td->flag & TD_NOACTION) { + break; + } + + if (td->flag & TD_SKIP) { + continue; + } + + if (td->val) { + *td->val = td->ival * ratio; + /* apply PET */ + *td->val = (*td->val * td->factor) + ((1.0f - td->factor) * td->ival); + CLAMP(*td->val, 0.0f, 1.0f); + } + } + } + + ED_area_status_text(t->area, str); +} + +void initGPOpacity(TransInfo *t) +{ + t->mode = TFM_GPENCIL_OPACITY; + t->transform = applyGPOpacity; + + initMouseInputMode(t, &t->mouse, INPUT_SPRING); + + t->idx_max = 0; + t->num.idx_max = 0; + t->snap[0] = 0.0f; + t->snap[1] = 0.1f; + t->snap[2] = t->snap[1] * 0.1f; + + copy_v3_fl(t->num.val_inc, t->snap[1]); + t->num.unit_sys = t->scene->unit.system; + t->num.unit_type[0] = B_UNIT_NONE; + + t->flag |= T_NO_ZERO; +#ifdef USE_NUM_NO_ZERO + t->num.val_flag[0] |= NUM_NO_ZERO; +#endif + + t->flag |= T_NO_CONSTRAINT; +} +/** \} */ diff --git a/source/blender/editors/transform/transform_mode_gpshrinkfatten.c b/source/blender/editors/transform/transform_mode_gpshrinkfatten.c new file mode 100644 index 00000000000..7c49d107703 --- /dev/null +++ b/source/blender/editors/transform/transform_mode_gpshrinkfatten.c @@ -0,0 +1,122 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + */ + +/** \file + * \ingroup edtransform + */ + +#include <stdlib.h> + +#include "BLI_math.h" +#include "BLI_string.h" + +#include "BKE_context.h" +#include "BKE_unit.h" + +#include "ED_screen.h" + +#include "UI_interface.h" + +#include "BLT_translation.h" + +#include "transform.h" +#include "transform_mode.h" +#include "transform_snap.h" + +/* -------------------------------------------------------------------- */ +/* Transform (GPencil Shrink/Fatten) */ + +/** \name Transform GPencil Strokes Shrink/Fatten + * \{ */ + +static void applyGPShrinkFatten(TransInfo *t, const int UNUSED(mval[2])) +{ + float ratio; + int i; + char str[UI_MAX_DRAW_STR]; + + ratio = t->values[0]; + + snapGridIncrement(t, &ratio); + + applyNumInput(&t->num, &ratio); + + t->values_final[0] = ratio; + + /* header print for NumInput */ + if (hasNumInput(&t->num)) { + char c[NUM_STR_REP_LEN]; + + outputNumInput(&(t->num), c, &t->scene->unit); + BLI_snprintf(str, sizeof(str), TIP_("Shrink/Fatten: %s"), c); + } + else { + BLI_snprintf(str, sizeof(str), TIP_("Shrink/Fatten: %3f"), ratio); + } + + FOREACH_TRANS_DATA_CONTAINER (t, tc) { + TransData *td = tc->data; + for (i = 0; i < tc->data_len; i++, td++) { + if (td->flag & TD_NOACTION) { + break; + } + + if (td->flag & TD_SKIP) { + continue; + } + + if (td->val) { + *td->val = td->ival * ratio; + /* apply PET */ + *td->val = (*td->val * td->factor) + ((1.0f - td->factor) * td->ival); + if (*td->val <= 0.0f) { + *td->val = 0.001f; + } + } + } + } + + ED_area_status_text(t->area, str); +} + +void initGPShrinkFatten(TransInfo *t) +{ + t->mode = TFM_GPENCIL_SHRINKFATTEN; + t->transform = applyGPShrinkFatten; + + initMouseInputMode(t, &t->mouse, INPUT_SPRING); + + t->idx_max = 0; + t->num.idx_max = 0; + t->snap[0] = 0.0f; + t->snap[1] = 0.1f; + t->snap[2] = t->snap[1] * 0.1f; + + copy_v3_fl(t->num.val_inc, t->snap[1]); + t->num.unit_sys = t->scene->unit.system; + t->num.unit_type[0] = B_UNIT_NONE; + + t->flag |= T_NO_ZERO; +#ifdef USE_NUM_NO_ZERO + t->num.val_flag[0] |= NUM_NO_ZERO; +#endif + + t->flag |= T_NO_CONSTRAINT; +} +/** \} */ diff --git a/source/blender/editors/transform/transform_mode_maskshrinkfatten.c b/source/blender/editors/transform/transform_mode_maskshrinkfatten.c new file mode 100644 index 00000000000..e42439920db --- /dev/null +++ b/source/blender/editors/transform/transform_mode_maskshrinkfatten.c @@ -0,0 +1,154 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + */ + +/** \file + * \ingroup edtransform + */ + +#include <stdlib.h> + +#include "BLI_math.h" +#include "BLI_string.h" + +#include "BKE_context.h" +#include "BKE_unit.h" + +#include "ED_screen.h" + +#include "UI_interface.h" + +#include "BLT_translation.h" + +#include "transform.h" +#include "transform_mode.h" +#include "transform_snap.h" + +/* -------------------------------------------------------------------- */ +/* Transform (Mask Shrink/Fatten) */ + +/** \name Transform Mask Shrink/Fatten + * \{ */ + +static void applyMaskShrinkFatten(TransInfo *t, const int UNUSED(mval[2])) +{ + float ratio; + int i; + bool initial_feather = false; + char str[UI_MAX_DRAW_STR]; + + ratio = t->values[0]; + + snapGridIncrement(t, &ratio); + + applyNumInput(&t->num, &ratio); + + t->values_final[0] = ratio; + + /* header print for NumInput */ + if (hasNumInput(&t->num)) { + char c[NUM_STR_REP_LEN]; + + outputNumInput(&(t->num), c, &t->scene->unit); + BLI_snprintf(str, sizeof(str), TIP_("Feather Shrink/Fatten: %s"), c); + } + else { + BLI_snprintf(str, sizeof(str), TIP_("Feather Shrink/Fatten: %3f"), ratio); + } + + /* detect if no points have feather yet */ + if (ratio > 1.0f) { + initial_feather = true; + + FOREACH_TRANS_DATA_CONTAINER (t, tc) { + TransData *td = tc->data; + for (i = 0; i < tc->data_len; i++, td++) { + if (td->flag & TD_NOACTION) { + break; + } + + if (td->flag & TD_SKIP) { + continue; + } + + if (td->ival >= 0.001f) { + initial_feather = false; + } + } + } + } + + /* apply shrink/fatten */ + FOREACH_TRANS_DATA_CONTAINER (t, tc) { + TransData *td = tc->data; + for (td = tc->data, i = 0; i < tc->data_len; i++, td++) { + if (td->flag & TD_NOACTION) { + break; + } + + if (td->flag & TD_SKIP) { + continue; + } + + if (td->val) { + if (initial_feather) { + *td->val = td->ival + (ratio - 1.0f) * 0.01f; + } + else { + *td->val = td->ival * ratio; + } + + /* apply PET */ + *td->val = (*td->val * td->factor) + ((1.0f - td->factor) * td->ival); + if (*td->val <= 0.0f) { + *td->val = 0.001f; + } + } + } + } + + recalcData(t); + + ED_area_status_text(t->area, str); +} + +void initMaskShrinkFatten(TransInfo *t) +{ + t->mode = TFM_MASK_SHRINKFATTEN; + t->transform = applyMaskShrinkFatten; + + initMouseInputMode(t, &t->mouse, INPUT_SPRING); + + t->idx_max = 0; + t->num.idx_max = 0; + t->snap[0] = 0.0f; + t->snap[1] = 0.1f; + t->snap[2] = t->snap[1] * 0.1f; + + copy_v3_fl(t->num.val_inc, t->snap[1]); + t->num.unit_sys = t->scene->unit.system; + t->num.unit_type[0] = B_UNIT_NONE; + + t->flag |= T_NO_ZERO; +#ifdef USE_NUM_NO_ZERO + t->num.val_flag[0] |= NUM_NO_ZERO; +#endif + + t->flag |= T_NO_CONSTRAINT; +} +/** \} */ diff --git a/source/blender/editors/transform/transform_mode_mirror.c b/source/blender/editors/transform/transform_mode_mirror.c new file mode 100644 index 00000000000..dae17374481 --- /dev/null +++ b/source/blender/editors/transform/transform_mode_mirror.c @@ -0,0 +1,129 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + */ + +/** \file + * \ingroup edtransform + */ + +#include <stdlib.h> + +#include "BLI_math.h" +#include "BLI_string.h" + +#include "BKE_context.h" + +#include "ED_screen.h" + +#include "UI_interface.h" + +#include "BLT_translation.h" + +#include "transform.h" +#include "transform_mode.h" + +/* -------------------------------------------------------------------- */ +/* Transform (Mirror) */ + +/** \name Transform Mirror + * \{ */ + +static void applyMirror(TransInfo *t, const int UNUSED(mval[2])) +{ + float size[3], mat[3][3]; + int i; + char str[UI_MAX_DRAW_STR]; + copy_v3_v3(t->values_final, t->values); + + /* OPTIMIZATION: + * This still recalculates transformation on mouse move + * while it should only recalculate on constraint change. */ + + /* if an axis has been selected */ + if (t->con.mode & CON_APPLY) { + size[0] = size[1] = size[2] = -1; + + size_to_mat3(mat, size); + + if (t->con.applySize) { + t->con.applySize(t, NULL, NULL, mat); + } + + BLI_snprintf(str, sizeof(str), TIP_("Mirror%s"), t->con.text); + + FOREACH_TRANS_DATA_CONTAINER (t, tc) { + TransData *td = tc->data; + for (i = 0; i < tc->data_len; i++, td++) { + if (td->flag & TD_NOACTION) { + break; + } + + if (td->flag & TD_SKIP) { + continue; + } + + ElementResize(t, tc, td, mat); + } + } + + recalcData(t); + + ED_area_status_text(t->area, str); + } + else { + size[0] = size[1] = size[2] = 1; + + size_to_mat3(mat, size); + + FOREACH_TRANS_DATA_CONTAINER (t, tc) { + TransData *td = tc->data; + for (i = 0; i < tc->data_len; i++, td++) { + if (td->flag & TD_NOACTION) { + break; + } + + if (td->flag & TD_SKIP) { + continue; + } + + ElementResize(t, tc, td, mat); + } + } + + recalcData(t); + + if (t->flag & T_2D_EDIT) { + ED_area_status_text(t->area, TIP_("Select a mirror axis (X, Y)")); + } + else { + ED_area_status_text(t->area, TIP_("Select a mirror axis (X, Y, Z)")); + } + } +} + +void initMirror(TransInfo *t) +{ + t->transform = applyMirror; + initMouseInputMode(t, &t->mouse, INPUT_NONE); + + t->flag |= T_NULL_ONE; + if ((t->flag & T_EDIT) == 0) { + t->flag |= T_NO_ZERO; + } +} +/** \} */ diff --git a/source/blender/editors/transform/transform_mode_push_pull.c b/source/blender/editors/transform/transform_mode_push_pull.c new file mode 100644 index 00000000000..6eb038ea9b0 --- /dev/null +++ b/source/blender/editors/transform/transform_mode_push_pull.c @@ -0,0 +1,137 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + */ + +/** \file + * \ingroup edtransform + */ + +#include <stdlib.h> + +#include "BLI_math.h" +#include "BLI_string.h" + +#include "BKE_context.h" +#include "BKE_unit.h" + +#include "ED_screen.h" + +#include "UI_interface.h" + +#include "BLT_translation.h" + +#include "transform.h" +#include "transform_constraints.h" +#include "transform_mode.h" +#include "transform_snap.h" + +/* -------------------------------------------------------------------- */ +/* Transform (Push/Pull) */ + +/** \name Transform Push/Pull + * \{ */ + +static void applyPushPull(TransInfo *t, const int UNUSED(mval[2])) +{ + float vec[3], axis_global[3]; + float distance; + int i; + char str[UI_MAX_DRAW_STR]; + + distance = t->values[0]; + + snapGridIncrement(t, &distance); + + applyNumInput(&t->num, &distance); + + t->values_final[0] = distance; + + /* header print for NumInput */ + if (hasNumInput(&t->num)) { + char c[NUM_STR_REP_LEN]; + + outputNumInput(&(t->num), c, &t->scene->unit); + + BLI_snprintf(str, sizeof(str), TIP_("Push/Pull: %s%s %s"), c, t->con.text, t->proptext); + } + else { + /* default header print */ + BLI_snprintf( + str, sizeof(str), TIP_("Push/Pull: %.4f%s %s"), distance, t->con.text, t->proptext); + } + + if (t->con.applyRot && t->con.mode & CON_APPLY) { + t->con.applyRot(t, NULL, NULL, axis_global, NULL); + } + + FOREACH_TRANS_DATA_CONTAINER (t, tc) { + TransData *td = tc->data; + for (i = 0; i < tc->data_len; i++, td++) { + if (td->flag & TD_NOACTION) { + break; + } + + if (td->flag & TD_SKIP) { + continue; + } + + sub_v3_v3v3(vec, tc->center_local, td->center); + if (t->con.applyRot && t->con.mode & CON_APPLY) { + float axis[3]; + copy_v3_v3(axis, axis_global); + t->con.applyRot(t, tc, td, axis, NULL); + + mul_m3_v3(td->smtx, axis); + if (isLockConstraint(t)) { + float dvec[3]; + project_v3_v3v3(dvec, vec, axis); + sub_v3_v3(vec, dvec); + } + else { + project_v3_v3v3(vec, vec, axis); + } + } + normalize_v3_length(vec, distance * td->factor); + + add_v3_v3v3(td->loc, td->iloc, vec); + } + } + + recalcData(t); + + ED_area_status_text(t->area, str); +} + +void initPushPull(TransInfo *t) +{ + t->mode = TFM_PUSHPULL; + t->transform = applyPushPull; + + initMouseInputMode(t, &t->mouse, INPUT_VERTICAL_ABSOLUTE); + + t->idx_max = 0; + t->num.idx_max = 0; + t->snap[0] = 0.0f; + t->snap[1] = 1.0f; + t->snap[2] = t->snap[1] * 0.1f; + + copy_v3_fl(t->num.val_inc, t->snap[1]); + t->num.unit_sys = t->scene->unit.system; + t->num.unit_type[0] = B_UNIT_LENGTH; +} +/** \} */ diff --git a/source/blender/editors/transform/transform_mode_resize.c b/source/blender/editors/transform/transform_mode_resize.c new file mode 100644 index 00000000000..00644b9bfdc --- /dev/null +++ b/source/blender/editors/transform/transform_mode_resize.c @@ -0,0 +1,170 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + */ + +/** \file + * \ingroup edtransform + */ + +#include <stdlib.h> + +#include "BLI_math.h" + +#include "BKE_context.h" +#include "BKE_unit.h" + +#include "ED_screen.h" + +#include "UI_interface.h" + +#include "transform.h" +#include "transform_constraints.h" +#include "transform_convert.h" +#include "transform_mode.h" +#include "transform_snap.h" + +/* -------------------------------------------------------------------- */ +/* Transform (Resize) */ + +/** \name Transform Resize + * \{ */ + +static void applyResize(TransInfo *t, const int UNUSED(mval[2])) +{ + float mat[3][3]; + int i; + char str[UI_MAX_DRAW_STR]; + + if (t->flag & T_INPUT_IS_VALUES_FINAL) { + copy_v3_v3(t->values_final, t->values); + } + else { + float ratio = t->values[0]; + + copy_v3_fl(t->values_final, ratio); + + snapGridIncrement(t, t->values_final); + + if (applyNumInput(&t->num, t->values_final)) { + constraintNumInput(t, t->values_final); + } + + applySnapping(t, t->values_final); + } + + size_to_mat3(mat, t->values_final); + if (t->con.mode & CON_APPLY) { + t->con.applySize(t, NULL, NULL, mat); + + /* Only so we have re-usable value with redo. */ + float pvec[3] = {0.0f, 0.0f, 0.0f}; + int j = 0; + for (i = 0; i < 3; i++) { + if (!(t->con.mode & (CON_AXIS0 << i))) { + t->values_final[i] = 1.0f; + } + else { + pvec[j++] = t->values_final[i]; + } + } + headerResize(t, pvec, str); + } + else { + headerResize(t, t->values_final, str); + } + + copy_m3_m3(t->mat, mat); // used in gizmo + + FOREACH_TRANS_DATA_CONTAINER (t, tc) { + TransData *td = tc->data; + for (i = 0; i < tc->data_len; i++, td++) { + if (td->flag & TD_NOACTION) { + break; + } + + if (td->flag & TD_SKIP) { + continue; + } + + ElementResize(t, tc, td, mat); + } + } + + /* evil hack - redo resize if cliping needed */ + if (t->flag & T_CLIP_UV && clipUVTransform(t, t->values_final, 1)) { + size_to_mat3(mat, t->values_final); + + if (t->con.mode & CON_APPLY) { + t->con.applySize(t, NULL, NULL, mat); + } + + FOREACH_TRANS_DATA_CONTAINER (t, tc) { + TransData *td = tc->data; + for (i = 0; i < tc->data_len; i++, td++) { + ElementResize(t, tc, td, mat); + } + + /* In proportional edit it can happen that */ + /* vertices in the radius of the brush end */ + /* outside the clipping area */ + /* XXX HACK - dg */ + if (t->flag & T_PROP_EDIT_ALL) { + clipUVData(t); + } + } + } + + recalcData(t); + + ED_area_status_text(t->area, str); +} + +void initResize(TransInfo *t) +{ + t->mode = TFM_RESIZE; + t->transform = applyResize; + + initMouseInputMode(t, &t->mouse, INPUT_SPRING_FLIP); + + t->flag |= T_NULL_ONE; + t->num.val_flag[0] |= NUM_NULL_ONE; + t->num.val_flag[1] |= NUM_NULL_ONE; + t->num.val_flag[2] |= NUM_NULL_ONE; + t->num.flag |= NUM_AFFECT_ALL; + if ((t->flag & T_EDIT) == 0) { + t->flag |= T_NO_ZERO; +#ifdef USE_NUM_NO_ZERO + t->num.val_flag[0] |= NUM_NO_ZERO; + t->num.val_flag[1] |= NUM_NO_ZERO; + t->num.val_flag[2] |= NUM_NO_ZERO; +#endif + } + + t->idx_max = 2; + t->num.idx_max = 2; + t->snap[0] = 0.0f; + t->snap[1] = 0.1f; + t->snap[2] = t->snap[1] * 0.1f; + + copy_v3_fl(t->num.val_inc, t->snap[1]); + t->num.unit_sys = t->scene->unit.system; + t->num.unit_type[0] = B_UNIT_NONE; + t->num.unit_type[1] = B_UNIT_NONE; + t->num.unit_type[2] = B_UNIT_NONE; +} +/** \} */ diff --git a/source/blender/editors/transform/transform_mode_rotate.c b/source/blender/editors/transform/transform_mode_rotate.c new file mode 100644 index 00000000000..f52bfda0d14 --- /dev/null +++ b/source/blender/editors/transform/transform_mode_rotate.c @@ -0,0 +1,198 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + */ + +/** \file + * \ingroup edtransform + */ + +#include <stdlib.h> + +#include "BLI_math.h" + +#include "BKE_context.h" +#include "BKE_unit.h" + +#include "ED_screen.h" + +#include "UI_interface.h" + +#include "transform.h" +#include "transform_mode.h" +#include "transform_snap.h" + +/* -------------------------------------------------------------------- */ +/* Transform (Rotation) */ + +/** \name Transform Rotation + * \{ */ + +static float large_rotation_limit(float angle) +{ + /* Limit rotation to 1001 turns max + * (otherwise iterative handling of 'large' rotations would become too slow). */ + const float angle_max = (float)(M_PI * 2000.0); + if (fabsf(angle) > angle_max) { + const float angle_sign = angle < 0.0f ? -1.0f : 1.0f; + angle = angle_sign * (fmodf(fabsf(angle), (float)(M_PI * 2.0)) + angle_max); + } + return angle; +} + +static void applyRotationValue(TransInfo *t, + float angle, + float axis[3], + const bool is_large_rotation) +{ + float mat[3][3]; + int i; + + const float angle_sign = angle < 0.0f ? -1.0f : 1.0f; + /* We cannot use something too close to 180°, or 'continuous' rotation may fail + * due to computing error... */ + const float angle_step = angle_sign * (float)(0.9 * M_PI); + + if (is_large_rotation) { + /* Just in case, calling code should have already done that in practice + * (for UI feedback reasons). */ + angle = large_rotation_limit(angle); + } + + axis_angle_normalized_to_mat3(mat, axis, angle); + /* Counter for needed updates (when we need to update to non-default matrix, + * we also need another update on next iteration to go back to default matrix, + * hence the '2' value used here, instead of a mere boolean). */ + short do_update_matrix = 0; + + FOREACH_TRANS_DATA_CONTAINER (t, tc) { + TransData *td = tc->data; + for (i = 0; i < tc->data_len; i++, td++) { + if (td->flag & TD_NOACTION) { + break; + } + + if (td->flag & TD_SKIP) { + continue; + } + + float angle_final = angle; + if (t->con.applyRot) { + t->con.applyRot(t, tc, td, axis, NULL); + angle_final = angle * td->factor; + /* Even though final angle might be identical to orig value, + * we have to update the rotation matrix in that case... */ + do_update_matrix = 2; + } + else if (t->flag & T_PROP_EDIT) { + angle_final = angle * td->factor; + } + + /* Rotation is very likely to be above 180°, we need to do rotation by steps. + * Note that this is only needed when doing 'absolute' rotation + * (i.e. from initial rotation again, typically when using numinput). + * regular incremental rotation (from mouse/widget/...) will be called often enough, + * hence steps are small enough to be properly handled without that complicated trick. + * Note that we can only do that kind of stepped rotation if we have initial rotation values + * (and access to some actual rotation value storage). + * Otherwise, just assume it's useless (e.g. in case of mesh/UV/etc. editing). + * Also need to be in Euler rotation mode, the others never allow more than one turn anyway. + */ + if (is_large_rotation && td->ext != NULL && td->ext->rotOrder == ROT_MODE_EUL) { + copy_v3_v3(td->ext->rot, td->ext->irot); + for (float angle_progress = angle_step; fabsf(angle_progress) < fabsf(angle_final); + angle_progress += angle_step) { + axis_angle_normalized_to_mat3(mat, axis, angle_progress); + ElementRotation(t, tc, td, mat, t->around); + } + do_update_matrix = 2; + } + else if (angle_final != angle) { + do_update_matrix = 2; + } + + if (do_update_matrix > 0) { + axis_angle_normalized_to_mat3(mat, axis, angle_final); + do_update_matrix--; + } + + ElementRotation(t, tc, td, mat, t->around); + } + } +} + +static void applyRotation(TransInfo *t, const int UNUSED(mval[2])) +{ + char str[UI_MAX_DRAW_STR]; + + float final; + + final = t->values[0]; + + snapGridIncrement(t, &final); + + float axis_final[3]; + copy_v3_v3(axis_final, t->spacemtx[t->orient_axis]); + + if ((t->con.mode & CON_APPLY) && t->con.applyRot) { + t->con.applyRot(t, NULL, NULL, axis_final, NULL); + } + + applySnapping(t, &final); + + if (applyNumInput(&t->num, &final)) { + /* We have to limit the amount of turns to a reasonable number here, + * to avoid things getting *very* slow, see how applyRotationValue() handles those... */ + final = large_rotation_limit(final); + } + + t->values_final[0] = final; + + headerRotation(t, str, final); + + const bool is_large_rotation = hasNumInput(&t->num); + applyRotationValue(t, final, axis_final, is_large_rotation); + + recalcData(t); + + ED_area_status_text(t->area, str); +} + +void initRotation(TransInfo *t) +{ + t->mode = TFM_ROTATION; + t->transform = applyRotation; + + setInputPostFct(&t->mouse, postInputRotation); + initMouseInputMode(t, &t->mouse, INPUT_ANGLE); + + t->idx_max = 0; + t->num.idx_max = 0; + t->snap[0] = 0.0f; + t->snap[1] = DEG2RAD(5.0); + t->snap[2] = DEG2RAD(1.0); + + copy_v3_fl(t->num.val_inc, t->snap[2]); + t->num.unit_sys = t->scene->unit.system; + t->num.unit_use_radians = (t->scene->unit.system_rotation == USER_UNIT_ROT_RADIANS); + t->num.unit_type[0] = B_UNIT_ROTATION; + + if (t->flag & T_2D_EDIT) { + t->flag |= T_NO_CONSTRAINT; + } +} +/** \} */ diff --git a/source/blender/editors/transform/transform_mode_shear.c b/source/blender/editors/transform/transform_mode_shear.c new file mode 100644 index 00000000000..da34bf50ba3 --- /dev/null +++ b/source/blender/editors/transform/transform_mode_shear.c @@ -0,0 +1,248 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + */ + +/** \file + * \ingroup edtransform + */ + +#include <stdlib.h> + +#include "DNA_gpencil_types.h" + +#include "BLI_math.h" +#include "BLI_string.h" + +#include "BKE_context.h" +#include "BKE_unit.h" + +#include "ED_screen.h" + +#include "WM_types.h" + +#include "UI_interface.h" + +#include "BLT_translation.h" + +#include "transform.h" +#include "transform_mode.h" +#include "transform_snap.h" + +/* -------------------------------------------------------------------- */ +/* Transform (Shear) */ + +/** \name Transform Shear + * \{ */ + +static void initShear_mouseInputMode(TransInfo *t) +{ + float dir[3]; + bool dir_flip = false; + copy_v3_v3(dir, t->spacemtx[t->orient_axis_ortho]); + + /* Needed for axis aligned view gizmo. */ + if (t->orientation.types[t->orientation.index] == V3D_ORIENT_VIEW) { + if (t->orient_axis_ortho == 0) { + if (t->center2d[1] < t->mouse.imval[1]) { + dir_flip = !dir_flip; + } + } + else if (t->orient_axis_ortho == 1) { + if (t->center2d[0] < t->mouse.imval[0]) { + dir_flip = !dir_flip; + } + } + } + + /* Without this, half the gizmo handles move in the opposite direction. */ + if ((t->orient_axis_ortho + 1) % 3 != t->orient_axis) { + dir_flip = !dir_flip; + } + + if (dir_flip) { + negate_v3(dir); + } + + mul_mat3_m4_v3(t->viewmat, dir); + if (normalize_v2(dir) == 0.0f) { + dir[0] = 1.0f; + } + setCustomPointsFromDirection(t, &t->mouse, dir); + + initMouseInputMode(t, &t->mouse, INPUT_CUSTOM_RATIO); +} + +static eRedrawFlag handleEventShear(TransInfo *t, const wmEvent *event) +{ + eRedrawFlag status = TREDRAW_NOTHING; + + if (event->type == MIDDLEMOUSE && event->val == KM_PRESS) { + /* Use custom.mode.data pointer to signal Shear direction */ + do { + t->orient_axis_ortho = (t->orient_axis_ortho + 1) % 3; + } while (t->orient_axis_ortho == t->orient_axis); + + initShear_mouseInputMode(t); + + status = TREDRAW_HARD; + } + else if (event->type == EVT_XKEY && event->val == KM_PRESS) { + t->orient_axis_ortho = (t->orient_axis + 1) % 3; + initShear_mouseInputMode(t); + + status = TREDRAW_HARD; + } + else if (event->type == EVT_YKEY && event->val == KM_PRESS) { + t->orient_axis_ortho = (t->orient_axis + 2) % 3; + initShear_mouseInputMode(t); + + status = TREDRAW_HARD; + } + + return status; +} + +static void applyShear(TransInfo *t, const int UNUSED(mval[2])) +{ + float vec[3]; + float smat[3][3], tmat[3][3], totmat[3][3], axismat[3][3], axismat_inv[3][3]; + float value; + int i; + char str[UI_MAX_DRAW_STR]; + const bool is_local_center = transdata_check_local_center(t, t->around); + + value = t->values[0]; + + snapGridIncrement(t, &value); + + applyNumInput(&t->num, &value); + + t->values_final[0] = value; + + /* header print for NumInput */ + if (hasNumInput(&t->num)) { + char c[NUM_STR_REP_LEN]; + + outputNumInput(&(t->num), c, &t->scene->unit); + + BLI_snprintf(str, sizeof(str), TIP_("Shear: %s %s"), c, t->proptext); + } + else { + /* default header print */ + BLI_snprintf(str, + sizeof(str), + TIP_("Shear: %.3f %s (Press X or Y to set shear axis)"), + value, + t->proptext); + } + + unit_m3(smat); + smat[1][0] = value; + + copy_v3_v3(axismat_inv[0], t->spacemtx[t->orient_axis_ortho]); + copy_v3_v3(axismat_inv[2], t->spacemtx[t->orient_axis]); + cross_v3_v3v3(axismat_inv[1], axismat_inv[0], axismat_inv[2]); + invert_m3_m3(axismat, axismat_inv); + + mul_m3_series(totmat, axismat_inv, smat, axismat); + + FOREACH_TRANS_DATA_CONTAINER (t, tc) { + TransData *td = tc->data; + for (i = 0; i < tc->data_len; i++, td++) { + const float *center, *co; + + if (td->flag & TD_NOACTION) { + break; + } + + if (td->flag & TD_SKIP) { + continue; + } + + if (t->flag & T_EDIT) { + mul_m3_series(tmat, td->smtx, totmat, td->mtx); + } + else { + copy_m3_m3(tmat, totmat); + } + + if (is_local_center) { + center = td->center; + co = td->loc; + } + else { + center = tc->center_local; + co = td->center; + } + + sub_v3_v3v3(vec, co, center); + + mul_m3_v3(tmat, vec); + + add_v3_v3(vec, center); + sub_v3_v3(vec, co); + + if (t->options & CTX_GPENCIL_STROKES) { + /* grease pencil multiframe falloff */ + bGPDstroke *gps = (bGPDstroke *)td->extra; + if (gps != NULL) { + mul_v3_fl(vec, td->factor * gps->runtime.multi_frame_falloff); + } + else { + mul_v3_fl(vec, td->factor); + } + } + else { + mul_v3_fl(vec, td->factor); + } + + add_v3_v3v3(td->loc, td->iloc, vec); + } + } + + recalcData(t); + + ED_area_status_text(t->area, str); +} + +void initShear(TransInfo *t) +{ + t->mode = TFM_SHEAR; + t->transform = applyShear; + t->handleEvent = handleEventShear; + + if (t->orient_axis == t->orient_axis_ortho) { + t->orient_axis = 2; + t->orient_axis_ortho = 1; + } + + initShear_mouseInputMode(t); + + t->idx_max = 0; + t->num.idx_max = 0; + t->snap[0] = 0.0f; + t->snap[1] = 0.1f; + t->snap[2] = t->snap[1] * 0.1f; + + copy_v3_fl(t->num.val_inc, t->snap[1]); + t->num.unit_sys = t->scene->unit.system; + t->num.unit_type[0] = B_UNIT_NONE; /* Don't think we have any unit here? */ + + t->flag |= T_NO_CONSTRAINT; +} +/** \} */ diff --git a/source/blender/editors/transform/transform_mode_shrink_fatten.c b/source/blender/editors/transform/transform_mode_shrink_fatten.c new file mode 100644 index 00000000000..ed082e86b6d --- /dev/null +++ b/source/blender/editors/transform/transform_mode_shrink_fatten.c @@ -0,0 +1,146 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + */ + +/** \file + * \ingroup edtransform + */ + +#include <stdlib.h> + +#include "BLI_math.h" +#include "BLI_string.h" + +#include "BKE_context.h" +#include "BKE_unit.h" + +#include "ED_screen.h" + +#include "WM_api.h" + +#include "UI_interface.h" + +#include "BLT_translation.h" + +#include "transform.h" +#include "transform_mode.h" +#include "transform_snap.h" + +/* -------------------------------------------------------------------- */ +/* Transform (Shrink-Fatten) */ + +/** \name Transform Shrink-Fatten + * \{ */ + +static void applyShrinkFatten(TransInfo *t, const int UNUSED(mval[2])) +{ + float distance; + int i; + char str[UI_MAX_DRAW_STR]; + size_t ofs = 0; + + distance = -t->values[0]; + + snapGridIncrement(t, &distance); + + applyNumInput(&t->num, &distance); + + t->values_final[0] = -distance; + + /* header print for NumInput */ + ofs += BLI_strncpy_rlen(str + ofs, TIP_("Shrink/Fatten:"), sizeof(str) - ofs); + if (hasNumInput(&t->num)) { + char c[NUM_STR_REP_LEN]; + outputNumInput(&(t->num), c, &t->scene->unit); + ofs += BLI_snprintf(str + ofs, sizeof(str) - ofs, " %s", c); + } + else { + /* default header print */ + ofs += BLI_snprintf(str + ofs, sizeof(str) - ofs, " %.4f", distance); + } + + if (t->proptext[0]) { + ofs += BLI_snprintf(str + ofs, sizeof(str) - ofs, " %s", t->proptext); + } + ofs += BLI_strncpy_rlen(str + ofs, ", (", sizeof(str) - ofs); + + if (t->keymap) { + wmKeyMapItem *kmi = WM_modalkeymap_find_propvalue(t->keymap, TFM_MODAL_RESIZE); + if (kmi) { + ofs += WM_keymap_item_to_string(kmi, false, str + ofs, sizeof(str) - ofs); + } + } + BLI_snprintf(str + ofs, + sizeof(str) - ofs, + TIP_(" or Alt) Even Thickness %s"), + WM_bool_as_string((t->flag & T_ALT_TRANSFORM) != 0)); + /* done with header string */ + + FOREACH_TRANS_DATA_CONTAINER (t, tc) { + TransData *td = tc->data; + for (i = 0; i < tc->data_len; i++, td++) { + float tdistance; /* temp dist */ + if (td->flag & TD_NOACTION) { + break; + } + + if (td->flag & TD_SKIP) { + continue; + } + + /* get the final offset */ + tdistance = distance * td->factor; + if (td->ext && (t->flag & T_ALT_TRANSFORM) != 0) { + tdistance *= td->ext->isize[0]; /* shell factor */ + } + + madd_v3_v3v3fl(td->loc, td->iloc, td->axismtx[2], tdistance); + } + } + + recalcData(t); + + ED_area_status_text(t->area, str); +} + +void initShrinkFatten(TransInfo *t) +{ + // If not in mesh edit mode, fallback to Resize + if ((t->flag & T_EDIT) == 0 || (t->obedit_type != OB_MESH)) { + initResize(t); + } + else { + t->mode = TFM_SHRINKFATTEN; + t->transform = applyShrinkFatten; + + initMouseInputMode(t, &t->mouse, INPUT_VERTICAL_ABSOLUTE); + + t->idx_max = 0; + t->num.idx_max = 0; + t->snap[0] = 0.0f; + t->snap[1] = 1.0f; + t->snap[2] = t->snap[1] * 0.1f; + + copy_v3_fl(t->num.val_inc, t->snap[1]); + t->num.unit_sys = t->scene->unit.system; + t->num.unit_type[0] = B_UNIT_LENGTH; + + t->flag |= T_NO_CONSTRAINT; + } +} +/** \} */ diff --git a/source/blender/editors/transform/transform_mode_skin_resize.c b/source/blender/editors/transform/transform_mode_skin_resize.c new file mode 100644 index 00000000000..b53dbb55c62 --- /dev/null +++ b/source/blender/editors/transform/transform_mode_skin_resize.c @@ -0,0 +1,141 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + */ + +/** \file + * \ingroup edtransform + */ + +#include <stdlib.h> + +#include "BLI_math.h" + +#include "BKE_context.h" +#include "BKE_unit.h" + +#include "ED_screen.h" + +#include "UI_interface.h" + +#include "transform.h" +#include "transform_constraints.h" +#include "transform_mode.h" +#include "transform_snap.h" + +/* -------------------------------------------------------------------- */ +/* Transform (Skin) */ + +/** \name Transform Skin + * \{ */ + +static void applySkinResize(TransInfo *t, const int UNUSED(mval[2])) +{ + float mat[3][3]; + int i; + char str[UI_MAX_DRAW_STR]; + + if (t->flag & T_INPUT_IS_VALUES_FINAL) { + copy_v3_v3(t->values_final, t->values); + } + else { + copy_v3_fl(t->values_final, t->values[0]); + + snapGridIncrement(t, t->values_final); + + if (applyNumInput(&t->num, t->values_final)) { + constraintNumInput(t, t->values_final); + } + + applySnapping(t, t->values_final); + } + + size_to_mat3(mat, t->values_final); + + headerResize(t, t->values_final, str); + + FOREACH_TRANS_DATA_CONTAINER (t, tc) { + TransData *td = tc->data; + for (i = 0; i < tc->data_len; i++, td++) { + float tmat[3][3], smat[3][3]; + float fsize[3]; + + if (td->flag & TD_NOACTION) { + break; + } + + if (td->flag & TD_SKIP) { + continue; + } + + if (t->flag & T_EDIT) { + mul_m3_m3m3(smat, mat, td->mtx); + mul_m3_m3m3(tmat, td->smtx, smat); + } + else { + copy_m3_m3(tmat, mat); + } + + if (t->con.applySize) { + t->con.applySize(t, NULL, NULL, tmat); + } + + mat3_to_size(fsize, tmat); + td->val[0] = td->ext->isize[0] * (1 + (fsize[0] - 1) * td->factor); + td->val[1] = td->ext->isize[1] * (1 + (fsize[1] - 1) * td->factor); + } + } + + recalcData(t); + + ED_area_status_text(t->area, str); +} + +void initSkinResize(TransInfo *t) +{ + t->mode = TFM_SKIN_RESIZE; + t->transform = applySkinResize; + + initMouseInputMode(t, &t->mouse, INPUT_SPRING_FLIP); + + t->flag |= T_NULL_ONE; + t->num.val_flag[0] |= NUM_NULL_ONE; + t->num.val_flag[1] |= NUM_NULL_ONE; + t->num.val_flag[2] |= NUM_NULL_ONE; + t->num.flag |= NUM_AFFECT_ALL; + if ((t->flag & T_EDIT) == 0) { + t->flag |= T_NO_ZERO; +#ifdef USE_NUM_NO_ZERO + t->num.val_flag[0] |= NUM_NO_ZERO; + t->num.val_flag[1] |= NUM_NO_ZERO; + t->num.val_flag[2] |= NUM_NO_ZERO; +#endif + } + + t->idx_max = 2; + t->num.idx_max = 2; + t->snap[0] = 0.0f; + t->snap[1] = 0.1f; + t->snap[2] = t->snap[1] * 0.1f; + + copy_v3_fl(t->num.val_inc, t->snap[1]); + t->num.unit_sys = t->scene->unit.system; + t->num.unit_type[0] = B_UNIT_NONE; + t->num.unit_type[1] = B_UNIT_NONE; + t->num.unit_type[2] = B_UNIT_NONE; +} +/** \} */ diff --git a/source/blender/editors/transform/transform_mode_tilt.c b/source/blender/editors/transform/transform_mode_tilt.c new file mode 100644 index 00000000000..2f56f4bd162 --- /dev/null +++ b/source/blender/editors/transform/transform_mode_tilt.c @@ -0,0 +1,119 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + */ + +/** \file + * \ingroup edtransform + */ + +#include <stdlib.h> + +#include "BLI_math.h" +#include "BLI_string.h" + +#include "BKE_context.h" +#include "BKE_unit.h" + +#include "ED_screen.h" + +#include "UI_interface.h" + +#include "BLT_translation.h" + +#include "transform.h" +#include "transform_mode.h" +#include "transform_snap.h" + +/* -------------------------------------------------------------------- */ +/* Transform (Tilt) */ + +/** \name Transform Tilt + * \{ */ + +static void applyTilt(TransInfo *t, const int UNUSED(mval[2])) +{ + int i; + char str[UI_MAX_DRAW_STR]; + + float final; + + final = t->values[0]; + + snapGridIncrement(t, &final); + + applyNumInput(&t->num, &final); + + t->values_final[0] = final; + + if (hasNumInput(&t->num)) { + char c[NUM_STR_REP_LEN]; + + outputNumInput(&(t->num), c, &t->scene->unit); + + BLI_snprintf(str, sizeof(str), TIP_("Tilt: %s° %s"), &c[0], t->proptext); + + /* XXX For some reason, this seems needed for this op, else RNA prop is not updated... :/ */ + t->values_final[0] = final; + } + else { + BLI_snprintf(str, sizeof(str), TIP_("Tilt: %.2f° %s"), RAD2DEGF(final), t->proptext); + } + + FOREACH_TRANS_DATA_CONTAINER (t, tc) { + TransData *td = tc->data; + for (i = 0; i < tc->data_len; i++, td++) { + if (td->flag & TD_NOACTION) { + break; + } + + if (td->flag & TD_SKIP) { + continue; + } + + if (td->val) { + *td->val = td->ival + final * td->factor; + } + } + } + + recalcData(t); + + ED_area_status_text(t->area, str); +} + +void initTilt(TransInfo *t) +{ + t->mode = TFM_TILT; + t->transform = applyTilt; + + initMouseInputMode(t, &t->mouse, INPUT_ANGLE); + + t->idx_max = 0; + t->num.idx_max = 0; + t->snap[0] = 0.0f; + t->snap[1] = DEG2RAD(5.0); + t->snap[2] = DEG2RAD(1.0); + + copy_v3_fl(t->num.val_inc, t->snap[2]); + t->num.unit_sys = t->scene->unit.system; + t->num.unit_use_radians = (t->scene->unit.system_rotation == USER_UNIT_ROT_RADIANS); + t->num.unit_type[0] = B_UNIT_ROTATION; + + t->flag |= T_NO_CONSTRAINT | T_NO_PROJECT; +} +/** \} */ diff --git a/source/blender/editors/transform/transform_mode_timescale.c b/source/blender/editors/transform/transform_mode_timescale.c new file mode 100644 index 00000000000..ce46cc36276 --- /dev/null +++ b/source/blender/editors/transform/transform_mode_timescale.c @@ -0,0 +1,158 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + */ + +/** \file + * \ingroup edtransform + */ + +#include <stdlib.h> + +#include "DNA_anim_types.h" + +#include "BLI_math.h" +#include "BLI_string.h" + +#include "BKE_context.h" +#include "BKE_nla.h" +#include "BKE_unit.h" + +#include "ED_screen.h" + +#include "UI_interface.h" + +#include "BLT_translation.h" + +#include "transform.h" +#include "transform_mode.h" + +/* -------------------------------------------------------------------- */ +/* Transform (Animation Time Scale) */ + +/** \name Transform Animation Time Scale + * \{ */ + +static void headerTimeScale(TransInfo *t, char str[UI_MAX_DRAW_STR]) +{ + char tvec[NUM_STR_REP_LEN * 3]; + + if (hasNumInput(&t->num)) { + outputNumInput(&(t->num), tvec, &t->scene->unit); + } + else { + BLI_snprintf(&tvec[0], NUM_STR_REP_LEN, "%.4f", t->values_final[0]); + } + + BLI_snprintf(str, UI_MAX_DRAW_STR, TIP_("ScaleX: %s"), &tvec[0]); +} + +static void applyTimeScaleValue(TransInfo *t, float value) +{ + Scene *scene = t->scene; + const short autosnap = getAnimEdit_SnapMode(t); + + FOREACH_TRANS_DATA_CONTAINER (t, tc) { + TransData *td = tc->data; + TransData2D *td2d = tc->data_2d; + for (int i = 0; i < tc->data_len; i++, td++, td2d++) { + /* it is assumed that td->extra is a pointer to the AnimData, + * whose active action is where this keyframe comes from + * (this is only valid when not in NLA) + */ + AnimData *adt = (t->spacetype != SPACE_NLA) ? td->extra : NULL; + float startx = CFRA; + float fac = value; + + /* take proportional editing into account */ + fac = ((fac - 1.0f) * td->factor) + 1; + + /* check if any need to apply nla-mapping */ + if (adt) { + startx = BKE_nla_tweakedit_remap(adt, startx, NLATIME_CONVERT_UNMAP); + } + + /* now, calculate the new value */ + *(td->val) = ((td->ival - startx) * fac) + startx; + + /* apply nearest snapping */ + doAnimEdit_SnapFrame(t, td, td2d, adt, autosnap); + } + } +} + +static void applyTimeScale(TransInfo *t, const int UNUSED(mval[2])) +{ + char str[UI_MAX_DRAW_STR]; + + /* handle numeric-input stuff */ + t->vec[0] = t->values[0]; + applyNumInput(&t->num, &t->vec[0]); + t->values_final[0] = t->vec[0]; + headerTimeScale(t, str); + + applyTimeScaleValue(t, t->values_final[0]); + + recalcData(t); + + ED_area_status_text(t->area, str); +} + +void initTimeScale(TransInfo *t) +{ + float center[2]; + + /* this tool is only really available in the Action Editor + * AND NLA Editor (for strip scaling) + */ + if (ELEM(t->spacetype, SPACE_ACTION, SPACE_NLA) == 0) { + t->state = TRANS_CANCEL; + } + + t->mode = TFM_TIME_SCALE; + t->transform = applyTimeScale; + + /* recalculate center2d to use CFRA and mouse Y, since that's + * what is used in time scale */ + if ((t->flag & T_OVERRIDE_CENTER) == 0) { + t->center_global[0] = t->scene->r.cfra; + projectFloatView(t, t->center_global, center); + center[1] = t->mouse.imval[1]; + } + + /* force a reinit with the center2d used here */ + initMouseInput(t, &t->mouse, center, t->mouse.imval, false); + + initMouseInputMode(t, &t->mouse, INPUT_SPRING_FLIP); + + t->flag |= T_NULL_ONE; + t->num.val_flag[0] |= NUM_NULL_ONE; + + /* num-input has max of (n-1) */ + t->idx_max = 0; + t->num.flag = 0; + t->num.idx_max = t->idx_max; + + /* initialize snap like for everything else */ + t->snap[0] = 0.0f; + t->snap[1] = t->snap[2] = 1.0f; + + copy_v3_fl(t->num.val_inc, t->snap[1]); + t->num.unit_sys = t->scene->unit.system; + t->num.unit_type[0] = B_UNIT_NONE; +} +/** \} */ diff --git a/source/blender/editors/transform/transform_mode_timeslide.c b/source/blender/editors/transform/transform_mode_timeslide.c new file mode 100644 index 00000000000..43e14a26930 --- /dev/null +++ b/source/blender/editors/transform/transform_mode_timeslide.c @@ -0,0 +1,236 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + */ + +/** \file + * \ingroup edtransform + */ + +#include <stdlib.h> + +#include "MEM_guardedalloc.h" + +#include "DNA_anim_types.h" + +#include "BLI_math.h" +#include "BLI_string.h" + +#include "BKE_context.h" +#include "BKE_nla.h" +#include "BKE_unit.h" + +#include "ED_screen.h" + +#include "UI_interface.h" +#include "UI_view2d.h" + +#include "BLT_translation.h" + +#include "transform.h" +#include "transform_mode.h" + +/* -------------------------------------------------------------------- */ +/* Transform (Animation Time Slide) */ + +/** \name Transform Animation Time Slide + * \{ */ + +static void headerTimeSlide(TransInfo *t, const float sval, char str[UI_MAX_DRAW_STR]) +{ + char tvec[NUM_STR_REP_LEN * 3]; + + if (hasNumInput(&t->num)) { + outputNumInput(&(t->num), tvec, &t->scene->unit); + } + else { + const float *range = t->custom.mode.data; + float minx = range[0]; + float maxx = range[1]; + float cval = t->values_final[0]; + float val; + + val = 2.0f * (cval - sval) / (maxx - minx); + CLAMP(val, -1.0f, 1.0f); + + BLI_snprintf(&tvec[0], NUM_STR_REP_LEN, "%.4f", val); + } + + BLI_snprintf(str, UI_MAX_DRAW_STR, TIP_("TimeSlide: %s"), &tvec[0]); +} + +static void applyTimeSlideValue(TransInfo *t, float sval, float cval) +{ + int i; + const float *range = t->custom.mode.data; + float minx = range[0]; + float maxx = range[1]; + + /* set value for drawing black line */ + if (t->spacetype == SPACE_ACTION) { + SpaceAction *saction = (SpaceAction *)t->area->spacedata.first; + saction->timeslide = cval; + } + + /* It doesn't matter whether we apply to t->data or + * t->data2d, but t->data2d is more convenient. */ + FOREACH_TRANS_DATA_CONTAINER (t, tc) { + TransData *td = tc->data; + for (i = 0; i < tc->data_len; i++, td++) { + /* it is assumed that td->extra is a pointer to the AnimData, + * whose active action is where this keyframe comes from + * (this is only valid when not in NLA) + */ + AnimData *adt = (t->spacetype != SPACE_NLA) ? td->extra : NULL; + + /* only apply to data if in range */ + if ((sval > minx) && (sval < maxx)) { + float cvalc = CLAMPIS(cval, minx, maxx); + float ival = td->ival; + float timefac; + + /* NLA mapping magic here works as follows: + * - "ival" goes from strip time to global time + * - calculation is performed into td->val in global time + * (since sval and min/max are all in global time) + * - "td->val" then gets put back into strip time + */ + if (adt) { + /* strip to global */ + ival = BKE_nla_tweakedit_remap(adt, ival, NLATIME_CONVERT_MAP); + } + + /* left half? */ + if (ival < sval) { + timefac = (sval - ival) / (sval - minx); + *(td->val) = cvalc - timefac * (cvalc - minx); + } + else { + timefac = (ival - sval) / (maxx - sval); + *(td->val) = cvalc + timefac * (maxx - cvalc); + } + + if (adt) { + /* global to strip */ + *(td->val) = BKE_nla_tweakedit_remap(adt, *(td->val), NLATIME_CONVERT_UNMAP); + } + } + } + } +} + +static void applyTimeSlide(TransInfo *t, const int mval[2]) +{ + View2D *v2d = (View2D *)t->view; + float cval[2], sval[2]; + const float *range = t->custom.mode.data; + float minx = range[0]; + float maxx = range[1]; + char str[UI_MAX_DRAW_STR]; + + /* calculate mouse co-ordinates */ + UI_view2d_region_to_view(v2d, mval[0], mval[1], &cval[0], &cval[1]); + UI_view2d_region_to_view(v2d, t->mouse.imval[0], t->mouse.imval[1], &sval[0], &sval[1]); + + /* t->values_final[0] stores cval[0], which is the current mouse-pointer location (in frames) */ + // XXX Need to be able to repeat this + /* t->values_final[0] = cval[0]; */ /* UNUSED (reset again later). */ + + /* handle numeric-input stuff */ + t->vec[0] = 2.0f * (cval[0] - sval[0]) / (maxx - minx); + applyNumInput(&t->num, &t->vec[0]); + t->values_final[0] = (maxx - minx) * t->vec[0] / 2.0f + sval[0]; + + headerTimeSlide(t, sval[0], str); + applyTimeSlideValue(t, sval[0], t->values_final[0]); + + recalcData(t); + + ED_area_status_text(t->area, str); +} + +void initTimeSlide(TransInfo *t) +{ + /* this tool is only really available in the Action Editor... */ + if (t->spacetype == SPACE_ACTION) { + SpaceAction *saction = (SpaceAction *)t->area->spacedata.first; + + /* set flag for drawing stuff */ + saction->flag |= SACTION_MOVING; + } + else { + t->state = TRANS_CANCEL; + } + + t->mode = TFM_TIME_SLIDE; + t->transform = applyTimeSlide; + + initMouseInputMode(t, &t->mouse, INPUT_NONE); + + { + Scene *scene = t->scene; + float *range; + t->custom.mode.data = range = MEM_mallocN(sizeof(float[2]), "TimeSlide Min/Max"); + t->custom.mode.use_free = true; + + float min = 999999999.0f, max = -999999999.0f; + int i; + FOREACH_TRANS_DATA_CONTAINER (t, tc) { + TransData *td = tc->data; + for (i = 0; i < tc->data_len; i++, td++) { + AnimData *adt = (t->spacetype != SPACE_NLA) ? td->extra : NULL; + float val = *(td->val); + + /* strip/action time to global (mapped) time */ + if (adt) { + val = BKE_nla_tweakedit_remap(adt, val, NLATIME_CONVERT_MAP); + } + + if (min > val) { + min = val; + } + if (max < val) { + max = val; + } + } + } + + if (min == max) { + /* just use the current frame ranges */ + min = (float)PSFRA; + max = (float)PEFRA; + } + + range[0] = min; + range[1] = max; + } + + /* num-input has max of (n-1) */ + t->idx_max = 0; + t->num.flag = 0; + t->num.idx_max = t->idx_max; + + /* initialize snap like for everything else */ + t->snap[0] = 0.0f; + t->snap[1] = t->snap[2] = 1.0f; + + copy_v3_fl(t->num.val_inc, t->snap[1]); + t->num.unit_sys = t->scene->unit.system; + /* No time unit supporting frames currently... */ + t->num.unit_type[0] = B_UNIT_NONE; +} +/** \} */ diff --git a/source/blender/editors/transform/transform_mode_timetranslate.c b/source/blender/editors/transform/transform_mode_timetranslate.c new file mode 100644 index 00000000000..c514df497bc --- /dev/null +++ b/source/blender/editors/transform/transform_mode_timetranslate.c @@ -0,0 +1,167 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + */ + +/** \file + * \ingroup edtransform + */ + +#include <stdlib.h> + +#include "DNA_anim_types.h" + +#include "BLI_math.h" +#include "BLI_string.h" + +#include "BKE_context.h" +#include "BKE_nla.h" +#include "BKE_unit.h" + +#include "ED_screen.h" + +#include "UI_interface.h" +#include "UI_view2d.h" + +#include "BLT_translation.h" + +#include "transform.h" +#include "transform_mode.h" +#include "transform_snap.h" + +/* -------------------------------------------------------------------- */ +/* Transform (Animation Translation) */ + +/** \name Transform Animation Translation + * \{ */ + +static void headerTimeTranslate(TransInfo *t, char str[UI_MAX_DRAW_STR]) +{ + 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)) { + outputNumInput(&(t->num), tvec, &t->scene->unit); + } + else { + const short autosnap = getAnimEdit_SnapMode(t); + float val = t->values_final[0]; + + float snap_val; + snapFrameTransform(t, autosnap, false, val, &snap_val); + + if (autosnap == SACTSNAP_FRAME) { + BLI_snprintf(&tvec[0], NUM_STR_REP_LEN, "%.2f (%.4f)", snap_val, val); + } + else if (autosnap == SACTSNAP_SECOND) { + BLI_snprintf(&tvec[0], NUM_STR_REP_LEN, "%.2f sec (%.4f)", snap_val, val); + } + else if (autosnap == SACTSNAP_TSTEP) { + BLI_snprintf(&tvec[0], NUM_STR_REP_LEN, "%.4f sec", snap_val); + } + else { + BLI_snprintf(&tvec[0], NUM_STR_REP_LEN, "%.4f", snap_val); + } + } + + ofs += BLI_snprintf(str, UI_MAX_DRAW_STR, TIP_("DeltaX: %s"), &tvec[0]); + + if (t->flag & T_PROP_EDIT_ALL) { + ofs += BLI_snprintf( + str + ofs, UI_MAX_DRAW_STR - ofs, TIP_(" Proportional size: %.2f"), t->prop_size); + } +} + +static void applyTimeTranslateValue(TransInfo *t, const float deltax) +{ + const short autosnap = getAnimEdit_SnapMode(t); + + FOREACH_TRANS_DATA_CONTAINER (t, tc) { + TransData *td = tc->data; + TransData2D *td2d = tc->data_2d; + /* It doesn't matter whether we apply to t->data or + * t->data2d, but t->data2d is more convenient. */ + for (int i = 0; i < tc->data_len; i++, td++, td2d++) { + /* It is assumed that td->extra is a pointer to the AnimData, + * whose active action is where this keyframe comes from. + * (this is only valid when not in NLA) + * (also: masks and gpencil dont have animadata) + */ + AnimData *adt = (t->spacetype != SPACE_NLA) ? td->extra : NULL; + + /* apply nearest snapping */ + *(td->val) = td->ival + deltax * td->factor; + doAnimEdit_SnapFrame(t, td, td2d, adt, autosnap); + } + } +} + +static void applyTimeTranslate(TransInfo *t, const int mval[2]) +{ + View2D *v2d = (View2D *)t->view; + char str[UI_MAX_DRAW_STR]; + + /* calculate translation amount from mouse movement - in 'time-grid space' */ + 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->mouse.imval[0], t->mouse.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]; + } + + /* handle numeric-input stuff */ + t->vec[0] = t->values[0]; + applyNumInput(&t->num, &t->vec[0]); + t->values_final[0] = t->vec[0]; + headerTimeTranslate(t, str); + + applyTimeTranslateValue(t, t->values_final[0]); + + recalcData(t); + + ED_area_status_text(t->area, str); +} + +void initTimeTranslate(TransInfo *t) +{ + /* this tool is only really available in the Action Editor... */ + if (!ELEM(t->spacetype, SPACE_ACTION, SPACE_SEQ)) { + t->state = TRANS_CANCEL; + } + + t->transform = applyTimeTranslate; + + initMouseInputMode(t, &t->mouse, INPUT_NONE); + + /* num-input has max of (n-1) */ + t->idx_max = 0; + t->num.flag = 0; + t->num.idx_max = t->idx_max; + + /* initialize snap like for everything else */ + t->snap[0] = 0.0f; + t->snap[1] = t->snap[2] = 1.0f; + + copy_v3_fl(t->num.val_inc, t->snap[1]); + t->num.unit_sys = t->scene->unit.system; + /* No time unit supporting frames currently... */ + t->num.unit_type[0] = B_UNIT_NONE; +} +/** \} */ diff --git a/source/blender/editors/transform/transform_mode_tosphere.c b/source/blender/editors/transform/transform_mode_tosphere.c new file mode 100644 index 00000000000..841ccf41365 --- /dev/null +++ b/source/blender/editors/transform/transform_mode_tosphere.c @@ -0,0 +1,139 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + */ + +/** \file + * \ingroup edtransform + */ + +#include <stdlib.h> + +#include "BLI_math.h" +#include "BLI_string.h" + +#include "BKE_context.h" +#include "BKE_unit.h" + +#include "ED_screen.h" + +#include "UI_interface.h" + +#include "BLT_translation.h" + +#include "transform.h" +#include "transform_mode.h" +#include "transform_snap.h" + +/* -------------------------------------------------------------------- */ +/* Transform (ToSphere) */ + +/** \name Transform ToSphere + * \{ */ + +static void applyToSphere(TransInfo *t, const int UNUSED(mval[2])) +{ + float vec[3]; + float ratio, radius; + int i; + char str[UI_MAX_DRAW_STR]; + + ratio = t->values[0]; + + snapGridIncrement(t, &ratio); + + applyNumInput(&t->num, &ratio); + + CLAMP(ratio, 0.0f, 1.0f); + + t->values_final[0] = ratio; + + /* header print for NumInput */ + if (hasNumInput(&t->num)) { + char c[NUM_STR_REP_LEN]; + + outputNumInput(&(t->num), c, &t->scene->unit); + + BLI_snprintf(str, sizeof(str), TIP_("To Sphere: %s %s"), c, t->proptext); + } + else { + /* default header print */ + BLI_snprintf(str, sizeof(str), TIP_("To Sphere: %.4f %s"), ratio, t->proptext); + } + + FOREACH_TRANS_DATA_CONTAINER (t, tc) { + TransData *td = tc->data; + for (i = 0; i < tc->data_len; i++, td++) { + float tratio; + if (td->flag & TD_NOACTION) { + break; + } + + if (td->flag & TD_SKIP) { + continue; + } + + sub_v3_v3v3(vec, td->iloc, tc->center_local); + + radius = normalize_v3(vec); + + tratio = ratio * td->factor; + + mul_v3_fl(vec, radius * (1.0f - tratio) + t->val * tratio); + + add_v3_v3v3(td->loc, tc->center_local, vec); + } + } + + recalcData(t); + + ED_area_status_text(t->area, str); +} + +void initToSphere(TransInfo *t) +{ + int i; + + t->mode = TFM_TOSPHERE; + t->transform = applyToSphere; + + initMouseInputMode(t, &t->mouse, INPUT_HORIZONTAL_RATIO); + + t->idx_max = 0; + t->num.idx_max = 0; + t->snap[0] = 0.0f; + t->snap[1] = 0.1f; + t->snap[2] = t->snap[1] * 0.1f; + + copy_v3_fl(t->num.val_inc, t->snap[1]); + t->num.unit_sys = t->scene->unit.system; + t->num.unit_type[0] = B_UNIT_NONE; + + t->num.val_flag[0] |= NUM_NULL_ONE | NUM_NO_NEGATIVE; + t->flag |= T_NO_CONSTRAINT; + + // Calculate average radius + FOREACH_TRANS_DATA_CONTAINER (t, tc) { + TransData *td = tc->data; + for (i = 0; i < tc->data_len; i++, td++) { + t->val += len_v3v3(tc->center_local, td->iloc); + } + } + + t->val /= (float)t->data_len_all; +} +/** \} */ diff --git a/source/blender/editors/transform/transform_mode_trackball.c b/source/blender/editors/transform/transform_mode_trackball.c new file mode 100644 index 00000000000..c6e0b205204 --- /dev/null +++ b/source/blender/editors/transform/transform_mode_trackball.c @@ -0,0 +1,170 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + */ + +/** \file + * \ingroup edtransform + */ + +#include <stdlib.h> + +#include "BLI_math.h" +#include "BLI_string.h" + +#include "BKE_context.h" +#include "BKE_unit.h" + +#include "ED_screen.h" + +#include "UI_interface.h" + +#include "BLT_translation.h" + +#include "transform.h" +#include "transform_mode.h" +#include "transform_snap.h" + +/* -------------------------------------------------------------------- */ +/* Transform (Rotation - Trackball) */ + +/** \name Transform Rotation - Trackball + * \{ */ + +static void applyTrackballValue(TransInfo *t, + const float axis1[3], + const float axis2[3], + const float angles[2]) +{ + float mat[3][3]; + float axis[3]; + float angle; + int i; + + mul_v3_v3fl(axis, axis1, angles[0]); + madd_v3_v3fl(axis, axis2, angles[1]); + angle = normalize_v3(axis); + axis_angle_normalized_to_mat3(mat, axis, angle); + + FOREACH_TRANS_DATA_CONTAINER (t, tc) { + TransData *td = tc->data; + for (i = 0; i < tc->data_len; i++, td++) { + if (td->flag & TD_NOACTION) { + break; + } + + if (td->flag & TD_SKIP) { + continue; + } + + if (t->flag & T_PROP_EDIT) { + axis_angle_normalized_to_mat3(mat, axis, td->factor * angle); + } + + ElementRotation(t, tc, td, mat, t->around); + } + } +} + +static void applyTrackball(TransInfo *t, const int UNUSED(mval[2])) +{ + char str[UI_MAX_DRAW_STR]; + 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]); + copy_v3_v3(axis2, t->persinv[1]); + normalize_v3(axis1); + normalize_v3(axis2); + + copy_v2_v2(phi, t->values); + + snapGridIncrement(t, phi); + + applyNumInput(&t->num, phi); + + copy_v2_v2(t->values_final, phi); + + if (hasNumInput(&t->num)) { + char c[NUM_STR_REP_LEN * 2]; + + outputNumInput(&(t->num), c, &t->scene->unit); + + ofs += BLI_snprintf(str + ofs, + sizeof(str) - ofs, + TIP_("Trackball: %s %s %s"), + &c[0], + &c[NUM_STR_REP_LEN], + t->proptext); + } + else { + ofs += BLI_snprintf(str + ofs, + sizeof(str) - ofs, + TIP_("Trackball: %.2f %.2f %s"), + RAD2DEGF(phi[0]), + RAD2DEGF(phi[1]), + t->proptext); + } + + if (t->flag & T_PROP_EDIT_ALL) { + ofs += BLI_snprintf( + str + ofs, sizeof(str) - ofs, TIP_(" 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]); + + mul_m3_m3m3(mat, smat, totmat); + + // TRANSFORM_FIX_ME + //copy_m3_m3(t->mat, mat); // used in gizmo +#endif + + applyTrackballValue(t, axis1, axis2, phi); + + recalcData(t); + + ED_area_status_text(t->area, str); +} + +void initTrackball(TransInfo *t) +{ + t->mode = TFM_TRACKBALL; + t->transform = applyTrackball; + + initMouseInputMode(t, &t->mouse, INPUT_TRACKBALL); + + t->idx_max = 1; + t->num.idx_max = 1; + t->snap[0] = 0.0f; + t->snap[1] = DEG2RAD(5.0); + t->snap[2] = DEG2RAD(1.0); + + copy_v3_fl(t->num.val_inc, t->snap[2]); + t->num.unit_sys = t->scene->unit.system; + t->num.unit_use_radians = (t->scene->unit.system_rotation == USER_UNIT_ROT_RADIANS); + t->num.unit_type[0] = B_UNIT_ROTATION; + t->num.unit_type[1] = B_UNIT_ROTATION; + + t->flag |= T_NO_CONSTRAINT; +} +/** \} */ diff --git a/source/blender/editors/transform/transform_mode_translate.c b/source/blender/editors/transform/transform_mode_translate.c new file mode 100644 index 00000000000..0a7d8bd90d3 --- /dev/null +++ b/source/blender/editors/transform/transform_mode_translate.c @@ -0,0 +1,412 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + */ + +/** \file + * \ingroup edtransform + */ + +#include <stdlib.h> + +#include "MEM_guardedalloc.h" + +#include "DNA_gpencil_types.h" + +#include "BLI_math.h" +#include "BLI_string.h" + +#include "BKE_context.h" +#include "BKE_report.h" +#include "BKE_unit.h" + +#include "ED_screen.h" + +#include "WM_api.h" + +#include "UI_interface.h" + +#include "BLT_translation.h" + +#include "transform.h" +#include "transform_convert.h" +#include "transform_mode.h" +#include "transform_snap.h" + +/* -------------------------------------------------------------------- */ +/* Transform (Translation) */ + +/** \name Transform Translation + * \{ */ + +static void headerTranslation(TransInfo *t, const float vec[3], char str[UI_MAX_DRAW_STR]) +{ + size_t ofs = 0; + char tvec[NUM_STR_REP_LEN * 3]; + char distvec[NUM_STR_REP_LEN]; + char autoik[NUM_STR_REP_LEN]; + float dist; + + if (hasNumInput(&t->num)) { + outputNumInput(&(t->num), tvec, &t->scene->unit); + dist = len_v3(t->num.val); + } + else { + float dvec[3]; + + copy_v3_v3(dvec, vec); + applyAspectRatio(t, dvec); + + dist = len_v3(vec); + if (!(t->flag & T_2D_EDIT) && t->scene->unit.system) { + int i; + + for (i = 0; i < 3; i++) { + bUnit_AsString2(&tvec[NUM_STR_REP_LEN * i], + NUM_STR_REP_LEN, + dvec[i] * t->scene->unit.scale_length, + 4, + B_UNIT_LENGTH, + &t->scene->unit, + true); + } + } + else { + BLI_snprintf(&tvec[0], NUM_STR_REP_LEN, "%.4f", dvec[0]); + BLI_snprintf(&tvec[NUM_STR_REP_LEN], NUM_STR_REP_LEN, "%.4f", dvec[1]); + BLI_snprintf(&tvec[NUM_STR_REP_LEN * 2], NUM_STR_REP_LEN, "%.4f", dvec[2]); + } + } + + if (!(t->flag & T_2D_EDIT) && t->scene->unit.system) { + bUnit_AsString2(distvec, + sizeof(distvec), + dist * t->scene->unit.scale_length, + 4, + B_UNIT_LENGTH, + &t->scene->unit, + false); + } + else if (dist > 1e10f || dist < -1e10f) { + /* prevent string buffer overflow */ + BLI_snprintf(distvec, NUM_STR_REP_LEN, "%.4e", dist); + } + else { + BLI_snprintf(distvec, NUM_STR_REP_LEN, "%.4f", dist); + } + + if (t->flag & T_AUTOIK) { + short chainlen = t->settings->autoik_chainlen; + + if (chainlen) { + BLI_snprintf(autoik, NUM_STR_REP_LEN, TIP_("AutoIK-Len: %d"), chainlen); + } + else { + autoik[0] = '\0'; + } + } + else { + autoik[0] = '\0'; + } + + if (t->con.mode & CON_APPLY) { + switch (t->num.idx_max) { + case 0: + ofs += BLI_snprintf(str + ofs, + UI_MAX_DRAW_STR - ofs, + "D: %s (%s)%s %s %s", + &tvec[0], + distvec, + t->con.text, + t->proptext, + autoik); + break; + case 1: + ofs += BLI_snprintf(str + ofs, + UI_MAX_DRAW_STR - ofs, + "D: %s D: %s (%s)%s %s %s", + &tvec[0], + &tvec[NUM_STR_REP_LEN], + distvec, + t->con.text, + t->proptext, + autoik); + break; + case 2: + ofs += BLI_snprintf(str + ofs, + UI_MAX_DRAW_STR - ofs, + "D: %s D: %s D: %s (%s)%s %s %s", + &tvec[0], + &tvec[NUM_STR_REP_LEN], + &tvec[NUM_STR_REP_LEN * 2], + distvec, + t->con.text, + t->proptext, + autoik); + break; + } + } + else { + if (t->flag & T_2D_EDIT) { + ofs += BLI_snprintf(str + ofs, + UI_MAX_DRAW_STR - ofs, + "Dx: %s Dy: %s (%s)%s %s", + &tvec[0], + &tvec[NUM_STR_REP_LEN], + distvec, + t->con.text, + t->proptext); + } + else { + ofs += BLI_snprintf(str + ofs, + UI_MAX_DRAW_STR - ofs, + "Dx: %s Dy: %s Dz: %s (%s)%s %s %s", + &tvec[0], + &tvec[NUM_STR_REP_LEN], + &tvec[NUM_STR_REP_LEN * 2], + distvec, + t->con.text, + t->proptext, + autoik); + } + } + + if (t->flag & T_PROP_EDIT_ALL) { + ofs += BLI_snprintf( + str + ofs, UI_MAX_DRAW_STR - ofs, TIP_(" Proportional size: %.2f"), t->prop_size); + } + + if (t->spacetype == SPACE_NODE) { + SpaceNode *snode = (SpaceNode *)t->area->spacedata.first; + + if ((snode->flag & SNODE_SKIP_INSOFFSET) == 0) { + const char *str_old = BLI_strdup(str); + const char *str_dir = (snode->insert_ofs_dir == SNODE_INSERTOFS_DIR_RIGHT) ? TIP_("right") : + TIP_("left"); + char str_km[64]; + + WM_modalkeymap_items_to_string( + t->keymap, TFM_MODAL_INSERTOFS_TOGGLE_DIR, true, str_km, sizeof(str_km)); + + ofs += BLI_snprintf(str, + UI_MAX_DRAW_STR, + TIP_("Auto-offset set to %s - press %s to toggle direction | %s"), + str_dir, + str_km, + str_old); + + MEM_freeN((void *)str_old); + } + } +} + +static void applyTranslationValue(TransInfo *t, const float vec[3]) +{ + const bool apply_snap_align_rotation = usingSnappingNormal( + t); // && (t->tsnap.status & POINT_INIT); + float tvec[3]; + + /* The ideal would be "apply_snap_align_rotation" only when a snap point is found + * so, maybe inside this function is not the best place to apply this rotation. + * but you need "handle snapping rotation before doing the translation" (really?) */ + FOREACH_TRANS_DATA_CONTAINER (t, tc) { + + float pivot[3]; + if (apply_snap_align_rotation) { + copy_v3_v3(pivot, t->tsnap.snapTarget); + /* The pivot has to be in local-space (see T49494) */ + if (tc->use_local_mat) { + mul_m4_v3(tc->imat, pivot); + } + } + + TransData *td = tc->data; + for (int i = 0; i < tc->data_len; i++, td++) { + if (td->flag & TD_NOACTION) { + break; + } + + if (td->flag & TD_SKIP) { + continue; + } + + float rotate_offset[3] = {0}; + bool use_rotate_offset = false; + + /* handle snapping rotation before doing the translation */ + if (apply_snap_align_rotation) { + float mat[3][3]; + + if (validSnappingNormal(t)) { + const float *original_normal; + + /* In pose mode, we want to align normals with Y axis of bones... */ + if (t->flag & T_POSE) { + original_normal = td->axismtx[1]; + } + else { + original_normal = td->axismtx[2]; + } + + rotation_between_vecs_to_mat3(mat, original_normal, t->tsnap.snapNormal); + } + else { + unit_m3(mat); + } + + ElementRotation_ex(t, tc, td, mat, pivot); + + if (td->loc) { + use_rotate_offset = true; + sub_v3_v3v3(rotate_offset, td->loc, td->iloc); + } + } + + if (t->con.applyVec) { + float pvec[3]; + t->con.applyVec(t, tc, td, vec, tvec, pvec); + } + else { + copy_v3_v3(tvec, vec); + } + + mul_m3_v3(td->smtx, tvec); + + if (use_rotate_offset) { + add_v3_v3(tvec, rotate_offset); + } + + if (t->options & CTX_GPENCIL_STROKES) { + /* grease pencil multiframe falloff */ + bGPDstroke *gps = (bGPDstroke *)td->extra; + if (gps != NULL) { + mul_v3_fl(tvec, td->factor * gps->runtime.multi_frame_falloff); + } + else { + mul_v3_fl(tvec, td->factor); + } + } + else { + /* proportional editing falloff */ + mul_v3_fl(tvec, td->factor); + } + + protectedTransBits(td->protectflag, tvec); + + if (td->loc) { + add_v3_v3v3(td->loc, td->iloc, tvec); + } + + constraintTransLim(t, td); + } + } +} + +static void applyTranslation(TransInfo *t, const int UNUSED(mval[2])) +{ + char str[UI_MAX_DRAW_STR]; + float values_final[3]; + + if (t->flag & T_INPUT_IS_VALUES_FINAL) { + copy_v3_v3(t->values_final, t->values); + } + else { + copy_v3_v3(t->values_final, t->values); + if ((t->con.mode & CON_APPLY) == 0) { + snapGridIncrement(t, t->values_final); + } + + if (applyNumInput(&t->num, t->values_final)) { + removeAspectRatio(t, t->values_final); + } + + applySnapping(t, t->values_final); + } + copy_v3_v3(values_final, t->values_final); + + if (t->con.mode & CON_APPLY) { + float pvec[3] = {0.0f, 0.0f, 0.0f}; + t->con.applyVec(t, NULL, NULL, t->values_final, values_final, pvec); + headerTranslation(t, pvec, str); + + /* only so we have re-usable value with redo, see T46741. */ + mul_v3_m3v3(t->values_final, t->con.imtx, values_final); + } + else { + headerTranslation(t, t->values_final, str); + copy_v3_v3(values_final, t->values_final); + } + + /* don't use 't->values' now on */ + + applyTranslationValue(t, values_final); + + /* evil hack - redo translation if clipping needed */ + if (t->flag & T_CLIP_UV && clipUVTransform(t, values_final, 0)) { + applyTranslationValue(t, values_final); + + /* In proportional edit it can happen that */ + /* vertices in the radius of the brush end */ + /* outside the clipping area */ + /* XXX HACK - dg */ + if (t->flag & T_PROP_EDIT_ALL) { + clipUVData(t); + } + } + + recalcData(t); + + ED_area_status_text(t->area, str); +} + +void initTranslation(TransInfo *t) +{ + if (t->spacetype == SPACE_ACTION) { + /* this space uses time translate */ + BKE_report(t->reports, + RPT_ERROR, + "Use 'Time_Translate' transform mode instead of 'Translation' mode " + "for translating keyframes in Dope Sheet Editor"); + t->state = TRANS_CANCEL; + } + + t->transform = applyTranslation; + + initMouseInputMode(t, &t->mouse, INPUT_VECTOR); + + t->idx_max = (t->flag & T_2D_EDIT) ? 1 : 2; + t->num.flag = 0; + t->num.idx_max = t->idx_max; + + copy_v3_v3(t->snap, t->snap_spatial); + + copy_v3_fl(t->num.val_inc, t->snap[1]); + t->num.unit_sys = t->scene->unit.system; + if (t->spacetype == SPACE_VIEW3D) { + /* Handling units makes only sense in 3Dview... See T38877. */ + t->num.unit_type[0] = B_UNIT_LENGTH; + t->num.unit_type[1] = B_UNIT_LENGTH; + t->num.unit_type[2] = B_UNIT_LENGTH; + } + else { + /* SPACE_GRAPH, SPACE_ACTION, etc. could use some time units, when we have them... */ + t->num.unit_type[0] = B_UNIT_NONE; + t->num.unit_type[1] = B_UNIT_NONE; + t->num.unit_type[2] = B_UNIT_NONE; + } +} +/** \} */ diff --git a/source/blender/editors/transform/transform_mode_vert_slide.c b/source/blender/editors/transform/transform_mode_vert_slide.c new file mode 100644 index 00000000000..7bee48337f9 --- /dev/null +++ b/source/blender/editors/transform/transform_mode_vert_slide.c @@ -0,0 +1,666 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + */ + +/** \file + * \ingroup edtransform + */ + +#include <stdlib.h> + +#include "MEM_guardedalloc.h" + +#include "BLI_math.h" +#include "BLI_string.h" + +#include "BKE_context.h" +#include "BKE_editmesh.h" +#include "BKE_unit.h" + +#include "GPU_immediate.h" +#include "GPU_matrix.h" +#include "GPU_state.h" + +#include "ED_screen.h" + +#include "WM_api.h" +#include "WM_types.h" + +#include "UI_interface.h" +#include "UI_resources.h" + +#include "BLT_translation.h" + +#include "transform.h" +#include "transform_convert.h" +#include "transform_mode.h" +#include "transform_snap.h" + +/* -------------------------------------------------------------------- */ +/* Transform (Vert Slide) */ + +/** \name Transform Vert Slide + * \{ */ + +typedef struct TransDataVertSlideVert { + /** #TransDataGenericSlideVert (header) */ + struct BMVert *v; + struct LinkNode **cd_loop_groups; + float co_orig_3d[3]; + /* end generic */ + + float (*co_link_orig_3d)[3]; + int co_link_tot; + int co_link_curr; +} TransDataVertSlideVert; + +typedef struct VertSlideData { + TransDataVertSlideVert *sv; + int totsv; + int curr_sv_index; + + /* result of ED_view3d_ob_project_mat_get */ + float proj_mat[4][4]; +} VertSlideData; + +typedef struct VertSlideParams { + float perc; + + bool use_even; + bool flipped; +} VertSlideParams; + +static void calcVertSlideCustomPoints(struct TransInfo *t) +{ + VertSlideParams *slp = t->custom.mode.data; + VertSlideData *sld = TRANS_DATA_CONTAINER_FIRST_OK(t)->custom.mode.data; + TransDataVertSlideVert *sv = &sld->sv[sld->curr_sv_index]; + + 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->region, co_orig_3d, co_orig_2d, sld->proj_mat); + ED_view3d_project_float_v2_m4(t->region, co_curr_3d, co_curr_2d, sld->proj_mat); + + ARRAY_SET_ITEMS(mval_ofs, t->mouse.imval[0] - co_orig_2d[0], t->mouse.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 (slp->flipped && slp->use_even) { + setCustomPoints(t, &t->mouse, mval_start, mval_end); + } + else { + setCustomPoints(t, &t->mouse, mval_end, mval_start); + } + + /* setCustomPoints isn't normally changing as the mouse moves, + * in this case apply mouse input immediately so we don't refresh + * with the value from the previous points */ + applyMouseInput(t, &t->mouse, t->mval, t->values); +} + +/** + * Run once when initializing vert slide to find the reference edge + */ +static void calcVertSlideMouseActiveVert(struct TransInfo *t, const int mval[2]) +{ + /* Active object may have no selected vertices. */ + VertSlideData *sld = TRANS_DATA_CONTAINER_FIRST_OK(t)->custom.mode.data; + float mval_fl[2] = {UNPACK2(mval)}; + TransDataVertSlideVert *sv; + + /* set the vertex to use as a reference for the mouse direction 'curr_sv_index' */ + float dist_sq = 0.0f; + float dist_min_sq = FLT_MAX; + int i; + + for (i = 0, sv = sld->sv; i < sld->totsv; i++, sv++) { + float co_2d[2]; + + ED_view3d_project_float_v2_m4(t->region, 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 = TRANS_DATA_CONTAINER_FIRST_OK(t)->custom.mode.data; + float imval_fl[2] = {UNPACK2(t->mouse.imval)}; + float mval_fl[2] = {UNPACK2(mval)}; + + float dir[3]; + TransDataVertSlideVert *sv; + int i; + + /* note: we could save a matrix-multiply for each vertex + * by finding the closest edge in local-space. + * However this skews the outcome with non-uniform-scale. */ + + /* first get the direction of the original mouse position */ + sub_v2_v2v2(dir, imval_fl, mval_fl); + ED_view3d_win_to_delta(t->region, dir, dir, t->zfac); + normalize_v3(dir); + + for (i = 0, sv = sld->sv; i < sld->totsv; i++, sv++) { + if (sv->co_link_tot > 1) { + float dir_dot_best = -FLT_MAX; + int co_link_curr_best = -1; + int j; + + for (j = 0; j < sv->co_link_tot; j++) { + float tdir[3]; + float dir_dot; + + sub_v3_v3v3(tdir, sv->co_orig_3d, sv->co_link_orig_3d[j]); + mul_mat3_m4_v3(TRANS_DATA_CONTAINER_FIRST_OK(t)->obedit->obmat, tdir); + 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; + } + } + + if (co_link_curr_best != -1) { + sv->co_link_curr = co_link_curr_best; + } + } + } +} + +static bool createVertSlideVerts(TransInfo *t, TransDataContainer *tc) +{ + BMEditMesh *em = BKE_editmesh_from_object(tc->obedit); + BMesh *bm = em->bm; + BMIter iter; + BMIter eiter; + BMEdge *e; + BMVert *v; + TransDataVertSlideVert *sv_array; + VertSlideData *sld = MEM_callocN(sizeof(*sld), "sld"); + int j; + + sld->curr_sv_index = 0; + + j = 0; + BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) { + bool ok = false; + if (BM_elem_flag_test(v, BM_ELEM_SELECT) && v->e) { + BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) { + if (!BM_elem_flag_test(e, BM_ELEM_HIDDEN)) { + ok = true; + break; + } + } + } + + if (ok) { + BM_elem_flag_enable(v, BM_ELEM_TAG); + j += 1; + } + else { + BM_elem_flag_disable(v, BM_ELEM_TAG); + } + } + + if (!j) { + MEM_freeN(sld); + return false; + } + + sv_array = MEM_callocN(sizeof(TransDataVertSlideVert) * j, "sv_array"); + + j = 0; + BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) { + if (BM_elem_flag_test(v, BM_ELEM_TAG)) { + int k; + sv_array[j].v = v; + copy_v3_v3(sv_array[j].co_orig_3d, v->co); + + k = 0; + BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) { + if (!BM_elem_flag_test(e, BM_ELEM_HIDDEN)) { + k++; + } + } + + sv_array[j].co_link_orig_3d = MEM_mallocN(sizeof(*sv_array[j].co_link_orig_3d) * k, + __func__); + sv_array[j].co_link_tot = k; + + k = 0; + BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) { + 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); + k++; + } + } + j++; + } + } + + sld->sv = sv_array; + sld->totsv = j; + + tc->custom.mode.data = sld; + + /* most likely will be set below */ + unit_m4(sld->proj_mat); + + if (t->spacetype == SPACE_VIEW3D) { + /* view vars */ + RegionView3D *rv3d = NULL; + ARegion *region = t->region; + + rv3d = region ? region->regiondata : NULL; + if (rv3d) { + ED_view3d_ob_project_mat_get(rv3d, tc->obedit, sld->proj_mat); + } + } + + /* XXX, calc vert slide across all objects */ + if (tc == t->data_container) { + calcVertSlideMouseActiveVert(t, t->mval); + calcVertSlideMouseActiveEdges(t, t->mval); + } + + return true; +} + +static void freeVertSlideVerts(TransInfo *UNUSED(t), + TransDataContainer *UNUSED(tc), + TransCustomData *custom_data) +{ + VertSlideData *sld = custom_data->data; + + if (!sld) { + return; + } + + if (sld->totsv > 0) { + TransDataVertSlideVert *sv = sld->sv; + int i = 0; + for (i = 0; i < sld->totsv; i++, sv++) { + MEM_freeN(sv->co_link_orig_3d); + } + } + + MEM_freeN(sld->sv); + MEM_freeN(sld); + + custom_data->data = NULL; +} + +static eRedrawFlag handleEventVertSlide(struct TransInfo *t, const struct wmEvent *event) +{ + if (t->mode == TFM_VERT_SLIDE) { + VertSlideParams *slp = t->custom.mode.data; + + if (slp) { + switch (event->type) { + case EVT_EKEY: + if (event->val == KM_PRESS) { + slp->use_even = !slp->use_even; + if (slp->flipped) { + calcVertSlideCustomPoints(t); + } + return TREDRAW_HARD; + } + break; + case EVT_FKEY: + if (event->val == KM_PRESS) { + slp->flipped = !slp->flipped; + calcVertSlideCustomPoints(t); + return TREDRAW_HARD; + } + break; + case EVT_CKEY: + /* use like a modifier key */ + if (event->val == KM_PRESS) { + t->flag ^= T_ALT_TRANSFORM; + calcVertSlideCustomPoints(t); + 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: { + /* don't recalculate the best edge */ + const bool is_clamp = !(t->flag & T_ALT_TRANSFORM); + if (is_clamp) { + calcVertSlideMouseActiveEdges(t, event->mval); + } + calcVertSlideCustomPoints(t); + break; + } + default: + break; + } + } + } + return TREDRAW_NOTHING; +} + +void projectVertSlideData(TransInfo *t, bool is_final) +{ + FOREACH_TRANS_DATA_CONTAINER (t, tc) { + trans_mesh_customdata_correction_apply(tc, is_final); + } +} + +void drawVertSlide(TransInfo *t) +{ + if ((t->mode == TFM_VERT_SLIDE) && TRANS_DATA_CONTAINER_FIRST_OK(t)->custom.mode.data) { + const VertSlideParams *slp = t->custom.mode.data; + VertSlideData *sld = TRANS_DATA_CONTAINER_FIRST_OK(t)->custom.mode.data; + const bool is_clamp = !(t->flag & T_ALT_TRANSFORM); + + /* Non-Prop mode */ + { + 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; + int i; + + GPU_depth_test(false); + + GPU_blend(true); + GPU_blend_set_func_separate( + GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA); + + GPU_matrix_push(); + GPU_matrix_mul(TRANS_DATA_CONTAINER_FIRST_OK(t)->obedit->obmat); + + GPU_line_width(line_size); + + const uint shdr_pos = GPU_vertformat_attr_add( + immVertexFormat(), "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT); + + immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR); + immUniformThemeColorShadeAlpha(TH_EDGE_SELECT, 80, alpha_shade); + + immBegin(GPU_PRIM_LINES, sld->totsv * 2); + if (is_clamp) { + sv = sld->sv; + for (i = 0; i < sld->totsv; i++, sv++) { + immVertex3fv(shdr_pos, sv->co_orig_3d); + immVertex3fv(shdr_pos, sv->co_link_orig_3d[sv->co_link_curr]); + } + } + else { + sv = sld->sv; + for (i = 0; i < sld->totsv; i++, sv++) { + float a[3], b[3]; + sub_v3_v3v3(a, sv->co_link_orig_3d[sv->co_link_curr], sv->co_orig_3d); + mul_v3_fl(a, 100.0f); + negate_v3_v3(b, a); + add_v3_v3(a, sv->co_orig_3d); + add_v3_v3(b, sv->co_orig_3d); + + immVertex3fv(shdr_pos, a); + immVertex3fv(shdr_pos, b); + } + } + immEnd(); + + GPU_point_size(ctrl_size); + + immBegin(GPU_PRIM_POINTS, 1); + immVertex3fv(shdr_pos, + (slp->flipped && slp->use_even) ? + curr_sv->co_link_orig_3d[curr_sv->co_link_curr] : + curr_sv->co_orig_3d); + immEnd(); + + immUnbindProgram(); + + /* direction from active vertex! */ + if ((t->mval[0] != t->mouse.imval[0]) || (t->mval[1] != t->mouse.imval[1])) { + float zfac; + float mval_ofs[2]; + float co_orig_3d[3]; + float co_dest_3d[3]; + + mval_ofs[0] = t->mval[0] - t->mouse.imval[0]; + mval_ofs[1] = t->mval[1] - t->mouse.imval[1]; + + mul_v3_m4v3( + co_orig_3d, TRANS_DATA_CONTAINER_FIRST_OK(t)->obedit->obmat, curr_sv->co_orig_3d); + zfac = ED_view3d_calc_zfac(t->region->regiondata, co_orig_3d, NULL); + + ED_view3d_win_to_delta(t->region, mval_ofs, co_dest_3d, zfac); + + invert_m4_m4(TRANS_DATA_CONTAINER_FIRST_OK(t)->obedit->imat, + TRANS_DATA_CONTAINER_FIRST_OK(t)->obedit->obmat); + mul_mat3_m4_v3(TRANS_DATA_CONTAINER_FIRST_OK(t)->obedit->imat, co_dest_3d); + + add_v3_v3(co_dest_3d, curr_sv->co_orig_3d); + + GPU_line_width(1.0f); + + immBindBuiltinProgram(GPU_SHADER_3D_LINE_DASHED_UNIFORM_COLOR); + + float viewport_size[4]; + GPU_viewport_size_get_f(viewport_size); + immUniform2f("viewport_size", viewport_size[2], viewport_size[3]); + + immUniform1i("colors_len", 0); /* "simple" mode */ + immUniformColor4f(1.0f, 1.0f, 1.0f, 1.0f); + immUniform1f("dash_width", 6.0f); + immUniform1f("dash_factor", 0.5f); + + immBegin(GPU_PRIM_LINES, 2); + immVertex3fv(shdr_pos, curr_sv->co_orig_3d); + immVertex3fv(shdr_pos, co_dest_3d); + immEnd(); + + immUnbindProgram(); + } + + GPU_matrix_pop(); + + GPU_depth_test(true); + } + } +} + +void doVertSlide(TransInfo *t, float perc) +{ + VertSlideParams *slp = t->custom.mode.data; + + slp->perc = perc; + + FOREACH_TRANS_DATA_CONTAINER (t, tc) { + VertSlideData *sld = tc->custom.mode.data; + TransDataVertSlideVert *svlist = sld->sv, *sv; + int i; + + sv = svlist; + + if (slp->use_even == false) { + for (i = 0; i < sld->totsv; i++, sv++) { + interp_v3_v3v3(sv->v->co, sv->co_orig_3d, sv->co_link_orig_3d[sv->co_link_curr], perc); + } + } + else { + TransDataVertSlideVert *sv_curr = &sld->sv[sld->curr_sv_index]; + const float edge_len_curr = len_v3v3(sv_curr->co_orig_3d, + sv_curr->co_link_orig_3d[sv_curr->co_link_curr]); + const float tperc = perc * edge_len_curr; + + for (i = 0; i < sld->totsv; i++, sv++) { + float edge_len; + float dir[3]; + + sub_v3_v3v3(dir, sv->co_link_orig_3d[sv->co_link_curr], sv->co_orig_3d); + edge_len = normalize_v3(dir); + + if (edge_len > FLT_EPSILON) { + if (slp->flipped) { + madd_v3_v3v3fl(sv->v->co, sv->co_link_orig_3d[sv->co_link_curr], dir, -tperc); + } + else { + madd_v3_v3v3fl(sv->v->co, sv->co_orig_3d, dir, tperc); + } + } + else { + copy_v3_v3(sv->v->co, sv->co_orig_3d); + } + } + } + } +} + +static void applyVertSlide(TransInfo *t, const int UNUSED(mval[2])) +{ + char str[UI_MAX_DRAW_STR]; + size_t ofs = 0; + float final; + VertSlideParams *slp = t->custom.mode.data; + const bool flipped = slp->flipped; + const bool use_even = slp->use_even; + 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 */ + if (is_constrained) { + CLAMP(final, 0.0f, 1.0f); + } + + applyNumInput(&t->num, &final); + + t->values_final[0] = final; + + /* header string */ + ofs += BLI_strncpy_rlen(str + ofs, TIP_("Vert Slide: "), sizeof(str) - ofs); + if (hasNumInput(&t->num)) { + char c[NUM_STR_REP_LEN]; + outputNumInput(&(t->num), c, &t->scene->unit); + ofs += BLI_strncpy_rlen(str + ofs, &c[0], sizeof(str) - ofs); + } + else { + ofs += BLI_snprintf(str + ofs, sizeof(str) - ofs, "%.4f ", final); + } + ofs += BLI_snprintf( + str + ofs, sizeof(str) - ofs, TIP_("(E)ven: %s, "), WM_bool_as_string(use_even)); + if (use_even) { + ofs += BLI_snprintf( + str + ofs, sizeof(str) - ofs, TIP_("(F)lipped: %s, "), WM_bool_as_string(flipped)); + } + ofs += BLI_snprintf( + str + ofs, sizeof(str) - ofs, TIP_("Alt or (C)lamp: %s"), WM_bool_as_string(is_clamp)); + /* done with header string */ + + /* do stuff here */ + doVertSlide(t, final); + + recalcData(t); + + ED_area_status_text(t->area, str); +} + +void initVertSlide_ex(TransInfo *t, bool use_even, bool flipped, bool use_clamp) +{ + + t->mode = TFM_VERT_SLIDE; + t->transform = applyVertSlide; + t->handleEvent = handleEventVertSlide; + + { + VertSlideParams *slp = MEM_callocN(sizeof(*slp), __func__); + slp->use_even = use_even; + slp->flipped = flipped; + slp->perc = 0.0f; + + if (!use_clamp) { + t->flag |= T_ALT_TRANSFORM; + } + + t->custom.mode.data = slp; + t->custom.mode.use_free = true; + } + + bool ok = false; + FOREACH_TRANS_DATA_CONTAINER (t, tc) { + ok |= createVertSlideVerts(t, tc); + VertSlideData *sld = tc->custom.mode.data; + if (sld) { + tc->custom.mode.free_cb = freeVertSlideVerts; + } + } + + if (ok == false) { + t->state = TRANS_CANCEL; + return; + } + + trans_mesh_customdata_correction_init(t); + + /* set custom point first if you want value to be initialized by init */ + calcVertSlideCustomPoints(t); + initMouseInputMode(t, &t->mouse, INPUT_CUSTOM_RATIO); + + t->idx_max = 0; + t->num.idx_max = 0; + t->snap[0] = 0.0f; + t->snap[1] = 0.1f; + t->snap[2] = t->snap[1] * 0.1f; + + copy_v3_fl(t->num.val_inc, t->snap[1]); + t->num.unit_sys = t->scene->unit.system; + t->num.unit_type[0] = B_UNIT_NONE; + + t->flag |= T_NO_CONSTRAINT | T_NO_PROJECT; +} + +void initVertSlide(TransInfo *t) +{ + initVertSlide_ex(t, false, false, true); +} +/** \} */ diff --git a/source/blender/editors/transform/transform_ops.c b/source/blender/editors/transform/transform_ops.c index 09992e8be0e..d643244e6ca 100644 --- a/source/blender/editors/transform/transform_ops.c +++ b/source/blender/editors/transform/transform_ops.c @@ -30,10 +30,10 @@ #include "BLT_translation.h" #include "BKE_context.h" -#include "BKE_global.h" -#include "BKE_report.h" #include "BKE_editmesh.h" +#include "BKE_global.h" #include "BKE_layer.h" +#include "BKE_report.h" #include "BKE_scene.h" #include "RNA_access.h" @@ -42,8 +42,8 @@ #include "WM_api.h" #include "WM_message.h" -#include "WM_types.h" #include "WM_toolsystem.h" +#include "WM_types.h" #include "UI_interface.h" #include "UI_resources.h" @@ -75,6 +75,7 @@ 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_BONE_SIZE[] = "TRANSFORM_OT_bbone_resize"; 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"; @@ -94,6 +95,7 @@ static void TRANSFORM_OT_push_pull(struct wmOperatorType *ot); static void TRANSFORM_OT_tilt(struct wmOperatorType *ot); static void TRANSFORM_OT_trackball(struct wmOperatorType *ot); static void TRANSFORM_OT_mirror(struct wmOperatorType *ot); +static void TRANSFORM_OT_bbone_resize(struct wmOperatorType *ot); static void TRANSFORM_OT_edge_slide(struct wmOperatorType *ot); static void TRANSFORM_OT_vert_slide(struct wmOperatorType *ot); static void TRANSFORM_OT_edge_crease(struct wmOperatorType *ot); @@ -114,6 +116,7 @@ static TransformModeItem transform_modes[] = { {OP_TILT, TFM_TILT, TRANSFORM_OT_tilt}, {OP_TRACKBALL, TFM_TRACKBALL, TRANSFORM_OT_trackball}, {OP_MIRROR, TFM_MIRROR, TRANSFORM_OT_mirror}, + {OP_BONE_SIZE, TFM_BONESIZE, TRANSFORM_OT_bbone_resize}, {OP_EDGE_SLIDE, TFM_EDGE_SLIDE, TRANSFORM_OT_edge_slide}, {OP_VERT_SLIDE, TFM_VERT_SLIDE, TRANSFORM_OT_vert_slide}, {OP_EDGE_CREASE, TFM_CREASE, TRANSFORM_OT_edge_crease}, @@ -220,6 +223,9 @@ static int delete_orientation_exec(bContext *C, wmOperator *UNUSED(op)) WM_event_add_notifier(C, NC_SCENE | NA_EDITED, scene); + struct wmMsgBus *mbus = CTX_wm_message_bus(C); + WM_msg_publish_rna_prop(mbus, &scene->id, scene, Scene, transform_orientation_slots); + return OPERATOR_FINISHED; } @@ -230,12 +236,11 @@ static int delete_orientation_invoke(bContext *C, wmOperator *op, const wmEvent static bool delete_orientation_poll(bContext *C) { - Scene *scene = CTX_data_scene(C); - if (ED_operator_areaactive(C) == 0) { return 0; } + Scene *scene = CTX_data_scene(C); return ((scene->orientation_slots[SCE_ORIENT_DEFAULT].type >= V3D_ORIENT_CUSTOM) && (scene->orientation_slots[SCE_ORIENT_DEFAULT].index_custom != -1)); } @@ -261,6 +266,7 @@ static int create_orientation_exec(bContext *C, wmOperator *op) const bool overwrite = RNA_boolean_get(op->ptr, "overwrite"); const bool use_view = RNA_boolean_get(op->ptr, "use_view"); View3D *v3d = CTX_wm_view3d(C); + Scene *scene = CTX_data_scene(C); RNA_string_get(op->ptr, "name", name); @@ -271,10 +277,18 @@ static int create_orientation_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } - BIF_createTransformOrientation(C, op->reports, name, use_view, use, overwrite); + if (!BIF_createTransformOrientation(C, op->reports, name, use_view, use, overwrite)) { + BKE_report(op->reports, RPT_ERROR, "Unable to create orientation"); + return OPERATOR_CANCELLED; + } + + if (use) { + struct wmMsgBus *mbus = CTX_wm_message_bus(C); + WM_msg_publish_rna_prop(mbus, &scene->id, scene, Scene, transform_orientation_slots); + WM_event_add_notifier(C, NC_SCENE | NA_EDITED, scene); + } WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, v3d); - WM_event_add_notifier(C, NC_SCENE | NA_EDITED, CTX_data_scene(C)); return OPERATOR_FINISHED; } @@ -702,6 +716,15 @@ void Transform_Properties(struct wmOperatorType *ot, int flags) prop = RNA_def_boolean(ot->srna, "use_accurate", 0, "Accurate", "Use accurate transformation"); RNA_def_property_flag(prop, PROP_HIDDEN); } + + if (flags & P_POST_TRANSFORM) { + prop = RNA_def_boolean(ot->srna, + "use_automerge_and_split", + 0, + "Auto Merge & Split", + "Forces the use of Auto Merge & Split"); + RNA_def_property_flag(prop, PROP_HIDDEN); + } } static void TRANSFORM_OT_translate(struct wmOperatorType *ot) @@ -727,7 +750,7 @@ static void TRANSFORM_OT_translate(struct wmOperatorType *ot) Transform_Properties(ot, P_ORIENT_MATRIX | P_CONSTRAINT | P_PROPORTIONAL | P_MIRROR | P_ALIGN_SNAP | - P_OPTIONS | P_GPENCIL_EDIT | P_CURSOR_EDIT); + P_OPTIONS | P_GPENCIL_EDIT | P_CURSOR_EDIT | P_POST_TRANSFORM); } static void TRANSFORM_OT_resize(struct wmOperatorType *ot) @@ -890,8 +913,8 @@ static bool transform_shear_poll(bContext *C) return false; } - ScrArea *sa = CTX_wm_area(C); - return sa && !ELEM(sa->spacetype, SPACE_ACTION); + ScrArea *area = CTX_wm_area(C); + return area && !ELEM(area->spacetype, SPACE_ACTION); } static void TRANSFORM_OT_shear(struct wmOperatorType *ot) @@ -1015,6 +1038,30 @@ static void TRANSFORM_OT_mirror(struct wmOperatorType *ot) ot, P_ORIENT_MATRIX | P_CONSTRAINT | P_PROPORTIONAL | P_GPENCIL_EDIT | P_CENTER); } +static void TRANSFORM_OT_bbone_resize(struct wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Scale B-Bone"; + ot->description = "Scale selected bendy bones display size"; + ot->idname = OP_BONE_SIZE; + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_BLOCKING; + + /* api callbacks */ + ot->invoke = transform_invoke; + ot->exec = transform_exec; + ot->modal = transform_modal; + ot->cancel = transform_cancel; + ot->poll = ED_operator_editarmature; + ot->poll_property = transform_poll_property; + + RNA_def_float_translation( + ot->srna, "value", 2, VecOne, -FLT_MAX, FLT_MAX, "Display Size", "", -FLT_MAX, FLT_MAX); + + WM_operatortype_props_advanced_begin(ot); + + Transform_Properties(ot, P_ORIENT_MATRIX | P_CONSTRAINT | P_MIRROR); +} + static void TRANSFORM_OT_edge_slide(struct wmOperatorType *ot) { PropertyRNA *prop; @@ -1221,8 +1268,8 @@ static int transform_from_gizmo_invoke(bContext *C, { bToolRef *tref = WM_toolsystem_ref_from_context(C); if (tref) { - ARegion *ar = CTX_wm_region(C); - wmGizmoMap *gzmap = ar->gizmo_map; + ARegion *region = CTX_wm_region(C); + wmGizmoMap *gzmap = region->gizmo_map; wmGizmoGroup *gzgroup = gzmap ? WM_gizmomap_group_find(gzmap, "VIEW3D_GGT_xform_gizmo") : NULL; if (gzgroup != NULL) { PointerRNA gzg_ptr; diff --git a/source/blender/editors/transform/transform_orientations.c b/source/blender/editors/transform/transform_orientations.c index 1952a2c862e..81c63278366 100644 --- a/source/blender/editors/transform/transform_orientations.c +++ b/source/blender/editors/transform/transform_orientations.c @@ -18,9 +18,9 @@ * \ingroup edtransform */ -#include <string.h> -#include <stddef.h> #include <ctype.h> +#include <stddef.h> +#include <string.h> #include "MEM_guardedalloc.h" @@ -34,15 +34,15 @@ #include "DNA_view3d_types.h" #include "DNA_workspace_types.h" -#include "BLI_math.h" #include "BLI_listbase.h" +#include "BLI_math.h" #include "BLI_string.h" #include "BLI_string_utils.h" #include "BLI_utildefines.h" #include "BKE_action.h" -#include "BKE_curve.h" #include "BKE_context.h" +#include "BKE_curve.h" #include "BKE_editmesh.h" #include "BKE_layer.h" #include "BKE_report.h" @@ -296,7 +296,7 @@ bool createSpaceNormalTangent(float mat[3][3], const float normal[3], const floa return true; } -void BIF_createTransformOrientation(bContext *C, +bool BIF_createTransformOrientation(bContext *C, ReportList *reports, const char *name, const bool use_view, @@ -333,6 +333,7 @@ void BIF_createTransformOrientation(bContext *C, if (activate && ts != NULL) { BIF_selectTransformOrientation(C, ts); } + return (ts != NULL); } TransformOrientation *addMatrixSpace(bContext *C, @@ -406,14 +407,19 @@ bool applyTransformOrientation(const TransformOrientation *ts, float r_mat[3][3] return true; } -static int count_bone_select(bArmature *arm, ListBase *lb, const bool do_it) +/* Updates all `BONE_TRANSFORM` flags. + * Returns total number of bones with `BONE_TRANSFORM`. + * Note: `transform_convert_pose_transflags_update` has a similar logic. */ +static int armature_bone_transflags_update_recursive(bArmature *arm, + ListBase *lb, + const bool do_it) { Bone *bone; bool do_next; int total = 0; for (bone = lb->first; bone; bone = bone->next) { - bone->flag &= ~(BONE_TRANSFORM | BONE_TRANSFORM_MIRROR); + bone->flag &= ~BONE_TRANSFORM; do_next = do_it; if (do_it) { if (bone->layer & arm->layer) { @@ -426,18 +432,18 @@ static int count_bone_select(bArmature *arm, ListBase *lb, const bool do_it) } } } - total += count_bone_select(arm, &bone->childbase, do_next); + total += armature_bone_transflags_update_recursive(arm, &bone->childbase, do_next); } return total; } -void initTransformOrientation(bContext *C, TransInfo *t) +void initTransformOrientation(bContext *C, TransInfo *t, short orientation) { Object *ob = CTX_data_active_object(C); Object *obedit = CTX_data_active_object(C); - switch (t->orientation.user) { + switch (orientation) { case V3D_ORIENT_GLOBAL: unit_m3(t->spacemtx); BLI_strncpy(t->spacename, TIP_("global"), sizeof(t->spacename)); @@ -470,32 +476,33 @@ void initTransformOrientation(bContext *C, TransInfo *t) break; - case V3D_ORIENT_VIEW: - if ((t->spacetype == SPACE_VIEW3D) && (t->ar->regiontype == RGN_TYPE_WINDOW)) { - RegionView3D *rv3d = t->ar->regiondata; - float mat[3][3]; - + case V3D_ORIENT_VIEW: { + float mat[3][3]; + if ((t->spacetype == SPACE_VIEW3D) && (t->region->regiontype == RGN_TYPE_WINDOW)) { BLI_strncpy(t->spacename, TIP_("view"), sizeof(t->spacename)); - copy_m3_m4(mat, rv3d->viewinv); + copy_m3_m4(mat, t->viewinv); normalize_m3(mat); - copy_m3_m3(t->spacemtx, mat); } else { - unit_m3(t->spacemtx); + unit_m3(mat); } + negate_v3(mat[2]); + copy_m3_m3(t->spacemtx, mat); break; + } case V3D_ORIENT_CURSOR: { BLI_strncpy(t->spacename, TIP_("cursor"), sizeof(t->spacename)); BKE_scene_cursor_rot_to_mat3(&t->scene->cursor, t->spacemtx); break; } case V3D_ORIENT_CUSTOM_MATRIX: - /* Already set. */ BLI_strncpy(t->spacename, TIP_("custom"), sizeof(t->spacename)); + copy_m3_m3(t->spacemtx, t->orientation.custom_matrix); break; case V3D_ORIENT_CUSTOM: + default: + BLI_assert(orientation >= V3D_ORIENT_CUSTOM); BLI_strncpy(t->spacename, t->orientation.custom->name, sizeof(t->spacename)); - if (applyTransformOrientation(t->orientation.custom, t->spacemtx, t->spacename)) { /* pass */ } @@ -504,31 +511,17 @@ void initTransformOrientation(bContext *C, TransInfo *t) } break; } - - if (t->orient_matrix_is_set == false) { - t->orient_matrix_is_set = true; - if (t->flag & T_MODAL) { - /* Rotate for example defaults to operating on the view plane. */ - t->orientation.unset = V3D_ORIENT_VIEW; - copy_m3_m4(t->orient_matrix, t->viewinv); - normalize_m3(t->orient_matrix); - } - else { - copy_m3_m3(t->orient_matrix, t->spacemtx); - } - negate_m3(t->orient_matrix); - } } /** * utility function - get first n, selected vert/edge/faces */ -static unsigned int bm_mesh_elems_select_get_n__internal( - BMesh *bm, BMElem **elems, const unsigned int n, const BMIterType itype, const char htype) +static uint bm_mesh_elems_select_get_n__internal( + BMesh *bm, BMElem **elems, const uint n, const BMIterType itype, const char htype) { BMIter iter; BMElem *ele; - unsigned int i; + uint i; BLI_assert(ELEM(htype, BM_VERT, BM_EDGE, BM_FACE)); BLI_assert(ELEM(itype, BM_VERTS_OF_MESH, BM_EDGES_OF_MESH, BM_FACES_OF_MESH)); @@ -579,18 +572,18 @@ static unsigned int bm_mesh_elems_select_get_n__internal( return i; } -static unsigned int bm_mesh_verts_select_get_n(BMesh *bm, BMVert **elems, const unsigned int n) +static uint bm_mesh_verts_select_get_n(BMesh *bm, BMVert **elems, const uint n) { return bm_mesh_elems_select_get_n__internal( bm, (BMElem **)elems, min_ii(n, bm->totvertsel), BM_VERTS_OF_MESH, BM_VERT); } -static unsigned int bm_mesh_edges_select_get_n(BMesh *bm, BMEdge **elems, const unsigned int n) +static uint bm_mesh_edges_select_get_n(BMesh *bm, BMEdge **elems, const uint n) { return bm_mesh_elems_select_get_n__internal( bm, (BMElem **)elems, min_ii(n, bm->totedgesel), BM_EDGES_OF_MESH, BM_EDGE); } #if 0 -static unsigned int bm_mesh_faces_select_get_n(BMesh *bm, BMVert **elems, const unsigned int n) +static uint bm_mesh_faces_select_get_n(BMesh *bm, BMVert **elems, const uint n) { return bm_mesh_elems_select_get_n__internal( bm, (BMElem **)elems, min_ii(n, bm->totfacesel), BM_FACES_OF_MESH, BM_FACE); @@ -1071,10 +1064,9 @@ int getTransformOrientation_ex(const bContext *C, ok = true; } else { - int totsel; - - totsel = count_bone_select(arm, &arm->bonebase, true); - if (totsel) { + int transformed_len; + transformed_len = armature_bone_transflags_update_recursive(arm, &arm->bonebase, true); + if (transformed_len) { /* use channels to get stats */ for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) { if (pchan->bone && pchan->bone->flag & BONE_TRANSFORM) { diff --git a/source/blender/editors/transform/transform_snap.c b/source/blender/editors/transform/transform_snap.c index 4b6ab2045c0..cb4446deb99 100644 --- a/source/blender/editors/transform/transform_snap.c +++ b/source/blender/editors/transform/transform_snap.c @@ -21,36 +21,36 @@ * \ingroup edtransform */ -#include <stdlib.h> -#include <math.h> #include <float.h> +#include <math.h> #include <stdio.h> +#include <stdlib.h> #include "PIL_time.h" -#include "DNA_scene_types.h" -#include "DNA_object_types.h" #include "DNA_meshdata_types.h" /* Temporary, for snapping to other unselected meshes */ #include "DNA_node_types.h" -#include "DNA_space_types.h" +#include "DNA_object_types.h" +#include "DNA_scene_types.h" #include "DNA_screen_types.h" +#include "DNA_space_types.h" #include "DNA_view3d_types.h" #include "DNA_windowmanager_types.h" -#include "BLI_math.h" #include "BLI_blenlib.h" +#include "BLI_math.h" #include "BLI_utildefines.h" #include "GPU_immediate.h" #include "GPU_state.h" -#include "BKE_layer.h" -#include "BKE_object.h" -#include "BKE_anim.h" /* for duplis */ #include "BKE_context.h" +#include "BKE_duplilist.h" #include "BKE_editmesh.h" -#include "BKE_sequencer.h" +#include "BKE_layer.h" #include "BKE_main.h" +#include "BKE_object.h" +#include "BKE_sequencer.h" #include "RNA_access.h" @@ -59,9 +59,9 @@ #include "ED_image.h" #include "ED_markers.h" #include "ED_node.h" +#include "ED_transform_snap_object_context.h" #include "ED_uvedit.h" #include "ED_view3d.h" -#include "ED_transform_snap_object_context.h" #include "DEG_depsgraph.h" @@ -158,7 +158,7 @@ static bool doForceIncrementSnap(const TransInfo *t) void drawSnapping(const struct bContext *C, TransInfo *t) { - unsigned char col[4], selectedCol[4], activeCol[4]; + uchar col[4], selectedCol[4], activeCol[4]; if (!activeSnap(t)) { return; @@ -283,7 +283,7 @@ void drawSnapping(const struct bContext *C, TransInfo *t) } else if (t->spacetype == SPACE_NODE) { if (validSnap(t)) { - ARegion *ar = CTX_wm_region(C); + ARegion *region = CTX_wm_region(C); TransSnapPoint *p; float size; @@ -304,13 +304,13 @@ void drawSnapping(const struct bContext *C, TransInfo *t) immUniformColor4ubv(col); } - ED_node_draw_snap(&ar->v2d, p->co, size, 0, pos); + ED_node_draw_snap(®ion->v2d, p->co, size, 0, pos); } if (t->tsnap.status & POINT_INIT) { immUniformColor4ubv(activeCol); - ED_node_draw_snap(&ar->v2d, t->tsnap.snapPoint, size, t->tsnap.snapNodeBorder, pos); + ED_node_draw_snap(®ion->v2d, t->tsnap.snapPoint, size, t->tsnap.snapNodeBorder, pos); } immUnbindProgram(); @@ -373,10 +373,11 @@ void applyProject(TransInfo *t) copy_v3_v3(iloc, td->ob->obmat[3]); } - if (ED_view3d_project_float_global(t->ar, iloc, mval_fl, V3D_PROJ_TEST_NOP) == + if (ED_view3d_project_float_global(t->region, iloc, mval_fl, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK) { if (ED_transform_snap_object_project_view3d( t->tsnap.object_context, + t->depsgraph, SCE_SNAP_MODE_FACE, &(const struct SnapObjectParams){ .snap_select = t->tsnap.modeSelect, @@ -686,7 +687,7 @@ static void initSnappingMode(TransInfo *t) if (t->spacetype == SPACE_VIEW3D) { if (t->tsnap.object_context == NULL) { t->tsnap.object_context = ED_transform_snap_object_context_create_view3d( - bmain, t->scene, t->depsgraph, 0, t->ar, t->view); + bmain, t->scene, 0, t->region, t->view); ED_transform_snap_object_context_set_editmesh_callbacks( t->tsnap.object_context, @@ -847,7 +848,7 @@ eRedrawFlag updateSelectedSnapPoint(TransInfo *t) for (p = t->tsnap.points.first; p; p = p->next) { float dist_sq; - if (ED_view3d_project_float_global(t->ar, p->co, screen_loc, V3D_PROJ_TEST_NOP) != + if (ED_view3d_project_float_global(t->region, p->co, screen_loc, V3D_PROJ_TEST_NOP) != V3D_PROJ_RET_OK) { continue; } @@ -936,7 +937,7 @@ static void ApplySnapTranslation(TransInfo *t, float vec[3]) else { if (t->spacetype == SPACE_VIEW3D) { if (t->options & CTX_PAINT_CURVE) { - if (ED_view3d_project_float_global(t->ar, point, point, V3D_PROJ_TEST_NOP) != + if (ED_view3d_project_float_global(t->region, point, point, V3D_PROJ_TEST_NOP) != V3D_PROJ_RET_OK) { zero_v3(point); /* no good answer here... */ } @@ -1105,10 +1106,10 @@ static void CalcSnapGeometry(TransInfo *t, float *UNUSED(vec)) } else if (t->spacetype == SPACE_IMAGE && t->obedit_type == OB_MESH) { if (t->tsnap.mode & SCE_SNAP_MODE_VERTEX) { - Image *ima = ED_space_image(t->sa->spacedata.first); + Image *ima = ED_space_image(t->area->spacedata.first); float co[2]; - UI_view2d_region_to_view(&t->ar->v2d, t->mval[0], t->mval[1], &co[0], &co[1]); + UI_view2d_region_to_view(&t->region->v2d, t->mval[0], t->mval[1], &co[0], &co[1]); uint objects_len = 0; Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs( @@ -1365,6 +1366,7 @@ short snapObjectsTransform( float *target = (t->tsnap.status & TARGET_INIT) ? t->tsnap.snapTarget : t->center_global; return ED_transform_snap_object_project_view3d_ex( t->tsnap.object_context, + t->depsgraph, t->scene->toolsettings->snap_mode, &(const struct SnapObjectParams){ .snap_select = t->tsnap.modeSelect, @@ -1389,17 +1391,26 @@ short snapObjectsTransform( /** \name Peeling * \{ */ -bool peelObjectsSnapContext(SnapObjectContext *sctx, - const float mval[2], - const struct SnapObjectParams *params, - const bool use_peel_object, - /* return args */ - float r_loc[3], - float r_no[3], - float *r_thickness) +bool peelObjectsTransform(TransInfo *t, + const float mval[2], + const bool use_peel_object, + /* return args */ + float r_loc[3], + float r_no[3], + float *r_thickness) { ListBase depths_peel = {0}; - ED_transform_snap_object_project_all_view3d_ex(sctx, params, mval, -1.0f, false, &depths_peel); + ED_transform_snap_object_project_all_view3d_ex( + t->tsnap.object_context, + t->depsgraph, + &(const struct SnapObjectParams){ + .snap_select = t->tsnap.modeSelect, + .use_object_edit_cage = (t->flag & T_EDIT) != 0, + }, + mval, + -1.0f, + false, + &depths_peel); if (!BLI_listbase_is_empty(&depths_peel)) { /* At the moment we only use the hits of the first object */ @@ -1455,26 +1466,6 @@ bool peelObjectsSnapContext(SnapObjectContext *sctx, return false; } -bool peelObjectsTransform(TransInfo *t, - const float mval[2], - const bool use_peel_object, - /* return args */ - float r_loc[3], - float r_no[3], - float *r_thickness) -{ - return peelObjectsSnapContext(t->tsnap.object_context, - mval, - &(const struct SnapObjectParams){ - .snap_select = t->tsnap.modeSelect, - .use_object_edit_cage = (t->flag & T_EDIT) != 0, - }, - use_peel_object, - r_loc, - r_no, - r_thickness); -} - /** \} */ /* -------------------------------------------------------------------- */ @@ -1504,14 +1495,14 @@ static NodeBorder snapNodeBorder(int snap_node_mode) static bool snapNode(ToolSettings *ts, SpaceNode *UNUSED(snode), - ARegion *ar, + ARegion *region, bNode *node, const int mval[2], float r_loc[2], float *r_dist_px, char *r_node_border) { - View2D *v2d = &ar->v2d; + View2D *v2d = ®ion->v2d; NodeBorder border = snapNodeBorder(ts->snap_node_mode); bool retval = false; rcti totr; @@ -1564,7 +1555,7 @@ static bool snapNode(ToolSettings *ts, static bool snapNodes(ToolSettings *ts, SpaceNode *snode, - ARegion *ar, + ARegion *region, const int mval[2], eSnapSelect snap_select, float r_loc[2], @@ -1578,8 +1569,8 @@ static bool snapNodes(ToolSettings *ts, *r_node_border = 0; for (node = ntree->nodes.first; node; node = node->next) { - if (snapNodeTest(&ar->v2d, node, snap_select)) { - retval |= snapNode(ts, snode, ar, node, mval, r_loc, r_dist_px, r_node_border); + if (snapNodeTest(®ion->v2d, node, snap_select)) { + retval |= snapNode(ts, snode, region, node, mval, r_loc, r_dist_px, r_node_border); } } @@ -1590,8 +1581,8 @@ bool snapNodesTransform( TransInfo *t, const int mval[2], float r_loc[2], float *r_dist_px, char *r_node_border) { return snapNodes(t->settings, - t->sa->spacedata.first, - t->ar, + t->area->spacedata.first, + t->region, mval, t->tsnap.modeSelect, r_loc, @@ -1691,7 +1682,7 @@ void snapSequenceBounds(TransInfo *t, const int mval[2]) } /* convert to frame range */ - UI_view2d_region_to_view(&t->ar->v2d, mval[0], mval[1], &xmouse, &ymouse); + UI_view2d_region_to_view(&t->region->v2d, mval[0], mval[1], &xmouse, &ymouse); mframe = round_fl_to_int(xmouse); /* now find the closest sequence */ frame = BKE_sequencer_find_next_prev_edit(t->scene, mframe, SEQ_SIDE_BOTH, true, false, true); @@ -1723,9 +1714,9 @@ static void applyGridIncrement( if (use_aspect) { /* custom aspect for fcurve */ if (t->spacetype == SPACE_GRAPH) { - View2D *v2d = &t->ar->v2d; + View2D *v2d = &t->region->v2d; Scene *scene = t->scene; - SpaceGraph *sipo = t->sa->spacedata.first; + SpaceGraph *sipo = t->area->spacedata.first; asp_local[0] = UI_view2d_grid_resolution_x__frames_or_seconds( v2d, scene, sipo->flag & SIPO_DRAWTIME); asp_local[1] = UI_view2d_grid_resolution_y__values(v2d); diff --git a/source/blender/editors/transform/transform_snap.h b/source/blender/editors/transform/transform_snap.h index a188e2eb829..c088cf80f0d 100644 --- a/source/blender/editors/transform/transform_snap.h +++ b/source/blender/editors/transform/transform_snap.h @@ -35,14 +35,6 @@ bool peelObjectsTransform(struct TransInfo *t, float r_loc[3], float r_no[3], float *r_thickness); -bool peelObjectsSnapContext(struct SnapObjectContext *sctx, - const float mval[2], - const struct SnapObjectParams *params, - const bool use_peel_object, - /* return args */ - float r_loc[3], - float r_no[3], - float *r_thickness); short snapObjectsTransform(struct TransInfo *t, const float mval[2], diff --git a/source/blender/editors/transform/transform_snap_object.c b/source/blender/editors/transform/transform_snap_object.c index 63b9eb3937a..2cfeedbb346 100644 --- a/source/blender/editors/transform/transform_snap_object.c +++ b/source/blender/editors/transform/transform_snap_object.c @@ -19,50 +19,44 @@ */ #include <stdlib.h> -#include <math.h> -#include <float.h> -#include <stdio.h> #include "MEM_guardedalloc.h" -#include "BLI_math.h" -#include "BLI_kdopbvh.h" -#include "BLI_memarena.h" #include "BLI_ghash.h" +#include "BLI_kdopbvh.h" #include "BLI_listbase.h" +#include "BLI_math.h" +#include "BLI_memarena.h" #include "BLI_utildefines.h" #include "DNA_armature_types.h" #include "DNA_curve_types.h" -#include "DNA_scene_types.h" -#include "DNA_object_types.h" #include "DNA_mesh_types.h" #include "DNA_meshdata_types.h" +#include "DNA_object_types.h" +#include "DNA_scene_types.h" #include "DNA_screen_types.h" #include "DNA_view3d_types.h" -#include "BKE_bvhutils.h" #include "BKE_armature.h" +#include "BKE_bvhutils.h" #include "BKE_curve.h" -#include "BKE_object.h" -#include "BKE_anim.h" /* for duplis */ +#include "BKE_duplilist.h" #include "BKE_editmesh.h" #include "BKE_layer.h" #include "BKE_main.h" -#include "BKE_tracking.h" -#include "BKE_context.h" #include "BKE_mesh.h" #include "BKE_mesh_runtime.h" +#include "BKE_object.h" +#include "BKE_tracking.h" -#include "DEG_depsgraph.h" #include "DEG_depsgraph_query.h" -#include "ED_transform.h" +#include "ED_armature.h" #include "ED_transform_snap_object_context.h" #include "ED_view3d.h" -#include "ED_armature.h" -#include "transform.h" +#include "ED_transform.h" /* -------------------------------------------------------------------- */ /** \name Internal Data Types @@ -92,30 +86,32 @@ typedef struct SnapObjectData { SNAP_MESH = 1, SNAP_EDIT_MESH, } type; -} SnapObjectData; - -typedef struct SnapObjectData_Mesh { - SnapObjectData sd; - BVHTreeFromMesh treedata; - const struct MPoly *poly; - BVHTree *bvhtree[2]; /* from loose verts and from loose edges */ - uint has_looptris : 1; - uint has_loose_edge : 1; - uint has_loose_vert : 1; -} SnapObjectData_Mesh; + BVHTree *bvhtree[2]; /* MESH: loose edges, loose verts + * EDIT_MESH: verts, edges. */ + bool cached[2]; -typedef struct SnapObjectData_EditMesh { - SnapObjectData sd; - BVHTreeFromEditMesh *bvh_trees[3]; - float min[3], max[3]; - -} SnapObjectData_EditMesh; + union { + struct { + /* SNAP_MESH */ + BVHTreeFromMesh treedata_mesh; + const struct MPoly *poly; + uint has_looptris : 1; + uint has_loose_edge : 1; + uint has_loose_vert : 1; + }; + struct { + /* SNAP_EDIT_MESH */ + BVHTreeFromEditMesh treedata_editmesh; + float min[3], max[3]; + struct LinkNode **bvh_cache_p; + }; + }; +} SnapObjectData; struct SnapObjectContext { Main *bmain; Scene *scene; - Depsgraph *depsgraph; int flag; @@ -124,7 +120,7 @@ struct SnapObjectContext { bool use_v3d; struct { const struct View3D *v3d; - const struct ARegion *ar; + const struct ARegion *region; } v3d_data; /* Object -> SnapObjectData map */ @@ -149,7 +145,7 @@ struct SnapObjectContext { /** \} */ /* -------------------------------------------------------------------- */ -/** \name Common Utilities +/** \name Snap Object Data * \{ */ /** @@ -166,6 +162,45 @@ static void bm_mesh_minmax(BMesh *bm, float r_min[3], float r_max[3]) } } +static void snap_object_data_mesh_clear(SnapObjectData *sod) +{ + BLI_assert(sod->type == SNAP_MESH); + for (int i = 0; i < ARRAY_SIZE(sod->bvhtree); i++) { + if (!sod->cached[i]) { + BLI_bvhtree_free(sod->bvhtree[i]); + } + sod->bvhtree[i] = NULL; + } + free_bvhtree_from_mesh(&sod->treedata_mesh); +} + +static void snap_object_data_editmesh_clear(SnapObjectData *sod) +{ + BLI_assert(sod->type == SNAP_EDIT_MESH); + for (int i = 0; i < ARRAY_SIZE(sod->bvhtree); i++) { + if (!sod->cached[i]) { + BLI_bvhtree_free(sod->bvhtree[i]); + } + sod->bvhtree[i] = NULL; + } + free_bvhtree_from_editmesh(&sod->treedata_editmesh); +} + +static void snap_object_data_clear(SnapObjectData *sod) +{ + switch (sod->type) { + case SNAP_MESH: { + snap_object_data_mesh_clear(sod); + break; + } + case SNAP_EDIT_MESH: { + snap_object_data_editmesh_clear(sod); + break; + } + } + memset(&sod->type, 0x0, sizeof(*sod) - offsetof(SnapObjectData, type)); +} + static SnapObjectData *snap_object_data_lookup(SnapObjectContext *sctx, Object *ob) { SnapObjectData *sod = BLI_ghash_lookup(sctx->cache.object_map, ob); @@ -181,29 +216,55 @@ static SnapObjectData *snap_object_data_lookup(SnapObjectContext *sctx, Object * return sod; } -static SnapObjectData_Mesh *snap_object_data_mesh_get(SnapObjectContext *sctx, Object *ob) +static SnapObjectData *snap_object_data_mesh_get(SnapObjectContext *sctx, Object *ob) { + SnapObjectData *sod; void **sod_p; + bool init = false; + if (BLI_ghash_ensure_p(sctx->cache.object_map, ob, &sod_p)) { - BLI_assert(((SnapObjectData *)*sod_p)->type == SNAP_MESH); + sod = *sod_p; + if (sod->type != SNAP_MESH) { + snap_object_data_clear(sod); + init = true; + } } else { - SnapObjectData_Mesh *sod = *sod_p = BLI_memarena_calloc(sctx->cache.mem_arena, sizeof(*sod)); - sod->sd.type = SNAP_MESH; + sod = *sod_p = BLI_memarena_calloc(sctx->cache.mem_arena, sizeof(*sod)); + init = true; + } + + if (init) { + sod->type = SNAP_MESH; /* start assuming that it has each of these element types */ sod->has_looptris = true; sod->has_loose_edge = true; sod->has_loose_vert = true; } - return *sod_p; + return sod; } -static SnapObjectData_EditMesh *snap_object_data_editmesh_get(SnapObjectContext *sctx, - Object *ob, - BMEditMesh *em) +static struct LinkNode **snap_object_data_editmesh_bvh_cache_get(Object *ob) { + BMEditMesh *em = BKE_editmesh_from_object(ob); + if (em->mesh_eval_final) { + return &em->mesh_eval_final->runtime.bvh_cache; + } + if (em->mesh_eval_cage) { + return &em->mesh_eval_cage->runtime.bvh_cache; + } + + return &((Mesh *)ob->data)->runtime.bvh_cache; +} + +static SnapObjectData *snap_object_data_editmesh_get(SnapObjectContext *sctx, + Object *ob, + BMEditMesh *em) +{ + SnapObjectData *sod; void **sod_p; + bool init = false, init_min_max = true, clear_cache = false; { /* Use object-data as the key in ghash since the editmesh @@ -221,18 +282,83 @@ static SnapObjectData_EditMesh *snap_object_data_editmesh_get(SnapObjectContext } if (BLI_ghash_ensure_p(sctx->cache.object_map, ob, &sod_p)) { - BLI_assert(((SnapObjectData *)*sod_p)->type == SNAP_EDIT_MESH); + sod = *sod_p; + bool clear = false; + /* Check if the geometry has changed. */ + if (sod->type != SNAP_EDIT_MESH) { + clear = true; + } + else if (sod->treedata_editmesh.em != em) { + clear_cache = true; + init = true; + } + else if (sod->bvh_cache_p) { + if (sod->bvh_cache_p != snap_object_data_editmesh_bvh_cache_get(ob)) { + clear_cache = true; + init = true; + } + else if (sod->treedata_editmesh.tree && sod->treedata_editmesh.cached && + !bvhcache_has_tree(*sod->bvh_cache_p, sod->treedata_editmesh.tree)) { + /* The tree is owned by the EditMesh and may have been freed since we last used! */ + clear = true; + } + else if (sod->bvhtree[0] && sod->cached[0] && + !bvhcache_has_tree(*sod->bvh_cache_p, sod->bvhtree[0])) { + /* The tree is owned by the EditMesh and may have been freed since we last used! */ + clear = true; + } + else if (sod->bvhtree[1] && sod->cached[1] && + !bvhcache_has_tree(*sod->bvh_cache_p, sod->bvhtree[1])) { + /* The tree is owned by the EditMesh and may have been freed since we last used! */ + clear = true; + } + } + + if (clear) { + snap_object_data_clear(sod); + init = true; + } } else { - SnapObjectData_EditMesh *sod = *sod_p = BLI_memarena_calloc(sctx->cache.mem_arena, - sizeof(*sod)); - sod->sd.type = SNAP_EDIT_MESH; - bm_mesh_minmax(em->bm, sod->min, sod->max); + sod = *sod_p = BLI_memarena_calloc(sctx->cache.mem_arena, sizeof(*sod)); + init = true; + } + + if (init) { + sod->type = SNAP_EDIT_MESH; + sod->treedata_editmesh.em = em; + + if (clear_cache) { + /* Only init min and max when you have a non-custom bvhtree pending. */ + init_min_max = false; + if (sod->treedata_editmesh.cached) { + sod->treedata_editmesh.tree = NULL; + init_min_max = true; + } + for (int i = 0; i < ARRAY_SIZE(sod->bvhtree); i++) { + if (sod->cached[i]) { + sod->bvhtree[i] = NULL; + init_min_max = true; + } + } + } + + if (init_min_max) { + bm_mesh_minmax(em->bm, sod->min, sod->max); + } + + sod->bvh_cache_p = snap_object_data_editmesh_bvh_cache_get(ob); } - return *sod_p; + return sod; } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Iterator + * \{ */ + typedef void (*IterSnapObjsCallback)(SnapObjectContext *sctx, bool is_obedit, bool use_backface_culling, @@ -247,11 +373,12 @@ typedef void (*IterSnapObjsCallback)(SnapObjectContext *sctx, * \param snap_select: from enum #eSnapSelect. */ static void iter_snap_objects(SnapObjectContext *sctx, + Depsgraph *depsgraph, const struct SnapObjectParams *params, IterSnapObjsCallback sob_callback, void *data) { - ViewLayer *view_layer = DEG_get_input_view_layer(sctx->depsgraph); + ViewLayer *view_layer = DEG_get_input_view_layer(depsgraph); const View3D *v3d = sctx->v3d_data.v3d; const eSnapSelect snap_select = params->snap_select; const bool use_object_edit_cage = params->use_object_edit_cage; @@ -282,10 +409,10 @@ static void iter_snap_objects(SnapObjectContext *sctx, } } - Object *obj_eval = DEG_get_evaluated_object(sctx->depsgraph, base->object); + Object *obj_eval = DEG_get_evaluated_object(depsgraph, base->object); if (obj_eval->transflag & OB_DUPLI) { DupliObject *dupli_ob; - ListBase *lb = object_duplilist(sctx->depsgraph, sctx->scene, obj_eval); + ListBase *lb = object_duplilist(depsgraph, sctx->scene, obj_eval); for (dupli_ob = lb->first; dupli_ob; dupli_ob = dupli_ob->next) { sob_callback( sctx, use_object_edit_cage, use_backface_culling, dupli_ob->ob, dupli_ob->mat, data); @@ -320,7 +447,7 @@ struct RayCastAll_Data { float local_scale; Object *ob; - unsigned int ob_uuid; + uint ob_uuid; /* output data */ ListBase *hit_list; @@ -333,7 +460,7 @@ static struct SnapObjectHitDepth *hit_depth_create(const float depth, int index, Object *ob, const float obmat[4][4], - unsigned int ob_uuid) + uint ob_uuid) { struct SnapObjectHitDepth *hit = MEM_mallocN(sizeof(*hit), __func__); @@ -459,7 +586,7 @@ static bool raycastMesh(SnapObjectContext *sctx, Object *ob, Mesh *me, const float obmat[4][4], - const unsigned int ob_index, + const uint ob_index, bool use_hide, bool use_backface_culling, /* read/write args */ @@ -516,9 +643,9 @@ static bool raycastMesh(SnapObjectContext *sctx, len_diff = 0.0f; } - SnapObjectData_Mesh *sod = snap_object_data_mesh_get(sctx, ob); + SnapObjectData *sod = snap_object_data_mesh_get(sctx, ob); - BVHTreeFromMesh *treedata = &sod->treedata; + BVHTreeFromMesh *treedata = &sod->treedata_mesh; /* The tree is owned by the Mesh and may have been freed since we last used. */ if (treedata->tree) { @@ -634,7 +761,7 @@ static bool raycastEditMesh(SnapObjectContext *sctx, Object *ob, BMEditMesh *em, const float obmat[4][4], - const unsigned int ob_index, + const uint ob_index, bool use_backface_culling, /* read/write args */ float *ray_depth, @@ -668,7 +795,7 @@ static bool raycastEditMesh(SnapObjectContext *sctx, local_depth *= local_scale; } - SnapObjectData_EditMesh *sod = snap_object_data_editmesh_get(sctx, ob, em); + SnapObjectData *sod = snap_object_data_editmesh_get(sctx, ob, em); /* Test BoundBox */ @@ -690,30 +817,18 @@ static bool raycastEditMesh(SnapObjectContext *sctx, len_diff = 0.0f; } - if (sod->bvh_trees[2] == NULL) { - sod->bvh_trees[2] = BLI_memarena_calloc(sctx->cache.mem_arena, sizeof(BVHTreeFromEditMesh)); - } - - BVHTreeFromEditMesh *treedata = sod->bvh_trees[2]; - - BVHCache **em_bvh_cache = &((Mesh *)ob->data)->runtime.bvh_cache; - - if (sctx->callbacks.edit_mesh.test_face_fn == NULL) { - /* The tree is owned by the Mesh and may have been freed since we last used! */ - if (treedata->tree && !bvhcache_has_tree(*em_bvh_cache, treedata->tree)) { - free_bvhtree_from_editmesh(treedata); - } - } + BVHTreeFromEditMesh *treedata = &sod->treedata_editmesh; if (treedata->tree == NULL) { - /* Get original version of the edit_mesh. */ - BMEditMesh *em_orig = BKE_editmesh_from_object(DEG_get_original_object(ob)); + /* Operators only update the editmesh looptris of the original mesh. */ + BLI_assert(sod->treedata_editmesh.em == BKE_editmesh_from_object(DEG_get_original_object(ob))); + em = sod->treedata_editmesh.em; if (sctx->callbacks.edit_mesh.test_face_fn) { - BMesh *bm = em_orig->bm; - BLI_assert(poly_to_tri_count(bm->totface, bm->totloop) == em_orig->tottri); + BMesh *bm = em->bm; + BLI_assert(poly_to_tri_count(bm->totface, bm->totloop) == em->tottri); - BLI_bitmap *elem_mask = BLI_BITMAP_NEW(em_orig->tottri, __func__); + BLI_bitmap *elem_mask = BLI_BITMAP_NEW(em->tottri, __func__); int looptri_num_active = BM_iter_mesh_bitmap_from_filter_tessface( bm, elem_mask, @@ -721,14 +836,14 @@ static bool raycastEditMesh(SnapObjectContext *sctx, sctx->callbacks.edit_mesh.user_data); bvhtree_from_editmesh_looptri_ex( - treedata, em_orig, elem_mask, looptri_num_active, 0.0f, 4, 6, 0, NULL); + treedata, em, elem_mask, looptri_num_active, 0.0f, 4, 6, 0, NULL); MEM_freeN(elem_mask); } else { /* Only cache if bvhtree is created without a mask. * This helps keep a standardized bvhtree in cache. */ - BKE_bvhtree_from_editmesh_get(treedata, em_orig, 4, BVHTREE_FROM_EM_LOOPTRI, em_bvh_cache); + BKE_bvhtree_from_editmesh_get(treedata, em, 4, BVHTREE_FROM_EM_LOOPTRI, sod->bvh_cache_p); } if (treedata->tree == NULL) { @@ -795,10 +910,9 @@ static bool raycastEditMesh(SnapObjectContext *sctx, retval = true; if (r_index) { - /* Get original version of the edit_mesh. */ - BMEditMesh *em_orig = BKE_editmesh_from_object(DEG_get_original_object(ob)); + em = sod->treedata_editmesh.em; - *r_index = BM_elem_index_get(em_orig->looptris[hit.index][0]->f); + *r_index = BM_elem_index_get(em->looptris[hit.index][0]->f); } } } @@ -817,7 +931,7 @@ static bool raycastObj(SnapObjectContext *sctx, const float ray_dir[3], Object *ob, const float obmat[4][4], - const unsigned int ob_index, + const uint ob_index, bool use_obedit, bool use_occlusion_test, bool use_backface_culling, @@ -850,13 +964,14 @@ static bool raycastObj(SnapObjectContext *sctx, Mesh *me = ob->data; bool use_hide = false; if (BKE_object_is_in_editmode(ob)) { - BMEditMesh *em = BKE_editmesh_from_object(ob); if (use_obedit) { + /* Operators only update the editmesh looptris of the original mesh. */ + BMEditMesh *em_orig = BKE_editmesh_from_object(DEG_get_original_object(ob)); retval = raycastEditMesh(sctx, ray_start, ray_dir, ob, - em, + em_orig, obmat, ob_index, use_backface_culling, @@ -867,9 +982,12 @@ static bool raycastObj(SnapObjectContext *sctx, r_hit_list); break; } - else if (em->mesh_eval_final) { - me = em->mesh_eval_final; - use_hide = true; + else { + BMEditMesh *em = BKE_editmesh_from_object(ob); + if (em->mesh_eval_final) { + me = em->mesh_eval_final; + use_hide = true; + } } } retval = raycastMesh(sctx, @@ -891,12 +1009,13 @@ static bool raycastObj(SnapObjectContext *sctx, case OB_CURVE: case OB_SURF: case OB_FONT: { - if (ob->runtime.mesh_eval) { + Mesh *mesh_eval = BKE_object_get_evaluated_mesh(ob); + if (mesh_eval) { retval = raycastMesh(sctx, ray_start, ray_dir, ob, - ob->runtime.mesh_eval, + mesh_eval, obmat, ob_index, false, @@ -927,7 +1046,7 @@ static bool raycastObj(SnapObjectContext *sctx, struct RaycastObjUserData { const float *ray_start; const float *ray_dir; - unsigned int ob_index; + uint ob_index; /* read/write args */ float *ray_depth; /* return args */ @@ -997,6 +1116,7 @@ static void raycast_obj_cb(SnapObjectContext *sctx, * \param r_hit_list: List of #SnapObjectHitDepth (caller must free). */ static bool raycastObjects(SnapObjectContext *sctx, + Depsgraph *depsgraph, const struct SnapObjectParams *params, const float ray_start[3], const float ray_dir[3], @@ -1025,7 +1145,7 @@ static bool raycastObjects(SnapObjectContext *sctx, .ret = false, }; - iter_snap_objects(sctx, params, raycast_obj_cb, &data); + iter_snap_objects(sctx, depsgraph, params, raycast_obj_cb, &data); return data.ret; } @@ -1037,7 +1157,7 @@ static bool raycastObjects(SnapObjectContext *sctx, * \{ */ /* Test BoundBox */ -static bool snap_bound_box_check_dist(float min[3], +static bool snap_bound_box_check_dist(const float min[3], const float max[3], const float lpmat[4][4], const float win_size[2], @@ -1107,7 +1227,7 @@ static void cb_mlooptri_edges_get(const int index, int v_index[3], const BVHTree const MLoopTri *lt = &data->looptri[index]; for (int j = 2, j_next = 0; j_next < 3; j = j_next++) { const MEdge *ed = &medge[mloop[lt->tri[j]].e]; - unsigned int tri_edge[2] = {mloop[lt->tri[j]].v, mloop[lt->tri[j_next]].v}; + uint tri_edge[2] = {mloop[lt->tri[j]].v, mloop[lt->tri[j_next]].v}; if (ELEM(ed->v1, tri_edge[0], tri_edge[1]) && ELEM(ed->v2, tri_edge[0], tri_edge[1])) { // printf("real edge found\n"); v_index[j] = mloop[lt->tri[j]].e; @@ -1392,7 +1512,7 @@ static short snap_mesh_polygon(SnapObjectContext *sctx, BVHTreeNearest nearest = { .index = -1, - .dist_sq = SQUARE(*dist_px), + .dist_sq = square_f(*dist_px), }; SnapObjectData *sod = snap_object_data_lookup(sctx, ob); @@ -1400,14 +1520,14 @@ static short snap_mesh_polygon(SnapObjectContext *sctx, BLI_assert(sod != NULL); if (sod->type == SNAP_MESH) { - BVHTreeFromMesh *treedata = &((SnapObjectData_Mesh *)sod)->treedata; + BVHTreeFromMesh *treedata = &sod->treedata_mesh; nearest2d.userdata = treedata; nearest2d.get_vert_co = (Nearest2DGetVertCoCallback)cb_mvert_co_get; nearest2d.get_edge_verts_index = (Nearest2DGetEdgeVertsCallback)cb_medge_verts_get; nearest2d.copy_vert_no = (Nearest2DCopyVertNoCallback)cb_mvert_no_copy; - const MPoly *mp = &((SnapObjectData_Mesh *)sod)->poly[*r_index]; + const MPoly *mp = &sod->poly[*r_index]; const MLoop *ml = &treedata->loop[mp->loopstart]; if (snapdata->snap_to_flag & SCE_SNAP_MODE_EDGE) { elem = SCE_SNAP_MODE_EDGE; @@ -1435,7 +1555,7 @@ static short snap_mesh_polygon(SnapObjectContext *sctx, } else { BLI_assert(sod->type == SNAP_EDIT_MESH); - BMEditMesh *em = BKE_editmesh_from_object(ob); + BMEditMesh *em = sod->treedata_editmesh.em; nearest2d.userdata = em; nearest2d.get_vert_co = (Nearest2DGetVertCoCallback)cb_bvert_co_get; @@ -1525,14 +1645,14 @@ static short snap_mesh_edge_verts_mixed(SnapObjectContext *sctx, nearest2d.is_persp = snapdata->view_proj == VIEW_PROJ_PERSP; nearest2d.use_backface_culling = use_backface_culling; if (sod->type == SNAP_MESH) { - nearest2d.userdata = &((SnapObjectData_Mesh *)sod)->treedata; + nearest2d.userdata = &sod->treedata_mesh; nearest2d.get_vert_co = (Nearest2DGetVertCoCallback)cb_mvert_co_get; nearest2d.get_edge_verts_index = (Nearest2DGetEdgeVertsCallback)cb_medge_verts_get; nearest2d.copy_vert_no = (Nearest2DCopyVertNoCallback)cb_mvert_no_copy; } else { BLI_assert(sod->type == SNAP_EDIT_MESH); - nearest2d.userdata = BKE_editmesh_from_object(ob); + nearest2d.userdata = sod->treedata_editmesh.em; nearest2d.get_vert_co = (Nearest2DGetVertCoCallback)cb_bvert_co_get; nearest2d.get_edge_verts_index = (Nearest2DGetEdgeVertsCallback)cb_bedge_verts_get; nearest2d.copy_vert_no = (Nearest2DCopyVertNoCallback)cb_bvert_no_copy; @@ -1557,7 +1677,7 @@ static short snap_mesh_edge_verts_mixed(SnapObjectContext *sctx, BVHTreeNearest nearest = { .index = -1, - .dist_sq = SQUARE(original_dist_px), + .dist_sq = square_f(original_dist_px), }; float lambda; @@ -1690,7 +1810,7 @@ static short snapArmature(SnapData *snapdata, return retval; } - float lpmat[4][4], dist_px_sq = SQUARE(*dist_px); + float lpmat[4][4], dist_px_sq = square_f(*dist_px); mul_m4_m4m4(lpmat, snapdata->pmat, obmat); struct DistProjectedAABBPrecalc neasrest_precalc; @@ -1718,7 +1838,7 @@ static short snapArmature(SnapData *snapdata, bArmature *arm = ob->data; if (arm->edbo) { - for (EditBone *eBone = arm->edbo->first; eBone; eBone = eBone->next) { + LISTBASE_FOREACH (EditBone *, eBone, arm->edbo) { if (eBone->layer & arm->layer) { /* skip hidden or moving (selected) bones */ if ((eBone->flag & (BONE_HIDDEN_A | BONE_ROOTSEL | BONE_TIPSEL)) == 0) { @@ -1761,7 +1881,7 @@ static short snapArmature(SnapData *snapdata, } } else if (ob->pose && ob->pose->chanbase.first) { - for (bPoseChannel *pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) { + LISTBASE_FOREACH (bPoseChannel *, pchan, &ob->pose->chanbase) { Bone *bone = pchan->bone; /* skip hidden bones */ if (bone && !(bone->flag & (BONE_HIDDEN_P | BONE_HIDDEN_PG))) { @@ -1837,7 +1957,7 @@ static short snapCurve(SnapData *snapdata, } Curve *cu = ob->data; - float dist_px_sq = SQUARE(*dist_px); + float dist_px_sq = square_f(*dist_px); float lpmat[4][4]; mul_m4_m4m4(lpmat, snapdata->pmat, obmat); @@ -1998,7 +2118,7 @@ static short snapEmpty(SnapData *snapdata, } bool is_persp = snapdata->view_proj == VIEW_PROJ_PERSP; - float dist_px_sq = SQUARE(*dist_px); + float dist_px_sq = square_f(*dist_px); float co[3]; copy_v3_v3(co, obmat[3]); if (test_projected_vert_dist(&neasrest_precalc, @@ -2040,7 +2160,7 @@ static short snapCamera(const SnapObjectContext *sctx, Scene *scene = sctx->scene; bool is_persp = snapdata->view_proj == VIEW_PROJ_PERSP; - float dist_px_sq = SQUARE(*dist_px); + float dist_px_sq = square_f(*dist_px); float orig_camera_mat[4][4], orig_camera_imat[4][4], imat[4][4]; MovieClip *clip = BKE_object_movieclip_get(scene, object, false); @@ -2055,7 +2175,7 @@ static short snapCamera(const SnapObjectContext *sctx, tracking = &clip->tracking; - BKE_tracking_get_camera_object_matrix(scene, object, orig_camera_mat); + BKE_tracking_get_camera_object_matrix(object, orig_camera_mat); invert_m4_m4(orig_camera_imat, orig_camera_mat); invert_m4_m4(imat, obmat); @@ -2151,7 +2271,7 @@ static short snapMesh(SnapObjectContext *sctx, float lpmat[4][4]; mul_m4_m4m4(lpmat, snapdata->pmat, obmat); - float dist_px_sq = SQUARE(*dist_px); + float dist_px_sq = square_f(*dist_px); /* Test BoundBox */ BoundBox *bb = BKE_mesh_boundbox_get(ob); @@ -2160,27 +2280,23 @@ static short snapMesh(SnapObjectContext *sctx, return 0; } - SnapObjectData_Mesh *sod = snap_object_data_mesh_get(sctx, ob); + SnapObjectData *sod = snap_object_data_mesh_get(sctx, ob); BVHTreeFromMesh *treedata, dummy_treedata; - BVHTree **bvhtree; - treedata = &sod->treedata; - bvhtree = sod->bvhtree; + treedata = &sod->treedata_mesh; /* The tree is owned by the Mesh and may have been freed since we last used! */ - if ((sod->has_looptris && treedata->tree && - !bvhcache_has_tree(me->runtime.bvh_cache, treedata->tree)) || - (sod->has_loose_edge && bvhtree[0] && - !bvhcache_has_tree(me->runtime.bvh_cache, bvhtree[0])) || - (sod->has_loose_vert && bvhtree[1] && - !bvhcache_has_tree(me->runtime.bvh_cache, bvhtree[1]))) { - BLI_assert(!treedata->tree || !bvhcache_has_tree(me->runtime.bvh_cache, treedata->tree)); - BLI_assert(!bvhtree[0] || !bvhcache_has_tree(me->runtime.bvh_cache, bvhtree[0])); - BLI_assert(!bvhtree[1] || !bvhcache_has_tree(me->runtime.bvh_cache, bvhtree[1])); - + if (treedata->cached && treedata->tree && + !bvhcache_has_tree(me->runtime.bvh_cache, treedata->tree)) { free_bvhtree_from_mesh(treedata); - bvhtree[0] = NULL; - bvhtree[1] = NULL; + } + if (sod->cached[0] && sod->bvhtree[0] && + !bvhcache_has_tree(me->runtime.bvh_cache, sod->bvhtree[0])) { + sod->bvhtree[0] = NULL; + } + if (sod->cached[1] && sod->bvhtree[1] && + !bvhcache_has_tree(me->runtime.bvh_cache, sod->bvhtree[1])) { + sod->bvhtree[1] = NULL; } if (sod->has_looptris && treedata->tree == NULL) { @@ -2191,9 +2307,10 @@ static short snapMesh(SnapObjectContext *sctx, treedata->edge = me->medge; /* CustomData_get_layer(&me->edata, CD_MEDGE);? */ } } - if (sod->has_loose_edge && bvhtree[0] == NULL) { - bvhtree[0] = BKE_bvhtree_from_mesh_get(&dummy_treedata, me, BVHTREE_FROM_LOOSEEDGES, 2); - sod->has_loose_edge = bvhtree[0] != NULL; + if (sod->has_loose_edge && sod->bvhtree[0] == NULL) { + sod->bvhtree[0] = BKE_bvhtree_from_mesh_get(&dummy_treedata, me, BVHTREE_FROM_LOOSEEDGES, 2); + sod->has_loose_edge = sod->bvhtree[0] != NULL; + sod->cached[0] = dummy_treedata.cached; if (sod->has_loose_edge) { BLI_assert(treedata->vert_allocated == false); @@ -2206,9 +2323,10 @@ static short snapMesh(SnapObjectContext *sctx, } } if (snapdata->snap_to_flag & SCE_SNAP_MODE_VERTEX) { - if (sod->has_loose_vert && bvhtree[1] == NULL) { - bvhtree[1] = BKE_bvhtree_from_mesh_get(&dummy_treedata, me, BVHTREE_FROM_LOOSEVERTS, 2); - sod->has_loose_vert = bvhtree[1] != NULL; + if (sod->has_loose_vert && sod->bvhtree[1] == NULL) { + sod->bvhtree[1] = BKE_bvhtree_from_mesh_get(&dummy_treedata, me, BVHTREE_FROM_LOOSEVERTS, 2); + sod->has_loose_vert = sod->bvhtree[1] != NULL; + sod->cached[1] = dummy_treedata.cached; if (sod->has_loose_vert) { BLI_assert(treedata->vert_allocated == false); @@ -2226,7 +2344,7 @@ static short snapMesh(SnapObjectContext *sctx, if (treedata->vert_allocated == false) { treedata->vert = me->mvert; /* CustomData_get_layer(&me->vdata, CD_MVERT);? */ } - if (treedata->tree || bvhtree[0]) { + if (treedata->tree || sod->bvhtree[0]) { if (treedata->edge_allocated == false) { /* If raycast has been executed before, `treedata->edge` can be NULL. */ treedata->edge = me->medge; /* CustomData_get_layer(&me->edata, CD_MEDGE);? */ @@ -2263,9 +2381,9 @@ static short snapMesh(SnapObjectContext *sctx, mul_v4_m4v4(clip_planes_local[i], tobmat, snapdata->clip_plane[i]); } - if (bvhtree[1] && (snapdata->snap_to_flag & SCE_SNAP_MODE_VERTEX)) { + if (sod->bvhtree[1] && (snapdata->snap_to_flag & SCE_SNAP_MODE_VERTEX)) { /* snap to loose verts */ - BLI_bvhtree_find_nearest_projected(bvhtree[1], + BLI_bvhtree_find_nearest_projected(sod->bvhtree[1], lpmat, snapdata->win_size, snapdata->mval, @@ -2279,9 +2397,9 @@ static short snapMesh(SnapObjectContext *sctx, } if (snapdata->snap_to_flag & SCE_SNAP_MODE_EDGE) { - if (bvhtree[0]) { + if (sod->bvhtree[0]) { /* snap to loose edges */ - BLI_bvhtree_find_nearest_projected(bvhtree[0], + BLI_bvhtree_find_nearest_projected(sod->bvhtree[0], lpmat, snapdata->win_size, snapdata->mval, @@ -2311,9 +2429,9 @@ static short snapMesh(SnapObjectContext *sctx, } else { BLI_assert(snapdata->snap_to_flag & SCE_SNAP_MODE_VERTEX); - if (bvhtree[0]) { - /* snap to loose edges */ - BLI_bvhtree_find_nearest_projected(bvhtree[0], + if (sod->bvhtree[0]) { + /* snap to loose edge verts */ + BLI_bvhtree_find_nearest_projected(sod->bvhtree[0], lpmat, snapdata->win_size, snapdata->mval, @@ -2325,7 +2443,7 @@ static short snapMesh(SnapObjectContext *sctx, } if (treedata->tree) { - /* snap to looptris */ + /* snap to looptri verts */ BLI_bvhtree_find_nearest_projected(treedata->tree, lpmat, snapdata->win_size, @@ -2388,17 +2506,12 @@ static short snapEditMesh(SnapObjectContext *sctx, } } - BVHTreeFromEditMesh *treedata_vert = NULL, *treedata_edge = NULL; - - BLI_assert(BKE_object_get_pre_modified_mesh(ob) == BKE_object_get_pre_modified_mesh(ob)); - UNUSED_VARS_NDEBUG(ob); - float lpmat[4][4]; mul_m4_m4m4(lpmat, snapdata->pmat, obmat); - float dist_px_sq = SQUARE(*dist_px); + float dist_px_sq = square_f(*dist_px); - SnapObjectData_EditMesh *sod = snap_object_data_editmesh_get(sctx, ob, em); + SnapObjectData *sod = snap_object_data_editmesh_get(sctx, ob, em); /* Test BoundBox */ @@ -2408,22 +2521,10 @@ static short snapEditMesh(SnapObjectContext *sctx, return 0; } - BVHCache **em_bvh_cache = &((Mesh *)ob->data)->runtime.bvh_cache; - if (snapdata->snap_to_flag & SCE_SNAP_MODE_VERTEX) { - if (sod->bvh_trees[0] == NULL) { - sod->bvh_trees[0] = BLI_memarena_calloc(sctx->cache.mem_arena, sizeof(**sod->bvh_trees)); - } - treedata_vert = sod->bvh_trees[0]; - - if (sctx->callbacks.edit_mesh.test_vert_fn == NULL) { - /* The tree is owned by the Mesh and may have been freed since we last used! */ - if (treedata_vert->tree && !bvhcache_has_tree(*em_bvh_cache, treedata_vert->tree)) { - free_bvhtree_from_editmesh(treedata_vert); - } - } + BVHTreeFromEditMesh treedata = {.tree = sod->bvhtree[0]}; - if (treedata_vert->tree == NULL) { + if (treedata.tree == NULL) { BLI_bitmap *verts_mask = NULL; int verts_num_active = -1; if (sctx->callbacks.edit_mesh.test_vert_fn) { @@ -2436,29 +2537,21 @@ static short snapEditMesh(SnapObjectContext *sctx, sctx->callbacks.edit_mesh.user_data); bvhtree_from_editmesh_verts_ex( - treedata_vert, em, verts_mask, verts_num_active, 0.0f, 2, 6, 0, NULL); + &treedata, em, verts_mask, verts_num_active, 0.0f, 2, 6, 0, NULL); MEM_freeN(verts_mask); } else { - BKE_bvhtree_from_editmesh_get(treedata_vert, em, 2, BVHTREE_FROM_EM_VERTS, em_bvh_cache); + BKE_bvhtree_from_editmesh_get(&treedata, em, 2, BVHTREE_FROM_EM_VERTS, sod->bvh_cache_p); } + sod->bvhtree[0] = treedata.tree; + sod->cached[0] = treedata.cached; } } if (snapdata->snap_to_flag & SCE_SNAP_MODE_EDGE) { - if (sod->bvh_trees[1] == NULL) { - sod->bvh_trees[1] = BLI_memarena_calloc(sctx->cache.mem_arena, sizeof(**sod->bvh_trees)); - } - treedata_edge = sod->bvh_trees[1]; - - if (sctx->callbacks.edit_mesh.test_edge_fn == NULL) { - /* The tree is owned by the Mesh and may have been freed since we last used! */ - if (treedata_edge->tree && !bvhcache_has_tree(*em_bvh_cache, treedata_edge->tree)) { - free_bvhtree_from_editmesh(treedata_edge); - } - } + BVHTreeFromEditMesh treedata = {.tree = sod->bvhtree[1]}; - if (treedata_edge->tree == NULL) { + if (treedata.tree == NULL) { BLI_bitmap *edges_mask = NULL; int edges_num_active = -1; if (sctx->callbacks.edit_mesh.test_edge_fn) { @@ -2471,12 +2564,14 @@ static short snapEditMesh(SnapObjectContext *sctx, sctx->callbacks.edit_mesh.user_data); bvhtree_from_editmesh_edges_ex( - treedata_edge, em, edges_mask, edges_num_active, 0.0f, 2, 6, 0, NULL); + &treedata, em, edges_mask, edges_num_active, 0.0f, 2, 6, 0, NULL); MEM_freeN(edges_mask); } else { - BKE_bvhtree_from_editmesh_get(treedata_edge, em, 2, BVHTREE_FROM_EM_EDGES, em_bvh_cache); + BKE_bvhtree_from_editmesh_get(&treedata, em, 2, BVHTREE_FROM_EM_EDGES, sod->bvh_cache_p); } + sod->bvhtree[1] = treedata.tree; + sod->cached[1] = treedata.cached; } } @@ -2502,10 +2597,10 @@ static short snapEditMesh(SnapObjectContext *sctx, mul_v4_m4v4(clip_planes_local[i], tobmat, snapdata->clip_plane[i]); } - if (treedata_vert && (snapdata->snap_to_flag & SCE_SNAP_MODE_VERTEX)) { + if (sod->bvhtree[0] && (snapdata->snap_to_flag & SCE_SNAP_MODE_VERTEX)) { BM_mesh_elem_table_ensure(em->bm, BM_VERT); BM_mesh_elem_index_ensure(em->bm, BM_VERT); - BLI_bvhtree_find_nearest_projected(treedata_vert->tree, + BLI_bvhtree_find_nearest_projected(sod->bvhtree[0], lpmat, snapdata->win_size, snapdata->mval, @@ -2516,12 +2611,12 @@ static short snapEditMesh(SnapObjectContext *sctx, &nearest2d); } - if (treedata_edge && (snapdata->snap_to_flag & SCE_SNAP_MODE_EDGE)) { + if (sod->bvhtree[1] && (snapdata->snap_to_flag & SCE_SNAP_MODE_EDGE)) { int last_index = nearest.index; nearest.index = -1; BM_mesh_elem_table_ensure(em->bm, BM_EDGE | BM_VERT); BM_mesh_elem_index_ensure(em->bm, BM_EDGE | BM_VERT); - BLI_bvhtree_find_nearest_projected(treedata_edge->tree, + BLI_bvhtree_find_nearest_projected(sod->bvhtree[1], lpmat, snapdata->win_size, snapdata->mval, @@ -2588,14 +2683,26 @@ static short snapObject(SnapObjectContext *sctx, case OB_MESH: { Mesh *me = ob->data; if (BKE_object_is_in_editmode(ob)) { - BMEditMesh *em = BKE_editmesh_from_object(ob); if (use_obedit) { - retval = snapEditMesh( - sctx, snapdata, ob, em, obmat, use_backface_culling, dist_px, r_loc, r_no, r_index); + /* Operators only update the editmesh looptris of the original mesh. */ + BMEditMesh *em_orig = BKE_editmesh_from_object(DEG_get_original_object(ob)); + retval = snapEditMesh(sctx, + snapdata, + ob, + em_orig, + obmat, + use_backface_culling, + dist_px, + r_loc, + r_no, + r_index); break; } - else if (em->mesh_eval_final) { - me = em->mesh_eval_final; + else { + BMEditMesh *em = BKE_editmesh_from_object(ob); + if (em->mesh_eval_final) { + me = em->mesh_eval_final; + } } } else if (ob->dt == OB_BOUNDBOX) { @@ -2615,11 +2722,12 @@ static short snapObject(SnapObjectContext *sctx, break; /* Use ATTR_FALLTHROUGH if we want to snap to the generated mesh. */ case OB_SURF: case OB_FONT: { - if (ob->runtime.mesh_eval) { + Mesh *mesh_eval = BKE_object_get_evaluated_mesh(ob); + if (mesh_eval) { retval |= snapMesh(sctx, snapdata, ob, - ob->runtime.mesh_eval, + mesh_eval, obmat, use_backface_culling, dist_px, @@ -2721,6 +2829,7 @@ static void sanp_obj_cb(SnapObjectContext *sctx, * \param r_obmat: Object matrix (may not be #Object.obmat with dupli-instances). */ static short snapObjectsRay(SnapObjectContext *sctx, + Depsgraph *depsgraph, SnapData *snapdata, const struct SnapObjectParams *params, /* read/write args */ @@ -2743,7 +2852,7 @@ static short snapObjectsRay(SnapObjectContext *sctx, .ret = 0, }; - iter_snap_objects(sctx, params, sanp_obj_cb, &data); + iter_snap_objects(sctx, depsgraph, params, sanp_obj_cb, &data); return data.ret; } @@ -2754,10 +2863,7 @@ static short snapObjectsRay(SnapObjectContext *sctx, /** \name Public Object Snapping API * \{ */ -SnapObjectContext *ED_transform_snap_object_context_create(Main *bmain, - Scene *scene, - Depsgraph *depsgraph, - int flag) +SnapObjectContext *ED_transform_snap_object_context_create(Main *bmain, Scene *scene, int flag) { SnapObjectContext *sctx = MEM_callocN(sizeof(*sctx), __func__); @@ -2765,7 +2871,6 @@ SnapObjectContext *ED_transform_snap_object_context_create(Main *bmain, sctx->bmain = bmain; sctx->scene = scene; - sctx->depsgraph = depsgraph; sctx->cache.object_map = BLI_ghash_ptr_new(__func__); /* Initialize as needed (edit-mode only). */ @@ -2777,16 +2882,15 @@ SnapObjectContext *ED_transform_snap_object_context_create(Main *bmain, SnapObjectContext *ED_transform_snap_object_context_create_view3d(Main *bmain, Scene *scene, - Depsgraph *depsgraph, int flag, /* extra args for view3d */ - const ARegion *ar, + const ARegion *region, const View3D *v3d) { - SnapObjectContext *sctx = ED_transform_snap_object_context_create(bmain, scene, depsgraph, flag); + SnapObjectContext *sctx = ED_transform_snap_object_context_create(bmain, scene, flag); sctx->use_v3d = true; - sctx->v3d_data.ar = ar; + sctx->v3d_data.region = region; sctx->v3d_data.v3d = v3d; return sctx; @@ -2794,24 +2898,8 @@ SnapObjectContext *ED_transform_snap_object_context_create_view3d(Main *bmain, static void snap_object_data_free(void *sod_v) { - switch (((SnapObjectData *)sod_v)->type) { - case SNAP_MESH: { - SnapObjectData_Mesh *sod = sod_v; - if (sod->treedata.tree) { - free_bvhtree_from_mesh(&sod->treedata); - } - break; - } - case SNAP_EDIT_MESH: { - SnapObjectData_EditMesh *sod = sod_v; - for (int i = 0; i < ARRAY_SIZE(sod->bvh_trees); i++) { - if (sod->bvh_trees[i]) { - free_bvhtree_from_editmesh(sod->bvh_trees[i]); - } - } - break; - } - } + SnapObjectData *sod = sod_v; + snap_object_data_clear(sod); } void ED_transform_snap_object_context_destroy(SnapObjectContext *sctx) @@ -2840,6 +2928,7 @@ void ED_transform_snap_object_context_set_editmesh_callbacks( } bool ED_transform_snap_object_project_ray_ex(SnapObjectContext *sctx, + Depsgraph *depsgraph, const struct SnapObjectParams *params, const float ray_start[3], const float ray_normal[3], @@ -2850,8 +2939,18 @@ bool ED_transform_snap_object_project_ray_ex(SnapObjectContext *sctx, Object **r_ob, float r_obmat[4][4]) { - return raycastObjects( - sctx, params, ray_start, ray_normal, ray_depth, r_loc, r_no, r_index, r_ob, r_obmat, NULL); + return raycastObjects(sctx, + depsgraph, + params, + ray_start, + ray_normal, + ray_depth, + r_loc, + r_no, + r_index, + r_ob, + r_obmat, + NULL); } /** @@ -2862,6 +2961,7 @@ bool ED_transform_snap_object_project_ray_ex(SnapObjectContext *sctx, * \param r_hit_list: List of #SnapObjectHitDepth (caller must free). */ bool ED_transform_snap_object_project_ray_all(SnapObjectContext *sctx, + Depsgraph *depsgraph, const struct SnapObjectParams *params, const float ray_start[3], const float ray_normal[3], @@ -2877,8 +2977,18 @@ bool ED_transform_snap_object_project_ray_all(SnapObjectContext *sctx, float ray_depth_prev = ray_depth; #endif - bool retval = raycastObjects( - sctx, params, ray_start, ray_normal, &ray_depth, NULL, NULL, NULL, NULL, NULL, r_hit_list); + bool retval = raycastObjects(sctx, + depsgraph, + params, + ray_start, + ray_normal, + &ray_depth, + NULL, + NULL, + NULL, + NULL, + NULL, + r_hit_list); /* meant to be readonly for 'all' hits, ensure it is */ #ifdef DEBUG @@ -2900,6 +3010,7 @@ bool ED_transform_snap_object_project_ray_all(SnapObjectContext *sctx, * \return Snap success */ static bool transform_snap_context_project_ray_impl(SnapObjectContext *sctx, + Depsgraph *depsgraph, const struct SnapObjectParams *params, const float ray_start[3], const float ray_normal[3], @@ -2911,12 +3022,13 @@ static bool transform_snap_context_project_ray_impl(SnapObjectContext *sctx, /* try snap edge, then face if it fails */ ret = ED_transform_snap_object_project_ray_ex( - sctx, params, ray_start, ray_normal, ray_depth, r_co, r_no, NULL, NULL, NULL); + sctx, depsgraph, params, ray_start, ray_normal, ray_depth, r_co, r_no, NULL, NULL, NULL); return ret; } bool ED_transform_snap_object_project_ray(SnapObjectContext *sctx, + Depsgraph *depsgraph, const struct SnapObjectParams *params, const float ray_origin[3], const float ray_direction[3], @@ -2931,12 +3043,13 @@ bool ED_transform_snap_object_project_ray(SnapObjectContext *sctx, } return transform_snap_context_project_ray_impl( - sctx, params, ray_origin, ray_direction, ray_depth, r_co, r_no); + sctx, depsgraph, params, ray_origin, ray_direction, ray_depth, r_co, r_no); } static short transform_snap_context_project_view3d_mixed_impl( SnapObjectContext *sctx, - const unsigned short snap_to_flag, + Depsgraph *depsgraph, + const ushort snap_to_flag, const struct SnapObjectParams *params, const float mval[2], const float prev_co[3], @@ -2958,15 +3071,15 @@ static short transform_snap_context_project_view3d_mixed_impl( float loc[3], no[3], obmat[4][4]; int index = -1; - const ARegion *ar = sctx->v3d_data.ar; - const RegionView3D *rv3d = ar->regiondata; + const ARegion *region = sctx->v3d_data.region; + const RegionView3D *rv3d = region->regiondata; bool use_occlusion_test = params->use_occlusion_test && !XRAY_ENABLED(sctx->v3d_data.v3d); if (snap_to_flag & SCE_SNAP_MODE_FACE || use_occlusion_test) { float ray_start[3], ray_normal[3]; - if (!ED_view3d_win_to_ray_clipped_ex(sctx->depsgraph, - sctx->v3d_data.ar, + if (!ED_view3d_win_to_ray_clipped_ex(depsgraph, + sctx->v3d_data.region, sctx->v3d_data.v3d, mval, NULL, @@ -2978,8 +3091,18 @@ static short transform_snap_context_project_view3d_mixed_impl( float dummy_ray_depth = BVH_RAYCAST_DIST_MAX; - has_hit = raycastObjects( - sctx, params, ray_start, ray_normal, &dummy_ray_depth, loc, no, &index, &ob, obmat, NULL); + has_hit = raycastObjects(sctx, + depsgraph, + params, + ray_start, + ray_normal, + &dummy_ray_depth, + loc, + no, + &index, + &ob, + obmat, + NULL); if (has_hit && (snap_to_flag & SCE_SNAP_MODE_FACE)) { retval = SCE_SNAP_MODE_FACE; @@ -3007,8 +3130,8 @@ static short transform_snap_context_project_view3d_mixed_impl( SnapData snapdata; copy_m4_m4(snapdata.pmat, rv3d->persmat); - snapdata.win_size[0] = ar->winx; - snapdata.win_size[1] = ar->winy; + snapdata.win_size[0] = region->winx; + snapdata.win_size[1] = region->winy; copy_v2_v2(snapdata.mval, mval); snapdata.view_proj = rv3d->is_persp ? VIEW_PROJ_PERSP : VIEW_PROJ_ORTHO; @@ -3053,7 +3176,8 @@ static short transform_snap_context_project_view3d_mixed_impl( snapdata.has_occlusion_plane = true; } - elem_test = snapObjectsRay(sctx, &snapdata, params, &dist_px_tmp, loc, no, &index, &ob, obmat); + elem_test = snapObjectsRay( + sctx, depsgraph, &snapdata, params, &dist_px_tmp, loc, no, &index, &ob, obmat); if (elem_test) { elem = elem_test; } @@ -3100,7 +3224,8 @@ static short transform_snap_context_project_view3d_mixed_impl( } short ED_transform_snap_object_project_view3d_ex(SnapObjectContext *sctx, - const unsigned short snap_to, + Depsgraph *depsgraph, + const ushort snap_to, const struct SnapObjectParams *params, const float mval[2], const float prev_co[3], @@ -3111,8 +3236,18 @@ short ED_transform_snap_object_project_view3d_ex(SnapObjectContext *sctx, Object **r_ob, float r_obmat[4][4]) { - return transform_snap_context_project_view3d_mixed_impl( - sctx, snap_to, params, mval, prev_co, dist_px, r_loc, r_no, r_index, r_ob, r_obmat); + return transform_snap_context_project_view3d_mixed_impl(sctx, + depsgraph, + snap_to, + params, + mval, + prev_co, + dist_px, + r_loc, + r_no, + r_index, + r_ob, + r_obmat); } /** @@ -3129,7 +3264,8 @@ short ED_transform_snap_object_project_view3d_ex(SnapObjectContext *sctx, * \return Snap success */ bool ED_transform_snap_object_project_view3d(SnapObjectContext *sctx, - const unsigned short snap_to, + Depsgraph *depsgraph, + const ushort snap_to, const struct SnapObjectParams *params, const float mval[2], const float prev_co[3], @@ -3137,14 +3273,25 @@ bool ED_transform_snap_object_project_view3d(SnapObjectContext *sctx, float r_loc[3], float r_no[3]) { - return ED_transform_snap_object_project_view3d_ex( - sctx, snap_to, params, mval, prev_co, dist_px, r_loc, r_no, NULL, NULL, NULL) != 0; + return ED_transform_snap_object_project_view3d_ex(sctx, + depsgraph, + snap_to, + params, + mval, + prev_co, + dist_px, + r_loc, + r_no, + NULL, + NULL, + NULL) != 0; } /** * see: #ED_transform_snap_object_project_ray_all */ bool ED_transform_snap_object_project_all_view3d_ex(SnapObjectContext *sctx, + Depsgraph *depsgraph, const struct SnapObjectParams *params, const float mval[2], float ray_depth, @@ -3153,8 +3300,8 @@ bool ED_transform_snap_object_project_all_view3d_ex(SnapObjectContext *sctx, { float ray_start[3], ray_normal[3]; - if (!ED_view3d_win_to_ray_clipped_ex(sctx->depsgraph, - sctx->v3d_data.ar, + if (!ED_view3d_win_to_ray_clipped_ex(depsgraph, + sctx->v3d_data.region, sctx->v3d_data.v3d, mval, NULL, @@ -3165,7 +3312,7 @@ bool ED_transform_snap_object_project_all_view3d_ex(SnapObjectContext *sctx, } return ED_transform_snap_object_project_ray_all( - sctx, params, ray_start, ray_normal, ray_depth, sort, r_hit_list); + sctx, depsgraph, params, ray_start, ray_normal, ray_depth, sort, r_hit_list); } /** \} */ |