Changeset View
Changeset View
Standalone View
Standalone View
source/blender/editors/transform/transform_snap.c
| Show First 20 Lines • Show All 130 Lines • ▼ Show 20 Lines | |||||
| bool validSnap(const TransInfo *t) | bool validSnap(const TransInfo *t) | ||||
| { | { | ||||
| return (t->tsnap.status & (POINT_INIT | TARGET_INIT)) == (POINT_INIT | TARGET_INIT) || | return (t->tsnap.status & (POINT_INIT | TARGET_INIT)) == (POINT_INIT | TARGET_INIT) || | ||||
| (t->tsnap.status & (MULTI_POINTS | TARGET_INIT)) == (MULTI_POINTS | TARGET_INIT); | (t->tsnap.status & (MULTI_POINTS | TARGET_INIT)) == (MULTI_POINTS | TARGET_INIT); | ||||
| } | } | ||||
| bool activeSnap(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) || | return ((t->modifiers & (MOD_SNAP | MOD_SNAP_INVERT)) == MOD_SNAP) || | ||||
| ((t->modifiers & (MOD_SNAP | MOD_SNAP_INVERT)) == MOD_SNAP_INVERT); | ((t->modifiers & (MOD_SNAP | MOD_SNAP_INVERT)) == MOD_SNAP_INVERT); | ||||
| } | } | ||||
| bool activeSnap_with_project(const TransInfo *t) | bool activeSnap_with_project(const TransInfo *t) | ||||
| { | { | ||||
| if (!t->tsnap.project) { | if (!t->tsnap.project) { | ||||
| return false; | return false; | ||||
| Show All 26 Lines | if (ELEM(t->mode, TFM_VERT_SLIDE, TFM_EDGE_SLIDE, TFM_SEQ_SLIDE)) { | ||||
| return true; | return true; | ||||
| } | } | ||||
| return false; | return false; | ||||
| } | } | ||||
| static bool doForceIncrementSnap(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) | void drawSnapping(const struct bContext *C, TransInfo *t) | ||||
| { | { | ||||
| uchar col[4], selectedCol[4], activeCol[4]; | uchar col[4], selectedCol[4], activeCol[4]; | ||||
| if (!activeSnap(t)) { | if (!activeSnap(t)) { | ||||
| return; | return; | ||||
| Show All 37 Lines | if (draw_target || validSnap(t)) { | ||||
| immUniformColor4ubv(selectedCol); | immUniformColor4ubv(selectedCol); | ||||
| } | } | ||||
| else { | else { | ||||
| immUniformColor4ubv(col); | immUniformColor4ubv(col); | ||||
| } | } | ||||
| imm_drawcircball(p->co, ED_view3d_pixel_size(rv3d, p->co) * size, view_inv, pos); | imm_drawcircball(p->co, ED_view3d_pixel_size(rv3d, p->co) * size, view_inv, pos); | ||||
| } | } | ||||
| if (t->modifiers & MOD_EDIT_SNAP_ORIGIN) { | |||||
| 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(); | immUnbindProgram(); | ||||
| } | } | ||||
| /* draw normal if needed */ | /* draw normal if needed */ | ||||
| if (usingSnappingNormal(t) && validSnappingNormal(t)) { | if (usingSnappingNormal(t) && validSnappingNormal(t)) { | ||||
| normal = t->tsnap.snapNormal; | normal = t->tsnap.snapNormal; | ||||
| } | } | ||||
| if (draw_target) { | if (draw_target) { | ||||
| loc_prev = t->tsnap.snapTarget; | loc_prev = t->tsnap.snapTarget; | ||||
| } | } | ||||
| if (validSnap(t)) { | if (t->tsnap.status & POINT_INIT) { | ||||
| loc_cur = t->tsnap.snapPoint; | loc_cur = t->tsnap.snapPoint; | ||||
| } | } | ||||
| ED_view3d_cursor_snap_draw_util( | ED_view3d_cursor_snap_draw_util( | ||||
| rv3d, loc_prev, loc_cur, normal, col, activeCol, t->tsnap.snapElem); | rv3d, loc_prev, loc_cur, normal, col, activeCol, t->tsnap.snapElem); | ||||
| GPU_depth_test(GPU_DEPTH_LESS_EQUAL); | GPU_depth_test(GPU_DEPTH_LESS_EQUAL); | ||||
| } | } | ||||
| ▲ Show 20 Lines • Show All 216 Lines • ▼ Show 20 Lines | for (i = 0, td = tc->data; i < tc->data_len; i++, td++) { | ||||
| mul_m3_v3(td->smtx, tvec); | mul_m3_v3(td->smtx, tvec); | ||||
| add_v3_v3(td->loc, tvec); | add_v3_v3(td->loc, tvec); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| void applySnapping(TransInfo *t, float *vec) | void applySnapping(TransInfo *t, float *vec) | ||||
| { | { | ||||
| /* Each Trans Data already makes the snap to face */ | if (!transformModeUseSnap(t) && !(t->modifiers & MOD_SNAP_TEMP)) { | ||||
| if (doForceIncrementSnap(t)) { | |||||
| return; | return; | ||||
| } | } | ||||
| if (t->tsnap.project && t->tsnap.mode == SCE_SNAP_MODE_FACE) { | if (t->tsnap.project && t->tsnap.mode == SCE_SNAP_MODE_FACE) { | ||||
| /* A similar snap will be applied to each transdata in `applyProject`. */ | /* A similar snap will be applied to each transdata in `applyProject`. */ | ||||
| return; | return; | ||||
| } | } | ||||
| ▲ Show 20 Lines • Show All 164 Lines • ▼ Show 20 Lines | static short snap_select_type_get(TransInfo *t) | ||||
| } | } | ||||
| else if (ELEM(t->spacetype, SPACE_NODE, SPACE_SEQ)) { | else if (ELEM(t->spacetype, SPACE_NODE, SPACE_SEQ)) { | ||||
| r_snap_select = SNAP_NOT_SELECTED; | r_snap_select = SNAP_NOT_SELECTED; | ||||
| } | } | ||||
| return r_snap_select; | 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) | static void initSnappingMode(TransInfo *t) | ||||
| { | { | ||||
| ToolSettings *ts = t->settings; | ToolSettings *ts = t->settings; | ||||
| t->tsnap.mode = snap_mode_from_scene(t); | t->tsnap.mode = snap_mode_from_scene(t); | ||||
| t->tsnap.modeSelect = snap_select_type_get(t); | t->tsnap.modeSelect = snap_select_type_get(t); | ||||
| if ((t->spacetype != SPACE_VIEW3D) || !(ts->snap_mode & SCE_SNAP_MODE_FACE)) { | if ((t->spacetype != SPACE_VIEW3D) || !(ts->snap_mode & SCE_SNAP_MODE_FACE)) { | ||||
| /* Force project off when not supported. */ | /* Force project off when not supported. */ | ||||
| t->tsnap.project = 0; | 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->spacetype == SPACE_VIEW3D) { | ||||
| if (t->tsnap.object_context == NULL) { | if (t->tsnap.object_context == NULL) { | ||||
| t->tsnap.use_backface_culling = snap_use_backface_culling(t); | t->tsnap.use_backface_culling = snap_use_backface_culling(t); | ||||
| t->tsnap.object_context = ED_transform_snap_object_context_create(t->scene, 0); | t->tsnap.object_context = ED_transform_snap_object_context_create(t->scene, 0); | ||||
| snap_object_context_setup(t); | |||||
| 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))); | |||||
| } | |||||
| } | } | ||||
| } | } | ||||
| else if (t->spacetype == SPACE_SEQ) { | else if (t->spacetype == SPACE_SEQ) { | ||||
| if (t->tsnap.seq_context == NULL) { | if (t->tsnap.seq_context == NULL) { | ||||
| t->tsnap.seq_context = transform_snap_sequencer_data_alloc(t); | t->tsnap.seq_context = transform_snap_sequencer_data_alloc(t); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| ▲ Show 20 Lines • Show All 68 Lines • ▼ Show 20 Lines | else if (t->tsnap.object_context) { | ||||
| ED_transform_snap_object_context_destroy(t->tsnap.object_context); | ED_transform_snap_object_context_destroy(t->tsnap.object_context); | ||||
| t->tsnap.object_context = NULL; | t->tsnap.object_context = NULL; | ||||
| } | } | ||||
| } | } | ||||
| static void setSnappingCallback(TransInfo *t) | static void setSnappingCallback(TransInfo *t) | ||||
| { | { | ||||
| if (t->spacetype == SPACE_VIEW3D) { | 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; | t->tsnap.calcSnap = snap_calc_view3d_fn; | ||||
| } | } | ||||
| else if (t->spacetype == SPACE_IMAGE && t->obedit_type == OB_MESH) { | else if (t->spacetype == SPACE_IMAGE) { | ||||
| if (t->obedit_type == OB_MESH) { | |||||
| t->tsnap.calcSnap = snap_calc_uv_fn; | t->tsnap.calcSnap = snap_calc_uv_fn; | ||||
| } | } | ||||
| } | |||||
| else if (t->spacetype == SPACE_NODE) { | else if (t->spacetype == SPACE_NODE) { | ||||
| t->tsnap.calcSnap = snap_calc_node_fn; | t->tsnap.calcSnap = snap_calc_node_fn; | ||||
| } | } | ||||
| else if (t->spacetype == SPACE_SEQ) { | else if (t->spacetype == SPACE_SEQ) { | ||||
| t->tsnap.calcSnap = snap_calc_sequencer_fn; | t->tsnap.calcSnap = snap_calc_sequencer_fn; | ||||
| /* The target is calculated along with the snap point. */ | /* The target is calculated along with the snap point. */ | ||||
| return; | return; | ||||
| } | } | ||||
| else { | |||||
| return; | |||||
| } | |||||
| switch (t->tsnap.target) { | switch (t->tsnap.target) { | ||||
| case SCE_SNAP_TARGET_CLOSEST: | case SCE_SNAP_TARGET_CLOSEST: | ||||
| t->tsnap.targetSnap = TargetSnapClosest; | t->tsnap.targetSnap = TargetSnapClosest; | ||||
| break; | break; | ||||
| case SCE_SNAP_TARGET_CENTER: | case SCE_SNAP_TARGET_CENTER: | ||||
| if (!ELEM(t->mode, TFM_ROTATION, TFM_RESIZE)) { | if (!ELEM(t->mode, TFM_ROTATION, TFM_RESIZE)) { | ||||
| t->tsnap.targetSnap = TargetSnapCenter; | t->tsnap.targetSnap = TargetSnapCenter; | ||||
| ▲ Show 20 Lines • Show All 101 Lines • ▼ Show 20 Lines | if (t->tsnap.points.first) { | ||||
| mul_v3_fl(vec, 1.0f / total); | mul_v3_fl(vec, 1.0f / total); | ||||
| } | } | ||||
| else { | else { | ||||
| copy_v3_v3(vec, t->tsnap.snapPoint); | copy_v3_v3(vec, t->tsnap.snapPoint); | ||||
| } | } | ||||
| } | } | ||||
| 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; | |||||
| } | |||||
| } | |||||
| /** \} */ | /** \} */ | ||||
| /* -------------------------------------------------------------------- */ | /* -------------------------------------------------------------------- */ | ||||
| /** \name Calc Snap | /** \name Calc Snap | ||||
| * \{ */ | * \{ */ | ||||
| static void snap_calc_view3d_fn(TransInfo *t, float *UNUSED(vec)) | static void snap_calc_view3d_fn(TransInfo *t, float *UNUSED(vec)) | ||||
| { | { | ||||
| ▲ Show 20 Lines • Show All 698 Lines • ▼ Show 20 Lines | bool transform_snap_increment_ex(const TransInfo *t, bool use_local_space, float *r_val) | ||||
| return true; | return true; | ||||
| } | } | ||||
| bool transform_snap_increment(const TransInfo *t, float *r_val) | bool transform_snap_increment(const TransInfo *t, float *r_val) | ||||
| { | { | ||||
| return transform_snap_increment_ex(t, false, r_val); | return transform_snap_increment_ex(t, false, r_val); | ||||
| } | } | ||||
| static void snap_origin_interactive_start(TransInfo *t) | |||||
| { | |||||
| t->modifiers |= MOD_EDIT_SNAP_ORIGIN; | |||||
| 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_origin_interactive_end(TransInfo *t) | |||||
| { | |||||
| t->modifiers &= ~MOD_EDIT_SNAP_ORIGIN; | |||||
| /* Restore. */ | |||||
| t->tsnap.modeSelect = snap_select_type_get(t); | |||||
| snap_object_context_setup(t); | |||||
| transform_snap_multipoints_free(t); | |||||
| } | |||||
| void tranform_snap_origin_interactive_toggle(TransInfo *t) | |||||
| { | |||||
| if (!U.experimental.use_transform_snap_origin) { | |||||
| return; | |||||
| } | |||||
| if (t->flag & T_RELEASE_CONFIRM) { | |||||
| return; | |||||
| } | |||||
| if (!(t->modifiers & MOD_EDIT_SNAP_ORIGIN)) { | |||||
| snap_origin_interactive_start(t); | |||||
| } | |||||
| else if (t->modifiers & MOD_EDIT_SNAP_ORIGIN) { | |||||
| /* Cancel. */ | |||||
| t->modifiers &= ~MOD_SNAP_TEMP; | |||||
| t->tsnap.mode = snap_mode_from_scene(t); | |||||
| setSnappingCallback(t); | |||||
| snap_origin_interactive_end(t); | |||||
| } | |||||
| } | |||||
| void tranform_snap_origin_interactive_update(TransInfo *t) | |||||
| { | |||||
| BLI_assert(t->modifiers & MOD_EDIT_SNAP_ORIGIN); | |||||
| /* 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_origin_interactive_confirm(TransInfo *t) | |||||
| { | |||||
| BLI_assert(t->modifiers & MOD_EDIT_SNAP_ORIGIN); | |||||
| getSnapPoint(t, t->tsnap.snapTarget); | |||||
| transform_input_reset(&t->mouse, t->mval); | |||||
| snap_origin_interactive_end(t); | |||||
| } | |||||
| /** \} */ | /** \} */ | ||||
| /* -------------------------------------------------------------------- */ | /* -------------------------------------------------------------------- */ | ||||
| /** \name Generic callbacks | /** \name Generic callbacks | ||||
| * \{ */ | * \{ */ | ||||
| float transform_snap_distance_len_squared_fn(TransInfo *UNUSED(t), | float transform_snap_distance_len_squared_fn(TransInfo *UNUSED(t), | ||||
| const float p1[3], | const float p1[3], | ||||
| const float p2[3]) | const float p2[3]) | ||||
| { | { | ||||
| return len_squared_v3v3(p1, p2); | return len_squared_v3v3(p1, p2); | ||||
| } | } | ||||
| /** \} */ | /** \} */ | ||||