Cleanup: Split 'transform_snap_object.cc' into smaller files
This commit splits the `transform_snap_object.cc` file into 4 files: - `transform_snap_object.hh` - `transform_snap_object.cc` - `transform_snap_object_editmesh.cc` - `transform_snap_object_mesh.cc` The `transform_snap_object.hh` header, in addition to sharing common types, allows functions defined in each of these files to be shared between them. This makes the code easier to read and simplifies maintenance. Pull Request: https://projects.blender.org/blender/blender/pulls/108949
This commit is contained in:
committed by
Germano Cavalcante
parent
f98e488311
commit
9265fa1eed
@@ -98,6 +98,8 @@ set(SRC
|
||||
transform_snap.cc
|
||||
transform_snap_animation.c
|
||||
transform_snap_object.cc
|
||||
transform_snap_object_editmesh.cc
|
||||
transform_snap_object_mesh.cc
|
||||
transform_snap_sequencer.c
|
||||
|
||||
transform.h
|
||||
@@ -109,6 +111,7 @@ set(SRC
|
||||
transform_mode.h
|
||||
transform_orientations.h
|
||||
transform_snap.h
|
||||
transform_snap_object.hh
|
||||
)
|
||||
|
||||
set(LIB
|
||||
|
||||
@@ -6,27 +6,13 @@
|
||||
* \ingroup edtransform
|
||||
*/
|
||||
|
||||
#include <cstdlib>
|
||||
|
||||
#include "MEM_guardedalloc.h"
|
||||
|
||||
#include "BLI_bitmap.h"
|
||||
#include "BLI_kdopbvh.h"
|
||||
#include "BLI_listbase.h"
|
||||
#include "BLI_map.hh"
|
||||
#include "BLI_math.h"
|
||||
#include "BLI_math_matrix_types.hh"
|
||||
#include "BLI_math_vector.hh"
|
||||
#include "BLI_utildefines.h"
|
||||
|
||||
#include "DNA_armature_types.h"
|
||||
#include "DNA_curve_types.h"
|
||||
#include "DNA_mesh_types.h"
|
||||
#include "DNA_meshdata_types.h"
|
||||
#include "DNA_object_types.h"
|
||||
#include "DNA_scene_types.h"
|
||||
#include "DNA_screen_types.h"
|
||||
#include "DNA_view3d_types.h"
|
||||
|
||||
#include "BKE_armature.h"
|
||||
#include "BKE_bvhutils.h"
|
||||
@@ -34,126 +20,17 @@
|
||||
#include "BKE_duplilist.h"
|
||||
#include "BKE_editmesh.h"
|
||||
#include "BKE_geometry_set.h"
|
||||
#include "BKE_global.h"
|
||||
#include "BKE_layer.h"
|
||||
#include "BKE_mesh.hh"
|
||||
#include "BKE_mesh_runtime.h"
|
||||
#include "BKE_mesh_wrapper.h"
|
||||
#include "BKE_object.h"
|
||||
#include "BKE_tracking.h"
|
||||
|
||||
#include "DEG_depsgraph_query.h"
|
||||
|
||||
#include "ED_armature.h"
|
||||
#include "ED_transform_snap_object_context.h"
|
||||
#include "ED_view3d.h"
|
||||
|
||||
using blender::float3;
|
||||
using blender::float4x4;
|
||||
using blender::Map;
|
||||
using blender::Span;
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Internal Data Types
|
||||
* \{ */
|
||||
|
||||
#define MAX_CLIPPLANE_LEN 3
|
||||
|
||||
enum eViewProj {
|
||||
VIEW_PROJ_NONE = -1,
|
||||
VIEW_PROJ_ORTHO = 0,
|
||||
VIEW_PROJ_PERSP = -1,
|
||||
};
|
||||
|
||||
/** #SnapObjectContext.editmesh_caches */
|
||||
struct SnapData_EditMesh {
|
||||
/* Verts, Edges. */
|
||||
BVHTree *bvhtree[2];
|
||||
bool cached[2];
|
||||
|
||||
/* BVH tree from #BMEditMesh.looptris. */
|
||||
BVHTreeFromEditMesh treedata_editmesh;
|
||||
|
||||
blender::bke::MeshRuntime *mesh_runtime;
|
||||
float min[3], max[3];
|
||||
|
||||
void clear()
|
||||
{
|
||||
for (int i = 0; i < ARRAY_SIZE(this->bvhtree); i++) {
|
||||
if (!this->cached[i]) {
|
||||
BLI_bvhtree_free(this->bvhtree[i]);
|
||||
}
|
||||
this->bvhtree[i] = nullptr;
|
||||
}
|
||||
free_bvhtree_from_editmesh(&this->treedata_editmesh);
|
||||
}
|
||||
|
||||
~SnapData_EditMesh()
|
||||
{
|
||||
this->clear();
|
||||
}
|
||||
|
||||
#ifdef WITH_CXX_GUARDEDALLOC
|
||||
MEM_CXX_CLASS_ALLOC_FUNCS("SnapData_EditMesh")
|
||||
#endif
|
||||
};
|
||||
|
||||
struct SnapObjectContext {
|
||||
Scene *scene;
|
||||
|
||||
int flag;
|
||||
|
||||
Map<const BMEditMesh *, std::unique_ptr<SnapData_EditMesh>> editmesh_caches;
|
||||
|
||||
/* Filter data, returns true to check this value */
|
||||
struct {
|
||||
struct {
|
||||
bool (*test_vert_fn)(BMVert *, void *user_data);
|
||||
bool (*test_edge_fn)(BMEdge *, void *user_data);
|
||||
bool (*test_face_fn)(BMFace *, void *user_data);
|
||||
void *user_data;
|
||||
} edit_mesh;
|
||||
} callbacks;
|
||||
|
||||
struct {
|
||||
Depsgraph *depsgraph;
|
||||
const ARegion *region;
|
||||
const View3D *v3d;
|
||||
|
||||
float mval[2];
|
||||
float pmat[4][4]; /* perspective matrix */
|
||||
float win_size[2]; /* win x and y */
|
||||
enum eViewProj view_proj;
|
||||
float clip_plane[MAX_CLIPPLANE_LEN][4];
|
||||
short clip_plane_len;
|
||||
eSnapMode snap_to_flag;
|
||||
bool has_occlusion_plane; /* Ignore plane of occlusion in curves. */
|
||||
} runtime;
|
||||
|
||||
/* Output. */
|
||||
struct {
|
||||
/* Location of snapped point on target surface. */
|
||||
float loc[3];
|
||||
/* Normal of snapped point on target surface. */
|
||||
float no[3];
|
||||
/* Index of snapped element on target object (-1 when no valid index is found). */
|
||||
int index;
|
||||
/* Matrix of target object (may not be #Object.object_to_world with dupli-instances). */
|
||||
float obmat[4][4];
|
||||
/* List of #SnapObjectHitDepth (caller must free). */
|
||||
ListBase *hit_list;
|
||||
/* Snapped object. */
|
||||
Object *ob;
|
||||
/* Snapped data. */
|
||||
ID *data;
|
||||
|
||||
float dist_sq;
|
||||
|
||||
bool is_edit;
|
||||
} ret;
|
||||
};
|
||||
|
||||
/** \} */
|
||||
#include "transform_snap_object.hh"
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Utilities
|
||||
@@ -212,184 +89,6 @@ static ID *data_for_snap(Object *ob_eval, eSnapEditType edit_mode_type, bool *r_
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Snap Object Data
|
||||
* \{ */
|
||||
|
||||
/**
|
||||
* Calculate the minimum and maximum coordinates of the box that encompasses this mesh.
|
||||
*/
|
||||
static void snap_editmesh_minmax(SnapObjectContext *sctx,
|
||||
BMesh *bm,
|
||||
float r_min[3],
|
||||
float r_max[3])
|
||||
{
|
||||
INIT_MINMAX(r_min, r_max);
|
||||
BMIter iter;
|
||||
BMVert *v;
|
||||
|
||||
BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
|
||||
if (sctx->callbacks.edit_mesh.test_vert_fn &&
|
||||
!sctx->callbacks.edit_mesh.test_vert_fn(v, sctx->callbacks.edit_mesh.user_data))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
minmax_v3v3_v3(r_min, r_max, v->co);
|
||||
}
|
||||
}
|
||||
|
||||
static void snap_object_data_mesh_get(const Mesh *me_eval,
|
||||
bool use_hide,
|
||||
BVHTreeFromMesh *r_treedata)
|
||||
{
|
||||
const Span<float3> vert_positions = me_eval->vert_positions();
|
||||
const blender::OffsetIndices polys = me_eval->polys();
|
||||
const Span<int> corner_verts = me_eval->corner_verts();
|
||||
|
||||
/* The BVHTree from looptris is always required. */
|
||||
BKE_bvhtree_from_mesh_get(
|
||||
r_treedata, me_eval, use_hide ? BVHTREE_FROM_LOOPTRI_NO_HIDDEN : BVHTREE_FROM_LOOPTRI, 4);
|
||||
|
||||
BLI_assert(reinterpret_cast<const float3 *>(r_treedata->vert_positions) ==
|
||||
vert_positions.data());
|
||||
BLI_assert(r_treedata->corner_verts == corner_verts.data());
|
||||
BLI_assert(!polys.data() || r_treedata->looptri);
|
||||
BLI_assert(!r_treedata->tree || r_treedata->looptri);
|
||||
|
||||
UNUSED_VARS_NDEBUG(vert_positions, polys, corner_verts);
|
||||
}
|
||||
|
||||
/* Searches for the #Mesh_Runtime associated with the object that is most likely to be updated due
|
||||
* to changes in the `edit_mesh`. */
|
||||
static blender::bke::MeshRuntime *snap_object_data_editmesh_runtime_get(Object *ob_eval)
|
||||
{
|
||||
Mesh *editmesh_eval_final = BKE_object_get_editmesh_eval_final(ob_eval);
|
||||
if (editmesh_eval_final) {
|
||||
return editmesh_eval_final->runtime;
|
||||
}
|
||||
|
||||
Mesh *editmesh_eval_cage = BKE_object_get_editmesh_eval_cage(ob_eval);
|
||||
if (editmesh_eval_cage) {
|
||||
return editmesh_eval_cage->runtime;
|
||||
}
|
||||
|
||||
return ((Mesh *)ob_eval->data)->runtime;
|
||||
}
|
||||
|
||||
static SnapData_EditMesh *snap_object_data_editmesh_get(SnapObjectContext *sctx,
|
||||
Object *ob_eval,
|
||||
BMEditMesh *em)
|
||||
{
|
||||
SnapData_EditMesh *sod;
|
||||
bool init = false;
|
||||
|
||||
if (std::unique_ptr<SnapData_EditMesh> *sod_p = sctx->editmesh_caches.lookup_ptr(em)) {
|
||||
sod = sod_p->get();
|
||||
bool is_dirty = false;
|
||||
/* Check if the geometry has changed. */
|
||||
if (sod->treedata_editmesh.em != em) {
|
||||
is_dirty = true;
|
||||
}
|
||||
else if (sod->mesh_runtime) {
|
||||
if (sod->mesh_runtime != snap_object_data_editmesh_runtime_get(ob_eval)) {
|
||||
if (G.moving) {
|
||||
/* WORKAROUND: avoid updating while transforming. */
|
||||
BLI_assert(!sod->treedata_editmesh.cached && !sod->cached[0] && !sod->cached[1]);
|
||||
sod->mesh_runtime = snap_object_data_editmesh_runtime_get(ob_eval);
|
||||
}
|
||||
else {
|
||||
is_dirty = true;
|
||||
}
|
||||
}
|
||||
else if (sod->treedata_editmesh.tree && sod->treedata_editmesh.cached &&
|
||||
!bvhcache_has_tree(sod->mesh_runtime->bvh_cache, sod->treedata_editmesh.tree))
|
||||
{
|
||||
/* The tree is owned by the EditMesh and may have been freed since we last used! */
|
||||
is_dirty = true;
|
||||
}
|
||||
else if (sod->bvhtree[0] && sod->cached[0] &&
|
||||
!bvhcache_has_tree(sod->mesh_runtime->bvh_cache, sod->bvhtree[0]))
|
||||
{
|
||||
/* The tree is owned by the EditMesh and may have been freed since we last used! */
|
||||
is_dirty = true;
|
||||
}
|
||||
else if (sod->bvhtree[1] && sod->cached[1] &&
|
||||
!bvhcache_has_tree(sod->mesh_runtime->bvh_cache, sod->bvhtree[1]))
|
||||
{
|
||||
/* The tree is owned by the EditMesh and may have been freed since we last used! */
|
||||
is_dirty = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (is_dirty) {
|
||||
sod->clear();
|
||||
init = true;
|
||||
}
|
||||
}
|
||||
else {
|
||||
std::unique_ptr<SnapData_EditMesh> sod_ptr = std::make_unique<SnapData_EditMesh>();
|
||||
sod = sod_ptr.get();
|
||||
sctx->editmesh_caches.add_new(em, std::move(sod_ptr));
|
||||
init = true;
|
||||
}
|
||||
|
||||
if (init) {
|
||||
sod->treedata_editmesh.em = em;
|
||||
sod->mesh_runtime = snap_object_data_editmesh_runtime_get(ob_eval);
|
||||
snap_editmesh_minmax(sctx, em->bm, sod->min, sod->max);
|
||||
}
|
||||
|
||||
return sod;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
blender::BitVector<> elem_mask(em->tottri);
|
||||
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);
|
||||
}
|
||||
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,
|
||||
/* WORKAROUND: avoid updating while transforming. */
|
||||
G.moving ? nullptr : &sod->mesh_runtime->bvh_cache,
|
||||
&sod->mesh_runtime->eval_mutex);
|
||||
}
|
||||
}
|
||||
if (treedata->tree == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return treedata;
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Iterator
|
||||
* \{ */
|
||||
@@ -528,26 +227,6 @@ static eSnapMode iter_snap_objects(SnapObjectContext *sctx,
|
||||
/* Store all ray-hits
|
||||
* Support for storing all depths, not just the first (ray-cast 'all'). */
|
||||
|
||||
struct RayCastAll_Data {
|
||||
void *bvhdata;
|
||||
|
||||
/* internal vars for adding depths */
|
||||
BVHTree_RayCastCallback raycast_callback;
|
||||
|
||||
const float (*obmat)[4];
|
||||
const float (*timat)[3];
|
||||
|
||||
float len_diff;
|
||||
float local_scale;
|
||||
|
||||
Object *ob_eval;
|
||||
uint ob_uuid;
|
||||
|
||||
/* output data */
|
||||
ListBase *hit_list;
|
||||
bool retval;
|
||||
};
|
||||
|
||||
static SnapObjectHitDepth *hit_depth_create(const float depth,
|
||||
const float co[3],
|
||||
const float no[3],
|
||||
@@ -586,7 +265,7 @@ static int hit_depth_cmp(const void *arg1, const void *arg2)
|
||||
return val;
|
||||
}
|
||||
|
||||
static void raycast_all_cb(void *userdata, int index, const BVHTreeRay *ray, BVHTreeRayHit *hit)
|
||||
void raycast_all_cb(void *userdata, int index, const BVHTreeRay *ray, BVHTreeRayHit *hit)
|
||||
{
|
||||
RayCastAll_Data *data = static_cast<RayCastAll_Data *>(userdata);
|
||||
data->raycast_callback(data->bvhdata, index, ray, hit);
|
||||
@@ -610,350 +289,13 @@ static void raycast_all_cb(void *userdata, int index, const BVHTreeRay *ray, BVH
|
||||
}
|
||||
}
|
||||
|
||||
static bool raycast_tri_backface_culling_test(
|
||||
bool raycast_tri_backface_culling_test(
|
||||
const float dir[3], const float v0[3], const float v1[3], const float v2[3], float no[3])
|
||||
{
|
||||
cross_tri_v3(no, v0, v1, v2);
|
||||
return dot_v3v3(no, dir) < 0.0f;
|
||||
}
|
||||
|
||||
/* Callback to ray-cast with back-face culling (#Mesh). */
|
||||
static void mesh_looptri_raycast_backface_culling_cb(void *userdata,
|
||||
int index,
|
||||
const BVHTreeRay *ray,
|
||||
BVHTreeRayHit *hit)
|
||||
{
|
||||
const BVHTreeFromMesh *data = (BVHTreeFromMesh *)userdata;
|
||||
const float(*vert_positions)[3] = data->vert_positions;
|
||||
const MLoopTri *lt = &data->looptri[index];
|
||||
const float *vtri_co[3] = {
|
||||
vert_positions[data->corner_verts[lt->tri[0]]],
|
||||
vert_positions[data->corner_verts[lt->tri[1]]],
|
||||
vert_positions[data->corner_verts[lt->tri[2]]],
|
||||
};
|
||||
float dist = bvhtree_ray_tri_intersection(ray, hit->dist, UNPACK3(vtri_co));
|
||||
|
||||
if (dist >= 0 && dist < hit->dist) {
|
||||
float no[3];
|
||||
if (raycast_tri_backface_culling_test(ray->direction, UNPACK3(vtri_co), no)) {
|
||||
hit->index = index;
|
||||
hit->dist = dist;
|
||||
madd_v3_v3v3fl(hit->co, ray->origin, ray->direction, dist);
|
||||
normalize_v3_v3(hit->no, no);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Callback to ray-cast with back-face culling (#EditMesh). */
|
||||
static void editmesh_looptri_raycast_backface_culling_cb(void *userdata,
|
||||
int index,
|
||||
const BVHTreeRay *ray,
|
||||
BVHTreeRayHit *hit)
|
||||
{
|
||||
const BVHTreeFromEditMesh *data = (BVHTreeFromEditMesh *)userdata;
|
||||
BMEditMesh *em = data->em;
|
||||
const BMLoop **ltri = (const BMLoop **)em->looptris[index];
|
||||
|
||||
const float *t0, *t1, *t2;
|
||||
t0 = ltri[0]->v->co;
|
||||
t1 = ltri[1]->v->co;
|
||||
t2 = ltri[2]->v->co;
|
||||
|
||||
{
|
||||
float dist = bvhtree_ray_tri_intersection(ray, hit->dist, t0, t1, t2);
|
||||
|
||||
if (dist >= 0 && dist < hit->dist) {
|
||||
float no[3];
|
||||
if (raycast_tri_backface_culling_test(ray->direction, t0, t1, t2, no)) {
|
||||
hit->index = index;
|
||||
hit->dist = dist;
|
||||
madd_v3_v3v3fl(hit->co, ray->origin, ray->direction, dist);
|
||||
normalize_v3_v3(hit->no, no);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static bool raycastMesh(const SnapObjectParams *params,
|
||||
const float ray_start[3],
|
||||
const float ray_dir[3],
|
||||
Object *ob_eval,
|
||||
const Mesh *me_eval,
|
||||
const float obmat[4][4],
|
||||
const uint ob_index,
|
||||
bool use_hide,
|
||||
/* read/write args */
|
||||
float *ray_depth,
|
||||
/* return args */
|
||||
float r_loc[3],
|
||||
float r_no[3],
|
||||
int *r_index,
|
||||
ListBase *r_hit_list)
|
||||
{
|
||||
bool retval = false;
|
||||
|
||||
if (me_eval->totpoly == 0) {
|
||||
return retval;
|
||||
}
|
||||
|
||||
float imat[4][4];
|
||||
float ray_start_local[3], ray_normal_local[3];
|
||||
float local_scale, local_depth, len_diff = 0.0f;
|
||||
|
||||
invert_m4_m4(imat, obmat);
|
||||
|
||||
copy_v3_v3(ray_start_local, ray_start);
|
||||
copy_v3_v3(ray_normal_local, ray_dir);
|
||||
|
||||
mul_m4_v3(imat, ray_start_local);
|
||||
mul_mat3_m4_v3(imat, ray_normal_local);
|
||||
|
||||
/* local scale in normal direction */
|
||||
local_scale = normalize_v3(ray_normal_local);
|
||||
local_depth = *ray_depth;
|
||||
if (local_depth != BVH_RAYCAST_DIST_MAX) {
|
||||
local_depth *= local_scale;
|
||||
}
|
||||
|
||||
/* Test BoundBox */
|
||||
if (ob_eval->data == me_eval) {
|
||||
const BoundBox *bb = BKE_object_boundbox_get(ob_eval);
|
||||
if (bb) {
|
||||
/* was BKE_boundbox_ray_hit_check, see: cf6ca226fa58 */
|
||||
if (!isect_ray_aabb_v3_simple(
|
||||
ray_start_local, ray_normal_local, bb->vec[0], bb->vec[6], &len_diff, nullptr))
|
||||
{
|
||||
return retval;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* We pass a temp ray_start, set from object's boundbox, to avoid precision issues with
|
||||
* very far away ray_start values (as returned in case of ortho view3d), see #50486, #38358.
|
||||
*/
|
||||
if (len_diff > 400.0f) {
|
||||
/* Make temporary start point a bit away from bounding-box hit point. */
|
||||
len_diff -= local_scale;
|
||||
madd_v3_v3fl(ray_start_local, ray_normal_local, len_diff);
|
||||
local_depth -= len_diff;
|
||||
}
|
||||
else {
|
||||
len_diff = 0.0f;
|
||||
}
|
||||
|
||||
BVHTreeFromMesh treedata;
|
||||
snap_object_data_mesh_get(me_eval, use_hide, &treedata);
|
||||
|
||||
const blender::Span<int> looptri_polys = me_eval->looptri_polys();
|
||||
|
||||
if (treedata.tree == nullptr) {
|
||||
return retval;
|
||||
}
|
||||
|
||||
float timat[3][3]; /* transpose inverse matrix for normals */
|
||||
transpose_m3_m4(timat, imat);
|
||||
|
||||
BLI_assert(treedata.raycast_callback != nullptr);
|
||||
if (r_hit_list) {
|
||||
RayCastAll_Data data;
|
||||
|
||||
data.bvhdata = &treedata;
|
||||
data.raycast_callback = treedata.raycast_callback;
|
||||
data.obmat = obmat;
|
||||
data.timat = timat;
|
||||
data.len_diff = len_diff;
|
||||
data.local_scale = local_scale;
|
||||
data.ob_eval = ob_eval;
|
||||
data.ob_uuid = ob_index;
|
||||
data.hit_list = r_hit_list;
|
||||
data.retval = retval;
|
||||
|
||||
BLI_bvhtree_ray_cast_all(
|
||||
treedata.tree, ray_start_local, ray_normal_local, 0.0f, *ray_depth, raycast_all_cb, &data);
|
||||
|
||||
retval = data.retval;
|
||||
}
|
||||
else {
|
||||
BVHTreeRayHit hit{};
|
||||
hit.index = -1;
|
||||
hit.dist = local_depth;
|
||||
|
||||
if (BLI_bvhtree_ray_cast(treedata.tree,
|
||||
ray_start_local,
|
||||
ray_normal_local,
|
||||
0.0f,
|
||||
&hit,
|
||||
params->use_backface_culling ?
|
||||
mesh_looptri_raycast_backface_culling_cb :
|
||||
treedata.raycast_callback,
|
||||
&treedata) != -1)
|
||||
{
|
||||
hit.dist += len_diff;
|
||||
hit.dist /= local_scale;
|
||||
if (hit.dist <= *ray_depth) {
|
||||
*ray_depth = hit.dist;
|
||||
copy_v3_v3(r_loc, hit.co);
|
||||
|
||||
/* Back to world-space. */
|
||||
mul_m4_v3(obmat, r_loc);
|
||||
|
||||
if (r_no) {
|
||||
copy_v3_v3(r_no, hit.no);
|
||||
mul_m3_v3(timat, r_no);
|
||||
normalize_v3(r_no);
|
||||
}
|
||||
|
||||
retval = true;
|
||||
|
||||
if (r_index) {
|
||||
*r_index = looptri_polys[hit.index];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
static bool raycastEditMesh(SnapObjectContext *sctx,
|
||||
const SnapObjectParams *params,
|
||||
const float ray_start[3],
|
||||
const float ray_dir[3],
|
||||
Object *ob_eval,
|
||||
BMEditMesh *em,
|
||||
const float obmat[4][4],
|
||||
const uint ob_index,
|
||||
/* read/write args */
|
||||
float *ray_depth,
|
||||
/* return args */
|
||||
float r_loc[3],
|
||||
float r_no[3],
|
||||
int *r_index,
|
||||
ListBase *r_hit_list)
|
||||
{
|
||||
bool retval = false;
|
||||
if (em->bm->totface == 0) {
|
||||
return retval;
|
||||
}
|
||||
|
||||
float imat[4][4];
|
||||
float ray_start_local[3], ray_normal_local[3];
|
||||
float local_scale, local_depth, len_diff = 0.0f;
|
||||
|
||||
invert_m4_m4(imat, obmat);
|
||||
|
||||
copy_v3_v3(ray_start_local, ray_start);
|
||||
copy_v3_v3(ray_normal_local, ray_dir);
|
||||
|
||||
mul_m4_v3(imat, ray_start_local);
|
||||
mul_mat3_m4_v3(imat, ray_normal_local);
|
||||
|
||||
/* local scale in normal direction */
|
||||
local_scale = normalize_v3(ray_normal_local);
|
||||
local_depth = *ray_depth;
|
||||
if (local_depth != BVH_RAYCAST_DIST_MAX) {
|
||||
local_depth *= local_scale;
|
||||
}
|
||||
|
||||
SnapData_EditMesh *sod = snap_object_data_editmesh_get(sctx, ob_eval, em);
|
||||
|
||||
/* Test BoundBox */
|
||||
|
||||
/* was BKE_boundbox_ray_hit_check, see: cf6ca226fa58 */
|
||||
if (!isect_ray_aabb_v3_simple(
|
||||
ray_start_local, ray_normal_local, sod->min, sod->max, &len_diff, nullptr))
|
||||
{
|
||||
return retval;
|
||||
}
|
||||
|
||||
/* We pass a temp ray_start, set from object's boundbox, to avoid precision issues with
|
||||
* very far away ray_start values (as returned in case of ortho view3d), see #50486, #38358.
|
||||
*/
|
||||
if (len_diff > 400.0f) {
|
||||
len_diff -= local_scale; /* make temp start point a bit away from bbox hit point. */
|
||||
madd_v3_v3fl(ray_start_local, ray_normal_local, len_diff);
|
||||
local_depth -= len_diff;
|
||||
}
|
||||
else {
|
||||
len_diff = 0.0f;
|
||||
}
|
||||
|
||||
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 */
|
||||
transpose_m3_m4(timat, imat);
|
||||
|
||||
if (r_hit_list) {
|
||||
RayCastAll_Data data;
|
||||
|
||||
data.bvhdata = treedata;
|
||||
data.raycast_callback = treedata->raycast_callback;
|
||||
data.obmat = obmat;
|
||||
data.timat = timat;
|
||||
data.len_diff = len_diff;
|
||||
data.local_scale = local_scale;
|
||||
data.ob_eval = ob_eval;
|
||||
data.ob_uuid = ob_index;
|
||||
data.hit_list = r_hit_list;
|
||||
data.retval = retval;
|
||||
|
||||
BLI_bvhtree_ray_cast_all(treedata->tree,
|
||||
ray_start_local,
|
||||
ray_normal_local,
|
||||
0.0f,
|
||||
*ray_depth,
|
||||
raycast_all_cb,
|
||||
&data);
|
||||
|
||||
retval = data.retval;
|
||||
}
|
||||
else {
|
||||
BVHTreeRayHit hit{};
|
||||
hit.index = -1;
|
||||
hit.dist = local_depth;
|
||||
|
||||
if (BLI_bvhtree_ray_cast(treedata->tree,
|
||||
ray_start_local,
|
||||
ray_normal_local,
|
||||
0.0f,
|
||||
&hit,
|
||||
params->use_backface_culling ?
|
||||
editmesh_looptri_raycast_backface_culling_cb :
|
||||
treedata->raycast_callback,
|
||||
treedata) != -1)
|
||||
{
|
||||
hit.dist += len_diff;
|
||||
hit.dist /= local_scale;
|
||||
if (hit.dist <= *ray_depth) {
|
||||
*ray_depth = hit.dist;
|
||||
copy_v3_v3(r_loc, hit.co);
|
||||
|
||||
/* Back to world-space. */
|
||||
mul_m4_v3(obmat, r_loc);
|
||||
|
||||
if (r_no) {
|
||||
copy_v3_v3(r_no, hit.no);
|
||||
mul_m3_v3(timat, r_no);
|
||||
normalize_v3(r_no);
|
||||
}
|
||||
|
||||
retval = true;
|
||||
|
||||
if (r_index) {
|
||||
em = sod->treedata_editmesh.em;
|
||||
|
||||
*r_index = BM_elem_index_get(em->looptris[hit.index][0]->f);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
struct RaycastObjUserData {
|
||||
const float *ray_start;
|
||||
const float *ray_dir;
|
||||
@@ -1133,18 +475,18 @@ static void nearest_world_tree_co(BVHTree *tree,
|
||||
}
|
||||
}
|
||||
|
||||
static bool nearest_world_tree(SnapObjectContext * /*sctx*/,
|
||||
const 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)
|
||||
bool nearest_world_tree(SnapObjectContext * /*sctx*/,
|
||||
const 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. */
|
||||
@@ -1206,68 +548,6 @@ static bool nearest_world_tree(SnapObjectContext * /*sctx*/,
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool nearest_world_mesh(SnapObjectContext *sctx,
|
||||
const SnapObjectParams *params,
|
||||
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_get(me_eval, use_hide, &treedata);
|
||||
if (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 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) {
|
||||
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 eSnapMode nearest_world_object_fn(SnapObjectContext *sctx,
|
||||
const SnapObjectParams *params,
|
||||
Object *ob_eval,
|
||||
@@ -1369,12 +649,12 @@ static bool nearestWorldObjects(SnapObjectContext *sctx,
|
||||
* \{ */
|
||||
|
||||
/* Test BoundBox */
|
||||
static bool snap_bound_box_check_dist(const float min[3],
|
||||
const float max[3],
|
||||
const float lpmat[4][4],
|
||||
const float win_size[2],
|
||||
const float mval[2],
|
||||
float dist_px_sq)
|
||||
bool snap_bound_box_check_dist(const float min[3],
|
||||
const float max[3],
|
||||
const float lpmat[4][4],
|
||||
const float win_size[2],
|
||||
const float mval[2],
|
||||
float dist_px_sq)
|
||||
{
|
||||
/* In vertex and edges you need to get the pixel distance from ray to BoundBox,
|
||||
* see: #46099, #46816 */
|
||||
@@ -1397,118 +677,6 @@ static bool snap_bound_box_check_dist(const float min[3],
|
||||
/** \name Callbacks
|
||||
* \{ */
|
||||
|
||||
struct Nearest2dUserData;
|
||||
|
||||
using Nearest2DGetVertCoCallback = void (*)(const int index,
|
||||
const Nearest2dUserData *data,
|
||||
const float **r_co);
|
||||
using Nearest2DGetEdgeVertsCallback = void (*)(const int index,
|
||||
const Nearest2dUserData *data,
|
||||
int r_v_index[2]);
|
||||
using Nearest2DGetTriVertsCallback = void (*)(const int index,
|
||||
const Nearest2dUserData *data,
|
||||
int r_v_index[3]);
|
||||
/* Equal the previous one */
|
||||
using Nearest2DGetTriEdgesCallback = void (*)(const int index,
|
||||
const Nearest2dUserData *data,
|
||||
int r_e_index[3]);
|
||||
using Nearest2DCopyVertNoCallback = void (*)(const int index,
|
||||
const Nearest2dUserData *data,
|
||||
float r_no[3]);
|
||||
|
||||
struct Nearest2dUserData {
|
||||
Nearest2DGetVertCoCallback get_vert_co;
|
||||
Nearest2DGetEdgeVertsCallback get_edge_verts_index;
|
||||
Nearest2DGetTriVertsCallback get_tri_verts_index;
|
||||
Nearest2DGetTriEdgesCallback get_tri_edges_index;
|
||||
Nearest2DCopyVertNoCallback copy_vert_no;
|
||||
|
||||
union {
|
||||
struct {
|
||||
BMesh *bm;
|
||||
};
|
||||
struct {
|
||||
const blender::float3 *vert_positions;
|
||||
const blender::float3 *vert_normals;
|
||||
const blender::int2 *edges; /* only used for #BVHTreeFromMeshEdges */
|
||||
const int *corner_verts;
|
||||
const int *corner_edges;
|
||||
const MLoopTri *looptris;
|
||||
};
|
||||
};
|
||||
|
||||
bool is_persp;
|
||||
bool use_backface_culling;
|
||||
};
|
||||
|
||||
static void cb_mvert_co_get(const int index, const Nearest2dUserData *data, const float **r_co)
|
||||
{
|
||||
*r_co = data->vert_positions[index];
|
||||
}
|
||||
|
||||
static void cb_bvert_co_get(const int index, const Nearest2dUserData *data, const float **r_co)
|
||||
{
|
||||
BMVert *eve = BM_vert_at_index(data->bm, index);
|
||||
*r_co = eve->co;
|
||||
}
|
||||
|
||||
static void cb_mvert_no_copy(const int index, const Nearest2dUserData *data, float r_no[3])
|
||||
{
|
||||
copy_v3_v3(r_no, data->vert_normals[index]);
|
||||
}
|
||||
|
||||
static void cb_bvert_no_copy(const int index, const Nearest2dUserData *data, float r_no[3])
|
||||
{
|
||||
BMVert *eve = BM_vert_at_index(data->bm, index);
|
||||
|
||||
copy_v3_v3(r_no, eve->no);
|
||||
}
|
||||
|
||||
static void cb_medge_verts_get(const int index, const Nearest2dUserData *data, int r_v_index[2])
|
||||
{
|
||||
const blender::int2 &edge = data->edges[index];
|
||||
|
||||
r_v_index[0] = edge[0];
|
||||
r_v_index[1] = edge[1];
|
||||
}
|
||||
|
||||
static void cb_bedge_verts_get(const int index, const Nearest2dUserData *data, int r_v_index[2])
|
||||
{
|
||||
BMEdge *eed = BM_edge_at_index(data->bm, index);
|
||||
|
||||
r_v_index[0] = BM_elem_index_get(eed->v1);
|
||||
r_v_index[1] = BM_elem_index_get(eed->v2);
|
||||
}
|
||||
|
||||
static void cb_mlooptri_edges_get(const int index, const Nearest2dUserData *data, int r_v_index[3])
|
||||
{
|
||||
const blender::int2 *edges = data->edges;
|
||||
const int *corner_verts = data->corner_verts;
|
||||
const int *corner_edges = data->corner_edges;
|
||||
const MLoopTri *lt = &data->looptris[index];
|
||||
for (int j = 2, j_next = 0; j_next < 3; j = j_next++) {
|
||||
const blender::int2 &edge = edges[corner_edges[lt->tri[j]]];
|
||||
const int tri_edge[2] = {corner_verts[lt->tri[j]], corner_verts[lt->tri[j_next]]};
|
||||
if (ELEM(edge[0], tri_edge[0], tri_edge[1]) && ELEM(edge[1], tri_edge[0], tri_edge[1])) {
|
||||
// printf("real edge found\n");
|
||||
r_v_index[j] = corner_edges[lt->tri[j]];
|
||||
}
|
||||
else {
|
||||
r_v_index[j] = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void cb_mlooptri_verts_get(const int index, const Nearest2dUserData *data, int r_v_index[3])
|
||||
{
|
||||
const int *corner_verts = data->corner_verts;
|
||||
const MLoopTri *looptri = &data->looptris[index];
|
||||
|
||||
r_v_index[0] = corner_verts[looptri->tri[0]];
|
||||
r_v_index[1] = corner_verts[looptri->tri[1]];
|
||||
r_v_index[2] = corner_verts[looptri->tri[2]];
|
||||
}
|
||||
|
||||
static bool test_projected_vert_dist(const DistProjectedAABBPrecalc *precalc,
|
||||
const float (*clip_plane)[4],
|
||||
const int clip_plane_len,
|
||||
@@ -1569,12 +737,12 @@ static bool test_projected_edge_dist(const DistProjectedAABBPrecalc *precalc,
|
||||
precalc, clip_plane, clip_plane_len, is_persp, near_co, dist_px_sq, r_co);
|
||||
}
|
||||
|
||||
static void cb_snap_vert(void *userdata,
|
||||
int index,
|
||||
const DistProjectedAABBPrecalc *precalc,
|
||||
const float (*clip_plane)[4],
|
||||
const int clip_plane_len,
|
||||
BVHTreeNearest *nearest)
|
||||
void cb_snap_vert(void *userdata,
|
||||
int index,
|
||||
const DistProjectedAABBPrecalc *precalc,
|
||||
const float (*clip_plane)[4],
|
||||
const int clip_plane_len,
|
||||
BVHTreeNearest *nearest)
|
||||
{
|
||||
Nearest2dUserData *data = static_cast<Nearest2dUserData *>(userdata);
|
||||
|
||||
@@ -1589,12 +757,12 @@ static void cb_snap_vert(void *userdata,
|
||||
}
|
||||
}
|
||||
|
||||
static void cb_snap_edge(void *userdata,
|
||||
int index,
|
||||
const DistProjectedAABBPrecalc *precalc,
|
||||
const float (*clip_plane)[4],
|
||||
const int clip_plane_len,
|
||||
BVHTreeNearest *nearest)
|
||||
void cb_snap_edge(void *userdata,
|
||||
int index,
|
||||
const DistProjectedAABBPrecalc *precalc,
|
||||
const float (*clip_plane)[4],
|
||||
const int clip_plane_len,
|
||||
BVHTreeNearest *nearest)
|
||||
{
|
||||
Nearest2dUserData *data = static_cast<Nearest2dUserData *>(userdata);
|
||||
|
||||
@@ -1619,261 +787,50 @@ static void cb_snap_edge(void *userdata,
|
||||
}
|
||||
}
|
||||
|
||||
static void cb_snap_edge_verts(void *userdata,
|
||||
int index,
|
||||
const DistProjectedAABBPrecalc *precalc,
|
||||
const float (*clip_plane)[4],
|
||||
const int clip_plane_len,
|
||||
BVHTreeNearest *nearest)
|
||||
{
|
||||
Nearest2dUserData *data = static_cast<Nearest2dUserData *>(userdata);
|
||||
|
||||
int vindex[2];
|
||||
data->get_edge_verts_index(index, data, vindex);
|
||||
|
||||
for (int i = 2; i--;) {
|
||||
if (vindex[i] == nearest->index) {
|
||||
continue;
|
||||
}
|
||||
cb_snap_vert(userdata, vindex[i], precalc, clip_plane, clip_plane_len, nearest);
|
||||
}
|
||||
}
|
||||
|
||||
static void cb_snap_tri_edges(void *userdata,
|
||||
int index,
|
||||
const DistProjectedAABBPrecalc *precalc,
|
||||
const float (*clip_plane)[4],
|
||||
const int clip_plane_len,
|
||||
BVHTreeNearest *nearest)
|
||||
{
|
||||
Nearest2dUserData *data = static_cast<Nearest2dUserData *>(userdata);
|
||||
|
||||
if (data->use_backface_culling) {
|
||||
int vindex[3];
|
||||
data->get_tri_verts_index(index, data, vindex);
|
||||
|
||||
const float *t0, *t1, *t2;
|
||||
data->get_vert_co(vindex[0], data, &t0);
|
||||
data->get_vert_co(vindex[1], data, &t1);
|
||||
data->get_vert_co(vindex[2], data, &t2);
|
||||
float dummy[3];
|
||||
if (raycast_tri_backface_culling_test(precalc->ray_direction, t0, t1, t2, dummy)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
int eindex[3];
|
||||
data->get_tri_edges_index(index, data, eindex);
|
||||
for (int i = 3; i--;) {
|
||||
if (eindex[i] != -1) {
|
||||
if (eindex[i] == nearest->index) {
|
||||
continue;
|
||||
}
|
||||
cb_snap_edge(userdata, eindex[i], precalc, clip_plane, clip_plane_len, nearest);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void cb_snap_tri_verts(void *userdata,
|
||||
int index,
|
||||
const DistProjectedAABBPrecalc *precalc,
|
||||
const float (*clip_plane)[4],
|
||||
const int clip_plane_len,
|
||||
BVHTreeNearest *nearest)
|
||||
{
|
||||
Nearest2dUserData *data = static_cast<Nearest2dUserData *>(userdata);
|
||||
|
||||
int vindex[3];
|
||||
data->get_tri_verts_index(index, data, vindex);
|
||||
|
||||
if (data->use_backface_culling) {
|
||||
const float *t0, *t1, *t2;
|
||||
data->get_vert_co(vindex[0], data, &t0);
|
||||
data->get_vert_co(vindex[1], data, &t1);
|
||||
data->get_vert_co(vindex[2], data, &t2);
|
||||
float dummy[3];
|
||||
if (raycast_tri_backface_culling_test(precalc->ray_direction, t0, t1, t2, dummy)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 3; i--;) {
|
||||
if (vindex[i] == nearest->index) {
|
||||
continue;
|
||||
}
|
||||
cb_snap_vert(userdata, vindex[i], precalc, clip_plane, clip_plane_len, nearest);
|
||||
}
|
||||
}
|
||||
|
||||
static void nearest2d_data_init_mesh(const Mesh *mesh,
|
||||
bool is_persp,
|
||||
bool use_backface_culling,
|
||||
Nearest2dUserData *r_nearest2d)
|
||||
{
|
||||
r_nearest2d->get_vert_co = cb_mvert_co_get;
|
||||
r_nearest2d->get_edge_verts_index = cb_medge_verts_get;
|
||||
r_nearest2d->copy_vert_no = cb_mvert_no_copy;
|
||||
r_nearest2d->get_tri_verts_index = cb_mlooptri_verts_get;
|
||||
r_nearest2d->get_tri_edges_index = cb_mlooptri_edges_get;
|
||||
|
||||
r_nearest2d->vert_positions = mesh->vert_positions().data();
|
||||
r_nearest2d->vert_normals = mesh->vert_normals().data();
|
||||
r_nearest2d->edges = mesh->edges().data();
|
||||
r_nearest2d->corner_verts = mesh->corner_verts().data();
|
||||
r_nearest2d->corner_edges = mesh->corner_edges().data();
|
||||
r_nearest2d->looptris = mesh->looptris().data();
|
||||
|
||||
r_nearest2d->is_persp = is_persp;
|
||||
r_nearest2d->use_backface_culling = use_backface_culling;
|
||||
}
|
||||
|
||||
static void nearest2d_data_init_editmesh(SnapData_EditMesh *sod,
|
||||
bool is_persp,
|
||||
bool use_backface_culling,
|
||||
Nearest2dUserData *r_nearest2d)
|
||||
{
|
||||
r_nearest2d->get_vert_co = cb_bvert_co_get;
|
||||
r_nearest2d->get_edge_verts_index = cb_bedge_verts_get;
|
||||
r_nearest2d->copy_vert_no = cb_bvert_no_copy;
|
||||
r_nearest2d->get_tri_verts_index = nullptr;
|
||||
r_nearest2d->get_tri_edges_index = nullptr;
|
||||
|
||||
r_nearest2d->bm = sod->treedata_editmesh.em->bm;
|
||||
|
||||
r_nearest2d->is_persp = is_persp;
|
||||
r_nearest2d->use_backface_culling = use_backface_culling;
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Internal Object Snapping API
|
||||
* \{ */
|
||||
|
||||
static eSnapMode snap_mesh_polygon(SnapObjectContext *sctx,
|
||||
const SnapObjectParams *params,
|
||||
/* read/write args */
|
||||
float *dist_px)
|
||||
static eSnapMode snap_polygon(SnapObjectContext *sctx,
|
||||
const SnapObjectParams *params,
|
||||
/* read/write args */
|
||||
float *dist_px)
|
||||
{
|
||||
eSnapMode elem = SCE_SNAP_MODE_NONE;
|
||||
|
||||
float lpmat[4][4];
|
||||
mul_m4_m4m4(lpmat, sctx->runtime.pmat, sctx->ret.obmat);
|
||||
|
||||
DistProjectedAABBPrecalc neasrest_precalc;
|
||||
dist_squared_to_projected_aabb_precalc(
|
||||
&neasrest_precalc, lpmat, sctx->runtime.win_size, sctx->runtime.mval);
|
||||
|
||||
float tobmat[4][4], clip_planes_local[MAX_CLIPPLANE_LEN][4];
|
||||
transpose_m4_m4(tobmat, sctx->ret.obmat);
|
||||
for (int i = sctx->runtime.clip_plane_len; i--;) {
|
||||
mul_v4_m4v4(clip_planes_local[i], tobmat, sctx->runtime.clip_plane[i]);
|
||||
}
|
||||
|
||||
BVHTreeNearest nearest{};
|
||||
nearest.index = -1;
|
||||
nearest.dist_sq = square_f(*dist_px);
|
||||
|
||||
Nearest2dUserData nearest2d;
|
||||
const Mesh *mesh = sctx->ret.data && GS(sctx->ret.data->name) == ID_ME ?
|
||||
(const Mesh *)sctx->ret.data :
|
||||
nullptr;
|
||||
if (mesh) {
|
||||
nearest2d_data_init_mesh(mesh,
|
||||
sctx->runtime.view_proj == VIEW_PROJ_PERSP,
|
||||
params->use_backface_culling,
|
||||
&nearest2d);
|
||||
|
||||
const blender::IndexRange poly = mesh->polys()[sctx->ret.index];
|
||||
|
||||
if (sctx->runtime.snap_to_flag & SCE_SNAP_MODE_EDGE) {
|
||||
elem = SCE_SNAP_MODE_EDGE;
|
||||
BLI_assert(nearest2d.edges != nullptr);
|
||||
const int *poly_edges = &nearest2d.corner_edges[poly.start()];
|
||||
for (int i = poly.size(); i--;) {
|
||||
cb_snap_edge(&nearest2d,
|
||||
poly_edges[i],
|
||||
&neasrest_precalc,
|
||||
clip_planes_local,
|
||||
sctx->runtime.clip_plane_len,
|
||||
&nearest);
|
||||
}
|
||||
}
|
||||
else {
|
||||
elem = SCE_SNAP_MODE_VERTEX;
|
||||
const int *poly_verts = &nearest2d.corner_verts[poly.start()];
|
||||
for (int i = poly.size(); i--;) {
|
||||
cb_snap_vert(&nearest2d,
|
||||
poly_verts[i],
|
||||
&neasrest_precalc,
|
||||
clip_planes_local,
|
||||
sctx->runtime.clip_plane_len,
|
||||
&nearest);
|
||||
}
|
||||
}
|
||||
return snap_polygon_mesh(sctx,
|
||||
params,
|
||||
mesh,
|
||||
sctx->ret.obmat,
|
||||
clip_planes_local,
|
||||
dist_px,
|
||||
sctx->ret.loc,
|
||||
sctx->ret.no,
|
||||
&sctx->ret.index);
|
||||
}
|
||||
else if (sctx->ret.is_edit) {
|
||||
/* The object's #BMEditMesh was used to snap instead. */
|
||||
std::unique_ptr<SnapData_EditMesh> &sod_editmesh = sctx->editmesh_caches.lookup(
|
||||
BKE_editmesh_from_object(sctx->ret.ob));
|
||||
BLI_assert(sod_editmesh.get() != nullptr);
|
||||
|
||||
nearest2d_data_init_editmesh(sod_editmesh.get(),
|
||||
sctx->runtime.view_proj == VIEW_PROJ_PERSP,
|
||||
params->use_backface_culling,
|
||||
&nearest2d);
|
||||
|
||||
BMEditMesh *em = sod_editmesh->treedata_editmesh.em;
|
||||
|
||||
BM_mesh_elem_table_ensure(em->bm, BM_FACE);
|
||||
BMFace *f = BM_face_at_index(em->bm, sctx->ret.index);
|
||||
BMLoop *l_iter, *l_first;
|
||||
l_iter = l_first = BM_FACE_FIRST_LOOP(f);
|
||||
if (sctx->runtime.snap_to_flag & SCE_SNAP_MODE_EDGE) {
|
||||
elem = SCE_SNAP_MODE_EDGE;
|
||||
BM_mesh_elem_index_ensure(em->bm, BM_VERT | BM_EDGE);
|
||||
BM_mesh_elem_table_ensure(em->bm, BM_VERT | BM_EDGE);
|
||||
do {
|
||||
cb_snap_edge(&nearest2d,
|
||||
BM_elem_index_get(l_iter->e),
|
||||
&neasrest_precalc,
|
||||
clip_planes_local,
|
||||
sctx->runtime.clip_plane_len,
|
||||
&nearest);
|
||||
} while ((l_iter = l_iter->next) != l_first);
|
||||
}
|
||||
else {
|
||||
elem = SCE_SNAP_MODE_VERTEX;
|
||||
BM_mesh_elem_index_ensure(em->bm, BM_VERT);
|
||||
BM_mesh_elem_table_ensure(em->bm, BM_VERT);
|
||||
do {
|
||||
cb_snap_vert(&nearest2d,
|
||||
BM_elem_index_get(l_iter->v),
|
||||
&neasrest_precalc,
|
||||
clip_planes_local,
|
||||
sctx->runtime.clip_plane_len,
|
||||
&nearest);
|
||||
} while ((l_iter = l_iter->next) != l_first);
|
||||
}
|
||||
}
|
||||
|
||||
if (nearest.index != -1) {
|
||||
*dist_px = sqrtf(nearest.dist_sq);
|
||||
|
||||
copy_v3_v3(sctx->ret.loc, nearest.co);
|
||||
mul_m4_v3(sctx->ret.obmat, sctx->ret.loc);
|
||||
|
||||
{
|
||||
float imat[4][4];
|
||||
invert_m4_m4(imat, sctx->ret.obmat);
|
||||
|
||||
copy_v3_v3(sctx->ret.no, nearest.no);
|
||||
mul_transposed_mat3_m4_v3(imat, sctx->ret.no);
|
||||
normalize_v3(sctx->ret.no);
|
||||
}
|
||||
|
||||
sctx->ret.index = nearest.index;
|
||||
return elem;
|
||||
return snap_polygon_editmesh(sctx,
|
||||
params,
|
||||
BKE_editmesh_from_object(sctx->ret.ob),
|
||||
sctx->ret.obmat,
|
||||
clip_planes_local,
|
||||
dist_px,
|
||||
sctx->ret.loc,
|
||||
sctx->ret.no,
|
||||
&sctx->ret.index);
|
||||
}
|
||||
|
||||
return SCE_SNAP_MODE_NONE;
|
||||
@@ -1905,9 +862,7 @@ static eSnapMode snap_mesh_edge_verts_mixed(SnapObjectContext *sctx,
|
||||
}
|
||||
else if (sctx->ret.is_edit) {
|
||||
/* The object's #BMEditMesh was used to snap instead. */
|
||||
std::unique_ptr<SnapData_EditMesh> &sod_editmesh = sctx->editmesh_caches.lookup(
|
||||
BKE_editmesh_from_object(sctx->ret.ob));
|
||||
nearest2d_data_init_editmesh(sod_editmesh.get(),
|
||||
nearest2d_data_init_editmesh(BKE_editmesh_from_object(sctx->ret.ob),
|
||||
sctx->runtime.view_proj == VIEW_PROJ_PERSP,
|
||||
params->use_backface_culling,
|
||||
&nearest2d);
|
||||
@@ -2524,350 +1479,6 @@ static eSnapMode snapCamera(const SnapObjectContext *sctx,
|
||||
return SCE_SNAP_MODE_NONE;
|
||||
}
|
||||
|
||||
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);
|
||||
if (me_eval->totvert == 0) {
|
||||
return SCE_SNAP_MODE_NONE;
|
||||
}
|
||||
if (me_eval->totedge == 0 && !(sctx->runtime.snap_to_flag & SCE_SNAP_MODE_VERTEX)) {
|
||||
return SCE_SNAP_MODE_NONE;
|
||||
}
|
||||
|
||||
float lpmat[4][4];
|
||||
mul_m4_m4m4(lpmat, sctx->runtime.pmat, obmat);
|
||||
|
||||
float dist_px_sq = square_f(*dist_px);
|
||||
|
||||
/* Test BoundBox */
|
||||
if (ob_eval->data == me_eval) {
|
||||
const BoundBox *bb = BKE_object_boundbox_get(ob_eval);
|
||||
if (!snap_bound_box_check_dist(
|
||||
bb->vec[0], bb->vec[6], lpmat, sctx->runtime.win_size, sctx->runtime.mval, dist_px_sq))
|
||||
{
|
||||
return SCE_SNAP_MODE_NONE;
|
||||
}
|
||||
}
|
||||
|
||||
BVHTreeFromMesh treedata, treedata_dummy;
|
||||
snap_object_data_mesh_get(me_eval, use_hide, &treedata);
|
||||
|
||||
BVHTree *bvhtree[2] = {nullptr};
|
||||
bvhtree[0] = BKE_bvhtree_from_mesh_get(&treedata_dummy, me_eval, BVHTREE_FROM_LOOSEEDGES, 2);
|
||||
BLI_assert(treedata_dummy.cached);
|
||||
if (sctx->runtime.snap_to_flag & SCE_SNAP_MODE_VERTEX) {
|
||||
bvhtree[1] = BKE_bvhtree_from_mesh_get(&treedata_dummy, me_eval, BVHTREE_FROM_LOOSEVERTS, 2);
|
||||
BLI_assert(treedata_dummy.cached);
|
||||
}
|
||||
|
||||
Nearest2dUserData nearest2d;
|
||||
nearest2d_data_init_mesh(me_eval,
|
||||
sctx->runtime.view_proj == VIEW_PROJ_PERSP,
|
||||
params->use_backface_culling,
|
||||
&nearest2d);
|
||||
|
||||
BVHTreeNearest nearest{};
|
||||
nearest.index = -1;
|
||||
nearest.dist_sq = dist_px_sq;
|
||||
|
||||
int last_index = nearest.index;
|
||||
eSnapMode elem = SCE_SNAP_MODE_VERTEX;
|
||||
|
||||
float tobmat[4][4], clip_planes_local[MAX_CLIPPLANE_LEN][4];
|
||||
transpose_m4_m4(tobmat, obmat);
|
||||
for (int i = sctx->runtime.clip_plane_len; i--;) {
|
||||
mul_v4_m4v4(clip_planes_local[i], tobmat, sctx->runtime.clip_plane[i]);
|
||||
}
|
||||
|
||||
if (bvhtree[1]) {
|
||||
BLI_assert(sctx->runtime.snap_to_flag & SCE_SNAP_MODE_VERTEX);
|
||||
/* snap to loose verts */
|
||||
BLI_bvhtree_find_nearest_projected(bvhtree[1],
|
||||
lpmat,
|
||||
sctx->runtime.win_size,
|
||||
sctx->runtime.mval,
|
||||
clip_planes_local,
|
||||
sctx->runtime.clip_plane_len,
|
||||
&nearest,
|
||||
cb_snap_vert,
|
||||
&nearest2d);
|
||||
|
||||
last_index = nearest.index;
|
||||
}
|
||||
|
||||
if (sctx->runtime.snap_to_flag & SCE_SNAP_MODE_EDGE) {
|
||||
if (bvhtree[0]) {
|
||||
/* Snap to loose edges. */
|
||||
BLI_bvhtree_find_nearest_projected(bvhtree[0],
|
||||
lpmat,
|
||||
sctx->runtime.win_size,
|
||||
sctx->runtime.mval,
|
||||
clip_planes_local,
|
||||
sctx->runtime.clip_plane_len,
|
||||
&nearest,
|
||||
cb_snap_edge,
|
||||
&nearest2d);
|
||||
}
|
||||
|
||||
if (treedata.tree) {
|
||||
/* Snap to looptris. */
|
||||
BLI_bvhtree_find_nearest_projected(treedata.tree,
|
||||
lpmat,
|
||||
sctx->runtime.win_size,
|
||||
sctx->runtime.mval,
|
||||
clip_planes_local,
|
||||
sctx->runtime.clip_plane_len,
|
||||
&nearest,
|
||||
cb_snap_tri_edges,
|
||||
&nearest2d);
|
||||
}
|
||||
|
||||
if (last_index != nearest.index) {
|
||||
elem = SCE_SNAP_MODE_EDGE;
|
||||
}
|
||||
}
|
||||
else {
|
||||
BLI_assert(sctx->runtime.snap_to_flag & SCE_SNAP_MODE_VERTEX);
|
||||
if (bvhtree[0]) {
|
||||
/* Snap to loose edge verts. */
|
||||
BLI_bvhtree_find_nearest_projected(bvhtree[0],
|
||||
lpmat,
|
||||
sctx->runtime.win_size,
|
||||
sctx->runtime.mval,
|
||||
clip_planes_local,
|
||||
sctx->runtime.clip_plane_len,
|
||||
&nearest,
|
||||
cb_snap_edge_verts,
|
||||
&nearest2d);
|
||||
}
|
||||
|
||||
if (treedata.tree) {
|
||||
/* Snap to looptri verts. */
|
||||
BLI_bvhtree_find_nearest_projected(treedata.tree,
|
||||
lpmat,
|
||||
sctx->runtime.win_size,
|
||||
sctx->runtime.mval,
|
||||
clip_planes_local,
|
||||
sctx->runtime.clip_plane_len,
|
||||
&nearest,
|
||||
cb_snap_tri_verts,
|
||||
&nearest2d);
|
||||
}
|
||||
}
|
||||
|
||||
if (nearest.index != -1) {
|
||||
*dist_px = sqrtf(nearest.dist_sq);
|
||||
|
||||
copy_v3_v3(r_loc, nearest.co);
|
||||
mul_m4_v3(obmat, r_loc);
|
||||
|
||||
if (r_no) {
|
||||
float imat[4][4];
|
||||
invert_m4_m4(imat, obmat);
|
||||
|
||||
copy_v3_v3(r_no, nearest.no);
|
||||
mul_transposed_mat3_m4_v3(imat, r_no);
|
||||
normalize_v3(r_no);
|
||||
}
|
||||
if (r_index) {
|
||||
*r_index = nearest.index;
|
||||
}
|
||||
|
||||
return elem;
|
||||
}
|
||||
|
||||
return SCE_SNAP_MODE_NONE;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
if ((sctx->runtime.snap_to_flag & ~SCE_SNAP_MODE_FACE) == SCE_SNAP_MODE_VERTEX) {
|
||||
if (em->bm->totvert == 0) {
|
||||
return SCE_SNAP_MODE_NONE;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (em->bm->totedge == 0) {
|
||||
return SCE_SNAP_MODE_NONE;
|
||||
}
|
||||
}
|
||||
|
||||
float lpmat[4][4];
|
||||
mul_m4_m4m4(lpmat, sctx->runtime.pmat, obmat);
|
||||
|
||||
float dist_px_sq = square_f(*dist_px);
|
||||
|
||||
SnapData_EditMesh *sod = snap_object_data_editmesh_get(sctx, ob_eval, em);
|
||||
|
||||
/* Test BoundBox */
|
||||
|
||||
/* 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 SCE_SNAP_MODE_NONE;
|
||||
}
|
||||
|
||||
if (sctx->runtime.snap_to_flag & SCE_SNAP_MODE_VERTEX) {
|
||||
BVHTreeFromEditMesh treedata{};
|
||||
treedata.tree = sod->bvhtree[0];
|
||||
|
||||
if (treedata.tree == nullptr) {
|
||||
if (sctx->callbacks.edit_mesh.test_vert_fn) {
|
||||
blender::BitVector<> verts_mask(em->bm->totvert);
|
||||
const int verts_num_active = BM_iter_mesh_bitmap_from_filter(
|
||||
BM_VERTS_OF_MESH,
|
||||
em->bm,
|
||||
verts_mask,
|
||||
(bool (*)(BMElem *, void *))sctx->callbacks.edit_mesh.test_vert_fn,
|
||||
sctx->callbacks.edit_mesh.user_data);
|
||||
|
||||
bvhtree_from_editmesh_verts_ex(&treedata, em, verts_mask, verts_num_active, 0.0f, 2, 6);
|
||||
}
|
||||
else {
|
||||
BKE_bvhtree_from_editmesh_get(&treedata,
|
||||
em,
|
||||
2,
|
||||
BVHTREE_FROM_EM_VERTS,
|
||||
/* WORKAROUND: avoid updating while transforming. */
|
||||
G.moving ? nullptr : &sod->mesh_runtime->bvh_cache,
|
||||
&sod->mesh_runtime->eval_mutex);
|
||||
}
|
||||
sod->bvhtree[0] = treedata.tree;
|
||||
sod->cached[0] = treedata.cached;
|
||||
}
|
||||
}
|
||||
|
||||
if (sctx->runtime.snap_to_flag & SCE_SNAP_MODE_EDGE) {
|
||||
BVHTreeFromEditMesh treedata{};
|
||||
treedata.tree = sod->bvhtree[1];
|
||||
|
||||
if (treedata.tree == nullptr) {
|
||||
if (sctx->callbacks.edit_mesh.test_edge_fn) {
|
||||
blender::BitVector<> edges_mask(em->bm->totedge);
|
||||
const int edges_num_active = BM_iter_mesh_bitmap_from_filter(
|
||||
BM_EDGES_OF_MESH,
|
||||
em->bm,
|
||||
edges_mask,
|
||||
(bool (*)(BMElem *, void *))sctx->callbacks.edit_mesh.test_edge_fn,
|
||||
sctx->callbacks.edit_mesh.user_data);
|
||||
|
||||
bvhtree_from_editmesh_edges_ex(&treedata, em, edges_mask, edges_num_active, 0.0f, 2, 6);
|
||||
}
|
||||
else {
|
||||
BKE_bvhtree_from_editmesh_get(&treedata,
|
||||
em,
|
||||
2,
|
||||
BVHTREE_FROM_EM_EDGES,
|
||||
/* WORKAROUND: avoid updating while transforming. */
|
||||
G.moving ? nullptr : &sod->mesh_runtime->bvh_cache,
|
||||
&sod->mesh_runtime->eval_mutex);
|
||||
}
|
||||
sod->bvhtree[1] = treedata.tree;
|
||||
sod->cached[1] = treedata.cached;
|
||||
}
|
||||
}
|
||||
|
||||
Nearest2dUserData nearest2d;
|
||||
nearest2d_data_init_editmesh(
|
||||
sod, sctx->runtime.view_proj == VIEW_PROJ_PERSP, params->use_backface_culling, &nearest2d);
|
||||
|
||||
BVHTreeNearest nearest{};
|
||||
nearest.index = -1;
|
||||
nearest.dist_sq = dist_px_sq;
|
||||
|
||||
eSnapMode elem = SCE_SNAP_MODE_VERTEX;
|
||||
|
||||
float tobmat[4][4], clip_planes_local[MAX_CLIPPLANE_LEN][4];
|
||||
transpose_m4_m4(tobmat, obmat);
|
||||
|
||||
for (int i = sctx->runtime.clip_plane_len; i--;) {
|
||||
mul_v4_m4v4(clip_planes_local[i], tobmat, sctx->runtime.clip_plane[i]);
|
||||
}
|
||||
|
||||
if (sod->bvhtree[0] && (sctx->runtime.snap_to_flag & SCE_SNAP_MODE_VERTEX)) {
|
||||
BM_mesh_elem_table_ensure(em->bm, BM_VERT);
|
||||
BM_mesh_elem_index_ensure(em->bm, BM_VERT);
|
||||
BLI_bvhtree_find_nearest_projected(sod->bvhtree[0],
|
||||
lpmat,
|
||||
sctx->runtime.win_size,
|
||||
sctx->runtime.mval,
|
||||
clip_planes_local,
|
||||
sctx->runtime.clip_plane_len,
|
||||
&nearest,
|
||||
cb_snap_vert,
|
||||
&nearest2d);
|
||||
}
|
||||
|
||||
if (sod->bvhtree[1] && (sctx->runtime.snap_to_flag & SCE_SNAP_MODE_EDGE)) {
|
||||
int last_index = nearest.index;
|
||||
nearest.index = -1;
|
||||
BM_mesh_elem_table_ensure(em->bm, BM_EDGE | BM_VERT);
|
||||
BM_mesh_elem_index_ensure(em->bm, BM_EDGE | BM_VERT);
|
||||
BLI_bvhtree_find_nearest_projected(sod->bvhtree[1],
|
||||
lpmat,
|
||||
sctx->runtime.win_size,
|
||||
sctx->runtime.mval,
|
||||
clip_planes_local,
|
||||
sctx->runtime.clip_plane_len,
|
||||
&nearest,
|
||||
cb_snap_edge,
|
||||
&nearest2d);
|
||||
|
||||
if (nearest.index != -1) {
|
||||
elem = SCE_SNAP_MODE_EDGE;
|
||||
}
|
||||
else {
|
||||
nearest.index = last_index;
|
||||
}
|
||||
}
|
||||
|
||||
if (nearest.index != -1) {
|
||||
*dist_px = sqrtf(nearest.dist_sq);
|
||||
|
||||
copy_v3_v3(r_loc, nearest.co);
|
||||
mul_m4_v3(obmat, r_loc);
|
||||
if (r_no) {
|
||||
float imat[4][4];
|
||||
invert_m4_m4(imat, obmat);
|
||||
|
||||
copy_v3_v3(r_no, nearest.no);
|
||||
mul_transposed_mat3_m4_v3(imat, r_no);
|
||||
normalize_v3(r_no);
|
||||
}
|
||||
if (r_index) {
|
||||
*r_index = nearest.index;
|
||||
}
|
||||
|
||||
return elem;
|
||||
}
|
||||
|
||||
return SCE_SNAP_MODE_NONE;
|
||||
}
|
||||
|
||||
struct SnapObjUserData {
|
||||
/* read/write args */
|
||||
float *dist_px;
|
||||
@@ -3403,7 +2014,7 @@ static eSnapMode transform_snap_context_project_view3d_mixed_impl(SnapObjectCont
|
||||
new_clipplane[3] += 0.01f;
|
||||
|
||||
/* Try to snap only to the polygon. */
|
||||
elem_test = snap_mesh_polygon(sctx, params, &dist_px_tmp);
|
||||
elem_test = snap_polygon(sctx, params, &dist_px_tmp);
|
||||
if (elem_test) {
|
||||
elem = elem_test;
|
||||
}
|
||||
|
||||
335
source/blender/editors/transform/transform_snap_object.hh
Normal file
335
source/blender/editors/transform/transform_snap_object.hh
Normal file
@@ -0,0 +1,335 @@
|
||||
/* SPDX-FileCopyrightText: 2023 Blender Foundation
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup editors
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#define MAX_CLIPPLANE_LEN 3
|
||||
|
||||
enum eViewProj {
|
||||
VIEW_PROJ_NONE = -1,
|
||||
VIEW_PROJ_ORTHO = 0,
|
||||
VIEW_PROJ_PERSP = -1,
|
||||
};
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Internal Data Types
|
||||
* \{ */
|
||||
|
||||
/** #SnapObjectContext.editmesh_caches */
|
||||
struct SnapData_EditMesh {
|
||||
/* Verts, Edges. */
|
||||
BVHTree *bvhtree[2];
|
||||
bool cached[2];
|
||||
|
||||
/* BVH tree from #BMEditMesh.looptris. */
|
||||
BVHTreeFromEditMesh treedata_editmesh;
|
||||
|
||||
blender::bke::MeshRuntime *mesh_runtime;
|
||||
float min[3], max[3];
|
||||
|
||||
void clear()
|
||||
{
|
||||
for (int i = 0; i < ARRAY_SIZE(this->bvhtree); i++) {
|
||||
if (!this->cached[i]) {
|
||||
BLI_bvhtree_free(this->bvhtree[i]);
|
||||
}
|
||||
this->bvhtree[i] = nullptr;
|
||||
}
|
||||
free_bvhtree_from_editmesh(&this->treedata_editmesh);
|
||||
}
|
||||
|
||||
~SnapData_EditMesh()
|
||||
{
|
||||
this->clear();
|
||||
}
|
||||
|
||||
#ifdef WITH_CXX_GUARDEDALLOC
|
||||
MEM_CXX_CLASS_ALLOC_FUNCS("SnapData_EditMesh")
|
||||
#endif
|
||||
};
|
||||
|
||||
/** \} */
|
||||
|
||||
struct SnapObjectContext {
|
||||
struct Scene *scene;
|
||||
|
||||
int flag;
|
||||
|
||||
blender::Map<const BMEditMesh *, std::unique_ptr<SnapData_EditMesh>> editmesh_caches;
|
||||
|
||||
/* Filter data, returns true to check this value */
|
||||
struct {
|
||||
struct {
|
||||
bool (*test_vert_fn)(BMVert *, void *user_data);
|
||||
bool (*test_edge_fn)(BMEdge *, void *user_data);
|
||||
bool (*test_face_fn)(BMFace *, void *user_data);
|
||||
void *user_data;
|
||||
} edit_mesh;
|
||||
} callbacks;
|
||||
|
||||
struct {
|
||||
Depsgraph *depsgraph;
|
||||
const ARegion *region;
|
||||
const View3D *v3d;
|
||||
|
||||
float mval[2];
|
||||
float pmat[4][4]; /* perspective matrix */
|
||||
float win_size[2]; /* win x and y */
|
||||
enum eViewProj view_proj;
|
||||
float clip_plane[MAX_CLIPPLANE_LEN][4];
|
||||
short clip_plane_len;
|
||||
eSnapMode snap_to_flag;
|
||||
bool has_occlusion_plane; /* Ignore plane of occlusion in curves. */
|
||||
} runtime;
|
||||
|
||||
/* Output. */
|
||||
struct {
|
||||
/* Location of snapped point on target surface. */
|
||||
float loc[3];
|
||||
/* Normal of snapped point on target surface. */
|
||||
float no[3];
|
||||
/* Index of snapped element on target object (-1 when no valid index is found). */
|
||||
int index;
|
||||
/* Matrix of target object (may not be #Object.object_to_world with dupli-instances). */
|
||||
float obmat[4][4];
|
||||
/* List of #SnapObjectHitDepth (caller must free). */
|
||||
ListBase *hit_list;
|
||||
/* Snapped object. */
|
||||
Object *ob;
|
||||
/* Snapped data. */
|
||||
ID *data;
|
||||
|
||||
float dist_sq;
|
||||
|
||||
bool is_edit;
|
||||
} ret;
|
||||
};
|
||||
|
||||
struct RayCastAll_Data {
|
||||
void *bvhdata;
|
||||
|
||||
/* internal vars for adding depths */
|
||||
BVHTree_RayCastCallback raycast_callback;
|
||||
|
||||
const float (*obmat)[4];
|
||||
const float (*timat)[3];
|
||||
|
||||
float len_diff;
|
||||
float local_scale;
|
||||
|
||||
Object *ob_eval;
|
||||
uint ob_uuid;
|
||||
|
||||
/* output data */
|
||||
ListBase *hit_list;
|
||||
bool retval;
|
||||
};
|
||||
|
||||
struct Nearest2dUserData;
|
||||
|
||||
using Nearest2DGetVertCoCallback = void (*)(const int index,
|
||||
const Nearest2dUserData *data,
|
||||
const float **r_co);
|
||||
using Nearest2DGetEdgeVertsCallback = void (*)(const int index,
|
||||
const Nearest2dUserData *data,
|
||||
int r_v_index[2]);
|
||||
using Nearest2DGetTriVertsCallback = void (*)(const int index,
|
||||
const Nearest2dUserData *data,
|
||||
int r_v_index[3]);
|
||||
/* Equal the previous one */
|
||||
using Nearest2DGetTriEdgesCallback = void (*)(const int index,
|
||||
const Nearest2dUserData *data,
|
||||
int r_e_index[3]);
|
||||
using Nearest2DCopyVertNoCallback = void (*)(const int index,
|
||||
const Nearest2dUserData *data,
|
||||
float r_no[3]);
|
||||
|
||||
struct Nearest2dUserData {
|
||||
Nearest2DGetVertCoCallback get_vert_co;
|
||||
Nearest2DGetEdgeVertsCallback get_edge_verts_index;
|
||||
Nearest2DGetTriVertsCallback get_tri_verts_index;
|
||||
Nearest2DGetTriEdgesCallback get_tri_edges_index;
|
||||
Nearest2DCopyVertNoCallback copy_vert_no;
|
||||
|
||||
union {
|
||||
struct {
|
||||
BMesh *bm;
|
||||
};
|
||||
struct {
|
||||
const blender::float3 *vert_positions;
|
||||
const blender::float3 *vert_normals;
|
||||
const blender::int2 *edges; /* only used for #BVHTreeFromMeshEdges */
|
||||
const int *corner_verts;
|
||||
const int *corner_edges;
|
||||
const MLoopTri *looptris;
|
||||
};
|
||||
};
|
||||
|
||||
bool is_persp;
|
||||
bool use_backface_culling;
|
||||
};
|
||||
|
||||
/* transform_snap_object.cc */
|
||||
|
||||
void raycast_all_cb(void *userdata, int index, const BVHTreeRay *ray, BVHTreeRayHit *hit);
|
||||
|
||||
bool raycast_tri_backface_culling_test(
|
||||
const float dir[3], const float v0[3], const float v1[3], const float v2[3], float no[3]);
|
||||
|
||||
bool snap_bound_box_check_dist(const float min[3],
|
||||
const float max[3],
|
||||
const float lpmat[4][4],
|
||||
const float win_size[2],
|
||||
const float mval[2],
|
||||
float dist_px_sq);
|
||||
|
||||
void cb_snap_vert(void *userdata,
|
||||
int index,
|
||||
const DistProjectedAABBPrecalc *precalc,
|
||||
const float (*clip_plane)[4],
|
||||
const int clip_plane_len,
|
||||
BVHTreeNearest *nearest);
|
||||
|
||||
void cb_snap_edge(void *userdata,
|
||||
int index,
|
||||
const DistProjectedAABBPrecalc *precalc,
|
||||
const float (*clip_plane)[4],
|
||||
const int clip_plane_len,
|
||||
BVHTreeNearest *nearest);
|
||||
|
||||
bool nearest_world_tree(SnapObjectContext *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);
|
||||
|
||||
/* transform_snap_object_editmesh.cc */
|
||||
|
||||
bool raycastEditMesh(SnapObjectContext *sctx,
|
||||
const struct SnapObjectParams *params,
|
||||
const float ray_start[3],
|
||||
const float ray_dir[3],
|
||||
Object *ob_eval,
|
||||
BMEditMesh *em,
|
||||
const float obmat[4][4],
|
||||
const uint ob_index,
|
||||
/* read/write args */
|
||||
float *ray_depth,
|
||||
/* return args */
|
||||
float r_loc[3],
|
||||
float r_no[3],
|
||||
int *r_index,
|
||||
ListBase *r_hit_list);
|
||||
|
||||
eSnapMode snap_polygon_editmesh(SnapObjectContext *sctx,
|
||||
const SnapObjectParams *params,
|
||||
BMEditMesh *em,
|
||||
const float obmat[4][4],
|
||||
float clip_planes_local[MAX_CLIPPLANE_LEN][4],
|
||||
/* read/write args */
|
||||
float *dist_px,
|
||||
/* return args */
|
||||
float r_loc[3],
|
||||
float r_no[3],
|
||||
int *r_index);
|
||||
|
||||
eSnapMode snapEditMesh(struct SnapObjectContext *sctx,
|
||||
const struct SnapObjectParams *params,
|
||||
struct Object *ob_eval,
|
||||
struct 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);
|
||||
|
||||
bool nearest_world_editmesh(struct SnapObjectContext *sctx,
|
||||
const struct SnapObjectParams *params,
|
||||
struct Object *ob_eval,
|
||||
struct 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);
|
||||
|
||||
void nearest2d_data_init_editmesh(struct BMEditMesh *em,
|
||||
bool is_persp,
|
||||
bool use_backface_culling,
|
||||
struct Nearest2dUserData *r_nearest2d);
|
||||
|
||||
/* transform_snap_object_mesh.cc */
|
||||
|
||||
bool raycastMesh(const struct SnapObjectParams *params,
|
||||
const float ray_start[3],
|
||||
const float ray_dir[3],
|
||||
struct Object *ob_eval,
|
||||
const struct Mesh *me_eval,
|
||||
const float obmat[4][4],
|
||||
const uint ob_index,
|
||||
bool use_hide,
|
||||
/* read/write args */
|
||||
float *ray_depth,
|
||||
/* return args */
|
||||
float r_loc[3],
|
||||
float r_no[3],
|
||||
int *r_index,
|
||||
struct ListBase *r_hit_list);
|
||||
|
||||
bool nearest_world_mesh(SnapObjectContext *sctx,
|
||||
const SnapObjectParams *params,
|
||||
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);
|
||||
|
||||
void nearest2d_data_init_mesh(const Mesh *mesh,
|
||||
bool is_persp,
|
||||
bool use_backface_culling,
|
||||
Nearest2dUserData *r_nearest2d);
|
||||
|
||||
eSnapMode snap_polygon_mesh(SnapObjectContext *sctx,
|
||||
const SnapObjectParams *params,
|
||||
const Mesh *mesh,
|
||||
const float obmat[4][4],
|
||||
float clip_planes_local[MAX_CLIPPLANE_LEN][4],
|
||||
/* read/write args */
|
||||
float *dist_px,
|
||||
/* return args */
|
||||
float r_loc[3],
|
||||
float r_no[3],
|
||||
int *r_index);
|
||||
|
||||
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);
|
||||
@@ -0,0 +1,704 @@
|
||||
/* SPDX-FileCopyrightText: 2023 Blender Foundation
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup edtransform
|
||||
*/
|
||||
|
||||
#include "BLI_math.h"
|
||||
#include "BLI_math_matrix_types.hh"
|
||||
|
||||
#include "BKE_bvhutils.h"
|
||||
#include "BKE_editmesh.h"
|
||||
#include "BKE_global.h"
|
||||
#include "BKE_mesh.hh"
|
||||
#include "BKE_object.h"
|
||||
|
||||
#include "DEG_depsgraph_query.h"
|
||||
|
||||
#include "ED_transform_snap_object_context.h"
|
||||
|
||||
#include "transform_snap_object.hh"
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Snap Object Data
|
||||
* \{ */
|
||||
|
||||
/**
|
||||
* Calculate the minimum and maximum coordinates of the box that encompasses this mesh.
|
||||
*/
|
||||
static void snap_editmesh_minmax(SnapObjectContext *sctx,
|
||||
BMesh *bm,
|
||||
float r_min[3],
|
||||
float r_max[3])
|
||||
{
|
||||
INIT_MINMAX(r_min, r_max);
|
||||
BMIter iter;
|
||||
BMVert *v;
|
||||
|
||||
BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
|
||||
if (sctx->callbacks.edit_mesh.test_vert_fn &&
|
||||
!sctx->callbacks.edit_mesh.test_vert_fn(v, sctx->callbacks.edit_mesh.user_data))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
minmax_v3v3_v3(r_min, r_max, v->co);
|
||||
}
|
||||
}
|
||||
|
||||
/* Searches for the #Mesh_Runtime associated with the object that is most likely to be updated due
|
||||
* to changes in the `edit_mesh`. */
|
||||
static blender::bke::MeshRuntime *snap_object_data_editmesh_runtime_get(Object *ob_eval)
|
||||
{
|
||||
Mesh *editmesh_eval_final = BKE_object_get_editmesh_eval_final(ob_eval);
|
||||
if (editmesh_eval_final) {
|
||||
return editmesh_eval_final->runtime;
|
||||
}
|
||||
|
||||
Mesh *editmesh_eval_cage = BKE_object_get_editmesh_eval_cage(ob_eval);
|
||||
if (editmesh_eval_cage) {
|
||||
return editmesh_eval_cage->runtime;
|
||||
}
|
||||
|
||||
return ((Mesh *)ob_eval->data)->runtime;
|
||||
}
|
||||
|
||||
static SnapData_EditMesh *snap_object_data_editmesh_get(SnapObjectContext *sctx,
|
||||
Object *ob_eval,
|
||||
BMEditMesh *em)
|
||||
{
|
||||
SnapData_EditMesh *sod;
|
||||
bool init = false;
|
||||
|
||||
if (std::unique_ptr<SnapData_EditMesh> *sod_p = sctx->editmesh_caches.lookup_ptr(em)) {
|
||||
sod = sod_p->get();
|
||||
bool is_dirty = false;
|
||||
/* Check if the geometry has changed. */
|
||||
if (sod->treedata_editmesh.em != em) {
|
||||
is_dirty = true;
|
||||
}
|
||||
else if (sod->mesh_runtime) {
|
||||
if (sod->mesh_runtime != snap_object_data_editmesh_runtime_get(ob_eval)) {
|
||||
if (G.moving) {
|
||||
/* WORKAROUND: avoid updating while transforming. */
|
||||
BLI_assert(!sod->treedata_editmesh.cached && !sod->cached[0] && !sod->cached[1]);
|
||||
sod->mesh_runtime = snap_object_data_editmesh_runtime_get(ob_eval);
|
||||
}
|
||||
else {
|
||||
is_dirty = true;
|
||||
}
|
||||
}
|
||||
else if (sod->treedata_editmesh.tree && sod->treedata_editmesh.cached &&
|
||||
!bvhcache_has_tree(sod->mesh_runtime->bvh_cache, sod->treedata_editmesh.tree))
|
||||
{
|
||||
/* The tree is owned by the EditMesh and may have been freed since we last used! */
|
||||
is_dirty = true;
|
||||
}
|
||||
else if (sod->bvhtree[0] && sod->cached[0] &&
|
||||
!bvhcache_has_tree(sod->mesh_runtime->bvh_cache, sod->bvhtree[0]))
|
||||
{
|
||||
/* The tree is owned by the EditMesh and may have been freed since we last used! */
|
||||
is_dirty = true;
|
||||
}
|
||||
else if (sod->bvhtree[1] && sod->cached[1] &&
|
||||
!bvhcache_has_tree(sod->mesh_runtime->bvh_cache, sod->bvhtree[1]))
|
||||
{
|
||||
/* The tree is owned by the EditMesh and may have been freed since we last used! */
|
||||
is_dirty = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (is_dirty) {
|
||||
sod->clear();
|
||||
init = true;
|
||||
}
|
||||
}
|
||||
else {
|
||||
std::unique_ptr<SnapData_EditMesh> sod_ptr = std::make_unique<SnapData_EditMesh>();
|
||||
sod = sod_ptr.get();
|
||||
sctx->editmesh_caches.add_new(em, std::move(sod_ptr));
|
||||
init = true;
|
||||
}
|
||||
|
||||
if (init) {
|
||||
sod->treedata_editmesh.em = em;
|
||||
sod->mesh_runtime = snap_object_data_editmesh_runtime_get(ob_eval);
|
||||
snap_editmesh_minmax(sctx, em->bm, sod->min, sod->max);
|
||||
}
|
||||
|
||||
return sod;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
blender::BitVector<> elem_mask(em->tottri);
|
||||
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);
|
||||
}
|
||||
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,
|
||||
/* WORKAROUND: avoid updating while transforming. */
|
||||
G.moving ? nullptr : &sod->mesh_runtime->bvh_cache,
|
||||
&sod->mesh_runtime->eval_mutex);
|
||||
}
|
||||
}
|
||||
if (treedata->tree == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return treedata;
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Ray Cast Functions
|
||||
* \{ */
|
||||
|
||||
/* Callback to ray-cast with back-face culling (#EditMesh). */
|
||||
static void editmesh_looptri_raycast_backface_culling_cb(void *userdata,
|
||||
int index,
|
||||
const BVHTreeRay *ray,
|
||||
BVHTreeRayHit *hit)
|
||||
{
|
||||
const BVHTreeFromEditMesh *data = (BVHTreeFromEditMesh *)userdata;
|
||||
BMEditMesh *em = data->em;
|
||||
const BMLoop **ltri = (const BMLoop **)em->looptris[index];
|
||||
|
||||
const float *t0, *t1, *t2;
|
||||
t0 = ltri[0]->v->co;
|
||||
t1 = ltri[1]->v->co;
|
||||
t2 = ltri[2]->v->co;
|
||||
|
||||
{
|
||||
float dist = bvhtree_ray_tri_intersection(ray, hit->dist, t0, t1, t2);
|
||||
|
||||
if (dist >= 0 && dist < hit->dist) {
|
||||
float no[3];
|
||||
if (raycast_tri_backface_culling_test(ray->direction, t0, t1, t2, no)) {
|
||||
hit->index = index;
|
||||
hit->dist = dist;
|
||||
madd_v3_v3v3fl(hit->co, ray->origin, ray->direction, dist);
|
||||
normalize_v3_v3(hit->no, no);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool raycastEditMesh(SnapObjectContext *sctx,
|
||||
const SnapObjectParams *params,
|
||||
const float ray_start[3],
|
||||
const float ray_dir[3],
|
||||
Object *ob_eval,
|
||||
BMEditMesh *em,
|
||||
const float obmat[4][4],
|
||||
const uint ob_index,
|
||||
/* read/write args */
|
||||
float *ray_depth,
|
||||
/* return args */
|
||||
float r_loc[3],
|
||||
float r_no[3],
|
||||
int *r_index,
|
||||
ListBase *r_hit_list)
|
||||
{
|
||||
bool retval = false;
|
||||
if (em->bm->totface == 0) {
|
||||
return retval;
|
||||
}
|
||||
|
||||
float imat[4][4];
|
||||
float ray_start_local[3], ray_normal_local[3];
|
||||
float local_scale, local_depth, len_diff = 0.0f;
|
||||
|
||||
invert_m4_m4(imat, obmat);
|
||||
|
||||
copy_v3_v3(ray_start_local, ray_start);
|
||||
copy_v3_v3(ray_normal_local, ray_dir);
|
||||
|
||||
mul_m4_v3(imat, ray_start_local);
|
||||
mul_mat3_m4_v3(imat, ray_normal_local);
|
||||
|
||||
/* local scale in normal direction */
|
||||
local_scale = normalize_v3(ray_normal_local);
|
||||
local_depth = *ray_depth;
|
||||
if (local_depth != BVH_RAYCAST_DIST_MAX) {
|
||||
local_depth *= local_scale;
|
||||
}
|
||||
|
||||
SnapData_EditMesh *sod = snap_object_data_editmesh_get(sctx, ob_eval, em);
|
||||
|
||||
/* Test BoundBox */
|
||||
|
||||
/* was BKE_boundbox_ray_hit_check, see: cf6ca226fa58 */
|
||||
if (!isect_ray_aabb_v3_simple(
|
||||
ray_start_local, ray_normal_local, sod->min, sod->max, &len_diff, nullptr))
|
||||
{
|
||||
return retval;
|
||||
}
|
||||
|
||||
/* We pass a temp ray_start, set from object's boundbox, to avoid precision issues with
|
||||
* very far away ray_start values (as returned in case of ortho view3d), see #50486, #38358.
|
||||
*/
|
||||
if (len_diff > 400.0f) {
|
||||
len_diff -= local_scale; /* make temp start point a bit away from bbox hit point. */
|
||||
madd_v3_v3fl(ray_start_local, ray_normal_local, len_diff);
|
||||
local_depth -= len_diff;
|
||||
}
|
||||
else {
|
||||
len_diff = 0.0f;
|
||||
}
|
||||
|
||||
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 */
|
||||
transpose_m3_m4(timat, imat);
|
||||
|
||||
if (r_hit_list) {
|
||||
RayCastAll_Data data;
|
||||
|
||||
data.bvhdata = treedata;
|
||||
data.raycast_callback = treedata->raycast_callback;
|
||||
data.obmat = obmat;
|
||||
data.timat = timat;
|
||||
data.len_diff = len_diff;
|
||||
data.local_scale = local_scale;
|
||||
data.ob_eval = ob_eval;
|
||||
data.ob_uuid = ob_index;
|
||||
data.hit_list = r_hit_list;
|
||||
data.retval = retval;
|
||||
|
||||
BLI_bvhtree_ray_cast_all(treedata->tree,
|
||||
ray_start_local,
|
||||
ray_normal_local,
|
||||
0.0f,
|
||||
*ray_depth,
|
||||
raycast_all_cb,
|
||||
&data);
|
||||
|
||||
retval = data.retval;
|
||||
}
|
||||
else {
|
||||
BVHTreeRayHit hit{};
|
||||
hit.index = -1;
|
||||
hit.dist = local_depth;
|
||||
|
||||
if (BLI_bvhtree_ray_cast(treedata->tree,
|
||||
ray_start_local,
|
||||
ray_normal_local,
|
||||
0.0f,
|
||||
&hit,
|
||||
params->use_backface_culling ?
|
||||
editmesh_looptri_raycast_backface_culling_cb :
|
||||
treedata->raycast_callback,
|
||||
treedata) != -1)
|
||||
{
|
||||
hit.dist += len_diff;
|
||||
hit.dist /= local_scale;
|
||||
if (hit.dist <= *ray_depth) {
|
||||
*ray_depth = hit.dist;
|
||||
copy_v3_v3(r_loc, hit.co);
|
||||
|
||||
/* Back to world-space. */
|
||||
mul_m4_v3(obmat, r_loc);
|
||||
|
||||
if (r_no) {
|
||||
copy_v3_v3(r_no, hit.no);
|
||||
mul_m3_v3(timat, r_no);
|
||||
normalize_v3(r_no);
|
||||
}
|
||||
|
||||
retval = true;
|
||||
|
||||
if (r_index) {
|
||||
em = sod->treedata_editmesh.em;
|
||||
|
||||
*r_index = BM_elem_index_get(em->looptris[hit.index][0]->f);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Surface Snap Functions
|
||||
* \{ */
|
||||
|
||||
bool nearest_world_editmesh(SnapObjectContext *sctx,
|
||||
const 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) {
|
||||
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);
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Callbacks
|
||||
* \{ */
|
||||
|
||||
static void cb_bvert_co_get(const int index, const Nearest2dUserData *data, const float **r_co)
|
||||
{
|
||||
BMVert *eve = BM_vert_at_index(data->bm, index);
|
||||
*r_co = eve->co;
|
||||
}
|
||||
|
||||
static void cb_bvert_no_copy(const int index, const Nearest2dUserData *data, float r_no[3])
|
||||
{
|
||||
BMVert *eve = BM_vert_at_index(data->bm, index);
|
||||
|
||||
copy_v3_v3(r_no, eve->no);
|
||||
}
|
||||
|
||||
static void cb_bedge_verts_get(const int index, const Nearest2dUserData *data, int r_v_index[2])
|
||||
{
|
||||
BMEdge *eed = BM_edge_at_index(data->bm, index);
|
||||
|
||||
r_v_index[0] = BM_elem_index_get(eed->v1);
|
||||
r_v_index[1] = BM_elem_index_get(eed->v2);
|
||||
}
|
||||
|
||||
void nearest2d_data_init_editmesh(BMEditMesh *em,
|
||||
bool is_persp,
|
||||
bool use_backface_culling,
|
||||
Nearest2dUserData *r_nearest2d)
|
||||
{
|
||||
r_nearest2d->get_vert_co = cb_bvert_co_get;
|
||||
r_nearest2d->get_edge_verts_index = cb_bedge_verts_get;
|
||||
r_nearest2d->copy_vert_no = cb_bvert_no_copy;
|
||||
r_nearest2d->get_tri_verts_index = nullptr;
|
||||
r_nearest2d->get_tri_edges_index = nullptr;
|
||||
|
||||
r_nearest2d->bm = em->bm;
|
||||
|
||||
r_nearest2d->is_persp = is_persp;
|
||||
r_nearest2d->use_backface_culling = use_backface_culling;
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Internal Object Snapping API
|
||||
* \{ */
|
||||
|
||||
eSnapMode snap_polygon_editmesh(SnapObjectContext *sctx,
|
||||
const SnapObjectParams *params,
|
||||
BMEditMesh *em,
|
||||
const float obmat[4][4],
|
||||
float clip_planes_local[MAX_CLIPPLANE_LEN][4],
|
||||
/* read/write args */
|
||||
float *dist_px,
|
||||
/* return args */
|
||||
float r_loc[3],
|
||||
float r_no[3],
|
||||
int *r_index)
|
||||
{
|
||||
BLI_assert(sctx->editmesh_caches.lookup(em).get()->treedata_editmesh.em == em);
|
||||
|
||||
eSnapMode elem = SCE_SNAP_MODE_NONE;
|
||||
|
||||
float lpmat[4][4];
|
||||
mul_m4_m4m4(lpmat, sctx->runtime.pmat, obmat);
|
||||
|
||||
DistProjectedAABBPrecalc neasrest_precalc;
|
||||
dist_squared_to_projected_aabb_precalc(
|
||||
&neasrest_precalc, lpmat, sctx->runtime.win_size, sctx->runtime.mval);
|
||||
|
||||
BVHTreeNearest nearest{};
|
||||
nearest.index = -1;
|
||||
nearest.dist_sq = square_f(*dist_px);
|
||||
|
||||
Nearest2dUserData nearest2d;
|
||||
|
||||
nearest2d_data_init_editmesh(
|
||||
em, sctx->runtime.view_proj == VIEW_PROJ_PERSP, params->use_backface_culling, &nearest2d);
|
||||
|
||||
BM_mesh_elem_table_ensure(em->bm, BM_FACE);
|
||||
BMFace *f = BM_face_at_index(em->bm, sctx->ret.index);
|
||||
BMLoop *l_iter, *l_first;
|
||||
l_iter = l_first = BM_FACE_FIRST_LOOP(f);
|
||||
if (sctx->runtime.snap_to_flag & SCE_SNAP_MODE_EDGE) {
|
||||
elem = SCE_SNAP_MODE_EDGE;
|
||||
BM_mesh_elem_index_ensure(em->bm, BM_VERT | BM_EDGE);
|
||||
BM_mesh_elem_table_ensure(em->bm, BM_VERT | BM_EDGE);
|
||||
do {
|
||||
cb_snap_edge(&nearest2d,
|
||||
BM_elem_index_get(l_iter->e),
|
||||
&neasrest_precalc,
|
||||
clip_planes_local,
|
||||
sctx->runtime.clip_plane_len,
|
||||
&nearest);
|
||||
} while ((l_iter = l_iter->next) != l_first);
|
||||
}
|
||||
else {
|
||||
elem = SCE_SNAP_MODE_VERTEX;
|
||||
BM_mesh_elem_index_ensure(em->bm, BM_VERT);
|
||||
BM_mesh_elem_table_ensure(em->bm, BM_VERT);
|
||||
do {
|
||||
cb_snap_vert(&nearest2d,
|
||||
BM_elem_index_get(l_iter->v),
|
||||
&neasrest_precalc,
|
||||
clip_planes_local,
|
||||
sctx->runtime.clip_plane_len,
|
||||
&nearest);
|
||||
} while ((l_iter = l_iter->next) != l_first);
|
||||
}
|
||||
|
||||
if (nearest.index != -1) {
|
||||
*dist_px = sqrtf(nearest.dist_sq);
|
||||
|
||||
mul_m4_v3(obmat, nearest.co);
|
||||
copy_v3_v3(r_loc, nearest.co);
|
||||
|
||||
{
|
||||
float imat[4][4];
|
||||
invert_m4_m4(imat, obmat);
|
||||
mul_transposed_mat3_m4_v3(imat, nearest.no);
|
||||
normalize_v3(nearest.no);
|
||||
|
||||
copy_v3_v3(r_no, nearest.no);
|
||||
}
|
||||
|
||||
*r_index = nearest.index;
|
||||
return elem;
|
||||
}
|
||||
|
||||
return SCE_SNAP_MODE_NONE;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
if ((sctx->runtime.snap_to_flag & ~SCE_SNAP_MODE_FACE) == SCE_SNAP_MODE_VERTEX) {
|
||||
if (em->bm->totvert == 0) {
|
||||
return SCE_SNAP_MODE_NONE;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (em->bm->totedge == 0) {
|
||||
return SCE_SNAP_MODE_NONE;
|
||||
}
|
||||
}
|
||||
|
||||
float lpmat[4][4];
|
||||
mul_m4_m4m4(lpmat, sctx->runtime.pmat, obmat);
|
||||
|
||||
float dist_px_sq = square_f(*dist_px);
|
||||
|
||||
SnapData_EditMesh *sod = snap_object_data_editmesh_get(sctx, ob_eval, em);
|
||||
|
||||
/* Test BoundBox */
|
||||
|
||||
/* 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 SCE_SNAP_MODE_NONE;
|
||||
}
|
||||
|
||||
if (sctx->runtime.snap_to_flag & SCE_SNAP_MODE_VERTEX) {
|
||||
BVHTreeFromEditMesh treedata{};
|
||||
treedata.tree = sod->bvhtree[0];
|
||||
|
||||
if (treedata.tree == nullptr) {
|
||||
if (sctx->callbacks.edit_mesh.test_vert_fn) {
|
||||
blender::BitVector<> verts_mask(em->bm->totvert);
|
||||
const int verts_num_active = BM_iter_mesh_bitmap_from_filter(
|
||||
BM_VERTS_OF_MESH,
|
||||
em->bm,
|
||||
verts_mask,
|
||||
(bool (*)(BMElem *, void *))sctx->callbacks.edit_mesh.test_vert_fn,
|
||||
sctx->callbacks.edit_mesh.user_data);
|
||||
|
||||
bvhtree_from_editmesh_verts_ex(&treedata, em, verts_mask, verts_num_active, 0.0f, 2, 6);
|
||||
}
|
||||
else {
|
||||
BKE_bvhtree_from_editmesh_get(&treedata,
|
||||
em,
|
||||
2,
|
||||
BVHTREE_FROM_EM_VERTS,
|
||||
/* WORKAROUND: avoid updating while transforming. */
|
||||
G.moving ? nullptr : &sod->mesh_runtime->bvh_cache,
|
||||
&sod->mesh_runtime->eval_mutex);
|
||||
}
|
||||
sod->bvhtree[0] = treedata.tree;
|
||||
sod->cached[0] = treedata.cached;
|
||||
}
|
||||
}
|
||||
|
||||
if (sctx->runtime.snap_to_flag & SCE_SNAP_MODE_EDGE) {
|
||||
BVHTreeFromEditMesh treedata{};
|
||||
treedata.tree = sod->bvhtree[1];
|
||||
|
||||
if (treedata.tree == nullptr) {
|
||||
if (sctx->callbacks.edit_mesh.test_edge_fn) {
|
||||
blender::BitVector<> edges_mask(em->bm->totedge);
|
||||
const int edges_num_active = BM_iter_mesh_bitmap_from_filter(
|
||||
BM_EDGES_OF_MESH,
|
||||
em->bm,
|
||||
edges_mask,
|
||||
(bool (*)(BMElem *, void *))sctx->callbacks.edit_mesh.test_edge_fn,
|
||||
sctx->callbacks.edit_mesh.user_data);
|
||||
|
||||
bvhtree_from_editmesh_edges_ex(&treedata, em, edges_mask, edges_num_active, 0.0f, 2, 6);
|
||||
}
|
||||
else {
|
||||
BKE_bvhtree_from_editmesh_get(&treedata,
|
||||
em,
|
||||
2,
|
||||
BVHTREE_FROM_EM_EDGES,
|
||||
/* WORKAROUND: avoid updating while transforming. */
|
||||
G.moving ? nullptr : &sod->mesh_runtime->bvh_cache,
|
||||
&sod->mesh_runtime->eval_mutex);
|
||||
}
|
||||
sod->bvhtree[1] = treedata.tree;
|
||||
sod->cached[1] = treedata.cached;
|
||||
}
|
||||
}
|
||||
|
||||
Nearest2dUserData nearest2d;
|
||||
nearest2d_data_init_editmesh(sod->treedata_editmesh.em,
|
||||
sctx->runtime.view_proj == VIEW_PROJ_PERSP,
|
||||
params->use_backface_culling,
|
||||
&nearest2d);
|
||||
|
||||
BVHTreeNearest nearest{};
|
||||
nearest.index = -1;
|
||||
nearest.dist_sq = dist_px_sq;
|
||||
|
||||
eSnapMode elem = SCE_SNAP_MODE_VERTEX;
|
||||
|
||||
float tobmat[4][4], clip_planes_local[MAX_CLIPPLANE_LEN][4];
|
||||
transpose_m4_m4(tobmat, obmat);
|
||||
|
||||
for (int i = sctx->runtime.clip_plane_len; i--;) {
|
||||
mul_v4_m4v4(clip_planes_local[i], tobmat, sctx->runtime.clip_plane[i]);
|
||||
}
|
||||
|
||||
if (sod->bvhtree[0] && (sctx->runtime.snap_to_flag & SCE_SNAP_MODE_VERTEX)) {
|
||||
BM_mesh_elem_table_ensure(em->bm, BM_VERT);
|
||||
BM_mesh_elem_index_ensure(em->bm, BM_VERT);
|
||||
BLI_bvhtree_find_nearest_projected(sod->bvhtree[0],
|
||||
lpmat,
|
||||
sctx->runtime.win_size,
|
||||
sctx->runtime.mval,
|
||||
clip_planes_local,
|
||||
sctx->runtime.clip_plane_len,
|
||||
&nearest,
|
||||
cb_snap_vert,
|
||||
&nearest2d);
|
||||
}
|
||||
|
||||
if (sod->bvhtree[1] && (sctx->runtime.snap_to_flag & SCE_SNAP_MODE_EDGE)) {
|
||||
int last_index = nearest.index;
|
||||
nearest.index = -1;
|
||||
BM_mesh_elem_table_ensure(em->bm, BM_EDGE | BM_VERT);
|
||||
BM_mesh_elem_index_ensure(em->bm, BM_EDGE | BM_VERT);
|
||||
BLI_bvhtree_find_nearest_projected(sod->bvhtree[1],
|
||||
lpmat,
|
||||
sctx->runtime.win_size,
|
||||
sctx->runtime.mval,
|
||||
clip_planes_local,
|
||||
sctx->runtime.clip_plane_len,
|
||||
&nearest,
|
||||
cb_snap_edge,
|
||||
&nearest2d);
|
||||
|
||||
if (nearest.index != -1) {
|
||||
elem = SCE_SNAP_MODE_EDGE;
|
||||
}
|
||||
else {
|
||||
nearest.index = last_index;
|
||||
}
|
||||
}
|
||||
|
||||
if (nearest.index != -1) {
|
||||
*dist_px = sqrtf(nearest.dist_sq);
|
||||
|
||||
copy_v3_v3(r_loc, nearest.co);
|
||||
mul_m4_v3(obmat, r_loc);
|
||||
if (r_no) {
|
||||
float imat[4][4];
|
||||
invert_m4_m4(imat, obmat);
|
||||
|
||||
copy_v3_v3(r_no, nearest.no);
|
||||
mul_transposed_mat3_m4_v3(imat, r_no);
|
||||
normalize_v3(r_no);
|
||||
}
|
||||
if (r_index) {
|
||||
*r_index = nearest.index;
|
||||
}
|
||||
|
||||
return elem;
|
||||
}
|
||||
|
||||
return SCE_SNAP_MODE_NONE;
|
||||
}
|
||||
|
||||
/** \} */
|
||||
676
source/blender/editors/transform/transform_snap_object_mesh.cc
Normal file
676
source/blender/editors/transform/transform_snap_object_mesh.cc
Normal file
@@ -0,0 +1,676 @@
|
||||
/* SPDX-FileCopyrightText: 2023 Blender Foundation
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup edtransform
|
||||
*/
|
||||
|
||||
#include "BLI_math.h"
|
||||
#include "BLI_math_matrix_types.hh"
|
||||
|
||||
#include "BKE_bvhutils.h"
|
||||
#include "BKE_editmesh.h"
|
||||
#include "BKE_mesh.hh"
|
||||
#include "BKE_object.h"
|
||||
|
||||
#include "ED_transform_snap_object_context.h"
|
||||
|
||||
#include "transform_snap_object.hh"
|
||||
|
||||
using blender::float3;
|
||||
using blender::Span;
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Snap Object Data
|
||||
* \{ */
|
||||
|
||||
static void snap_object_data_mesh_get(const Mesh *me_eval,
|
||||
bool use_hide,
|
||||
BVHTreeFromMesh *r_treedata)
|
||||
{
|
||||
const Span<float3> vert_positions = me_eval->vert_positions();
|
||||
const blender::OffsetIndices polys = me_eval->polys();
|
||||
const Span<int> corner_verts = me_eval->corner_verts();
|
||||
|
||||
/* The BVHTree from looptris is always required. */
|
||||
BKE_bvhtree_from_mesh_get(
|
||||
r_treedata, me_eval, use_hide ? BVHTREE_FROM_LOOPTRI_NO_HIDDEN : BVHTREE_FROM_LOOPTRI, 4);
|
||||
|
||||
BLI_assert(reinterpret_cast<const float3 *>(r_treedata->vert_positions) ==
|
||||
vert_positions.data());
|
||||
BLI_assert(r_treedata->corner_verts == corner_verts.data());
|
||||
BLI_assert(!polys.data() || r_treedata->looptri);
|
||||
BLI_assert(!r_treedata->tree || r_treedata->looptri);
|
||||
|
||||
UNUSED_VARS_NDEBUG(vert_positions, polys, corner_verts);
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Ray Cast Functions
|
||||
* \{ */
|
||||
|
||||
/* Store all ray-hits
|
||||
* Support for storing all depths, not just the first (ray-cast 'all'). */
|
||||
|
||||
/* Callback to ray-cast with back-face culling (#Mesh). */
|
||||
static void mesh_looptri_raycast_backface_culling_cb(void *userdata,
|
||||
int index,
|
||||
const BVHTreeRay *ray,
|
||||
BVHTreeRayHit *hit)
|
||||
{
|
||||
const BVHTreeFromMesh *data = (BVHTreeFromMesh *)userdata;
|
||||
const float(*vert_positions)[3] = data->vert_positions;
|
||||
const MLoopTri *lt = &data->looptri[index];
|
||||
const float *vtri_co[3] = {
|
||||
vert_positions[data->corner_verts[lt->tri[0]]],
|
||||
vert_positions[data->corner_verts[lt->tri[1]]],
|
||||
vert_positions[data->corner_verts[lt->tri[2]]],
|
||||
};
|
||||
float dist = bvhtree_ray_tri_intersection(ray, hit->dist, UNPACK3(vtri_co));
|
||||
|
||||
if (dist >= 0 && dist < hit->dist) {
|
||||
float no[3];
|
||||
if (raycast_tri_backface_culling_test(ray->direction, UNPACK3(vtri_co), no)) {
|
||||
hit->index = index;
|
||||
hit->dist = dist;
|
||||
madd_v3_v3v3fl(hit->co, ray->origin, ray->direction, dist);
|
||||
normalize_v3_v3(hit->no, no);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool raycastMesh(const SnapObjectParams *params,
|
||||
const float ray_start[3],
|
||||
const float ray_dir[3],
|
||||
Object *ob_eval,
|
||||
const Mesh *me_eval,
|
||||
const float obmat[4][4],
|
||||
const uint ob_index,
|
||||
bool use_hide,
|
||||
/* read/write args */
|
||||
float *ray_depth,
|
||||
/* return args */
|
||||
float r_loc[3],
|
||||
float r_no[3],
|
||||
int *r_index,
|
||||
ListBase *r_hit_list)
|
||||
{
|
||||
bool retval = false;
|
||||
|
||||
if (me_eval->totpoly == 0) {
|
||||
return retval;
|
||||
}
|
||||
|
||||
float imat[4][4];
|
||||
float ray_start_local[3], ray_normal_local[3];
|
||||
float local_scale, local_depth, len_diff = 0.0f;
|
||||
|
||||
invert_m4_m4(imat, obmat);
|
||||
|
||||
copy_v3_v3(ray_start_local, ray_start);
|
||||
copy_v3_v3(ray_normal_local, ray_dir);
|
||||
|
||||
mul_m4_v3(imat, ray_start_local);
|
||||
mul_mat3_m4_v3(imat, ray_normal_local);
|
||||
|
||||
/* local scale in normal direction */
|
||||
local_scale = normalize_v3(ray_normal_local);
|
||||
local_depth = *ray_depth;
|
||||
if (local_depth != BVH_RAYCAST_DIST_MAX) {
|
||||
local_depth *= local_scale;
|
||||
}
|
||||
|
||||
/* Test BoundBox */
|
||||
if (ob_eval->data == me_eval) {
|
||||
const BoundBox *bb = BKE_object_boundbox_get(ob_eval);
|
||||
if (bb) {
|
||||
/* was BKE_boundbox_ray_hit_check, see: cf6ca226fa58 */
|
||||
if (!isect_ray_aabb_v3_simple(
|
||||
ray_start_local, ray_normal_local, bb->vec[0], bb->vec[6], &len_diff, nullptr))
|
||||
{
|
||||
return retval;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* We pass a temp ray_start, set from object's boundbox, to avoid precision issues with
|
||||
* very far away ray_start values (as returned in case of ortho view3d), see #50486, #38358.
|
||||
*/
|
||||
if (len_diff > 400.0f) {
|
||||
/* Make temporary start point a bit away from bounding-box hit point. */
|
||||
len_diff -= local_scale;
|
||||
madd_v3_v3fl(ray_start_local, ray_normal_local, len_diff);
|
||||
local_depth -= len_diff;
|
||||
}
|
||||
else {
|
||||
len_diff = 0.0f;
|
||||
}
|
||||
|
||||
BVHTreeFromMesh treedata;
|
||||
snap_object_data_mesh_get(me_eval, use_hide, &treedata);
|
||||
|
||||
const blender::Span<int> looptri_polys = me_eval->looptri_polys();
|
||||
|
||||
if (treedata.tree == nullptr) {
|
||||
return retval;
|
||||
}
|
||||
|
||||
float timat[3][3]; /* transpose inverse matrix for normals */
|
||||
transpose_m3_m4(timat, imat);
|
||||
|
||||
BLI_assert(treedata.raycast_callback != nullptr);
|
||||
if (r_hit_list) {
|
||||
RayCastAll_Data data;
|
||||
|
||||
data.bvhdata = &treedata;
|
||||
data.raycast_callback = treedata.raycast_callback;
|
||||
data.obmat = obmat;
|
||||
data.timat = timat;
|
||||
data.len_diff = len_diff;
|
||||
data.local_scale = local_scale;
|
||||
data.ob_eval = ob_eval;
|
||||
data.ob_uuid = ob_index;
|
||||
data.hit_list = r_hit_list;
|
||||
data.retval = retval;
|
||||
|
||||
BLI_bvhtree_ray_cast_all(
|
||||
treedata.tree, ray_start_local, ray_normal_local, 0.0f, *ray_depth, raycast_all_cb, &data);
|
||||
|
||||
retval = data.retval;
|
||||
}
|
||||
else {
|
||||
BVHTreeRayHit hit{};
|
||||
hit.index = -1;
|
||||
hit.dist = local_depth;
|
||||
|
||||
if (BLI_bvhtree_ray_cast(treedata.tree,
|
||||
ray_start_local,
|
||||
ray_normal_local,
|
||||
0.0f,
|
||||
&hit,
|
||||
params->use_backface_culling ?
|
||||
mesh_looptri_raycast_backface_culling_cb :
|
||||
treedata.raycast_callback,
|
||||
&treedata) != -1)
|
||||
{
|
||||
hit.dist += len_diff;
|
||||
hit.dist /= local_scale;
|
||||
if (hit.dist <= *ray_depth) {
|
||||
*ray_depth = hit.dist;
|
||||
copy_v3_v3(r_loc, hit.co);
|
||||
|
||||
/* Back to world-space. */
|
||||
mul_m4_v3(obmat, r_loc);
|
||||
|
||||
if (r_no) {
|
||||
copy_v3_v3(r_no, hit.no);
|
||||
mul_m3_v3(timat, r_no);
|
||||
normalize_v3(r_no);
|
||||
}
|
||||
|
||||
retval = true;
|
||||
|
||||
if (r_index) {
|
||||
*r_index = looptri_polys[hit.index];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Surface Snap Functions
|
||||
* \{ */
|
||||
|
||||
bool nearest_world_mesh(SnapObjectContext *sctx,
|
||||
const SnapObjectParams *params,
|
||||
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_get(me_eval, use_hide, &treedata);
|
||||
if (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);
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Callbacks
|
||||
* \{ */
|
||||
|
||||
static void cb_snap_edge_verts(void *userdata,
|
||||
int index,
|
||||
const DistProjectedAABBPrecalc *precalc,
|
||||
const float (*clip_plane)[4],
|
||||
const int clip_plane_len,
|
||||
BVHTreeNearest *nearest)
|
||||
{
|
||||
Nearest2dUserData *data = static_cast<Nearest2dUserData *>(userdata);
|
||||
|
||||
int vindex[2];
|
||||
data->get_edge_verts_index(index, data, vindex);
|
||||
|
||||
for (int i = 2; i--;) {
|
||||
if (vindex[i] == nearest->index) {
|
||||
continue;
|
||||
}
|
||||
cb_snap_vert(userdata, vindex[i], precalc, clip_plane, clip_plane_len, nearest);
|
||||
}
|
||||
}
|
||||
|
||||
static void cb_snap_tri_edges(void *userdata,
|
||||
int index,
|
||||
const DistProjectedAABBPrecalc *precalc,
|
||||
const float (*clip_plane)[4],
|
||||
const int clip_plane_len,
|
||||
BVHTreeNearest *nearest)
|
||||
{
|
||||
Nearest2dUserData *data = static_cast<Nearest2dUserData *>(userdata);
|
||||
|
||||
if (data->use_backface_culling) {
|
||||
int vindex[3];
|
||||
data->get_tri_verts_index(index, data, vindex);
|
||||
|
||||
const float *t0, *t1, *t2;
|
||||
data->get_vert_co(vindex[0], data, &t0);
|
||||
data->get_vert_co(vindex[1], data, &t1);
|
||||
data->get_vert_co(vindex[2], data, &t2);
|
||||
float dummy[3];
|
||||
if (raycast_tri_backface_culling_test(precalc->ray_direction, t0, t1, t2, dummy)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
int eindex[3];
|
||||
data->get_tri_edges_index(index, data, eindex);
|
||||
for (int i = 3; i--;) {
|
||||
if (eindex[i] != -1) {
|
||||
if (eindex[i] == nearest->index) {
|
||||
continue;
|
||||
}
|
||||
cb_snap_edge(userdata, eindex[i], precalc, clip_plane, clip_plane_len, nearest);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void cb_snap_tri_verts(void *userdata,
|
||||
int index,
|
||||
const DistProjectedAABBPrecalc *precalc,
|
||||
const float (*clip_plane)[4],
|
||||
const int clip_plane_len,
|
||||
BVHTreeNearest *nearest)
|
||||
{
|
||||
Nearest2dUserData *data = static_cast<Nearest2dUserData *>(userdata);
|
||||
|
||||
int vindex[3];
|
||||
data->get_tri_verts_index(index, data, vindex);
|
||||
|
||||
if (data->use_backface_culling) {
|
||||
const float *t0, *t1, *t2;
|
||||
data->get_vert_co(vindex[0], data, &t0);
|
||||
data->get_vert_co(vindex[1], data, &t1);
|
||||
data->get_vert_co(vindex[2], data, &t2);
|
||||
float dummy[3];
|
||||
if (raycast_tri_backface_culling_test(precalc->ray_direction, t0, t1, t2, dummy)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 3; i--;) {
|
||||
if (vindex[i] == nearest->index) {
|
||||
continue;
|
||||
}
|
||||
cb_snap_vert(userdata, vindex[i], precalc, clip_plane, clip_plane_len, nearest);
|
||||
}
|
||||
}
|
||||
|
||||
static void cb_mvert_co_get(const int index, const Nearest2dUserData *data, const float **r_co)
|
||||
{
|
||||
*r_co = data->vert_positions[index];
|
||||
}
|
||||
|
||||
static void cb_mvert_no_copy(const int index, const Nearest2dUserData *data, float r_no[3])
|
||||
{
|
||||
copy_v3_v3(r_no, data->vert_normals[index]);
|
||||
}
|
||||
|
||||
static void cb_medge_verts_get(const int index, const Nearest2dUserData *data, int r_v_index[2])
|
||||
{
|
||||
const blender::int2 &edge = data->edges[index];
|
||||
|
||||
r_v_index[0] = edge[0];
|
||||
r_v_index[1] = edge[1];
|
||||
}
|
||||
|
||||
static void cb_mlooptri_edges_get(const int index, const Nearest2dUserData *data, int r_v_index[3])
|
||||
{
|
||||
const blender::int2 *edges = data->edges;
|
||||
const int *corner_verts = data->corner_verts;
|
||||
const int *corner_edges = data->corner_edges;
|
||||
const MLoopTri *lt = &data->looptris[index];
|
||||
for (int j = 2, j_next = 0; j_next < 3; j = j_next++) {
|
||||
const blender::int2 &edge = edges[corner_edges[lt->tri[j]]];
|
||||
const int tri_edge[2] = {corner_verts[lt->tri[j]], corner_verts[lt->tri[j_next]]};
|
||||
if (ELEM(edge[0], tri_edge[0], tri_edge[1]) && ELEM(edge[1], tri_edge[0], tri_edge[1])) {
|
||||
// printf("real edge found\n");
|
||||
r_v_index[j] = corner_edges[lt->tri[j]];
|
||||
}
|
||||
else {
|
||||
r_v_index[j] = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void cb_mlooptri_verts_get(const int index, const Nearest2dUserData *data, int r_v_index[3])
|
||||
{
|
||||
const int *corner_verts = data->corner_verts;
|
||||
const MLoopTri *looptri = &data->looptris[index];
|
||||
|
||||
r_v_index[0] = corner_verts[looptri->tri[0]];
|
||||
r_v_index[1] = corner_verts[looptri->tri[1]];
|
||||
r_v_index[2] = corner_verts[looptri->tri[2]];
|
||||
}
|
||||
|
||||
void nearest2d_data_init_mesh(const Mesh *mesh,
|
||||
bool is_persp,
|
||||
bool use_backface_culling,
|
||||
Nearest2dUserData *r_nearest2d)
|
||||
{
|
||||
r_nearest2d->get_vert_co = cb_mvert_co_get;
|
||||
r_nearest2d->get_edge_verts_index = cb_medge_verts_get;
|
||||
r_nearest2d->copy_vert_no = cb_mvert_no_copy;
|
||||
r_nearest2d->get_tri_verts_index = cb_mlooptri_verts_get;
|
||||
r_nearest2d->get_tri_edges_index = cb_mlooptri_edges_get;
|
||||
|
||||
r_nearest2d->vert_positions = mesh->vert_positions().data();
|
||||
r_nearest2d->vert_normals = mesh->vert_normals().data();
|
||||
r_nearest2d->edges = mesh->edges().data();
|
||||
r_nearest2d->corner_verts = mesh->corner_verts().data();
|
||||
r_nearest2d->corner_edges = mesh->corner_edges().data();
|
||||
r_nearest2d->looptris = mesh->looptris().data();
|
||||
|
||||
r_nearest2d->is_persp = is_persp;
|
||||
r_nearest2d->use_backface_culling = use_backface_culling;
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Internal Object Snapping API
|
||||
* \{ */
|
||||
|
||||
eSnapMode snap_polygon_mesh(SnapObjectContext *sctx,
|
||||
const SnapObjectParams *params,
|
||||
const Mesh *mesh,
|
||||
const float obmat[4][4],
|
||||
float clip_planes_local[MAX_CLIPPLANE_LEN][4],
|
||||
/* read/write args */
|
||||
float *dist_px,
|
||||
/* return args */
|
||||
float r_loc[3],
|
||||
float r_no[3],
|
||||
int *r_index)
|
||||
{
|
||||
eSnapMode elem = SCE_SNAP_MODE_NONE;
|
||||
|
||||
float lpmat[4][4];
|
||||
mul_m4_m4m4(lpmat, sctx->runtime.pmat, obmat);
|
||||
|
||||
DistProjectedAABBPrecalc neasrest_precalc;
|
||||
dist_squared_to_projected_aabb_precalc(
|
||||
&neasrest_precalc, lpmat, sctx->runtime.win_size, sctx->runtime.mval);
|
||||
|
||||
BVHTreeNearest nearest{};
|
||||
nearest.index = -1;
|
||||
nearest.dist_sq = square_f(*dist_px);
|
||||
|
||||
Nearest2dUserData nearest2d;
|
||||
nearest2d_data_init_mesh(
|
||||
mesh, sctx->runtime.view_proj == VIEW_PROJ_PERSP, params->use_backface_culling, &nearest2d);
|
||||
|
||||
const blender::IndexRange poly = mesh->polys()[sctx->ret.index];
|
||||
|
||||
if (sctx->runtime.snap_to_flag & SCE_SNAP_MODE_EDGE) {
|
||||
elem = SCE_SNAP_MODE_EDGE;
|
||||
BLI_assert(nearest2d.edges != nullptr);
|
||||
const int *poly_edges = &nearest2d.corner_edges[poly.start()];
|
||||
for (int i = poly.size(); i--;) {
|
||||
cb_snap_edge(&nearest2d,
|
||||
poly_edges[i],
|
||||
&neasrest_precalc,
|
||||
clip_planes_local,
|
||||
sctx->runtime.clip_plane_len,
|
||||
&nearest);
|
||||
}
|
||||
}
|
||||
else {
|
||||
elem = SCE_SNAP_MODE_VERTEX;
|
||||
const int *poly_verts = &nearest2d.corner_verts[poly.start()];
|
||||
for (int i = poly.size(); i--;) {
|
||||
cb_snap_vert(&nearest2d,
|
||||
poly_verts[i],
|
||||
&neasrest_precalc,
|
||||
clip_planes_local,
|
||||
sctx->runtime.clip_plane_len,
|
||||
&nearest);
|
||||
}
|
||||
}
|
||||
|
||||
if (nearest.index != -1) {
|
||||
*dist_px = sqrtf(nearest.dist_sq);
|
||||
|
||||
mul_m4_v3(obmat, nearest.co);
|
||||
copy_v3_v3(r_loc, nearest.co);
|
||||
|
||||
{
|
||||
float imat[4][4];
|
||||
invert_m4_m4(imat, obmat);
|
||||
mul_transposed_mat3_m4_v3(imat, nearest.no);
|
||||
normalize_v3(nearest.no);
|
||||
|
||||
copy_v3_v3(r_no, nearest.no);
|
||||
}
|
||||
|
||||
*r_index = nearest.index;
|
||||
return elem;
|
||||
}
|
||||
|
||||
return SCE_SNAP_MODE_NONE;
|
||||
}
|
||||
|
||||
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);
|
||||
if (me_eval->totvert == 0) {
|
||||
return SCE_SNAP_MODE_NONE;
|
||||
}
|
||||
if (me_eval->totedge == 0 && !(sctx->runtime.snap_to_flag & SCE_SNAP_MODE_VERTEX)) {
|
||||
return SCE_SNAP_MODE_NONE;
|
||||
}
|
||||
|
||||
float lpmat[4][4];
|
||||
mul_m4_m4m4(lpmat, sctx->runtime.pmat, obmat);
|
||||
|
||||
float dist_px_sq = square_f(*dist_px);
|
||||
|
||||
/* Test BoundBox */
|
||||
if (ob_eval->data == me_eval) {
|
||||
const BoundBox *bb = BKE_object_boundbox_get(ob_eval);
|
||||
if (!snap_bound_box_check_dist(
|
||||
bb->vec[0], bb->vec[6], lpmat, sctx->runtime.win_size, sctx->runtime.mval, dist_px_sq))
|
||||
{
|
||||
return SCE_SNAP_MODE_NONE;
|
||||
}
|
||||
}
|
||||
|
||||
BVHTreeFromMesh treedata, treedata_dummy;
|
||||
snap_object_data_mesh_get(me_eval, use_hide, &treedata);
|
||||
|
||||
BVHTree *bvhtree[2] = {nullptr};
|
||||
bvhtree[0] = BKE_bvhtree_from_mesh_get(&treedata_dummy, me_eval, BVHTREE_FROM_LOOSEEDGES, 2);
|
||||
BLI_assert(treedata_dummy.cached);
|
||||
if (sctx->runtime.snap_to_flag & SCE_SNAP_MODE_VERTEX) {
|
||||
bvhtree[1] = BKE_bvhtree_from_mesh_get(&treedata_dummy, me_eval, BVHTREE_FROM_LOOSEVERTS, 2);
|
||||
BLI_assert(treedata_dummy.cached);
|
||||
}
|
||||
|
||||
Nearest2dUserData nearest2d;
|
||||
nearest2d_data_init_mesh(me_eval,
|
||||
sctx->runtime.view_proj == VIEW_PROJ_PERSP,
|
||||
params->use_backface_culling,
|
||||
&nearest2d);
|
||||
|
||||
BVHTreeNearest nearest{};
|
||||
nearest.index = -1;
|
||||
nearest.dist_sq = dist_px_sq;
|
||||
|
||||
int last_index = nearest.index;
|
||||
eSnapMode elem = SCE_SNAP_MODE_VERTEX;
|
||||
|
||||
float tobmat[4][4], clip_planes_local[MAX_CLIPPLANE_LEN][4];
|
||||
transpose_m4_m4(tobmat, obmat);
|
||||
for (int i = sctx->runtime.clip_plane_len; i--;) {
|
||||
mul_v4_m4v4(clip_planes_local[i], tobmat, sctx->runtime.clip_plane[i]);
|
||||
}
|
||||
|
||||
if (bvhtree[1]) {
|
||||
BLI_assert(sctx->runtime.snap_to_flag & SCE_SNAP_MODE_VERTEX);
|
||||
/* snap to loose verts */
|
||||
BLI_bvhtree_find_nearest_projected(bvhtree[1],
|
||||
lpmat,
|
||||
sctx->runtime.win_size,
|
||||
sctx->runtime.mval,
|
||||
clip_planes_local,
|
||||
sctx->runtime.clip_plane_len,
|
||||
&nearest,
|
||||
cb_snap_vert,
|
||||
&nearest2d);
|
||||
|
||||
last_index = nearest.index;
|
||||
}
|
||||
|
||||
if (sctx->runtime.snap_to_flag & SCE_SNAP_MODE_EDGE) {
|
||||
if (bvhtree[0]) {
|
||||
/* Snap to loose edges. */
|
||||
BLI_bvhtree_find_nearest_projected(bvhtree[0],
|
||||
lpmat,
|
||||
sctx->runtime.win_size,
|
||||
sctx->runtime.mval,
|
||||
clip_planes_local,
|
||||
sctx->runtime.clip_plane_len,
|
||||
&nearest,
|
||||
cb_snap_edge,
|
||||
&nearest2d);
|
||||
}
|
||||
|
||||
if (treedata.tree) {
|
||||
/* Snap to looptris. */
|
||||
BLI_bvhtree_find_nearest_projected(treedata.tree,
|
||||
lpmat,
|
||||
sctx->runtime.win_size,
|
||||
sctx->runtime.mval,
|
||||
clip_planes_local,
|
||||
sctx->runtime.clip_plane_len,
|
||||
&nearest,
|
||||
cb_snap_tri_edges,
|
||||
&nearest2d);
|
||||
}
|
||||
|
||||
if (last_index != nearest.index) {
|
||||
elem = SCE_SNAP_MODE_EDGE;
|
||||
}
|
||||
}
|
||||
else {
|
||||
BLI_assert(sctx->runtime.snap_to_flag & SCE_SNAP_MODE_VERTEX);
|
||||
if (bvhtree[0]) {
|
||||
/* Snap to loose edge verts. */
|
||||
BLI_bvhtree_find_nearest_projected(bvhtree[0],
|
||||
lpmat,
|
||||
sctx->runtime.win_size,
|
||||
sctx->runtime.mval,
|
||||
clip_planes_local,
|
||||
sctx->runtime.clip_plane_len,
|
||||
&nearest,
|
||||
cb_snap_edge_verts,
|
||||
&nearest2d);
|
||||
}
|
||||
|
||||
if (treedata.tree) {
|
||||
/* Snap to looptri verts. */
|
||||
BLI_bvhtree_find_nearest_projected(treedata.tree,
|
||||
lpmat,
|
||||
sctx->runtime.win_size,
|
||||
sctx->runtime.mval,
|
||||
clip_planes_local,
|
||||
sctx->runtime.clip_plane_len,
|
||||
&nearest,
|
||||
cb_snap_tri_verts,
|
||||
&nearest2d);
|
||||
}
|
||||
}
|
||||
|
||||
if (nearest.index != -1) {
|
||||
*dist_px = sqrtf(nearest.dist_sq);
|
||||
|
||||
copy_v3_v3(r_loc, nearest.co);
|
||||
mul_m4_v3(obmat, r_loc);
|
||||
|
||||
if (r_no) {
|
||||
float imat[4][4];
|
||||
invert_m4_m4(imat, obmat);
|
||||
|
||||
copy_v3_v3(r_no, nearest.no);
|
||||
mul_transposed_mat3_m4_v3(imat, r_no);
|
||||
normalize_v3(r_no);
|
||||
}
|
||||
if (r_index) {
|
||||
*r_index = nearest.index;
|
||||
}
|
||||
|
||||
return elem;
|
||||
}
|
||||
|
||||
return SCE_SNAP_MODE_NONE;
|
||||
}
|
||||
|
||||
/** \} */
|
||||
Reference in New Issue
Block a user