Sculpt: Face iterator API

This patch adds basic face iterators to the sculpt API.  The interface is similar to the existing vertex iterators.  It's not C++ (though it does mark private fields in PBVHFaceIter as private if compiling under C++).

Example:

```
PBVHFaceIter fd;

BKE_pbvh_face_iter_begin(pbvh, node, fd) {

  /* Face reference and face index */
  PBVHFaceRef face = fd->face;
  int face_index = fd->index;

  /* Can read and modify hide flag if it exist (it may not) */
  if (fd->hide) {
    *fd->hide ^= true; /* toggle hide */
  }

  /* Can read and modify face set if it exists */
  if (fd->face_set) {
    *fd->face_set = something;
  }

  /*Can read vertices*/
  for (int i=0; i<fd.verts_num; i++) {
    float *co = SCULPT_vertex_co_get(ss, fd.verts[i]);
  }
}
BKE_pbvh_face_iter_end(fd);
```

Reviewed By: Brecht Von Lommen and Hans Goudey
Differential Revision: https://developer.blender.org/D16225
Ref D16225
This commit is contained in:
Joseph Eagar 2022-11-20 08:08:26 -08:00
parent 5097105b3c
commit 6b3cee2538
3 changed files with 243 additions and 0 deletions

View File

@ -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

View File

@ -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);

View File

@ -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;
}
}