Blender V4.3
mesh_iterators.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
11#include "BKE_customdata.hh"
12#include "BKE_editmesh.hh"
13#include "BKE_editmesh_cache.hh"
14#include "BKE_mesh.hh"
15#include "BKE_mesh_iterators.hh"
16
17#include "BLI_bitmap.h"
18#include "BLI_math_vector.h"
19
20#include "MEM_guardedalloc.h"
21
22/* General note on iterating verts/loops/edges/faces and end mode.
23 *
24 * The edit mesh pointer is set for both final and cage meshes in both cases when there are
25 * modifiers applied and not. This helps consistency of checks in the draw manager, where the
26 * existence of the edit mesh pointer does not depend on object configuration.
27 *
28 * For the iterating, however, we need to follow the `CD_ORIGINDEX` code paths when there are
29 * modifiers applied on the cage. In the code terms it means that the check for the edit mode code
30 * path needs to consist of both edit mesh and edit data checks. */
31
33 const Mesh *mesh,
34 void (*func)(void *user_data, int index, const float co[3], const float no[3]),
35 void *user_data,
37{
38 if (mesh->runtime->edit_mesh != nullptr && mesh->runtime->edit_data != nullptr) {
39 BMEditMesh *em = mesh->runtime->edit_mesh.get();
40 BMesh *bm = em->bm;
41 BMIter iter;
42 BMVert *eve;
43 int i;
44 if (!mesh->runtime->edit_data->vert_positions.is_empty()) {
45 const blender::Span<blender::float3> positions = mesh->runtime->edit_data->vert_positions;
48 vert_normals = BKE_editmesh_cache_ensure_vert_normals(*em, *mesh->runtime->edit_data);
49 }
50 BM_ITER_MESH_INDEX (eve, &iter, bm, BM_VERTS_OF_MESH, i) {
51 const float *no = (flag & MESH_FOREACH_USE_NORMAL) ? &vert_normals[i].x : nullptr;
52 func(user_data, i, positions[i], no);
53 }
54 }
55 else {
56 BM_ITER_MESH_INDEX (eve, &iter, bm, BM_VERTS_OF_MESH, i) {
57 const float *no = (flag & MESH_FOREACH_USE_NORMAL) ? eve->no : nullptr;
58 func(user_data, i, eve->co, no);
59 }
60 }
61 }
62 else {
63 const blender::Span<blender::float3> positions = mesh->vert_positions();
64 const int *index = static_cast<const int *>(
65 CustomData_get_layer(&mesh->vert_data, CD_ORIGINDEX));
68 vert_normals = mesh->vert_normals();
69 }
70
71 if (index) {
72 for (int i = 0; i < mesh->verts_num; i++) {
73 const float *no = (flag & MESH_FOREACH_USE_NORMAL) ? &vert_normals[i].x : nullptr;
74 const int orig = *index++;
75 if (orig == ORIGINDEX_NONE) {
76 continue;
77 }
78 func(user_data, orig, positions[i], no);
79 }
80 }
81 else {
82 for (int i = 0; i < mesh->verts_num; i++) {
83 const float *no = (flag & MESH_FOREACH_USE_NORMAL) ? &vert_normals[i].x : nullptr;
84 func(user_data, i, positions[i], no);
85 }
86 }
87 }
88}
89
91 Mesh *mesh,
92 const int tot_edges,
93 void (*func)(void *user_data, int index, const float v0co[3], const float v1co[3]),
94 void *user_data)
95{
96 if (mesh->runtime->edit_mesh != nullptr && mesh->runtime->edit_data) {
97 BMEditMesh *em = mesh->runtime->edit_mesh.get();
98 BMesh *bm = em->bm;
99 BMIter iter;
100 BMEdge *eed;
101 int i;
102 if (!mesh->runtime->edit_data->vert_positions.is_empty()) {
103 const blender::Span<blender::float3> positions = mesh->runtime->edit_data->vert_positions;
105 BM_ITER_MESH_INDEX (eed, &iter, bm, BM_EDGES_OF_MESH, i) {
106 func(user_data,
107 i,
108 positions[BM_elem_index_get(eed->v1)],
109 positions[BM_elem_index_get(eed->v2)]);
110 }
111 }
112 else {
113 BM_ITER_MESH_INDEX (eed, &iter, bm, BM_EDGES_OF_MESH, i) {
114 func(user_data, i, eed->v1->co, eed->v2->co);
115 }
116 }
117 }
118 else {
119 const blender::Span<blender::float3> positions = mesh->vert_positions();
120 const blender::Span<blender::int2> edges = mesh->edges();
121 const int *index = static_cast<const int *>(
122 CustomData_get_layer(&mesh->edge_data, CD_ORIGINDEX));
123
124 if (index) {
125 for (const int i : edges.index_range()) {
126
127 const int orig = *index++;
128 if (orig == ORIGINDEX_NONE) {
129 continue;
130 }
131 func(user_data, orig, positions[edges[i][0]], positions[edges[i][1]]);
132 }
133 }
134 else if (mesh->edges_num == tot_edges) {
135 for (const int i : edges.index_range()) {
136 func(user_data, i, positions[edges[i][0]], positions[edges[i][1]]);
137 }
138 }
139 }
140}
141
143 void (*func)(void *user_data,
144 int vertex_index,
145 int face_index,
146 const float co[3],
147 const float no[3]),
148 void *user_data,
150{
151
152 /* We can't use `dm->getLoopDataLayout(dm)` here,
153 * we want to always access `dm->loopData`, `EditDerivedBMesh` would
154 * return loop data from BMesh itself. */
155 if (mesh->runtime->edit_mesh != nullptr && mesh->runtime->edit_data) {
156 BMEditMesh *em = mesh->runtime->edit_mesh.get();
157 BMesh *bm = em->bm;
158 BMIter iter;
159 BMFace *efa;
160
161 const blender::Span<blender::float3> positions = mesh->runtime->edit_data->vert_positions;
162
163 /* XXX: investigate using EditMesh data. */
164 blender::Span<blender::float3> corner_normals;
166 corner_normals = mesh->corner_normals();
167 }
168
169 int f_idx;
170
172
173 BM_ITER_MESH_INDEX (efa, &iter, bm, BM_FACES_OF_MESH, f_idx) {
174 BMLoop *l_iter, *l_first;
175
176 l_iter = l_first = BM_FACE_FIRST_LOOP(efa);
177 do {
178 const BMVert *eve = l_iter->v;
179 const int v_idx = BM_elem_index_get(eve);
180 func(user_data,
181 v_idx,
182 f_idx,
183 positions.is_empty() ? positions[v_idx] : blender::float3(eve->co),
184 corner_normals.is_empty() ? nullptr : &corner_normals[BM_elem_index_get(l_iter)].x);
185 } while ((l_iter = l_iter->next) != l_first);
186 }
187 }
188 else {
189 blender::Span<blender::float3> corner_normals;
191 corner_normals = mesh->corner_normals();
192 }
193
194 const blender::Span<blender::float3> positions = mesh->vert_positions();
195 const blender::OffsetIndices faces = mesh->faces();
196 const blender::Span<int> corner_verts = mesh->corner_verts();
197 const int *v_index = static_cast<const int *>(
198 CustomData_get_layer(&mesh->vert_data, CD_ORIGINDEX));
199 const int *f_index = static_cast<const int *>(
200 CustomData_get_layer(&mesh->face_data, CD_ORIGINDEX));
201
202 if (v_index || f_index) {
203 for (const int face_i : faces.index_range()) {
204 for (const int corner : faces[face_i]) {
205 const int vert = corner_verts[corner];
206 const int v_idx = v_index ? v_index[vert] : vert;
207 const int f_idx = f_index ? f_index[face_i] : face_i;
208 const float *no = corner_normals.is_empty() ? nullptr : &corner_normals[corner].x;
209 if (ELEM(ORIGINDEX_NONE, v_idx, f_idx)) {
210 continue;
211 }
212 func(user_data, v_idx, f_idx, positions[vert], no);
213 }
214 }
215 }
216 else {
217 for (const int face_i : faces.index_range()) {
218 for (const int corner : faces[face_i]) {
219 const int vert = corner_verts[corner];
220 const float *no = corner_normals.is_empty() ? nullptr : &corner_normals[corner].x;
221 func(user_data, vert, face_i, positions[vert], no);
222 }
223 }
224 }
225 }
226}
227
229 Mesh *mesh,
230 void (*func)(void *user_data, int index, const float cent[3], const float no[3]),
231 void *user_data,
233{
234 using namespace blender;
235 if (mesh->runtime->edit_mesh != nullptr && mesh->runtime->edit_data != nullptr) {
236 BMEditMesh *em = mesh->runtime->edit_mesh.get();
237 BMesh *bm = em->bm;
238 BMFace *efa;
239 BMIter iter;
240 int i;
241
243 *em, *mesh->runtime->edit_data);
244
245 Span<float3> face_normals;
247 face_normals = BKE_editmesh_cache_ensure_face_normals(*em, *mesh->runtime->edit_data);
248 }
249
250 if (!face_normals.is_empty()) {
251 BM_ITER_MESH_INDEX (efa, &iter, bm, BM_FACES_OF_MESH, i) {
252 const float *no = face_normals[i];
253 func(user_data, i, face_centers[i], no);
254 }
255 }
256 else {
257 BM_ITER_MESH_INDEX (efa, &iter, bm, BM_FACES_OF_MESH, i) {
258 const float *no = (flag & MESH_FOREACH_USE_NORMAL) ? efa->no : nullptr;
259 func(user_data, i, face_centers[i], no);
260 }
261 }
262 }
263 else {
264 const blender::Span<float3> positions = mesh->vert_positions();
265 const blender::OffsetIndices faces = mesh->faces();
266 const blender::Span<int> corner_verts = mesh->corner_verts();
267 const int *index = static_cast<const int *>(
268 CustomData_get_layer(&mesh->face_data, CD_ORIGINDEX));
269
270 if (index) {
271 for (const int i : faces.index_range()) {
272 const int orig = *index++;
273 if (orig == ORIGINDEX_NONE) {
274 continue;
275 }
276 const Span<int> face_verts = corner_verts.slice(faces[i]);
277 const float3 center = bke::mesh::face_center_calc(positions, face_verts);
279 const float3 normal = bke::mesh::face_normal_calc(positions, face_verts);
280 func(user_data, orig, center, normal);
281 }
282 else {
283 func(user_data, orig, center, nullptr);
284 }
285 }
286 }
287 else {
288 for (const int i : faces.index_range()) {
289 const Span<int> face_verts = corner_verts.slice(faces[i]);
290 const float3 center = bke::mesh::face_center_calc(positions, face_verts);
292 const float3 normal = bke::mesh::face_normal_calc(positions, face_verts);
293 func(user_data, i, center, normal);
294 }
295 else {
296 func(user_data, i, center, nullptr);
297 }
298 }
299 }
300 }
301}
302
304 Mesh *mesh,
305 void (*func)(void *user_data, int index, const float cent[3], const float no[3]),
306 void *user_data,
308{
309 const blender::Span<blender::float3> positions = mesh->vert_positions();
310 const blender::OffsetIndices faces = mesh->faces();
311 const blender::Span<int> corner_verts = mesh->corner_verts();
314 vert_normals = mesh->vert_normals();
315 }
316 const int *index = static_cast<const int *>(
317 CustomData_get_layer(&mesh->face_data, CD_ORIGINDEX));
318 const blender::BitSpan facedot_tags = mesh->runtime->subsurf_face_dot_tags;
319
320 if (index) {
321 for (const int i : faces.index_range()) {
322 const int orig = *index++;
323 if (orig == ORIGINDEX_NONE) {
324 continue;
325 }
326 for (const int vert : corner_verts.slice(faces[i])) {
327 if (facedot_tags[vert]) {
328 func(user_data,
329 orig,
330 positions[vert],
331 (flag & MESH_FOREACH_USE_NORMAL) ? &vert_normals[vert].x : nullptr);
332 }
333 }
334 }
335 }
336 else {
337 for (const int i : faces.index_range()) {
338 for (const int vert : corner_verts.slice(faces[i])) {
339 if (facedot_tags[vert]) {
340 func(user_data,
341 i,
342 positions[vert],
343 (flag & MESH_FOREACH_USE_NORMAL) ? &vert_normals[vert].x : nullptr);
344 }
345 }
346 }
347 }
348}
349
350/* Helpers based on above foreach loopers> */
351
356
357static void get_vertexcos__mapFunc(void *user_data,
358 int index,
359 const float co[3],
360 const float /*no*/[3])
361{
362 MappedVCosData *mapped_vcos_data = (MappedVCosData *)user_data;
363
364 if (BLI_BITMAP_TEST(mapped_vcos_data->vertex_visit, index) == 0) {
365 /* We need coord from prototype vertex, not from copies,
366 * we assume they stored in the beginning of vertex array stored in evaluated mesh
367 * (mirror modifier for eg does this). */
368 copy_v3_v3(mapped_vcos_data->vertexcos[index], co);
369 BLI_BITMAP_ENABLE(mapped_vcos_data->vertex_visit, index);
370 }
371}
372
374 float (*r_cos)[3],
375 const int totcos)
376{
377 MappedVCosData user_data;
378 memset(r_cos, 0, sizeof(*r_cos) * totcos);
379 user_data.vertexcos = r_cos;
380 user_data.vertex_visit = BLI_BITMAP_NEW(totcos, __func__);
382 MEM_freeN(user_data.vertex_visit);
383}
CustomData interface, see also DNA_customdata_types.h.
const void * CustomData_get_layer(const CustomData *data, eCustomDataType type)
#define ORIGINDEX_NONE
blender::Span< blender::float3 > BKE_editmesh_cache_ensure_face_centers(BMEditMesh &em, blender::bke::EditMeshData &emd)
blender::Span< blender::float3 > BKE_editmesh_cache_ensure_vert_normals(BMEditMesh &em, blender::bke::EditMeshData &emd)
blender::Span< blender::float3 > BKE_editmesh_cache_ensure_face_normals(BMEditMesh &em, blender::bke::EditMeshData &emd)
MeshForeachFlag
@ MESH_FOREACH_NOP
@ MESH_FOREACH_USE_NORMAL
#define BLI_BITMAP_NEW(_num, _alloc_string)
Definition BLI_bitmap.h:41
#define BLI_BITMAP_TEST(_bitmap, _index)
Definition BLI_bitmap.h:65
#define BLI_BITMAP_ENABLE(_bitmap, _index)
Definition BLI_bitmap.h:82
unsigned int BLI_bitmap
Definition BLI_bitmap.h:17
MINLINE void copy_v3_v3(float r[3], const float a[3])
#define ELEM(...)
Read Guarded memory(de)allocation.
#define BM_FACE_FIRST_LOOP(p)
#define BM_elem_index_get(ele)
#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_elem_index_ensure(BMesh *bm, const char htype)
#define BM_VERT
constexpr Span slice(int64_t start, int64_t size) const
Definition BLI_span.hh:138
constexpr bool is_empty() const
Definition BLI_span.hh:261
draw_view in_light_buf[] float
void MEM_freeN(void *vmemh)
Definition mallocn.cc:105
void BKE_mesh_foreach_mapped_loop(Mesh *mesh, void(*func)(void *user_data, int vertex_index, int face_index, const float co[3], const float no[3]), void *user_data, MeshForeachFlag flag)
void BKE_mesh_foreach_mapped_face_center(Mesh *mesh, void(*func)(void *user_data, int index, const float cent[3], const float no[3]), void *user_data, MeshForeachFlag flag)
void BKE_mesh_foreach_mapped_vert_coords_get(const Mesh *mesh_eval, float(*r_cos)[3], const int totcos)
void BKE_mesh_foreach_mapped_subdiv_face_center(Mesh *mesh, void(*func)(void *user_data, int index, const float cent[3], const float no[3]), void *user_data, MeshForeachFlag flag)
static void get_vertexcos__mapFunc(void *user_data, int index, const float co[3], const float[3])
void BKE_mesh_foreach_mapped_edge(Mesh *mesh, const int tot_edges, void(*func)(void *user_data, int index, const float v0co[3], const float v1co[3]), void *user_data)
void BKE_mesh_foreach_mapped_vert(const Mesh *mesh, void(*func)(void *user_data, int index, const float co[3], const float no[3]), void *user_data, MeshForeachFlag flag)
VecBase< float, 3 > float3
BMVert * v1
BMVert * v2
float no[3]
struct BMVert * v
struct BMLoop * next
float co[3]
float no[3]
BLI_bitmap * vertex_visit
float(* vertexcos)[3]
uint8_t flag
Definition wm_window.cc:138