diff options
Diffstat (limited to 'source/blender/blenkernel/intern/mesh_iterators.cc')
-rw-r--r-- | source/blender/blenkernel/intern/mesh_iterators.cc | 388 |
1 files changed, 388 insertions, 0 deletions
diff --git a/source/blender/blenkernel/intern/mesh_iterators.cc b/source/blender/blenkernel/intern/mesh_iterators.cc new file mode 100644 index 00000000000..a99e9b2348d --- /dev/null +++ b/source/blender/blenkernel/intern/mesh_iterators.cc @@ -0,0 +1,388 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +/** \file + * \ingroup bke + * + * Functions for iterating mesh features. + */ + +#include "DNA_mesh_types.h" +#include "DNA_meshdata_types.h" + +#include "BKE_customdata.h" +#include "BKE_editmesh.h" +#include "BKE_editmesh_cache.h" +#include "BKE_mesh.h" +#include "BKE_mesh_iterators.h" + +#include "BLI_bitmap.h" +#include "BLI_math.h" + +#include "MEM_guardedalloc.h" + +/* General note on iterating verts/loops/edges/polys and end mode. + * + * The edit mesh pointer is set for both final and cage meshes in both cases when there are + * modifiers applied and not. This helps consistency of checks in the draw manager, where the + * existence of the edit mesh pointer does not depend on object configuration. + * + * For the iterating, however, we need to follow the `CD_ORIGINDEX` code paths when there are + * modifiers applied on the cage. In the code terms it means that the check for the edit mode code + * path needs to consist of both edit mesh and edit data checks. */ + +void BKE_mesh_foreach_mapped_vert( + Mesh *mesh, + void (*func)(void *userData, int index, const float co[3], const float no[3]), + void *userData, + MeshForeachFlag flag) +{ + if (mesh->edit_mesh != nullptr && mesh->runtime->edit_data != nullptr) { + BMEditMesh *em = mesh->edit_mesh; + BMesh *bm = em->bm; + BMIter iter; + BMVert *eve; + int i; + if (mesh->runtime->edit_data->vertexCos != nullptr) { + const float(*vertexCos)[3] = mesh->runtime->edit_data->vertexCos; + const float(*vertexNos)[3]; + if (flag & MESH_FOREACH_USE_NORMAL) { + BKE_editmesh_cache_ensure_vert_normals(em, mesh->runtime->edit_data); + vertexNos = mesh->runtime->edit_data->vertexNos; + } + else { + vertexNos = nullptr; + } + BM_ITER_MESH_INDEX (eve, &iter, bm, BM_VERTS_OF_MESH, i) { + const float *no = (flag & MESH_FOREACH_USE_NORMAL) ? vertexNos[i] : nullptr; + func(userData, i, vertexCos[i], no); + } + } + else { + BM_ITER_MESH_INDEX (eve, &iter, bm, BM_VERTS_OF_MESH, i) { + const float *no = (flag & MESH_FOREACH_USE_NORMAL) ? eve->no : nullptr; + func(userData, i, eve->co, no); + } + } + } + else { + const MVert *mv = BKE_mesh_verts(mesh); + const int *index = static_cast<const int *>(CustomData_get_layer(&mesh->vdata, CD_ORIGINDEX)); + const float(*vert_normals)[3] = (flag & MESH_FOREACH_USE_NORMAL) ? + BKE_mesh_vertex_normals_ensure(mesh) : + nullptr; + + if (index) { + for (int i = 0; i < mesh->totvert; i++, mv++) { + const float *no = (flag & MESH_FOREACH_USE_NORMAL) ? vert_normals[i] : nullptr; + const int orig = *index++; + if (orig == ORIGINDEX_NONE) { + continue; + } + func(userData, orig, mv->co, no); + } + } + else { + for (int i = 0; i < mesh->totvert; i++, mv++) { + const float *no = (flag & MESH_FOREACH_USE_NORMAL) ? vert_normals[i] : nullptr; + func(userData, i, mv->co, no); + } + } + } +} + +void BKE_mesh_foreach_mapped_edge( + Mesh *mesh, + const int tot_edges, + void (*func)(void *userData, int index, const float v0co[3], const float v1co[3]), + void *userData) +{ + if (mesh->edit_mesh != nullptr && mesh->runtime->edit_data) { + BMEditMesh *em = mesh->edit_mesh; + BMesh *bm = em->bm; + BMIter iter; + BMEdge *eed; + int i; + if (mesh->runtime->edit_data->vertexCos != nullptr) { + const float(*vertexCos)[3] = mesh->runtime->edit_data->vertexCos; + BM_mesh_elem_index_ensure(bm, BM_VERT); + + BM_ITER_MESH_INDEX (eed, &iter, bm, BM_EDGES_OF_MESH, i) { + func(userData, + i, + vertexCos[BM_elem_index_get(eed->v1)], + vertexCos[BM_elem_index_get(eed->v2)]); + } + } + else { + BM_ITER_MESH_INDEX (eed, &iter, bm, BM_EDGES_OF_MESH, i) { + func(userData, i, eed->v1->co, eed->v2->co); + } + } + } + else { + const MVert *mv = BKE_mesh_verts(mesh); + const MEdge *med = BKE_mesh_edges(mesh); + const int *index = static_cast<const int *>(CustomData_get_layer(&mesh->edata, CD_ORIGINDEX)); + + if (index) { + for (int i = 0; i < mesh->totedge; i++, med++) { + const int orig = *index++; + if (orig == ORIGINDEX_NONE) { + continue; + } + func(userData, orig, mv[med->v1].co, mv[med->v2].co); + } + } + else if (mesh->totedge == tot_edges) { + for (int i = 0; i < mesh->totedge; i++, med++) { + func(userData, i, mv[med->v1].co, mv[med->v2].co); + } + } + } +} + +void BKE_mesh_foreach_mapped_loop(Mesh *mesh, + void (*func)(void *userData, + int vertex_index, + int face_index, + const float co[3], + const float no[3]), + void *userData, + MeshForeachFlag flag) +{ + + /* We can't use `dm->getLoopDataLayout(dm)` here, + * we want to always access `dm->loopData`, `EditDerivedBMesh` would + * return loop data from BMesh itself. */ + if (mesh->edit_mesh != nullptr && mesh->runtime->edit_data) { + BMEditMesh *em = mesh->edit_mesh; + BMesh *bm = em->bm; + BMIter iter; + BMFace *efa; + + const float(*vertexCos)[3] = mesh->runtime->edit_data->vertexCos; + + /* XXX: investigate using EditMesh data. */ + const float(*lnors)[3] = (flag & MESH_FOREACH_USE_NORMAL) ? + static_cast<const float(*)[3]>( + CustomData_get_layer(&mesh->ldata, CD_NORMAL)) : + nullptr; + + int f_idx; + + BM_mesh_elem_index_ensure(bm, BM_VERT); + + BM_ITER_MESH_INDEX (efa, &iter, bm, BM_FACES_OF_MESH, f_idx) { + BMLoop *l_iter, *l_first; + + l_iter = l_first = BM_FACE_FIRST_LOOP(efa); + do { + const BMVert *eve = l_iter->v; + const int v_idx = BM_elem_index_get(eve); + const float *no = lnors ? *lnors++ : nullptr; + func(userData, v_idx, f_idx, vertexCos ? vertexCos[v_idx] : eve->co, no); + } while ((l_iter = l_iter->next) != l_first); + } + } + else { + const float(*lnors)[3] = (flag & MESH_FOREACH_USE_NORMAL) ? + static_cast<const float(*)[3]>( + CustomData_get_layer(&mesh->ldata, CD_NORMAL)) : + nullptr; + + const MVert *mv = BKE_mesh_verts(mesh); + const MLoop *ml = BKE_mesh_loops(mesh); + const MPoly *mp = BKE_mesh_polys(mesh); + const int *v_index = static_cast<const int *>( + CustomData_get_layer(&mesh->vdata, CD_ORIGINDEX)); + const int *f_index = static_cast<const int *>( + CustomData_get_layer(&mesh->pdata, CD_ORIGINDEX)); + int p_idx, i; + + if (v_index || f_index) { + for (p_idx = 0; p_idx < mesh->totpoly; p_idx++, mp++) { + for (i = 0; i < mp->totloop; i++, ml++) { + const int v_idx = v_index ? v_index[ml->v] : ml->v; + const int f_idx = f_index ? f_index[p_idx] : p_idx; + const float *no = lnors ? *lnors++ : nullptr; + if (ELEM(ORIGINDEX_NONE, v_idx, f_idx)) { + continue; + } + func(userData, v_idx, f_idx, mv[ml->v].co, no); + } + } + } + else { + for (p_idx = 0; p_idx < mesh->totpoly; p_idx++, mp++) { + for (i = 0; i < mp->totloop; i++, ml++) { + const int v_idx = ml->v; + const int f_idx = p_idx; + const float *no = lnors ? *lnors++ : nullptr; + func(userData, v_idx, f_idx, mv[ml->v].co, no); + } + } + } + } +} + +void BKE_mesh_foreach_mapped_face_center( + Mesh *mesh, + void (*func)(void *userData, int index, const float cent[3], const float no[3]), + void *userData, + MeshForeachFlag flag) +{ + if (mesh->edit_mesh != nullptr && mesh->runtime->edit_data != nullptr) { + BMEditMesh *em = mesh->edit_mesh; + BMesh *bm = em->bm; + const float(*polyCos)[3]; + const float(*polyNos)[3]; + BMFace *efa; + BMIter iter; + int i; + + BKE_editmesh_cache_ensure_poly_centers(em, mesh->runtime->edit_data); + polyCos = mesh->runtime->edit_data->polyCos; /* always set */ + + if (flag & MESH_FOREACH_USE_NORMAL) { + BKE_editmesh_cache_ensure_poly_normals(em, mesh->runtime->edit_data); + polyNos = mesh->runtime->edit_data->polyNos; /* maybe nullptr */ + } + else { + polyNos = nullptr; + } + + if (polyNos) { + BM_ITER_MESH_INDEX (efa, &iter, bm, BM_FACES_OF_MESH, i) { + const float *no = polyNos[i]; + func(userData, i, polyCos[i], no); + } + } + else { + BM_ITER_MESH_INDEX (efa, &iter, bm, BM_FACES_OF_MESH, i) { + const float *no = (flag & MESH_FOREACH_USE_NORMAL) ? efa->no : nullptr; + func(userData, i, polyCos[i], no); + } + } + } + else { + const MVert *mvert = BKE_mesh_verts(mesh); + const MPoly *mp = BKE_mesh_polys(mesh); + const MLoop *loops = BKE_mesh_loops(mesh); + const MLoop *ml; + float _no_buf[3]; + float *no = (flag & MESH_FOREACH_USE_NORMAL) ? _no_buf : nullptr; + const int *index = static_cast<const int *>(CustomData_get_layer(&mesh->pdata, CD_ORIGINDEX)); + + if (index) { + for (int i = 0; i < mesh->totpoly; i++, mp++) { + const int orig = *index++; + if (orig == ORIGINDEX_NONE) { + continue; + } + float cent[3]; + ml = &loops[mp->loopstart]; + BKE_mesh_calc_poly_center(mp, ml, mvert, cent); + if (flag & MESH_FOREACH_USE_NORMAL) { + BKE_mesh_calc_poly_normal(mp, ml, mvert, no); + } + func(userData, orig, cent, no); + } + } + else { + for (int i = 0; i < mesh->totpoly; i++, mp++) { + float cent[3]; + ml = &loops[mp->loopstart]; + BKE_mesh_calc_poly_center(mp, ml, mvert, cent); + if (flag & MESH_FOREACH_USE_NORMAL) { + BKE_mesh_calc_poly_normal(mp, ml, mvert, no); + } + func(userData, i, cent, no); + } + } + } +} + +void BKE_mesh_foreach_mapped_subdiv_face_center( + Mesh *mesh, + void (*func)(void *userData, int index, const float cent[3], const float no[3]), + void *userData, + MeshForeachFlag flag) +{ + const MVert *verts = BKE_mesh_verts(mesh); + const MPoly *mp = BKE_mesh_polys(mesh); + const MLoop *loops = BKE_mesh_loops(mesh); + const MLoop *ml; + const MVert *mv; + const float(*vert_normals)[3] = (flag & MESH_FOREACH_USE_NORMAL) ? + BKE_mesh_vertex_normals_ensure(mesh) : + nullptr; + const int *index = static_cast<const int *>(CustomData_get_layer(&mesh->pdata, CD_ORIGINDEX)); + const BLI_bitmap *facedot_tags = mesh->runtime->subsurf_face_dot_tags; + BLI_assert(facedot_tags != nullptr); + + if (index) { + for (int i = 0; i < mesh->totpoly; i++, mp++) { + const int orig = *index++; + if (orig == ORIGINDEX_NONE) { + continue; + } + ml = &loops[mp->loopstart]; + for (int j = 0; j < mp->totloop; j++, ml++) { + mv = &verts[ml->v]; + if (BLI_BITMAP_TEST(facedot_tags, ml->v)) { + func(userData, + orig, + mv->co, + (flag & MESH_FOREACH_USE_NORMAL) ? vert_normals[ml->v] : nullptr); + } + } + } + } + else { + for (int i = 0; i < mesh->totpoly; i++, mp++) { + ml = &loops[mp->loopstart]; + for (int j = 0; j < mp->totloop; j++, ml++) { + mv = &verts[ml->v]; + if (BLI_BITMAP_TEST(facedot_tags, ml->v)) { + func(userData, + i, + mv->co, + (flag & MESH_FOREACH_USE_NORMAL) ? vert_normals[ml->v] : nullptr); + } + } + } + } +} + +/* Helpers based on above foreach loopers> */ + +struct MappedVCosData { + float (*vertexcos)[3]; + BLI_bitmap *vertex_visit; +}; + +static void get_vertexcos__mapFunc(void *user_data, + int index, + const float co[3], + const float /*no*/[3]) +{ + MappedVCosData *mapped_vcos_data = (MappedVCosData *)user_data; + + if (BLI_BITMAP_TEST(mapped_vcos_data->vertex_visit, index) == 0) { + /* We need coord from prototype vertex, not from copies, + * we assume they stored in the beginning of vertex array stored in evaluated mesh + * (mirror modifier for eg does this). */ + copy_v3_v3(mapped_vcos_data->vertexcos[index], co); + BLI_BITMAP_ENABLE(mapped_vcos_data->vertex_visit, index); + } +} + +void BKE_mesh_foreach_mapped_vert_coords_get(Mesh *me_eval, float (*r_cos)[3], const int totcos) +{ + MappedVCosData user_data; + memset(r_cos, 0, sizeof(*r_cos) * totcos); + user_data.vertexcos = r_cos; + user_data.vertex_visit = BLI_BITMAP_NEW(totcos, __func__); + BKE_mesh_foreach_mapped_vert(me_eval, get_vertexcos__mapFunc, &user_data, MESH_FOREACH_NOP); + MEM_freeN(user_data.vertex_visit); +} |