[Bf-blender-cvs] [6b3cee25389] master: Sculpt: Face iterator API

Joseph Eagar noreply at git.blender.org
Sun Nov 20 17:09:58 CET 2022


Commit: 6b3cee25389d28bd863c02884383ab9c2c2dab0e
Author: Joseph Eagar
Date:   Sun Nov 20 08:08:26 2022 -0800
Branches: master
https://developer.blender.org/rB6b3cee25389d28bd863c02884383ab9c2c2dab0e

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

===================================================================

M	.clang-format
M	source/blender/blenkernel/BKE_pbvh.h
M	source/blender/blenkernel/intern/pbvh.c

===================================================================

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



More information about the Bf-blender-cvs mailing list