diff options
author | Germano Cavalcante <mano-wii> | 2021-11-17 17:02:54 +0300 |
---|---|---|
committer | Germano Cavalcante <germano.costa@ig.com.br> | 2021-11-18 19:14:18 +0300 |
commit | f19bd637e2c38b8b967944a88609a190b5179439 (patch) | |
tree | 88c9adba987a194e1f59f1e22210c684d4839c6b /source/blender/editors/transform/transform_snap.c | |
parent | 67b4eecac9311ab677dadb7b8bd1c54031dd3589 (diff) |
Transform: interactive mode for editing 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
Diffstat (limited to 'source/blender/editors/transform/transform_snap.c')
-rw-r--r-- | source/blender/editors/transform/transform_snap.c | 158 |
1 files changed, 136 insertions, 22 deletions
diff --git a/source/blender/editors/transform/transform_snap.c b/source/blender/editors/transform/transform_snap.c index 71f26ef0594..f52061f8910 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,15 @@ 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) { + float snap_point[3]; + getSnapPoint(t, snap_point); + + immUniformColor4ubv(col); + imm_drawX( + snap_point, 0.75f * size * ED_view3d_pixel_size(rv3d, snap_point), view_inv, pos); + } + immUnbindProgram(); } @@ -244,7 +257,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 +490,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 +671,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 +696,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 +787,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 +806,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 +926,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 +1649,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); +} + /** \} */ /* -------------------------------------------------------------------- */ |