Changeset View
Changeset View
Standalone View
Standalone View
source/blender/editors/transform/transform_snap.c
| Show First 20 Lines • Show All 120 Lines • ▼ Show 20 Lines | |||||
| } | } | ||||
| bool activeSnap(const TransInfo *t) | bool activeSnap(const TransInfo *t) | ||||
| { | { | ||||
| 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_SnappingIndividual(const TransInfo *t) | ||||
| { | { | ||||
| if (activeSnap(t) && t->tsnap.mode & SCE_SNAP_MODE_FACE_NEAREST) { | |||||
| return true; | |||||
| } | |||||
| if (!t->tsnap.project) { | if (!t->tsnap.project) { | ||||
| return false; | return false; | ||||
| } | } | ||||
| if (!activeSnap(t) || (t->flag & T_NO_PROJECT)) { | if (!activeSnap(t) || (t->flag & T_NO_PROJECT)) { | ||||
| return false; | return false; | ||||
| } | } | ||||
| if (doForceIncrementSnap(t)) { | if (doForceIncrementSnap(t)) { | ||||
| return false; | return false; | ||||
| } | } | ||||
| return true; | return true; | ||||
| } | } | ||||
| bool activeSnap_SnappingAsGroup(const TransInfo *t) | |||||
| { | |||||
| if (!activeSnap(t)) { | |||||
| return false; | |||||
| } | |||||
| if (t->tsnap.mode == SCE_SNAP_MODE_FACE_RAYCAST && t->tsnap.project) { | |||||
| return false; | |||||
| } | |||||
| if (t->tsnap.mode == SCE_SNAP_MODE_FACE_NEAREST) { | |||||
| return false; | |||||
| } | |||||
| if (doForceIncrementSnap(t)) { | |||||
| return false; | |||||
| } | |||||
| return true; | |||||
| } | |||||
| bool transformModeUseSnap(const TransInfo *t) | bool transformModeUseSnap(const TransInfo *t) | ||||
| { | { | ||||
| ToolSettings *ts = t->settings; | ToolSettings *ts = t->settings; | ||||
| if (t->mode == TFM_TRANSLATION) { | if (t->mode == TFM_TRANSLATION) { | ||||
| return (ts->snap_transform_mode_flag & SCE_SNAP_TRANSFORM_MODE_TRANSLATE) != 0; | return (ts->snap_transform_mode_flag & SCE_SNAP_TRANSFORM_MODE_TRANSLATE) != 0; | ||||
| } | } | ||||
| if (t->mode == TFM_ROTATION) { | if (t->mode == TFM_ROTATION) { | ||||
| return (ts->snap_transform_mode_flag & SCE_SNAP_TRANSFORM_MODE_ROTATE) != 0; | return (ts->snap_transform_mode_flag & SCE_SNAP_TRANSFORM_MODE_ROTATE) != 0; | ||||
| ▲ Show 20 Lines • Show All 184 Lines • ▼ Show 20 Lines | |||||
| #endif | #endif | ||||
| if (event->type == MOUSEMOVE) { | if (event->type == MOUSEMOVE) { | ||||
| status |= updateSelectedSnapPoint(t); | status |= updateSelectedSnapPoint(t); | ||||
| } | } | ||||
| return status; | return status; | ||||
| } | } | ||||
| void applyProject(TransInfo *t) | static bool applyFaceProject(TransInfo *t, TransDataContainer *tc, TransData *td) | ||||
| { | { | ||||
| if (!activeSnap_with_project(t)) { | if (!(t->tsnap.mode & SCE_SNAP_MODE_FACE_RAYCAST)) { | ||||
| return; | return false; | ||||
| } | } | ||||
| float tvec[3]; | |||||
| int i; | |||||
| /* XXX FLICKER IN OBJECT MODE */ | |||||
| FOREACH_TRANS_DATA_CONTAINER (t, tc) { | |||||
| TransData *td = tc->data; | |||||
| for (i = 0; i < tc->data_len; i++, td++) { | |||||
| float iloc[3], loc[3], no[3]; | float iloc[3], loc[3], no[3]; | ||||
| float mval_fl[2]; | float mval_fl[2]; | ||||
| if (td->flag & TD_SKIP) { | |||||
| continue; | |||||
| } | |||||
| if ((t->flag & T_PROP_EDIT) && (td->factor == 0.0f)) { | |||||
| continue; | |||||
| } | |||||
| copy_v3_v3(iloc, td->loc); | copy_v3_v3(iloc, td->loc); | ||||
| if (tc->use_local_mat) { | if (tc->use_local_mat) { | ||||
| mul_m4_v3(tc->mat, iloc); | mul_m4_v3(tc->mat, iloc); | ||||
| } | } | ||||
| else if (t->options & CTX_OBJECT) { | else if (t->options & CTX_OBJECT) { | ||||
| BKE_object_eval_transform_all(t->depsgraph, t->scene, td->ob); | BKE_object_eval_transform_all(t->depsgraph, t->scene, td->ob); | ||||
| copy_v3_v3(iloc, td->ob->obmat[3]); | copy_v3_v3(iloc, td->ob->obmat[3]); | ||||
| } | } | ||||
| if (ED_view3d_project_float_global(t->region, iloc, mval_fl, V3D_PROJ_TEST_NOP) == | if (ED_view3d_project_float_global(t->region, iloc, mval_fl, V3D_PROJ_TEST_NOP) != | ||||
| V3D_PROJ_RET_OK) { | V3D_PROJ_RET_OK) { | ||||
| return false; | |||||
| } | |||||
| eSnapMode hit = ED_transform_snap_object_project_view3d( | eSnapMode hit = ED_transform_snap_object_project_view3d( | ||||
| t->tsnap.object_context, | t->tsnap.object_context, | ||||
| t->depsgraph, | t->depsgraph, | ||||
| t->region, | t->region, | ||||
| t->view, | t->view, | ||||
| SCE_SNAP_MODE_FACE, | SCE_SNAP_MODE_FACE_RAYCAST, | ||||
| &(const struct SnapObjectParams){ | &(const struct SnapObjectParams){ | ||||
| .snap_target_select = t->tsnap.target_select, | .snap_target_select = t->tsnap.target_select, | ||||
| .edit_mode_type = (t->flag & T_EDIT) != 0 ? SNAP_GEOM_EDIT : SNAP_GEOM_FINAL, | .edit_mode_type = (t->flag & T_EDIT) != 0 ? SNAP_GEOM_EDIT : SNAP_GEOM_FINAL, | ||||
| .use_occlusion_test = false, | .use_occlusion_test = false, | ||||
| .use_backface_culling = t->tsnap.use_backface_culling, | .use_backface_culling = t->tsnap.use_backface_culling, | ||||
| }, | }, | ||||
| NULL, | |||||
| mval_fl, | mval_fl, | ||||
| NULL, | NULL, | ||||
| 0, | 0, | ||||
| loc, | loc, | ||||
| no); | no); | ||||
| if (hit != SCE_SNAP_MODE_FACE) { | if (hit != SCE_SNAP_MODE_FACE_RAYCAST) { | ||||
| return; | return false; | ||||
| } | |||||
| #if 0 | |||||
| if (tc->use_local_mat) { | |||||
| mul_m4_v3(tc->imat, loc); | |||||
| } | } | ||||
| #endif | |||||
| float tvec[3]; | |||||
| sub_v3_v3v3(tvec, loc, iloc); | sub_v3_v3v3(tvec, loc, iloc); | ||||
| mul_m3_v3(td->smtx, tvec); | mul_m3_v3(td->smtx, tvec); | ||||
| add_v3_v3(td->loc, tvec); | add_v3_v3(td->loc, tvec); | ||||
| if (t->tsnap.align && (t->options & CTX_OBJECT)) { | if (t->tsnap.align && (t->options & CTX_OBJECT)) { | ||||
| /* handle alignment as well */ | /* handle alignment as well */ | ||||
| const float *original_normal; | const float *original_normal; | ||||
| float mat[3][3]; | float mat[3][3]; | ||||
| /* In pose mode, we want to align normals with Y axis of bones... */ | /* In pose mode, we want to align normals with Y axis of bones. */ | ||||
| original_normal = td->axismtx[2]; | original_normal = td->axismtx[2]; | ||||
| rotation_between_vecs_to_mat3(mat, original_normal, no); | rotation_between_vecs_to_mat3(mat, original_normal, no); | ||||
| transform_data_ext_rotate(td, mat, true); | transform_data_ext_rotate(td, mat, true); | ||||
| /* TODO: support constraints for rotation too? see #ElementRotation. */ | /* TODO: support constraints for rotation too? see #ElementRotation. */ | ||||
| } | } | ||||
| return true; | |||||
| } | |||||
| static void applyFaceNearest(TransInfo *t, TransDataContainer *tc, TransData *td) | |||||
| { | |||||
| if (!(t->tsnap.mode & SCE_SNAP_MODE_FACE_NEAREST)) { | |||||
| return; | |||||
| } | |||||
campbellbarton: Should this be removed? | |||||
Done Inline Actionsdone gfxcoder: done | |||||
| float init_loc[3]; | |||||
| float prev_loc[3]; | |||||
| float snap_loc[3], snap_no[3]; | |||||
| copy_v3_v3(init_loc, td->iloc); | |||||
| copy_v3_v3(prev_loc, td->loc); | |||||
| if (tc->use_local_mat) { | |||||
| mul_m4_v3(tc->mat, init_loc); | |||||
| mul_m4_v3(tc->mat, prev_loc); | |||||
| } | } | ||||
Not Done Inline Actions*picky* use full sentences, capitalized with single full-stop. campbellbarton: *picky* use full sentences, capitalized with single full-stop. | |||||
Done Inline Actionsdone gfxcoder: done | |||||
| else if (t->options & CTX_OBJECT) { | |||||
| BKE_object_eval_transform_all(t->depsgraph, t->scene, td->ob); | |||||
| copy_v3_v3(init_loc, td->ob->obmat[3]); | |||||
| } | } | ||||
| eSnapMode hit = ED_transform_snap_object_project_view3d( | |||||
| t->tsnap.object_context, | |||||
| t->depsgraph, | |||||
| t->region, | |||||
| t->view, | |||||
| SCE_SNAP_MODE_FACE_NEAREST, | |||||
| &(const struct SnapObjectParams){ | |||||
| .snap_target_select = t->tsnap.target_select, | |||||
| .edit_mode_type = (t->flag & T_EDIT) != 0 ? SNAP_GEOM_EDIT : SNAP_GEOM_FINAL, | |||||
| .use_occlusion_test = false, | |||||
| .use_backface_culling = false, | |||||
| .face_nearest_steps = t->tsnap.face_nearest_steps, | |||||
| .keep_on_same_target = t->tsnap.flag & SCE_SNAP_KEEP_ON_SAME_OBJECT, | |||||
| }, | |||||
| init_loc, | |||||
| NULL, | |||||
| prev_loc, | |||||
| 0, | |||||
| snap_loc, | |||||
| snap_no); | |||||
| if (hit != SCE_SNAP_MODE_FACE_NEAREST) { | |||||
| return; | |||||
| } | |||||
| float tvec[3]; | |||||
| sub_v3_v3v3(tvec, snap_loc, prev_loc); | |||||
| mul_m3_v3(td->smtx, tvec); | |||||
| add_v3_v3(td->loc, tvec); | |||||
| /* TODO: support snap alignment similar to #SCE_SNAP_MODE_FACE_RAYCAST? */ | |||||
| } | |||||
| void applySnappingIndividual(TransInfo *t) | |||||
| { | |||||
| if (!activeSnap_SnappingIndividual(t)) { | |||||
| return; | |||||
| } | |||||
Not Done Inline ActionsA single line explanation for why this would be useful would be good. I assume this would allow many objects to snap onto the surface of an object and rotate aligning to it's surface. campbellbarton: A single line explanation for why this would be useful would be good. I assume this would allow… | |||||
Done Inline Actionsreworked gfxcoder: reworked | |||||
| /* XXX FLICKER IN OBJECT MODE */ | |||||
| FOREACH_TRANS_DATA_CONTAINER (t, tc) { | |||||
| TransData *td = tc->data; | |||||
| for (int i = 0; i < tc->data_len; i++, td++) { | |||||
| if (td->flag & TD_SKIP) { | |||||
| continue; | |||||
| } | |||||
| if ((t->flag & T_PROP_EDIT) && (td->factor == 0.0f)) { | |||||
| continue; | |||||
| } | |||||
| /* If both face ray-cast and face nearest methods are enabled, start with face ray-cast and | |||||
| * fallback to face nearest ray-cast does not hit. */ | |||||
| bool hit = applyFaceProject(t, tc, td); | |||||
| if (!hit) { | |||||
| applyFaceNearest(t, tc, td); | |||||
| } | |||||
| #if 0 /* TODO: support this? */ | #if 0 /* TODO: support this? */ | ||||
| constraintTransLim(t, td); | constraintTransLim(t, td); | ||||
| #endif | #endif | ||||
| } | } | ||||
| } | } | ||||
| } | |||||
| void applyGridAbsolute(TransInfo *t) | void applyGridAbsolute(TransInfo *t) | ||||
| { | { | ||||
| int i; | int i; | ||||
| if (!(activeSnap(t) && (t->tsnap.mode & (SCE_SNAP_MODE_INCREMENT | SCE_SNAP_MODE_GRID)))) { | if (!(activeSnap(t) && (t->tsnap.mode & (SCE_SNAP_MODE_INCREMENT | SCE_SNAP_MODE_GRID)))) { | ||||
| return; | return; | ||||
| } | } | ||||
| Show All 35 Lines | for (i = 0, td = tc->data; i < tc->data_len; i++, td++) { | ||||
| sub_v3_v3v3(tvec, loc, iloc); | sub_v3_v3v3(tvec, loc, iloc); | ||||
| 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 applySnappingAsGroup(TransInfo *t, float *vec) | ||||
| { | { | ||||
| /* Each Trans Data already makes the snap to face */ | if (!activeSnap_SnappingAsGroup(t)) { | ||||
| if (doForceIncrementSnap(t)) { | |||||
| return; | |||||
| } | |||||
| if (t->tsnap.project && t->tsnap.mode == SCE_SNAP_MODE_FACE) { | |||||
| /* A similar snap will be applied to each transdata in `applyProject`. */ | |||||
| return; | return; | ||||
| } | } | ||||
| if (t->tsnap.status & SNAP_FORCED) { | if (t->tsnap.status & SNAP_FORCED) { | ||||
| t->tsnap.targetSnap(t); | t->tsnap.targetSnap(t); | ||||
| t->tsnap.applySnap(t, vec); | t->tsnap.applySnap(t, vec); | ||||
| } | } | ||||
| ▲ Show 20 Lines • Show All 136 Lines • ▼ Show 20 Lines | static eSnapMode snap_mode_from_spacetype(TransInfo *t) | ||||
| if (ELEM(t->spacetype, SPACE_ACTION, SPACE_NLA)) { | if (ELEM(t->spacetype, SPACE_ACTION, SPACE_NLA)) { | ||||
| /* No incremental snapping. */ | /* No incremental snapping. */ | ||||
| return 0; | return 0; | ||||
| } | } | ||||
| return SCE_SNAP_MODE_INCREMENT; | return SCE_SNAP_MODE_INCREMENT; | ||||
| } | } | ||||
| static eSnapTargetSelect snap_select_type_get(TransInfo *t) | static eSnapTargetSelect snap_target_select_from_spacetype(TransInfo *t) | ||||
| { | { | ||||
| ViewLayer *view_layer = t->view_layer; | ViewLayer *view_layer = t->view_layer; | ||||
| Base *base_act = view_layer->basact; | Base *base_act = view_layer->basact; | ||||
| eSnapTargetSelect ret = SCE_SNAP_TARGET_ALL; | |||||
| bool use_snap_active = (t->tsnap.target_select & SCE_SNAP_TARGET_NOT_ACTIVE) == 0; | |||||
| bool use_snap_edit = (t->tsnap.target_select & SCE_SNAP_TARGET_NOT_EDITED) == 0; | |||||
Not Done Inline ActionsThese interrupted names are weird. Also, just to make sure the bools are 0 or 1, you might want to put a != 0 at the end of each. mano-wii: These interrupted names are weird.
In my opinion, informative name is preferable over… | |||||
Done Inline Actionsagreed. gfxcoder: agreed. | |||||
| bool use_snap_nonedit = (t->tsnap.target_select & SCE_SNAP_TARGET_NOT_NONEDITED) == 0; | |||||
| bool use_snap_selectable_only = (t->tsnap.target_select & SCE_SNAP_TARGET_ONLY_SELECTABLE) != 0; | |||||
| if (ELEM(t->spacetype, SPACE_VIEW3D, SPACE_IMAGE) && !(t->options & CTX_CAMERA)) { | if (ELEM(t->spacetype, SPACE_VIEW3D, SPACE_IMAGE) && !(t->options & CTX_CAMERA)) { | ||||
| if (base_act && (base_act->object->mode & OB_MODE_PARTICLE_EDIT)) { | |||||
| /* Particles edit mode. */ | |||||
| return ret; | |||||
| } | |||||
| if (use_snap_selectable_only) { | |||||
| ret |= SCE_SNAP_TARGET_ONLY_SELECTABLE; | |||||
| } | |||||
| if (t->options & (CTX_GPENCIL_STROKES | CTX_CURSOR | CTX_OBMODE_XFORM_OBDATA)) { | if (t->options & (CTX_GPENCIL_STROKES | CTX_CURSOR | CTX_OBMODE_XFORM_OBDATA)) { | ||||
| /* In "Edit Strokes" mode, | /* In "Edit Strokes" mode, | ||||
| * snap tool can perform snap to selected or active objects (see T49632) | * snap tool can perform snap to selected or active objects (see T49632) | ||||
| * TODO: perform self snap in gpencil_strokes. | * TODO: perform self snap in gpencil_strokes. | ||||
| * | * | ||||
| * When we're moving the origins, allow snapping onto our own geometry (see T69132). */ | * When we're moving the origins, allow snapping onto our own geometry (see T69132). */ | ||||
| return SCE_SNAP_TARGET_ALL; | return ret; | ||||
| } | } | ||||
| const int obedit_type = t->obedit_type; | const int obedit_type = t->obedit_type; | ||||
| if (obedit_type != -1) { | if (obedit_type != -1) { | ||||
| /* Edit mode */ | /* Edit mode */ | ||||
| if (ELEM(obedit_type, | if (obedit_type == OB_MESH) { | ||||
| OB_MESH, | /* Editing a mesh */ | ||||
| OB_ARMATURE, | if ((t->flag & T_PROP_EDIT) != 0) { | ||||
| OB_CURVES_LEGACY, | /* Exclude editmesh when using proportional edit */ | ||||
| OB_SURF, | ret |= SCE_SNAP_TARGET_NOT_EDITED; | ||||
| OB_LATTICE, | |||||
| OB_MBALL)) { | |||||
| /* Temporary limited to edit mode meshes, armature, curves, lattice and metaballs. */ | |||||
| if ((obedit_type == OB_MESH) && (t->flag & T_PROP_EDIT)) { | |||||
| /* Exclude editmesh if using proportional edit */ | |||||
| return SCE_SNAP_TARGET_NOT_EDITED; | |||||
| } | } | ||||
| if (!use_snap_active) { | |||||
| if (!t->tsnap.snap_self) { | ret |= SCE_SNAP_TARGET_NOT_ACTIVE; | ||||
| return SCE_SNAP_TARGET_NOT_ACTIVE; | |||||
| } | } | ||||
| if (!use_snap_edit) { | |||||
| return SCE_SNAP_TARGET_NOT_SELECTED; | ret |= SCE_SNAP_TARGET_NOT_EDITED; | ||||
| } | } | ||||
| if (!use_snap_nonedit) { | |||||
| return SCE_SNAP_TARGET_ALL; | ret |= SCE_SNAP_TARGET_NOT_NONEDITED; | ||||
| } | } | ||||
| if (base_act && (base_act->object->mode & OB_MODE_PARTICLE_EDIT)) { | |||||
| /* Particles edit mode. */ | |||||
| return SCE_SNAP_TARGET_ALL; | |||||
| } | } | ||||
| else if (ELEM(obedit_type, OB_ARMATURE, OB_CURVES_LEGACY, OB_SURF, OB_LATTICE, OB_MBALL)) { | |||||
| /* Temporary limited to edit mode armature, curves, surfaces, lattices, and metaballs. */ | |||||
| ret |= SCE_SNAP_TARGET_NOT_SELECTED; | |||||
| } | |||||
| } | |||||
| else { | |||||
| /* Object or pose mode. */ | /* Object or pose mode. */ | ||||
| return SCE_SNAP_TARGET_NOT_SELECTED; | ret |= SCE_SNAP_TARGET_NOT_SELECTED | SCE_SNAP_TARGET_NOT_ACTIVE; | ||||
| } | } | ||||
| } | |||||
| if (ELEM(t->spacetype, SPACE_NODE, SPACE_SEQ)) { | else if (ELEM(t->spacetype, SPACE_NODE, SPACE_SEQ)) { | ||||
| return SCE_SNAP_TARGET_NOT_SELECTED; | ret |= SCE_SNAP_TARGET_NOT_SELECTED; | ||||
| } | } | ||||
| return SCE_SNAP_TARGET_ALL; | return ret; | ||||
| } | } | ||||
| static void initSnappingMode(TransInfo *t) | static void initSnappingMode(TransInfo *t) | ||||
| { | { | ||||
| ToolSettings *ts = t->settings; | if ((t->spacetype != SPACE_VIEW3D) || !(t->tsnap.mode & SCE_SNAP_MODE_FACE_RAYCAST)) { | ||||
| t->tsnap.mode = snap_mode_from_spacetype(t); | |||||
| t->tsnap.target_select = snap_select_type_get(t); | |||||
| 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 = false; | t->tsnap.project = false; | ||||
| } | } | ||||
| if (ELEM(t->spacetype, SPACE_VIEW3D, SPACE_IMAGE, SPACE_NODE, SPACE_SEQ)) { | if (ELEM(t->spacetype, SPACE_VIEW3D, SPACE_IMAGE, SPACE_NODE, SPACE_SEQ)) { | ||||
| /* Not with camera selected in camera view. */ | /* Not with camera selected in camera view. */ | ||||
| if (!(t->options & CTX_CAMERA)) { | if (!(t->options & CTX_CAMERA)) { | ||||
| setSnappingCallback(t); | setSnappingCallback(t); | ||||
| Show All 29 Lines | 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); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| void initSnapping(TransInfo *t, wmOperator *op) | void initSnapping(TransInfo *t, wmOperator *op) | ||||
| { | { | ||||
| ToolSettings *ts = t->settings; | |||||
| eSnapSourceSelect snap_source = ts->snap_target; | |||||
| resetSnapping(t); | resetSnapping(t); | ||||
| t->tsnap.mode = snap_mode_from_spacetype(t); | |||||
| t->tsnap.flag = snap_flag_from_spacetype(t); | t->tsnap.flag = snap_flag_from_spacetype(t); | ||||
| eSnapSourceSelect snap_source = t->settings->snap_target; | t->tsnap.target_select = snap_target_select_from_spacetype(t); | ||||
| t->tsnap.face_nearest_steps = max_ii(ts->snap_face_nearest_steps, 1); | |||||
| /* if snap property exists */ | /* if snap property exists */ | ||||
| PropertyRNA *prop; | PropertyRNA *prop; | ||||
| if (op && (prop = RNA_struct_find_property(op->ptr, "snap")) && | if (op && (prop = RNA_struct_find_property(op->ptr, "snap")) && | ||||
| RNA_property_is_set(op->ptr, prop)) { | RNA_property_is_set(op->ptr, prop)) { | ||||
| if (RNA_property_boolean_get(op->ptr, prop)) { | if (RNA_property_boolean_get(op->ptr, prop)) { | ||||
| t->modifiers |= MOD_SNAP; | t->modifiers |= MOD_SNAP; | ||||
| if ((prop = RNA_struct_find_property(op->ptr, "snap_elements")) && | |||||
| RNA_property_is_set(op->ptr, prop)) { | |||||
| t->tsnap.mode = RNA_property_enum_get(op->ptr, prop); | |||||
| } | |||||
| /* 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). */ | |||||
| if ((prop = RNA_struct_find_property(op->ptr, "snap_target")) && | if ((prop = RNA_struct_find_property(op->ptr, "snap_target")) && | ||||
| RNA_property_is_set(op->ptr, prop)) { | RNA_property_is_set(op->ptr, prop)) { | ||||
| /* 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). */ | |||||
| snap_source = RNA_property_enum_get(op->ptr, prop); | snap_source = RNA_property_enum_get(op->ptr, prop); | ||||
| } | } | ||||
| if ((prop = RNA_struct_find_property(op->ptr, "snap_point")) && | if ((prop = RNA_struct_find_property(op->ptr, "snap_point")) && | ||||
| RNA_property_is_set(op->ptr, prop)) { | RNA_property_is_set(op->ptr, prop)) { | ||||
| RNA_property_float_get_array(op->ptr, prop, t->tsnap.snapPoint); | RNA_property_float_get_array(op->ptr, prop, t->tsnap.snapPoint); | ||||
| t->tsnap.status |= SNAP_FORCED | POINT_INIT; | t->tsnap.status |= SNAP_FORCED | POINT_INIT; | ||||
| } | } | ||||
| /* snap align only defined in specific cases */ | /* snap align only defined in specific cases */ | ||||
| if ((prop = RNA_struct_find_property(op->ptr, "snap_align")) && | if ((prop = RNA_struct_find_property(op->ptr, "snap_align")) && | ||||
| RNA_property_is_set(op->ptr, prop)) { | RNA_property_is_set(op->ptr, prop)) { | ||||
| t->tsnap.align = RNA_property_boolean_get(op->ptr, prop); | t->tsnap.align = RNA_property_boolean_get(op->ptr, prop); | ||||
| RNA_float_get_array(op->ptr, "snap_normal", t->tsnap.snapNormal); | RNA_float_get_array(op->ptr, "snap_normal", t->tsnap.snapNormal); | ||||
| normalize_v3(t->tsnap.snapNormal); | normalize_v3(t->tsnap.snapNormal); | ||||
| } | } | ||||
| if ((prop = RNA_struct_find_property(op->ptr, "use_snap_project")) && | if ((prop = RNA_struct_find_property(op->ptr, "use_snap_project")) && | ||||
| RNA_property_is_set(op->ptr, prop)) { | RNA_property_is_set(op->ptr, prop)) { | ||||
| t->tsnap.project = RNA_property_boolean_get(op->ptr, prop); | t->tsnap.project = RNA_property_boolean_get(op->ptr, prop); | ||||
| } | } | ||||
| /* use_snap_self is misnamed and should be use_snap_active */ | |||||
| if ((prop = RNA_struct_find_property(op->ptr, "use_snap_self")) && | if ((prop = RNA_struct_find_property(op->ptr, "use_snap_self")) && | ||||
| RNA_property_is_set(op->ptr, prop)) { | RNA_property_is_set(op->ptr, prop)) { | ||||
| t->tsnap.snap_self = RNA_property_boolean_get(op->ptr, prop); | SET_FLAG_FROM_TEST(t->tsnap.target_select, | ||||
| !RNA_property_boolean_get(op->ptr, prop), | |||||
| SCE_SNAP_TARGET_NOT_ACTIVE); | |||||
| } | |||||
| if ((prop = RNA_struct_find_property(op->ptr, "use_snap_edit")) && | |||||
| RNA_property_is_set(op->ptr, prop)) { | |||||
| SET_FLAG_FROM_TEST(t->tsnap.target_select, | |||||
| !RNA_property_boolean_get(op->ptr, prop), | |||||
| SCE_SNAP_TARGET_NOT_EDITED); | |||||
| } | |||||
| if ((prop = RNA_struct_find_property(op->ptr, "use_snap_nonedit")) && | |||||
| RNA_property_is_set(op->ptr, prop)) { | |||||
| SET_FLAG_FROM_TEST(t->tsnap.target_select, | |||||
| !RNA_property_boolean_get(op->ptr, prop), | |||||
| SCE_SNAP_TARGET_NOT_NONEDITED); | |||||
| } | |||||
| if ((prop = RNA_struct_find_property(op->ptr, "use_snap_selectable")) && | |||||
| RNA_property_is_set(op->ptr, prop)) { | |||||
| SET_FLAG_FROM_TEST(t->tsnap.target_select, | |||||
| RNA_property_boolean_get(op->ptr, prop), | |||||
| SCE_SNAP_TARGET_ONLY_SELECTABLE); | |||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| /* use scene defaults only when transform is modal */ | /* use scene defaults only when transform is modal */ | ||||
| else if (t->flag & T_MODAL) { | else if (t->flag & T_MODAL) { | ||||
| if (transformModeUseSnap(t) && (t->tsnap.flag & SCE_SNAP)) { | if (transformModeUseSnap(t) && (t->tsnap.flag & SCE_SNAP)) { | ||||
| t->modifiers |= MOD_SNAP; | t->modifiers |= MOD_SNAP; | ||||
| } | } | ||||
| t->tsnap.align = ((t->tsnap.flag & SCE_SNAP_ROTATE) != 0); | t->tsnap.align = ((t->tsnap.flag & SCE_SNAP_ROTATE) != 0); | ||||
| t->tsnap.project = ((t->tsnap.flag & SCE_SNAP_PROJECT) != 0); | t->tsnap.project = ((t->tsnap.flag & SCE_SNAP_PROJECT) != 0); | ||||
| t->tsnap.snap_self = !((t->tsnap.flag & SCE_SNAP_NO_SELF) != 0); | |||||
| t->tsnap.peel = ((t->tsnap.flag & SCE_SNAP_PROJECT) != 0); | t->tsnap.peel = ((t->tsnap.flag & SCE_SNAP_PROJECT) != 0); | ||||
| SET_FLAG_FROM_TEST(t->tsnap.target_select, | |||||
| (ts->snap_flag & SCE_SNAP_NOT_TO_ACTIVE), | |||||
| SCE_SNAP_TARGET_NOT_ACTIVE); | |||||
| SET_FLAG_FROM_TEST(t->tsnap.target_select, | |||||
| !(ts->snap_flag & SCE_SNAP_TO_INCLUDE_EDITED), | |||||
| SCE_SNAP_TARGET_NOT_EDITED); | |||||
| SET_FLAG_FROM_TEST(t->tsnap.target_select, | |||||
| !(ts->snap_flag & SCE_SNAP_TO_INCLUDE_NONEDITED), | |||||
| SCE_SNAP_TARGET_NOT_NONEDITED); | |||||
| SET_FLAG_FROM_TEST(t->tsnap.target_select, | |||||
| (ts->snap_flag & SCE_SNAP_TO_ONLY_SELECTABLE), | |||||
| SCE_SNAP_TARGET_ONLY_SELECTABLE); | |||||
| } | } | ||||
| t->tsnap.source_select = snap_source; | t->tsnap.source_select = snap_source; | ||||
| initSnappingMode(t); | initSnappingMode(t); | ||||
| } | } | ||||
| void freeSnapping(TransInfo *t) | void freeSnapping(TransInfo *t) | ||||
| ▲ Show 20 Lines • Show All 168 Lines • ▼ Show 20 Lines | static void snap_calc_view3d_fn(TransInfo *t, float *UNUSED(vec)) | ||||
| mval[1] = t->mval[1]; | mval[1] = t->mval[1]; | ||||
| if (t->tsnap.mode & SCE_SNAP_MODE_GEOM) { | if (t->tsnap.mode & SCE_SNAP_MODE_GEOM) { | ||||
| zero_v3(no); /* objects won't set this */ | zero_v3(no); /* objects won't set this */ | ||||
| snap_elem = snapObjectsTransform(t, mval, &dist_px, loc, no); | snap_elem = snapObjectsTransform(t, mval, &dist_px, loc, no); | ||||
| found = (snap_elem != SCE_SNAP_MODE_NONE); | found = (snap_elem != SCE_SNAP_MODE_NONE); | ||||
| } | } | ||||
| if ((found == false) && (t->tsnap.mode & SCE_SNAP_MODE_VOLUME)) { | if ((found == false) && (t->tsnap.mode & SCE_SNAP_MODE_VOLUME)) { | ||||
| found = peelObjectsTransform( | bool use_peel = (t->settings->snap_flag & SCE_SNAP_PEEL_OBJECT) != 0; | ||||
| t, mval, (t->settings->snap_flag & SCE_SNAP_PEEL_OBJECT) != 0, loc, no, NULL); | found = peelObjectsTransform(t, mval, use_peel, loc, no, NULL); | ||||
| if (found) { | if (found) { | ||||
| snap_elem = SCE_SNAP_MODE_VOLUME; | snap_elem = SCE_SNAP_MODE_VOLUME; | ||||
| } | } | ||||
| } | } | ||||
| if (found == true) { | if (found == true) { | ||||
| copy_v3_v3(t->tsnap.snapPoint, loc); | copy_v3_v3(t->tsnap.snapPoint, loc); | ||||
| Show All 17 Lines | Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs( | ||||
| t->view_layer, NULL, &objects_len); | t->view_layer, NULL, &objects_len); | ||||
| float dist_sq = square_f((float)SNAP_MIN_DISTANCE); | float dist_sq = square_f((float)SNAP_MIN_DISTANCE); | ||||
| if (ED_uvedit_nearest_uv_multi(&t->region->v2d, | if (ED_uvedit_nearest_uv_multi(&t->region->v2d, | ||||
| t->scene, | t->scene, | ||||
| objects, | objects, | ||||
| objects_len, | objects_len, | ||||
| t->mval, | t->mval, | ||||
| t->tsnap.target_select == SCE_SNAP_TARGET_NOT_SELECTED, | t->tsnap.target_select & SCE_SNAP_TARGET_NOT_SELECTED, | ||||
| &dist_sq, | &dist_sq, | ||||
| t->tsnap.snapPoint)) { | t->tsnap.snapPoint)) { | ||||
| t->tsnap.snapPoint[0] *= t->aspect[0]; | t->tsnap.snapPoint[0] *= t->aspect[0]; | ||||
| t->tsnap.snapPoint[1] *= t->aspect[1]; | t->tsnap.snapPoint[1] *= t->aspect[1]; | ||||
| t->tsnap.status |= POINT_INIT; | t->tsnap.status |= POINT_INIT; | ||||
| } | } | ||||
| else { | else { | ||||
| ▲ Show 20 Lines • Show All 278 Lines • ▼ Show 20 Lines | return ED_transform_snap_object_project_view3d( | ||||
| t->tsnap.object_context, | t->tsnap.object_context, | ||||
| t->depsgraph, | t->depsgraph, | ||||
| t->region, | t->region, | ||||
| t->view, | t->view, | ||||
| t->tsnap.mode, | t->tsnap.mode, | ||||
| &(const struct SnapObjectParams){ | &(const struct SnapObjectParams){ | ||||
| .snap_target_select = t->tsnap.target_select, | .snap_target_select = t->tsnap.target_select, | ||||
| .edit_mode_type = (t->flag & T_EDIT) != 0 ? SNAP_GEOM_EDIT : SNAP_GEOM_FINAL, | .edit_mode_type = (t->flag & T_EDIT) != 0 ? SNAP_GEOM_EDIT : SNAP_GEOM_FINAL, | ||||
| .use_occlusion_test = t->settings->snap_mode != SCE_SNAP_MODE_FACE, | .use_occlusion_test = t->settings->snap_mode != SCE_SNAP_MODE_FACE_RAYCAST, | ||||
| .use_backface_culling = t->tsnap.use_backface_culling, | .use_backface_culling = t->tsnap.use_backface_culling, | ||||
| }, | }, | ||||
| NULL, | |||||
| mval, | mval, | ||||
| target, | target, | ||||
| dist_px, | dist_px, | ||||
| r_loc, | r_loc, | ||||
| r_no); | r_no); | ||||
| } | } | ||||
| /** \} */ | /** \} */ | ||||
| ▲ Show 20 Lines • Show All 83 Lines • ▼ Show 20 Lines | |||||
| /* -------------------------------------------------------------------- */ | /* -------------------------------------------------------------------- */ | ||||
| /** \name snap Nodes | /** \name snap Nodes | ||||
| * \{ */ | * \{ */ | ||||
| static bool snapNodeTest(View2D *v2d, bNode *node, eSnapTargetSelect snap_target_select) | static bool snapNodeTest(View2D *v2d, bNode *node, eSnapTargetSelect snap_target_select) | ||||
| { | { | ||||
| /* node is use for snapping only if a) snap mode matches and b) node is inside the view */ | /* node is use for snapping only if a) snap mode matches and b) node is inside the view */ | ||||
| return ((snap_target_select == SCE_SNAP_TARGET_NOT_SELECTED && !(node->flag & NODE_SELECT)) || | return (((snap_target_select & SCE_SNAP_TARGET_NOT_SELECTED) && !(node->flag & NODE_SELECT)) || | ||||
| (snap_target_select == SCE_SNAP_TARGET_ALL && !(node->flag & NODE_ACTIVE))) && | (snap_target_select == SCE_SNAP_TARGET_ALL && !(node->flag & NODE_ACTIVE))) && | ||||
| (node->totr.xmin < v2d->cur.xmax && node->totr.xmax > v2d->cur.xmin && | (node->totr.xmin < v2d->cur.xmax && node->totr.xmax > v2d->cur.xmin && | ||||
| node->totr.ymin < v2d->cur.ymax && node->totr.ymax > v2d->cur.ymin); | node->totr.ymin < v2d->cur.ymax && node->totr.ymax > v2d->cur.ymin); | ||||
| } | } | ||||
| static NodeBorder snapNodeBorder(eSnapMode snap_node_mode) | static NodeBorder snapNodeBorder(eSnapMode snap_node_mode) | ||||
| { | { | ||||
| NodeBorder flag = 0; | NodeBorder flag = 0; | ||||
| ▲ Show 20 Lines • Show All 274 Lines • Show Last 20 Lines | |||||
Should this be removed?