diff options
author | Sergey Sharybin <sergey.vfx@gmail.com> | 2019-10-04 19:49:39 +0300 |
---|---|---|
committer | Brecht Van Lommel <brechtvanlommel@gmail.com> | 2019-10-04 20:00:57 +0300 |
commit | 8f1f756b839942531c69a7608c25ea85de1beb8a (patch) | |
tree | 9c9cb3d03598521ae1f8ef753b3cd1dcb0b4dadd /source | |
parent | bebdb6c8249939623f80cc72433aa7d7418444bf (diff) |
Subdiv CCG: add utility functions for accessing multires vertex neighbors
This is to be used by the new sculpting tools.
Diffstat (limited to 'source')
-rw-r--r-- | source/blender/blenkernel/BKE_subdiv_ccg.h | 42 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/subdiv_ccg.c | 506 | ||||
-rw-r--r-- | source/blender/editors/sculpt_paint/sculpt.c | 32 |
3 files changed, 575 insertions, 5 deletions
diff --git a/source/blender/blenkernel/BKE_subdiv_ccg.h b/source/blender/blenkernel/BKE_subdiv_ccg.h index 9b7c613aa94..6e2733eb1ac 100644 --- a/source/blender/blenkernel/BKE_subdiv_ccg.h +++ b/source/blender/blenkernel/BKE_subdiv_ccg.h @@ -131,6 +131,9 @@ typedef struct SubdivCCG { /* Resolution of grid. All grids have matching resolution, and resolution * is same as ptex created for non-quad polygons. */ int grid_size; + /* Size of a single element of a grid (including coordinate and all the other layers). + * Measured in bytes. */ + int grid_element_size; /* Grids represent limit surface, with displacement applied. Grids are * corresponding to face-corners of coarse mesh, each grid has * grid_size^2 elements. @@ -251,4 +254,43 @@ void BKE_subdiv_ccg_topology_counters(const SubdivCCG *subdiv_ccg, int *r_num_faces, int *r_num_loops); +typedef struct SubdivCCGCoord { + /* Index of the grid within SubdivCCG::grids array. */ + int grid_index; + + /* Coordinate within the grid. */ + int x, y; +} SubdivCCGCoord; + +typedef struct SubdivCCGNeighbors { + SubdivCCGCoord *coords; + int size; + + SubdivCCGCoord coords_fixed[256]; +} SubdivCCGNeighbors; + +void BKE_subdiv_ccg_print_coord(const char *message, const SubdivCCGCoord *coord); +bool BKE_subdiv_ccg_check_coord_valid(const SubdivCCG *subdiv_ccg, const SubdivCCGCoord *coord); + +/* CCG element neighbors. + * + * Neighbors are considered: + * + * - For an inner elements of a grid other elements which are sharing same row or column (4 + * neighbor elements in total). + * + * - For the corner element a single neighboring element on every adjacent edge, single from + * every gird. + * + * - For the boundary element two neighbor elements on the boundary (from same grid) and one + * element inside of every neighboring grid. */ + +/* Get actual neighbors of the given coordinate. + * + * SubdivCCGNeighbors.neighbors must be freed if it is not equal to + * SubdivCCGNeighbors.fixed_neighbors. */ +void BKE_subdiv_ccg_neighbor_coords_get(const SubdivCCG *subdiv_ccg, + const SubdivCCGCoord *coord, + SubdivCCGNeighbors *r_neighbors); + #endif /* __BKE_SUBDIV_CCG_H__ */ diff --git a/source/blender/blenkernel/intern/subdiv_ccg.c b/source/blender/blenkernel/intern/subdiv_ccg.c index bbd73db42bf..66db58ec683 100644 --- a/source/blender/blenkernel/intern/subdiv_ccg.c +++ b/source/blender/blenkernel/intern/subdiv_ccg.c @@ -129,6 +129,7 @@ static void subdiv_ccg_alloc_elements(SubdivCCG *subdiv_ccg, Subdiv *subdiv) const int num_grids = topology_refiner_count_face_corners(topology_refiner); const int grid_size = BKE_subdiv_grid_size_from_level(subdiv_ccg->level); const int grid_area = grid_size * grid_size; + subdiv_ccg->grid_element_size = element_size; subdiv_ccg->num_grids = num_grids; subdiv_ccg->grids = MEM_calloc_arrayN(num_grids, sizeof(CCGElem *), "subdiv ccg grids"); subdiv_ccg->grids_storage = MEM_calloc_arrayN( @@ -1229,3 +1230,508 @@ void BKE_subdiv_ccg_topology_counters(const SubdivCCG *subdiv_ccg, *r_num_faces = num_grids * (grid_size - 1) * (grid_size - 1); *r_num_loops = *r_num_faces * 4; } + +/* ============================================================================= + * Neighbors. + */ + +void BKE_subdiv_ccg_print_coord(const char *message, const SubdivCCGCoord *coord) +{ + printf("%s: grid index: %d, coord: (%d, %d)\n", message, coord->grid_index, coord->x, coord->y); +} + +bool BKE_subdiv_ccg_check_coord_valid(const SubdivCCG *subdiv_ccg, const SubdivCCGCoord *coord) +{ + if (coord->grid_index < 0 || coord->grid_index >= subdiv_ccg->num_grids) { + return false; + } + const int grid_size = subdiv_ccg->grid_size; + if (coord->x < 0 || coord->x >= grid_size) { + return false; + } + if (coord->y < 0 || coord->y >= grid_size) { + return false; + } + return true; +} + +BLI_INLINE void subdiv_ccg_neighbors_init(SubdivCCGNeighbors *neighbors, int size) +{ + neighbors->size = size; + if (size < ARRAY_SIZE(neighbors->coords_fixed)) { + neighbors->coords = neighbors->coords_fixed; + } + else { + neighbors->coords = MEM_mallocN(sizeof(*neighbors->coords) * size, + "SubdivCCGNeighbors.coords"); + } +} + +/* Check whether given coordinate belongs to a grid corner. */ +BLI_INLINE bool is_corner_grid_coord(const SubdivCCG *subdiv_ccg, const SubdivCCGCoord *coord) +{ + const int grid_size_1 = subdiv_ccg->grid_size - 1; + return (coord->x == 0 && coord->y == 0) || (coord->x == 0 && coord->y == grid_size_1) || + (coord->x == grid_size_1 && coord->y == grid_size_1) || + (coord->x == grid_size_1 && coord->y == 0); +} + +/* Check whether given coordinate belongs to a grid boundary. */ +BLI_INLINE bool is_boundary_grid_coord(const SubdivCCG *subdiv_ccg, const SubdivCCGCoord *coord) +{ + const int grid_size_1 = subdiv_ccg->grid_size - 1; + return coord->x == 0 || coord->y == 0 || coord->x == grid_size_1 || coord->y == grid_size_1; +} + +/* Check whether coordinate is at the boundary between two grids of the same face. */ +BLI_INLINE bool is_inner_edge_grid_coordinate(const SubdivCCG *subdiv_ccg, + const SubdivCCGCoord *coord) +{ + const int grid_size_1 = subdiv_ccg->grid_size - 1; + if (coord->x == 0) { + return coord->y > 0 && coord->y < grid_size_1; + } + if (coord->y == 0) { + return coord->x > 0 && coord->x < grid_size_1; + } + return false; +} + +BLI_INLINE SubdivCCGCoord coord_at_prev_row(const SubdivCCG *UNUSED(subdiv_ccg), + const SubdivCCGCoord *coord) +{ + BLI_assert(coord->y > 0); + SubdivCCGCoord result = *coord; + result.y -= 1; + return result; +} +BLI_INLINE SubdivCCGCoord coord_at_next_row(const SubdivCCG *subdiv_ccg, + const SubdivCCGCoord *coord) +{ + UNUSED_VARS_NDEBUG(subdiv_ccg); + BLI_assert(coord->y < subdiv_ccg->grid_size - 1); + SubdivCCGCoord result = *coord; + result.y += 1; + return result; +} + +BLI_INLINE SubdivCCGCoord coord_at_prev_col(const SubdivCCG *UNUSED(subdiv_ccg), + const SubdivCCGCoord *coord) +{ + BLI_assert(coord->x > 0); + SubdivCCGCoord result = *coord; + result.x -= 1; + return result; +} +BLI_INLINE SubdivCCGCoord coord_at_next_col(const SubdivCCG *subdiv_ccg, + const SubdivCCGCoord *coord) +{ + UNUSED_VARS_NDEBUG(subdiv_ccg); + BLI_assert(coord->x < subdiv_ccg->grid_size - 1); + SubdivCCGCoord result = *coord; + result.x += 1; + return result; +} + +BLI_INLINE SubdivCCGCoord coord_from_ccg_element(const SubdivCCG *subdiv_ccg, CCGElem *element) +{ + const size_t element_data_offset = (unsigned char *)element - subdiv_ccg->grids_storage; + const size_t element_global_index = element_data_offset / subdiv_ccg->grid_element_size; + const int grid_area = subdiv_ccg->grid_size * subdiv_ccg->grid_size; + const int grid_index = element_global_index / grid_area; + const size_t grid_start_element_index = grid_index * grid_area; + const int element_grid_index = element_global_index - grid_start_element_index; + + const int y = element_grid_index / subdiv_ccg->grid_size; + const int x = element_grid_index - y * subdiv_ccg->grid_size; + + SubdivCCGCoord result; + result.grid_index = grid_index; + result.x = x; + result.y = y; + + return result; +} + +/* For the input coordinate which is at the boundary of the grid do one step inside. */ +static SubdivCCGCoord coord_step_inside_from_boundary(const SubdivCCG *subdiv_ccg, + const SubdivCCGCoord *coord) + +{ + SubdivCCGCoord result = *coord; + const int grid_size_1 = subdiv_ccg->grid_size - 1; + if (result.x == grid_size_1) { + --result.x; + } + else if (result.y == grid_size_1) { + --result.y; + } + else if (result.x == 0) { + ++result.x; + } + else if (result.y == 0) { + ++result.y; + } + else { + BLI_assert(!"non-boundary element given"); + } + return result; +} + +BLI_INLINE +int next_grid_index_from_coord(const SubdivCCG *subdiv_ccg, const SubdivCCGCoord *coord) +{ + SubdivCCGFace *face = subdiv_ccg->grid_faces[coord->grid_index]; + const int face_grid_index = coord->grid_index; + int next_face_grid_index = face_grid_index + 1 - face->start_grid_index; + if (next_face_grid_index == face->num_grids) { + next_face_grid_index = 0; + } + return face->start_grid_index + next_face_grid_index; +} +BLI_INLINE int prev_grid_index_from_coord(const SubdivCCG *subdiv_ccg, const SubdivCCGCoord *coord) +{ + SubdivCCGFace *face = subdiv_ccg->grid_faces[coord->grid_index]; + const int face_grid_index = coord->grid_index; + int prev_face_grid_index = face_grid_index - 1 - face->start_grid_index; + if (prev_face_grid_index < 0) { + prev_face_grid_index = face->num_grids - 1; + } + return face->start_grid_index + prev_face_grid_index; +} + +/* Simple case of getting neighbors of a corner coordinate: the corner is a face center, so + * can only iterate over grid of a single face, without looking into adjacency. */ +static void neighbor_coords_corner_center_get(const SubdivCCG *subdiv_ccg, + const SubdivCCGCoord *coord, + SubdivCCGNeighbors *r_neighbors) +{ + SubdivCCGFace *face = subdiv_ccg->grid_faces[coord->grid_index]; + + subdiv_ccg_neighbors_init(r_neighbors, face->num_grids); + + for (int face_grid_index = 0; face_grid_index < face->num_grids; ++face_grid_index) { + SubdivCCGCoord neighbor_coord; + neighbor_coord.grid_index = face->start_grid_index + face_grid_index; + neighbor_coord.x = 1; + neighbor_coord.y = 0; + r_neighbors->coords[face_grid_index] = neighbor_coord; + } +} + +/* Get index within adjacent_vertices array for the given CCG coordinate. */ +static int adjacent_vertex_index_from_coord(const SubdivCCG *subdiv_ccg, + const SubdivCCGCoord *coord) +{ + Subdiv *subdiv = subdiv_ccg->subdiv; + OpenSubdiv_TopologyRefiner *topology_refiner = subdiv->topology_refiner; + + const SubdivCCGFace *face = subdiv_ccg->grid_faces[coord->grid_index]; + const int face_index = face - subdiv_ccg->faces; + const int face_grid_index = coord->grid_index - face->start_grid_index; + const int num_face_grids = face->num_grids; + const int num_face_vertices = num_face_grids; + + StaticOrHeapIntStorage face_vertices_storage; + static_or_heap_storage_init(&face_vertices_storage); + + int *face_vertices = static_or_heap_storage_get(&face_vertices_storage, num_face_vertices); + topology_refiner->getFaceVertices(topology_refiner, face_index, face_vertices); + + const int adjacent_vertex_index = face_vertices[face_grid_index]; + static_or_heap_storage_free(&face_vertices_storage); + return adjacent_vertex_index; +} + +/* The corner is adjacent to a coarse vertex. */ +static void neighbor_coords_corner_vertex_get(const SubdivCCG *subdiv_ccg, + const SubdivCCGCoord *coord, + SubdivCCGNeighbors *r_neighbors) +{ + Subdiv *subdiv = subdiv_ccg->subdiv; + OpenSubdiv_TopologyRefiner *topology_refiner = subdiv->topology_refiner; + + const int adjacent_vertex_index = adjacent_vertex_index_from_coord(subdiv_ccg, coord); + BLI_assert(adjacent_vertex_index >= 0); + BLI_assert(adjacent_vertex_index < subdiv_ccg->num_adjacent_vertices); + const int num_vertex_edges = topology_refiner->getNumVertexEdges(topology_refiner, + adjacent_vertex_index); + + subdiv_ccg_neighbors_init(r_neighbors, num_vertex_edges); + + StaticOrHeapIntStorage vertex_edges_storage; + static_or_heap_storage_init(&vertex_edges_storage); + + int *vertex_edges = static_or_heap_storage_get(&vertex_edges_storage, num_vertex_edges); + topology_refiner->getVertexEdges(topology_refiner, adjacent_vertex_index, vertex_edges); + + for (int i = 0; i < num_vertex_edges; ++i) { + const int edge_index = vertex_edges[i]; + + /* Use very first grid of every edge. */ + const int edge_face_index = 0; + + /* Depending edge orientation we use first (zero-based) or previous-to-last point. */ + int edge_vertices_indices[2]; + topology_refiner->getEdgeVertices(topology_refiner, edge_index, edge_vertices_indices); + int edge_point_index; + if (edge_vertices_indices[0] == adjacent_vertex_index) { + edge_point_index = 1; + } + else { + /* Edge "consists" of 2 grids, which makes it 2 * grid_size elements per edge. + * The index of last edge element is 2 * grid_size - 1 (due to zero-based indices), + * and we are interested in previous to last element. */ + edge_point_index = subdiv_ccg->grid_size * 2 - 2; + } + + SubdivCCGAdjacentEdge *adjacent_edge = &subdiv_ccg->adjacent_edges[edge_index]; + CCGElem *boundary_element = + adjacent_edge->boundary_elements[edge_face_index][edge_point_index]; + + r_neighbors->coords[i] = coord_from_ccg_element(subdiv_ccg, boundary_element); + } + + static_or_heap_storage_free(&vertex_edges_storage); +} + +static int adjacent_edge_index_from_coord(const SubdivCCG *subdiv_ccg, const SubdivCCGCoord *coord) +{ + Subdiv *subdiv = subdiv_ccg->subdiv; + OpenSubdiv_TopologyRefiner *topology_refiner = subdiv->topology_refiner; + SubdivCCGFace *face = subdiv_ccg->grid_faces[coord->grid_index]; + + const int face_grid_index = coord->grid_index - face->start_grid_index; + const int face_index = face - subdiv_ccg->faces; + const int num_face_edges = topology_refiner->getNumFaceEdges(topology_refiner, face_index); + + StaticOrHeapIntStorage face_edges_storage; + static_or_heap_storage_init(&face_edges_storage); + int *face_edges_indices = static_or_heap_storage_get(&face_edges_storage, num_face_edges); + topology_refiner->getFaceEdges(topology_refiner, face_index, face_edges_indices); + + const int grid_size_1 = subdiv_ccg->grid_size - 1; + int adjacent_edge_index = -1; + if (coord->x == grid_size_1) { + adjacent_edge_index = face_edges_indices[face_grid_index]; + } + else { + BLI_assert(coord->y == grid_size_1); + adjacent_edge_index = + face_edges_indices[face_grid_index == 0 ? face->num_grids - 1 : face_grid_index - 1]; + } + + static_or_heap_storage_free(&face_edges_storage); + + return adjacent_edge_index; +} + +static int adjacent_edge_point_index_from_coord(const SubdivCCG *subdiv_ccg, + const SubdivCCGCoord *coord, + const int adjacent_edge_index) +{ + Subdiv *subdiv = subdiv_ccg->subdiv; + OpenSubdiv_TopologyRefiner *topology_refiner = subdiv->topology_refiner; + + const int adjacent_vertex_index = adjacent_vertex_index_from_coord(subdiv_ccg, coord); + int edge_vertices_indices[2]; + topology_refiner->getEdgeVertices(topology_refiner, adjacent_edge_index, edge_vertices_indices); + + /* Vertex index of an edge which is used to see whether edge points in the right direction. + * Tricky part here is that depending whether input coordinate is ar macimum X or Y coordinate + * of the grid we need to use dirrerent edge direction. + * Basically, the edge adjacent to a previous loop needs to point opposite direction. */ + int directional_edge_vertex_index = -1; + + const int grid_size_1 = subdiv_ccg->grid_size - 1; + int adjacent_edge_point_index = -1; + if (coord->x == grid_size_1) { + adjacent_edge_point_index = subdiv_ccg->grid_size - coord->y - 1; + directional_edge_vertex_index = edge_vertices_indices[0]; + } + else { + BLI_assert(coord->y == grid_size_1); + adjacent_edge_point_index = subdiv_ccg->grid_size + coord->x; + directional_edge_vertex_index = edge_vertices_indices[1]; + } + + /* Flip the index if the edde points opposite direction. */ + if (adjacent_vertex_index != directional_edge_vertex_index) { + const int num_edge_points = subdiv_ccg->grid_size * 2; + adjacent_edge_point_index = num_edge_points - adjacent_edge_point_index - 1; + } + + return adjacent_edge_point_index; +} + +/* Adjacent edge has two points in the middle which corresponds to grid corners, but which are + * the same point in the final geometry. + * So need to use extra step when calculating next/previous points, so we don't go from a corner + * of one grid to a corner of adjacent grid. */ +static int next_adjacent_edge_point_index(const SubdivCCG *subdiv_ccg, const int point_index) +{ + if (point_index == subdiv_ccg->grid_size - 1) { + return point_index + 2; + } + return point_index + 1; +} +static int prev_adjacent_edge_point_index(const SubdivCCG *subdiv_ccg, const int point_index) +{ + if (point_index == subdiv_ccg->grid_size) { + return point_index - 2; + } + return point_index - 1; +} + +/* Common implementation of neighbor calculation when input coordinate is at the edge between two + * coarse faces, but is not at the coarse vertex. */ +static void neighbor_coords_edge_get(const SubdivCCG *subdiv_ccg, + const SubdivCCGCoord *coord, + SubdivCCGNeighbors *r_neighbors) + +{ + const int adjacent_edge_index = adjacent_edge_index_from_coord(subdiv_ccg, coord); + BLI_assert(adjacent_edge_index >= 0); + BLI_assert(adjacent_edge_index < subdiv_ccg->num_adjacent_edges); + const SubdivCCGAdjacentEdge *adjacent_edge = &subdiv_ccg->adjacent_edges[adjacent_edge_index]; + + /* 2 neighbor points along the edge, plus one inner point per every adjacent grid. */ + const int num_neighbor_coord = adjacent_edge->num_adjacent_faces + 2; + subdiv_ccg_neighbors_init(r_neighbors, num_neighbor_coord); + + const int point_index = adjacent_edge_point_index_from_coord( + subdiv_ccg, coord, adjacent_edge_index); + const int next_point_index = next_adjacent_edge_point_index(subdiv_ccg, point_index); + const int prev_point_index = prev_adjacent_edge_point_index(subdiv_ccg, point_index); + + r_neighbors->coords[0] = coord_from_ccg_element( + subdiv_ccg, adjacent_edge->boundary_elements[0][prev_point_index]); + r_neighbors->coords[1] = coord_from_ccg_element( + subdiv_ccg, adjacent_edge->boundary_elements[0][next_point_index]); + + for (int i = 0; i < adjacent_edge->num_adjacent_faces; ++i) { + SubdivCCGCoord grid_coord = coord_from_ccg_element( + subdiv_ccg, adjacent_edge->boundary_elements[i][point_index]); + r_neighbors->coords[i + 2] = coord_step_inside_from_boundary(subdiv_ccg, &grid_coord); + } +} + +/* The corner is at the middle of edge between faces. */ +static void neighbor_coords_corner_edge_get(const SubdivCCG *subdiv_ccg, + const SubdivCCGCoord *coord, + SubdivCCGNeighbors *r_neighbors) +{ + neighbor_coords_edge_get(subdiv_ccg, coord, r_neighbors); +} + +/* Input coordinate is at one of 4 corners of its grid corners. */ +static void neighbor_coords_corner_get(const SubdivCCG *subdiv_ccg, + const SubdivCCGCoord *coord, + SubdivCCGNeighbors *r_neighbors) +{ + if (coord->x == 0 && coord->y == 0) { + neighbor_coords_corner_center_get(subdiv_ccg, coord, r_neighbors); + } + else { + const int grid_size_1 = subdiv_ccg->grid_size - 1; + if (coord->x == grid_size_1 && coord->y == grid_size_1) { + neighbor_coords_corner_vertex_get(subdiv_ccg, coord, r_neighbors); + } + else { + neighbor_coords_corner_edge_get(subdiv_ccg, coord, r_neighbors); + } + } +} + +/* Simple case of getting neighbors of a boundary coordinate: the input coordinate is at the + * boundary between two grids of the same face and there is no need to check adjacency with + * other faces. */ +static void neighbor_coords_boundary_inner_get(const SubdivCCG *subdiv_ccg, + const SubdivCCGCoord *coord, + SubdivCCGNeighbors *r_neighbors) +{ + subdiv_ccg_neighbors_init(r_neighbors, 4); + + if (coord->x == 0) { + r_neighbors->coords[0] = coord_at_prev_row(subdiv_ccg, coord); + r_neighbors->coords[1] = coord_at_next_row(subdiv_ccg, coord); + r_neighbors->coords[2] = coord_at_next_col(subdiv_ccg, coord); + + r_neighbors->coords[3].grid_index = prev_grid_index_from_coord(subdiv_ccg, coord); + r_neighbors->coords[3].x = coord->y; + r_neighbors->coords[3].y = 1; + } + else if (coord->y == 0) { + r_neighbors->coords[0] = coord_at_prev_col(subdiv_ccg, coord); + r_neighbors->coords[1] = coord_at_next_col(subdiv_ccg, coord); + r_neighbors->coords[2] = coord_at_next_row(subdiv_ccg, coord); + + r_neighbors->coords[3].grid_index = next_grid_index_from_coord(subdiv_ccg, coord); + r_neighbors->coords[3].x = 1; + r_neighbors->coords[3].y = coord->x; + } +} + +/* Input coordinate is on an edge between two faces. Need to check adjacency. */ +static void neighbor_coords_boundary_outer_get(const SubdivCCG *subdiv_ccg, + const SubdivCCGCoord *coord, + SubdivCCGNeighbors *r_neighbors) +{ + neighbor_coords_edge_get(subdiv_ccg, coord, r_neighbors); +} + +/* Input coordinate is at one of 4 boundaries of its grid. + * It could either be an inner boundary (which connects face center to the face edge) or could be + * a part of coarse face edge. */ +static void neighbor_coords_boundary_get(const SubdivCCG *subdiv_ccg, + const SubdivCCGCoord *coord, + SubdivCCGNeighbors *r_neighbors) +{ + if (is_inner_edge_grid_coordinate(subdiv_ccg, coord)) { + neighbor_coords_boundary_inner_get(subdiv_ccg, coord, r_neighbors); + } + else { + neighbor_coords_boundary_outer_get(subdiv_ccg, coord, r_neighbors); + } +} + +/* Input coordinate is inside of its grid, all the neighbors belong to the same grid. */ +static void neighbor_coords_inner_get(const SubdivCCG *subdiv_ccg, + const SubdivCCGCoord *coord, + SubdivCCGNeighbors *r_neighbors) +{ + subdiv_ccg_neighbors_init(r_neighbors, 4); + + r_neighbors->coords[0] = coord_at_prev_row(subdiv_ccg, coord); + r_neighbors->coords[1] = coord_at_next_row(subdiv_ccg, coord); + r_neighbors->coords[2] = coord_at_prev_col(subdiv_ccg, coord); + r_neighbors->coords[3] = coord_at_next_col(subdiv_ccg, coord); +} + +void BKE_subdiv_ccg_neighbor_coords_get(const SubdivCCG *subdiv_ccg, + const SubdivCCGCoord *coord, + SubdivCCGNeighbors *r_neighbors) +{ + BLI_assert(coord->grid_index >= 0); + BLI_assert(coord->grid_index < subdiv_ccg->num_grids); + BLI_assert(coord->x >= 0); + BLI_assert(coord->x < subdiv_ccg->grid_size); + BLI_assert(coord->y >= 0); + BLI_assert(coord->y < subdiv_ccg->grid_size); + + if (is_corner_grid_coord(subdiv_ccg, coord)) { + neighbor_coords_corner_get(subdiv_ccg, coord, r_neighbors); + } + else if (is_boundary_grid_coord(subdiv_ccg, coord)) { + neighbor_coords_boundary_get(subdiv_ccg, coord, r_neighbors); + } + else { + neighbor_coords_inner_get(subdiv_ccg, coord, r_neighbors); + } + +#ifndef NDEBUG + for (int i = 0; i < r_neighbors->size; i++) { + BLI_assert(BKE_subdiv_ccg_check_coord_valid(subdiv_ccg, &r_neighbors->coords[i])); + } +#endif +} diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c index 64674ecd0a1..9bd788f7960 100644 --- a/source/blender/editors/sculpt_paint/sculpt.c +++ b/source/blender/editors/sculpt_paint/sculpt.c @@ -64,6 +64,7 @@ #include "BKE_report.h" #include "BKE_scene.h" #include "BKE_screen.h" +#include "BKE_subdiv_ccg.h" #include "BKE_subsurf.h" #include "DEG_depsgraph.h" @@ -293,16 +294,37 @@ static void sculpt_vertex_neighbors_get_faces(SculptSession *ss, } } -static void sculpt_vertex_neighbors_get_grids(SculptSession *UNUSED(ss), - int UNUSED(index), +static void sculpt_vertex_neighbors_get_grids(SculptSession *ss, + int index, SculptVertexNeighborIter *iter) { - /* TODO: implement this for multires. It might also be worth changing this - * iterator to provide a coordinate and mask pointer directly for effiency, - * rather than converting back and forth between CCGElem and global index. */ + /* TODO: optimize this. We could fill SculptVertexNeighborIter directly, + * maybe provide coordinate and mask pointers directly rather than converting + * back and forth between CCGElem and global index. */ + 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; + + SubdivCCGCoord coord = {.grid_index = grid_index, + .x = vertex_index % key->grid_size, + .y = vertex_index / key->grid_size}; + + SubdivCCGNeighbors neighbors; + BKE_subdiv_ccg_neighbor_coords_get(ss->subdiv_ccg, &coord, &neighbors); + iter->size = 0; iter->capacity = SCULPT_VERTEX_NEIGHBOR_FIXED_CAPACITY; iter->neighbors = iter->neighbors_fixed; + + for (int i = 0; i < neighbors.size; i++) { + sculpt_vertex_neighbor_add(iter, + neighbors.coords[i].grid_index * key->grid_area + + neighbors.coords[i].y * key->grid_size + neighbors.coords[i].x); + } + + if (neighbors.coords != neighbors.coords_fixed) { + MEM_freeN(neighbors.coords); + } } static void sculpt_vertex_neighbors_get(SculptSession *ss, |