Changeset View
Changeset View
Standalone View
Standalone View
source/blender/bmesh/intern/bmesh_mesh_convert.cc
| Show First 20 Lines • Show All 105 Lines • ▼ Show 20 Lines | |||||
| using blender::Array; | using blender::Array; | ||||
| using blender::float3; | using blender::float3; | ||||
| using blender::IndexRange; | using blender::IndexRange; | ||||
| using blender::MutableSpan; | using blender::MutableSpan; | ||||
| using blender::Span; | using blender::Span; | ||||
| using blender::StringRef; | using blender::StringRef; | ||||
| static char bm_edge_flag_from_mflag(const short mflag) | |||||
| { | |||||
| return ((mflag & ME_SEAM) ? BM_ELEM_SEAM : 0) | ((mflag & ME_EDGEDRAW) ? BM_ELEM_DRAW : 0); | |||||
| } | |||||
| static char bm_face_flag_from_mflag(const char mflag) | |||||
| { | |||||
| return ((mflag & ME_SMOOTH) ? BM_ELEM_SMOOTH : 0); | |||||
| } | |||||
| static short bm_edge_flag_to_mflag(const BMEdge *e) | |||||
| { | |||||
| const char hflag = e->head.hflag; | |||||
| return ((hflag & BM_ELEM_SEAM) ? ME_SEAM : 0) | ((hflag & BM_ELEM_DRAW) ? ME_EDGEDRAW : 0); | |||||
| } | |||||
| static char bm_face_flag_to_mflag(const BMFace *f) | |||||
| { | |||||
| const char hflag = f->head.hflag; | |||||
| return ((hflag & BM_ELEM_SMOOTH) ? ME_SMOOTH : 0); | |||||
| } | |||||
| /* Static function for alloc (duplicate in modifiers_bmesh.c) */ | /* Static function for alloc (duplicate in modifiers_bmesh.c) */ | ||||
| static BMFace *bm_face_create_from_mpoly(BMesh &bm, | static BMFace *bm_face_create_from_mpoly(BMesh &bm, | ||||
| Span<MLoop> loops, | Span<MLoop> loops, | ||||
| Span<BMVert *> vtable, | Span<BMVert *> vtable, | ||||
| Span<BMEdge *> etable) | Span<BMEdge *> etable) | ||||
| { | { | ||||
| Array<BMVert *, BM_DEFAULT_NGON_STACK_SIZE> verts(loops.size()); | Array<BMVert *, BM_DEFAULT_NGON_STACK_SIZE> verts(loops.size()); | ||||
| Array<BMEdge *, BM_DEFAULT_NGON_STACK_SIZE> edges(loops.size()); | Array<BMEdge *, BM_DEFAULT_NGON_STACK_SIZE> edges(loops.size()); | ||||
| ▲ Show 20 Lines • Show All 258 Lines • ▼ Show 20 Lines | void BM_mesh_bm_from_me(BMesh *bm, const Mesh *me, const struct BMeshFromMeshParams *params) | ||||
| const Span<MEdge> medge = me->edges(); | const Span<MEdge> medge = me->edges(); | ||||
| Array<BMEdge *> etable(me->totedge); | Array<BMEdge *> etable(me->totedge); | ||||
| for (const int i : medge.index_range()) { | for (const int i : medge.index_range()) { | ||||
| BMEdge *e = etable[i] = BM_edge_create( | BMEdge *e = etable[i] = BM_edge_create( | ||||
| bm, vtable[medge[i].v1], vtable[medge[i].v2], nullptr, BM_CREATE_SKIP_CD); | bm, vtable[medge[i].v1], vtable[medge[i].v2], nullptr, BM_CREATE_SKIP_CD); | ||||
| BM_elem_index_set(e, i); /* set_ok */ | BM_elem_index_set(e, i); /* set_ok */ | ||||
| /* Transfer flags. */ | /* Transfer flags. */ | ||||
| e->head.hflag = BM_edge_flag_from_mflag(medge[i].flag); | e->head.hflag = bm_edge_flag_from_mflag(medge[i].flag); | ||||
| if (hide_edge && hide_edge[i]) { | if (hide_edge && hide_edge[i]) { | ||||
| BM_elem_flag_enable(e, BM_ELEM_HIDDEN); | BM_elem_flag_enable(e, BM_ELEM_HIDDEN); | ||||
| } | } | ||||
| if (select_edge && select_edge[i]) { | if (select_edge && select_edge[i]) { | ||||
| BM_edge_select_set(bm, e, true); | BM_edge_select_set(bm, e, true); | ||||
| } | } | ||||
| if (!(sharp_edges && sharp_edges[i])) { | if (!(sharp_edges && sharp_edges[i])) { | ||||
| BM_elem_flag_enable(e, BM_ELEM_SMOOTH); | BM_elem_flag_enable(e, BM_ELEM_SMOOTH); | ||||
| Show All 33 Lines | if (UNLIKELY(f == nullptr)) { | ||||
| i); | i); | ||||
| continue; | continue; | ||||
| } | } | ||||
| /* Don't use 'i' since we may have skipped the face. */ | /* Don't use 'i' since we may have skipped the face. */ | ||||
| BM_elem_index_set(f, bm->totface - 1); /* set_ok */ | BM_elem_index_set(f, bm->totface - 1); /* set_ok */ | ||||
| /* Transfer flag. */ | /* Transfer flag. */ | ||||
| f->head.hflag = BM_face_flag_from_mflag(mpoly[i].flag); | f->head.hflag = bm_face_flag_from_mflag(mpoly[i].flag); | ||||
| if (hide_poly && hide_poly[i]) { | if (hide_poly && hide_poly[i]) { | ||||
| BM_elem_flag_enable(f, BM_ELEM_HIDDEN); | BM_elem_flag_enable(f, BM_ELEM_HIDDEN); | ||||
| } | } | ||||
| if (select_poly && select_poly[i]) { | if (select_poly && select_poly[i]) { | ||||
| BM_face_select_set(bm, f, true); | BM_face_select_set(bm, f, true); | ||||
| } | } | ||||
| f->mat_nr = material_indices == nullptr ? 0 : material_indices[i]; | f->mat_nr = material_indices == nullptr ? 0 : material_indices[i]; | ||||
| ▲ Show 20 Lines • Show All 645 Lines • ▼ Show 20 Lines | void BM_mesh_bm_to_me(Main *bmain, BMesh *bm, Mesh *me, const struct BMeshToMeshParams *params) | ||||
| } | } | ||||
| bm->elem_index_dirty &= ~BM_VERT; | bm->elem_index_dirty &= ~BM_VERT; | ||||
| i = 0; | i = 0; | ||||
| BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) { | BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) { | ||||
| medge[i].v1 = BM_elem_index_get(e->v1); | medge[i].v1 = BM_elem_index_get(e->v1); | ||||
| medge[i].v2 = BM_elem_index_get(e->v2); | medge[i].v2 = BM_elem_index_get(e->v2); | ||||
| medge[i].flag = BM_edge_flag_to_mflag(e); | medge[i].flag = bm_edge_flag_to_mflag(e); | ||||
| if (BM_elem_flag_test(e, BM_ELEM_HIDDEN)) { | if (BM_elem_flag_test(e, BM_ELEM_HIDDEN)) { | ||||
| need_hide_edge = true; | need_hide_edge = true; | ||||
| } | } | ||||
| if (BM_elem_flag_test(e, BM_ELEM_SELECT)) { | if (BM_elem_flag_test(e, BM_ELEM_SELECT)) { | ||||
| need_select_edge = true; | need_select_edge = true; | ||||
| } | } | ||||
| if (!BM_elem_flag_test(e, BM_ELEM_SMOOTH)) { | if (!BM_elem_flag_test(e, BM_ELEM_SMOOTH)) { | ||||
| need_sharp_edge = true; | need_sharp_edge = true; | ||||
| Show All 13 Lines | void BM_mesh_bm_to_me(Main *bmain, BMesh *bm, Mesh *me, const struct BMeshToMeshParams *params) | ||||
| j = 0; | j = 0; | ||||
| BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) { | BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) { | ||||
| BMLoop *l_iter, *l_first; | BMLoop *l_iter, *l_first; | ||||
| mpoly[i].loopstart = j; | mpoly[i].loopstart = j; | ||||
| mpoly[i].totloop = f->len; | mpoly[i].totloop = f->len; | ||||
| if (f->mat_nr != 0) { | if (f->mat_nr != 0) { | ||||
| need_material_index = true; | need_material_index = true; | ||||
| } | } | ||||
| mpoly[i].flag = BM_face_flag_to_mflag(f); | mpoly[i].flag = bm_face_flag_to_mflag(f); | ||||
| if (BM_elem_flag_test(f, BM_ELEM_HIDDEN)) { | if (BM_elem_flag_test(f, BM_ELEM_HIDDEN)) { | ||||
| need_hide_poly = true; | need_hide_poly = true; | ||||
| } | } | ||||
| if (BM_elem_flag_test(f, BM_ELEM_SELECT)) { | if (BM_elem_flag_test(f, BM_ELEM_SELECT)) { | ||||
| need_select_poly = true; | need_select_poly = true; | ||||
| } | } | ||||
| l_iter = l_first = BM_FACE_FIRST_LOOP(f); | l_iter = l_first = BM_FACE_FIRST_LOOP(f); | ||||
| ▲ Show 20 Lines • Show All 143 Lines • ▼ Show 20 Lines | if (cd_shape_keyindex_offset != -1) { | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| /* Topology could be changed, ensure #CD_MDISPS are ok. */ | /* Topology could be changed, ensure #CD_MDISPS are ok. */ | ||||
| multires_topology_changed(me); | multires_topology_changed(me); | ||||
| } | } | ||||
| namespace blender { | |||||
campbellbarton: Prefer to keep naming order matching most other BMesh functions, e.g. `bm_vert_table_build`… | |||||
| static void bm_vert_table_build(BMesh &bm, | |||||
| MutableSpan<const BMVert *> table, | |||||
| bool &need_select_vert, | |||||
| bool &need_hide_vert) | |||||
| { | |||||
| char hflag = 0; | |||||
| BMIter iter; | |||||
| int i; | |||||
| BMVert *vert; | |||||
| BM_ITER_MESH_INDEX (vert, &iter, &bm, BM_VERTS_OF_MESH, i) { | |||||
| BM_elem_index_set(vert, i); /* set_inline */ | |||||
| table[i] = vert; | |||||
| hflag |= vert->head.hflag; | |||||
| } | |||||
| need_select_vert |= (hflag & BM_ELEM_SELECT); | |||||
| need_hide_vert |= (hflag & BM_ELEM_HIDDEN); | |||||
| } | |||||
| static void bm_edge_table_build(BMesh &bm, | |||||
| MutableSpan<const BMEdge *> table, | |||||
| bool &need_select_edge, | |||||
| bool &need_hide_edge, | |||||
| bool &need_sharp_edge) | |||||
| { | |||||
| char hflag = 0; | |||||
| BMIter iter; | |||||
| int i; | |||||
| BMEdge *edge; | |||||
| BM_ITER_MESH_INDEX (edge, &iter, &bm, BM_EDGES_OF_MESH, i) { | |||||
| BM_elem_index_set(edge, i); /* set_inline */ | |||||
Done Inline ActionsWhile unlikely to be a big difference, this logic could OR the hflag then assign need_* variables at the end of the loop. campbellbarton: While unlikely to be a big difference, this logic could OR the `hflag` then assign `need_*`… | |||||
| table[i] = edge; | |||||
| hflag |= edge->head.hflag; | |||||
| } | |||||
| need_select_edge |= (hflag & BM_ELEM_SELECT); | |||||
| need_hide_edge |= (hflag & BM_ELEM_HIDDEN); | |||||
| need_sharp_edge |= (hflag & BM_ELEM_SMOOTH); | |||||
| } | |||||
| static void bm_face_loop_table_build(BMesh &bm, | |||||
| MutableSpan<const BMFace *> face_table, | |||||
| MutableSpan<const BMLoop *> loop_table, | |||||
| bool &need_select_poly, | |||||
| bool &need_hide_poly, | |||||
| bool &need_material_index) | |||||
| { | |||||
| char hflag = 0; | |||||
| BMIter iter; | |||||
| int face_i = 0; | |||||
| int loop_i = 0; | |||||
| BMFace *face; | |||||
| BM_ITER_MESH_INDEX (face, &iter, &bm, BM_FACES_OF_MESH, face_i) { | |||||
| BM_elem_index_set(face, face_i); /* set_inline */ | |||||
| face_table[face_i] = face; | |||||
| hflag |= face->head.hflag; | |||||
| need_material_index |= face->mat_nr != 0; | |||||
| BMLoop *loop = BM_FACE_FIRST_LOOP(face); | |||||
| for ([[maybe_unused]] const int i : IndexRange(face->len)) { | |||||
| BM_elem_index_set(loop, loop_i); /* set_inline */ | |||||
| loop_table[loop_i] = loop; | |||||
| loop = loop->next; | |||||
| loop_i++; | |||||
| } | |||||
| } | |||||
| need_select_poly |= (hflag & BM_ELEM_SELECT); | |||||
| need_hide_poly |= (hflag & BM_ELEM_HIDDEN); | |||||
| } | |||||
| static void bm_to_mesh_verts(const BMesh &bm, | |||||
| const Span<const BMVert *> bm_verts, | |||||
| Mesh &mesh, | |||||
| MutableSpan<bool> select_vert, | |||||
| MutableSpan<bool> hide_vert) | |||||
| { | |||||
| MutableSpan<float3> dst_vert_positions = mesh.vert_positions_for_write(); | |||||
| threading::parallel_for(dst_vert_positions.index_range(), 1024, [&](const IndexRange range) { | |||||
| for (const int vert_i : range) { | |||||
| const BMVert &src_vert = *bm_verts[vert_i]; | |||||
| copy_v3_v3(dst_vert_positions[vert_i], src_vert.co); | |||||
| CustomData_from_bmesh_block(&bm.vdata, &mesh.vdata, src_vert.head.data, vert_i); | |||||
| } | |||||
| if (!select_vert.is_empty()) { | |||||
| for (const int vert_i : range) { | |||||
| select_vert[vert_i] = BM_elem_flag_test(bm_verts[vert_i], BM_ELEM_SELECT); | |||||
| } | |||||
| } | |||||
| if (!hide_vert.is_empty()) { | |||||
| for (const int vert_i : range) { | |||||
| hide_vert[vert_i] = BM_elem_flag_test(bm_verts[vert_i], BM_ELEM_HIDDEN); | |||||
| } | |||||
| } | |||||
| }); | |||||
| } | |||||
| static void bm_to_mesh_edges(const BMesh &bm, | |||||
| const Span<const BMEdge *> bm_edges, | |||||
| Mesh &mesh, | |||||
| MutableSpan<bool> select_edge, | |||||
| MutableSpan<bool> hide_edge, | |||||
| MutableSpan<bool> sharp_edge) | |||||
| { | |||||
| MutableSpan<MEdge> dst_edges = mesh.edges_for_write(); | |||||
| threading::parallel_for(dst_edges.index_range(), 512, [&](const IndexRange range) { | |||||
| for (const int edge_i : range) { | |||||
| const BMEdge &src_edge = *bm_edges[edge_i]; | |||||
| MEdge &dst_edge = dst_edges[edge_i]; | |||||
| dst_edge.v1 = BM_elem_index_get(src_edge.v1); | |||||
| dst_edge.v2 = BM_elem_index_get(src_edge.v2); | |||||
| dst_edge.flag = bm_edge_flag_to_mflag(&src_edge); | |||||
| /* Handle this differently to editmode switching; only enable draw for single user | |||||
| * edges rather than calculating angle. */ | |||||
| if ((dst_edge.flag & ME_EDGEDRAW) == 0) { | |||||
| if (src_edge.l && src_edge.l == src_edge.l->radial_next) { | |||||
| dst_edge.flag |= ME_EDGEDRAW; | |||||
| } | |||||
| } | |||||
| CustomData_from_bmesh_block(&bm.edata, &mesh.edata, src_edge.head.data, edge_i); | |||||
| } | |||||
| if (!select_edge.is_empty()) { | |||||
| for (const int edge_i : range) { | |||||
| select_edge[edge_i] = BM_elem_flag_test(bm_edges[edge_i], BM_ELEM_SELECT); | |||||
| } | |||||
| } | |||||
| if (!hide_edge.is_empty()) { | |||||
| for (const int edge_i : range) { | |||||
| hide_edge[edge_i] = BM_elem_flag_test(bm_edges[edge_i], BM_ELEM_HIDDEN); | |||||
| } | |||||
| } | |||||
| if (!sharp_edge.is_empty()) { | |||||
| for (const int edge_i : range) { | |||||
| sharp_edge[edge_i] = !BM_elem_flag_test(bm_edges[edge_i], BM_ELEM_SMOOTH); | |||||
| } | |||||
| } | |||||
| }); | |||||
| } | |||||
| static void bm_to_mesh_faces(const BMesh &bm, | |||||
| const Span<const BMFace *> bm_faces, | |||||
| Mesh &mesh, | |||||
| MutableSpan<bool> select_poly, | |||||
| MutableSpan<bool> hide_poly, | |||||
| MutableSpan<int> material_indices) | |||||
| { | |||||
| MutableSpan<MPoly> dst_polys = mesh.polys_for_write(); | |||||
| threading::parallel_for(dst_polys.index_range(), 1024, [&](const IndexRange range) { | |||||
| for (const int face_i : range) { | |||||
| const BMFace &src_face = *bm_faces[face_i]; | |||||
| MPoly &dst_poly = dst_polys[face_i]; | |||||
| dst_poly.totloop = src_face.len; | |||||
| dst_poly.loopstart = BM_elem_index_get(BM_FACE_FIRST_LOOP(&src_face)); | |||||
| dst_poly.flag = bm_face_flag_to_mflag(&src_face); | |||||
| CustomData_from_bmesh_block(&bm.pdata, &mesh.pdata, src_face.head.data, face_i); | |||||
| } | |||||
| if (!select_poly.is_empty()) { | |||||
| for (const int face_i : range) { | |||||
| select_poly[face_i] = BM_elem_flag_test(bm_faces[face_i], BM_ELEM_SELECT); | |||||
| } | |||||
| } | |||||
| if (!hide_poly.is_empty()) { | |||||
| for (const int face_i : range) { | |||||
| hide_poly[face_i] = BM_elem_flag_test(bm_faces[face_i], BM_ELEM_HIDDEN); | |||||
| } | |||||
| } | |||||
| if (!material_indices.is_empty()) { | |||||
| for (const int face_i : range) { | |||||
| material_indices[face_i] = bm_faces[face_i]->mat_nr; | |||||
| } | |||||
| } | |||||
| }); | |||||
| } | |||||
| static void bm_to_mesh_loops(const BMesh &bm, const Span<const BMLoop *> bm_loops, Mesh &mesh) | |||||
| { | |||||
| MutableSpan<MLoop> dst_loops = mesh.loops_for_write(); | |||||
| threading::parallel_for(dst_loops.index_range(), 1024, [&](const IndexRange range) { | |||||
| for (const int loop_i : range) { | |||||
| const BMLoop &src_loop = *bm_loops[loop_i]; | |||||
| MLoop &dst_loop = dst_loops[loop_i]; | |||||
| dst_loop.v = BM_elem_index_get(src_loop.v); | |||||
| dst_loop.e = BM_elem_index_get(src_loop.e); | |||||
| CustomData_from_bmesh_block(&bm.ldata, &mesh.ldata, src_loop.head.data, loop_i); | |||||
| } | |||||
| }); | |||||
| } | |||||
| } // namespace blender | |||||
| /* NOTE: The function is called from multiple threads with the same input BMesh and different | /* NOTE: The function is called from multiple threads with the same input BMesh and different | ||||
| * mesh objects. */ | * mesh objects. */ | ||||
| void BM_mesh_bm_to_me_for_eval(BMesh *bm, Mesh *me, const CustomData_MeshMasks *cd_mask_extra) | void BM_mesh_bm_to_me_for_eval(BMesh *bm, Mesh *me, const CustomData_MeshMasks *cd_mask_extra) | ||||
| { | { | ||||
| using namespace blender; | using namespace blender; | ||||
| /* Must be an empty mesh. */ | /* Must be an empty mesh. */ | ||||
| BLI_assert(me->totvert == 0); | BLI_assert(me->totvert == 0); | ||||
| BLI_assert(cd_mask_extra == nullptr || (cd_mask_extra->vmask & CD_MASK_SHAPEKEY) == 0); | BLI_assert(cd_mask_extra == nullptr || (cd_mask_extra->vmask & CD_MASK_SHAPEKEY) == 0); | ||||
| /* Just in case, clear the derived geometry caches from the input mesh. */ | /* Just in case, clear the derived geometry caches from the input mesh. */ | ||||
| BKE_mesh_runtime_clear_geometry(me); | BKE_mesh_runtime_clear_geometry(me); | ||||
| me->totvert = bm->totvert; | me->totvert = bm->totvert; | ||||
| me->totedge = bm->totedge; | me->totedge = bm->totedge; | ||||
| me->totface = 0; | me->totface = 0; | ||||
| me->totloop = bm->totloop; | me->totloop = bm->totloop; | ||||
| me->totpoly = bm->totface; | me->totpoly = bm->totface; | ||||
| if (!CustomData_get_layer_named(&me->vdata, CD_PROP_FLOAT3, "position")) { | if (!CustomData_get_layer_named(&me->vdata, CD_PROP_FLOAT3, "position")) { | ||||
| CustomData_add_layer_named( | CustomData_add_layer_named( | ||||
| &me->vdata, CD_PROP_FLOAT3, CD_CONSTRUCT, nullptr, bm->totvert, "position"); | &me->vdata, CD_PROP_FLOAT3, CD_CONSTRUCT, nullptr, bm->totvert, "position"); | ||||
| } | } | ||||
| CustomData_add_layer(&me->edata, CD_MEDGE, CD_SET_DEFAULT, nullptr, bm->totedge); | CustomData_add_layer(&me->edata, CD_MEDGE, CD_CONSTRUCT, nullptr, bm->totedge); | ||||
| CustomData_add_layer(&me->ldata, CD_MLOOP, CD_SET_DEFAULT, nullptr, bm->totloop); | CustomData_add_layer(&me->ldata, CD_MLOOP, CD_CONSTRUCT, nullptr, bm->totloop); | ||||
| CustomData_add_layer(&me->pdata, CD_MPOLY, CD_SET_DEFAULT, nullptr, bm->totface); | CustomData_add_layer(&me->pdata, CD_MPOLY, CD_CONSTRUCT, nullptr, bm->totface); | ||||
| /* Don't process shape-keys, we only feed them through the modifier stack as needed, | /* Don't process shape-keys, we only feed them through the modifier stack as needed, | ||||
| * e.g. for applying modifiers or the like. */ | * e.g. for applying modifiers or the like. */ | ||||
| CustomData_MeshMasks mask = CD_MASK_DERIVEDMESH; | CustomData_MeshMasks mask = CD_MASK_DERIVEDMESH; | ||||
| if (cd_mask_extra != nullptr) { | if (cd_mask_extra != nullptr) { | ||||
| CustomData_MeshMasks_update(&mask, cd_mask_extra); | CustomData_MeshMasks_update(&mask, cd_mask_extra); | ||||
| } | } | ||||
| mask.vmask &= ~CD_MASK_SHAPEKEY; | mask.vmask &= ~CD_MASK_SHAPEKEY; | ||||
| CustomData_merge(&bm->vdata, &me->vdata, mask.vmask, CD_SET_DEFAULT, me->totvert); | CustomData_merge(&bm->vdata, &me->vdata, mask.vmask, CD_CONSTRUCT, me->totvert); | ||||
| CustomData_merge(&bm->edata, &me->edata, mask.emask, CD_SET_DEFAULT, me->totedge); | CustomData_merge(&bm->edata, &me->edata, mask.emask, CD_CONSTRUCT, me->totedge); | ||||
| CustomData_merge(&bm->ldata, &me->ldata, mask.lmask, CD_SET_DEFAULT, me->totloop); | CustomData_merge(&bm->ldata, &me->ldata, mask.lmask, CD_CONSTRUCT, me->totloop); | ||||
| CustomData_merge(&bm->pdata, &me->pdata, mask.pmask, CD_SET_DEFAULT, me->totpoly); | CustomData_merge(&bm->pdata, &me->pdata, mask.pmask, CD_CONSTRUCT, me->totpoly); | ||||
| BMIter iter; | |||||
| BMVert *eve; | |||||
| BMEdge *eed; | |||||
| BMFace *efa; | |||||
| MutableSpan<float3> positions = me->vert_positions_for_write(); | |||||
| MutableSpan<MEdge> medge = me->edges_for_write(); | |||||
| MutableSpan<MPoly> mpoly = me->polys_for_write(); | |||||
| MutableSpan<MLoop> loops = me->loops_for_write(); | |||||
| MLoop *mloop = loops.data(); | |||||
| uint i, j; | |||||
| me->runtime->deformed_only = true; | me->runtime->deformed_only = true; | ||||
| bke::MutableAttributeAccessor mesh_attributes = me->attributes_for_write(); | /* In a first pass, update indices of BMesh elements and build tables for easy iteration later. | ||||
| * Also check if some optional mesh attributes should be added in the next step. Since each | |||||
| bke::SpanAttributeWriter<bool> hide_vert_attribute; | * domain has no effect on others, process the independent domains on separate threads. */ | ||||
| bke::SpanAttributeWriter<bool> select_vert_attribute; | bool need_select_vert = false; | ||||
| BM_ITER_MESH_INDEX (eve, &iter, bm, BM_VERTS_OF_MESH, i) { | bool need_select_edge = false; | ||||
| copy_v3_v3(positions[i], eve->co); | bool need_select_poly = false; | ||||
| bool need_hide_vert = false; | |||||
| BM_elem_index_set(eve, i); /* set_inline */ | bool need_hide_edge = false; | ||||
| bool need_hide_poly = false; | |||||
| if (BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) { | bool need_material_index = false; | ||||
| if (!hide_vert_attribute) { | bool need_sharp_edge = false; | ||||
| hide_vert_attribute = mesh_attributes.lookup_or_add_for_write_span<bool>( | Array<const BMVert *> vert_table; | ||||
| ".hide_vert", ATTR_DOMAIN_POINT); | Array<const BMEdge *> edge_table; | ||||
| } | Array<const BMFace *> face_table; | ||||
| hide_vert_attribute.span[i] = true; | Array<const BMLoop *> loop_table; | ||||
| } | threading::parallel_invoke( | ||||
| if (BM_elem_flag_test(eve, BM_ELEM_SELECT)) { | me->totface > 1024, | ||||
| if (!select_vert_attribute) { | [&]() { | ||||
| select_vert_attribute = mesh_attributes.lookup_or_add_for_write_span<bool>( | vert_table.reinitialize(bm->totvert); | ||||
| ".select_vert", ATTR_DOMAIN_POINT); | bm_vert_table_build(*bm, vert_table, need_select_vert, need_hide_vert); | ||||
| } | }, | ||||
| select_vert_attribute.span[i] = true; | [&]() { | ||||
| } | edge_table.reinitialize(bm->totedge); | ||||
| bm_edge_table_build(*bm, edge_table, need_select_edge, need_hide_edge, need_sharp_edge); | |||||
| CustomData_from_bmesh_block(&bm->vdata, &me->vdata, eve->head.data, i); | }, | ||||
| } | [&]() { | ||||
| bm->elem_index_dirty &= ~BM_VERT; | face_table.reinitialize(bm->totface); | ||||
| loop_table.reinitialize(bm->totloop); | |||||
| bke::SpanAttributeWriter<bool> hide_edge_attribute; | bm_face_loop_table_build( | ||||
| bke::SpanAttributeWriter<bool> select_edge_attribute; | *bm, face_table, loop_table, need_select_poly, need_hide_poly, need_material_index); | ||||
| bke::SpanAttributeWriter<bool> sharp_edge_attribute; | }); | ||||
| BM_ITER_MESH_INDEX (eed, &iter, bm, BM_EDGES_OF_MESH, i) { | bm->elem_index_dirty &= ~(BM_VERT | BM_EDGE | BM_FACE | BM_LOOP); | ||||
| MEdge *med = &medge[i]; | |||||
| BM_elem_index_set(eed, i); /* set_inline */ | |||||
| med->v1 = BM_elem_index_get(eed->v1); | |||||
| med->v2 = BM_elem_index_get(eed->v2); | |||||
| med->flag = BM_edge_flag_to_mflag(eed); | /* Add optional mesh attributes before parallel iteration. */ | ||||
| if (BM_elem_flag_test(eed, BM_ELEM_HIDDEN)) { | assert_bmesh_has_no_mesh_only_attributes(*bm); | ||||
| if (!hide_edge_attribute) { | bke::MutableAttributeAccessor attrs = me->attributes_for_write(); | ||||
| hide_edge_attribute = mesh_attributes.lookup_or_add_for_write_span<bool>(".hide_edge", | bke::SpanAttributeWriter<bool> select_vert; | ||||
| ATTR_DOMAIN_EDGE); | bke::SpanAttributeWriter<bool> hide_vert; | ||||
| bke::SpanAttributeWriter<bool> select_edge; | |||||
| bke::SpanAttributeWriter<bool> hide_edge; | |||||
| bke::SpanAttributeWriter<bool> sharp_edge; | |||||
| bke::SpanAttributeWriter<bool> select_poly; | |||||
| bke::SpanAttributeWriter<bool> hide_poly; | |||||
| bke::SpanAttributeWriter<int> material_index; | |||||
| if (need_select_vert) { | |||||
| select_vert = attrs.lookup_or_add_for_write_only_span<bool>(".select_vert", ATTR_DOMAIN_POINT); | |||||
| } | } | ||||
| hide_edge_attribute.span[i] = true; | if (need_hide_vert) { | ||||
| hide_vert = attrs.lookup_or_add_for_write_only_span<bool>(".hide_vert", ATTR_DOMAIN_POINT); | |||||
| } | } | ||||
| if (BM_elem_flag_test(eed, BM_ELEM_SELECT)) { | if (need_select_edge) { | ||||
| if (!select_edge_attribute) { | select_edge = attrs.lookup_or_add_for_write_only_span<bool>(".select_edge", ATTR_DOMAIN_EDGE); | ||||
| select_edge_attribute = mesh_attributes.lookup_or_add_for_write_span<bool>( | |||||
| ".select_edge", ATTR_DOMAIN_EDGE); | |||||
| } | } | ||||
| select_edge_attribute.span[i] = true; | if (need_sharp_edge) { | ||||
| sharp_edge = attrs.lookup_or_add_for_write_only_span<bool>("sharp_edge", ATTR_DOMAIN_EDGE); | |||||
| } | } | ||||
| if (!BM_elem_flag_test(eed, BM_ELEM_SMOOTH)) { | if (need_hide_edge) { | ||||
| if (!sharp_edge_attribute) { | hide_edge = attrs.lookup_or_add_for_write_only_span<bool>(".hide_edge", ATTR_DOMAIN_EDGE); | ||||
| sharp_edge_attribute = mesh_attributes.lookup_or_add_for_write_span<bool>( | |||||
| "sharp_edge", ATTR_DOMAIN_EDGE); | |||||
| } | } | ||||
| sharp_edge_attribute.span[i] = true; | if (need_select_poly) { | ||||
| select_poly = attrs.lookup_or_add_for_write_only_span<bool>(".select_poly", ATTR_DOMAIN_FACE); | |||||
| } | } | ||||
| if (need_hide_poly) { | |||||
| CustomData_from_bmesh_block(&bm->edata, &me->edata, eed->head.data, i); | hide_poly = attrs.lookup_or_add_for_write_only_span<bool>(".hide_poly", ATTR_DOMAIN_FACE); | ||||
| } | } | ||||
| bm->elem_index_dirty &= ~BM_EDGE; | if (need_material_index) { | ||||
| material_index = attrs.lookup_or_add_for_write_only_span<int>("material_index", | |||||
| j = 0; | |||||
| bke::SpanAttributeWriter<int> material_index_attribute; | |||||
| bke::SpanAttributeWriter<bool> hide_poly_attribute; | |||||
| bke::SpanAttributeWriter<bool> select_poly_attribute; | |||||
| BM_ITER_MESH_INDEX (efa, &iter, bm, BM_FACES_OF_MESH, i) { | |||||
| BMLoop *l_iter; | |||||
| BMLoop *l_first; | |||||
| MPoly *mp = &mpoly[i]; | |||||
| BM_elem_index_set(efa, i); /* set_inline */ | |||||
| mp->totloop = efa->len; | |||||
| mp->flag = BM_face_flag_to_mflag(efa); | |||||
| if (BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) { | |||||
| if (!hide_poly_attribute) { | |||||
| hide_poly_attribute = mesh_attributes.lookup_or_add_for_write_span<bool>(".hide_poly", | |||||
| ATTR_DOMAIN_FACE); | ATTR_DOMAIN_FACE); | ||||
| } | } | ||||
| hide_poly_attribute.span[i] = true; | |||||
| } | |||||
| if (BM_elem_flag_test(efa, BM_ELEM_SELECT)) { | |||||
| if (!select_poly_attribute) { | |||||
| select_poly_attribute = mesh_attributes.lookup_or_add_for_write_span<bool>( | |||||
| ".select_poly", ATTR_DOMAIN_FACE); | |||||
| } | |||||
| select_poly_attribute.span[i] = true; | |||||
| } | |||||
| mp->loopstart = j; | |||||
| if (efa->mat_nr != 0) { | |||||
| if (!material_index_attribute) { | |||||
| material_index_attribute = mesh_attributes.lookup_or_add_for_write_span<int>( | |||||
| "material_index", ATTR_DOMAIN_FACE); | |||||
| } | |||||
| material_index_attribute.span[i] = efa->mat_nr; | |||||
| } | |||||
| l_iter = l_first = BM_FACE_FIRST_LOOP(efa); | |||||
| do { | |||||
| mloop->v = BM_elem_index_get(l_iter->v); | |||||
| mloop->e = BM_elem_index_get(l_iter->e); | |||||
| CustomData_from_bmesh_block(&bm->ldata, &me->ldata, l_iter->head.data, j); | |||||
| BM_elem_index_set(l_iter, j); /* set_inline */ | |||||
| j++; | |||||
| mloop++; | |||||
| } while ((l_iter = l_iter->next) != l_first); | |||||
| CustomData_from_bmesh_block(&bm->pdata, &me->pdata, efa->head.data, i); | |||||
| } | |||||
| bm->elem_index_dirty &= ~(BM_FACE | BM_LOOP); | |||||
| assert_bmesh_has_no_mesh_only_attributes(*bm); | |||||
| material_index_attribute.finish(); | /* Loop over all elements in parallel, copying attributes and building the Mesh topology. */ | ||||
| hide_vert_attribute.finish(); | threading::parallel_invoke( | ||||
| hide_edge_attribute.finish(); | me->totvert > 1024, | ||||
| hide_poly_attribute.finish(); | [&]() { bm_to_mesh_verts(*bm, vert_table, *me, select_vert.span, hide_vert.span); }, | ||||
| select_vert_attribute.finish(); | [&]() { | ||||
| select_edge_attribute.finish(); | bm_to_mesh_edges(*bm, edge_table, *me, select_edge.span, hide_edge.span, sharp_edge.span); | ||||
| select_poly_attribute.finish(); | }, | ||||
| sharp_edge_attribute.finish(); | [&]() { | ||||
| bm_to_mesh_faces( | |||||
| *bm, face_table, *me, select_poly.span, hide_poly.span, material_index.span); | |||||
| }, | |||||
| [&]() { bm_to_mesh_loops(*bm, loop_table, *me); }); | |||||
| select_vert.finish(); | |||||
| hide_vert.finish(); | |||||
| select_edge.finish(); | |||||
| hide_edge.finish(); | |||||
| sharp_edge.finish(); | |||||
| select_poly.finish(); | |||||
| hide_poly.finish(); | |||||
| material_index.finish(); | |||||
| } | } | ||||
Prefer to keep naming order matching most other BMesh functions, e.g. bm_vert_table_build, could also call bm_vert_table_build_and_calc_needs