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:
Diffstat (limited to 'source/blender/editors/transform/transform_snap_object.cc')
-rw-r--r--source/blender/editors/transform/transform_snap_object.cc891
1 files changed, 636 insertions, 255 deletions
diff --git a/source/blender/editors/transform/transform_snap_object.cc b/source/blender/editors/transform/transform_snap_object.cc
index 0505772c668..479214ee2d3 100644
--- a/source/blender/editors/transform/transform_snap_object.cc
+++ b/source/blender/editors/transform/transform_snap_object.cc
@@ -157,7 +157,7 @@ struct SnapObjectContext {
enum eViewProj view_proj;
float clip_plane[MAX_CLIPPLANE_LEN][4];
short clip_plane_len;
- short snap_to_flag;
+ eSnapMode snap_to_flag;
bool has_occlusion_plane; /* Ignore plane of occlusion in curves. */
} runtime;
};
@@ -283,8 +283,10 @@ static SnapData_Mesh *snap_object_data_mesh_get(SnapObjectContext *sctx,
}
}
else {
- /* Any existing #SnapData_EditMesh is now invalid. */
- sctx->editmesh_caches.remove(BKE_editmesh_from_object(ob_eval));
+ if (ob_eval->type == OB_MESH) {
+ /* Any existing #SnapData_EditMesh is now invalid. */
+ sctx->editmesh_caches.remove(BKE_editmesh_from_object(ob_eval));
+ }
std::unique_ptr<SnapData_Mesh> sod_ptr = std::make_unique<SnapData_Mesh>();
sod = sod_ptr.get();
@@ -403,6 +405,62 @@ static SnapData_EditMesh *snap_object_data_editmesh_get(SnapObjectContext *sctx,
return sod;
}
+static BVHTreeFromMesh *snap_object_data_mesh_treedata_get(SnapObjectContext *sctx,
+ Object *ob_eval,
+ const Mesh *me_eval,
+ bool use_hide)
+{
+ SnapData_Mesh *sod = snap_object_data_mesh_get(sctx, ob_eval, me_eval, use_hide);
+ return &sod->treedata_mesh;
+}
+
+static BVHTreeFromEditMesh *snap_object_data_editmesh_treedata_get(SnapObjectContext *sctx,
+ Object *ob_eval,
+ BMEditMesh *em)
+{
+ SnapData_EditMesh *sod = snap_object_data_editmesh_get(sctx, ob_eval, em);
+
+ BVHTreeFromEditMesh *treedata = &sod->treedata_editmesh;
+
+ if (treedata->tree == nullptr) {
+ /* Operators only update the editmesh looptris of the original mesh. */
+ BLI_assert(sod->treedata_editmesh.em ==
+ BKE_editmesh_from_object(DEG_get_original_object(ob_eval)));
+ em = sod->treedata_editmesh.em;
+
+ if (sctx->callbacks.edit_mesh.test_face_fn) {
+ BMesh *bm = em->bm;
+ BLI_assert(poly_to_tri_count(bm->totface, bm->totloop) == em->tottri);
+
+ BLI_bitmap *elem_mask = BLI_BITMAP_NEW(em->tottri, __func__);
+ int looptri_num_active = BM_iter_mesh_bitmap_from_filter_tessface(
+ bm,
+ elem_mask,
+ sctx->callbacks.edit_mesh.test_face_fn,
+ sctx->callbacks.edit_mesh.user_data);
+
+ bvhtree_from_editmesh_looptri_ex(treedata, em, elem_mask, looptri_num_active, 0.0f, 4, 6);
+
+ MEM_freeN(elem_mask);
+ }
+ else {
+ /* Only cache if BVH-tree is created without a mask.
+ * This helps keep a standardized BVH-tree in cache. */
+ BKE_bvhtree_from_editmesh_get(treedata,
+ em,
+ 4,
+ BVHTREE_FROM_EM_LOOPTRI,
+ &sod->mesh_runtime->bvh_cache,
+ static_cast<ThreadMutex *>(sod->mesh_runtime->eval_mutex));
+ }
+ }
+ if (treedata == nullptr || treedata->tree == nullptr) {
+ return nullptr;
+ }
+
+ return treedata;
+}
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -417,16 +475,16 @@ using IterSnapObjsCallback = void (*)(SnapObjectContext *sctx,
void *data);
static bool snap_object_is_snappable(const SnapObjectContext *sctx,
- const eSnapSelect snap_select,
+ const eSnapTargetSelect snap_target_select,
const Base *base_act,
- const Base *base,
- const bool is_in_object_mode)
+ const Base *base)
{
if (!BASE_VISIBLE(sctx->runtime.v3d, base)) {
return false;
}
- if ((snap_select == SNAP_ALL) || (base->flag_legacy & BA_TRANSFORM_LOCKED_IN_PLACE)) {
+ if ((snap_target_select == SCE_SNAP_TARGET_ALL) ||
+ (base->flag_legacy & BA_TRANSFORM_LOCKED_IN_PLACE)) {
return true;
}
@@ -434,25 +492,37 @@ static bool snap_object_is_snappable(const SnapObjectContext *sctx,
return false;
}
- if (snap_select == SNAP_NOT_ACTIVE) {
- return base_act != base;
- }
+ /* Get attributes of potential target. */
+ const bool is_active = (base_act == base);
+ const bool is_selected = (base->flag & BASE_SELECTED) || (base->flag_legacy & BA_WAS_SEL);
+ const bool is_edited = (base->object->mode == OB_MODE_EDIT);
+ const bool is_selectable = (base->flag & BASE_SELECTABLE);
+ /* Get attributes of state. */
+ const bool is_in_object_mode = (base_act == NULL) || (base_act->object->mode == OB_MODE_OBJECT);
- if (snap_select == SNAP_NOT_EDITED) {
- return base->object->mode != OB_MODE_EDIT;
+ if (is_in_object_mode) {
+ /* Handle target selection options that make sense for object mode. */
+ if ((snap_target_select & SCE_SNAP_TARGET_NOT_SELECTED) && is_selected) {
+ /* What is selectable or not is part of the object and depends on the mode. */
+ return false;
+ }
}
-
- if (snap_select == SNAP_NOT_SELECTED) {
- if (is_in_object_mode) {
- return !((base->flag & BASE_SELECTED) || (base->flag_legacy & BA_WAS_SEL));
+ else {
+ /* Handle target selection options that make sense for edit/pose mode. */
+ if ((snap_target_select & SCE_SNAP_TARGET_NOT_ACTIVE) && is_active) {
+ return false;
+ }
+ if ((snap_target_select & SCE_SNAP_TARGET_NOT_EDITED) && is_edited && !is_active) {
+ /* Base is edited, but not active. */
+ return false;
+ }
+ if ((snap_target_select & SCE_SNAP_TARGET_NOT_NONEDITED) && !is_edited) {
+ return false;
}
-
- /* What is selectable or not is part of the object and depends on the mode. */
- return true;
}
- if (snap_select == SNAP_SELECTABLE) {
- return (base->flag & BASE_SELECTABLE) != 0;
+ if ((snap_target_select & SCE_SNAP_TARGET_ONLY_SELECTABLE) && !is_selectable) {
+ return false;
}
return true;
@@ -467,12 +537,11 @@ static void iter_snap_objects(SnapObjectContext *sctx,
void *data)
{
ViewLayer *view_layer = DEG_get_input_view_layer(sctx->runtime.depsgraph);
- const eSnapSelect snap_select = params->snap_select;
-
+ const eSnapTargetSelect snap_target_select = params->snap_target_select;
Base *base_act = view_layer->basact;
- const bool is_in_object_mode = !base_act || base_act->object->mode == OB_MODE_OBJECT;
+
LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) {
- if (!snap_object_is_snappable(sctx, snap_select, base_act, base, is_in_object_mode)) {
+ if (!snap_object_is_snappable(sctx, snap_target_select, base_act, base)) {
continue;
}
@@ -848,40 +917,9 @@ static bool raycastEditMesh(SnapObjectContext *sctx,
len_diff = 0.0f;
}
- BVHTreeFromEditMesh *treedata = &sod->treedata_editmesh;
-
- if (treedata->tree == nullptr) {
- em = sod->treedata_editmesh.em;
-
- if (sctx->callbacks.edit_mesh.test_face_fn) {
- BMesh *bm = em->bm;
- BLI_assert(poly_to_tri_count(bm->totface, bm->totloop) == em->tottri);
-
- BLI_bitmap *elem_mask = BLI_BITMAP_NEW(em->tottri, __func__);
- int looptri_num_active = BM_iter_mesh_bitmap_from_filter_tessface(
- bm,
- elem_mask,
- sctx->callbacks.edit_mesh.test_face_fn,
- sctx->callbacks.edit_mesh.user_data);
-
- bvhtree_from_editmesh_looptri_ex(treedata, em, elem_mask, looptri_num_active, 0.0f, 4, 6);
-
- MEM_freeN(elem_mask);
- }
- else {
- /* Only cache if bvhtree is created without a mask.
- * This helps keep a standardized bvhtree in cache. */
- BKE_bvhtree_from_editmesh_get(treedata,
- em,
- 4,
- BVHTREE_FROM_EM_LOOPTRI,
- &sod->mesh_runtime->bvh_cache,
- static_cast<ThreadMutex *>(sod->mesh_runtime->eval_mutex));
- }
-
- if (treedata->tree == nullptr) {
- return retval;
- }
+ BVHTreeFromEditMesh *treedata = snap_object_data_editmesh_treedata_get(sctx, ob_eval, em);
+ if (treedata == nullptr) {
+ return retval;
}
float timat[3][3]; /* transpose inverse matrix for normals */
@@ -1096,7 +1134,7 @@ static void raycast_obj_fn(SnapObjectContext *sctx,
* \param r_loc: Hit location.
* \param r_no: Hit normal (optional).
* \param r_index: Hit index or -1 when no valid index is found.
- * (currently only set to the polygon index when using `snap_to == SCE_SNAP_MODE_FACE`).
+ * (currently only set to the polygon index when using `snap_to == SCE_SNAP_MODE_FACE_RAYCAST`).
* \param r_ob: Hit object.
* \param r_obmat: Object matrix (may not be #Object.obmat with dupli-instances).
* \param r_hit_list: List of #SnapObjectHitDepth (caller must free).
@@ -1148,6 +1186,324 @@ static bool raycastObjects(SnapObjectContext *sctx,
/** \} */
/* -------------------------------------------------------------------- */
+/** \name Surface Snap Funcs
+ * \{ */
+
+struct NearestWorldObjUserData {
+ const float *init_co;
+ const float *curr_co;
+ /* return args */
+ float *r_loc;
+ float *r_no;
+ int *r_index;
+ float r_dist_sq;
+ Object **r_ob;
+ float (*r_obmat)[4];
+ ListBase *r_hit_list;
+ bool ret;
+};
+
+static void nearest_world_tree_co(BVHTree *tree,
+ BVHTree_NearestPointCallback nearest_cb,
+ void *treedata,
+ float co[3],
+ float r_co[3],
+ float r_no[3],
+ int *r_index,
+ float *r_dist_sq)
+{
+ BVHTreeNearest nearest = {};
+ nearest.index = -1;
+ copy_v3_fl(nearest.co, FLT_MAX);
+ nearest.dist_sq = FLT_MAX;
+
+ BLI_bvhtree_find_nearest(tree, co, &nearest, nearest_cb, treedata);
+
+ if (r_co) {
+ copy_v3_v3(r_co, nearest.co);
+ }
+ if (r_no) {
+ copy_v3_v3(r_no, nearest.no);
+ }
+ if (r_index) {
+ *r_index = nearest.index;
+ }
+ if (r_dist_sq) {
+ float diff[3];
+ sub_v3_v3v3(diff, co, nearest.co);
+ *r_dist_sq = len_squared_v3(diff);
+ }
+}
+
+static bool nearest_world_tree(SnapObjectContext *UNUSED(sctx),
+ const struct SnapObjectParams *params,
+ BVHTree *tree,
+ BVHTree_NearestPointCallback nearest_cb,
+ void *treedata,
+ const float (*obmat)[4],
+ const float init_co[3],
+ const float curr_co[3],
+ float *r_dist_sq,
+ float *r_loc,
+ float *r_no,
+ int *r_index)
+{
+ if (curr_co == nullptr || init_co == nullptr) {
+ /* No location to work with, so just return. */
+ return false;
+ }
+
+ float imat[4][4];
+ invert_m4_m4(imat, obmat);
+
+ float timat[3][3]; /* transpose inverse matrix for normals */
+ transpose_m3_m4(timat, imat);
+
+ /* compute offset between init co and prev co in local space */
+ float init_co_local[3], curr_co_local[3];
+ float delta_local[3];
+ mul_v3_m4v3(init_co_local, imat, init_co);
+ mul_v3_m4v3(curr_co_local, imat, curr_co);
+ sub_v3_v3v3(delta_local, curr_co_local, init_co_local);
+
+ float dist_sq;
+ if (params->keep_on_same_target) {
+ nearest_world_tree_co(
+ tree, nearest_cb, treedata, init_co_local, nullptr, nullptr, nullptr, &dist_sq);
+ }
+ else {
+ /* NOTE: when `params->face_nearest_steps == 1`, the return variables of function below contain
+ * the answer. We could return immediately after updating r_loc, r_no, r_index, but that would
+ * also complicate the code. Foregoing slight optimization for code clarity. */
+ nearest_world_tree_co(
+ tree, nearest_cb, treedata, curr_co_local, nullptr, nullptr, nullptr, &dist_sq);
+ }
+ if (*r_dist_sq <= dist_sq) {
+ return false;
+ }
+ *r_dist_sq = dist_sq;
+
+ /* scale to make `snap_face_nearest_steps` steps */
+ float step_scale_factor = 1.0f / max_ff(1.0f, (float)params->face_nearest_steps);
+ mul_v3_fl(delta_local, step_scale_factor);
+
+ float co_local[3];
+ float no_local[3];
+ int index;
+
+ copy_v3_v3(co_local, init_co_local);
+
+ for (int i = 0; i < params->face_nearest_steps; i++) {
+ add_v3_v3(co_local, delta_local);
+ nearest_world_tree_co(
+ tree, nearest_cb, treedata, co_local, co_local, no_local, &index, nullptr);
+ }
+
+ mul_v3_m4v3(r_loc, obmat, co_local);
+
+ if (r_no) {
+ mul_v3_m3v3(r_no, timat, no_local);
+ normalize_v3(r_no);
+ }
+
+ if (r_index) {
+ *r_index = index;
+ }
+
+ return true;
+}
+
+static bool nearest_world_mesh(SnapObjectContext *sctx,
+ const struct SnapObjectParams *params,
+ Object *ob_eval,
+ const Mesh *me_eval,
+ const float (*obmat)[4],
+ bool use_hide,
+ const float init_co[3],
+ const float curr_co[3],
+ float *r_dist_sq,
+ float *r_loc,
+ float *r_no,
+ int *r_index)
+{
+ BVHTreeFromMesh *treedata = snap_object_data_mesh_treedata_get(sctx, ob_eval, me_eval, use_hide);
+ if (treedata == nullptr || treedata->tree == nullptr) {
+ return false;
+ }
+
+ return nearest_world_tree(sctx,
+ params,
+ treedata->tree,
+ treedata->nearest_callback,
+ treedata,
+ obmat,
+ init_co,
+ curr_co,
+ r_dist_sq,
+ r_loc,
+ r_no,
+ r_index);
+}
+
+static bool nearest_world_editmesh(SnapObjectContext *sctx,
+ const struct SnapObjectParams *params,
+ Object *ob_eval,
+ BMEditMesh *em,
+ const float (*obmat)[4],
+ const float init_co[3],
+ const float curr_co[3],
+ float *r_dist_sq,
+ float *r_loc,
+ float *r_no,
+ int *r_index)
+{
+ BVHTreeFromEditMesh *treedata = snap_object_data_editmesh_treedata_get(sctx, ob_eval, em);
+ if (treedata == nullptr || treedata->tree == nullptr) {
+ return false;
+ }
+
+ return nearest_world_tree(sctx,
+ params,
+ treedata->tree,
+ treedata->nearest_callback,
+ treedata,
+ obmat,
+ init_co,
+ curr_co,
+ r_dist_sq,
+ r_loc,
+ r_no,
+ r_index);
+}
+static void nearest_world_object_fn(SnapObjectContext *sctx,
+ const struct SnapObjectParams *params,
+ Object *ob_eval,
+ const float obmat[4][4],
+ bool is_object_active,
+ void *data)
+{
+ struct NearestWorldObjUserData *dt = static_cast<NearestWorldObjUserData *>(data);
+
+ bool retval = false;
+ switch (ob_eval->type) {
+ case OB_MESH: {
+ const eSnapEditType edit_mode_type = params->edit_mode_type;
+ bool use_hide = false;
+ const Mesh *me_eval = mesh_for_snap(ob_eval, edit_mode_type, &use_hide);
+ if (me_eval) {
+ retval = nearest_world_mesh(sctx,
+ params,
+ ob_eval,
+ me_eval,
+ obmat,
+ use_hide,
+ dt->init_co,
+ dt->curr_co,
+ &dt->r_dist_sq,
+ dt->r_loc,
+ dt->r_no,
+ dt->r_index);
+ }
+ else {
+ BMEditMesh *em = BKE_editmesh_from_object(ob_eval);
+ BLI_assert_msg(em == BKE_editmesh_from_object(DEG_get_original_object(ob_eval)),
+ "Make sure there is only one pointer for looptris");
+ retval = nearest_world_editmesh(sctx,
+ params,
+ ob_eval,
+ em,
+ obmat,
+ dt->init_co,
+ dt->curr_co,
+ &dt->r_dist_sq,
+ dt->r_loc,
+ dt->r_no,
+ dt->r_index);
+ }
+ break;
+ }
+ case OB_CURVES_LEGACY:
+ case OB_SURF:
+ case OB_FONT:
+ if (!is_object_active) {
+ const Mesh *me_eval = BKE_object_get_evaluated_mesh(ob_eval);
+ if (me_eval) {
+ retval = nearest_world_mesh(sctx,
+ params,
+ ob_eval,
+ me_eval,
+ obmat,
+ false,
+ dt->init_co,
+ dt->curr_co,
+ &dt->r_dist_sq,
+ dt->r_loc,
+ dt->r_no,
+ dt->r_index);
+ }
+ }
+ break;
+ }
+
+ if (retval) {
+ if (dt->r_ob) {
+ *dt->r_ob = ob_eval;
+ }
+ if (dt->r_obmat) {
+ copy_m4_m4(dt->r_obmat, obmat);
+ }
+ dt->ret = true;
+ }
+}
+
+/**
+ * Main Nearest World Surface Function
+ * ===================================
+ *
+ * Walks through all objects in the scene to find the nearest location on target surface.
+ *
+ * \param sctx: Snap context to store data.
+ * \param params: Settings for snapping.
+ * \param init_co: Initial location of source point.
+ * \param prev_co: Current location of source point after transformation but before snapping.
+ *
+ * Output Args
+ * -----------
+ *
+ * \param r_loc: Location of nearest point on target surface.
+ * \param r_no: Normal of nearest point on target surface.
+ * \param r_index: Index of nearest polygon on target surface.
+ * \param r_ob: Nearest target object.
+ * \param r_obmat: Nearest target matrix (may not be #Object.obmat with dupli-instances).
+ */
+static bool nearestWorldObjects(SnapObjectContext *sctx,
+ const struct SnapObjectParams *params,
+ const float init_co[3],
+ const float curr_co[3],
+ float *r_loc /* NOLINT */,
+ float *r_no /* NOLINT */,
+ int *r_index /* NOLINT */,
+ Object **r_ob,
+ float r_obmat[4][4])
+{
+ NearestWorldObjUserData data = {};
+ data.init_co = init_co;
+ data.curr_co = curr_co;
+ data.r_loc = r_loc;
+ data.r_no = r_no;
+ data.r_index = r_index;
+ data.r_dist_sq = FLT_MAX;
+ data.r_ob = r_ob;
+ data.r_obmat = r_obmat;
+ data.ret = false;
+
+ iter_snap_objects(sctx, params, nearest_world_object_fn, &data);
+ return data.ret;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
/** \name Snap Nearest utilities
* \{ */
@@ -1533,18 +1889,18 @@ static void nearest2d_data_init_editmesh(SnapData_EditMesh *sod,
/** \name Internal Object Snapping API
* \{ */
-static short snap_mesh_polygon(SnapObjectContext *sctx,
- const SnapObjectParams *params,
- Object *ob_eval,
- const float obmat[4][4],
- /* read/write args */
- float *dist_px,
- /* return args */
- float r_loc[3],
- float r_no[3],
- int *r_index)
+static eSnapMode snap_mesh_polygon(SnapObjectContext *sctx,
+ const SnapObjectParams *params,
+ Object *ob_eval,
+ const float obmat[4][4],
+ /* read/write args */
+ float *dist_px,
+ /* return args */
+ float r_loc[3],
+ float r_no[3],
+ int *r_index)
{
- short elem = 0;
+ eSnapMode elem = SCE_SNAP_MODE_NONE;
float lpmat[4][4];
mul_m4_m4m4(lpmat, sctx->runtime.pmat, obmat);
@@ -1663,23 +2019,23 @@ static short snap_mesh_polygon(SnapObjectContext *sctx,
return elem;
}
- return 0;
+ return SCE_SNAP_MODE_NONE;
}
-static short snap_mesh_edge_verts_mixed(SnapObjectContext *sctx,
- const SnapObjectParams *params,
- Object *ob_eval,
- const float obmat[4][4],
- float original_dist_px,
- const float prev_co[3],
- /* read/write args */
- float *dist_px,
- /* return args */
- float r_loc[3],
- float r_no[3],
- int *r_index)
+static eSnapMode snap_mesh_edge_verts_mixed(SnapObjectContext *sctx,
+ const SnapObjectParams *params,
+ Object *ob_eval,
+ const float obmat[4][4],
+ float original_dist_px,
+ const float prev_co[3],
+ /* read/write args */
+ float *dist_px,
+ /* return args */
+ float r_loc[3],
+ float r_no[3],
+ int *r_index)
{
- short elem = SCE_SNAP_MODE_EDGE;
+ eSnapMode elem = SCE_SNAP_MODE_EDGE;
if (ob_eval->type != OB_MESH) {
return elem;
@@ -1826,21 +2182,22 @@ static short snap_mesh_edge_verts_mixed(SnapObjectContext *sctx,
return elem;
}
-static short snapArmature(SnapObjectContext *sctx,
- const SnapObjectParams *params,
- Object *ob_eval,
- const float obmat[4][4],
- bool is_object_active,
- /* read/write args */
- float *dist_px,
- /* return args */
- float r_loc[3],
- float *UNUSED(r_no),
- int *r_index)
+static eSnapMode snapArmature(SnapObjectContext *sctx,
+ const SnapObjectParams *params,
+ Object *ob_eval,
+ const float obmat[4][4],
+ bool is_object_active,
+ /* read/write args */
+ float *dist_px,
+ /* return args */
+ float r_loc[3],
+ float *UNUSED(r_no),
+ int *r_index)
{
- short retval = 0;
+ eSnapMode retval = SCE_SNAP_MODE_NONE;
- if (sctx->runtime.snap_to_flag == SCE_SNAP_MODE_FACE) { /* Currently only edge and vert */
+ if (sctx->runtime.snap_to_flag == SCE_SNAP_MODE_FACE_RAYCAST) {
+ /* Currently only edge and vert */
return retval;
}
@@ -1875,7 +2232,7 @@ static short snapArmature(SnapObjectContext *sctx,
const bool is_posemode = is_object_active && (ob_eval->mode & OB_MODE_POSE);
const bool skip_selected = (is_editmode || is_posemode) &&
- (params->snap_select == SNAP_NOT_SELECTED);
+ (params->snap_target_select & SCE_SNAP_TARGET_NOT_SELECTED);
const bool is_persp = sctx->runtime.view_proj == VIEW_PROJ_PERSP;
if (arm->edbo) {
@@ -1990,25 +2347,25 @@ static short snapArmature(SnapObjectContext *sctx,
return retval;
}
- return 0;
+ return SCE_SNAP_MODE_NONE;
}
-static short snapCurve(SnapObjectContext *sctx,
- const SnapObjectParams *params,
- Object *ob_eval,
- const float obmat[4][4],
- /* read/write args */
- float *dist_px,
- /* return args */
- float r_loc[3],
- float *UNUSED(r_no),
- int *r_index)
+static eSnapMode snapCurve(SnapObjectContext *sctx,
+ const SnapObjectParams *params,
+ Object *ob_eval,
+ const float obmat[4][4],
+ /* read/write args */
+ float *dist_px,
+ /* return args */
+ float r_loc[3],
+ float *UNUSED(r_no),
+ int *r_index)
{
bool has_snap = false;
/* only vertex snapping mode (eg control points and handles) supported for now) */
if ((sctx->runtime.snap_to_flag & SCE_SNAP_MODE_VERTEX) == 0) {
- return 0;
+ return SCE_SNAP_MODE_NONE;
}
Curve *cu = static_cast<Curve *>(ob_eval->data);
@@ -2032,7 +2389,7 @@ static short snapCurve(SnapObjectContext *sctx,
sctx->runtime.win_size,
sctx->runtime.mval,
dist_px_sq)) {
- return 0;
+ return SCE_SNAP_MODE_NONE;
}
}
@@ -2054,7 +2411,7 @@ static short snapCurve(SnapObjectContext *sctx,
}
bool is_persp = sctx->runtime.view_proj == VIEW_PROJ_PERSP;
- bool skip_selected = params->snap_select == SNAP_NOT_SELECTED;
+ bool skip_selected = params->snap_target_select & SCE_SNAP_TARGET_NOT_SELECTED;
LISTBASE_FOREACH (Nurb *, nu, (use_obedit ? &cu->editnurb->nurbs : &cu->nurb)) {
for (int u = 0; u < nu->pntsu; u++) {
@@ -2077,11 +2434,14 @@ static short snapCurve(SnapObjectContext *sctx,
nu->bezt[u].vec[1],
&dist_px_sq,
r_loc);
+
/* Don't snap if handle is selected (moving),
* or if it is aligning to a moving handle. */
- is_selected = (!(nu->bezt[u].f1 & SELECT) &&
- !(nu->bezt[u].h1 & HD_ALIGN && nu->bezt[u].f3 & SELECT)) != 0;
- if (!(is_selected && skip_selected)) {
+ bool is_selected_h1 = (nu->bezt[u].f1 & SELECT) != 0;
+ bool is_selected_h2 = (nu->bezt[u].f3 & SELECT) != 0;
+ bool is_autoalign_h1 = (nu->bezt[u].h1 & HD_ALIGN) != 0;
+ bool is_autoalign_h2 = (nu->bezt[u].h2 & HD_ALIGN) != 0;
+ if (!skip_selected || !(is_selected_h1 || (is_autoalign_h1 && is_selected_h2))) {
has_snap |= test_projected_vert_dist(&neasrest_precalc,
clip_planes_local,
clip_plane_len,
@@ -2091,9 +2451,7 @@ static short snapCurve(SnapObjectContext *sctx,
r_loc);
}
- is_selected = (!(nu->bezt[u].f3 & SELECT) &&
- !(nu->bezt[u].h2 & HD_ALIGN && nu->bezt[u].f1 & SELECT)) != 0;
- if (!(is_selected && skip_selected)) {
+ if (!skip_selected || !(is_selected_h2 || (is_autoalign_h2 && is_selected_h1))) {
has_snap |= test_projected_vert_dist(&neasrest_precalc,
clip_planes_local,
clip_plane_len,
@@ -2159,21 +2517,21 @@ static short snapCurve(SnapObjectContext *sctx,
return SCE_SNAP_MODE_VERTEX;
}
- return 0;
+ return SCE_SNAP_MODE_NONE;
}
/* may extend later (for now just snaps to empty center) */
-static short snap_object_center(const SnapObjectContext *sctx,
- Object *ob_eval,
- const float obmat[4][4],
- /* read/write args */
- float *dist_px,
- /* return args */
- float r_loc[3],
- float *UNUSED(r_no),
- int *r_index)
+static eSnapMode snap_object_center(const SnapObjectContext *sctx,
+ Object *ob_eval,
+ const float obmat[4][4],
+ /* read/write args */
+ float *dist_px,
+ /* return args */
+ float r_loc[3],
+ float *UNUSED(r_no),
+ int *r_index)
{
- short retval = 0;
+ eSnapMode retval = SCE_SNAP_MODE_NONE;
if (ob_eval->transflag & OB_DUPLI) {
return retval;
@@ -2215,20 +2573,20 @@ static short snap_object_center(const SnapObjectContext *sctx,
return retval;
}
- return 0;
+ return SCE_SNAP_MODE_NONE;
}
-static short snapCamera(const SnapObjectContext *sctx,
- Object *object,
- const float obmat[4][4],
- /* read/write args */
- float *dist_px,
- /* return args */
- float r_loc[3],
- float *r_no,
- int *r_index)
+static eSnapMode snapCamera(const SnapObjectContext *sctx,
+ Object *object,
+ const float obmat[4][4],
+ /* read/write args */
+ float *dist_px,
+ /* return args */
+ float r_loc[3],
+ float *r_no,
+ int *r_index)
{
- short retval = 0;
+ eSnapMode retval = SCE_SNAP_MODE_NONE;
Scene *scene = sctx->scene;
@@ -2265,7 +2623,7 @@ static short snapCamera(const SnapObjectContext *sctx,
if ((tracking_object->flag & TRACKING_OBJECT_CAMERA) == 0) {
BKE_tracking_camera_get_reconstructed_interpolate(
- tracking, tracking_object, CFRA, reconstructed_camera_mat);
+ tracking, tracking_object, scene->r.cfra, reconstructed_camera_mat);
invert_m4_m4(reconstructed_camera_imat, reconstructed_camera_mat);
}
@@ -2309,28 +2667,28 @@ static short snapCamera(const SnapObjectContext *sctx,
return retval;
}
- return 0;
+ return SCE_SNAP_MODE_NONE;
}
-static short snapMesh(SnapObjectContext *sctx,
- const SnapObjectParams *params,
- Object *ob_eval,
- const Mesh *me_eval,
- const float obmat[4][4],
- bool use_hide,
- /* read/write args */
- float *dist_px,
- /* return args */
- float r_loc[3],
- float r_no[3],
- int *r_index)
+static eSnapMode snapMesh(SnapObjectContext *sctx,
+ const SnapObjectParams *params,
+ Object *ob_eval,
+ const Mesh *me_eval,
+ const float obmat[4][4],
+ bool use_hide,
+ /* read/write args */
+ float *dist_px,
+ /* return args */
+ float r_loc[3],
+ float r_no[3],
+ int *r_index)
{
- BLI_assert(sctx->runtime.snap_to_flag != SCE_SNAP_MODE_FACE);
+ BLI_assert(sctx->runtime.snap_to_flag != SCE_SNAP_MODE_FACE_RAYCAST);
if (me_eval->totvert == 0) {
- return 0;
+ return SCE_SNAP_MODE_NONE;
}
if (me_eval->totedge == 0 && !(sctx->runtime.snap_to_flag & SCE_SNAP_MODE_VERTEX)) {
- return 0;
+ return SCE_SNAP_MODE_NONE;
}
float lpmat[4][4];
@@ -2343,7 +2701,7 @@ static short snapMesh(SnapObjectContext *sctx,
if (bb &&
!snap_bound_box_check_dist(
bb->vec[0], bb->vec[6], lpmat, sctx->runtime.win_size, sctx->runtime.mval, dist_px_sq)) {
- return 0;
+ return SCE_SNAP_MODE_NONE;
}
SnapData_Mesh *sod = snap_object_data_mesh_get(sctx, ob_eval, me_eval, use_hide);
@@ -2384,7 +2742,7 @@ static short snapMesh(SnapObjectContext *sctx,
nearest.dist_sq = dist_px_sq;
int last_index = nearest.index;
- short elem = SCE_SNAP_MODE_VERTEX;
+ eSnapMode elem = SCE_SNAP_MODE_VERTEX;
float tobmat[4][4], clip_planes_local[MAX_CLIPPLANE_LEN][4];
transpose_m4_m4(tobmat, obmat);
@@ -2488,31 +2846,31 @@ static short snapMesh(SnapObjectContext *sctx,
return elem;
}
- return 0;
+ return SCE_SNAP_MODE_NONE;
}
-static short snapEditMesh(SnapObjectContext *sctx,
- const SnapObjectParams *params,
- Object *ob_eval,
- BMEditMesh *em,
- const float obmat[4][4],
- /* read/write args */
- float *dist_px,
- /* return args */
- float r_loc[3],
- float r_no[3],
- int *r_index)
+static eSnapMode snapEditMesh(SnapObjectContext *sctx,
+ const SnapObjectParams *params,
+ Object *ob_eval,
+ BMEditMesh *em,
+ const float obmat[4][4],
+ /* read/write args */
+ float *dist_px,
+ /* return args */
+ float r_loc[3],
+ float r_no[3],
+ int *r_index)
{
- BLI_assert(sctx->runtime.snap_to_flag != SCE_SNAP_MODE_FACE);
+ BLI_assert(sctx->runtime.snap_to_flag != SCE_SNAP_MODE_FACE_RAYCAST);
- if ((sctx->runtime.snap_to_flag & ~SCE_SNAP_MODE_FACE) == SCE_SNAP_MODE_VERTEX) {
+ if ((sctx->runtime.snap_to_flag & ~SCE_SNAP_MODE_FACE_RAYCAST) == SCE_SNAP_MODE_VERTEX) {
if (em->bm->totvert == 0) {
- return 0;
+ return SCE_SNAP_MODE_NONE;
}
}
else {
if (em->bm->totedge == 0) {
- return 0;
+ return SCE_SNAP_MODE_NONE;
}
}
@@ -2528,7 +2886,7 @@ static short snapEditMesh(SnapObjectContext *sctx,
/* was BKE_boundbox_ray_hit_check, see: cf6ca226fa58 */
if (!snap_bound_box_check_dist(
sod->min, sod->max, lpmat, sctx->runtime.win_size, sctx->runtime.mval, dist_px_sq)) {
- return 0;
+ return SCE_SNAP_MODE_NONE;
}
if (sctx->runtime.snap_to_flag & SCE_SNAP_MODE_VERTEX) {
@@ -2603,7 +2961,7 @@ static short snapEditMesh(SnapObjectContext *sctx,
nearest.index = -1;
nearest.dist_sq = dist_px_sq;
- short elem = SCE_SNAP_MODE_VERTEX;
+ eSnapMode elem = SCE_SNAP_MODE_VERTEX;
float tobmat[4][4], clip_planes_local[MAX_CLIPPLANE_LEN][4];
transpose_m4_m4(tobmat, obmat);
@@ -2669,7 +3027,7 @@ static short snapEditMesh(SnapObjectContext *sctx,
return elem;
}
- return 0;
+ return SCE_SNAP_MODE_NONE;
}
struct SnapObjUserData {
@@ -2681,7 +3039,7 @@ struct SnapObjUserData {
int *r_index;
Object **r_ob;
float (*r_obmat)[4];
- short ret;
+ eSnapMode ret;
};
/**
@@ -2695,7 +3053,7 @@ static void snap_obj_fn(SnapObjectContext *sctx,
void *data)
{
SnapObjUserData *dt = static_cast<SnapObjUserData *>(data);
- short retval = 0;
+ eSnapMode retval = SCE_SNAP_MODE_NONE;
switch (ob_eval->type) {
case OB_MESH: {
@@ -2742,11 +3100,8 @@ static void snap_obj_fn(SnapObjectContext *sctx,
dt->r_index);
break;
case OB_CURVES_LEGACY:
- retval = snapCurve(
- sctx, params, ob_eval, obmat, dt->dist_px, dt->r_loc, dt->r_no, dt->r_index);
- break; /* Use ATTR_FALLTHROUGH if we want to snap to the generated mesh. */
case OB_SURF:
- if (BKE_object_is_in_editmode(ob_eval)) {
+ if (ob_eval->type == OB_CURVES_LEGACY || BKE_object_is_in_editmode(ob_eval)) {
retval = snapCurve(
sctx, params, ob_eval, obmat, dt->dist_px, dt->r_loc, dt->r_no, dt->r_index);
if (params->edit_mode_type != SNAP_GEOM_FINAL) {
@@ -2811,22 +3166,22 @@ static void snap_obj_fn(SnapObjectContext *sctx,
* \param r_loc: Hit location.
* \param r_no: Hit normal (optional).
* \param r_index: Hit index or -1 when no valid index is found.
- * (currently only set to the polygon index when using `snap_to == SCE_SNAP_MODE_FACE`).
+ * (currently only set to the polygon index when using `snap_to == SCE_SNAP_MODE_FACE_RAYCAST`).
* \param r_ob: Hit object.
* \param r_obmat: Object matrix (may not be #Object.obmat with dupli-instances).
*/
-static short snapObjectsRay(SnapObjectContext *sctx,
- const SnapObjectParams *params,
- /* read/write args */
- /* Parameters below cannot be const, because they are assigned to a
- * non-const variable (readability-non-const-parameter). */
- float *dist_px /* NOLINT */,
- /* return args */
- float r_loc[3] /* NOLINT */,
- float r_no[3] /* NOLINT */,
- int *r_index /* NOLINT */,
- Object **r_ob,
- float r_obmat[4][4])
+static eSnapMode snapObjectsRay(SnapObjectContext *sctx,
+ const SnapObjectParams *params,
+ /* read/write args */
+ /* Parameters below cannot be const, because they are assigned to a
+ * non-const variable (readability-non-const-parameter). */
+ float *dist_px /* NOLINT */,
+ /* return args */
+ float r_loc[3] /* NOLINT */,
+ float r_no[3] /* NOLINT */,
+ int *r_index /* NOLINT */,
+ Object **r_ob,
+ float r_obmat[4][4])
{
SnapObjUserData data = {};
data.dist_px = dist_px;
@@ -2835,7 +3190,7 @@ static short snapObjectsRay(SnapObjectContext *sctx,
data.r_ob = r_ob;
data.r_index = r_index;
data.r_obmat = r_obmat;
- data.ret = 0;
+ data.ret = SCE_SNAP_MODE_NONE;
iter_snap_objects(sctx, params, snap_obj_fn, &data);
@@ -3008,31 +3363,30 @@ bool ED_transform_snap_object_project_ray(SnapObjectContext *sctx,
sctx, depsgraph, v3d, params, ray_origin, ray_direction, ray_depth, r_co, r_no);
}
-static short transform_snap_context_project_view3d_mixed_impl(SnapObjectContext *sctx,
- Depsgraph *depsgraph,
- const ARegion *region,
- const View3D *v3d,
- const ushort snap_to_flag,
- const SnapObjectParams *params,
- const float mval[2],
- const float prev_co[3],
- float *dist_px,
- float r_loc[3],
- float r_no[3],
- int *r_index,
- Object **r_ob,
- float r_obmat[4][4],
- float r_face_nor[3])
+static eSnapMode transform_snap_context_project_view3d_mixed_impl(SnapObjectContext *sctx,
+ Depsgraph *depsgraph,
+ const ARegion *region,
+ const View3D *v3d,
+ const eSnapMode snap_to_flag,
+ const SnapObjectParams *params,
+ const float init_co[3],
+ const float mval[2],
+ const float prev_co[3],
+ float *dist_px,
+ float r_loc[3],
+ float r_no[3],
+ int *r_index,
+ Object **r_ob,
+ float r_obmat[4][4],
+ float r_face_nor[3])
{
sctx->runtime.depsgraph = depsgraph;
sctx->runtime.region = region;
sctx->runtime.v3d = v3d;
- BLI_assert((snap_to_flag & (SCE_SNAP_MODE_VERTEX | SCE_SNAP_MODE_EDGE | SCE_SNAP_MODE_FACE |
- SCE_SNAP_MODE_EDGE_MIDPOINT | SCE_SNAP_MODE_EDGE_PERPENDICULAR)) !=
- 0);
+ BLI_assert((snap_to_flag & SCE_SNAP_MODE_GEOM) != 0);
- short retval = 0;
+ eSnapMode retval = SCE_SNAP_MODE_NONE;
bool has_hit = false;
Object *ob_eval = nullptr;
@@ -3047,11 +3401,36 @@ static short transform_snap_context_project_view3d_mixed_impl(SnapObjectContext
bool use_occlusion_test = params->use_occlusion_test && !XRAY_ENABLED(v3d);
- if (snap_to_flag & SCE_SNAP_MODE_FACE || use_occlusion_test) {
+ /* Note: if both face raycast and face nearest are enabled, first find result of nearest, then
+ * override with raycast. */
+ if ((snap_to_flag & SCE_SNAP_MODE_FACE_NEAREST) && !has_hit) {
+ has_hit = nearestWorldObjects(
+ sctx, params, init_co, prev_co, loc, no, &index, &ob_eval, obmat);
+
+ if (has_hit) {
+ retval = SCE_SNAP_MODE_FACE_NEAREST;
+
+ copy_v3_v3(r_loc, loc);
+ if (r_no) {
+ copy_v3_v3(r_no, no);
+ }
+ if (r_ob) {
+ *r_ob = ob_eval;
+ }
+ if (r_obmat) {
+ copy_m4_m4(r_obmat, obmat);
+ }
+ if (r_index) {
+ *r_index = index;
+ }
+ }
+ }
+
+ if (snap_to_flag & SCE_SNAP_MODE_FACE_RAYCAST || use_occlusion_test) {
float ray_start[3], ray_normal[3];
if (!ED_view3d_win_to_ray_clipped_ex(
depsgraph, region, v3d, mval, nullptr, ray_normal, ray_start, true)) {
- return 0;
+ return retval;
}
float dummy_ray_depth = BVH_RAYCAST_DIST_MAX;
@@ -3073,8 +3452,8 @@ static short transform_snap_context_project_view3d_mixed_impl(SnapObjectContext
copy_v3_v3(r_face_nor, no);
}
- if ((snap_to_flag & SCE_SNAP_MODE_FACE)) {
- retval = SCE_SNAP_MODE_FACE;
+ if ((snap_to_flag & SCE_SNAP_MODE_FACE_RAYCAST)) {
+ retval = SCE_SNAP_MODE_FACE_RAYCAST;
copy_v3_v3(r_loc, loc);
if (r_no) {
@@ -3095,7 +3474,7 @@ static short transform_snap_context_project_view3d_mixed_impl(SnapObjectContext
if (snap_to_flag & (SCE_SNAP_MODE_VERTEX | SCE_SNAP_MODE_EDGE | SCE_SNAP_MODE_EDGE_MIDPOINT |
SCE_SNAP_MODE_EDGE_PERPENDICULAR)) {
- short elem_test, elem = 0;
+ eSnapMode elem_test, elem = SCE_SNAP_MODE_NONE;
float dist_px_tmp = *dist_px;
copy_m4_m4(sctx->runtime.pmat, rv3d->persmat);
@@ -3105,9 +3484,11 @@ static short transform_snap_context_project_view3d_mixed_impl(SnapObjectContext
sctx->runtime.view_proj = rv3d->is_persp ? VIEW_PROJ_PERSP : VIEW_PROJ_ORTHO;
/* First snap to edge instead of middle or perpendicular. */
- sctx->runtime.snap_to_flag = snap_to_flag & (SCE_SNAP_MODE_VERTEX | SCE_SNAP_MODE_EDGE);
+ sctx->runtime.snap_to_flag = static_cast<eSnapMode>(
+ snap_to_flag & (SCE_SNAP_MODE_VERTEX | SCE_SNAP_MODE_EDGE));
if (snap_to_flag & (SCE_SNAP_MODE_EDGE_MIDPOINT | SCE_SNAP_MODE_EDGE_PERPENDICULAR)) {
- sctx->runtime.snap_to_flag |= SCE_SNAP_MODE_EDGE;
+ sctx->runtime.snap_to_flag = static_cast<eSnapMode>(sctx->runtime.snap_to_flag |
+ SCE_SNAP_MODE_EDGE);
}
planes_from_projmat(sctx->runtime.pmat,
@@ -3179,10 +3560,6 @@ static short transform_snap_context_project_view3d_mixed_impl(SnapObjectContext
if (r_index) {
*r_index = index;
}
- if (r_face_nor && !has_hit) {
- /* Fallback. */
- copy_v3_v3(r_face_nor, no);
- }
*dist_px = dist_px_tmp;
}
@@ -3191,21 +3568,22 @@ static short transform_snap_context_project_view3d_mixed_impl(SnapObjectContext
return retval;
}
-short ED_transform_snap_object_project_view3d_ex(SnapObjectContext *sctx,
- Depsgraph *depsgraph,
- const ARegion *region,
- const View3D *v3d,
- const ushort snap_to,
- const SnapObjectParams *params,
- const float mval[2],
- const float prev_co[3],
- float *dist_px,
- float r_loc[3],
- float r_no[3],
- int *r_index,
- Object **r_ob,
- float r_obmat[4][4],
- float r_face_nor[3])
+eSnapMode ED_transform_snap_object_project_view3d_ex(SnapObjectContext *sctx,
+ Depsgraph *depsgraph,
+ const ARegion *region,
+ const View3D *v3d,
+ const eSnapMode snap_to,
+ const SnapObjectParams *params,
+ const float init_co[3],
+ const float mval[2],
+ const float prev_co[3],
+ float *dist_px,
+ float r_loc[3],
+ float r_no[3],
+ int *r_index,
+ Object **r_ob,
+ float r_obmat[4][4],
+ float r_face_nor[3])
{
return transform_snap_context_project_view3d_mixed_impl(sctx,
depsgraph,
@@ -3213,6 +3591,7 @@ short ED_transform_snap_object_project_view3d_ex(SnapObjectContext *sctx,
v3d,
snap_to,
params,
+ init_co,
mval,
prev_co,
dist_px,
@@ -3224,17 +3603,18 @@ short ED_transform_snap_object_project_view3d_ex(SnapObjectContext *sctx,
r_face_nor);
}
-short ED_transform_snap_object_project_view3d(SnapObjectContext *sctx,
- Depsgraph *depsgraph,
- const ARegion *region,
- const View3D *v3d,
- const ushort snap_to,
- const SnapObjectParams *params,
- const float mval[2],
- const float prev_co[3],
- float *dist_px,
- float r_loc[3],
- float r_no[3])
+eSnapMode ED_transform_snap_object_project_view3d(SnapObjectContext *sctx,
+ Depsgraph *depsgraph,
+ const ARegion *region,
+ const View3D *v3d,
+ const eSnapMode snap_to,
+ const SnapObjectParams *params,
+ const float init_co[3],
+ const float mval[2],
+ const float prev_co[3],
+ float *dist_px,
+ float r_loc[3],
+ float r_no[3])
{
return ED_transform_snap_object_project_view3d_ex(sctx,
depsgraph,
@@ -3242,6 +3622,7 @@ short ED_transform_snap_object_project_view3d(SnapObjectContext *sctx,
v3d,
snap_to,
params,
+ init_co,
mval,
prev_co,
dist_px,