Blender  V3.3
extract_mesh_ibo_lines_adjacency.cc
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later
2  * Copyright 2021 Blender Foundation. All rights reserved. */
3 
8 #include "BLI_edgehash.h"
9 #include "BLI_vector.hh"
10 
11 #include "MEM_guardedalloc.h"
12 
13 #include "draw_subdivision.h"
14 #include "extract_mesh.hh"
15 
16 namespace blender::draw {
17 
18 /* ---------------------------------------------------------------------- */
22 #define NO_EDGE INT_MAX
23 
28  /* Array to convert vert index to any loop index of this vert. */
30 };
31 
33  uint vert_len,
34  uint loop_len,
35  uint tess_edge_len)
36 {
37  data->vert_to_loop = static_cast<uint *>(MEM_callocN(sizeof(uint) * vert_len, __func__));
38 
39  GPU_indexbuf_init(&data->elb, GPU_PRIM_LINES_ADJ, tess_edge_len, loop_len);
40  data->eh = BLI_edgehash_new_ex(__func__, tess_edge_len);
41  data->is_manifold = true;
42 }
43 
45  MeshBatchCache *UNUSED(cache),
46  void *UNUSED(buf),
47  void *tls_data)
48 {
49  /* Similar to poly_to_tri_count().
50  * There is always (loop + triangle - 1) edges inside a polygon.
51  * Accumulate for all polys and you get : */
52  uint tess_edge_len = mr->loop_len + mr->tri_len - mr->poly_len;
53 
55  line_adjacency_data_init(data, mr->vert_len, mr->loop_len, tess_edge_len);
56 }
57 
60 {
61  GPUIndexBufBuilder *elb = &data->elb;
62  /* Iterate around the triangle's edges. */
63  for (int e = 0; e < 3; e++) {
64  SHIFT3(uint, v3, v2, v1);
65  SHIFT3(uint, l3, l2, l1);
66 
67  bool inv_indices = (v2 > v3);
68  void **pval;
69  bool value_is_init = BLI_edgehash_ensure_p(data->eh, v2, v3, &pval);
70  int v_data = POINTER_AS_INT(*pval);
71  if (!value_is_init || v_data == NO_EDGE) {
72  /* Save the winding order inside the sign bit. Because the
73  * Edge-hash sort the keys and we need to compare winding later. */
74  int value = (int)l1 + 1; /* 0 cannot be signed so add one. */
75  *pval = POINTER_FROM_INT((inv_indices) ? -value : value);
76  /* Store loop indices for remaining non-manifold edges. */
77  data->vert_to_loop[v2] = l2;
78  data->vert_to_loop[v3] = l3;
79  }
80  else {
81  /* HACK Tag as not used. Prevent overhead of BLI_edgehash_remove. */
82  *pval = POINTER_FROM_INT(NO_EDGE);
83  bool inv_opposite = (v_data < 0);
84  uint l_opposite = (uint)abs(v_data) - 1;
85  /* TODO: Make this part thread-safe. */
86  if (inv_opposite == inv_indices) {
87  /* Don't share edge if triangles have non matching winding. */
88  GPU_indexbuf_add_line_adj_verts(elb, l1, l2, l3, l1);
89  GPU_indexbuf_add_line_adj_verts(elb, l_opposite, l2, l3, l_opposite);
90  data->is_manifold = false;
91  }
92  else {
93  GPU_indexbuf_add_line_adj_verts(elb, l1, l2, l3, l_opposite);
94  }
95  }
96  }
97 }
98 
100  BMLoop **elt,
101  const int UNUSED(elt_index),
102  void *_data)
103 {
105  if (!BM_elem_flag_test(elt[0]->f, BM_ELEM_HIDDEN)) {
107  BM_elem_index_get(elt[1]->v),
108  BM_elem_index_get(elt[2]->v),
109  BM_elem_index_get(elt[0]),
110  BM_elem_index_get(elt[1]),
111  BM_elem_index_get(elt[2]),
112  data);
113  }
114 }
115 
117  const MLoopTri *mlt,
118  const int UNUSED(elt_index),
119  void *_data)
120 {
122  const MPoly *mp = &mr->mpoly[mlt->poly];
123  if (!(mr->use_hide && (mp->flag & ME_HIDE))) {
124  lines_adjacency_triangle(mr->mloop[mlt->tri[0]].v,
125  mr->mloop[mlt->tri[1]].v,
126  mr->mloop[mlt->tri[2]].v,
127  mlt->tri[0],
128  mlt->tri[1],
129  mlt->tri[2],
130  data);
131  }
132 }
133 
135  MeshBatchCache *cache,
136  void *buf,
137  void *_data)
138 {
139  GPUIndexBuf *ibo = static_cast<GPUIndexBuf *>(buf);
141  /* Create edges for remaining non manifold edges. */
144  uint v2, v3, l1, l2, l3;
146  if (v_data != NO_EDGE) {
147  BLI_edgehashIterator_getKey(ehi, &v2, &v3);
148  l1 = (uint)abs(v_data) - 1;
149  if (v_data < 0) { /* `inv_opposite`. */
150  SWAP(uint, v2, v3);
151  }
152  l2 = data->vert_to_loop[v2];
153  l3 = data->vert_to_loop[v3];
154  GPU_indexbuf_add_line_adj_verts(&data->elb, l1, l2, l3, l1);
155  data->is_manifold = false;
156  }
157  }
159  BLI_edgehash_free(data->eh, nullptr);
160 
161  cache->is_manifold = data->is_manifold;
162 
163  GPU_indexbuf_build_in_place(&data->elb, ibo);
164  MEM_freeN(data->vert_to_loop);
165 }
166 
167 static void extract_lines_adjacency_init_subdiv(const DRWSubdivCache *subdiv_cache,
168  const MeshRenderData *UNUSED(mr),
169  MeshBatchCache *UNUSED(cache),
170  void *UNUSED(buf),
171  void *_data)
172 {
174 
175  /* For each polygon there is (loop + triangle - 1) edges. Since we only have quads, and a quad
176  * is split into 2 triangles, we have (loop + 2 - 1) = (loop + 1) edges for each quad, or in
177  * total: (number_of_loops + number_of_quads). */
178  const uint tess_len = subdiv_cache->num_subdiv_loops + subdiv_cache->num_subdiv_quads;
180  data, subdiv_cache->num_subdiv_verts, subdiv_cache->num_subdiv_loops, tess_len);
181 }
182 
183 static void extract_lines_adjacency_iter_subdiv(const DRWSubdivCache *subdiv_cache,
184  const MeshRenderData *UNUSED(mr),
185  void *_data,
186  uint subdiv_quad_index)
187 {
189 
190  const uint loop_index = subdiv_quad_index * 4;
191  const uint l0 = loop_index + 0;
192  const uint l1 = loop_index + 1;
193  const uint l2 = loop_index + 2;
194  const uint l3 = loop_index + 3;
195 
196  const uint v0 = subdiv_cache->subdiv_loop_subdiv_vert_index[l0];
197  const uint v1 = subdiv_cache->subdiv_loop_subdiv_vert_index[l1];
198  const uint v2 = subdiv_cache->subdiv_loop_subdiv_vert_index[l2];
199  const uint v3 = subdiv_cache->subdiv_loop_subdiv_vert_index[l3];
200 
201  lines_adjacency_triangle(v0, v1, v2, l0, l1, l2, data);
202  lines_adjacency_triangle(v0, v2, v3, l0, l2, l3, data);
203 }
204 
206  const MeshRenderData *mr,
207  void *_data,
208  uint subdiv_quad_index,
209  const BMFace *UNUSED(coarse_quad))
210 {
211  extract_lines_adjacency_iter_subdiv(subdiv_cache, mr, _data, subdiv_quad_index);
212 }
213 
215  const MeshRenderData *mr,
216  void *_data,
217  uint subdiv_quad_index,
218  const MPoly *UNUSED(coarse_quad))
219 {
220  extract_lines_adjacency_iter_subdiv(subdiv_cache, mr, _data, subdiv_quad_index);
221 }
222 
224  const MeshRenderData *mr,
225  MeshBatchCache *cache,
226  void *buf,
227  void *_data)
228 {
229  extract_lines_adjacency_finish(mr, cache, buf, _data);
230 }
231 
232 #undef NO_EDGE
233 
235 {
236  MeshExtract extractor = {nullptr};
245  extractor.data_type = MR_DATA_NONE;
246  extractor.data_size = sizeof(MeshExtract_LineAdjacency_Data);
247  extractor.use_threading = false;
248  extractor.mesh_buffer_offset = offsetof(MeshBufferList, ibo.lines_adjacency);
249  return extractor;
250 }
251 
254 } // namespace blender::draw
255 
#define BLI_INLINE
void BLI_edgehash_free(EdgeHash *eh, EdgeHashFreeFP free_value)
Definition: edgehash.c:230
BLI_INLINE void BLI_edgehashIterator_getKey(EdgeHashIterator *ehi, unsigned int *r_v0, unsigned int *r_v1)
Definition: BLI_edgehash.h:161
EdgeHashIterator * BLI_edgehashIterator_new(EdgeHash *eh) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT
Definition: edgehash.c:394
bool BLI_edgehash_ensure_p(EdgeHash *eh, unsigned int v0, unsigned int v1, void ***r_val) ATTR_WARN_UNUSED_RESULT
Definition: edgehash.c:307
BLI_INLINE void BLI_edgehashIterator_step(EdgeHashIterator *ehi)
Definition: BLI_edgehash.h:153
void BLI_edgehashIterator_free(EdgeHashIterator *ehi)
Definition: edgehash.c:408
BLI_INLINE void * BLI_edgehashIterator_getValue(EdgeHashIterator *ehi)
Definition: BLI_edgehash.h:169
BLI_INLINE bool BLI_edgehashIterator_isDone(const EdgeHashIterator *ehi)
Definition: BLI_edgehash.h:157
EdgeHash * BLI_edgehash_new_ex(const char *info, unsigned int nentries_reserve)
Definition: edgehash.c:212
unsigned int uint
Definition: BLI_sys_types.h:67
#define SWAP(type, a, b)
#define POINTER_FROM_INT(i)
#define SHIFT3(type, a, b, c)
#define UNUSED(x)
#define POINTER_AS_INT(i)
@ ME_HIDE
struct GPUIndexBuf GPUIndexBuf
void GPU_indexbuf_init(GPUIndexBufBuilder *, GPUPrimType, uint prim_len, uint vertex_len)
void GPU_indexbuf_add_line_adj_verts(GPUIndexBufBuilder *, uint v1, uint v2, uint v3, uint v4)
void GPU_indexbuf_build_in_place(GPUIndexBufBuilder *, GPUIndexBuf *)
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint GLsizei GLsizei GLenum type _GL_VOID_RET _GL_VOID GLsizei GLenum GLenum const void *pixels _GL_VOID_RET _GL_VOID const void *pointer _GL_VOID_RET _GL_VOID GLdouble v _GL_VOID_RET _GL_VOID GLfloat v _GL_VOID_RET _GL_VOID GLint GLint i2 _GL_VOID_RET _GL_VOID GLint j _GL_VOID_RET _GL_VOID GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble GLdouble GLdouble zFar _GL_VOID_RET _GL_UINT GLdouble *equation _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLenum GLfloat *v _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLfloat *values _GL_VOID_RET _GL_VOID GLushort *values _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLenum GLdouble *params _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_BOOL GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLenum GLfloat param _GL_VOID_RET _GL_VOID GLenum GLint param _GL_VOID_RET _GL_VOID GLushort pattern _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint const GLdouble *points _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint GLdouble v1
@ GPU_PRIM_LINES_ADJ
Definition: GPU_primitive.h:29
Read Guarded memory(de)allocation.
@ BM_ELEM_HIDDEN
Definition: bmesh_class.h:472
#define BM_elem_index_get(ele)
Definition: bmesh_inline.h:110
#define BM_elem_flag_test(ele, hflag)
Definition: bmesh_inline.h:12
ATTR_WARN_UNUSED_RESULT const BMVert * v2
ATTR_WARN_UNUSED_RESULT const BMVert const BMEdge * e
ATTR_WARN_UNUSED_RESULT const BMVert * v
@ MR_DATA_NONE
Extraction of Mesh data into VBO to feed to GPU.
const MeshExtract extract_lines_adjacency
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:27
void *(* MEM_callocN)(size_t len, const char *str)
Definition: mallocn.c:31
static void extract_lines_adjacency_iter_subdiv_bm(const DRWSubdivCache *subdiv_cache, const MeshRenderData *mr, void *_data, uint subdiv_quad_index, const BMFace *UNUSED(coarse_quad))
static void line_adjacency_data_init(MeshExtract_LineAdjacency_Data *data, uint vert_len, uint loop_len, uint tess_edge_len)
static void extract_lines_adjacency_iter_subdiv_mesh(const DRWSubdivCache *subdiv_cache, const MeshRenderData *mr, void *_data, uint subdiv_quad_index, const MPoly *UNUSED(coarse_quad))
static void extract_lines_adjacency_iter_subdiv(const DRWSubdivCache *subdiv_cache, const MeshRenderData *UNUSED(mr), void *_data, uint subdiv_quad_index)
static void extract_lines_adjacency_finish_subdiv(const DRWSubdivCache *UNUSED(subdiv_cache), const MeshRenderData *mr, MeshBatchCache *cache, void *buf, void *_data)
constexpr MeshExtract create_extractor_lines_adjacency()
static void extract_lines_adjacency_iter_looptri_mesh(const MeshRenderData *mr, const MLoopTri *mlt, const int UNUSED(elt_index), void *_data)
BLI_INLINE void lines_adjacency_triangle(uint v1, uint v2, uint v3, uint l1, uint l2, uint l3, MeshExtract_LineAdjacency_Data *data)
static void extract_lines_adjacency_finish(const MeshRenderData *UNUSED(mr), MeshBatchCache *cache, void *buf, void *_data)
static void extract_lines_adjacency_init(const MeshRenderData *mr, MeshBatchCache *UNUSED(cache), void *UNUSED(buf), void *tls_data)
static void extract_lines_adjacency_iter_looptri_bm(const MeshRenderData *UNUSED(mr), BMLoop **elt, const int UNUSED(elt_index), void *_data)
static void extract_lines_adjacency_init_subdiv(const DRWSubdivCache *subdiv_cache, const MeshRenderData *UNUSED(mr), MeshBatchCache *UNUSED(cache), void *UNUSED(buf), void *_data)
T abs(const T &a)
int * subdiv_loop_subdiv_vert_index
unsigned int poly
unsigned int tri[3]
unsigned int v
GPUIndexBuf * lines_adjacency
ExtractIterSubdivBMeshFn * iter_subdiv_bm
size_t mesh_buffer_offset
eMRDataType data_type
ExtractFinishFn * finish
ExtractIterSubdivMeshFn * iter_subdiv_mesh
ExtractInitSubdivFn * init_subdiv
size_t data_size
ExtractTriBMeshFn * iter_looptri_bm
ExtractFinishSubdivFn * finish_subdiv
ExtractTriMeshFn * iter_looptri_mesh
bool use_threading
ExtractInitFn * init
const MLoop * mloop
Definition: extract_mesh.hh:76
const MPoly * mpoly
Definition: extract_mesh.hh:77