Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGermano Cavalcante <mano-wii>2021-11-17 17:02:54 +0300
committerGermano Cavalcante <germano.costa@ig.com.br>2021-12-03 02:03:22 +0300
commit1fadff5350105ed1fd318a5d063171e1858d6f07 (patch)
treeb6dc554f9b5b19f13c945e99de297294ae5dc86d
parent56ff9540307e0dee7478bbc4241d5e024ba1d8b3 (diff)
Transform: interactive mode for setting a 'Snap Source'
This patch implements part of what was stated in {T66484}, with respect to `Base Point`. ## Introduction The snapping feature of the transform tools has a variety of applications: - Organization of nodes. - Positioning of frames in precise time units. - Retopology with snap to face - Creation of armatures with bone positioning through the snap to volume - Precise positioning of 3D or 2D objects in the surrounding geometry (CAD modeling) The goal of this document is to make it more powerful for precision modeling and still supporting the old use cases without extra complexity. The main topic addressed here is the introduction of a **interactive mode for setting a snap source** (See terminology). ## Terminology * **Snap Source**: 3d coordinate * we want to snap from. (Currently defined by the `Snap With` options: `Closest`, `Center`, `Median` and `Active`). * **Snap Target**: 3d coordinate* we want to snap to. (Vertices, Edges, Faces, Grid...) ## Interactive Mode for Editing a Snap Source Currently the fixed snap point can only be obtained through the `Snap With` options. So it's a little tricky for the user to define a snap source point having so much geometry on an object. Because of this, the user needs to resort to impractical solutions to get a point in the geometry. See example of an impractical use: {F11714181, layout=left, width=960, alt="The user used the cursor (which can be snapped) to choose the snap origin point."} The user used the cursor (which can be snapped) to choose the snap source point. While it is possible to work around this current limitation, it is important to reduce the number of steps and allow the user to set a snap source point through an optional interactive mode during a transformation. The proposed solution is to be able to move the current snap source point through a modal modifier activated with a key (eg. B). The snap source point can thus "snap" to the elements in the scene (vertex, mid-edge, Lamp, …) during this mode. {F9122814, layout=left, width=960, alt="Base Point Snap, example of transform operation via the shortcut (not the tool). After pressing g and the snap base change shortcut (e.g., shift + ctrl) the user set the base point. The base point is then visible until the end of the operation. The z axis constrains the final position."} ## Implementation Details - The feature will only be available in 3D View. - The feature will only be available for `Move`, `Rotate` and `Scale` transform modes. - The snap source editing will be enabled with a single click on the modifier key (B). - Having a snap point indicated, the new snap origin point will be confirmed with the same buttons that confirms the transformation (but the transformation will not be concluded). - The snap source editing can be canceled with the same key that activated it (B). - If the transformation is done with "release_confirm" (common for gizmos), the new feature cannot be enabled. - During the transformation, when enabling the feature, if the snap option is turned off in the scene, the snap will be forced on throughout the rest of the transformation (unless interactive mode is canceled). - 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 will be set automatically. - Snap cannot be turned off during the snap source editing. - Constraint or similar modification features will not be available during the snap source editing. - Text input will not be available during the snap source editing. - When adding multiple snap points (A) the new prone snap source point will be indicated with an "X" drawing. {F11817267} Maniphest Tasks: T66484 Differential Revision: https://developer.blender.org/D9415
-rw-r--r--release/scripts/presets/keyconfig/keymap_data/blender_default.py1
-rw-r--r--release/scripts/presets/keyconfig/keymap_data/industry_compatible_data.py1
-rw-r--r--source/blender/editors/transform/transform.c59
-rw-r--r--source/blender/editors/transform/transform.h7
-rw-r--r--source/blender/editors/transform/transform_input.c15
-rw-r--r--source/blender/editors/transform/transform_snap.c190
-rw-r--r--source/blender/editors/transform/transform_snap.h4
-rw-r--r--source/blender/editors/transform/transform_snap_object.c36
8 files changed, 278 insertions, 35 deletions
diff --git a/release/scripts/presets/keyconfig/keymap_data/blender_default.py b/release/scripts/presets/keyconfig/keymap_data/blender_default.py
index 543742709ef..25fdadc04db 100644
--- a/release/scripts/presets/keyconfig/keymap_data/blender_default.py
+++ b/release/scripts/presets/keyconfig/keymap_data/blender_default.py
@@ -5606,6 +5606,7 @@ def km_transform_modal_map(_params):
("AUTOCONSTRAINPLANE", {"type": 'MIDDLEMOUSE', "value": 'ANY', "shift": True}, None),
("PRECISION", {"type": 'LEFT_SHIFT', "value": 'ANY', "any": True}, None),
("PRECISION", {"type": 'RIGHT_SHIFT', "value": 'ANY', "any": True}, None),
+ ("EDIT_SNAP_SOURCE", {"type": 'B', "value": 'PRESS'}, None),
])
return keymap
diff --git a/release/scripts/presets/keyconfig/keymap_data/industry_compatible_data.py b/release/scripts/presets/keyconfig/keymap_data/industry_compatible_data.py
index 3019322d340..a5a8cba5c74 100644
--- a/release/scripts/presets/keyconfig/keymap_data/industry_compatible_data.py
+++ b/release/scripts/presets/keyconfig/keymap_data/industry_compatible_data.py
@@ -3997,6 +3997,7 @@ def km_transform_modal_map(_params):
("AUTOCONSTRAINPLANE", {"type": 'MIDDLEMOUSE', "value": 'ANY', "shift": True}, None),
("PRECISION", {"type": 'LEFT_SHIFT', "value": 'ANY', "any": True}, None),
("PRECISION", {"type": 'RIGHT_SHIFT', "value": 'ANY', "any": True}, None),
+ ("EDIT_SNAP_SOURCE", {"type": 'B', "value": 'PRESS'}, None),
])
return keymap
diff --git a/source/blender/editors/transform/transform.c b/source/blender/editors/transform/transform.c
index ae4c3f02c46..c376c718245 100644
--- a/source/blender/editors/transform/transform.c
+++ b/source/blender/editors/transform/transform.c
@@ -578,6 +578,21 @@ 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_SNAP_INV_ON,
+ TFM_MODAL_SNAP_INV_OFF,
+ 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
@@ -593,6 +608,13 @@ static bool transform_modal_item_poll(const wmOperator *op, int value)
}
break;
}
+ case TFM_MODAL_SNAP_INV_ON:
+ case TFM_MODAL_SNAP_INV_OFF: {
+ if (t->modifiers & MOD_SNAP_TEMP) {
+ return false;
+ }
+ break;
+ }
case TFM_MODAL_ADD_SNAP:
case TFM_MODAL_REMOVE_SNAP: {
if (t->spacetype != SPACE_VIEW3D) {
@@ -664,6 +686,19 @@ 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 (t->flag & T_RELEASE_CONFIRM) {
+ return false;
+ }
+ if (!ELEM(t->mode, TFM_TRANSLATION, TFM_ROTATION, TFM_RESIZE)) {
+ /* More modes can be added over time if this feature proves useful for them. */
+ return false;
+ }
+ break;
+ }
}
return true;
}
@@ -714,6 +749,7 @@ wmKeyMap *transform_modal_keymap(wmKeyConfig *keyconf)
{TFM_MODAL_AUTOCONSTRAINT, "AUTOCONSTRAIN", 0, "Automatic Constraint", ""},
{TFM_MODAL_AUTOCONSTRAINTPLANE, "AUTOCONSTRAINPLANE", 0, "Automatic Constraint Plane", ""},
{TFM_MODAL_PRECISION, "PRECISION", 0, "Precision Mode", ""},
+ {TFM_MODAL_EDIT_SNAP_SOURCE, "EDIT_SNAP_SOURCE", 0, "Snap Source Toggle", ""},
{0, NULL, 0, NULL, NULL},
};
@@ -891,7 +927,12 @@ int transformEvent(TransInfo *t, const wmEvent *event)
handled = true;
break;
case TFM_MODAL_CONFIRM:
- t->state = TRANS_CONFIRM;
+ if (t->modifiers & MOD_EDIT_SNAP_SOURCE) {
+ tranform_snap_source_mod_confirm(t);
+ }
+ else {
+ t->state = TRANS_CONFIRM;
+ }
handled = true;
break;
case TFM_MODAL_TRANSLATE:
@@ -1156,6 +1197,9 @@ int transformEvent(TransInfo *t, const wmEvent *event)
t->redraw |= TREDRAW_HARD;
}
break;
+ case TFM_MODAL_EDIT_SNAP_SOURCE:
+ tranform_snap_source_mod_toggle(t);
+ break;
/* Those two are only handled in transform's own handler, see T44634! */
case TFM_MODAL_EDGESLIDE_UP:
case TFM_MODAL_EDGESLIDE_DOWN:
@@ -1532,7 +1576,7 @@ void saveTransform(bContext *C, TransInfo *t, wmOperator *op)
if (t->flag & T_MODAL) {
/* do we check for parameter? */
- if (transformModeUseSnap(t)) {
+ if (transformModeUseSnap(t) && !(t->modifiers & MOD_SNAP_TEMP)) {
if (!(t->modifiers & MOD_SNAP) != !(ts->snap_flag & SCE_SNAP)) {
if (t->modifiers & MOD_SNAP) {
ts->snap_flag |= SCE_SNAP;
@@ -1920,14 +1964,17 @@ void transformApply(bContext *C, TransInfo *t)
if ((t->redraw & TREDRAW_HARD) || (t->draw_handle_apply == NULL && (t->redraw & TREDRAW_SOFT))) {
selectConstraint(t);
- if (t->transform) {
+ if (t->modifiers & MOD_EDIT_SNAP_SOURCE) {
+ tranform_snap_source_mod_update(t);
+ }
+ else if (t->transform) {
t->transform(t, t->mval); /* calls recalcData() */
- viewRedrawForce(C, t);
}
- t->redraw = TREDRAW_NOTHING;
}
- else if (t->redraw & TREDRAW_SOFT) {
+
+ if (t->redraw & (TREDRAW_HARD | TREDRAW_SOFT)) {
viewRedrawForce(C, t);
+ t->redraw = TREDRAW_NOTHING;
}
/* If auto confirm is on, break after one pass */
diff --git a/source/blender/editors/transform/transform.h b/source/blender/editors/transform/transform.h
index 380df739876..00ae4a82d95 100644
--- a/source/blender/editors/transform/transform.h
+++ b/source/blender/editors/transform/transform.h
@@ -163,7 +163,9 @@ typedef enum {
MOD_PRECISION = 1 << 1,
MOD_SNAP = 1 << 2,
MOD_SNAP_INVERT = 1 << 3,
- MOD_CONSTRAINT_SELECT_PLANE = 1 << 4,
+ MOD_SNAP_TEMP = 1 << 4,
+ MOD_CONSTRAINT_SELECT_PLANE = 1 << 5,
+ MOD_EDIT_SNAP_SOURCE = 1 << 6,
} eTModifier;
/** #TransSnap.status */
@@ -294,6 +296,8 @@ enum {
TFM_MODAL_AUTOCONSTRAINTPLANE = 29,
TFM_MODAL_PRECISION = 30,
+
+ TFM_MODAL_EDIT_SNAP_SOURCE = 31,
};
/** \} */
@@ -761,6 +765,7 @@ void applyMouseInput(struct TransInfo *t,
struct MouseInput *mi,
const int mval[2],
float output[3]);
+void transform_input_reset(MouseInput *mi, 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 0b46d0b9a13..d9a29b8d6b7 100644
--- a/source/blender/editors/transform/transform_input.c
+++ b/source/blender/editors/transform/transform_input.c
@@ -418,6 +418,10 @@ void setInputPostFct(MouseInput *mi, void (*post)(struct TransInfo *t, float val
void applyMouseInput(TransInfo *t, MouseInput *mi, const int mval[2], float output[3])
{
+ if (t->modifiers & MOD_EDIT_SNAP_SOURCE) {
+ return;
+ }
+
double mval_db[2];
if (mi->use_virtual_mval) {
@@ -455,4 +459,15 @@ void applyMouseInput(TransInfo *t, MouseInput *mi, const int mval[2], float outp
}
}
+void transform_input_reset(MouseInput *mi, const int mval[2])
+{
+ 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_snap.c b/source/blender/editors/transform/transform_snap.c
index 71f26ef0594..8ed0a1f2ea8 100644
--- a/source/blender/editors/transform/transform_snap.c
+++ b/source/blender/editors/transform/transform_snap.c
@@ -136,6 +136,10 @@ bool validSnap(const TransInfo *t)
bool activeSnap(const TransInfo *t)
{
+ if (t->modifiers & MOD_SNAP_TEMP) {
+ return true;
+ }
+
return ((t->modifiers & (MOD_SNAP | MOD_SNAP_INVERT)) == MOD_SNAP) ||
((t->modifiers & (MOD_SNAP | MOD_SNAP_INVERT)) == MOD_SNAP_INVERT);
}
@@ -178,7 +182,7 @@ bool transformModeUseSnap(const TransInfo *t)
static bool doForceIncrementSnap(const TransInfo *t)
{
- return !transformModeUseSnap(t);
+ return !(t->modifiers & MOD_SNAP_TEMP) && !transformModeUseSnap(t);
}
void drawSnapping(const struct bContext *C, TransInfo *t)
@@ -232,6 +236,47 @@ void drawSnapping(const struct bContext *C, TransInfo *t)
imm_drawcircball(p->co, ED_view3d_pixel_size(rv3d, p->co) * size, view_inv, pos);
}
+ if (t->modifiers & MOD_EDIT_SNAP_SOURCE) {
+ /* Indicate the new snap source position. */
+
+ float snap_point[3];
+ getSnapPoint(t, snap_point);
+
+ float vx[3], vy[3], v[3];
+ float size_tmp = ED_view3d_pixel_size(rv3d, snap_point) * 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_point, size_tmp, view_inv, pos);
+
+ immBegin(GPU_PRIM_LINES, 8);
+ add_v3_v3v3(v, snap_point, vx);
+ immVertex3fv(pos, v);
+ madd_v3_v3fl(v, vx, size_fac);
+ immVertex3fv(pos, v);
+
+ sub_v3_v3v3(v, snap_point, vx);
+ immVertex3fv(pos, v);
+ madd_v3_v3fl(v, vx, -size_fac);
+ immVertex3fv(pos, v);
+
+ add_v3_v3v3(v, snap_point, vy);
+ immVertex3fv(pos, v);
+ madd_v3_v3fl(v, vy, size_fac);
+ immVertex3fv(pos, v);
+
+ sub_v3_v3v3(v, snap_point, vy);
+ immVertex3fv(pos, v);
+ madd_v3_v3fl(v, vy, -size_fac);
+ immVertex3fv(pos, v);
+
+ immEnd();
+ }
+
immUnbindProgram();
}
@@ -244,7 +289,7 @@ void drawSnapping(const struct bContext *C, TransInfo *t)
loc_prev = t->tsnap.snapTarget;
}
- if (validSnap(t)) {
+ if (t->tsnap.status & POINT_INIT) {
loc_cur = t->tsnap.snapPoint;
}
@@ -477,8 +522,7 @@ void applyGridAbsolute(TransInfo *t)
void applySnapping(TransInfo *t, float *vec)
{
- /* Each Trans Data already makes the snap to face */
- if (doForceIncrementSnap(t)) {
+ if (!transformModeUseSnap(t) && !(t->modifiers & MOD_SNAP_TEMP)) {
return;
}
@@ -659,6 +703,20 @@ static short snap_select_type_get(TransInfo *t)
return r_snap_select;
}
+static void snap_object_context_setup(TransInfo *t)
+{
+ if (t->data_type != TC_MESH_VERTS) {
+ return;
+ }
+ /* 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)));
+}
+
static void initSnappingMode(TransInfo *t)
{
ToolSettings *ts = t->settings;
@@ -670,27 +728,13 @@ static void initSnappingMode(TransInfo *t)
t->tsnap.project = 0;
}
- if (ELEM(t->spacetype, SPACE_VIEW3D, SPACE_IMAGE, SPACE_NODE, SPACE_SEQ)) {
- /* Not with camera selected in camera view. */
- if (!(t->options & CTX_CAMERA)) {
- setSnappingCallback(t);
- }
- }
+ setSnappingCallback(t);
if (t->spacetype == SPACE_VIEW3D) {
if (t->tsnap.object_context == NULL) {
t->tsnap.use_backface_culling = snap_use_backface_culling(t);
t->tsnap.object_context = ED_transform_snap_object_context_create(t->scene, 0);
-
- if (t->data_type == TC_MESH_VERTS) {
- /* 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)));
- }
+ snap_object_context_setup(t);
}
}
else if (t->spacetype == SPACE_SEQ) {
@@ -775,10 +819,16 @@ void freeSnapping(TransInfo *t)
static void setSnappingCallback(TransInfo *t)
{
if (t->spacetype == SPACE_VIEW3D) {
+ if (t->options & CTX_CAMERA) {
+ /* Not with camera selected in camera view. */
+ return;
+ }
t->tsnap.calcSnap = snap_calc_view3d_fn;
}
- else if (t->spacetype == SPACE_IMAGE && t->obedit_type == OB_MESH) {
- t->tsnap.calcSnap = snap_calc_uv_fn;
+ else if (t->spacetype == SPACE_IMAGE) {
+ if (t->obedit_type == OB_MESH) {
+ t->tsnap.calcSnap = snap_calc_uv_fn;
+ }
}
else if (t->spacetype == SPACE_NODE) {
t->tsnap.calcSnap = snap_calc_node_fn;
@@ -788,6 +838,9 @@ static void setSnappingCallback(TransInfo *t)
/* The target is calculated along with the snap point. */
return;
}
+ else {
+ return;
+ }
switch (t->tsnap.target) {
case SCE_SNAP_TARGET_CLOSEST:
@@ -905,6 +958,15 @@ void getSnapPoint(const TransInfo *t, float vec[3])
}
}
+static void transform_snap_multipoints_free(TransInfo *t)
+{
+ if (t->tsnap.status & MULTI_POINTS) {
+ BLI_freelistN(&t->tsnap.points);
+ t->tsnap.status &= ~MULTI_POINTS;
+ t->tsnap.selectedPoint = NULL;
+ }
+}
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -1619,6 +1681,90 @@ bool transform_snap_increment(const TransInfo *t, float *r_val)
return transform_snap_increment_ex(t, false, r_val);
}
+static void snap_source_mod_start(TransInfo *t)
+{
+ t->modifiers |= MOD_EDIT_SNAP_SOURCE;
+ t->tsnap.modeSelect = SNAP_ALL;
+ if ((t->tsnap.status & TARGET_INIT) == 0) {
+ /* Calculate the current target for the perpendicular snap. */
+ t->tsnap.targetSnap(t);
+
+ /* Fallback. */
+ TargetSnapMedian(t);
+ }
+ t->tsnap.targetSnap = NULL;
+
+ 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;
+ }
+
+ if (!activeSnap(t) || !transformModeUseSnap(t)) {
+ t->modifiers |= MOD_SNAP_TEMP;
+ }
+
+ restoreTransObjects(t);
+
+ if (t->data_type == TC_MESH_VERTS) {
+ ED_transform_snap_object_context_set_editmesh_callbacks(
+ t->tsnap.object_context, NULL, NULL, NULL, NULL);
+ }
+
+ t->redraw |= TREDRAW_SOFT;
+}
+
+static void snap_source_mod_end(TransInfo *t)
+{
+ t->modifiers &= ~MOD_EDIT_SNAP_SOURCE;
+
+ /* Restore. */
+ t->tsnap.modeSelect = snap_select_type_get(t);
+ snap_object_context_setup(t);
+ transform_snap_multipoints_free(t);
+}
+
+void tranform_snap_source_mod_toggle(TransInfo *t)
+{
+ if (t->flag & T_RELEASE_CONFIRM) {
+ return;
+ }
+
+ if (!(t->modifiers & MOD_EDIT_SNAP_SOURCE)) {
+ snap_source_mod_start(t);
+ }
+ else if (t->modifiers & MOD_EDIT_SNAP_SOURCE) {
+ /* Cancel. */
+ t->modifiers &= ~MOD_SNAP_TEMP;
+ t->tsnap.mode = snap_mode_from_scene(t);
+ setSnappingCallback(t);
+ snap_source_mod_end(t);
+ }
+}
+
+void tranform_snap_source_mod_update(TransInfo *t)
+{
+ BLI_assert(t->modifiers & MOD_EDIT_SNAP_SOURCE);
+
+ /* Time base quirky code to go around findnearest slowness */
+ /* TODO: add exception for object mode, no need to slow it down then. */
+ double current = PIL_check_seconds_timer();
+ if (current - t->tsnap.last >= 0.01) {
+ t->tsnap.calcSnap(t, NULL);
+ t->tsnap.last = current;
+ t->redraw |= TREDRAW_SOFT;
+ }
+}
+
+void tranform_snap_source_mod_confirm(TransInfo *t)
+{
+ BLI_assert(t->modifiers & MOD_EDIT_SNAP_SOURCE);
+ getSnapPoint(t, t->tsnap.snapTarget);
+
+ transform_input_reset(&t->mouse, t->mval);
+ snap_source_mod_end(t);
+}
+
/** \} */
/* -------------------------------------------------------------------- */
diff --git a/source/blender/editors/transform/transform_snap.h b/source/blender/editors/transform/transform_snap.h
index ed7f93304bc..af13dac7ee7 100644
--- a/source/blender/editors/transform/transform_snap.h
+++ b/source/blender/editors/transform/transform_snap.h
@@ -52,6 +52,10 @@ bool transform_snap_increment_ex(const TransInfo *t, bool use_local_space, float
bool transform_snap_increment(const TransInfo *t, float *val);
bool transform_snap_grid(TransInfo *t, float *val);
+void tranform_snap_source_mod_toggle(TransInfo *t);
+void tranform_snap_source_mod_update(TransInfo *t);
+void tranform_snap_source_mod_confirm(TransInfo *t);
+
bool activeSnap(const TransInfo *t);
bool activeSnap_with_project(const TransInfo *t);
diff --git a/source/blender/editors/transform/transform_snap_object.c b/source/blender/editors/transform/transform_snap_object.c
index 4b981e763f1..9f05a0a9562 100644
--- a/source/blender/editors/transform/transform_snap_object.c
+++ b/source/blender/editors/transform/transform_snap_object.c
@@ -391,9 +391,8 @@ static SnapObjectData *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) {
+ if (G.moving && !sod->treedata_editmesh.cached && !sod->cached[0] && !sod->cached[1]) {
/* Hack to 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);
}
else {
@@ -2830,6 +2829,15 @@ void ED_transform_snap_object_context_destroy(SnapObjectContext *sctx)
MEM_freeN(sctx);
}
+static void transform_snap_object_context_cache_clear(SnapObjectContext *sctx)
+{
+ BLI_ghash_clear(sctx->cache.object_map, NULL, snap_object_data_free);
+ if (sctx->cache.data_to_object_map != NULL) {
+ BLI_ghash_clear(sctx->cache.data_to_object_map, NULL, NULL);
+ }
+ BLI_memarena_clear(sctx->cache.mem_arena);
+}
+
void ED_transform_snap_object_context_set_editmesh_callbacks(
SnapObjectContext *sctx,
bool (*test_vert_fn)(BMVert *, void *user_data),
@@ -2837,11 +2845,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) {
+ transform_snap_object_context_cache_clear(sctx);
+ }
}
bool ED_transform_snap_object_project_ray_ex(SnapObjectContext *sctx,