Blender V5.0
sculpt_flood_fill.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2024 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
6
7#include "BKE_attribute.hh"
8#include "BKE_mesh.hh"
9
10#include "DNA_mesh_types.h"
11
12#include "paint_intern.hh"
13#include "sculpt_hide.hh"
14#include "sculpt_intern.hh"
15
16#include "bmesh.hh"
17
18/* -------------------------------------------------------------------- */
23
25
26void FillDataMesh::add_initial(const int vertex)
27{
28 this->queue.push(vertex);
29}
30
32{
33 for (const int vert : verts) {
34 this->add_initial(vert);
35 }
36}
37
39{
40 this->queue.push(vertex);
41}
42
44{
45 for (const int vert : verts) {
47 }
48}
49
51{
52 this->queue.push(vertex);
53}
54
56{
57 for (const int vert : verts) {
58 this->add_initial(BM_vert_at_index(&bm, vert));
59 }
60}
61
63{
64 this->queue.push(vertex);
65 this->visited_verts[vertex].set();
66}
67
68void FillDataGrids::add_and_skip_initial(const SubdivCCGCoord vertex, const int index)
69{
70 this->queue.push(vertex);
71 this->visited_verts[index].set();
72}
73
74void FillDataBMesh::add_and_skip_initial(BMVert *vertex, const int index)
75{
76 this->queue.push(vertex);
77 this->visited_verts[index].set();
78}
79
81 const GroupedSpan<int> vert_to_face_map,
82 FunctionRef<bool(int from_v, int to_v)> func)
83{
84 Mesh &mesh = *static_cast<Mesh *>(object.data);
85 const OffsetIndices faces = mesh.faces();
86 const Span<int> corner_verts = mesh.corner_verts();
87 const bke::AttributeAccessor attributes = mesh.attributes();
88 const VArraySpan hide_poly = *attributes.lookup<bool>(".hide_poly", bke::AttrDomain::Face);
89 const VArray hide_vert = *attributes.lookup_or_default<bool>(
90 ".hide_vert", bke::AttrDomain::Point, false);
91
92 Vector<int> neighbors;
93 while (!this->queue.empty()) {
94 const int from_v = this->queue.front();
95 this->queue.pop();
96
97 vert_neighbors_get_mesh(faces, corner_verts, vert_to_face_map, hide_poly, from_v, neighbors);
98 if (!this->fake_neighbors.is_empty() && this->fake_neighbors[from_v] != FAKE_NEIGHBOR_NONE) {
99 neighbors.append(this->fake_neighbors[from_v]);
100 }
101
102 for (const int neighbor : neighbors) {
103 if (this->visited_verts[neighbor]) {
104 continue;
105 }
106
107 if (!hide_vert.is_empty() && hide_vert[neighbor]) {
108 continue;
109 }
110
111 this->visited_verts[neighbor].set();
112 if (func(from_v, neighbor)) {
113 this->queue.push(neighbor);
114 }
115 }
116 }
117}
118
120 Object & /*object*/,
121 const SubdivCCG &subdiv_ccg,
122 FunctionRef<bool(SubdivCCGCoord from_v, SubdivCCGCoord to_v, bool is_duplicate)> func)
123{
124 const CCGKey key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
125 while (!this->queue.empty()) {
126 SubdivCCGCoord from_v = this->queue.front();
127 this->queue.pop();
128
129 SubdivCCGNeighbors neighbors;
130 BKE_subdiv_ccg_neighbor_coords_get(subdiv_ccg, from_v, true, neighbors);
131 if (!this->fake_neighbors.is_empty() &&
132 this->fake_neighbors[from_v.to_index(key)] != FAKE_NEIGHBOR_NONE)
133 {
134 neighbors.coords.insert(
135 0, SubdivCCGCoord::from_index(key, this->fake_neighbors[from_v.to_index(key)]));
136 }
137
138 const int num_unique = neighbors.coords.size() - neighbors.num_duplicates;
139
140 /* Flood fill expects the duplicate entries to be passed to the per-neighbor lambda first, so
141 * iterate from the end of the vector to the beginning. */
142 for (int i = neighbors.coords.size() - 1; i >= 0; i--) {
143 SubdivCCGCoord neighbor = neighbors.coords[i];
144 const int index_in_grid = neighbor.y * key.grid_size + neighbor.x;
145 const int index = neighbor.grid_index * key.grid_area + index_in_grid;
146 if (this->visited_verts[index]) {
147 continue;
148 }
149
150 if (!subdiv_ccg.grid_hidden.is_empty() &&
151 subdiv_ccg.grid_hidden[neighbor.grid_index][index_in_grid])
152 {
153 continue;
154 }
155
156 this->visited_verts[index].set();
157 const bool is_duplicate = i >= num_unique;
158 if (func(from_v, neighbor, is_duplicate)) {
159 this->queue.push(neighbor);
160 }
161 }
162 }
163}
164
165void FillDataBMesh::execute(Object &object, FunctionRef<bool(BMVert *from_v, BMVert *to_v)> func)
166{
167 BMesh *bm = object.sculpt->bm;
168 BMeshNeighborVerts neighbors;
169 while (!this->queue.empty()) {
170 BMVert *from_v = this->queue.front();
171 this->queue.pop();
172
173 if (!this->fake_neighbors.is_empty() &&
174 this->fake_neighbors[BM_elem_index_get(from_v)] != FAKE_NEIGHBOR_NONE)
175 {
176 neighbors.append(BM_vert_at_index(bm, this->fake_neighbors[BM_elem_index_get(from_v)]));
177 }
178
179 for (BMVert *neighbor : vert_neighbors_get_bmesh(*from_v, neighbors)) {
180 const int neighbor_idx = BM_elem_index_get(neighbor);
181 if (this->visited_verts[neighbor_idx]) {
182 continue;
183 }
184
185 if (BM_elem_flag_test(neighbor, BM_ELEM_HIDDEN)) {
186 continue;
187 }
188
189 this->visited_verts[neighbor_idx].set();
190 if (func(from_v, neighbor)) {
191 this->queue.push(neighbor);
192 }
193 }
194 }
195}
196
197} // namespace blender::ed::sculpt_paint::flood_fill
198
CCGKey BKE_subdiv_ccg_key_top_level(const SubdivCCG &subdiv_ccg)
void BKE_subdiv_ccg_neighbor_coords_get(const SubdivCCG &subdiv_ccg, const SubdivCCGCoord &coord, bool include_duplicates, SubdivCCGNeighbors &r_neighbors)
@ BM_ELEM_HIDDEN
#define BM_elem_index_get(ele)
#define BM_elem_flag_test(ele, hflag)
BMesh * bm
BLI_INLINE BMVert * BM_vert_at_index(BMesh *bm, const int index)
int64_t size() const
void append(const T &value)
void insert(const int64_t insert_index, const T &value)
GAttributeReader lookup_or_default(StringRef attribute_id, AttrDomain domain, AttrType data_type, const void *default_value=nullptr) const
GAttributeReader lookup(const StringRef attribute_id) const
static float verts[][3]
static char faces[256]
Vector< BMVert *, 64 > BMeshNeighborVerts
Span< BMVert * > vert_neighbors_get_bmesh(BMVert &vert, BMeshNeighborVerts &r_neighbors)
Definition sculpt.cc:387
Span< int > vert_neighbors_get_mesh(const OffsetIndices< int > faces, const Span< int > corner_verts, const GroupedSpan< int > vert_to_face, const Span< bool > hide_poly, const int vert, Vector< int > &r_neighbors)
Definition sculpt.cc:429
#define FAKE_NEIGHBOR_NONE
int grid_size
Definition BKE_ccg.hh:33
int grid_area
Definition BKE_ccg.hh:35
int to_index(const CCGKey &key) const
static SubdivCCGCoord from_index(const CCGKey &key, int index)
SubdivCCGNeighborCoords coords
blender::BitGroupVector grid_hidden
void execute(Object &object, FunctionRef< bool(BMVert *from_v, BMVert *to_v)> func)
void execute(Object &object, const SubdivCCG &subdiv_ccg, FunctionRef< bool(SubdivCCGCoord from_v, SubdivCCGCoord to_v, bool is_duplicate)> func)
void add_and_skip_initial(SubdivCCGCoord vertex, int index)
void execute(Object &object, GroupedSpan< int > vert_to_face_map, FunctionRef< bool(int from_v, int to_v)> func)
i
Definition text_draw.cc:230