Blender V4.5
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
41 /* Mesh created from the edited mesh. */
43
44 /* Reference to pointers that change when the mesh is changed. It is used to detect updates. */
45 const Mesh *mesh_ref;
48
50 {
51 if (mesh != this->mesh_ref || mesh->runtime != this->runtime_ref ||
52 mesh->runtime->edit_data.get() != this->edit_data_ref)
53 {
54 return true;
55 }
56
57 return false;
58 }
59
60 void clear()
61 {
62 if (this->mesh) {
63 BKE_id_free(nullptr, this->mesh);
64 }
65 }
66
68 {
69 this->clear();
70 }
71
72 MEM_CXX_CLASS_ALLOC_FUNCS("SnapCache_EditMesh")
73};
74
76 const Object *ob_eval,
77 eSnapEditType /*edit_mode_type*/)
78{
80 const BMEditMesh *em = BKE_editmesh_from_object(const_cast<Object *>(ob_eval));
81 BMesh *bm = em->bm;
82 BM_mesh_bm_to_me_compact(*bm, *mesh, nullptr, false);
83
84 bke::MutableAttributeAccessor attrs = mesh->attributes_for_write();
86 ".hide_vert", bke::AttrDomain::Point);
88 ".hide_edge", bke::AttrDomain::Edge);
90 ".hide_poly", bke::AttrDomain::Face);
91
92 /* Loop over all elements in parallel to choose which elements will participate in the snap.
93 * Hidden elements are ignored for snapping. */
94 const bool use_threading = (mesh->faces_num + mesh->edges_num) > 1024;
96 use_threading,
97 [&]() {
98 BMIter iter;
99 BMVert *v;
100 int i;
102 if (sctx->callbacks.edit_mesh.test_vert_fn) {
103 hide_vert.span[i] = !sctx->callbacks.edit_mesh.test_vert_fn(
105 }
106 else {
108 }
109 }
110 },
111 [&]() {
112 BMIter iter;
113 BMEdge *e;
114 int i;
116 if (sctx->callbacks.edit_mesh.test_edge_fn) {
117 hide_edge.span[i] = !sctx->callbacks.edit_mesh.test_edge_fn(
119 }
120 else {
121 hide_edge.span[i] = BM_elem_flag_test_bool(e, BM_ELEM_HIDDEN);
122 }
123 }
124 },
125 [&]() {
126 BMIter iter;
127 BMFace *f;
128 int i;
130 if (sctx->callbacks.edit_mesh.test_face_fn) {
131 hide_poly.span[i] = !sctx->callbacks.edit_mesh.test_face_fn(
132 f, sctx->callbacks.edit_mesh.user_data);
133 }
134 else {
135 hide_poly.span[i] = BM_elem_flag_test_bool(f, BM_ELEM_HIDDEN);
136 }
137 }
138 });
139
140 hide_vert.finish();
141 hide_edge.finish();
142 hide_poly.finish();
143 return mesh;
144}
145
147 const Object *ob_eval,
148 bool create)
149{
150 SnapCache_EditMesh *em_cache = nullptr;
151
152 bool init = false;
153 const Mesh *mesh_ref = (G.moving) ? /* WORKAROUND:
154 * Avoid updating while transforming. Do not check if the
155 * reference mesh has been updated. */
156 nullptr :
157 get_mesh_ref(ob_eval);
158
159 if (std::unique_ptr<SnapObjectContext::SnapCache> *em_cache_p = sctx->editmesh_caches.lookup_ptr(
160 ob_eval->runtime->data_orig))
161 {
162 em_cache = static_cast<SnapCache_EditMesh *>(em_cache_p->get());
163
164 /* Check if the geometry has changed. */
165 if (mesh_ref && em_cache->has_mesh_updated(mesh_ref)) {
166 em_cache->clear();
167 init = true;
168 }
169 }
170 else if (create) {
171 std::unique_ptr<SnapCache_EditMesh> em_cache_ptr = std::make_unique<SnapCache_EditMesh>();
172 em_cache = em_cache_ptr.get();
173 sctx->editmesh_caches.add_new(ob_eval->runtime->data_orig, std::move(em_cache_ptr));
174 init = true;
175 }
176
177 if (init) {
178 em_cache->mesh = create_mesh(sctx, ob_eval, sctx->runtime.params.edit_mode_type);
179 if (mesh_ref) {
180 em_cache->mesh_ref = mesh_ref;
181 em_cache->runtime_ref = mesh_ref->runtime;
182 em_cache->edit_data_ref = mesh_ref->runtime->edit_data.get();
183 }
184 }
185
186 return em_cache;
187}
188
190
191/* -------------------------------------------------------------------- */
194
196{
197 eSnapMode snap_mode_supported = SCE_SNAP_TO_NONE;
198 if (bm->totface) {
201 }
202 else if (bm->totedge) {
203 snap_mode_supported |= SNAP_TO_EDGE_ELEMENTS | SCE_SNAP_TO_POINT;
204 }
205 else if (bm->totvert) {
206 snap_mode_supported |= SCE_SNAP_TO_POINT;
207 }
208 return snap_mode_supported;
209}
210
212 const Object *ob_eval,
213 eSnapMode snap_to_flag)
214{
215 const BMEditMesh *em = BKE_editmesh_from_object(const_cast<Object *>(ob_eval));
216 if (em == nullptr) {
217 return nullptr;
218 }
219
220 SnapCache_EditMesh *em_cache = snap_object_data_editmesh_get(sctx, ob_eval, false);
221 if (em_cache != nullptr) {
222 return em_cache;
223 }
224
225 eSnapMode snap_mode_used = snap_to_flag & editmesh_snap_mode_supported(em->bm);
226 if (snap_mode_used == SCE_SNAP_TO_NONE) {
227 return nullptr;
228 }
229
230 return snap_object_data_editmesh_get(sctx, ob_eval, true);
231}
232
234
236 const Object *ob_eval,
237 const ID * /*id*/,
238 const float4x4 &obmat,
239 eSnapMode snap_to_flag,
240 bool /*use_hide*/)
241{
242 SnapCache_EditMesh *em_cache = editmesh_snapdata_init(sctx, ob_eval, snap_to_flag);
243 if (em_cache && em_cache->mesh) {
244 return snap_object_mesh(sctx, ob_eval, &em_cache->mesh->id, obmat, snap_to_flag, true, true);
245 }
246 return SCE_SNAP_TO_NONE;
247}
248
249} // 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:1500
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)
@ 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, eCustomDataType data_type)
#define this
#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:404
MeshRuntimeHandle * runtime
ObjectRuntimeHandle * runtime
struct blender::ed::transform::SnapObjectContext::@274174034202226355225361265035000052335134256331::@101325324177307207354241331175336004040234247152 edit_mesh
struct blender::ed::transform::SnapObjectContext::@274174034202226355225361265035000052335134256331 callbacks
struct blender::ed::transform::SnapObjectContext::@030342217121254226117135200143045314224065016366 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)
Map< const ID *, std::unique_ptr< SnapCache > > editmesh_caches
i
Definition text_draw.cc:230
#define SNAP_TO_EDGE_ELEMENTS