Blender V5.0
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
8
9#include "BKE_attribute.hh"
10#include "BKE_editmesh.hh"
11#include "BKE_global.hh"
12#include "BKE_lib_id.hh"
13#include "BKE_mesh.hh"
14#include "BKE_object.hh"
15#include "BKE_object_types.hh"
16
18
20
21namespace blender::ed::transform {
22
23/* -------------------------------------------------------------------- */
26
27static const Mesh *get_mesh_ref(const Object *ob_eval)
28{
29 if (const Mesh *me = BKE_object_get_editmesh_eval_final(ob_eval)) {
30 return me;
31 }
32
33 if (const Mesh *me = BKE_object_get_editmesh_eval_cage(ob_eval)) {
34 return me;
35 }
36
37 return static_cast<const Mesh *>(ob_eval->data);
38}
39
59 /* Mesh created from the edited mesh. */
61
62 /* Reference to pointers that change when the mesh is changed. It is used to detect updates. */
63 const Mesh *mesh_ref;
66
68 {
69 if (mesh != this->mesh_ref || mesh->runtime != this->runtime_ref ||
70 mesh->runtime->edit_data.get() != this->edit_data_ref)
71 {
72 return true;
73 }
74
75 return false;
76 }
77
78 void clear()
79 {
80 if (this->mesh) {
81 BKE_id_free(nullptr, this->mesh);
82 this->mesh = nullptr;
83 }
84 }
85
87 {
88 this->clear();
89 }
90
91 MEM_CXX_CLASS_ALLOC_FUNCS("SnapCache_EditMesh")
92};
93
95 const Object *ob_eval,
96 eSnapEditType /*edit_mode_type*/)
97{
99 const BMEditMesh *em = BKE_editmesh_from_object(const_cast<Object *>(ob_eval));
100 BMesh *bm = em->bm;
101 BM_mesh_bm_to_me_compact(*bm, *mesh, nullptr, false);
102
103 bke::MutableAttributeAccessor attrs = mesh->attributes_for_write();
105 ".hide_vert", bke::AttrDomain::Point);
107 ".hide_edge", bke::AttrDomain::Edge);
109 ".hide_poly", bke::AttrDomain::Face);
110
111 /* Loop over all elements in parallel to choose which elements will participate in the snap.
112 * Hidden elements are ignored for snapping. */
113 const bool use_threading = (mesh->faces_num + mesh->edges_num) > 1024;
115 use_threading,
116 [&]() {
117 BMIter iter;
118 BMVert *v;
119 int i;
121 if (sctx->callbacks.edit_mesh.test_vert_fn) {
122 hide_vert.span[i] = !sctx->callbacks.edit_mesh.test_vert_fn(
124 }
125 else {
127 }
128 }
129 },
130 [&]() {
131 BMIter iter;
132 BMEdge *e;
133 int i;
135 if (sctx->callbacks.edit_mesh.test_edge_fn) {
136 hide_edge.span[i] = !sctx->callbacks.edit_mesh.test_edge_fn(
138 }
139 else {
140 hide_edge.span[i] = BM_elem_flag_test_bool(e, BM_ELEM_HIDDEN);
141 }
142 }
143 },
144 [&]() {
145 BMIter iter;
146 BMFace *f;
147 int i;
149 if (sctx->callbacks.edit_mesh.test_face_fn) {
150 hide_poly.span[i] = !sctx->callbacks.edit_mesh.test_face_fn(
151 f, sctx->callbacks.edit_mesh.user_data);
152 }
153 else {
154 hide_poly.span[i] = BM_elem_flag_test_bool(f, BM_ELEM_HIDDEN);
155 }
156 }
157 });
158
159 hide_vert.finish();
160 hide_edge.finish();
161 hide_poly.finish();
162 return mesh;
163}
164
166 const Object *ob_eval,
167 bool create)
168{
169 BLI_assert(ob_eval->mode & OB_MODE_EDIT);
170 SnapCache_EditMesh *em_cache = nullptr;
171
172 bool init = false;
173 const Mesh *mesh_ref = (G.moving) ? /* WORKAROUND:
174 * Avoid updating while transforming. Do not check if the
175 * reference mesh has been updated. */
176 nullptr :
177 get_mesh_ref(ob_eval);
178
179 if (std::unique_ptr<SnapObjectContext::SnapCache> *em_cache_p = sctx->editmesh_caches.lookup_ptr(
180 ob_eval->runtime->data_orig))
181 {
182 em_cache = static_cast<SnapCache_EditMesh *>(em_cache_p->get());
183
184 /* Check if the geometry has changed. */
185 if (mesh_ref && em_cache->has_mesh_updated(mesh_ref)) {
186 em_cache->clear();
187 init = true;
188 }
189 }
190 else if (create) {
191 std::unique_ptr<SnapCache_EditMesh> em_cache_ptr = std::make_unique<SnapCache_EditMesh>();
192 em_cache = em_cache_ptr.get();
193 sctx->editmesh_caches.add_new(ob_eval->runtime->data_orig, std::move(em_cache_ptr));
194 init = true;
195 }
196
197 if (init) {
198 em_cache->mesh = create_mesh(sctx, ob_eval, sctx->runtime.params.edit_mode_type);
199 if (mesh_ref) {
200 em_cache->mesh_ref = mesh_ref;
201 em_cache->runtime_ref = mesh_ref->runtime;
202 em_cache->edit_data_ref = mesh_ref->runtime->edit_data.get();
203 }
204 }
205
206 return em_cache;
207}
208
210
211/* -------------------------------------------------------------------- */
214
216{
217 eSnapMode snap_mode_supported = SCE_SNAP_TO_NONE;
218 if (bm->totface) {
221 }
222 else if (bm->totedge) {
223 snap_mode_supported |= SNAP_TO_EDGE_ELEMENTS | SCE_SNAP_TO_POINT;
224 }
225 else if (bm->totvert) {
226 snap_mode_supported |= SCE_SNAP_TO_POINT;
227 }
228 return snap_mode_supported;
229}
230
232 const Object *ob_eval,
233 eSnapMode snap_to_flag)
234{
235 /* See code-comment on #SnapCache_EditMesh for why this is needed. */
236 if ((ob_eval->mode & OB_MODE_EDIT) == 0) {
237 return nullptr;
238 }
239
240 const BMEditMesh *em = BKE_editmesh_from_object(const_cast<Object *>(ob_eval));
241 if (em == nullptr) {
242 return nullptr;
243 }
244
245 SnapCache_EditMesh *em_cache = snap_object_data_editmesh_get(sctx, ob_eval, false);
246 if (em_cache != nullptr) {
247 return em_cache;
248 }
249
250 eSnapMode snap_mode_used = snap_to_flag & editmesh_snap_mode_supported(em->bm);
251 if (snap_mode_used == SCE_SNAP_TO_NONE) {
252 return nullptr;
253 }
254
255 return snap_object_data_editmesh_get(sctx, ob_eval, true);
256}
257
259
261 const Object *ob_eval,
262 const ID * /*id*/,
263 const float4x4 &obmat,
264 eSnapMode snap_to_flag,
265 bool /*use_hide*/)
266{
267 SnapCache_EditMesh *em_cache = editmesh_snapdata_init(sctx, ob_eval, snap_to_flag);
268 if (em_cache && em_cache->mesh) {
269 return snap_object_mesh(sctx, ob_eval, &em_cache->mesh->id, obmat, snap_to_flag, true, true);
270 }
271 return SCE_SNAP_TO_NONE;
272}
273
274} // namespace blender::ed::transform
BMEditMesh * BKE_editmesh_from_object(Object *ob)
Return the BMEditMesh for a given object.
Definition editmesh.cc:61
void BKE_id_free(Main *bmain, void *idv)
void * BKE_id_new_nomain(short type, const char *name)
Definition lib_id.cc:1519
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)
#define BLI_assert(a)
Definition BLI_assert.h:46
@ OB_MODE_EDIT
@ 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
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
GSpanAttributeWriter lookup_or_add_for_write_only_span(StringRef attribute_id, AttrDomain domain, AttrType data_type)
#define G(x, y, z)
static const Mesh * get_mesh_ref(const Object *ob_eval)
static SnapCache_EditMesh * snap_object_data_editmesh_get(SnapObjectContext *sctx, const Object *ob_eval, bool create)
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=false)
eSnapMode snap_object_editmesh(SnapObjectContext *sctx, const Object *ob_eval, const ID *id, const float4x4 &obmat, eSnapMode snap_to_flag, bool use_hide)
static SnapCache_EditMesh * editmesh_snapdata_init(SnapObjectContext *sctx, const Object *ob_eval, eSnapMode snap_to_flag)
static Mesh * create_mesh(SnapObjectContext *sctx, const Object *ob_eval, eSnapEditType)
static eSnapMode editmesh_snap_mode_supported(BMesh *bm)
void parallel_invoke(Functions &&...functions)
Definition BLI_task.hh:221
MatBase< float, 4, 4 > float4x4
static void init(bNodeTree *, bNode *node)
Definition DNA_ID.h:414
MeshRuntimeHandle * runtime
ObjectRuntimeHandle * runtime
struct blender::ed::transform::SnapObjectContext::@170374026073064374202114033260227063176045253050 runtime
bool(* test_edge_fn)(BMEdge *, void *user_data)
bool(* test_face_fn)(BMFace *, void *user_data)
bool(* test_vert_fn)(BMVert *, void *user_data)
struct blender::ed::transform::SnapObjectContext::@057303224201065302154130247374246316157207360104 callbacks
Map< const ID *, std::unique_ptr< SnapCache > > editmesh_caches
struct blender::ed::transform::SnapObjectContext::@057303224201065302154130247374246316157207360104::@052144141244060360354325332176274005342203076127 edit_mesh
i
Definition text_draw.cc:230
#define SNAP_TO_EDGE_ELEMENTS