forked from bartvdbraak/blender
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:
parent
5097105b3c
commit
6b3cee2538
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user