diff --git a/.clang-format b/.clang-format index 72add4594a4..4c140988720 100644 --- a/.clang-format +++ b/.clang-format @@ -162,6 +162,7 @@ PenaltyBreakString: 1000000 ForEachMacros: - BEGIN_ANIMFILTER_SUBCHANNELS - BKE_pbvh_vertex_iter_begin + - BKE_pbvh_face_iter_begin - BLI_FOREACH_SPARSE_RANGE - BLI_SMALLSTACK_ITER_BEGIN - BMO_ITER diff --git a/source/blender/blenkernel/BKE_pbvh.h b/source/blender/blenkernel/BKE_pbvh.h index 4badd1bc269..757a2e0f396 100644 --- a/source/blender/blenkernel/BKE_pbvh.h +++ b/source/blender/blenkernel/BKE_pbvh.h @@ -69,14 +69,22 @@ struct PBVHPublic { * intptr_t's in structs. */ +/* A generic PBVH vertex. + * + * Note: in PBVH_GRIDS we consider the final grid points + * to be vertices. This is not true of edges or faces which are pulled from + * the base mesh. + */ typedef struct PBVHVertRef { intptr_t i; } PBVHVertRef; +/* Note: edges in PBVH_GRIDS are always pulled from the base mesh.*/ typedef struct PBVHEdgeRef { intptr_t i; } PBVHEdgeRef; +/* Note: faces in PBVH_GRIDS are always puled from the base mesh.*/ typedef struct PBVHFaceRef { intptr_t i; } PBVHFaceRef; @@ -665,6 +673,57 @@ void pbvh_vertex_iter_init(PBVH *pbvh, PBVHNode *node, PBVHVertexIter *vi, int m } \ ((void)0) +#define PBVH_FACE_ITER_VERTS_RESERVED 8 + +typedef struct PBVHFaceIter { + PBVHFaceRef face; + int index; + bool *hide; + int *face_set; + int i; + + PBVHVertRef *verts; + int verts_num; + + /* Private. */ +#ifdef __cplusplus + private: +#endif + + PBVHVertRef verts_reserved_[PBVH_FACE_ITER_VERTS_RESERVED]; + const PBVHNode *node_; + PBVHType pbvh_type_; + int verts_size_; + GSetIterator bm_faces_iter_; + int cd_hide_poly_, cd_face_set_; + bool *hide_poly_; + int *face_sets_; + const struct MPoly *mpoly_; + const struct MLoopTri *looptri_; + const struct MLoop *mloop_; + int prim_index_; + const struct SubdivCCG *subdiv_ccg_; + const struct BMesh *bm; + + int last_face_index_; +} PBVHFaceIter; + +void BKE_pbvh_face_iter_init(PBVH *pbvh, PBVHNode *node, PBVHFaceIter *fd); +void BKE_pbvh_face_iter_step(PBVHFaceIter *fd); +bool BKE_pbvh_face_iter_done(PBVHFaceIter *fd); +void BKE_pbvh_face_iter_finish(PBVHFaceIter *fd); + +/** Iterate over faces inside a PBVHNode. These are either base mesh faces + * (for PBVH_FACES and PBVH_GRIDS) or BMesh faces (for PBVH_BMESH). + */ +#define BKE_pbvh_face_iter_begin(pbvh, node, fd) \ + BKE_pbvh_face_iter_init(pbvh, node, &fd); \ + for (; !BKE_pbvh_face_iter_done(&fd); BKE_pbvh_face_iter_step(&fd)) { + +#define BKE_pbvh_face_iter_end(fd) \ + } \ + BKE_pbvh_face_iter_finish(&fd) + void BKE_pbvh_node_get_proxies(PBVHNode *node, PBVHProxyNode **proxies, int *proxy_count); void BKE_pbvh_node_free_proxies(PBVHNode *node); PBVHProxyNode *BKE_pbvh_node_add_proxy(PBVH *pbvh, PBVHNode *node); diff --git a/source/blender/blenkernel/intern/pbvh.c b/source/blender/blenkernel/intern/pbvh.c index aa7a9804437..e3a272888a7 100644 --- a/source/blender/blenkernel/intern/pbvh.c +++ b/source/blender/blenkernel/intern/pbvh.c @@ -853,6 +853,9 @@ void BKE_pbvh_build_grids(PBVH *pbvh, pbvh->ldata = &me->ldata; pbvh->pdata = &me->pdata; + pbvh->mpoly = BKE_mesh_polys(me); + pbvh->mloop = BKE_mesh_loops(me); + /* We also need the base mesh for PBVH draw. */ pbvh->mesh = me; @@ -3519,3 +3522,183 @@ int BKE_pbvh_debug_draw_gen_get(PBVHNode *node) { return node->debug_draw_gen; } + +static void pbvh_face_iter_verts_reserve(PBVHFaceIter *fd, int verts_num) +{ + if (verts_num >= fd->verts_size_) { + fd->verts_size_ = (verts_num + 1) << 2; + + if (fd->verts != fd->verts_reserved_) { + MEM_SAFE_FREE(fd->verts); + } + + fd->verts = MEM_malloc_arrayN(fd->verts_size_, sizeof(void *), __func__); + } + + fd->verts_num = verts_num; +} + +BLI_INLINE int face_iter_prim_to_face(PBVHFaceIter *fd, int prim_index) +{ + if (fd->subdiv_ccg_) { + return BKE_subdiv_ccg_grid_to_face_index(fd->subdiv_ccg_, prim_index); + } + else { + return fd->looptri_[prim_index].poly; + } +} + +void pbvh_face_iter_step(PBVHFaceIter *fd, bool do_step) +{ + if (do_step) { + fd->i++; + } + + switch (fd->pbvh_type_) { + case PBVH_BMESH: { + if (do_step) { + BLI_gsetIterator_step(&fd->bm_faces_iter_); + if (BLI_gsetIterator_done(&fd->bm_faces_iter_)) { + return; + } + } + + BMFace *f = (BMFace *)BLI_gsetIterator_getKey(&fd->bm_faces_iter_); + fd->face.i = (intptr_t)f; + fd->index = f->head.index; + + if (fd->cd_face_set_ != -1) { + fd->face_set = (int *)BM_ELEM_CD_GET_VOID_P(f, fd->cd_face_set_); + } + + if (fd->cd_hide_poly_ != -1) { + fd->hide = (bool *)BM_ELEM_CD_GET_VOID_P(f, fd->cd_hide_poly_); + } + + pbvh_face_iter_verts_reserve(fd, f->len); + int vertex_i = 0; + + BMLoop *l = f->l_first; + do { + fd->verts[vertex_i++].i = (intptr_t)l->v; + } while ((l = l->next) != f->l_first); + + break; + } + case PBVH_GRIDS: + case PBVH_FACES: { + int face_index = 0; + + if (do_step) { + fd->prim_index_++; + + while (fd->prim_index_ < fd->node_->totprim) { + face_index = face_iter_prim_to_face(fd, fd->node_->prim_indices[fd->prim_index_]); + + if (face_index != fd->last_face_index_) { + break; + } + + fd->prim_index_++; + } + } + else if (fd->prim_index_ < fd->node_->totprim) { + face_index = face_iter_prim_to_face(fd, fd->node_->prim_indices[fd->prim_index_]); + } + + if (fd->prim_index_ >= fd->node_->totprim) { + return; + } + + fd->last_face_index_ = face_index; + const MPoly *mp = fd->mpoly_ + face_index; + + fd->face.i = fd->index = face_index; + + if (fd->face_sets_) { + fd->face_set = fd->face_sets_ + face_index; + } + if (fd->hide_poly_) { + fd->hide = fd->hide_poly_ + face_index; + } + + pbvh_face_iter_verts_reserve(fd, mp->totloop); + + const MLoop *ml = fd->mloop_ + mp->loopstart; + for (int i = 0; i < mp->totloop; i++, ml++) { + if (fd->pbvh_type_ == PBVH_GRIDS) { + /* Grid corners. */ + fd->verts[i].i = mp->loopstart + i; + } + else { + fd->verts[i].i = ml->v; + } + } + + break; + } + } +} + +void BKE_pbvh_face_iter_step(PBVHFaceIter *fd) +{ + pbvh_face_iter_step(fd, true); +} + +void BKE_pbvh_face_iter_init(PBVH *pbvh, PBVHNode *node, PBVHFaceIter *fd) +{ + memset(fd, 0, sizeof(*fd)); + + fd->node_ = node; + fd->pbvh_type_ = BKE_pbvh_type(pbvh); + fd->verts = fd->verts_reserved_; + fd->verts_size_ = PBVH_FACE_ITER_VERTS_RESERVED; + + switch (BKE_pbvh_type(pbvh)) { + case PBVH_GRIDS: + fd->subdiv_ccg_ = pbvh->subdiv_ccg; + case PBVH_FACES: + fd->mpoly_ = pbvh->mpoly; + fd->mloop_ = pbvh->mloop; + fd->looptri_ = pbvh->looptri; + fd->hide_poly_ = pbvh->hide_poly; + fd->face_sets_ = pbvh->face_sets; + fd->last_face_index_ = -1; + + break; + case PBVH_BMESH: + fd->bm = pbvh->header.bm; + fd->cd_face_set_ = CustomData_get_offset_named( + &pbvh->header.bm->pdata, CD_PROP_INT32, ".sculpt_face_set"); + fd->cd_hide_poly_ = CustomData_get_offset_named( + &pbvh->header.bm->pdata, CD_PROP_INT32, ".hide_poly"); + + BLI_gsetIterator_init(&fd->bm_faces_iter_, node->bm_faces); + break; + } + + if (!BKE_pbvh_face_iter_done(fd)) { + pbvh_face_iter_step(fd, false); + } +} + +void BKE_pbvh_face_iter_finish(PBVHFaceIter *fd) +{ + if (fd->verts != fd->verts_reserved_) { + MEM_SAFE_FREE(fd->verts); + } +} + +bool BKE_pbvh_face_iter_done(PBVHFaceIter *fd) +{ + switch (fd->pbvh_type_) { + case PBVH_FACES: + case PBVH_GRIDS: + return fd->prim_index_ >= fd->node_->totprim; + case PBVH_BMESH: + return BLI_gsetIterator_done(&fd->bm_faces_iter_); + default: + BLI_assert_unreachable(); + return true; + } +}