diff options
author | Campbell Barton <ideasman42@gmail.com> | 2017-03-11 12:39:28 +0300 |
---|---|---|
committer | Campbell Barton <ideasman42@gmail.com> | 2017-03-11 12:50:32 +0300 |
commit | 5afe4c787f0ed3ac30f7609c7f07c5092a20eac9 (patch) | |
tree | 2e424260547c1615efdc21aa9a3c9bfa2bc23ab3 /source/blender | |
parent | 5be8adf8c08e8b774577045bc9b1bc0c15353caa (diff) |
BMesh: add BM_mesh_separate_faces
Fast-path for bmesh split operator which duplicates and deletes.
Use when only separating faces, currently used by the intersect tool.
Diffstat (limited to 'source/blender')
-rw-r--r-- | source/blender/bmesh/CMakeLists.txt | 2 | ||||
-rw-r--r-- | source/blender/bmesh/bmesh_tools.h | 1 | ||||
-rw-r--r-- | source/blender/bmesh/operators/bmo_dupe.c | 4 | ||||
-rw-r--r-- | source/blender/bmesh/tools/bmesh_separate.c | 131 | ||||
-rw-r--r-- | source/blender/bmesh/tools/bmesh_separate.h | 32 | ||||
-rw-r--r-- | source/blender/editors/mesh/editmesh_intersect.c | 11 |
6 files changed, 174 insertions, 7 deletions
diff --git a/source/blender/bmesh/CMakeLists.txt b/source/blender/bmesh/CMakeLists.txt index 30fefe37f0e..ea24da86626 100644 --- a/source/blender/bmesh/CMakeLists.txt +++ b/source/blender/bmesh/CMakeLists.txt @@ -152,6 +152,8 @@ set(SRC tools/bmesh_path_region.h tools/bmesh_region_match.c tools/bmesh_region_match.h + tools/bmesh_separate.c + tools/bmesh_separate.h tools/bmesh_triangulate.c tools/bmesh_triangulate.h tools/bmesh_wireframe.c diff --git a/source/blender/bmesh/bmesh_tools.h b/source/blender/bmesh/bmesh_tools.h index 23212dd085e..a537c3b872c 100644 --- a/source/blender/bmesh/bmesh_tools.h +++ b/source/blender/bmesh/bmesh_tools.h @@ -43,6 +43,7 @@ extern "C" { #include "tools/bmesh_path.h" #include "tools/bmesh_path_region.h" #include "tools/bmesh_region_match.h" +#include "tools/bmesh_separate.h" #include "tools/bmesh_triangulate.h" #ifdef __cplusplus diff --git a/source/blender/bmesh/operators/bmo_dupe.c b/source/blender/bmesh/operators/bmo_dupe.c index 56639a097b6..8048add84d4 100644 --- a/source/blender/bmesh/operators/bmo_dupe.c +++ b/source/blender/bmesh/operators/bmo_dupe.c @@ -378,6 +378,10 @@ void BMO_dupe_from_flag(BMesh *bm, int htype, const char hflag) * BMOP_DUPE_VOUTPUT: Buffer containing pointers to the split mesh vertices * BMOP_DUPE_EOUTPUT: Buffer containing pointers to the split mesh edges * BMOP_DUPE_FOUTPUT: Buffer containing pointers to the split mesh faces + * + * \note Lower level uses of this operator may want to use #BM_mesh_separate_faces + * Since it's faster for the 'use_only_faces' case. + * */ void bmo_split_exec(BMesh *bm, BMOperator *op) { diff --git a/source/blender/bmesh/tools/bmesh_separate.c b/source/blender/bmesh/tools/bmesh_separate.c new file mode 100644 index 00000000000..571da2ff94c --- /dev/null +++ b/source/blender/bmesh/tools/bmesh_separate.c @@ -0,0 +1,131 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/bmesh/tools/bmesh_separate.c + * \ingroup bmesh + * + * BMesh separate, disconnects a set of faces from all others, + * so they don't share any vertices/edges with other faces. + */ + +#include <limits.h> + +#include "MEM_guardedalloc.h" + +#include "BLI_utildefines.h" +#include "BLI_buffer.h" + +#include "bmesh.h" +#include "intern/bmesh_private.h" +#include "bmesh_separate.h" /* own include */ + +/** + * Split all faces that match `filter_fn`. + * \note + */ +void BM_mesh_separate_faces( + BMesh *bm, + BMFaceFilterFunc filter_fn, void *user_data) +{ + BMFace **faces_array_all = MEM_mallocN(bm->totface * sizeof(BMFace *), __func__); + /* + * - Create an array of faces based on 'filter_fn'. + * First part of array for match, for non-match. + * + * - Clear all vertex tags, then tag all vertices from 'faces_b'. + * + * - Loop over 'faces_a', checking each vertex, + * splitting out any which are tagged (and therefor shared). + */ + + BMFace *f; + BMIter iter; + + unsigned int faces_a_len = 0; + unsigned int faces_b_len = 0; + { + int i_a = 0; + int i_b = bm->totface; + BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) { + faces_array_all[filter_fn(f, user_data) ? i_a++ : --i_b] = f; + } + faces_a_len = i_a; + faces_b_len = bm->totface - i_a; + } + + BMFace **faces_a = faces_array_all; + BMFace **faces_b = faces_array_all + faces_a_len; + + /* Enable for all */ + BM_mesh_elem_hflag_enable_all(bm, BM_VERT, BM_ELEM_TAG, false); + + /* Disable vert tag on faces_b */ + for (unsigned int i = 0; i < faces_b_len; i++) { + BMLoop *l_iter, *l_first; + l_iter = l_first = BM_FACE_FIRST_LOOP(faces_b[i]); + do { + BM_elem_flag_disable(l_iter->v, BM_ELEM_TAG); + } while ((l_iter = l_iter->next) != l_first); + } + + + BLI_buffer_declare_static(BMLoop **, loop_split, 0, 128); + + /* Check shared verts ('faces_a' tag and disable) */ + for (unsigned int i = 0; i < faces_a_len; i++) { + BMLoop *l_iter, *l_first; + l_iter = l_first = BM_FACE_FIRST_LOOP(faces_a[i]); + do { + if (!BM_elem_flag_test(l_iter->v, BM_ELEM_TAG)) { + BMVert *v = l_iter->v; + /* Disable, since we may visit this vertex again on other faces */ + BM_elem_flag_disable(v, BM_ELEM_TAG); + + /* We know the vertex is shared, collect all vertices and split them off. */ + + /* Fill 'loop_split' */ + { + BMEdge *e_first, *e_iter; + e_iter = e_first = l_iter->e; + do { + BMLoop *l_radial_first, *l_radial_iter; + l_radial_first = l_radial_iter = e_iter->l; + do { + if (l_radial_iter->v == v) { + if (filter_fn(l_radial_iter->f, user_data)) { + BLI_buffer_append(&loop_split, BMLoop *, l_radial_iter); + } + } + } while ((l_radial_iter = l_radial_iter->radial_next) != l_radial_first); + } while ((e_iter = bmesh_disk_edge_next(e_iter, v)) != e_first); + } + + /* Perform the split */ + bmesh_urmv_loop_multi(bm, loop_split.data, loop_split.count); + + BLI_buffer_empty(&loop_split); + } + } while ((l_iter = l_iter->next) != l_first); + } + + BLI_buffer_free(&loop_split); + + MEM_freeN(faces_array_all); +} diff --git a/source/blender/bmesh/tools/bmesh_separate.h b/source/blender/bmesh/tools/bmesh_separate.h new file mode 100644 index 00000000000..91b2b71c872 --- /dev/null +++ b/source/blender/bmesh/tools/bmesh_separate.h @@ -0,0 +1,32 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#ifndef __BMESH_SEPARATE_H__ +#define __BMESH_SEPARATE_H__ + +/** \file blender/bmesh/tools/bmesh_separate.h + * \ingroup bmesh + */ + +void BM_mesh_separate_faces( + BMesh *bm, + BMFaceFilterFunc filter_fn, void *user_data); + +#endif /* __BMESH_SEPARATE_H__ */ diff --git a/source/blender/editors/mesh/editmesh_intersect.c b/source/blender/editors/mesh/editmesh_intersect.c index bc9088401db..49bfde77032 100644 --- a/source/blender/editors/mesh/editmesh_intersect.c +++ b/source/blender/editors/mesh/editmesh_intersect.c @@ -51,6 +51,7 @@ #include "mesh_intern.h" /* own include */ #include "tools/bmesh_intersect.h" +#include "tools/bmesh_separate.h" /* detect isolated holes and fill them */ @@ -196,13 +197,9 @@ static int edbm_intersect_exec(bContext *C, wmOperator *op) if (use_separate_cut) { /* detach selected/un-selected faces */ - BMOperator bmop; - EDBM_op_init(em, &bmop, op, "split geom=%hf use_only_faces=%b", BM_ELEM_SELECT, true); - BMO_op_exec(em->bm, &bmop); - if (!EDBM_op_finish(em, &bmop, op, true)) { - /* should never happen! */ - BKE_report(op->reports, RPT_ERROR, "Error separating"); - } + BM_mesh_separate_faces( + bm, + BM_elem_cb_check_hflag_enabled_simple(const BMFace *, BM_ELEM_SELECT)); } if (has_isect) { |