diff options
-rw-r--r-- | source/blender/blenkernel/BKE_subdiv_ccg.h | 16 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/subdiv_ccg.c | 55 | ||||
-rw-r--r-- | source/blender/editors/sculpt_paint/sculpt.c | 149 | ||||
-rw-r--r-- | source/blender/editors/sculpt_paint/sculpt_automasking.c | 4 |
4 files changed, 183 insertions, 41 deletions
diff --git a/source/blender/blenkernel/BKE_subdiv_ccg.h b/source/blender/blenkernel/BKE_subdiv_ccg.h index 78e91d3ad2f..5808f223f32 100644 --- a/source/blender/blenkernel/BKE_subdiv_ccg.h +++ b/source/blender/blenkernel/BKE_subdiv_ccg.h @@ -313,6 +313,22 @@ void BKE_subdiv_ccg_neighbor_coords_get(const SubdivCCG *subdiv_ccg, int BKE_subdiv_ccg_grid_to_face_index(const SubdivCCG *subdiv_ccg, const int grid_index); +typedef enum SubdivCCGAdjacencyType { + SUBDIV_CCG_ADJACENT_NONE, + SUBDIV_CCG_ADJACENT_VERTEX, + SUBDIV_CCG_ADJACENT_EDGE, +} SubdivCCGAdjacencyType; + +/* Returns if a grid coordinates is adjacent to a coarse mesh edge, vertex or nothing. If it is + * adjacent to an edge, r_v1 and r_v2 will be set to the two vertices of that edge. If it is + * adjacent to a vertex, r_v1 and r_v2 will be the index of that vertex. */ +SubdivCCGAdjacencyType BKE_subdiv_ccg_coarse_mesh_adjacency_info_get(const SubdivCCG *subdiv_ccg, + const SubdivCCGCoord *coord, + const MLoop *mloop, + const MPoly *mpoly, + int *r_v1, + int *r_v2); + /* Get array which is indexed by face index and contains index of a first grid of the face. * * The "ensure" version allocates the mapping if it's not know yet and stores it in the subdiv_ccg diff --git a/source/blender/blenkernel/intern/subdiv_ccg.c b/source/blender/blenkernel/intern/subdiv_ccg.c index a1e218390c3..22649a2af07 100644 --- a/source/blender/blenkernel/intern/subdiv_ccg.c +++ b/source/blender/blenkernel/intern/subdiv_ccg.c @@ -1834,4 +1834,59 @@ const int *BKE_subdiv_ccg_start_face_grid_index_get(const SubdivCCG *subdiv_ccg) return subdiv_ccg->cache_.start_face_grid_index; } +static void adjacet_vertices_index_from_adjacent_edge(const SubdivCCG *subdiv_ccg, + const SubdivCCGCoord *coord, + const MLoop *mloop, + const MPoly *mpoly, + int *r_v1, + int *r_v2) +{ + const int grid_size_1 = subdiv_ccg->grid_size - 1; + const int poly_index = BKE_subdiv_ccg_grid_to_face_index(subdiv_ccg, coord->grid_index); + const MPoly *p = &mpoly[poly_index]; + *r_v1 = mloop[coord->grid_index].v; + if (coord->x == grid_size_1) { + const MLoop *next = ME_POLY_LOOP_NEXT(mloop, p, coord->grid_index); + *r_v2 = next->v; + } + if (coord->y == grid_size_1) { + const MLoop *prev = ME_POLY_LOOP_PREV(mloop, p, coord->grid_index); + *r_v2 = prev->v; + } +} + +SubdivCCGAdjacencyType BKE_subdiv_ccg_coarse_mesh_adjacency_info_get(const SubdivCCG *subdiv_ccg, + const SubdivCCGCoord *coord, + const MLoop *mloop, + const MPoly *mpoly, + int *r_v1, + int *r_v2) +{ + + const int grid_size_1 = subdiv_ccg->grid_size - 1; + if (is_corner_grid_coord(subdiv_ccg, coord)) { + if (coord->x == 0 && coord->y == 0) { + /* Grid corner in the center of a poly. */ + return SUBDIV_CCG_ADJACENT_NONE; + } + if (coord->x == grid_size_1 && coord->y == grid_size_1) { + /* Grid corner adjacent to a coarse mesh vertex. */ + *r_v1 = *r_v2 = mloop[coord->grid_index].v; + return SUBDIV_CCG_ADJACENT_VERTEX; + } + /* Grid corner adjacent to the middle of a coarse mesh edge. */ + adjacet_vertices_index_from_adjacent_edge(subdiv_ccg, coord, mloop, mpoly, r_v1, r_v2); + return SUBDIV_CCG_ADJACENT_EDGE; + } + + if (is_boundary_grid_coord(subdiv_ccg, coord)) { + if (!is_inner_edge_grid_coordinate(subdiv_ccg, coord)) { + /* Grid boundary adjacent to a coarse mesh edge. */ + adjacet_vertices_index_from_adjacent_edge(subdiv_ccg, coord, mloop, mpoly, r_v1, r_v2); + return SUBDIV_CCG_ADJACENT_EDGE; + } + } + return SUBDIV_CCG_ADJACENT_NONE; +} + /** \} */ diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c index 122430b0a51..7db6b07c911 100644 --- a/source/blender/editors/sculpt_paint/sculpt.c +++ b/source/blender/editors/sculpt_paint/sculpt.c @@ -547,28 +547,79 @@ void SCULPT_visibility_sync_all_vertex_to_face_sets(SculptSession *ss) } } -bool SCULPT_vertex_has_unique_face_set(SculptSession *ss, int index) +bool sculpt_check_unique_face_set_in_base_mesh(SculptSession *ss, int index) { - switch (BKE_pbvh_type(ss->pbvh)) { - case PBVH_FACES: { - MeshElemMap *vert_map = &ss->pmap[index]; - int face_set = -1; - for (int i = 0; i < ss->pmap[index].count; i++) { - if (face_set == -1) { - face_set = abs(ss->face_sets[vert_map->indices[i]]); + MeshElemMap *vert_map = &ss->pmap[index]; + int face_set = -1; + for (int i = 0; i < ss->pmap[index].count; i++) { + if (face_set == -1) { + face_set = abs(ss->face_sets[vert_map->indices[i]]); + } + else { + if (abs(ss->face_sets[vert_map->indices[i]]) != face_set) { + return false; + } + } + } + return true; +} + +/* Checks if the face sets of the adjacent faces to the edge between v1 and v2 in the base mesh are + * equal. */ +bool sculpt_check_unique_face_set_for_edge_in_base_mesh(SculptSession *ss, int v1, int v2) +{ + MeshElemMap *vert_map = &ss->pmap[v1]; + int p1 = -1, p2 = -1; + for (int i = 0; i < ss->pmap[v1].count; i++) { + MPoly *p = &ss->mpoly[vert_map->indices[i]]; + for (int l = 0; l < p->totloop; l++) { + MLoop *loop = &ss->mloop[p->loopstart + l]; + if (loop->v == v2) { + if (p1 == -1) { + p1 = vert_map->indices[i]; + break; } - else { - if (abs(ss->face_sets[vert_map->indices[i]]) != face_set) { - return false; - } + else if (p2 == -1) { + p2 = vert_map->indices[i]; + break; } } - return true; + } + } + + if (p1 != -1 && p2 != -1) { + return abs(ss->face_sets[p1]) == (ss->face_sets[p2]); + } + return true; +} + +bool SCULPT_vertex_has_unique_face_set(SculptSession *ss, int index) +{ + switch (BKE_pbvh_type(ss->pbvh)) { + case PBVH_FACES: { + return sculpt_check_unique_face_set_in_base_mesh(ss, index); } case PBVH_BMESH: return false; - case PBVH_GRIDS: - return true; + case PBVH_GRIDS: { + const CCGKey *key = BKE_pbvh_get_grid_key(ss->pbvh); + const int grid_index = index / key->grid_area; + const int vertex_index = index - grid_index * key->grid_area; + const SubdivCCGCoord coord = {.grid_index = grid_index, + .x = vertex_index % key->grid_size, + .y = vertex_index / key->grid_size}; + int v1, v2; + const SubdivCCGAdjacencyType adjacency = BKE_subdiv_ccg_coarse_mesh_adjacency_info_get( + ss->subdiv_ccg, &coord, ss->mloop, ss->mpoly, &v1, &v2); + switch (adjacency) { + case SUBDIV_CCG_ADJACENT_VERTEX: + return sculpt_check_unique_face_set_in_base_mesh(ss, v1); + case SUBDIV_CCG_ADJACENT_EDGE: + return sculpt_check_unique_face_set_for_edge_in_base_mesh(ss, v1, v2); + case SUBDIV_CCG_ADJACENT_NONE: + return true; + } + } } return false; } @@ -735,44 +786,64 @@ void SCULPT_vertex_neighbors_get(SculptSession *ss, } } +bool sculpt_check_boundary_vertex_in_base_mesh(SculptSession *ss, const int index) +{ + const MeshElemMap *vert_map = &ss->pmap[index]; + if (vert_map->count <= 1) { + return true; + } + for (int i = 0; i < vert_map->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, 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)) { + return true; + } + } + } + } + return false; +} + bool SCULPT_vertex_is_boundary(SculptSession *ss, const int index) { switch (BKE_pbvh_type(ss->pbvh)) { case PBVH_FACES: { - const MeshElemMap *vert_map = &ss->pmap[index]; - - if (vert_map->count <= 1) { - return false; - } - if (!SCULPT_vertex_all_face_sets_visible_get(ss, index)) { - return false; - } - - for (int i = 0; i < vert_map->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, 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)) { - return false; - } - } - } + return true; } - return true; + return sculpt_check_boundary_vertex_in_base_mesh(ss, index); } case PBVH_BMESH: { BMVert *v = BM_vert_at_index(ss->bm, index); return BM_vert_is_boundary(v); } - case PBVH_GRIDS: - return true; + case PBVH_GRIDS: { + const CCGKey *key = BKE_pbvh_get_grid_key(ss->pbvh); + const int grid_index = index / key->grid_area; + const int vertex_index = index - grid_index * key->grid_area; + const SubdivCCGCoord coord = {.grid_index = grid_index, + .x = vertex_index % key->grid_size, + .y = vertex_index / key->grid_size}; + int v1, v2; + const SubdivCCGAdjacencyType adjacency = BKE_subdiv_ccg_coarse_mesh_adjacency_info_get( + ss->subdiv_ccg, &coord, ss->mloop, ss->mpoly, &v1, &v2); + switch (adjacency) { + case SUBDIV_CCG_ADJACENT_VERTEX: + return sculpt_check_boundary_vertex_in_base_mesh(ss, v1); + case SUBDIV_CCG_ADJACENT_EDGE: + return sculpt_check_boundary_vertex_in_base_mesh(ss, v1) && + sculpt_check_boundary_vertex_in_base_mesh(ss, v2); + case SUBDIV_CCG_ADJACENT_NONE: + return false; + } + } } - return true; + return false; } /* Utilities */ diff --git a/source/blender/editors/sculpt_paint/sculpt_automasking.c b/source/blender/editors/sculpt_paint/sculpt_automasking.c index 7c79c1d7a2f..48b278e52b6 100644 --- a/source/blender/editors/sculpt_paint/sculpt_automasking.c +++ b/source/blender/editors/sculpt_paint/sculpt_automasking.c @@ -209,7 +209,7 @@ float *SCULPT_boundary_automasking_init(Object *ob, { SculptSession *ss = ob->sculpt; - if (BKE_pbvh_type(ss->pbvh) == PBVH_FACES && !ss->pmap) { + if (!ss->pmap) { BLI_assert(!"Boundary Edges masking: pmap missing"); return NULL; } @@ -221,7 +221,7 @@ float *SCULPT_boundary_automasking_init(Object *ob, edge_distance[i] = EDGE_DISTANCE_INF; switch (mode) { case AUTOMASK_INIT_BOUNDARY_EDGES: - if (!SCULPT_vertex_is_boundary(ss, i)) { + if (SCULPT_vertex_is_boundary(ss, i)) { edge_distance[i] = 0; } break; |