Changeset View
Changeset View
Standalone View
Standalone View
source/blender/editors/transform/transform_snap_object.cc
| Show First 20 Lines • Show All 1,019 Lines • ▼ Show 20 Lines | static void raycast_obj_fn(SnapObjectContext *sctx, | ||||
| void *data) | void *data) | ||||
| { | { | ||||
| RaycastObjUserData *dt = static_cast<RaycastObjUserData *>(data); | RaycastObjUserData *dt = static_cast<RaycastObjUserData *>(data); | ||||
| const uint ob_index = dt->ob_index++; | const uint ob_index = dt->ob_index++; | ||||
| bool use_occlusion_test = dt->use_occlusion_test; | bool use_occlusion_test = dt->use_occlusion_test; | ||||
| /* read/write args */ | /* read/write args */ | ||||
| float *ray_depth = dt->ray_depth; | float *ray_depth = dt->ray_depth; | ||||
| const bool use_retopo_mode = (params->snap_target_select & SCE_SNAP_TARGET_RETOPOLOGY_MODE); | |||||
| const bool is_object_edited = BKE_object_is_in_editmode(ob_eval); | |||||
| if (use_retopo_mode && is_object_edited) { | |||||
| return; | |||||
| } | |||||
| bool retval = false; | bool retval = false; | ||||
| if (use_occlusion_test) { | if (use_occlusion_test) { | ||||
| if (ELEM(ob_eval->dt, OB_BOUNDBOX, OB_WIRE)) { | if (ELEM(ob_eval->dt, OB_BOUNDBOX, OB_WIRE)) { | ||||
| /* Do not hit objects that are in wire or bounding box | /* Do not hit objects that are in wire or bounding box | ||||
| * display mode. */ | * display mode. */ | ||||
| return; | return; | ||||
| } | } | ||||
| } | } | ||||
| ▲ Show 20 Lines • Show All 232 Lines • ▼ Show 20 Lines | static bool nearest_world_tree(SnapObjectContext *UNUSED(sctx), | ||||
| float dist_sq; | float dist_sq; | ||||
| if (params->keep_on_same_target) { | if (params->keep_on_same_target) { | ||||
| nearest_world_tree_co( | nearest_world_tree_co( | ||||
| tree, nearest_cb, treedata, init_co_local, nullptr, nullptr, nullptr, &dist_sq); | tree, nearest_cb, treedata, init_co_local, nullptr, nullptr, nullptr, &dist_sq); | ||||
| } | } | ||||
| else { | else { | ||||
| /* NOTE: when `params->face_nearest_steps == 1`, the return variables of function below contain | /* 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 | * the answer. We could return immediately after updating `r_loc`, `r_no`, `r_index`, but that | ||||
| * also complicate the code. Foregoing slight optimization for code clarity. */ | * would also complicate the code. Foregoing slight optimization for code clarity. */ | ||||
| nearest_world_tree_co( | nearest_world_tree_co( | ||||
| tree, nearest_cb, treedata, curr_co_local, nullptr, nullptr, nullptr, &dist_sq); | tree, nearest_cb, treedata, curr_co_local, nullptr, nullptr, nullptr, &dist_sq); | ||||
| } | } | ||||
| if (*r_dist_sq <= dist_sq) { | if (*r_dist_sq <= dist_sq) { | ||||
| return false; | return false; | ||||
| } | } | ||||
| *r_dist_sq = dist_sq; | *r_dist_sq = dist_sq; | ||||
| ▲ Show 20 Lines • Show All 93 Lines • ▼ Show 20 Lines | static void nearest_world_object_fn(SnapObjectContext *sctx, | ||||
| const struct SnapObjectParams *params, | const struct SnapObjectParams *params, | ||||
| Object *ob_eval, | Object *ob_eval, | ||||
| const float obmat[4][4], | const float obmat[4][4], | ||||
| bool is_object_active, | bool is_object_active, | ||||
| void *data) | void *data) | ||||
| { | { | ||||
| struct NearestWorldObjUserData *dt = static_cast<NearestWorldObjUserData *>(data); | struct NearestWorldObjUserData *dt = static_cast<NearestWorldObjUserData *>(data); | ||||
| const bool use_retopo_mode = (params->snap_target_select & SCE_SNAP_TARGET_RETOPOLOGY_MODE); | |||||
| const bool is_object_edited = BKE_object_is_in_editmode(ob_eval); | |||||
| if (use_retopo_mode && is_object_edited) { | |||||
| return; | |||||
| } | |||||
| bool retval = false; | bool retval = false; | ||||
| switch (ob_eval->type) { | switch (ob_eval->type) { | ||||
| case OB_MESH: { | case OB_MESH: { | ||||
| const eSnapEditType edit_mode_type = params->edit_mode_type; | const eSnapEditType edit_mode_type = params->edit_mode_type; | ||||
| bool use_hide = false; | bool use_hide = false; | ||||
| const Mesh *me_eval = mesh_for_snap(ob_eval, edit_mode_type, &use_hide); | const Mesh *me_eval = mesh_for_snap(ob_eval, edit_mode_type, &use_hide); | ||||
| if (me_eval) { | if (me_eval) { | ||||
| retval = nearest_world_mesh(sctx, | retval = nearest_world_mesh(sctx, | ||||
| ▲ Show 20 Lines • Show All 1,655 Lines • ▼ Show 20 Lines | static void snap_obj_fn(SnapObjectContext *sctx, | ||||
| Object *ob_eval, | Object *ob_eval, | ||||
| const float obmat[4][4], | const float obmat[4][4], | ||||
| bool is_object_active, | bool is_object_active, | ||||
| void *data) | void *data) | ||||
| { | { | ||||
| SnapObjUserData *dt = static_cast<SnapObjUserData *>(data); | SnapObjUserData *dt = static_cast<SnapObjUserData *>(data); | ||||
| eSnapMode retval = SCE_SNAP_MODE_NONE; | eSnapMode retval = SCE_SNAP_MODE_NONE; | ||||
| const bool use_retopo_mode = (params->snap_target_select & SCE_SNAP_TARGET_RETOPOLOGY_MODE); | |||||
| const bool is_object_edited = BKE_object_is_in_editmode(ob_eval); | |||||
| if (use_retopo_mode && !is_object_edited) { | |||||
| return; | |||||
| } | |||||
| switch (ob_eval->type) { | switch (ob_eval->type) { | ||||
| case OB_MESH: { | case OB_MESH: { | ||||
| const eSnapEditType edit_mode_type = params->edit_mode_type; | const eSnapEditType edit_mode_type = params->edit_mode_type; | ||||
| bool use_hide; | bool use_hide; | ||||
| const Mesh *me_eval = mesh_for_snap(ob_eval, edit_mode_type, &use_hide); | const Mesh *me_eval = mesh_for_snap(ob_eval, edit_mode_type, &use_hide); | ||||
| if (me_eval == nullptr) { | if (me_eval == nullptr) { | ||||
| BMEditMesh *em = BKE_editmesh_from_object(ob_eval); | BMEditMesh *em = BKE_editmesh_from_object(ob_eval); | ||||
| if (UNLIKELY(!em)) { /* See #mesh_for_snap doc-string. */ | if (UNLIKELY(!em)) { /* See #mesh_for_snap doc-string. */ | ||||
| ▲ Show 20 Lines • Show All 313 Lines • ▼ Show 20 Lines | static eSnapMode transform_snap_context_project_view3d_mixed_impl(SnapObjectContext *sctx, | ||||
| Object **r_ob, | Object **r_ob, | ||||
| float r_obmat[4][4], | float r_obmat[4][4], | ||||
| float r_face_nor[3]) | float r_face_nor[3]) | ||||
| { | { | ||||
| sctx->runtime.depsgraph = depsgraph; | sctx->runtime.depsgraph = depsgraph; | ||||
| sctx->runtime.region = region; | sctx->runtime.region = region; | ||||
| sctx->runtime.v3d = v3d; | sctx->runtime.v3d = v3d; | ||||
| BLI_assert((snap_to_flag & SCE_SNAP_MODE_GEOM) != 0); | if ((snap_to_flag & SCE_SNAP_MODE_GEOM) == 0) { | ||||
| return SCE_SNAP_MODE_NONE; | |||||
| } | |||||
| eSnapMode retval = SCE_SNAP_MODE_NONE; | eSnapMode retval = SCE_SNAP_MODE_NONE; | ||||
| bool has_hit = false; | bool has_hit = false; | ||||
| Object *ob_eval = nullptr; | Object *ob_eval = nullptr; | ||||
| Object *ob_ray = nullptr; | |||||
| float loc[3]; | float loc[3]; | ||||
| /* Not all snapping callbacks set the normal, | /* Not all snapping callbacks set the normal, | ||||
| * initialize this since any hit copies both the `loc` and `no`. */ | * initialize this since any hit copies both the `loc` and `no`. */ | ||||
| float no[3] = {0.0f, 0.0f, 0.0f}; | float no[3] = {0.0f, 0.0f, 0.0f}; | ||||
| float obmat[4][4]; | float obmat[4][4]; | ||||
| float obmat_ray[4][4]; | |||||
| int index = -1; | int index = -1; | ||||
| const RegionView3D *rv3d = static_cast<RegionView3D *>(region->regiondata); | const RegionView3D *rv3d = static_cast<RegionView3D *>(region->regiondata); | ||||
| bool use_occlusion_test = params->use_occlusion_test && !XRAY_ENABLED(v3d); | const bool use_retopo_mode = (params->snap_target_select & SCE_SNAP_TARGET_RETOPOLOGY_MODE); | ||||
| const bool use_occlusion_test = params->use_occlusion_test && !XRAY_ENABLED(v3d); | |||||
| /* 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) { | if (snap_to_flag & SCE_SNAP_MODE_FACE_RAYCAST || use_occlusion_test) { | ||||
| float ray_start[3], ray_normal[3]; | float ray_start[3], ray_normal[3]; | ||||
| if (!ED_view3d_win_to_ray_clipped_ex( | if (!ED_view3d_win_to_ray_clipped_ex( | ||||
| depsgraph, region, v3d, mval, nullptr, ray_normal, ray_start, true)) { | depsgraph, region, v3d, mval, nullptr, ray_normal, ray_start, true)) { | ||||
| return retval; | return retval; | ||||
| } | } | ||||
| float dummy_ray_depth = BVH_RAYCAST_DIST_MAX; | float dummy_ray_depth = BVH_RAYCAST_DIST_MAX; | ||||
| has_hit = raycastObjects(sctx, | has_hit = raycastObjects(sctx, | ||||
| params, | params, | ||||
| ray_start, | ray_start, | ||||
| ray_normal, | ray_normal, | ||||
| &dummy_ray_depth, | &dummy_ray_depth, | ||||
| loc, | loc, | ||||
| no, | no, | ||||
| &index, | &index, | ||||
| &ob_eval, | &ob_ray, | ||||
| obmat, | obmat_ray, | ||||
| nullptr); | nullptr); | ||||
| if (has_hit) { | if (has_hit) { | ||||
| if (r_face_nor) { | if (r_face_nor) { | ||||
| copy_v3_v3(r_face_nor, no); | copy_v3_v3(r_face_nor, no); | ||||
| } | } | ||||
| if ((snap_to_flag & SCE_SNAP_MODE_FACE_RAYCAST)) { | if ((snap_to_flag & SCE_SNAP_MODE_FACE_RAYCAST)) { | ||||
| /* Record snap results only if face raycast snapping mode is enabled. */ | |||||
| retval = SCE_SNAP_MODE_FACE_RAYCAST; | retval = SCE_SNAP_MODE_FACE_RAYCAST; | ||||
| copy_v3_v3(r_loc, loc); | copy_v3_v3(r_loc, loc); | ||||
| if (r_no) { | if (r_no) { | ||||
| copy_v3_v3(r_no, no); | copy_v3_v3(r_no, no); | ||||
| } | } | ||||
| if (r_ob) { | if (r_ob) { | ||||
| *r_ob = ob_eval; | *r_ob = ob_ray; | ||||
| } | } | ||||
| if (r_obmat) { | if (r_obmat) { | ||||
| copy_m4_m4(r_obmat, obmat); | copy_m4_m4(r_obmat, obmat_ray); | ||||
| } | } | ||||
| if (r_index) { | if (r_index) { | ||||
| *r_index = index; | *r_index = index; | ||||
| } | } | ||||
| } | } | ||||
| if (use_occlusion_test && !use_retopo_mode) { | |||||
| ob_eval = ob_ray; | |||||
| copy_m4_m4(obmat, obmat_ray); | |||||
| } | |||||
| } | } | ||||
| } | } | ||||
| if (snap_to_flag & (SCE_SNAP_MODE_VERTEX | SCE_SNAP_MODE_EDGE | SCE_SNAP_MODE_EDGE_MIDPOINT | | if (snap_to_flag & (SCE_SNAP_MODE_VERTEX | SCE_SNAP_MODE_EDGE | SCE_SNAP_MODE_EDGE_MIDPOINT | | ||||
| SCE_SNAP_MODE_EDGE_PERPENDICULAR)) { | SCE_SNAP_MODE_EDGE_PERPENDICULAR)) { | ||||
| eSnapMode elem_test, elem = SCE_SNAP_MODE_NONE; | eSnapMode elem_test, elem = SCE_SNAP_MODE_NONE; | ||||
| float dist_px_tmp = *dist_px; | float dist_px_tmp = *dist_px; | ||||
| Show All 18 Lines | planes_from_projmat(sctx->runtime.pmat, | ||||
| nullptr, | nullptr, | ||||
| sctx->runtime.clip_plane[0], | sctx->runtime.clip_plane[0], | ||||
| sctx->runtime.clip_plane[1]); | sctx->runtime.clip_plane[1]); | ||||
| sctx->runtime.clip_plane_len = 2; | sctx->runtime.clip_plane_len = 2; | ||||
| sctx->runtime.has_occlusion_plane = false; | sctx->runtime.has_occlusion_plane = false; | ||||
| /* By convention we only snap to the original elements of a curve. */ | /* By convention we only snap to the original elements of a curve. */ | ||||
| if (has_hit && ob_eval->type != OB_CURVES_LEGACY) { | if (has_hit && ob_ray->type != OB_CURVES_LEGACY) { | ||||
| /* Compute the new clip_pane but do not add it yet. */ | /* Compute the new clip_pane but do not add it yet. */ | ||||
| float new_clipplane[4]; | float new_clipplane[4]; | ||||
| BLI_ASSERT_UNIT_V3(no); | BLI_ASSERT_UNIT_V3(no); | ||||
| plane_from_point_normal_v3(new_clipplane, loc, no); | plane_from_point_normal_v3(new_clipplane, loc, no); | ||||
| if (dot_v3v3(sctx->runtime.clip_plane[0], new_clipplane) > 0.0f) { | if (dot_v3v3(sctx->runtime.clip_plane[0], new_clipplane) > 0.0f) { | ||||
| /* The plane is facing the wrong direction. */ | /* The plane is facing the wrong direction. */ | ||||
| negate_v4(new_clipplane); | negate_v4(new_clipplane); | ||||
| } | } | ||||
| /* Small offset to simulate a kind of volume for edges and vertices. */ | /* Small offset to simulate a kind of volume for edges and vertices. */ | ||||
| new_clipplane[3] += 0.01f; | new_clipplane[3] += 0.01f; | ||||
| /* Try to snap only to the polygon. */ | /* Try to snap only to the polygon. */ | ||||
| elem_test = snap_mesh_polygon(sctx, params, ob_eval, obmat, &dist_px_tmp, loc, no, &index); | elem_test = snap_mesh_polygon( | ||||
| if (elem_test) { | sctx, params, ob_ray, obmat_ray, &dist_px_tmp, loc, no, &index); | ||||
| if (elem_test && !use_retopo_mode) { | |||||
| elem = elem_test; | elem = elem_test; | ||||
| } | } | ||||
| /* Add the new clip plane to the beginning of the list. */ | /* Add the new clip plane to the beginning of the list. */ | ||||
| for (int i = sctx->runtime.clip_plane_len; i != 0; i--) { | for (int i = sctx->runtime.clip_plane_len; i != 0; i--) { | ||||
| copy_v4_v4(sctx->runtime.clip_plane[i], sctx->runtime.clip_plane[i - 1]); | copy_v4_v4(sctx->runtime.clip_plane[i], sctx->runtime.clip_plane[i - 1]); | ||||
| } | } | ||||
| copy_v4_v4(sctx->runtime.clip_plane[0], new_clipplane); | copy_v4_v4(sctx->runtime.clip_plane[0], new_clipplane); | ||||
| Show All 30 Lines | if (elem & snap_to_flag) { | ||||
| if (r_index) { | if (r_index) { | ||||
| *r_index = index; | *r_index = index; | ||||
| } | } | ||||
| *dist_px = dist_px_tmp; | *dist_px = dist_px_tmp; | ||||
| } | } | ||||
| } | } | ||||
| /* Note: Perform face nearest snapping only if no other method snapped source geometry. */ | |||||
| 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; | |||||
| } | |||||
| } | |||||
| } | |||||
| return retval; | return retval; | ||||
| } | } | ||||
| eSnapMode ED_transform_snap_object_project_view3d_ex(SnapObjectContext *sctx, | eSnapMode ED_transform_snap_object_project_view3d_ex(SnapObjectContext *sctx, | ||||
| Depsgraph *depsgraph, | Depsgraph *depsgraph, | ||||
| const ARegion *region, | const ARegion *region, | ||||
| const View3D *v3d, | const View3D *v3d, | ||||
| const eSnapMode snap_to, | const eSnapMode snap_to, | ||||
| ▲ Show 20 Lines • Show All 83 Lines • Show Last 20 Lines | |||||