From 037cf920b42d9b3404687235c524516e50a31561 Mon Sep 17 00:00:00 2001 From: Pablo Dobarro Date: Wed, 14 Aug 2019 22:54:23 +0200 Subject: Sculpt: mesh abstraction API These functions make possible porting the tools from the sculpt branch, making them compatible with PBVH_FACES and PBVH_BMESH without duplicating the code. They can also help to simplify some existing code. These functions should not be used when working with PBVH_GRIDS data in SculptSession. PBVH_GRIDS needs to be removed from the sculpt code and converted to PBVH_FACES to be compatible with this API. Reviewed By: brecht Differential Revision: https://developer.blender.org/D5352 --- source/blender/blenkernel/BKE_paint.h | 2 + source/blender/blenkernel/BKE_pbvh.h | 3 + source/blender/editors/sculpt_paint/sculpt.c | 229 +++++++++++++++++++++++++++ 3 files changed, 234 insertions(+) diff --git a/source/blender/blenkernel/BKE_paint.h b/source/blender/blenkernel/BKE_paint.h index cbe250d0ac8..37667599488 100644 --- a/source/blender/blenkernel/BKE_paint.h +++ b/source/blender/blenkernel/BKE_paint.h @@ -259,6 +259,8 @@ typedef struct SculptSession { struct StrokeCache *cache; + int active_vertex_index; + union { struct { struct SculptVertexPaintGeomMap gmap; diff --git a/source/blender/blenkernel/BKE_pbvh.h b/source/blender/blenkernel/BKE_pbvh.h index 3806868e060..62544efad2c 100644 --- a/source/blender/blenkernel/BKE_pbvh.h +++ b/source/blender/blenkernel/BKE_pbvh.h @@ -301,6 +301,7 @@ typedef struct PBVHVertexIter { int gx; int gy; int i; + int index; /* grid */ struct CCGElem **grids; @@ -369,6 +370,7 @@ void pbvh_vertex_iter_init(PBVH *bvh, PBVHNode *node, PBVHVertexIter *vi, int mo continue; \ vi.co = vi.mvert->co; \ vi.no = vi.mvert->no; \ + vi.index = vi.vert_indices[vi.i]; \ if (vi.vmask) \ vi.mask = &vi.vmask[vi.vert_indices[vi.gx]]; \ } \ @@ -385,6 +387,7 @@ void pbvh_vertex_iter_init(PBVH *bvh, PBVHNode *node, PBVHVertexIter *vi, int mo continue; \ vi.co = vi.bm_vert->co; \ vi.fno = vi.bm_vert->no; \ + vi.index = BM_elem_index_get(vi.bm_vert); \ vi.mask = BM_ELEM_CD_GET_VOID_P(vi.bm_vert, vi.cd_vert_mask_offset); \ } diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c index efaac6e97cf..cdd82b8ced3 100644 --- a/source/blender/editors/sculpt_paint/sculpt.c +++ b/source/blender/editors/sculpt_paint/sculpt.c @@ -92,6 +92,235 @@ #include #include +/* Sculpt PBVH abstraction API */ + +/* Do not use these functions while working with PBVH_GRIDS data in SculptSession */ + +static int sculpt_active_vertex_get(SculptSession *ss) +{ + switch (BKE_pbvh_type(ss->pbvh)) { + case PBVH_FACES: + return ss->active_vertex_index; + case PBVH_BMESH: + return ss->active_vertex_index; + default: + return 0; + } +} + +static int sculpt_vertex_count_get(SculptSession *ss) +{ + switch (BKE_pbvh_type(ss->pbvh)) { + case PBVH_FACES: + return ss->totvert; + case PBVH_BMESH: + return BM_mesh_elem_count(BKE_pbvh_get_bmesh(ss->pbvh), BM_VERT); + default: + return 0; + } +} + +static void sculpt_vertex_normal_get(SculptSession *ss, int index, float no[3]) +{ + switch (BKE_pbvh_type(ss->pbvh)) { + case PBVH_FACES: + normal_short_to_float_v3(no, ss->mvert[index].no); + return; + case PBVH_BMESH: + copy_v3_v3(no, BM_vert_at_index(BKE_pbvh_get_bmesh(ss->pbvh), index)->no); + default: + return; + } +} + +static float *sculpt_vertex_co_get(SculptSession *ss, int index) +{ + switch (BKE_pbvh_type(ss->pbvh)) { + case PBVH_FACES: + return ss->mvert[index].co; + case PBVH_BMESH: + return BM_vert_at_index(BKE_pbvh_get_bmesh(ss->pbvh), index)->co; + default: + return NULL; + } +} + +static void sculpt_vertex_co_set(SculptSession *ss, int index, float co[3]) +{ + switch (BKE_pbvh_type(ss->pbvh)) { + case PBVH_FACES: + copy_v3_v3(ss->mvert[index].co, co); + return; + case PBVH_BMESH: + copy_v3_v3(BM_vert_at_index(BKE_pbvh_get_bmesh(ss->pbvh), index)->co, co); + return; + default: + return; + } +} + +static void sculpt_vertex_mask_set(SculptSession *ss, int index, float mask) +{ + BMVert *v; + float *mask_p; + switch (BKE_pbvh_type(ss->pbvh)) { + case PBVH_FACES: + ss->vmask[index] = mask; + return; + case PBVH_BMESH: + v = BM_vert_at_index(BKE_pbvh_get_bmesh(ss->pbvh), index); + mask_p = BM_ELEM_CD_GET_VOID_P(v, CustomData_get_offset(&ss->bm->vdata, CD_PAINT_MASK)); + *(mask_p) = mask; + return; + default: + return; + } +} + +static float sculpt_vertex_mask_get(SculptSession *ss, int index) +{ + BMVert *v; + float *mask; + switch (BKE_pbvh_type(ss->pbvh)) { + case PBVH_FACES: + return ss->vmask[index]; + case PBVH_BMESH: + v = BM_vert_at_index(BKE_pbvh_get_bmesh(ss->pbvh), index); + mask = BM_ELEM_CD_GET_VOID_P(v, CustomData_get_offset(&ss->bm->vdata, CD_PAINT_MASK)); + return *mask; + default: + return 0; + } +} + +static void sculpt_vertex_tag_update(SculptSession *ss, int index) +{ + switch (BKE_pbvh_type(ss->pbvh)) { + case PBVH_FACES: + ss->mvert[index].flag |= ME_VERT_PBVH_UPDATE; + return; + case PBVH_BMESH: + return; + default: + return; + } +} + +#define SCULPT_VERTEX_NEIGHBOUR_FIXED_CAPACITY 256 + +typedef struct SculptVertexNeighbourIter { + int *neighbours; + int size; + int capacity; + + int neighbours_fixed[SCULPT_VERTEX_NEIGHBOUR_FIXED_CAPACITY]; + + int index; + int i; +} SculptVertexNeighbourIter; + +static void sculpt_vertex_neighbour_add(SculptVertexNeighbourIter *iter, int neighbour_index) +{ + for (int i = 0; i < iter->size; i++) { + if (iter->neighbours[i] == neighbour_index) { + return; + } + } + + if (iter->size >= iter->capacity) { + iter->capacity += SCULPT_VERTEX_NEIGHBOUR_FIXED_CAPACITY; + + if (iter->neighbours == iter->neighbours_fixed) { + iter->neighbours = MEM_mallocN(iter->capacity * sizeof(int), "neighbour array"); + memcpy(iter->neighbours, iter->neighbours_fixed, sizeof(int) * iter->size); + } + else { + iter->neighbours = MEM_reallocN_id( + iter->neighbours, iter->capacity * sizeof(int), "neighbour array"); + } + } + + iter->neighbours[iter->size] = neighbour_index; + iter->size++; +} + +static void sculpt_vertex_neighbours_get_bmesh(SculptSession *ss, + int index, + SculptVertexNeighbourIter *iter) +{ + BMVert *v = BM_vert_at_index(ss->bm, index); + BMIter liter; + BMLoop *l; + iter->size = 0; + iter->capacity = SCULPT_VERTEX_NEIGHBOUR_FIXED_CAPACITY; + iter->neighbours = iter->neighbours_fixed; + + int i = 0; + BM_ITER_ELEM (l, &liter, v, BM_LOOPS_OF_VERT) { + const BMVert *adj_v[2] = {l->prev->v, l->next->v}; + for (i = 0; i < ARRAY_SIZE(adj_v); i++) { + const BMVert *v_other = adj_v[i]; + if (BM_elem_index_get(v_other) != (int)index) { + sculpt_vertex_neighbour_add(iter, BM_elem_index_get(v_other)); + } + } + } +} + +static void sculpt_vertex_neighbours_get_faces(SculptSession *ss, + int index, + SculptVertexNeighbourIter *iter) +{ + int i; + MeshElemMap *vert_map = &ss->pmap[(int)index]; + iter->size = 0; + iter->capacity = SCULPT_VERTEX_NEIGHBOUR_FIXED_CAPACITY; + iter->neighbours = iter->neighbours_fixed; + + for (i = 0; i < ss->pmap[(int)index].count; i++) { + const MPoly *p = &ss->mpoly[vert_map->indices[i]]; + unsigned f_adj_v[2]; + if (poly_get_adj_loops_from_vert(p, ss->mloop, (int)index, f_adj_v) != -1) { + int j; + for (j = 0; j < ARRAY_SIZE(f_adj_v); j += 1) { + if (vert_map->count != 2 || ss->pmap[f_adj_v[j]].count <= 2) { + if (f_adj_v[j] != (int)index) { + sculpt_vertex_neighbour_add(iter, f_adj_v[j]); + } + } + } + } + } +} + +static void sculpt_vertex_neighbours_get(SculptSession *ss, + int index, + SculptVertexNeighbourIter *iter) +{ + switch (BKE_pbvh_type(ss->pbvh)) { + case PBVH_FACES: + sculpt_vertex_neighbours_get_faces(ss, index, iter); + return; + case PBVH_BMESH: + sculpt_vertex_neighbours_get_bmesh(ss, index, iter); + return; + default: + break; + } +} + +#define sculpt_vertex_neighbours_iter_begin(ss, v_index, neighbour_iterator) \ + sculpt_vertex_neighbours_get(ss, v_index, &neighbour_iterator); \ + for (neighbour_iterator.i = 0; neighbour_iterator.i < neighbour_iterator.size; \ + neighbour_iterator.i++) { \ + neighbour_iterator.index = ni.neighbours[ni.i]; + +#define sculpt_vertex_neighbours_iter_end(neighbour_iterator) \ + } \ + if (neighbour_iterator.neighbours != neighbour_iterator.neighbours_fixed) { \ + MEM_freeN(neighbour_iterator.neighbours); \ + } + /** \name Tool Capabilities * * Avoid duplicate checks, internal logic only, -- cgit v1.2.3