From 93d33ce0275351e7b2dcbf275e62b52db33955a7 Mon Sep 17 00:00:00 2001 From: Germano Cavalcante Date: Fri, 19 May 2023 22:34:23 -0300 Subject: [PATCH 1/4] Transform: interactive mode for editing a 'Snap Source' Implements new modifier key ({key B}) to change the snap origin point during a transformation. Ref #66484 - The feature is only available in 3D View. - The feature is only available for `Move`, `Rotate` and `Scale` transform modes. - The 'snap source edit' is enabled while we are transforming and we press {key B} - The 'snap source edit' is confirmed when we press any of the keys: {key B}, {key LMB}, {key Enter} - During a transformation, if no snap target is set for an element in the scene (Vertex, Grid...), the snap targets to geometry Vertex, Edge, Face, Center of Edge and Perpendicular of Edge are set automatically. - Snap cannot be turned off during the snap source editing. - Constraint or similar modification features are not available during the snap source editing. - Text input is not available during the snap source editing. - When adding multiple snap points (A) the new prone snap source point is indicated with an small cursor drawing. --- {F11820463} **Build:** https://builder.blender.org/download/patch/D9415/ tmp --- scripts/modules/bl_keymap_utils/versioning.py | 11 + .../keyconfig/keymap_data/blender_default.py | 1 + .../keymap_data/industry_compatible_data.py | 1 + .../blender/blenkernel/BKE_blender_version.h | 2 +- .../blender/editors/transform/CMakeLists.txt | 1 + source/blender/editors/transform/transform.c | 47 +++- source/blender/editors/transform/transform.h | 4 + .../editors/transform/transform_input.c | 12 + .../editors/transform/transform_mode.h | 4 + .../transform/transform_mode_edge_slide.c | 37 ++- .../editors/transform/transform_mode_resize.c | 10 +- .../transform/transform_mode_snapsource.c | 247 ++++++++++++++++++ .../transform/transform_mode_vert_slide.c | 31 ++- .../editors/transform/transform_snap.cc | 152 ++++++++--- .../editors/transform/transform_snap.h | 2 + .../transform/transform_snap_object.cc | 39 ++- 16 files changed, 551 insertions(+), 50 deletions(-) create mode 100644 source/blender/editors/transform/transform_mode_snapsource.c diff --git a/scripts/modules/bl_keymap_utils/versioning.py b/scripts/modules/bl_keymap_utils/versioning.py index 3af81067b7a..9a1b8ce978a 100644 --- a/scripts/modules/bl_keymap_utils/versioning.py +++ b/scripts/modules/bl_keymap_utils/versioning.py @@ -80,4 +80,15 @@ def keyconfig_update(keyconfig_data, keyconfig_version): km_items.append(('ROTATE_NORMALS', {"type": 'N', "value": 'PRESS'}, None)) break + if keyconfig_version <= (3, 6, 2): + if not has_copy: + keyconfig_data = copy.deepcopy(keyconfig_data) + has_copy = True + + # "Snap Source Toggle" did not exist until then. + for km_name, _km_parms, km_items_data in keyconfig_data: + if km_name == "Transform Modal Map": + km_items_data["items"].append(("EDIT_SNAP_SOURCE", {"type": 'B', "value": 'PRESS'}, None)) + break + return keyconfig_data diff --git a/scripts/presets/keyconfig/keymap_data/blender_default.py b/scripts/presets/keyconfig/keymap_data/blender_default.py index ee7f5c0d1da..e030a8c1d7f 100644 --- a/scripts/presets/keyconfig/keymap_data/blender_default.py +++ b/scripts/presets/keyconfig/keymap_data/blender_default.py @@ -5882,6 +5882,7 @@ def km_transform_modal_map(params): ("TRACKBALL", {"type": 'R', "value": 'PRESS'}, None), ("RESIZE", {"type": 'S', "value": 'PRESS'}, None), ("ROTATE_NORMALS", {"type": 'N', "value": 'PRESS'}, None), + ("EDIT_SNAP_SOURCE", {"type": 'B', "value": 'PRESS'}, None), ("SNAP_TOGGLE", {"type": 'TAB', "value": 'PRESS', "shift": True}, None), ("SNAP_INV_ON", {"type": 'LEFT_CTRL', "value": 'PRESS', "any": True}, None), ("SNAP_INV_OFF", {"type": 'LEFT_CTRL', "value": 'RELEASE', "any": True}, None), diff --git a/scripts/presets/keyconfig/keymap_data/industry_compatible_data.py b/scripts/presets/keyconfig/keymap_data/industry_compatible_data.py index 1c6ac26c7e9..e47611fa88b 100644 --- a/scripts/presets/keyconfig/keymap_data/industry_compatible_data.py +++ b/scripts/presets/keyconfig/keymap_data/industry_compatible_data.py @@ -4034,6 +4034,7 @@ def km_transform_modal_map(_params): ("TRACKBALL", {"type": 'R', "value": 'PRESS'}, None), ("RESIZE", {"type": 'S', "value": 'PRESS'}, None), ("ROTATE_NORMALS", {"type": 'N', "value": 'PRESS'}, None), + ("EDIT_SNAP_SOURCE", {"type": 'B', "value": 'PRESS'}, None), ("SNAP_TOGGLE", {"type": 'TAB', "value": 'PRESS', "shift": True}, None), ("SNAP_INV_ON", {"type": 'LEFT_CTRL', "value": 'PRESS', "any": True}, None), ("SNAP_INV_OFF", {"type": 'LEFT_CTRL', "value": 'RELEASE', "any": True}, None), diff --git a/source/blender/blenkernel/BKE_blender_version.h b/source/blender/blenkernel/BKE_blender_version.h index 46a16875473..0a8fe263c6f 100644 --- a/source/blender/blenkernel/BKE_blender_version.h +++ b/source/blender/blenkernel/BKE_blender_version.h @@ -25,7 +25,7 @@ extern "C" { /* Blender file format version. */ #define BLENDER_FILE_VERSION BLENDER_VERSION -#define BLENDER_FILE_SUBVERSION 2 +#define BLENDER_FILE_SUBVERSION 3 /* Minimum Blender version that supports reading file written with the current * version. Older Blender versions will test this and show a warning if the file diff --git a/source/blender/editors/transform/CMakeLists.txt b/source/blender/editors/transform/CMakeLists.txt index 338e91589c6..ac74e563183 100644 --- a/source/blender/editors/transform/CMakeLists.txt +++ b/source/blender/editors/transform/CMakeLists.txt @@ -82,6 +82,7 @@ set(SRC transform_mode_shear.c transform_mode_shrink_fatten.c transform_mode_skin_resize.c + transform_mode_snapsource.c transform_mode_tilt.c transform_mode_timescale.c transform_mode_timeslide.c diff --git a/source/blender/editors/transform/transform.c b/source/blender/editors/transform/transform.c index 77725b5bd0d..7882cdb9e14 100644 --- a/source/blender/editors/transform/transform.c +++ b/source/blender/editors/transform/transform.c @@ -542,6 +542,19 @@ static void viewRedrawPost(bContext *C, TransInfo *t) static bool transform_modal_item_poll(const wmOperator *op, int value) { const TransInfo *t = op->customdata; + if (t->modifiers & MOD_EDIT_SNAP_SOURCE) { + if (value == TFM_MODAL_EDIT_SNAP_SOURCE) { + return true; + } + else if (!ELEM(value, + TFM_MODAL_CANCEL, + TFM_MODAL_CONFIRM, + TFM_MODAL_ADD_SNAP, + TFM_MODAL_REMOVE_SNAP)) { + return false; + } + } + switch (value) { case TFM_MODAL_CANCEL: { /* TODO: Canceling with LMB is not possible when the operator is activated @@ -669,6 +682,21 @@ static bool transform_modal_item_poll(const wmOperator *op, int value) } break; } + case TFM_MODAL_EDIT_SNAP_SOURCE: { + if (t->spacetype != SPACE_VIEW3D) { + return false; + } + if (!ELEM(t->mode, + TFM_TRANSLATION, + TFM_ROTATION, + TFM_RESIZE, + TFM_EDGE_SLIDE, + TFM_VERT_SLIDE)) { + /* More modes can be added over time if this feature proves useful for them. */ + return false; + } + break; + } } return true; } @@ -685,6 +713,7 @@ wmKeyMap *transform_modal_keymap(wmKeyConfig *keyconf) {TFM_MODAL_PLANE_Y, "PLANE_Y", 0, "Y Plane", ""}, {TFM_MODAL_PLANE_Z, "PLANE_Z", 0, "Z Plane", ""}, {TFM_MODAL_CONS_OFF, "CONS_OFF", 0, "Clear Constraints", ""}, + {TFM_MODAL_EDIT_SNAP_SOURCE, "EDIT_SNAP_SOURCE", 0, "Set Snap Base", ""}, {TFM_MODAL_SNAP_INV_ON, "SNAP_INV_ON", 0, "Snap Invert", ""}, {TFM_MODAL_SNAP_INV_OFF, "SNAP_INV_OFF", 0, "Snap Invert (Off)", ""}, {TFM_MODAL_SNAP_TOGGLE, "SNAP_TOGGLE", 0, "Snap Toggle", ""}, @@ -954,12 +983,16 @@ int transformEvent(TransInfo *t, const wmEvent *event) else if (event->type == EVT_MODAL_MAP) { switch (event->val) { case TFM_MODAL_CANCEL: - t->state = TRANS_CANCEL; - handled = true; + if (!(t->modifiers & MOD_EDIT_SNAP_SOURCE)) { + t->state = TRANS_CANCEL; + handled = true; + } break; case TFM_MODAL_CONFIRM: - t->state = TRANS_CONFIRM; - handled = true; + if (!(t->modifiers & MOD_EDIT_SNAP_SOURCE)) { + t->state = TRANS_CONFIRM; + handled = true; + } break; case TFM_MODAL_TRANSLATE: case TFM_MODAL_ROTATE: @@ -1244,6 +1277,12 @@ int transformEvent(TransInfo *t, const wmEvent *event) t->redraw |= TREDRAW_HARD; } break; + case TFM_MODAL_EDIT_SNAP_SOURCE: + if (event->prev_val == KM_PRESS) { + transform_mode_snap_source_init(t); + t->redraw |= TREDRAW_HARD; + } + break; default: break; } diff --git a/source/blender/editors/transform/transform.h b/source/blender/editors/transform/transform.h index c49e8338e12..106f5e37807 100644 --- a/source/blender/editors/transform/transform.h +++ b/source/blender/editors/transform/transform.h @@ -157,6 +157,7 @@ typedef enum { MOD_CONSTRAINT_SELECT_PLANE = 1 << 4, MOD_NODE_ATTACH = 1 << 5, MOD_SNAP_FORCED = 1 << 6, + MOD_EDIT_SNAP_SOURCE = 1 << 7, } eTModifier; ENUM_OPERATORS(eTModifier, MOD_NODE_ATTACH) @@ -270,6 +271,8 @@ enum { TFM_MODAL_VERT_EDGE_SLIDE = 31, TFM_MODAL_TRACKBALL = 32, TFM_MODAL_ROTATE_NORMALS = 33, + + TFM_MODAL_EDIT_SNAP_SOURCE = 34, }; /** \} */ @@ -768,6 +771,7 @@ void applyMouseInput(struct TransInfo *t, const int mval[2], float output[3]); void transform_input_update(TransInfo *t, const float fac); +void transform_input_reset(TransInfo *t, const int mval[2]); void setCustomPoints(TransInfo *t, MouseInput *mi, const int start[2], const int end[2]); void setCustomPointsFromDirection(TransInfo *t, MouseInput *mi, const float dir[2]); diff --git a/source/blender/editors/transform/transform_input.c b/source/blender/editors/transform/transform_input.c index bba57ff9602..cca7690a592 100644 --- a/source/blender/editors/transform/transform_input.c +++ b/source/blender/editors/transform/transform_input.c @@ -494,4 +494,16 @@ void transform_input_update(TransInfo *t, const float fac) } } +void transform_input_reset(TransInfo *t, const int mval[2]) +{ + MouseInput *mi = &t->mouse; + copy_v2_v2_int(mi->imval, mval); + if (ELEM(mi->apply, InputAngle, InputAngleSpring)) { + struct InputAngle_Data *data = mi->data; + data->mval_prev[0] = mi->imval[0]; + data->mval_prev[1] = mi->imval[1]; + data->angle = 0.0f; + } +} + /** \} */ diff --git a/source/blender/editors/transform/transform_mode.h b/source/blender/editors/transform/transform_mode.h index 6fc82a484bd..d6d9537f2d8 100644 --- a/source/blender/editors/transform/transform_mode.h +++ b/source/blender/editors/transform/transform_mode.h @@ -155,6 +155,10 @@ void initShrinkFatten(TransInfo *t); void initSkinResize(TransInfo *t); +/* transform_mode_snapsource.c */ + +void transform_mode_snap_source_init(TransInfo *t); + /* transform_mode_tilt.c */ void initTilt(TransInfo *t); diff --git a/source/blender/editors/transform/transform_mode_edge_slide.c b/source/blender/editors/transform/transform_mode_edge_slide.c index 4f4c75b63e3..a4b3043ccac 100644 --- a/source/blender/editors/transform/transform_mode_edge_slide.c +++ b/source/blender/editors/transform/transform_mode_edge_slide.c @@ -1483,6 +1483,41 @@ static void applyEdgeSlide(TransInfo *t, const int UNUSED(mval[2])) ED_area_status_text(t->area, str); } +static void edge_slide_transform_matrix_fn(struct TransInfo *t, float mat_xform[4][4]) +{ + float delta[3], orig_co[3], final_co[3]; + + EdgeSlideParams *slp = t->custom.mode.data; + TransDataContainer *tc = edge_slide_container_first_ok(t); + EdgeSlideData *sld_active = tc->custom.mode.data; + TransDataEdgeSlideVert *sv_active = &sld_active->sv[sld_active->curr_sv_index]; + + copy_v3_v3(orig_co, sv_active->v_co_orig); + + const float fac = t->values_final[0]; + float curr_length_fac = 0.0f; + if (slp->use_even) { + curr_length_fac = sv_active->edge_len * (((slp->flipped ? fac : -fac) + 1.0f) / 2.0f); + } + + edge_slide_apply_elem(sv_active, + fac, + curr_length_fac, + slp->curr_side_unclamp, + !(t->flag & T_ALT_TRANSFORM), + slp->use_even, + slp->flipped, + final_co); + + if (tc->use_local_mat) { + mul_m4_v3(tc->mat, orig_co); + mul_m4_v3(tc->mat, final_co); + } + + sub_v3_v3v3(delta, final_co, orig_co); + add_v3_v3(mat_xform[3], delta); +} + void initEdgeSlide_ex( TransInfo *t, bool use_double_side, bool use_even, bool flipped, bool use_clamp) { @@ -1492,7 +1527,7 @@ void initEdgeSlide_ex( t->mode = TFM_EDGE_SLIDE; t->transform = applyEdgeSlide; t->handleEvent = handleEventEdgeSlide; - t->transform_matrix = NULL; + t->transform_matrix = edge_slide_transform_matrix_fn; t->tsnap.snap_mode_apply_fn = edge_slide_snap_apply; t->tsnap.snap_mode_distance_fn = transform_snap_distance_len_squared_fn; diff --git a/source/blender/editors/transform/transform_mode_resize.c b/source/blender/editors/transform/transform_mode_resize.c index 5a42edb9ad4..22554cc6dd1 100644 --- a/source/blender/editors/transform/transform_mode_resize.c +++ b/source/blender/editors/transform/transform_mode_resize.c @@ -281,11 +281,19 @@ static void applyResize(TransInfo *t, const int UNUSED(mval[2])) ED_area_status_text(t->area, str); } +static void resize_transform_matrix_fn(struct TransInfo *t, float mat_xform[4][4]) +{ + float mat4[4][4]; + copy_m4_m3(mat4, t->mat); + transform_pivot_set_m4(mat4, t->center_global); + mul_m4_m4m4(mat_xform, mat4, mat_xform); +} + void initResize(TransInfo *t, float mouse_dir_constraint[3]) { t->mode = TFM_RESIZE; t->transform = applyResize; - t->transform_matrix = NULL; + t->transform_matrix = resize_transform_matrix_fn; t->tsnap.snap_mode_apply_fn = ApplySnapResize; t->tsnap.snap_mode_distance_fn = ResizeBetween; diff --git a/source/blender/editors/transform/transform_mode_snapsource.c b/source/blender/editors/transform/transform_mode_snapsource.c new file mode 100644 index 00000000000..1af88cb7d92 --- /dev/null +++ b/source/blender/editors/transform/transform_mode_snapsource.c @@ -0,0 +1,247 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later + * Copyright 2001-2002 NaN Holding BV. All rights reserved. */ + +/** \file + * \ingroup edtransform + */ + +#include "MEM_guardedalloc.h" + +#include "BLI_math.h" + +#include "DNA_windowmanager_types.h" + +#include "BKE_context.h" + +#include "ED_screen.h" +#include "ED_transform_snap_object_context.h" + +#include "transform.h" +#include "transform_convert.h" +#include "transform_gizmo.h" +#include "transform_snap.h" + +#include "transform_mode.h" + +#define RESET_TRANSFORMATION +#define REMOVE_GIZMO + +/* -------------------------------------------------------------------- */ +/** \name Transform Element + * \{ */ + +/** + * \note Small arrays / data-structures should be stored copied for faster memory access. + */ +struct SnapSouceCustomData { + void (*transform_prev)(struct TransInfo *, const int[2]); + eRedrawFlag (*handleEvent_prev)(struct TransInfo *, const struct wmEvent *); + void *customdata_mode_prev; + + eSnapTargetOP target_operation_prev; + + struct { + void (*apply)(struct TransInfo *t, + struct MouseInput *mi, + const double mval[2], + float output[3]); + void (*post)(struct TransInfo *t, float values[3]); + bool use_virtual_mval; + } mouse_prev; +}; + +static void snapsource_end(TransInfo *t) +{ + t->modifiers &= ~MOD_EDIT_SNAP_SOURCE; + + /* Restore. */ + struct SnapSouceCustomData *customdata = t->custom.mode.data; + t->transform = customdata->transform_prev; + t->custom.mode.data = customdata->customdata_mode_prev; + t->handleEvent = customdata->handleEvent_prev; + + t->tsnap.target_operation = customdata->target_operation_prev; + + t->mouse.apply = customdata->mouse_prev.apply; + t->mouse.post = customdata->mouse_prev.post; + t->mouse.use_virtual_mval = customdata->mouse_prev.use_virtual_mval; + + transform_gizmo_3d_model_from_constraint_and_mode_set(t); + + MEM_freeN(customdata); + + t->tsnap.snap_source_fn = NULL; + + tranform_snap_source_restore_context(t); +} + +static void snapsource_confirm(TransInfo *t) +{ + BLI_assert(t->modifiers & MOD_EDIT_SNAP_SOURCE); + getSnapPoint(t, t->tsnap.snap_source); + + int mval[2]; +#ifndef RESET_TRANSFORMATION + if (true) { + if (t->transform_matrix) { + float mat_inv[4][4]; + unit_m4(mat_inv); + t->transform_matrix(t, mat_inv); + invert_m4(mat_inv); + mul_m4_v3(mat_inv, t->tsnap.snap_source); + } + else { + float mat_inv[3][3]; + invert_m3_m3(mat_inv, t->mat); + + mul_m3_v3(mat_inv, t->tsnap.snap_source); + sub_v3_v3(t->tsnap.snap_source, t->vec); + } + + projectIntView(t, t->tsnap.snap_source, mval); + } + else +#endif + { + copy_v2_v2_int(mval, t->mval); + } + + snapsource_end(t); + transform_input_reset(t, mval); + + /* Remote individual snap projection since this mode does not use the new `snap_source`. */ + t->tsnap.flag &= ~SCE_SNAP_PROJECT; +} + +static eRedrawFlag snapsource_handle_event_fn(struct TransInfo *t, const struct wmEvent *event) +{ + if (event->type == EVT_MODAL_MAP) { + switch (event->val) { + case TFM_MODAL_CONFIRM: + case TFM_MODAL_EDIT_SNAP_SOURCE: + if (t->modifiers & MOD_EDIT_SNAP_SOURCE) { + snapsource_confirm(t); + + BLI_assert(t->state != TRANS_CONFIRM); + } + else { + t->modifiers |= MOD_EDIT_SNAP_SOURCE; + } + break; + case TFM_MODAL_CANCEL: + snapsource_end(t); + t->state = TRANS_CANCEL; + return TREDRAW_SOFT; + default: + break; + } + } + else if (event->val == KM_RELEASE && t->state == TRANS_CONFIRM) { + if (t->flag & T_RELEASE_CONFIRM && t->modifiers & MOD_EDIT_SNAP_SOURCE) { + snapsource_confirm(t); + t->flag &= ~T_RELEASE_CONFIRM; + t->state = TRANS_RUNNING; + } + } + return TREDRAW_NOTHING; +} + +static void snapsource_transform_fn(TransInfo *t, const int UNUSED(mval[2])) +{ + BLI_assert(t->modifiers & MOD_EDIT_SNAP_SOURCE); + + t->tsnap.snap_target_fn(t, NULL); + t->redraw |= TREDRAW_SOFT; +} + +void transform_mode_snap_source_init(TransInfo *t) +{ + if (t->transform == snapsource_transform_fn) { + /* Already running. */ + return; + } + + if (ELEM(t->mode, TFM_INIT, TFM_DUMMY)) { + /* Fallback */ + transform_mode_init(t, NULL, TFM_TRANSLATION); + } + + struct SnapSouceCustomData *customdata = MEM_callocN(sizeof(*customdata), __func__); + customdata->transform_prev = t->transform; + customdata->customdata_mode_prev = t->custom.mode.data; + customdata->handleEvent_prev = t->handleEvent; + + customdata->target_operation_prev = t->tsnap.target_operation; + + customdata->mouse_prev.apply = t->mouse.apply; + customdata->mouse_prev.post = t->mouse.post; + customdata->mouse_prev.use_virtual_mval = t->mouse.use_virtual_mval; + + t->custom.mode.data = customdata; + // t->custom.mode.use_free = true; + + t->transform = snapsource_transform_fn; + t->handleEvent = snapsource_handle_event_fn; + + if (!(t->modifiers & MOD_SNAP) || !transformModeUseSnap(t)) { + t->modifiers |= (MOD_SNAP | MOD_SNAP_FORCED); + } + + t->tsnap.target_operation = SCE_SNAP_TARGET_ALL; + + if ((t->tsnap.status & SNAP_SOURCE_FOUND) == 0) { + if (t->tsnap.snap_source_fn) { + /* Calculate the current snap source for perpendicular snap. */ + t->tsnap.snap_source_fn(t); + } + if ((t->tsnap.status & SNAP_SOURCE_FOUND) == 0) { + /* Fallback. */ + copy_v3_v3(t->tsnap.snap_source, t->center_global); + t->tsnap.status |= SNAP_SOURCE_FOUND; + } + } + + if ((t->tsnap.mode & ~(SCE_SNAP_MODE_INCREMENT | SCE_SNAP_MODE_GRID)) == 0) { + /* Initialize snap modes for geometry. */ + t->tsnap.mode &= ~(SCE_SNAP_MODE_INCREMENT | SCE_SNAP_MODE_GRID); + t->tsnap.mode |= SCE_SNAP_MODE_GEOM & ~SCE_SNAP_MODE_FACE_NEAREST; + } + + if (t->data_type == &TransConvertType_Mesh) { + ED_transform_snap_object_context_set_editmesh_callbacks( + t->tsnap.object_context, NULL, NULL, NULL, NULL); + } + +#ifdef RESET_TRANSFORMATION + /* Temporarily disable snapping. + * We don't want #SCE_SNAP_PROJECT to affect `recalcData` for example. */ + t->tsnap.flag &= ~SCE_SNAP; + + restoreTransObjects(t); + + /* Restore snapping status. */ + transform_snap_flag_from_modifiers_set(t); + + /* Reset initial values to restore gizmo position. */ + applyMouseInput(t, &t->mouse, t->mouse.imval, t->values_final); +#endif + +#ifdef REMOVE_GIZMO + struct wmGizmo *gz = WM_gizmomap_get_modal(t->region->gizmo_map); + if (gz) { + const struct wmEvent *event = CTX_wm_window(t->context)->eventstate; +# ifdef RESET_TRANSFORMATION + wmGizmoFnModal modal_fn = gz->custom_modal ? gz->custom_modal : gz->type->modal; + modal_fn(t->context, gz, event, 0); +# endif + + WM_gizmo_modal_set_while_modal(t->region->gizmo_map, t->context, NULL, event); + } +#endif + + t->mouse.apply = NULL; + t->mouse.post = NULL; + t->mouse.use_virtual_mval = false; +} + +/** \} */ diff --git a/source/blender/editors/transform/transform_mode_vert_slide.c b/source/blender/editors/transform/transform_mode_vert_slide.c index df96287af7c..07e9360cf80 100644 --- a/source/blender/editors/transform/transform_mode_vert_slide.c +++ b/source/blender/editors/transform/transform_mode_vert_slide.c @@ -609,13 +609,42 @@ static void applyVertSlide(TransInfo *t, const int UNUSED(mval[2])) ED_area_status_text(t->area, str); } +static void vert_slide_transform_matrix_fn(struct TransInfo *t, float mat_xform[4][4]) +{ + float delta[3], orig_co[3], final_co[3]; + + VertSlideParams *slp = t->custom.mode.data; + TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_OK(t); + VertSlideData *sld_active = tc->custom.mode.data; + TransDataVertSlideVert *sv_active = &sld_active->sv[sld_active->curr_sv_index]; + + copy_v3_v3(orig_co, sv_active->co_orig_3d); + + float tperc = t->values_final[0]; + if (slp->use_even) { + const float edge_len_curr = len_v3v3(sv_active->co_orig_3d, + sv_active->co_link_orig_3d[sv_active->co_link_curr]); + tperc *= edge_len_curr; + } + + vert_slide_apply_elem(sv_active, tperc, slp->use_even, slp->flipped, final_co); + + if (tc->use_local_mat) { + mul_m4_v3(tc->mat, orig_co); + mul_m4_v3(tc->mat, final_co); + } + + sub_v3_v3v3(delta, final_co, orig_co); + add_v3_v3(mat_xform[3], delta); +} + void initVertSlide_ex(TransInfo *t, bool use_even, bool flipped, bool use_clamp) { t->mode = TFM_VERT_SLIDE; t->transform = applyVertSlide; t->handleEvent = handleEventVertSlide; - t->transform_matrix = NULL; + t->transform_matrix = vert_slide_transform_matrix_fn; t->tsnap.snap_mode_apply_fn = vert_slide_snap_apply; t->tsnap.snap_mode_distance_fn = transform_snap_distance_len_squared_fn; diff --git a/source/blender/editors/transform/transform_snap.cc b/source/blender/editors/transform/transform_snap.cc index a1fc4ba75f2..09cc69744fc 100644 --- a/source/blender/editors/transform/transform_snap.cc +++ b/source/blender/editors/transform/transform_snap.cc @@ -165,17 +165,33 @@ static bool doForceIncrementSnap(const TransInfo *t) return !transformModeUseSnap(t); } +static void snap_source_transformed(TransInfo *t, float r_vec[3]) +{ + float mat[4][4]; + unit_m4(mat); + if (t->transform_matrix) { + t->transform_matrix(t, mat); + } + + mul_v3_m4v3(r_vec, mat, t->tsnap.snap_source); +} + void drawSnapping(const struct bContext *C, TransInfo *t) { uchar col[4], selectedCol[4], activeCol[4]; - if (!transform_snap_is_active(t)) { + if (!(transform_snap_is_active(t) || t->modifiers & MOD_EDIT_SNAP_SOURCE)) { return; } - bool draw_source = (t->spacetype == SPACE_VIEW3D) && (t->tsnap.status & SNAP_SOURCE_FOUND) && - (t->tsnap.mode & SCE_SNAP_MODE_EDGE_PERPENDICULAR); + const bool draw_source = (t->spacetype == SPACE_VIEW3D) && + (t->tsnap.status & SNAP_SOURCE_FOUND) && + (t->tsnap.mode & SCE_SNAP_MODE_EDGE_PERPENDICULAR); - if (!(draw_source || validSnap(t))) { + bool draw_source_transformed = (t->spacetype == SPACE_VIEW3D) && + (t->tsnap.status & SNAP_SOURCE_FOUND) && + !(t->modifiers & MOD_EDIT_SNAP_SOURCE); + + if (!(draw_source || draw_source_transformed || validSnap(t))) { return; } @@ -201,8 +217,8 @@ void drawSnapping(const struct bContext *C, TransInfo *t) GPU_depth_test(GPU_DEPTH_NONE); - RegionView3D *rv3d = CTX_wm_region_view3d(C); - if (!BLI_listbase_is_empty(&t->tsnap.points)) { + RegionView3D *rv3d = (RegionView3D *)t->region->regiondata; + if (draw_source_transformed || !BLI_listbase_is_empty(&t->tsnap.points)) { /* Draw snap points. */ float size = 2.0f * UI_GetThemeValuef(TH_VERTEX_SIZE); @@ -214,14 +230,67 @@ void drawSnapping(const struct bContext *C, TransInfo *t) immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR); - LISTBASE_FOREACH (TransSnapPoint *, p, &t->tsnap.points) { - if (p == t->tsnap.selectedPoint) { - immUniformColor4ubv(selectedCol); + float snap_source_tranformed[3]; + if (draw_source_transformed) { + snap_source_transformed(t, snap_source_tranformed); + } + + if (!BLI_listbase_is_empty(&t->tsnap.points)) { + LISTBASE_FOREACH (TransSnapPoint *, p, &t->tsnap.points) { + if (p == t->tsnap.selectedPoint) { + immUniformColor4ubv(selectedCol); + } + else { + immUniformColor4ubv(col); + } + imm_drawcircball(p->co, ED_view3d_pixel_size(rv3d, p->co) * size, view_inv, pos); } - else { - immUniformColor4ubv(col); + + if (t->modifiers & MOD_EDIT_SNAP_SOURCE) { + /* Indicate the new snap source position. */ + getSnapPoint(t, snap_source_tranformed); + draw_source_transformed = true; } - imm_drawcircball(p->co, ED_view3d_pixel_size(rv3d, p->co) * size, view_inv, pos); + } + + if (draw_source_transformed && + !compare_v3v3(snap_source_tranformed, t->tsnap.snap_target, FLT_EPSILON)) { + float view_inv[4][4]; + copy_m4_m4(view_inv, rv3d->viewinv); + + float vx[3], vy[3], v[3]; + float size_tmp = ED_view3d_pixel_size(rv3d, snap_source_tranformed) * size; + float size_fac = 0.5f; + + mul_v3_v3fl(vx, view_inv[0], size_tmp); + mul_v3_v3fl(vy, view_inv[1], size_tmp); + + immUniformColor4ubv(col); + + imm_drawcircball(snap_source_tranformed, size_tmp, view_inv, pos); + + immBegin(GPU_PRIM_LINES, 8); + add_v3_v3v3(v, snap_source_tranformed, vx); + immVertex3fv(pos, v); + madd_v3_v3fl(v, vx, size_fac); + immVertex3fv(pos, v); + + sub_v3_v3v3(v, snap_source_tranformed, vx); + immVertex3fv(pos, v); + madd_v3_v3fl(v, vx, -size_fac); + immVertex3fv(pos, v); + + add_v3_v3v3(v, snap_source_tranformed, vy); + immVertex3fv(pos, v); + madd_v3_v3fl(v, vy, size_fac); + immVertex3fv(pos, v); + + sub_v3_v3v3(v, snap_source_tranformed, vy); + immVertex3fv(pos, v); + madd_v3_v3fl(v, vy, -size_fac); + immVertex3fv(pos, v); + + immEnd(); } immUnbindProgram(); @@ -236,7 +305,7 @@ void drawSnapping(const struct bContext *C, TransInfo *t) loc_prev = t->tsnap.snap_source; } - if (validSnap(t)) { + if (t->tsnap.status & SNAP_TARGET_FOUND) { loc_cur = t->tsnap.snap_target; } @@ -733,6 +802,28 @@ static eSnapTargetOP snap_target_select_from_spacetype(TransInfo *t) return ret; } +static void snap_object_context_init(TransInfo *t) +{ + if (t->data_type == &TransConvertType_Mesh) { + /* Ignore elements being transformed. */ + ED_transform_snap_object_context_set_editmesh_callbacks( + t->tsnap.object_context, + (bool (*)(BMVert *, void *))BM_elem_cb_check_hflag_disabled, + bm_edge_is_snap_target, + bm_face_is_snap_target, + POINTER_FROM_UINT(BM_ELEM_SELECT | BM_ELEM_HIDDEN)); + } + else { + /* Ignore hidden geometry in the general case. */ + ED_transform_snap_object_context_set_editmesh_callbacks( + t->tsnap.object_context, + (bool (*)(BMVert *, void *))BM_elem_cb_check_hflag_disabled, + (bool (*)(BMEdge *, void *))BM_elem_cb_check_hflag_disabled, + (bool (*)(BMFace *, void *))BM_elem_cb_check_hflag_disabled, + POINTER_FROM_UINT(BM_ELEM_HIDDEN)); + } +} + static void initSnappingMode(TransInfo *t) { if (!transformModeUseSnap(t)) { @@ -763,25 +854,7 @@ static void initSnappingMode(TransInfo *t) if (t->tsnap.object_context == nullptr) { SET_FLAG_FROM_TEST(t->tsnap.flag, snap_use_backface_culling(t), SCE_SNAP_BACKFACE_CULLING); t->tsnap.object_context = ED_transform_snap_object_context_create(t->scene, 0); - - if (t->data_type == &TransConvertType_Mesh) { - /* Ignore elements being transformed. */ - ED_transform_snap_object_context_set_editmesh_callbacks( - t->tsnap.object_context, - (bool (*)(BMVert *, void *))BM_elem_cb_check_hflag_disabled, - bm_edge_is_snap_target, - bm_face_is_snap_target, - POINTER_FROM_UINT(BM_ELEM_SELECT | BM_ELEM_HIDDEN)); - } - else { - /* Ignore hidden geometry in the general case. */ - ED_transform_snap_object_context_set_editmesh_callbacks( - t->tsnap.object_context, - (bool (*)(BMVert *, void *))BM_elem_cb_check_hflag_disabled, - (bool (*)(BMEdge *, void *))BM_elem_cb_check_hflag_disabled, - (bool (*)(BMFace *, void *))BM_elem_cb_check_hflag_disabled, - POINTER_FROM_UINT(BM_ELEM_HIDDEN)); - } + snap_object_context_init(t); } } else if (t->spacetype == SPACE_SEQ) { @@ -1075,6 +1148,15 @@ void getSnapPoint(const TransInfo *t, float vec[3]) } } +static void snap_multipoints_free(TransInfo *t) +{ + if (t->tsnap.status & SNAP_MULTI_POINTS) { + BLI_freelistN(&t->tsnap.points); + t->tsnap.status &= ~SNAP_MULTI_POINTS; + t->tsnap.selectedPoint = NULL; + } +} + /** \} */ /* -------------------------------------------------------------------- */ @@ -1713,6 +1795,12 @@ float transform_snap_increment_get(const TransInfo *t) return 0.0f; } +void tranform_snap_source_restore_context(TransInfo *t) +{ + snap_object_context_init(t); + snap_multipoints_free(t); +} + /** \} */ /* -------------------------------------------------------------------- */ diff --git a/source/blender/editors/transform/transform_snap.h b/source/blender/editors/transform/transform_snap.h index ff1a3b62ef3..fd567fb9ef0 100644 --- a/source/blender/editors/transform/transform_snap.h +++ b/source/blender/editors/transform/transform_snap.h @@ -43,6 +43,8 @@ bool transform_snap_increment_ex(const TransInfo *t, bool use_local_space, float bool transform_snap_increment(const TransInfo *t, float *val); float transform_snap_increment_get(const TransInfo *t); +void tranform_snap_source_restore_context(TransInfo *t); + void transform_snap_flag_from_modifiers_set(TransInfo *t); bool transform_snap_is_active(const TransInfo *t); diff --git a/source/blender/editors/transform/transform_snap_object.cc b/source/blender/editors/transform/transform_snap_object.cc index 5df0dbdc7b9..de6fa85ec34 100644 --- a/source/blender/editors/transform/transform_snap_object.cc +++ b/source/blender/editors/transform/transform_snap_object.cc @@ -298,7 +298,7 @@ static SnapData_EditMesh *snap_object_data_editmesh_get(SnapObjectContext *sctx, else if (sod->mesh_runtime) { if (sod->mesh_runtime != snap_object_data_editmesh_runtime_get(ob_eval)) { if (G.moving) { - /* Hack to avoid updating while transforming. */ + /* WORKAROUND: avoid updating while transforming. */ BLI_assert(!sod->treedata_editmesh.cached && !sod->cached[0] && !sod->cached[1]); sod->mesh_runtime = snap_object_data_editmesh_runtime_get(ob_eval); } @@ -381,11 +381,12 @@ static BVHTreeFromEditMesh *snap_object_data_editmesh_treedata_get(SnapObjectCon em, 4, BVHTREE_FROM_EM_LOOPTRI, - &sod->mesh_runtime->bvh_cache, + /* WORKAROUND: avoid updating while transforming. */ + G.moving ? nullptr : &sod->mesh_runtime->bvh_cache, &sod->mesh_runtime->eval_mutex); } } - if (treedata == nullptr || treedata->tree == nullptr) { + if (treedata->tree == nullptr) { return nullptr; } @@ -1263,7 +1264,7 @@ static bool nearest_world_editmesh(SnapObjectContext *sctx, int *r_index) { BVHTreeFromEditMesh *treedata = snap_object_data_editmesh_treedata_get(sctx, ob_eval, em); - if (treedata == nullptr || treedata->tree == nullptr) { + if (treedata == nullptr) { return false; } @@ -2765,7 +2766,8 @@ static eSnapMode snapEditMesh(SnapObjectContext *sctx, em, 2, BVHTREE_FROM_EM_VERTS, - &sod->mesh_runtime->bvh_cache, + /* WORKAROUND: avoid updating while transforming. */ + G.moving ? nullptr : &sod->mesh_runtime->bvh_cache, &sod->mesh_runtime->eval_mutex); } sod->bvhtree[0] = treedata.tree; @@ -2794,7 +2796,8 @@ static eSnapMode snapEditMesh(SnapObjectContext *sctx, em, 2, BVHTREE_FROM_EM_EDGES, - &sod->mesh_runtime->bvh_cache, + /* WORKAROUND: avoid updating while transforming. */ + G.moving ? nullptr : &sod->mesh_runtime->bvh_cache, &sod->mesh_runtime->eval_mutex); } sod->bvhtree[1] = treedata.tree; @@ -3063,11 +3066,27 @@ void ED_transform_snap_object_context_set_editmesh_callbacks( bool (*test_face_fn)(BMFace *, void *user_data), void *user_data) { - sctx->callbacks.edit_mesh.test_vert_fn = test_vert_fn; - sctx->callbacks.edit_mesh.test_edge_fn = test_edge_fn; - sctx->callbacks.edit_mesh.test_face_fn = test_face_fn; + bool is_cache_dirty = false; + if (sctx->callbacks.edit_mesh.test_vert_fn != test_vert_fn) { + sctx->callbacks.edit_mesh.test_vert_fn = test_vert_fn; + is_cache_dirty = true; + } + if (sctx->callbacks.edit_mesh.test_edge_fn != test_edge_fn) { + sctx->callbacks.edit_mesh.test_edge_fn = test_edge_fn; + is_cache_dirty = true; + } + if (sctx->callbacks.edit_mesh.test_face_fn != test_face_fn) { + sctx->callbacks.edit_mesh.test_face_fn = test_face_fn; + is_cache_dirty = true; + } + if (sctx->callbacks.edit_mesh.user_data != user_data) { + sctx->callbacks.edit_mesh.user_data = user_data; + is_cache_dirty = true; + } - sctx->callbacks.edit_mesh.user_data = user_data; + if (is_cache_dirty) { + sctx->editmesh_caches.clear(); + } } bool ED_transform_snap_object_project_ray_ex(SnapObjectContext *sctx, -- 2.30.2 From f92dff0735b52f596df37286573bbfd032514015 Mon Sep 17 00:00:00 2001 From: Germano Cavalcante Date: Fri, 19 May 2023 22:23:28 -0300 Subject: [PATCH 2/4] Transform: Make 'Absolute Grid Snapping' a new Snap Mode Suggested in #73993. The old "Absolute Grid Snap" option has been removed. tmp --- scripts/modules/rna_manual_reference.py | 2 - scripts/startup/bl_ui/space_image.py | 2 - scripts/startup/bl_ui/space_view3d.py | 2 - .../editors/space_view3d/view3d_cursor_snap.c | 2 +- .../editors/space_view3d/view3d_placement.c | 2 +- source/blender/editors/transform/transform.c | 39 +--- .../editors/transform/transform_generics.c | 1 + .../transform/transform_mode_translate.c | 71 +------- .../editors/transform/transform_snap.cc | 170 ++++++++++++++---- .../editors/transform/transform_snap.h | 2 + source/blender/makesdna/DNA_scene_types.h | 2 +- source/blender/makesrna/intern/rna_scene.c | 30 +--- 12 files changed, 154 insertions(+), 171 deletions(-) diff --git a/scripts/modules/rna_manual_reference.py b/scripts/modules/rna_manual_reference.py index 7218c8ec1cc..560b989a82f 100644 --- a/scripts/modules/rna_manual_reference.py +++ b/scripts/modules/rna_manual_reference.py @@ -346,7 +346,6 @@ url_manual_mapping = ( ("bpy.types.toolsettings.use_edge_path_live_unwrap*", "modeling/meshes/tools/tool_settings.html#bpy-types-toolsettings-use-edge-path-live-unwrap"), ("bpy.types.toolsettings.use_gpencil_draw_additive*", "grease_pencil/modes/draw/introduction.html#bpy-types-toolsettings-use-gpencil-draw-additive"), ("bpy.types.toolsettings.use_snap_backface_culling*", "editors/3dview/controls/snapping.html#bpy-types-toolsettings-use-snap-backface-culling"), - ("bpy.types.toolsettings.use_snap_uv_grid_absolute*", "editors/uv/controls/snapping.html#bpy-types-toolsettings-use-snap-uv-grid-absolute"), ("bpy.types.toolsettings.use_transform_data_origin*", "scene_layout/object/tools/tool_settings.html#bpy-types-toolsettings-use-transform-data-origin"), ("bpy.types.view3doverlay.sculpt_mode_mask_opacity*", "sculpt_paint/sculpting/editing/mask.html#bpy-types-view3doverlay-sculpt-mode-mask-opacity"), ("bpy.types.view3doverlay.viewer_attribute_opacity*", "modeling/geometry_nodes/output/viewer.html#bpy-types-view3doverlay-viewer-attribute-opacity"), @@ -538,7 +537,6 @@ url_manual_mapping = ( ("bpy.types.spacespreadsheet.show_only_selected*", "editors/spreadsheet.html#bpy-types-spacespreadsheet-show-only-selected"), ("bpy.types.spacespreadsheetrowfilter.operation*", "editors/spreadsheet.html#bpy-types-spacespreadsheetrowfilter-operation"), ("bpy.types.spacespreadsheetrowfilter.threshold*", "editors/spreadsheet.html#bpy-types-spacespreadsheetrowfilter-threshold"), - ("bpy.types.toolsettings.use_snap_grid_absolute*", "editors/3dview/controls/snapping.html#bpy-types-toolsettings-use-snap-grid-absolute"), ("bpy.types.transformsequence.use_uniform_scale*", "video_editing/edit/montage/strips/effects/transform.html#bpy-types-transformsequence-use-uniform-scale"), ("bpy.types.view3doverlay.show_face_orientation*", "editors/3dview/display/overlays.html#bpy-types-view3doverlay-show-face-orientation"), ("bpy.types.view3doverlay.show_viewer_attribute*", "modeling/geometry_nodes/output/viewer.html#bpy-types-view3doverlay-show-viewer-attribute"), diff --git a/scripts/startup/bl_ui/space_image.py b/scripts/startup/bl_ui/space_image.py index 3d225ec569e..eda2be23e12 100644 --- a/scripts/startup/bl_ui/space_image.py +++ b/scripts/startup/bl_ui/space_image.py @@ -978,8 +978,6 @@ class IMAGE_PT_snapping(Panel): row.prop(tool_settings, "snap_target", expand=True) col.separator() - if 'INCREMENT' in tool_settings.snap_uv_element: - col.prop(tool_settings, "use_snap_uv_grid_absolute") col.label(text="Affect") row = col.row(align=True) diff --git a/scripts/startup/bl_ui/space_view3d.py b/scripts/startup/bl_ui/space_view3d.py index 7837df869b4..d0f4f840d20 100644 --- a/scripts/startup/bl_ui/space_view3d.py +++ b/scripts/startup/bl_ui/space_view3d.py @@ -7029,8 +7029,6 @@ class VIEW3D_PT_snapping(Panel): col.prop(tool_settings, "snap_elements", expand=True) col.separator() - if 'INCREMENT' in snap_elements: - col.prop(tool_settings, "use_snap_grid_absolute") if snap_elements != {'INCREMENT'}: if snap_elements != {'FACE_NEAREST'}: diff --git a/source/blender/editors/space_view3d/view3d_cursor_snap.c b/source/blender/editors/space_view3d/view3d_cursor_snap.c index 5ca82755cb7..d4972b43dec 100644 --- a/source/blender/editors/space_view3d/view3d_cursor_snap.c +++ b/source/blender/editors/space_view3d/view3d_cursor_snap.c @@ -136,7 +136,7 @@ static bool v3d_cursor_snap_calc_incremental( return false; } - if (scene->toolsettings->snap_flag & SCE_SNAP_ABS_GRID) { + if (scene->toolsettings->snap_mode & SCE_SNAP_MODE_GRID) { co_relative = NULL; } diff --git a/source/blender/editors/space_view3d/view3d_placement.c b/source/blender/editors/space_view3d/view3d_placement.c index 2f1a779dc88..e10a08c4dba 100644 --- a/source/blender/editors/space_view3d/view3d_placement.c +++ b/source/blender/editors/space_view3d/view3d_placement.c @@ -219,7 +219,7 @@ static bool idp_snap_calc_incremental( return false; } - if (scene->toolsettings->snap_flag & SCE_SNAP_ABS_GRID) { + if (scene->toolsettings->snap_mode & SCE_SNAP_MODE_GRID) { co_relative = NULL; } diff --git a/source/blender/editors/transform/transform.c b/source/blender/editors/transform/transform.c index 7882cdb9e14..3e6c060352e 100644 --- a/source/blender/editors/transform/transform.c +++ b/source/blender/editors/transform/transform.c @@ -1790,43 +1790,6 @@ void saveTransform(bContext *C, TransInfo *t, wmOperator *op) } } -static void initSnapSpatial(TransInfo *t, float r_snap[3], float *r_snap_precision) -{ - /* Default values. */ - r_snap[0] = r_snap[1] = 1.0f; - r_snap[2] = 0.0f; - *r_snap_precision = 0.1f; - - if (t->spacetype == SPACE_VIEW3D) { - if (t->region->regiondata) { - View3D *v3d = t->area->spacedata.first; - r_snap[0] = r_snap[1] = r_snap[2] = ED_view3d_grid_view_scale( - t->scene, v3d, t->region, NULL); - } - } - else if (t->spacetype == SPACE_IMAGE) { - SpaceImage *sima = t->area->spacedata.first; - View2D *v2d = &t->region->v2d; - int grid_size = SI_GRID_STEPS_LEN; - float zoom_factor = ED_space_image_zoom_level(v2d, grid_size); - float grid_steps_x[SI_GRID_STEPS_LEN]; - float grid_steps_y[SI_GRID_STEPS_LEN]; - - ED_space_image_grid_steps(sima, grid_steps_x, grid_steps_y, grid_size); - /* Snapping value based on what type of grid is used (adaptive-subdividing or custom-grid). */ - r_snap[0] = ED_space_image_increment_snap_value(grid_size, grid_steps_x, zoom_factor); - r_snap[1] = ED_space_image_increment_snap_value(grid_size, grid_steps_y, zoom_factor); - *r_snap_precision = 0.5f; - } - else if (t->spacetype == SPACE_CLIP) { - r_snap[0] = r_snap[1] = 0.125f; - *r_snap_precision = 0.5f; - } - else if (t->spacetype == SPACE_NODE) { - r_snap[0] = r_snap[1] = ED_node_grid_size(); - } -} - bool initTransform(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *event, int mode) { int options = 0; @@ -1991,7 +1954,7 @@ bool initTransform(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve initSnapping(t, op); /* Initialize snapping data AFTER mode flags */ - initSnapSpatial(t, t->snap_spatial, &t->snap_spatial_precision); + transform_snap_grid_init(t); /* EVIL! posemode code can switch translation to rotate when 1 bone is selected. * will be removed (ton) */ diff --git a/source/blender/editors/transform/transform_generics.c b/source/blender/editors/transform/transform_generics.c index 3d3ad5a2dd5..ee40e67a4ba 100644 --- a/source/blender/editors/transform/transform_generics.c +++ b/source/blender/editors/transform/transform_generics.c @@ -1229,6 +1229,7 @@ void tranformViewUpdate(TransInfo *t) calculateCenter2D(t); transform_input_update(t, zoom_prev / zoom_new); + transform_snap_grid_init(t); } void calculatePropRatio(TransInfo *t) diff --git a/source/blender/editors/transform/transform_mode_translate.c b/source/blender/editors/transform/transform_mode_translate.c index 8821d3e09c0..5874caf17f6 100644 --- a/source/blender/editors/transform/transform_mode_translate.c +++ b/source/blender/editors/transform/transform_mode_translate.c @@ -370,68 +370,6 @@ static void translate_snap_target_grid_ensure(TransInfo *t) } } -static void translate_snap_grid_apply(TransInfo *t, - const int max_index, - const float grid_dist[3], - const float loc[3], - float r_out[3]) -{ - BLI_assert(max_index <= 2); - translate_snap_target_grid_ensure(t); - const float *center_global = t->tsnap.snap_target_grid; - const float *asp = t->aspect; - - float in[3]; - if (t->con.mode & CON_APPLY) { - BLI_assert(t->tsnap.snapElem == SCE_SNAP_MODE_NONE); - t->con.applyVec(t, NULL, NULL, loc, in); - } - else { - copy_v3_v3(in, loc); - } - - for (int i = 0; i <= max_index; i++) { - const float iter_fac = grid_dist[i] * asp[i]; - r_out[i] = iter_fac * roundf((in[i] + center_global[i]) / iter_fac) - center_global[i]; - } -} - -static bool translate_snap_grid(TransInfo *t, float *val) -{ - if (!transform_snap_is_active(t)) { - return false; - } - - if (!(t->tsnap.mode & SCE_SNAP_MODE_GRID) || validSnap(t)) { - /* Don't do grid snapping if there is a valid snap point. */ - return false; - } - - /* Don't do grid snapping if not in 3D viewport or UV editor */ - if (!ELEM(t->spacetype, SPACE_VIEW3D, SPACE_IMAGE)) { - return false; - } - - if (t->mode != TFM_TRANSLATION) { - return false; - } - - float grid_dist[3]; - copy_v3_v3(grid_dist, t->snap_spatial); - if (t->modifiers & MOD_PRECISION) { - mul_v3_fl(grid_dist, t->snap_spatial_precision); - } - - /* Early bailing out if no need to snap */ - if (is_zero_v3(grid_dist)) { - return false; - } - - translate_snap_grid_apply(t, t->idx_max, grid_dist, val, val); - t->tsnap.snapElem = SCE_SNAP_MODE_GRID; - return true; -} - static void ApplySnapTranslation(TransInfo *t, float vec[3]) { float point[3]; @@ -459,7 +397,13 @@ static void ApplySnapTranslation(TransInfo *t, float vec[3]) } } - sub_v3_v3v3(vec, point, t->tsnap.snap_source); + if (t->tsnap.snapElem == SCE_SNAP_MODE_GRID) { + translate_snap_target_grid_ensure(t); + sub_v3_v3v3(vec, point, t->tsnap.snap_target_grid); + } + else { + sub_v3_v3v3(vec, point, t->tsnap.snap_source); + } } } @@ -610,7 +554,6 @@ static void applyTranslation(TransInfo *t, const int UNUSED(mval[2])) } transform_snap_mixed_apply(t, global_dir); - translate_snap_grid(t, global_dir); if (t->con.mode & CON_APPLY) { float in[3]; diff --git a/source/blender/editors/transform/transform_snap.cc b/source/blender/editors/transform/transform_snap.cc index 09cc69744fc..2dd19609a3d 100644 --- a/source/blender/editors/transform/transform_snap.cc +++ b/source/blender/editors/transform/transform_snap.cc @@ -32,6 +32,7 @@ #include "WM_types.h" #include "ED_gizmo_library.h" +#include "ED_image.h" #include "ED_markers.h" #include "ED_node.h" #include "ED_transform_snap_object_context.h" @@ -48,6 +49,7 @@ #include "MEM_guardedalloc.h" #include "transform.h" +#include "transform_constraints.h" #include "transform_convert.h" #include "transform_snap.h" @@ -254,7 +256,8 @@ void drawSnapping(const struct bContext *C, TransInfo *t) } if (draw_source_transformed && - !compare_v3v3(snap_source_tranformed, t->tsnap.snap_target, FLT_EPSILON)) { + !compare_v3v3(snap_source_tranformed, t->tsnap.snap_target, FLT_EPSILON)) + { float view_inv[4][4]; copy_m4_m4(view_inv, rv3d->viewinv); @@ -597,13 +600,13 @@ void transform_snap_mixed_apply(TransInfo *t, float *vec) return; } - if (t->tsnap.mode & ~(SCE_SNAP_MODE_INCREMENT | SCE_SNAP_MODE_GRID)) { + if (t->tsnap.mode != SCE_SNAP_MODE_INCREMENT) { double current = PIL_check_seconds_timer(); /* Time base quirky code to go around find-nearest slowness. */ /* TODO: add exception for object mode, no need to slow it down then. */ if (current - t->tsnap.last >= 0.01) { - if (t->tsnap.snap_target_fn) { + if (t->tsnap.snap_target_fn && (t->tsnap.mode != SCE_SNAP_MODE_GRID)) { t->tsnap.snap_target_fn(t, vec); } if (t->tsnap.snap_source_fn) { @@ -712,14 +715,7 @@ static eSnapMode snap_mode_from_spacetype(TransInfo *t) } if (t->spacetype == SPACE_IMAGE) { - eSnapMode snap_mode = eSnapMode(ts->snap_uv_mode); - if ((snap_mode & SCE_SNAP_MODE_INCREMENT) && (ts->snap_uv_flag & SCE_SNAP_ABS_GRID) && - (t->mode == TFM_TRANSLATION)) - { - snap_mode &= ~SCE_SNAP_MODE_INCREMENT; - snap_mode |= SCE_SNAP_MODE_GRID; - } - return snap_mode; + return eSnapMode(ts->snap_uv_mode); } if (t->spacetype == SPACE_SEQ) { @@ -730,16 +726,7 @@ static eSnapMode snap_mode_from_spacetype(TransInfo *t) if (t->options & (CTX_CAMERA | CTX_EDGE_DATA | CTX_PAINT_CURVE)) { return SCE_SNAP_MODE_INCREMENT; } - - eSnapMode snap_mode = eSnapMode(ts->snap_mode); - if ((snap_mode & SCE_SNAP_MODE_INCREMENT) && (ts->snap_flag & SCE_SNAP_ABS_GRID) && - (t->mode == TFM_TRANSLATION)) - { - /* Special case in which snap to increments is transformed to snap to grid. */ - snap_mode &= ~SCE_SNAP_MODE_INCREMENT; - snap_mode |= SCE_SNAP_MODE_GRID; - } - return snap_mode; + return eSnapMode(ts->snap_mode); } if (ELEM(t->spacetype, SPACE_ACTION, SPACE_NLA)) { @@ -1159,6 +1146,107 @@ static void snap_multipoints_free(TransInfo *t) /** \} */ +/* -------------------------------------------------------------------- */ +/** \name Calc Snap + * \{ */ + +void transform_snap_grid_init(TransInfo *t) +{ + /* Default values. */ + float grid_dist[3] = {1.0f, 1.0f, 0.0f}; + float grid_dist_precision = 0.1f; + + if (t->spacetype == SPACE_VIEW3D) { + if (t->region->regiondata) { + View3D *v3d = static_cast(t->area->spacedata.first); + grid_dist[0] = grid_dist[1] = grid_dist[2] = ED_view3d_grid_view_scale( + t->scene, v3d, t->region, NULL); + } + } + else if (t->spacetype == SPACE_IMAGE) { + SpaceImage *sima = static_cast(t->area->spacedata.first); + View2D *v2d = &t->region->v2d; + int grid_size = SI_GRID_STEPS_LEN; + float zoom_factor = ED_space_image_zoom_level(v2d, grid_size); + float grid_steps_x[SI_GRID_STEPS_LEN]; + float grid_steps_y[SI_GRID_STEPS_LEN]; + + ED_space_image_grid_steps(sima, grid_steps_x, grid_steps_y, grid_size); + /* Snapping value based on what type of grid is used (adaptive-subdividing or custom-grid). */ + grid_dist[0] = ED_space_image_increment_snap_value(grid_size, grid_steps_x, zoom_factor); + grid_dist[1] = ED_space_image_increment_snap_value(grid_size, grid_steps_y, zoom_factor); + grid_dist_precision = 0.5f; + } + else if (t->spacetype == SPACE_CLIP) { + grid_dist[0] = grid_dist[1] = 0.125f; + grid_dist_precision = 0.5f; + } + else if (t->spacetype == SPACE_NODE) { + grid_dist[0] = grid_dist[1] = ED_node_grid_size(); + } + + copy_v3_v3(t->snap_spatial, grid_dist); + t->snap_spatial_precision = grid_dist_precision; + + if (t->mode == TFM_TRANSLATION) { + /* WORKAROUND: Reset incremental snap values. */ + t->snap[0] = t->snap_spatial[0]; + t->snap[1] = t->snap_spatial[0] * t->snap_spatial_precision; + } +} + +static bool snap_grid(TransInfo *t, const float mval[2], const int val_size, float *r_val) +{ + float grid_dist[3]; + copy_v3_v3(grid_dist, t->snap_spatial); + if (t->modifiers & MOD_PRECISION) { + mul_v3_fl(grid_dist, t->snap_spatial_precision); + } + + /* Early bailing out if no need to snap */ + if (is_zero_v3(grid_dist)) { + return false; + } + + if (t->spacetype == SPACE_VIEW3D) { + float lambda; + float plane[4]; + float ray_dir[3]; + ED_view3d_win_to_ray_clipped( + t->depsgraph, t->region, (View3D *)t->view, mval, r_val, ray_dir, true); + + plane_from_point_normal_v3(plane, t->center_global, ray_dir); + + if (isect_ray_plane_v3(r_val, ray_dir, plane, &lambda, true)) { + madd_v3_v3fl(r_val, ray_dir, lambda); + } + else { + return false; + } + } + else { + const View2D *v2d = &t->region->v2d; + float scale[2], offset[2]; + UI_view2d_scale_get(v2d, &scale[0], &scale[1]); + UI_view2d_view_to_region_fl(v2d, 0.0f, 0.0f, &offset[0], &offset[1]); + + sub_v2_v2v2(r_val, mval, offset); + r_val[0] /= scale[0]; + r_val[1] /= scale[1]; + } + + /* Apply. */ + for (int i = 0; i < val_size; i++) { + const float iter_fac = grid_dist[i] * t->aspect[i]; + r_val[i] = iter_fac * roundf(r_val[i] / iter_fac); + } + + t->tsnap.snapElem = SCE_SNAP_MODE_GRID; + return true; +} + +/** \} */ + /* -------------------------------------------------------------------- */ /** \name Calc Snap * \{ */ @@ -1169,28 +1257,31 @@ static void snap_target_view3d_fn(TransInfo *t, float * /*vec*/) float loc[3]; float no[3]; float mval[2]; - bool found = false; eSnapMode snap_elem = SCE_SNAP_MODE_NONE; float dist_px = SNAP_MIN_DISTANCE; /* Use a user defined value here. */ + zero_v3(no); /* objects won't set this */ mval[0] = t->mval[0]; mval[1] = t->mval[1]; if (t->tsnap.mode & SCE_SNAP_MODE_GEOM) { - zero_v3(no); /* objects won't set this */ snap_elem = snapObjectsTransform(t, mval, &dist_px, loc, no); - found = (snap_elem != SCE_SNAP_MODE_NONE); } - if ((found == false) && (t->tsnap.mode & SCE_SNAP_MODE_VOLUME)) { - bool use_peel = (t->settings->snap_flag & SCE_SNAP_PEEL_OBJECT) != 0; - found = peelObjectsTransform(t, mval, use_peel, loc, no, nullptr); - if (found) { + if ((snap_elem == SCE_SNAP_MODE_NONE) && (t->tsnap.mode & SCE_SNAP_MODE_VOLUME)) { + bool use_peel = (t->settings->snap_flag & SCE_SNAP_PEEL_OBJECT) != 0; + if (peelObjectsTransform(t, mval, use_peel, loc, no, nullptr)) { snap_elem = SCE_SNAP_MODE_VOLUME; } } - if (found == true) { + if ((snap_elem == SCE_SNAP_MODE_NONE) && (t->tsnap.mode & SCE_SNAP_MODE_GRID)) { + if (snap_grid(t, mval, 3, loc)) { + snap_elem = SCE_SNAP_MODE_GRID; + } + } + + if (snap_elem != SCE_SNAP_MODE_NONE) { copy_v3_v3(t->tsnap.snap_target, loc); copy_v3_v3(t->tsnap.snapNormal, no); @@ -1206,6 +1297,8 @@ static void snap_target_view3d_fn(TransInfo *t, float * /*vec*/) static void snap_target_uv_fn(TransInfo *t, float * /*vec*/) { BLI_assert(t->spacetype == SPACE_IMAGE); + + eSnapMode snap_elem = SCE_SNAP_MODE_NONE; if (t->tsnap.mode & SCE_SNAP_MODE_VERTEX) { uint objects_len = 0; Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs( @@ -1224,13 +1317,22 @@ static void snap_target_uv_fn(TransInfo *t, float * /*vec*/) t->tsnap.snap_target[0] *= t->aspect[0]; t->tsnap.snap_target[1] *= t->aspect[1]; - t->tsnap.status |= SNAP_TARGET_FOUND; - } - else { - t->tsnap.status &= ~SNAP_TARGET_FOUND; + snap_elem = SCE_SNAP_MODE_VERTEX; } MEM_freeN(objects); } + + if ((snap_elem == SCE_SNAP_MODE_NONE) && (t->tsnap.mode & SCE_SNAP_MODE_GRID)) { + float mval[2]; + mval[0] = t->mval[0]; + mval[1] = t->mval[1]; + if (snap_grid(t, mval, 2, t->tsnap.snap_target)) { + snap_elem = SCE_SNAP_MODE_GRID; + } + } + + SET_FLAG_FROM_TEST(t->tsnap.status, snap_elem != SCE_SNAP_MODE_NONE, SNAP_TARGET_FOUND); + t->tsnap.snapElem = snap_elem; } static void snap_target_node_fn(TransInfo *t, float * /*vec*/) @@ -1698,7 +1800,7 @@ bool snapNodesTransform( /** \} */ /* -------------------------------------------------------------------- */ -/** \name snap Grid +/** \name snap Increment * \{ */ static void snap_increment_apply_ex(const TransInfo * /*t*/, diff --git a/source/blender/editors/transform/transform_snap.h b/source/blender/editors/transform/transform_snap.h index fd567fb9ef0..cb5b4daa8ec 100644 --- a/source/blender/editors/transform/transform_snap.h +++ b/source/blender/editors/transform/transform_snap.h @@ -38,6 +38,8 @@ bool snapNodesTransform(struct TransInfo *t, bool transformModeUseSnap(const TransInfo *t); +void transform_snap_grid_init(TransInfo *t); + void tranform_snap_target_median_calc(const TransInfo *t, float r_median[3]); bool transform_snap_increment_ex(const TransInfo *t, bool use_local_space, float *r_val); bool transform_snap_increment(const TransInfo *t, float *val); diff --git a/source/blender/makesdna/DNA_scene_types.h b/source/blender/makesdna/DNA_scene_types.h index e54b70023a2..ac673ada317 100644 --- a/source/blender/makesdna/DNA_scene_types.h +++ b/source/blender/makesdna/DNA_scene_types.h @@ -2257,7 +2257,7 @@ typedef enum eSnapFlag { SCE_SNAP_PROJECT = (1 << 3), /** Was `SCE_SNAP_NO_SELF`, but self should be active. */ SCE_SNAP_NOT_TO_ACTIVE = (1 << 4), - SCE_SNAP_ABS_GRID = (1 << 5), + /* SCE_SNAP_ABS_GRID = (1 << 5), */ /* UNUSED */ SCE_SNAP_BACKFACE_CULLING = (1 << 6), SCE_SNAP_KEEP_ON_SAME_OBJECT = (1 << 7), /** see #eSnapTargetOP */ diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c index d9d3fa959b5..2853711c49d 100644 --- a/source/blender/makesrna/intern/rna_scene.c +++ b/source/blender/makesrna/intern/rna_scene.c @@ -150,11 +150,8 @@ const EnumPropertyItem rna_enum_mesh_select_mode_uv_items[] = { }; const EnumPropertyItem rna_enum_snap_element_items[] = { - {SCE_SNAP_MODE_INCREMENT, - "INCREMENT", - ICON_SNAP_INCREMENT, - "Increment", - "Snap to increments of grid"}, + {SCE_SNAP_MODE_INCREMENT, "INCREMENT", ICON_SNAP_INCREMENT, "Increment", "Snap to increments"}, + {SCE_SNAP_MODE_GRID, "GRID", ICON_SNAP_GRID, "Grid", "Snap to grid"}, {SCE_SNAP_MODE_VERTEX, "VERTEX", ICON_SNAP_VERTEX, "Vertex", "Snap to vertices"}, {SCE_SNAP_MODE_EDGE, "EDGE", ICON_SNAP_EDGE, "Edge", "Snap to edges"}, {SCE_SNAP_MODE_FACE_RAYCAST, @@ -195,11 +192,8 @@ const EnumPropertyItem rna_enum_snap_node_element_items[] = { #ifndef RNA_RUNTIME static const EnumPropertyItem snap_uv_element_items[] = { - {SCE_SNAP_MODE_INCREMENT, - "INCREMENT", - ICON_SNAP_INCREMENT, - "Increment", - "Snap to increments of grid"}, + {SCE_SNAP_MODE_INCREMENT, "INCREMENT", ICON_SNAP_INCREMENT, "Increment", "Snap to increments"}, + {SCE_SNAP_MODE_GRID, "GRID", ICON_SNAP_GRID, "Grid", "Snap to grid"}, {SCE_SNAP_MODE_VERTEX, "VERTEX", ICON_SNAP_VERTEX, "Vertex", "Snap to vertices"}, {0, NULL, 0, NULL, NULL}, }; @@ -3383,14 +3377,6 @@ static void rna_def_tool_settings(BlenderRNA *brna) prop, "Align Rotation to Target", "Align rotation with the snapping target"); RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL); /* header redraw */ - prop = RNA_def_property(srna, "use_snap_grid_absolute", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "snap_flag", SCE_SNAP_ABS_GRID); - RNA_def_property_ui_text( - prop, - "Absolute Grid Snap", - "Absolute grid alignment while translating (based on the pivot center)"); - RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL); /* header redraw */ - prop = RNA_def_property(srna, "snap_elements", PROP_ENUM, PROP_NONE); RNA_def_property_enum_bitflag_sdna(prop, NULL, "snap_mode"); RNA_def_property_enum_items(prop, rna_enum_snap_element_items); @@ -3428,14 +3414,6 @@ static void rna_def_tool_settings(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Snap UV Element", "Type of element to snap to"); RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL); /* header redraw */ - prop = RNA_def_property(srna, "use_snap_uv_grid_absolute", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "snap_uv_flag", SCE_SNAP_ABS_GRID); - RNA_def_property_ui_text( - prop, - "Absolute Grid Snap", - "Absolute grid alignment while translating (based on the pivot center)"); - RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL); /* header redraw */ - /* TODO(@gfxcoder): Rename `snap_target` to `snap_source` to avoid previous ambiguity of "target" * (now, "source" is geometry to be moved and "target" is geometry to which moved geometry is * snapped). */ -- 2.30.2 From 519bbdccee5746ae55d73b23027be447c1f6aeb5 Mon Sep 17 00:00:00 2001 From: Germano Cavalcante Date: Wed, 22 Mar 2023 11:44:38 -0300 Subject: [PATCH 3/4] Transform: Support 'Snap with' options for Snap to Grid Suggested in #73993 --- source/blender/editors/transform/transform.h | 7 ++--- .../transform/transform_mode_translate.c | 28 ------------------- .../editors/transform/transform_snap.cc | 2 +- 3 files changed, 3 insertions(+), 34 deletions(-) diff --git a/source/blender/editors/transform/transform.h b/source/blender/editors/transform/transform.h index 106f5e37807..50b61a199c2 100644 --- a/source/blender/editors/transform/transform.h +++ b/source/blender/editors/transform/transform.h @@ -165,10 +165,8 @@ ENUM_OPERATORS(eTModifier, MOD_NODE_ATTACH) typedef enum eTSnap { SNAP_RESETTED = 0, SNAP_SOURCE_FOUND = 1 << 0, - /* Special flag for snap to grid. */ - SNAP_TARGET_GRID_FOUND = 1 << 1, - SNAP_TARGET_FOUND = 1 << 2, - SNAP_MULTI_POINTS = 1 << 3, + SNAP_TARGET_FOUND = 1 << 1, + SNAP_MULTI_POINTS = 1 << 2, } eTSnap; ENUM_OPERATORS(eTSnap, SNAP_MULTI_POINTS) @@ -303,7 +301,6 @@ typedef struct TransSnap { float snap_source[3]; /** to this point (in global-space). */ float snap_target[3]; - float snap_target_grid[3]; float snapNormal[3]; char snapNodeBorder; ListBase points; diff --git a/source/blender/editors/transform/transform_mode_translate.c b/source/blender/editors/transform/transform_mode_translate.c index 5874caf17f6..23073c40605 100644 --- a/source/blender/editors/transform/transform_mode_translate.c +++ b/source/blender/editors/transform/transform_mode_translate.c @@ -348,28 +348,6 @@ static void headerTranslation(TransInfo *t, const float vec[3], char str[UI_MAX_ /** \name Transform (Translation) Snapping * \{ */ -static void translate_snap_target_grid_ensure(TransInfo *t) -{ - /* Only need to calculate once. */ - if ((t->tsnap.status & SNAP_TARGET_GRID_FOUND) == 0) { - if (t->data_type == &TransConvertType_Cursor3D) { - /* Use a fallback when transforming the cursor. - * In this case the center is _not_ derived from the cursor which is being transformed. */ - copy_v3_v3(t->tsnap.snap_target_grid, TRANS_DATA_CONTAINER_FIRST_SINGLE(t)->data->iloc); - } - else if (t->around == V3D_AROUND_CURSOR) { - /* Use a fallback for cursor selection, - * this isn't useful as a global center for absolute grid snapping - * since its not based on the position of the selection. */ - tranform_snap_target_median_calc(t, t->tsnap.snap_target_grid); - } - else { - copy_v3_v3(t->tsnap.snap_target_grid, t->center_global); - } - t->tsnap.status |= SNAP_TARGET_GRID_FOUND; - } -} - static void ApplySnapTranslation(TransInfo *t, float vec[3]) { float point[3]; @@ -397,13 +375,7 @@ static void ApplySnapTranslation(TransInfo *t, float vec[3]) } } - if (t->tsnap.snapElem == SCE_SNAP_MODE_GRID) { - translate_snap_target_grid_ensure(t); - sub_v3_v3v3(vec, point, t->tsnap.snap_target_grid); - } - else { sub_v3_v3v3(vec, point, t->tsnap.snap_source); - } } } diff --git a/source/blender/editors/transform/transform_snap.cc b/source/blender/editors/transform/transform_snap.cc index 2dd19609a3d..fe740675eed 100644 --- a/source/blender/editors/transform/transform_snap.cc +++ b/source/blender/editors/transform/transform_snap.cc @@ -606,7 +606,7 @@ void transform_snap_mixed_apply(TransInfo *t, float *vec) /* Time base quirky code to go around find-nearest slowness. */ /* TODO: add exception for object mode, no need to slow it down then. */ if (current - t->tsnap.last >= 0.01) { - if (t->tsnap.snap_target_fn && (t->tsnap.mode != SCE_SNAP_MODE_GRID)) { + if (t->tsnap.snap_target_fn) { t->tsnap.snap_target_fn(t, vec); } if (t->tsnap.snap_source_fn) { -- 2.30.2 From 8b5f6d36e14bc35e17413632c3cee84ad8026547 Mon Sep 17 00:00:00 2001 From: Germano Cavalcante Date: Mon, 20 Mar 2023 15:10:03 -0300 Subject: [PATCH 4/4] Transform: Snap to Grid in Perspective View performed at ground level Suggested in #73993. --- .../editors/transform/transform_constraints.c | 80 ++++++++++++++----- .../editors/transform/transform_constraints.h | 13 +++ .../transform/transform_mode_snapsource.c | 6 +- .../editors/transform/transform_snap.cc | 27 +++++-- 4 files changed, 98 insertions(+), 28 deletions(-) diff --git a/source/blender/editors/transform/transform_constraints.c b/source/blender/editors/transform/transform_constraints.c index c040230e800..a8c1d7b0f09 100644 --- a/source/blender/editors/transform/transform_constraints.c +++ b/source/blender/editors/transform/transform_constraints.c @@ -101,6 +101,20 @@ static void constraint_plane_calc(const TransInfo *t, float r_plane[4]) r_plane[3] = -dot_v3v3(r_plane, t->center_global); } +static void constraint_axis_calc(const TransInfo *t, float r_dir[4]) +{ + if (t->con.mode & CON_AXIS0) { + copy_v3_v3(r_dir, t->spacemtx[0]); + } + else if (t->con.mode & CON_AXIS1) { + copy_v3_v3(r_dir, t->spacemtx[1]); + } + else { + BLI_assert(t->con.mode & CON_AXIS2); + copy_v3_v3(r_dir, t->spacemtx[2]); + } +} + void constraintNumInput(TransInfo *t, float vec[3]) { int mode = t->con.mode; @@ -170,6 +184,20 @@ static void viewAxisCorrectCenter(const TransInfo *t, float t_con_center[3]) } } +static bool isAxisProjectionViewAligned(const TransInfo *t, const float axis[3]) +{ + float angle = fabsf(angle_v3v3(axis, t->viewinv[2])); + if (angle > (float)M_PI_2) { + angle = (float)M_PI - angle; + } + + if (angle < DEG2RADF(5.0f)) { + return true; + } + + return false; +} + /** * Axis calculation taking the view into account, correcting view-aligned axis. */ @@ -178,7 +206,7 @@ static void axisProjection(const TransInfo *t, const float in[3], float out[3]) { - float vec[3], factor, angle; + float vec[3], factor; float t_con_center[3]; if (is_zero_v3(in)) { @@ -190,15 +218,10 @@ static void axisProjection(const TransInfo *t, /* checks for center being too close to the view center */ viewAxisCorrectCenter(t, t_con_center); - angle = fabsf(angle_v3v3(axis, t->viewinv[2])); - if (angle > (float)M_PI_2) { - angle = (float)M_PI - angle; - } - /* For when view is parallel to constraint... will cause NaNs otherwise * So we take vertical motion in 3D space and apply it to the * constraint axis. Nice for camera grab + MMB */ - if (angle < DEG2RADF(5.0f)) { + if (isAxisProjectionViewAligned(t, axis)) { project_v3_v3v3(vec, in, t->viewinv[1]); factor = dot_v3v3(t->viewinv[1], vec) * 2.0f; /* Since camera distance is quite relative, use quadratic relationship. @@ -434,17 +457,7 @@ static void applyAxisConstraintVec(const TransInfo *t, } else if (dims == 1) { float c[3]; - - if (t->con.mode & CON_AXIS0) { - copy_v3_v3(c, t->spacemtx[0]); - } - else if (t->con.mode & CON_AXIS1) { - copy_v3_v3(c, t->spacemtx[1]); - } - else { - BLI_assert(t->con.mode & CON_AXIS2); - copy_v3_v3(c, t->spacemtx[2]); - } + constraint_axis_calc(t, c); if (is_snap_to_edge) { transform_constraint_snap_axis_to_edge(t, c, out); @@ -1250,3 +1263,34 @@ int getConstraintSpaceDimension(const TransInfo *t) } /** \} */ + +bool transform_constraint_isect_ray(const TransInfo *t, + const float ray_co[3], + const float ray_dir[3], + float out[3]) +{ + float lambda; + const int dims = getConstraintSpaceDimension(t); + if (dims == 2) { + float plane[4]; + constraint_plane_calc(t, plane); + if (!isPlaneProjectionViewAligned(t, plane)) { + if (isect_ray_plane_v3(ray_co, ray_dir, plane, &lambda, false)) { + madd_v3_v3v3fl(out, ray_co, ray_dir, lambda); + return true; + } + } + } + else if (dims == 1) { + float axis[3]; + constraint_axis_calc(t, axis); + if (!isAxisProjectionViewAligned(t, axis)) { + if (isect_ray_ray_v3(t->center_global, axis, ray_co, ray_dir, &lambda, NULL)) { + madd_v3_v3v3fl(out, t->center_global, axis, lambda); + return true; + } + } + } + + return false; +} diff --git a/source/blender/editors/transform/transform_constraints.h b/source/blender/editors/transform/transform_constraints.h index 90a693b089e..ed6b0610af9 100644 --- a/source/blender/editors/transform/transform_constraints.h +++ b/source/blender/editors/transform/transform_constraints.h @@ -7,6 +7,10 @@ #pragma once +#ifdef __cplusplus +extern "C" { +#endif + struct TransInfo; void constraintNumInput(TransInfo *t, float vec[3]); @@ -57,3 +61,12 @@ bool isLockConstraint(const TransInfo *t); * (Which could happen for weird constraints not yet designed. Along a path for example.) */ int getConstraintSpaceDimension(const TransInfo *t); + +bool transform_constraint_isect_ray(const TransInfo *t, + const float ray_co[3], + const float ray_dir[3], + float out[3]); + +#ifdef __cplusplus +} +#endif diff --git a/source/blender/editors/transform/transform_mode_snapsource.c b/source/blender/editors/transform/transform_mode_snapsource.c index 1af88cb7d92..2ceafb2074d 100644 --- a/source/blender/editors/transform/transform_mode_snapsource.c +++ b/source/blender/editors/transform/transform_mode_snapsource.c @@ -201,10 +201,10 @@ void transform_mode_snap_source_init(TransInfo *t) } } - if ((t->tsnap.mode & ~(SCE_SNAP_MODE_INCREMENT | SCE_SNAP_MODE_GRID)) == 0) { + if (t->tsnap.mode == SCE_SNAP_MODE_INCREMENT) { /* Initialize snap modes for geometry. */ - t->tsnap.mode &= ~(SCE_SNAP_MODE_INCREMENT | SCE_SNAP_MODE_GRID); - t->tsnap.mode |= SCE_SNAP_MODE_GEOM & ~SCE_SNAP_MODE_FACE_NEAREST; + t->tsnap.mode &= ~SCE_SNAP_MODE_INCREMENT; + t->tsnap.mode |= SCE_SNAP_MODE_GEOM | SCE_SNAP_MODE_GRID & ~SCE_SNAP_MODE_FACE_NEAREST; } if (t->data_type == &TransConvertType_Mesh) { diff --git a/source/blender/editors/transform/transform_snap.cc b/source/blender/editors/transform/transform_snap.cc index fe740675eed..b4705040ed0 100644 --- a/source/blender/editors/transform/transform_snap.cc +++ b/source/blender/editors/transform/transform_snap.cc @@ -1209,19 +1209,32 @@ static bool snap_grid(TransInfo *t, const float mval[2], const int val_size, flo } if (t->spacetype == SPACE_VIEW3D) { - float lambda; - float plane[4]; float ray_dir[3]; ED_view3d_win_to_ray_clipped( t->depsgraph, t->region, (View3D *)t->view, mval, r_val, ray_dir, true); - plane_from_point_normal_v3(plane, t->center_global, ray_dir); - - if (isect_ray_plane_v3(r_val, ray_dir, plane, &lambda, true)) { - madd_v3_v3fl(r_val, ray_dir, lambda); + if ((t->mode != TFM_ROTATION) && (t->con.mode & CON_APPLY)) { + if (!transform_constraint_isect_ray(t, r_val, ray_dir, r_val)) { + return false; + } } else { - return false; + float lambda; + float plane[4]; + if (t->persp != RV3D_ORTHO) { + /* Intersect Plane Z. */ + copy_v4_fl4(plane, 0.0f, 0.0f, 1.0f, 0.0f); + } + else { + plane_from_point_normal_v3(plane, t->center_global, ray_dir); + } + + if (isect_ray_plane_v3(r_val, ray_dir, plane, &lambda, true)) { + madd_v3_v3fl(r_val, ray_dir, lambda); + } + else { + return false; + } } } else { -- 2.30.2