Blender V4.3
transform_snap_object_editmesh.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 "BKE_attribute.hh"
10#include "BKE_bvhutils.hh"
11#include "BKE_editmesh.hh"
12#include "BKE_global.hh"
13#include "BKE_lib_id.hh"
14#include "BKE_mesh.hh"
15#include "BKE_object.hh"
16
18
20
22
23using namespace blender;
24
25/* -------------------------------------------------------------------- */
29static const Mesh *get_mesh_ref(const Object *ob_eval)
30{
31 if (const Mesh *me = BKE_object_get_editmesh_eval_final(ob_eval)) {
32 return me;
33 }
34
35 if (const Mesh *me = BKE_object_get_editmesh_eval_cage(ob_eval)) {
36 return me;
37 }
38
39 return static_cast<const Mesh *>(ob_eval->data);
40}
41
43 /* Mesh created from the edited mesh. */
45
46 /* Reference to pointers that change when the mesh is changed. It is used to detect updates. */
47 const Mesh *mesh_ref;
50
51 bool has_mesh_updated(const Mesh *mesh)
52 {
53 if (mesh != this->mesh_ref || mesh->runtime != this->runtime_ref ||
54 mesh->runtime->edit_data.get() != this->edit_data_ref)
55 {
56 return true;
57 }
58
59 return false;
60 }
61
62 void clear()
63 {
64 if (this->mesh) {
65 BKE_id_free(nullptr, this->mesh);
66 }
67 }
68
70 {
71 this->clear();
72 }
73
74#ifdef WITH_CXX_GUARDEDALLOC
75 MEM_CXX_CLASS_ALLOC_FUNCS("SnapCache_EditMesh")
76#endif
77};
78
80 const Object *ob_eval,
81 eSnapEditType /*edit_mode_type*/)
82{
83 Mesh *mesh = static_cast<Mesh *>(BKE_id_new_nomain(ID_ME, nullptr));
84 const BMEditMesh *em = BKE_editmesh_from_object(const_cast<Object *>(ob_eval));
85 BMesh *bm = em->bm;
86 BM_mesh_bm_to_me_compact(*bm, *mesh, nullptr, false);
87
88 bke::MutableAttributeAccessor attrs = mesh->attributes_for_write();
90 ".hide_vert", bke::AttrDomain::Point);
92 ".hide_edge", bke::AttrDomain::Edge);
94 ".hide_poly", bke::AttrDomain::Face);
95
96 /* Loop over all elements in parallel to choose which elements will participate in the snap.
97 * Hidden elements are ignored for snapping. */
98 const bool use_threading = (mesh->faces_num + mesh->edges_num) > 1024;
100 use_threading,
101 [&]() {
102 BMIter iter;
103 BMVert *v;
104 int i;
106 if (sctx->callbacks.edit_mesh.test_vert_fn) {
107 hide_vert.span[i] = !sctx->callbacks.edit_mesh.test_vert_fn(
109 }
110 else {
112 }
113 }
114 },
115 [&]() {
116 BMIter iter;
117 BMEdge *e;
118 int i;
120 if (sctx->callbacks.edit_mesh.test_edge_fn) {
121 hide_edge.span[i] = !sctx->callbacks.edit_mesh.test_edge_fn(
123 }
124 else {
125 hide_edge.span[i] = BM_elem_flag_test_bool(e, BM_ELEM_HIDDEN);
126 }
127 }
128 },
129 [&]() {
130 BMIter iter;
131 BMFace *f;
132 int i;
133 BM_ITER_MESH_INDEX (f, &iter, bm, BM_FACES_OF_MESH, i) {
134 if (sctx->callbacks.edit_mesh.test_face_fn) {
135 hide_poly.span[i] = !sctx->callbacks.edit_mesh.test_face_fn(
136 f, sctx->callbacks.edit_mesh.user_data);
137 }
138 else {
139 hide_poly.span[i] = BM_elem_flag_test_bool(f, BM_ELEM_HIDDEN);
140 }
141 }
142 });
143
144 hide_vert.finish();
145 hide_edge.finish();
146 hide_poly.finish();
147 return mesh;
148}
149
151 const Object *ob_eval,
152 bool create)
153{
154 SnapCache_EditMesh *em_cache = nullptr;
155
156 bool init = false;
157 const Mesh *mesh_ref = (G.moving) ? /* WORKAROUND:
158 * Avoid updating while transforming. Do not check if the
159 * reference mesh has been updated. */
160 nullptr :
161 get_mesh_ref(ob_eval);
162
163 if (std::unique_ptr<SnapObjectContext::SnapCache> *em_cache_p = sctx->editmesh_caches.lookup_ptr(
164 ob_eval->runtime->data_orig))
165 {
166 em_cache = static_cast<SnapCache_EditMesh *>(em_cache_p->get());
167
168 /* Check if the geometry has changed. */
169 if (mesh_ref && em_cache->has_mesh_updated(mesh_ref)) {
170 em_cache->clear();
171 init = true;
172 }
173 }
174 else if (create) {
175 std::unique_ptr<SnapCache_EditMesh> em_cache_ptr = std::make_unique<SnapCache_EditMesh>();
176 em_cache = em_cache_ptr.get();
177 sctx->editmesh_caches.add_new(ob_eval->runtime->data_orig, std::move(em_cache_ptr));
178 init = true;
179 }
180
181 if (init) {
182 em_cache->mesh = create_mesh(sctx, ob_eval, sctx->runtime.params.edit_mode_type);
183 if (mesh_ref) {
184 em_cache->mesh_ref = mesh_ref;
185 em_cache->runtime_ref = mesh_ref->runtime;
186 em_cache->edit_data_ref = mesh_ref->runtime->edit_data.get();
187 }
188 }
189
190 return em_cache;
191}
192
195/* -------------------------------------------------------------------- */
200{
201 eSnapMode snap_mode_supported = SCE_SNAP_TO_NONE;
202 if (bm->totface) {
205 }
206 else if (bm->totedge) {
207 snap_mode_supported |= SNAP_TO_EDGE_ELEMENTS | SCE_SNAP_TO_POINT;
208 }
209 else if (bm->totvert) {
210 snap_mode_supported |= SCE_SNAP_TO_POINT;
211 }
212 return snap_mode_supported;
213}
214
216 const Object *ob_eval,
217 eSnapMode snap_to_flag)
218{
219 const BMEditMesh *em = BKE_editmesh_from_object(const_cast<Object *>(ob_eval));
220 if (em == nullptr) {
221 return nullptr;
222 }
223
224 SnapCache_EditMesh *em_cache = snap_object_data_editmesh_get(sctx, ob_eval, false);
225 if (em_cache != nullptr) {
226 return em_cache;
227 }
228
229 eSnapMode snap_mode_used = snap_to_flag & editmesh_snap_mode_supported(em->bm);
230 if (snap_mode_used == SCE_SNAP_TO_NONE) {
231 return nullptr;
232 }
233
234 return snap_object_data_editmesh_get(sctx, ob_eval, true);
235}
236
240 const Object *ob_eval,
241 const ID * /*id*/,
242 const float4x4 &obmat,
243 eSnapMode snap_to_flag,
244 bool /*use_hide*/)
245{
246 SnapCache_EditMesh *em_cache = editmesh_snapdata_init(sctx, ob_eval, snap_to_flag);
247 if (em_cache && em_cache->mesh) {
248 return snap_object_mesh(sctx, ob_eval, &em_cache->mesh->id, obmat, snap_to_flag, true, true);
249 }
250 return SCE_SNAP_TO_NONE;
251}
BMEditMesh * BKE_editmesh_from_object(Object *ob)
Return the BMEditMesh for a given object.
Definition editmesh.cc:63
void BKE_id_free(Main *bmain, void *idv)
void * BKE_id_new_nomain(short type, const char *name)
Definition lib_id.cc:1487
General operations, lookup, etc. for blender objects.
const Mesh * BKE_object_get_editmesh_eval_cage(const Object *object)
const Mesh * BKE_object_get_editmesh_eval_final(const Object *object)
@ ID_ME
@ SCE_SNAP_INDIVIDUAL_NEAREST
@ SCE_SNAP_TO_FACE
@ SCE_SNAP_TO_POINT
@ SCE_SNAP_TO_NONE
@ BM_ELEM_HIDDEN
#define BM_elem_flag_test_bool(ele, hflag)
#define BM_ITER_MESH_INDEX(ele, iter, bm, itype, indexvar)
@ BM_EDGES_OF_MESH
@ BM_VERTS_OF_MESH
@ BM_FACES_OF_MESH
ATTR_WARN_UNUSED_RESULT BMesh * bm
void BM_mesh_bm_to_me_compact(BMesh &bm, Mesh &mesh, const CustomData_MeshMasks *mask, const bool add_mesh_attributes)
ATTR_WARN_UNUSED_RESULT const BMVert const BMEdge * e
ATTR_WARN_UNUSED_RESULT const BMVert * v
void init()
GSpanAttributeWriter lookup_or_add_for_write_only_span(StringRef attribute_id, AttrDomain domain, eCustomDataType data_type)
#define G(x, y, z)
void parallel_invoke(Functions &&...functions)
Definition BLI_task.hh:199
int totvert
int totedge
int totface
Definition DNA_ID.h:413
MeshRuntimeHandle * runtime
ObjectRuntimeHandle * runtime
bool has_mesh_updated(const Mesh *mesh)
struct SnapObjectContext::@587::@591 edit_mesh
bool(* test_face_fn)(BMFace *, void *user_data)
bool(* test_edge_fn)(BMEdge *, void *user_data)
blender::Map< const ID *, std::unique_ptr< SnapCache > > editmesh_caches
bool(* test_vert_fn)(BMVert *, void *user_data)
struct SnapObjectContext::@589 runtime
struct SnapObjectContext::@587 callbacks
#define SNAP_TO_EDGE_ELEMENTS
eSnapMode snap_object_mesh(SnapObjectContext *sctx, const Object *ob_eval, const ID *id, const blender::float4x4 &obmat, eSnapMode snap_to_flag, bool skip_hidden, bool is_editmesh=false)
eSnapMode snap_object_editmesh(SnapObjectContext *sctx, const Object *ob_eval, const ID *, const float4x4 &obmat, eSnapMode snap_to_flag, bool)
static eSnapMode editmesh_snap_mode_supported(BMesh *bm)
static SnapCache_EditMesh * editmesh_snapdata_init(SnapObjectContext *sctx, const Object *ob_eval, eSnapMode snap_to_flag)
static SnapCache_EditMesh * snap_object_data_editmesh_get(SnapObjectContext *sctx, const Object *ob_eval, bool create)
static Mesh * create_mesh(SnapObjectContext *sctx, const Object *ob_eval, eSnapEditType)
static const Mesh * get_mesh_ref(const Object *ob_eval)