Blender V5.0
extract_mesh_ibo_lines_adjacency.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2021 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
8
9#include <climits>
10
11#include "BLI_map.hh"
12#include "BLI_ordered_edge.hh"
13
14#include "BKE_editmesh.hh"
15
16#include "GPU_index_buffer.hh"
17
18#include "draw_subdivision.hh"
19#include "extract_mesh.hh"
20
21namespace blender::draw {
22
23#define NO_EDGE INT_MAX
24
26 Map<OrderedEdge, int> &edge_hash,
28 bool &is_manifold)
29{
30 for (const auto item : edge_hash.items()) {
31 int v_data = item.value;
32 if (v_data == NO_EDGE) {
33 continue;
34 }
35
36 int v2 = item.key.v_low;
37 int v3 = item.key.v_high;
38
39 int l1 = uint(abs(v_data)) - 1;
40 if (v_data < 0) { /* `inv_opposite`. */
41 std::swap(v2, v3);
42 }
43 int l2 = vert_to_corner[v2];
44 int l3 = vert_to_corner[v3];
45 GPU_indexbuf_add_line_adj_verts(&elb, l1, l2, l3, l1);
46 is_manifold = false;
47 }
48}
49
50inline void rotate_vector(uint3 &value)
51{
52 const uint tmp = value[0];
53 value[0] = value[2];
54 value[2] = value[1];
55 value[1] = tmp;
56}
57
59inline void lines_adjacency_triangle(uint3 vert_tri,
60 uint3 corner_tri,
61 MutableSpan<int> vert_to_corner,
62 Map<OrderedEdge, int> &edge_hash,
64 bool &is_manifold)
65{
66 /* Iterate around the triangle's edges. */
67 for (int e = 0; e < 3; e++) {
68 rotate_vector(vert_tri);
69 rotate_vector(corner_tri);
70
71 bool inv_indices = (vert_tri[1] > vert_tri[2]);
72 edge_hash.add_or_modify(
73 {vert_tri[1], vert_tri[2]},
74 [&](int *value) {
75 int new_value = int(corner_tri[0]) + 1; /* 0 cannot be signed so add one. */
76 *value = inv_indices ? -new_value : new_value;
77 /* Store loop indices for remaining non-manifold edges. */
78 vert_to_corner[vert_tri[1]] = corner_tri[1];
79 vert_to_corner[vert_tri[2]] = corner_tri[2];
80 },
81 [&](int *value) {
82 int v_data = *value;
83 if (v_data == NO_EDGE) {
84 int new_value = int(corner_tri[0]) + 1; /* 0 cannot be signed so add one. */
85 *value = inv_indices ? -new_value : new_value;
86 /* Store loop indices for remaining non-manifold edges. */
87 vert_to_corner[vert_tri[1]] = corner_tri[1];
88 vert_to_corner[vert_tri[2]] = corner_tri[2];
89 }
90 else {
91 /* HACK Tag as not used. Prevent overhead of BLI_edgehash_remove. */
92 *value = NO_EDGE;
93 bool inv_opposite = (v_data < 0);
94 const int corner_opposite = abs(v_data) - 1;
95 /* TODO: Make this part thread-safe. */
96 if (inv_opposite == inv_indices) {
97 /* Don't share edge if triangles have non matching winding. */
99 &elb, corner_tri[0], corner_tri[1], corner_tri[2], corner_tri[0]);
101 &elb, corner_opposite, corner_tri[1], corner_tri[2], corner_opposite);
102 is_manifold = false;
103 }
104 else {
106 &elb, corner_tri[0], corner_tri[1], corner_tri[2], corner_opposite);
107 }
108 }
109 });
110 }
111}
112
113static void calc_adjacency_bm(const MeshRenderData &mr,
114 MutableSpan<int> vert_to_corner,
115 Map<OrderedEdge, int> &edge_hash,
117 bool &is_manifold)
118{
120 for (const int i : looptris.index_range()) {
121 const std::array<BMLoop *, 3> &tri = looptris[i];
122 if (BM_elem_flag_test(tri[0]->f, BM_ELEM_HIDDEN)) {
123 continue;
124 }
126 uint3(BM_elem_index_get(tri[0]->v),
127 BM_elem_index_get(tri[1]->v),
128 BM_elem_index_get(tri[2]->v)),
130 vert_to_corner,
131 edge_hash,
132 elb,
133 is_manifold);
134 }
135}
136
138 MutableSpan<int> vert_to_corner,
139 Map<OrderedEdge, int> &edge_hash,
141 bool &is_manifold)
142{
143 const OffsetIndices faces = mr.faces;
144 const Span<int> corner_verts = mr.corner_verts;
145 const Span<bool> hide_poly = mr.hide_poly;
146 const Span<int3> corner_tris = mr.mesh->corner_tris();
147 for (const int face : faces.index_range()) {
148 if (!hide_poly.is_empty() && hide_poly[face]) {
149 continue;
150 }
152 for (const int3 &tri : corner_tris.slice(tris)) {
154 uint3(corner_verts[tri[0]], corner_verts[tri[1]], corner_verts[tri[2]]),
155 uint3(tri),
156 vert_to_corner,
157 edge_hash,
158 elb,
159 is_manifold);
160 }
161 }
162}
163
165{
166 /* Similar to poly_to_tri_count().
167 * There is always (loop + triangle - 1) edges inside a face.
168 * Accumulate for all faces and you get : */
169 const int tess_edge_len = mr.corners_num + mr.corner_tris_num - mr.faces_num;
170 Map<OrderedEdge, int> edge_hash;
171 edge_hash.reserve(tess_edge_len);
172 Array<int> vert_to_corner(mr.verts_num, 0);
173 bool is_manifold = true;
174
175 GPUIndexBufBuilder builder;
176 GPU_indexbuf_init(&builder, GPU_PRIM_LINES_ADJ, tess_edge_len, mr.corners_num);
177
179 calc_adjacency_mesh(mr, vert_to_corner, edge_hash, builder, is_manifold);
180 }
181 else {
182 calc_adjacency_bm(mr, vert_to_corner, edge_hash, builder, is_manifold);
183 }
184
185 create_lines_for_remaining_edges(vert_to_corner, edge_hash, builder, is_manifold);
186
187 r_is_manifold = is_manifold;
188
189 return gpu::IndexBufPtr(GPU_indexbuf_build(&builder));
190}
191
193 bool &r_is_manifold)
194{
195 /* For each face there is (loop + triangle - 1) edges. Since we only have quads, and a quad
196 * is split into 2 triangles, we have (loop + 2 - 1) = (loop + 1) edges for each quad, or in
197 * total: (number_of_loops + number_of_quads). */
198 const uint tess_edge_len = subdiv_cache.num_subdiv_loops + subdiv_cache.num_subdiv_quads;
199
200 Array<int> vert_to_corner(subdiv_cache.num_subdiv_verts, 0);
201 Map<OrderedEdge, int> edge_hash;
202 edge_hash.reserve(tess_edge_len);
203
204 bool is_manifold = true;
205
206 GPUIndexBufBuilder builder;
207 GPU_indexbuf_init(&builder, GPU_PRIM_LINES_ADJ, tess_edge_len, subdiv_cache.num_subdiv_loops);
208
209 for (const int subdiv_quad_index : IndexRange(subdiv_cache.num_subdiv_quads)) {
210 const uint loop_index = subdiv_quad_index * 4;
211 const uint corner_0 = loop_index + 0;
212 const uint corner_1 = loop_index + 1;
213 const uint corner_2 = loop_index + 2;
214 const uint corner_3 = loop_index + 3;
215
216 const uint vert_0 = subdiv_cache.subdiv_loop_subdiv_vert_index[corner_0];
217 const uint vert_1 = subdiv_cache.subdiv_loop_subdiv_vert_index[corner_1];
218 const uint vert_2 = subdiv_cache.subdiv_loop_subdiv_vert_index[corner_2];
219 const uint vert_3 = subdiv_cache.subdiv_loop_subdiv_vert_index[corner_3];
220
221 lines_adjacency_triangle({vert_0, vert_1, vert_2},
222 {corner_0, corner_1, corner_2},
223 vert_to_corner,
224 edge_hash,
225 builder,
226 is_manifold);
227 lines_adjacency_triangle({vert_0, vert_2, vert_3},
228 {corner_0, corner_2, corner_3},
229 vert_to_corner,
230 edge_hash,
231 builder,
232 is_manifold);
233 }
234
235 create_lines_for_remaining_edges(vert_to_corner, edge_hash, builder, is_manifold);
236
237 r_is_manifold = is_manifold;
238
239 return gpu::IndexBufPtr(GPU_indexbuf_build(&builder));
240}
241
242#undef NO_EDGE
243
244} // namespace blender::draw
unsigned int uint
void GPU_indexbuf_init(GPUIndexBufBuilder *, GPUPrimType, uint prim_len, uint vertex_len)
blender::gpu::IndexBuf * GPU_indexbuf_build(GPUIndexBufBuilder *)
void GPU_indexbuf_add_line_adj_verts(GPUIndexBufBuilder *, uint v1, uint v2, uint v3, uint v4)
@ GPU_PRIM_LINES_ADJ
@ BM_ELEM_HIDDEN
#define BM_elem_index_get(ele)
#define BM_elem_flag_test(ele, hflag)
ATTR_WARN_UNUSED_RESULT const BMVert * v2
ATTR_WARN_UNUSED_RESULT const BMVert const BMEdge * e
ATTR_WARN_UNUSED_RESULT const BMVert * v
void reserve(int64_t n)
Definition BLI_map.hh:1028
auto add_or_modify(const Key &key, const CreateValueF &create_value, const ModifyValueF &modify_value) -> decltype(create_value(nullptr))
Definition BLI_map.hh:481
ItemIterator items() const &
Definition BLI_map.hh:902
constexpr Span slice(int64_t start, int64_t size) const
Definition BLI_span.hh:137
constexpr IndexRange index_range() const
Definition BLI_span.hh:401
constexpr bool is_empty() const
Definition BLI_span.hh:260
Extraction of Mesh data into VBO to feed to GPU.
#define abs
static char faces[256]
IndexRange face_triangles_range(OffsetIndices< int > faces, int face_i)
Definition BKE_mesh.hh:359
gpu::IndexBufPtr extract_lines_adjacency_subdiv(const DRWSubdivCache &subdiv_cache, bool &r_is_manifold)
gpu::IndexBufPtr extract_lines_adjacency(const MeshRenderData &mr, bool &r_is_manifold)
static void calc_adjacency_mesh(const MeshRenderData &mr, MutableSpan< int > vert_to_corner, Map< OrderedEdge, int > &edge_hash, GPUIndexBufBuilder &elb, bool &is_manifold)
void lines_adjacency_triangle(uint3 vert_tri, uint3 corner_tri, MutableSpan< int > vert_to_corner, Map< OrderedEdge, int > &edge_hash, GPUIndexBufBuilder &elb, bool &is_manifold)
static void calc_adjacency_bm(const MeshRenderData &mr, MutableSpan< int > vert_to_corner, Map< OrderedEdge, int > &edge_hash, GPUIndexBufBuilder &elb, bool &is_manifold)
static void create_lines_for_remaining_edges(MutableSpan< int > vert_to_corner, Map< OrderedEdge, int > &edge_hash, GPUIndexBufBuilder &elb, bool &is_manifold)
std::unique_ptr< IndexBuf, IndexBufDeleter > IndexBufPtr
VecBase< uint32_t, 3 > uint3
VecBase< int32_t, 3 > int3
blender::Array< std::array< BMLoop *, 3 > > looptris
OffsetIndices< int > faces
i
Definition text_draw.cc:230