Blender V4.3
transform_snap_object_mesh.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
9#include "BLI_math_matrix.hh"
10#include "BLI_math_vector.h"
11
12#include "BKE_bvhutils.hh"
13#include "BKE_mesh.hh"
14
16#include "ED_view3d.hh"
17
19
20#ifdef DEBUG_SNAP_TIME
21# if WIN32 and NDEBUG
22# pragma optimize("t", on)
23# endif
24#endif
25
26using namespace blender;
27
28/* -------------------------------------------------------------------- */
32static void snap_object_data_mesh_get(const Mesh *mesh_eval,
33 bool skip_hidden,
34 BVHTreeFromMesh *r_treedata)
35{
36 /* The BVHTree from corner_tris is always required. */
38 mesh_eval,
41 4);
42}
43
46/* -------------------------------------------------------------------- */
50/* Store all ray-hits
51 * Support for storing all depths, not just the first (ray-cast 'all'). */
52
53/* Callback to ray-cast with back-face culling (#Mesh). */
55 int index,
56 const BVHTreeRay *ray,
57 BVHTreeRayHit *hit)
58{
59 const BVHTreeFromMesh *data = (BVHTreeFromMesh *)userdata;
60 const blender::Span<blender::float3> positions = data->vert_positions;
61 const int3 &tri = data->corner_tris[index];
62 const float *vtri_co[3] = {
63 positions[data->corner_verts[tri[0]]],
64 positions[data->corner_verts[tri[1]]],
65 positions[data->corner_verts[tri[2]]],
66 };
67 float dist = bvhtree_ray_tri_intersection(ray, hit->dist, UNPACK3(vtri_co));
68
69 if (dist >= 0 && dist < hit->dist) {
70 float no[3];
71 if (raycast_tri_backface_culling_test(ray->direction, UNPACK3(vtri_co), no)) {
72 hit->index = index;
73 hit->dist = dist;
74 madd_v3_v3v3fl(hit->co, ray->origin, ray->direction, dist);
75 normalize_v3_v3(hit->no, no);
76 }
77 }
78}
79
81 const Object *ob_eval,
82 const Mesh *mesh_eval,
83 const float4x4 &obmat,
84 const uint ob_index,
85 bool use_hide)
86{
87 bool retval = false;
88
89 if (mesh_eval->faces_num == 0) {
90 return retval;
91 }
92
93 float4x4 imat = math::invert(obmat);
94 float3 ray_start_local = math::transform_point(imat, sctx->runtime.ray_start);
95 float3 ray_normal_local = math::transform_direction(imat, sctx->runtime.ray_dir);
96 float local_scale, local_depth, len_diff = 0.0f;
97
98 /* Local scale in normal direction. */
99 ray_normal_local = math::normalize_and_get_length(ray_normal_local, local_scale);
100
101 const bool is_in_front = (sctx->runtime.params.occlusion_test == SNAP_OCCLUSION_AS_SEEM) &&
102 (ob_eval->dtx & OB_DRAW_IN_FRONT);
103 const float depth_max = is_in_front ? sctx->ret.ray_depth_max_in_front : sctx->ret.ray_depth_max;
104 local_depth = depth_max;
105 if (local_depth != BVH_RAYCAST_DIST_MAX) {
106 local_depth *= local_scale;
107 }
108
109 /* Test bounding box. */
110 if (std::optional<Bounds<float3>> bounds = mesh_eval->bounds_min_max()) {
111 /* Was #BKE_boundbox_ray_hit_check, see: cf6ca226fa58 */
113 ray_start_local, ray_normal_local, bounds->min, bounds->max, &len_diff, nullptr))
114 {
115 return retval;
116 }
117 }
118
119 /* We pass a temp ray_start, set from object's boundbox, to avoid precision issues with
120 * very far away ray_start values (as returned in case of ortho view3d), see #50486, #38358.
121 */
122 if (len_diff > 400.0f) {
123 /* Make temporary start point a bit away from bounding-box hit point. */
124 len_diff -= local_scale;
125 madd_v3_v3fl(ray_start_local, ray_normal_local, len_diff);
126 local_depth -= len_diff;
127 }
128 else {
129 len_diff = 0.0f;
130 }
131
132 BVHTreeFromMesh treedata;
133 snap_object_data_mesh_get(mesh_eval, use_hide, &treedata);
134
135 const blender::Span<int> tri_faces = mesh_eval->corner_tri_faces();
136
137 if (treedata.tree == nullptr) {
138 return retval;
139 }
140
141 BLI_assert(treedata.raycast_callback != nullptr);
142 if (sctx->ret.hit_list) {
144
145 data.bvhdata = &treedata;
146 data.raycast_callback = treedata.raycast_callback;
147 data.obmat = &obmat;
148 data.len_diff = len_diff;
149 data.local_scale = local_scale;
150 data.ob_uuid = ob_index;
151 data.hit_list = sctx->ret.hit_list;
152
153 void *hit_last_prev = data.hit_list->last;
155 treedata.tree, ray_start_local, ray_normal_local, 0.0f, depth_max, raycast_all_cb, &data);
156
157 retval = hit_last_prev != data.hit_list->last;
158 }
159 else {
160 BVHTreeRayHit hit{};
161 hit.index = -1;
162 hit.dist = local_depth;
163
164 if (BLI_bvhtree_ray_cast(treedata.tree,
165 ray_start_local,
166 ray_normal_local,
167 0.0f,
168 &hit,
171 treedata.raycast_callback,
172 &treedata) != -1)
173 {
174 hit.dist += len_diff;
175 hit.dist /= local_scale;
176 if (hit.dist <= depth_max) {
177 hit.index = tri_faces[hit.index];
178 retval = true;
179 }
180 SnapData::register_result_raycast(sctx, ob_eval, &mesh_eval->id, obmat, &hit, is_in_front);
181 }
182 }
183
184 return retval;
185}
186
189/* -------------------------------------------------------------------- */
194 const Object *ob_eval,
195 const Mesh *mesh_eval,
196 const float4x4 &obmat,
197 bool use_hide)
198{
199 BVHTreeFromMesh treedata;
200 snap_object_data_mesh_get(mesh_eval, use_hide, &treedata);
201 if (treedata.tree == nullptr) {
202 return false;
203 }
204
205 BVHTreeNearest nearest{};
206 nearest.dist_sq = sctx->ret.dist_nearest_sq;
208 sctx, treedata.tree, treedata.nearest_callback, obmat, &treedata, &nearest))
209 {
210 SnapData::register_result(sctx, ob_eval, &mesh_eval->id, obmat, &nearest);
211 return true;
212 }
213 return false;
214}
215
218/* -------------------------------------------------------------------- */
222class SnapData_Mesh : public SnapData {
223 public:
226 const int2 *edges; /* Only used for #BVHTreeFromMeshEdges. */
227 const int *corner_verts;
228 const int *corner_edges;
230
231 SnapData_Mesh(SnapObjectContext *sctx, const Mesh *mesh_eval, const float4x4 &obmat)
232 : SnapData(sctx, obmat)
233 {
234 this->vert_positions = mesh_eval->vert_positions().data();
235 this->vert_normals = mesh_eval->vert_normals().data();
236 this->edges = mesh_eval->edges().data();
237 this->corner_verts = mesh_eval->corner_verts().data();
238 this->corner_edges = mesh_eval->corner_edges().data();
239 this->corner_tris = mesh_eval->corner_tris().data();
240 };
241
242 void get_vert_co(const int index, const float **r_co) override
243 {
244 *r_co = this->vert_positions[index];
245 }
246
247 void get_edge_verts_index(const int index, int r_v_index[2]) override
248 {
249 const blender::int2 &edge = this->edges[index];
250 r_v_index[0] = edge[0];
251 r_v_index[1] = edge[1];
252 }
253
254 void copy_vert_no(const int index, float r_no[3]) override
255 {
256 copy_v3_v3(r_no, this->vert_normals[index]);
257 }
258};
259
260static void cb_snap_edge_verts(void *userdata,
261 int index,
262 const DistProjectedAABBPrecalc *precalc,
263 const float (*clip_plane)[4],
264 const int clip_plane_len,
265 BVHTreeNearest *nearest)
266{
267 SnapData_Mesh *data = static_cast<SnapData_Mesh *>(userdata);
268
269 int vindex[2];
270 data->get_edge_verts_index(index, vindex);
271
272 for (int i = 2; i--;) {
273 if (vindex[i] == nearest->index) {
274 continue;
275 }
276 cb_snap_vert(userdata, vindex[i], precalc, clip_plane, clip_plane_len, nearest);
277 }
278}
279
280static void cb_snap_tri_verts(void *userdata,
281 int index,
282 const DistProjectedAABBPrecalc *precalc,
283 const float (*clip_plane)[4],
284 const int clip_plane_len,
285 BVHTreeNearest *nearest)
286{
287 SnapData_Mesh *data = static_cast<SnapData_Mesh *>(userdata);
288
289 int vindex[3];
290 const int *corner_verts = data->corner_verts;
291 const int3 &tri = data->corner_tris[index];
292 vindex[0] = corner_verts[tri[0]];
293 vindex[1] = corner_verts[tri[1]];
294 vindex[2] = corner_verts[tri[2]];
295
296 if (data->use_backface_culling) {
297 const float3 *vert_positions = data->vert_positions;
298 const float3 &t0 = vert_positions[vindex[0]];
299 const float3 &t1 = vert_positions[vindex[1]];
300 const float3 &t2 = vert_positions[vindex[2]];
301 float dummy[3];
302 if (raycast_tri_backface_culling_test(precalc->ray_direction, t0, t1, t2, dummy)) {
303 return;
304 }
305 }
306
307 for (int i = 3; i--;) {
308 if (vindex[i] == nearest->index) {
309 continue;
310 }
311 cb_snap_vert(userdata, vindex[i], precalc, clip_plane, clip_plane_len, nearest);
312 }
313}
314
315static void cb_snap_tri_edges(void *userdata,
316 int index,
317 const DistProjectedAABBPrecalc *precalc,
318 const float (*clip_plane)[4],
319 const int clip_plane_len,
320 BVHTreeNearest *nearest)
321{
322 SnapData_Mesh *data = static_cast<SnapData_Mesh *>(userdata);
323 const int *corner_verts = data->corner_verts;
324 const int3 &tri = data->corner_tris[index];
325
326 if (data->use_backface_culling) {
327 const float3 *vert_positions = data->vert_positions;
328 const float3 &t0 = vert_positions[corner_verts[tri[0]]];
329 const float3 &t1 = vert_positions[corner_verts[tri[1]]];
330 const float3 &t2 = vert_positions[corner_verts[tri[2]]];
331 float dummy[3];
332 if (raycast_tri_backface_culling_test(precalc->ray_direction, t0, t1, t2, dummy)) {
333 return;
334 }
335 }
336
337 const int2 *edges = data->edges;
338 const int *corner_edges = data->corner_edges;
339 for (int j = 2, j_next = 0; j_next < 3; j = j_next++) {
340 int eindex = corner_edges[tri[j]];
341 const int2 &edge = edges[eindex];
342 const int2 tri_edge = {corner_verts[tri[j]], corner_verts[tri[j_next]]};
343 if (ELEM(edge[0], tri_edge[0], tri_edge[1]) && ELEM(edge[1], tri_edge[0], tri_edge[1])) {
344 if (eindex == nearest->index) {
345 continue;
346 }
347 cb_snap_edge(userdata, eindex, precalc, clip_plane, clip_plane_len, nearest);
348 }
349 }
350}
351
354/* -------------------------------------------------------------------- */
359 const Object *ob_eval,
360 const ID *id,
361 const float4x4 &obmat,
362 eSnapMode snap_to_flag,
363 int face_index)
364{
366
367 const Mesh *mesh_eval = reinterpret_cast<const Mesh *>(id);
368
369 SnapData_Mesh nearest2d(sctx, mesh_eval, obmat);
370 nearest2d.clip_planes_enable(sctx, ob_eval);
371
372 BVHTreeNearest nearest{};
373 nearest.index = -1;
374 nearest.dist_sq = sctx->ret.dist_px_sq;
375
376 const blender::IndexRange face = mesh_eval->faces()[face_index];
377
378 if (snap_to_flag &
380 {
381 /* We return 'Snap to Edge' even if the intent is 'Snap to Edge Midpoitnt' or 'Snap to Edge
382 * Perpendicular'. This avoids complexity. These snap points will be tested in
383 * `snap_edge_points`. */
384 elem = SCE_SNAP_TO_EDGE;
385 BLI_assert(nearest2d.edges != nullptr);
386 const int *face_edges = &nearest2d.corner_edges[face.start()];
387 for (int i = face.size(); i--;) {
388 cb_snap_edge(&nearest2d,
389 face_edges[i],
390 &nearest2d.nearest_precalc,
391 reinterpret_cast<float(*)[4]>(nearest2d.clip_planes.data()),
392 nearest2d.clip_planes.size(),
393 &nearest);
394 }
395 }
396 else {
398 const int *face_verts = &nearest2d.corner_verts[face.start()];
399 for (int i = face.size(); i--;) {
400 cb_snap_vert(&nearest2d,
401 face_verts[i],
402 &nearest2d.nearest_precalc,
403 reinterpret_cast<float(*)[4]>(nearest2d.clip_planes.data()),
404 nearest2d.clip_planes.size(),
405 &nearest);
406 }
407 }
408
409 if (nearest.index != -1) {
410 nearest2d.nearest_point = nearest;
411 nearest2d.register_result(sctx, ob_eval, id);
412 return elem;
413 }
414
415 return SCE_SNAP_TO_NONE;
416}
417
419 const Object *ob_eval,
420 const ID *id,
421 const float4x4 &obmat,
422 float dist_px_sq_orig,
423 int edge_index)
424{
425 SnapData_Mesh nearest2d(sctx, reinterpret_cast<const Mesh *>(id), obmat);
426 eSnapMode elem = nearest2d.snap_edge_points_impl(sctx, edge_index, dist_px_sq_orig);
427 if (nearest2d.nearest_point.index != -2) {
428 nearest2d.register_result(sctx, ob_eval, id);
429 }
430 return elem;
431}
432
433static eSnapMode mesh_snap_mode_supported(const Mesh *mesh, bool skip_hidden)
434{
435 /* When skipping hidden geometry, we still cannot obtain the number of loose verts
436 * until computing #BVHTREE_FROM_LOOSEVERTS_NO_HIDDEN. Therefore, consider #SCE_SNAP_TO_POINT
437 * supported even if the mesh has no loose vertices in this case. */
438 eSnapMode snap_mode_supported = (skip_hidden || mesh->loose_verts().count) ? SCE_SNAP_TO_POINT :
440 if (mesh->faces_num) {
442 }
443 else if (mesh->edges_num) {
444 snap_mode_supported |= SNAP_TO_EDGE_ELEMENTS;
445 }
446
447 return snap_mode_supported;
448}
449
451 const Object *ob_eval,
452 const Mesh *mesh_eval,
453 const float4x4 &obmat,
454 bool skip_hidden,
455 bool is_editmesh,
456 eSnapMode snap_to)
457{
458 BLI_assert(snap_to != SCE_SNAP_TO_FACE);
459 SnapData_Mesh nearest2d(sctx, mesh_eval, obmat);
460 if (is_editmesh) {
461 nearest2d.use_backface_culling = false;
462 }
463
464 if (std::optional<Bounds<float3>> bounds = mesh_eval->bounds_min_max()) {
465 if (!nearest2d.snap_boundbox(bounds->min, bounds->max)) {
466 return SCE_SNAP_TO_NONE;
467 }
468 }
469
470 snap_to &= mesh_snap_mode_supported(mesh_eval, skip_hidden) &
472 if (snap_to == SCE_SNAP_TO_NONE) {
473 return SCE_SNAP_TO_NONE;
474 }
475
476 BVHTreeFromMesh treedata, treedata_dummy;
477 snap_object_data_mesh_get(mesh_eval, skip_hidden, &treedata);
478
479 BVHTree *bvhtree[2] = {nullptr};
480 bvhtree[0] = BKE_bvhtree_from_mesh_get(&treedata_dummy,
481 mesh_eval,
484 2);
485 BLI_assert(treedata_dummy.cached);
486 if (snap_to & SCE_SNAP_TO_POINT) {
487 bvhtree[1] = BKE_bvhtree_from_mesh_get(&treedata_dummy,
488 mesh_eval,
491 2);
492 BLI_assert(treedata_dummy.cached);
493 }
494
495 /* #XRAY_ENABLED can return false even with the XRAY flag enabled, this happens because the
496 * alpha is 1.0 in this case. But even with the alpha being 1.0, the edit mesh is still not
497 * occluded. */
498 const bool skip_occlusion_plane = is_editmesh && XRAY_FLAG_ENABLED(sctx->runtime.v3d);
499 nearest2d.clip_planes_enable(sctx, ob_eval, skip_occlusion_plane);
500
501 BVHTreeNearest nearest{};
502 nearest.index = -1;
503 nearest.dist_sq = sctx->ret.dist_px_sq;
504
505 int last_index = nearest.index;
507
508 if (bvhtree[1]) {
509 BLI_assert(snap_to & SCE_SNAP_TO_POINT);
510 /* Snap to loose verts. */
512 nearest2d.pmat_local.ptr(),
513 sctx->runtime.win_size,
514 sctx->runtime.mval,
515 reinterpret_cast<float(*)[4]>(nearest2d.clip_planes.data()),
516 nearest2d.clip_planes.size(),
517 &nearest,
519 &nearest2d);
520
521 if (nearest.index != -1) {
522 last_index = nearest.index;
523 elem = SCE_SNAP_TO_POINT;
524 }
525 }
526
528 if (bvhtree[0]) {
529 /* Snap to loose edges. */
531 bvhtree[0],
532 nearest2d.pmat_local.ptr(),
533 sctx->runtime.win_size,
534 sctx->runtime.mval,
535 reinterpret_cast<float(*)[4]>(nearest2d.clip_planes.data()),
536 nearest2d.clip_planes.size(),
537 &nearest,
539 &nearest2d);
540 }
541
542 if (treedata.tree) {
543 /* Snap to corner_tris. */
545 treedata.tree,
546 nearest2d.pmat_local.ptr(),
547 sctx->runtime.win_size,
548 sctx->runtime.mval,
549 reinterpret_cast<float(*)[4]>(nearest2d.clip_planes.data()),
550 nearest2d.clip_planes.size(),
551 &nearest,
553 &nearest2d);
554 }
555
556 if (last_index != nearest.index) {
557 elem = SCE_SNAP_TO_EDGE;
558 }
559 }
560 else {
562 if (bvhtree[0]) {
563 /* Snap to loose edges verts. */
565 bvhtree[0],
566 nearest2d.pmat_local.ptr(),
567 sctx->runtime.win_size,
568 sctx->runtime.mval,
569 reinterpret_cast<float(*)[4]>(nearest2d.clip_planes.data()),
570 nearest2d.clip_planes.size(),
571 &nearest,
573 &nearest2d);
574 }
575
576 if (treedata.tree) {
577 /* Snap to corner_tris verts. */
579 treedata.tree,
580 nearest2d.pmat_local.ptr(),
581 sctx->runtime.win_size,
582 sctx->runtime.mval,
583 reinterpret_cast<float(*)[4]>(nearest2d.clip_planes.data()),
584 nearest2d.clip_planes.size(),
585 &nearest,
587 &nearest2d);
588 }
589
590 if (last_index != nearest.index) {
592 }
593 }
594
595 if (nearest.index != -1) {
596 nearest2d.nearest_point = nearest;
597 nearest2d.register_result(sctx, ob_eval, &mesh_eval->id);
598 return elem;
599 }
600
601 return SCE_SNAP_TO_NONE;
602}
603
607 const Object *ob_eval,
608 const ID *id,
609 const float4x4 &obmat,
610 eSnapMode snap_to_flag,
611 bool skip_hidden,
612 bool is_editmesh)
613{
615 const Mesh *mesh_eval = reinterpret_cast<const Mesh *>(id);
616
617 if (snap_to_flag & (SNAP_TO_EDGE_ELEMENTS | SCE_SNAP_TO_POINT)) {
618 elem = snapMesh(sctx, ob_eval, mesh_eval, obmat, skip_hidden, is_editmesh, snap_to_flag);
619 if (elem) {
620 return elem;
621 }
622 }
623
624 if (snap_to_flag & SCE_SNAP_TO_FACE) {
625 if (raycastMesh(sctx, ob_eval, mesh_eval, obmat, sctx->runtime.object_index++, skip_hidden)) {
626 return SCE_SNAP_TO_FACE;
627 }
628 }
629
630 if (snap_to_flag & SCE_SNAP_INDIVIDUAL_NEAREST) {
631 if (nearest_world_mesh(sctx, ob_eval, mesh_eval, obmat, skip_hidden)) {
633 }
634 }
635
636 return SCE_SNAP_TO_NONE;
637}
BVHTree * BKE_bvhtree_from_mesh_get(BVHTreeFromMesh *data, const Mesh *mesh, BVHCacheType bvh_cache_type, int tree_type)
Definition bvhutils.cc:899
@ BVHTREE_FROM_CORNER_TRIS
@ BVHTREE_FROM_CORNER_TRIS_NO_HIDDEN
@ BVHTREE_FROM_LOOSEEDGES
@ BVHTREE_FROM_LOOSEVERTS
@ BVHTREE_FROM_LOOSEEDGES_NO_HIDDEN
@ BVHTREE_FROM_LOOSEVERTS_NO_HIDDEN
float bvhtree_ray_tri_intersection(const BVHTreeRay *ray, float m_dist, const float v0[3], const float v1[3], const float v2[3])
Definition bvhutils.cc:173
#define BLI_assert(a)
Definition BLI_assert.h:50
#define BVH_RAYCAST_DIST_MAX
Definition BLI_kdopbvh.h:92
int BLI_bvhtree_find_nearest_projected(const BVHTree *tree, float projmat[4][4], float winsize[2], float mval[2], float(*clip_planes)[4], int clip_plane_len, BVHTreeNearest *nearest, BVHTree_NearestProjectedCallback callback, void *userdata)
void BLI_bvhtree_ray_cast_all(const BVHTree *tree, const float co[3], const float dir[3], float radius, float hit_dist, BVHTree_RayCastCallback callback, void *userdata)
int BLI_bvhtree_ray_cast(const BVHTree *tree, const float co[3], const float dir[3], float radius, BVHTreeRayHit *hit, BVHTree_RayCastCallback callback, void *userdata)
bool isect_ray_aabb_v3_simple(const float orig[3], const float dir[3], const float bb_min[3], const float bb_max[3], float *tmin, float *tmax)
MINLINE void madd_v3_v3fl(float r[3], const float a[3], float f)
MINLINE void copy_v3_v3(float r[3], const float a[3])
MINLINE float normalize_v3_v3(float r[3], const float a[3])
MINLINE void madd_v3_v3v3fl(float r[3], const float a[3], const float b[3], float f)
unsigned int uint
#define UNPACK3(a)
#define ELEM(...)
@ OB_DRAW_IN_FRONT
@ SCE_SNAP_INDIVIDUAL_NEAREST
@ SCE_SNAP_TO_EDGE
@ SCE_SNAP_TO_FACE
@ SCE_SNAP_TO_EDGE_ENDPOINT
@ SCE_SNAP_TO_EDGE_MIDPOINT
@ SCE_SNAP_TO_EDGE_PERPENDICULAR
@ SCE_SNAP_TO_POINT
@ SCE_SNAP_TO_NONE
#define XRAY_FLAG_ENABLED(v3d)
void get_vert_co(const int index, const float **r_co) override
void get_edge_verts_index(const int index, int r_v_index[2]) override
void copy_vert_no(const int index, float r_no[3]) override
SnapData_Mesh(SnapObjectContext *sctx, const Mesh *mesh_eval, const float4x4 &obmat)
blender::Vector< blender::float4, MAX_CLIPPLANE_LEN+1 > clip_planes
void clip_planes_enable(SnapObjectContext *sctx, const Object *ob_eval, bool skip_occlusion_plane=false)
blender::float4x4 pmat_local
static void register_result_raycast(SnapObjectContext *sctx, const Object *ob_eval, const ID *id_eval, const blender::float4x4 &obmat, const BVHTreeRayHit *hit, const bool is_in_front)
static void register_result(SnapObjectContext *sctx, const Object *ob_eval, const ID *id_eval, const blender::float4x4 &obmat, BVHTreeNearest *r_nearest)
DistProjectedAABBPrecalc nearest_precalc
BVHTreeNearest nearest_point
eSnapMode snap_edge_points_impl(SnapObjectContext *sctx, int edge_index, float dist_px_sq_orig)
bool snap_boundbox(const blender::float3 &min, const blender::float3 &max)
QuaternionBase< T > normalize_and_get_length(const QuaternionBase< T > &q, T &out_length)
CartesianBasis invert(const CartesianBasis &basis)
VecBase< T, 3 > transform_direction(const MatBase< T, 3, 3 > &mat, const VecBase< T, 3 > &direction)
VecBase< T, 3 > transform_point(const CartesianBasis &basis, const VecBase< T, 3 > &v)
BVHTree_RayCastCallback raycast_callback
BVHTree_NearestPointCallback nearest_callback
Definition DNA_ID.h:413
void * last
int faces_num
struct SnapObjectContext::@590 ret
struct SnapObjectContext::@589 runtime
const c_style_mat & ptr() const
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_vert(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, BVHTree *tree, BVHTree_NearestPointCallback nearest_cb, const blender::float4x4 &obmat, void *treedata, BVHTreeNearest *r_nearest)
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])
void raycast_all_cb(void *userdata, int index, const BVHTreeRay *ray, BVHTreeRayHit *hit)
#define SNAP_TO_EDGE_ELEMENTS
static void snap_object_data_mesh_get(const Mesh *mesh_eval, bool skip_hidden, BVHTreeFromMesh *r_treedata)
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)
static eSnapMode mesh_snap_mode_supported(const Mesh *mesh, bool skip_hidden)
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)
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)
eSnapMode snap_object_mesh(SnapObjectContext *sctx, const Object *ob_eval, const ID *id, const float4x4 &obmat, eSnapMode snap_to_flag, bool skip_hidden, bool is_editmesh)
static void mesh_corner_tris_raycast_backface_culling_cb(void *userdata, int index, const BVHTreeRay *ray, BVHTreeRayHit *hit)
eSnapMode snap_edge_points_mesh(SnapObjectContext *sctx, const Object *ob_eval, const ID *id, const float4x4 &obmat, float dist_px_sq_orig, int edge_index)
static eSnapMode snapMesh(SnapObjectContext *sctx, const Object *ob_eval, const Mesh *mesh_eval, const float4x4 &obmat, bool skip_hidden, bool is_editmesh, eSnapMode snap_to)
eSnapMode snap_polygon_mesh(SnapObjectContext *sctx, const Object *ob_eval, const ID *id, const float4x4 &obmat, eSnapMode snap_to_flag, int face_index)
static bool raycastMesh(SnapObjectContext *sctx, const Object *ob_eval, const Mesh *mesh_eval, const float4x4 &obmat, const uint ob_index, bool use_hide)
static bool nearest_world_mesh(SnapObjectContext *sctx, const Object *ob_eval, const Mesh *mesh_eval, const float4x4 &obmat, bool use_hide)