Blender  V3.3
bmesh_decimate_dissolve.c
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2 
9 #include "MEM_guardedalloc.h"
10 
11 #include "BLI_heap.h"
12 #include "BLI_math.h"
13 
14 #include "BKE_customdata.h"
15 
16 #include "bmesh.h"
17 #include "bmesh_decimate.h" /* own include */
18 
19 /* check that collapsing a vertex between 2 edges doesn't cause a degenerate face. */
20 #define USE_DEGENERATE_CHECK
21 
22 #define COST_INVALID FLT_MAX
23 
24 struct DelimitData;
25 
26 static bool bm_edge_is_delimiter(const BMEdge *e,
27  const BMO_Delimit delimit,
28  const struct DelimitData *delimit_data);
29 static bool bm_vert_is_delimiter(const BMVert *v,
30  const BMO_Delimit delimit,
31  const struct DelimitData *delimit_data);
32 
33 /* multiply vertex edge angle by face angle
34  * this means we are not left with sharp corners between _almost_ planer faces
35  * convert angles [0-PI/2] -> [0-1], multiply together, then convert back to radians. */
37  const BMO_Delimit delimit,
38  const struct DelimitData *delimit_data)
39 {
40 #define UNIT_TO_ANGLE DEG2RADF(90.0f)
41 #define ANGLE_TO_UNIT (1.0f / UNIT_TO_ANGLE)
42 
43  const float angle = BM_vert_calc_edge_angle(v);
44  /* NOTE: could be either edge, it doesn't matter. */
45  if (v->e && BM_edge_is_manifold(v->e)) {
46  /* Checking delimited is important here,
47  * otherwise the boundary between two materials for e.g.
48  * will collapse if the faces on either side of the edge have a small angle.
49  *
50  * This way, delimiting edges are treated like boundary edges,
51  * the detail between two delimiting regions won't over-collapse. */
52  if (!bm_vert_is_delimiter(v, delimit, delimit_data)) {
55  }
56  }
57  return angle;
58 
59 #undef UNIT_TO_ANGLE
60 #undef ANGLE_TO_UNIT
61 }
62 
63 struct DelimitData {
68 };
69 
71  const struct DelimitData *delimit_data)
72 {
73  int cd_loop_offset;
74  for (cd_loop_offset = delimit_data->cd_loop_offset;
75  cd_loop_offset < delimit_data->cd_loop_offset_end;
76  cd_loop_offset += delimit_data->cd_loop_size) {
77  if (BM_edge_is_contiguous_loop_cd(e, delimit_data->cd_loop_type, cd_loop_offset) == false) {
78  return false;
79  }
80  }
81 
82  return true;
83 }
84 
85 static bool bm_edge_is_delimiter(const BMEdge *e,
86  const BMO_Delimit delimit,
87  const struct DelimitData *delimit_data)
88 {
89  /* Caller must ensure. */
91 
92  if (delimit != 0) {
93  if (delimit & BMO_DELIM_SEAM) {
95  return true;
96  }
97  }
98  if (delimit & BMO_DELIM_SHARP) {
99  if (BM_elem_flag_test(e, BM_ELEM_SMOOTH) == 0) {
100  return true;
101  }
102  }
103  if (delimit & BMO_DELIM_MATERIAL) {
104  if (e->l->f->mat_nr != e->l->radial_next->f->mat_nr) {
105  return true;
106  }
107  }
108  if (delimit & BMO_DELIM_NORMAL) {
109  if (!BM_edge_is_contiguous(e)) {
110  return true;
111  }
112  }
113  if (delimit & BMO_DELIM_UV) {
114  if (bm_edge_is_contiguous_loop_cd_all(e, delimit_data) == 0) {
115  return true;
116  }
117  }
118  }
119 
120  return false;
121 }
122 
123 static bool bm_vert_is_delimiter(const BMVert *v,
124  const BMO_Delimit delimit,
125  const struct DelimitData *delimit_data)
126 {
127  BLI_assert(v->e != NULL);
128 
129  if (delimit != 0) {
130  const BMEdge *e, *e_first;
131  e = e_first = v->e;
132  do {
133  if (BM_edge_is_manifold(e)) {
134  if (bm_edge_is_delimiter(e, delimit, delimit_data)) {
135  return true;
136  }
137  }
138  } while ((e = BM_DISK_EDGE_NEXT(e, v)) != e_first);
139  }
140  return false;
141 }
142 
144  const BMO_Delimit delimit,
145  const struct DelimitData *delimit_data)
146 {
147  if (BM_edge_is_manifold(e) && !bm_edge_is_delimiter(e, delimit, delimit_data)) {
148  float angle_cos_neg = dot_v3v3(e->l->f->no, e->l->radial_next->f->no);
149  if (BM_edge_is_contiguous(e)) {
150  angle_cos_neg *= -1;
151  }
152  return angle_cos_neg;
153  }
154 
155  return COST_INVALID;
156 }
157 
158 #ifdef USE_DEGENERATE_CHECK
159 
160 static void mul_v2_m3v3_center(float r[2],
161  const float m[3][3],
162  const float a[3],
163  const float center[3])
164 {
165  BLI_assert(r != a);
166  BLI_assert(r != center);
167 
168  float co[3];
169  sub_v3_v3v3(co, a, center);
170 
171  r[0] = m[0][0] * co[0] + m[1][0] * co[1] + m[2][0] * co[2];
172  r[1] = m[0][1] * co[0] + m[1][1] * co[1] + m[2][1] * co[2];
173 }
174 
176 {
177  /* Calculate relative to the central vertex for higher precision. */
178  const float *center = l_ear->v->co;
179 
180  float tri_2d[3][2];
181  float axis_mat[3][3];
182 
183  axis_dominant_v3_to_m3(axis_mat, l_ear->f->no);
184 
185  {
186  mul_v2_m3v3_center(tri_2d[0], axis_mat, l_ear->prev->v->co, center);
187 # if 0
188  mul_v2_m3v3_center(tri_2d[1], axis_mat, l_ear->v->co, center);
189 # else
190  zero_v2(tri_2d[1]);
191 # endif
192  mul_v2_m3v3_center(tri_2d[2], axis_mat, l_ear->next->v->co, center);
193  }
194 
195  /* check we're not flipping face corners before or after the ear */
196  {
197  float adjacent_2d[2];
198 
199  if (!BM_vert_is_edge_pair(l_ear->prev->v)) {
200  mul_v2_m3v3_center(adjacent_2d, axis_mat, l_ear->prev->prev->v->co, center);
201  if (signum_i(cross_tri_v2(adjacent_2d, tri_2d[0], tri_2d[1])) !=
202  signum_i(cross_tri_v2(adjacent_2d, tri_2d[0], tri_2d[2]))) {
203  return true;
204  }
205  }
206 
207  if (!BM_vert_is_edge_pair(l_ear->next->v)) {
208  mul_v2_m3v3_center(adjacent_2d, axis_mat, l_ear->next->next->v->co, center);
209  if (signum_i(cross_tri_v2(adjacent_2d, tri_2d[2], tri_2d[1])) !=
210  signum_i(cross_tri_v2(adjacent_2d, tri_2d[2], tri_2d[0]))) {
211  return true;
212  }
213  }
214  }
215 
216  /* check no existing verts are inside the triangle */
217  {
218  /* triangle may be concave, if so - flip so we can use clockwise check */
219  if (cross_tri_v2(UNPACK3(tri_2d)) < 0.0f) {
220  swap_v2_v2(tri_2d[1], tri_2d[2]);
221  }
222 
223  /* skip l_ear and adjacent verts */
224  BMLoop *l_iter, *l_first;
225 
226  l_iter = l_ear->next->next;
227  l_first = l_ear->prev;
228  do {
229  float co_2d[2];
230  mul_v2_m3v3_center(co_2d, axis_mat, l_iter->v->co, center);
231  if (isect_point_tri_v2_cw(co_2d, tri_2d[0], tri_2d[1], tri_2d[2])) {
232  return true;
233  }
234  } while ((l_iter = l_iter->next) != l_first);
235  }
236 
237  return false;
238 }
239 
241 {
242  BMEdge *e_pair[2];
243  BMVert *v_pair[2];
244 
245  if (BM_vert_edge_pair(v, &e_pair[0], &e_pair[1])) {
246 
247  /* allow wire edges */
248  if (BM_edge_is_wire(e_pair[0]) || BM_edge_is_wire(e_pair[1])) {
249  return false;
250  }
251 
252  v_pair[0] = BM_edge_other_vert(e_pair[0], v);
253  v_pair[1] = BM_edge_other_vert(e_pair[1], v);
254 
255  if (fabsf(cos_v3v3v3(v_pair[0]->co, v->co, v_pair[1]->co)) < (1.0f - FLT_EPSILON)) {
256  BMLoop *l_iter, *l_first;
257  l_iter = l_first = e_pair[1]->l;
258  do {
259  if (l_iter->f->len > 3) {
260  BMLoop *l_pivot = (l_iter->v == v ? l_iter : l_iter->next);
261  BLI_assert(v == l_pivot->v);
262  if (bm_loop_collapse_is_degenerate(l_pivot)) {
263  return true;
264  }
265  }
266  } while ((l_iter = l_iter->radial_next) != l_first);
267  }
268  return false;
269  }
270  return true;
271 }
272 #endif /* USE_DEGENERATE_CHECK */
273 
275  const float angle_limit,
276  const bool do_dissolve_boundaries,
277  BMO_Delimit delimit,
278  BMVert **vinput_arr,
279  const int vinput_len,
280  BMEdge **einput_arr,
281  const int einput_len,
282  const short oflag_out)
283 {
284  const float angle_limit_cos_neg = -cosf(angle_limit);
285  struct DelimitData delimit_data = {0};
286  const int eheap_table_len = do_dissolve_boundaries ? einput_len : max_ii(einput_len, vinput_len);
287  void *_heap_table = MEM_mallocN(sizeof(HeapNode *) * eheap_table_len, __func__);
288 
289  int i;
290 
291  if (delimit & BMO_DELIM_UV) {
292  const int layer_len = CustomData_number_of_layers(&bm->ldata, CD_MLOOPUV);
293  if (layer_len == 0) {
294  delimit &= ~BMO_DELIM_UV;
295  }
296  else {
297  delimit_data.cd_loop_type = CD_MLOOPUV;
298  delimit_data.cd_loop_size = CustomData_sizeof(delimit_data.cd_loop_type);
300  delimit_data.cd_loop_offset_end = delimit_data.cd_loop_size * layer_len;
301  }
302  }
303 
304  /* --- first edges --- */
305  if (1) {
306  BMEdge **earray;
307  Heap *eheap;
308  HeapNode **eheap_table = _heap_table;
309  HeapNode *enode_top;
310  int *vert_reverse_lookup;
311  BMIter iter;
312  BMEdge *e_iter;
313 
314  /* --- setup heap --- */
315  eheap = BLI_heap_new_ex(einput_len);
316 
317  /* wire -> tag */
318  BM_ITER_MESH (e_iter, &iter, bm, BM_EDGES_OF_MESH) {
319  BM_elem_flag_set(e_iter, BM_ELEM_TAG, BM_edge_is_wire(e_iter));
320  BM_elem_index_set(e_iter, -1); /* set dirty */
321  }
323 
324  /* build heap */
325  for (i = 0; i < einput_len; i++) {
326  BMEdge *e = einput_arr[i];
327  const float cost = bm_edge_calc_dissolve_error(e, delimit, &delimit_data);
328  eheap_table[i] = BLI_heap_insert(eheap, cost, e);
329  BM_elem_index_set(e, i); /* set dirty */
330  }
331 
332  while ((BLI_heap_is_empty(eheap) == false) &&
333  (BLI_heap_node_value((enode_top = BLI_heap_top(eheap))) < angle_limit_cos_neg)) {
334  BMFace *f_new = NULL;
335  BMEdge *e;
336 
337  e = BLI_heap_node_ptr(enode_top);
338  i = BM_elem_index_get(e);
339 
340  if (BM_edge_is_manifold(e)) {
341  f_new = BM_faces_join_pair(bm, e->l, e->l->radial_next, false);
342 
343  if (f_new) {
344  BMLoop *l_first, *l_iter;
345 
346  BLI_heap_remove(eheap, enode_top);
347  eheap_table[i] = NULL;
348 
349  /* update normal */
350  BM_face_normal_update(f_new);
351  if (oflag_out) {
352  BMO_face_flag_enable(bm, f_new, oflag_out);
353  }
354 
355  /* re-calculate costs */
356  l_iter = l_first = BM_FACE_FIRST_LOOP(f_new);
357  do {
358  const int j = BM_elem_index_get(l_iter->e);
359  if (j != -1 && eheap_table[j]) {
360  const float cost = bm_edge_calc_dissolve_error(l_iter->e, delimit, &delimit_data);
361  BLI_heap_node_value_update(eheap, eheap_table[j], cost);
362  }
363  } while ((l_iter = l_iter->next) != l_first);
364  }
365  }
366 
367  if (UNLIKELY(f_new == NULL)) {
368  BLI_heap_node_value_update(eheap, enode_top, COST_INVALID);
369  }
370  }
371 
372  /* prepare for cleanup */
374  vert_reverse_lookup = MEM_mallocN(sizeof(int) * bm->totvert, __func__);
375  copy_vn_i(vert_reverse_lookup, bm->totvert, -1);
376  for (i = 0; i < vinput_len; i++) {
377  BMVert *v = vinput_arr[i];
378  vert_reverse_lookup[BM_elem_index_get(v)] = i;
379  }
380 
381  /* --- cleanup --- */
382  earray = MEM_mallocN(sizeof(BMEdge *) * bm->totedge, __func__);
383  BM_ITER_MESH_INDEX (e_iter, &iter, bm, BM_EDGES_OF_MESH, i) {
384  earray[i] = e_iter;
385  }
386  /* Remove all edges/verts left behind from dissolving,
387  * NULL'ing the vertex array so we don't re-use. */
388  for (i = bm->totedge - 1; i != -1; i--) {
389  e_iter = earray[i];
390 
391  if (BM_edge_is_wire(e_iter) && (BM_elem_flag_test(e_iter, BM_ELEM_TAG) == false)) {
392  /* edge has become wire */
393  int vidx_reverse;
394  BMVert *v1 = e_iter->v1;
395  BMVert *v2 = e_iter->v2;
396  BM_edge_kill(bm, e_iter);
397  if (v1->e == NULL) {
398  vidx_reverse = vert_reverse_lookup[BM_elem_index_get(v1)];
399  if (vidx_reverse != -1) {
400  vinput_arr[vidx_reverse] = NULL;
401  }
402  BM_vert_kill(bm, v1);
403  }
404  if (v2->e == NULL) {
405  vidx_reverse = vert_reverse_lookup[BM_elem_index_get(v2)];
406  if (vidx_reverse != -1) {
407  vinput_arr[vidx_reverse] = NULL;
408  }
409  BM_vert_kill(bm, v2);
410  }
411  }
412  }
413  MEM_freeN(vert_reverse_lookup);
414  MEM_freeN(earray);
415 
416  BLI_heap_free(eheap, NULL);
417  }
418 
419  /* --- second verts --- */
420  if (do_dissolve_boundaries) {
421  /* simple version of the branch below, since we will dissolve _all_ verts that use 2 edges */
422  for (i = 0; i < vinput_len; i++) {
423  BMVert *v = vinput_arr[i];
424  if (LIKELY(v != NULL) && BM_vert_is_edge_pair(v)) {
425  BM_vert_collapse_edge(bm, v->e, v, true, true, true); /* join edges */
426  }
427  }
428  }
429  else {
430  Heap *vheap;
431  HeapNode **vheap_table = _heap_table;
432  HeapNode *vnode_top;
433 
434  BMVert *v_iter;
435  BMIter iter;
436 
437  BM_ITER_MESH (v_iter, &iter, bm, BM_VERTS_OF_MESH) {
438  BM_elem_index_set(v_iter, -1); /* set dirty */
439  }
441 
442  vheap = BLI_heap_new_ex(vinput_len);
443 
444  for (i = 0; i < vinput_len; i++) {
445  BMVert *v = vinput_arr[i];
446  if (LIKELY(v != NULL)) {
447  const float cost = bm_vert_edge_face_angle(v, delimit, &delimit_data);
448  vheap_table[i] = BLI_heap_insert(vheap, cost, v);
449  BM_elem_index_set(v, i); /* set dirty */
450  }
451  }
452 
453  while ((BLI_heap_is_empty(vheap) == false) &&
454  (BLI_heap_node_value((vnode_top = BLI_heap_top(vheap))) < angle_limit)) {
455  BMEdge *e_new = NULL;
456  BMVert *v;
457 
458  v = BLI_heap_node_ptr(vnode_top);
459  i = BM_elem_index_get(v);
460 
461  if (
464 #else
466 #endif
467  ) {
468  e_new = BM_vert_collapse_edge(bm, v->e, v, true, true, true); /* join edges */
469 
470  if (e_new) {
471 
472  BLI_heap_remove(vheap, vnode_top);
473  vheap_table[i] = NULL;
474 
475  /* update normal */
476  if (e_new->l) {
477  BMLoop *l_first, *l_iter;
478  l_iter = l_first = e_new->l;
479  do {
480  BM_face_normal_update(l_iter->f);
481  } while ((l_iter = l_iter->radial_next) != l_first);
482  }
483 
484  /* re-calculate costs */
485  BM_ITER_ELEM (v_iter, &iter, e_new, BM_VERTS_OF_EDGE) {
486  const int j = BM_elem_index_get(v_iter);
487  if (j != -1 && vheap_table[j]) {
488  const float cost = bm_vert_edge_face_angle(v_iter, delimit, &delimit_data);
489  BLI_heap_node_value_update(vheap, vheap_table[j], cost);
490  }
491  }
492 
493 #ifdef USE_DEGENERATE_CHECK
494  /* dissolving a vertex may mean vertices we previously weren't able to dissolve
495  * can now be re-evaluated. */
496  if (e_new->l) {
497  BMLoop *l_first, *l_iter;
498  l_iter = l_first = e_new->l;
499  do {
500  /* skip vertices part of this edge, evaluated above */
501  BMLoop *l_cycle_first, *l_cycle_iter;
502  l_cycle_iter = l_iter->next->next;
503  l_cycle_first = l_iter->prev;
504  do {
505  const int j = BM_elem_index_get(l_cycle_iter->v);
506  if (j != -1 && vheap_table[j] &&
507  (BLI_heap_node_value(vheap_table[j]) == COST_INVALID)) {
508  const float cost = bm_vert_edge_face_angle(
509  l_cycle_iter->v, delimit, &delimit_data);
510  BLI_heap_node_value_update(vheap, vheap_table[j], cost);
511  }
512  } while ((l_cycle_iter = l_cycle_iter->next) != l_cycle_first);
513 
514  } while ((l_iter = l_iter->radial_next) != l_first);
515  }
516 #endif /* USE_DEGENERATE_CHECK */
517  }
518  }
519 
520  if (UNLIKELY(e_new == NULL)) {
521  BLI_heap_node_value_update(vheap, vnode_top, COST_INVALID);
522  }
523  }
524 
525  BLI_heap_free(vheap, NULL);
526  }
527 
528  MEM_freeN(_heap_table);
529 }
530 
532  const float angle_limit,
533  const bool do_dissolve_boundaries,
534  const BMO_Delimit delimit)
535 {
536  int vinput_len;
537  int einput_len;
538 
539  BMVert **vinput_arr = BM_iter_as_arrayN(bm, BM_VERTS_OF_MESH, NULL, &vinput_len, NULL, 0);
540  BMEdge **einput_arr = BM_iter_as_arrayN(bm, BM_EDGES_OF_MESH, NULL, &einput_len, NULL, 0);
541 
543  angle_limit,
544  do_dissolve_boundaries,
545  delimit,
546  vinput_arr,
547  vinput_len,
548  einput_arr,
549  einput_len,
550  0);
551 
552  MEM_freeN(vinput_arr);
553  MEM_freeN(einput_arr);
554 }
CustomData interface, see also DNA_customdata_types.h.
int CustomData_number_of_layers(const struct CustomData *data, int type)
int CustomData_sizeof(int type)
Definition: customdata.cc:4268
int CustomData_get_n_offset(const struct CustomData *data, int type, int n)
#define BLI_assert(a)
Definition: BLI_assert.h:46
A min-heap / priority queue ADT.
void BLI_heap_free(Heap *heap, HeapFreeFP ptrfreefp) ATTR_NONNULL(1)
Definition: BLI_heap.c:202
void void float BLI_heap_node_value(const HeapNode *heap) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
Definition: BLI_heap.c:357
void void bool BLI_heap_is_empty(const Heap *heap) ATTR_NONNULL(1)
Definition: BLI_heap.c:279
Heap * BLI_heap_new_ex(unsigned int reserve_num) ATTR_WARN_UNUSED_RESULT
Definition: BLI_heap.c:182
void BLI_heap_node_value_update(Heap *heap, HeapNode *node, float value) ATTR_NONNULL(1
HeapNode * BLI_heap_insert(Heap *heap, float value, void *ptr) ATTR_NONNULL(1)
Definition: BLI_heap.c:245
void * BLI_heap_node_ptr(const HeapNode *heap) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
Definition: BLI_heap.c:362
HeapNode * BLI_heap_top(const Heap *heap) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
Definition: BLI_heap.c:289
void void BLI_heap_remove(Heap *heap, HeapNode *node) ATTR_NONNULL(1
MINLINE int max_ii(int a, int b)
MINLINE int signum_i(float a)
MINLINE float cross_tri_v2(const float v1[2], const float v2[2], const float v3[2])
bool isect_point_tri_v2_cw(const float pt[2], const float v1[2], const float v2[2], const float v3[2])
Definition: math_geom.c:1500
void axis_dominant_v3_to_m3(float r_mat[3][3], const float normal[3])
Normal to x,y matrix.
Definition: math_geom.c:3527
MINLINE void swap_v2_v2(float a[2], float b[2])
float cos_v3v3v3(const float p1[3], const float p2[3], const float p3[3]) ATTR_WARN_UNUSED_RESULT
Definition: math_vector.c:373
MINLINE void sub_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE float dot_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT
void copy_vn_i(int *array_tar, int size, int val)
Definition: math_vector.c:1223
MINLINE void zero_v2(float r[2])
#define UNPACK3(a)
#define UNLIKELY(x)
#define LIKELY(x)
@ CD_MLOOPUV
NSNotificationCenter * center
_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 GLdouble GLint GLint const GLdouble *points _GL_VOID_RET _GL_VOID GLdouble GLdouble u2 _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLdouble GLdouble v2 _GL_VOID_RET _GL_VOID GLenum GLfloat param _GL_VOID_RET _GL_VOID GLenum GLint param _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLdouble GLdouble nz _GL_VOID_RET _GL_VOID GLfloat GLfloat nz _GL_VOID_RET _GL_VOID GLint GLint nz _GL_VOID_RET _GL_VOID GLshort GLshort nz _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_VOID GLsizei const GLfloat *values _GL_VOID_RET _GL_VOID GLsizei const GLushort *values _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID const GLuint const GLclampf *priorities _GL_VOID_RET _GL_VOID GLdouble y _GL_VOID_RET _GL_VOID GLfloat y _GL_VOID_RET _GL_VOID GLint y _GL_VOID_RET _GL_VOID GLshort y _GL_VOID_RET _GL_VOID GLdouble GLdouble z _GL_VOID_RET _GL_VOID GLfloat GLfloat z _GL_VOID_RET _GL_VOID GLint GLint z _GL_VOID_RET _GL_VOID GLshort GLshort z _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble w _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat w _GL_VOID_RET _GL_VOID GLint GLint GLint w _GL_VOID_RET _GL_VOID GLshort GLshort GLshort w _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble y2 _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat y2 _GL_VOID_RET _GL_VOID GLint GLint GLint y2 _GL_VOID_RET _GL_VOID GLshort GLshort GLshort y2 _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble z _GL_VOID_RET _GL_VOID GLdouble GLdouble z _GL_VOID_RET _GL_VOID GLuint *buffer _GL_VOID_RET _GL_VOID GLdouble t _GL_VOID_RET _GL_VOID GLfloat t _GL_VOID_RET _GL_VOID GLint t _GL_VOID_RET _GL_VOID GLshort t _GL_VOID_RET _GL_VOID GLdouble GLdouble r _GL_VOID_RET _GL_VOID GLfloat GLfloat r _GL_VOID_RET _GL_VOID GLint GLint r _GL_VOID_RET _GL_VOID GLshort GLshort r _GL_VOID_RET _GL_VOID GLdouble GLdouble r
_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
Read Guarded memory(de)allocation.
#define BM_DISK_EDGE_NEXT(e, v)
Definition: bmesh_class.h:625
#define BM_FACE_FIRST_LOOP(p)
Definition: bmesh_class.h:622
@ BM_VERT
Definition: bmesh_class.h:383
@ BM_EDGE
Definition: bmesh_class.h:384
@ BM_ELEM_SEAM
Definition: bmesh_class.h:473
@ BM_ELEM_SMOOTH
Definition: bmesh_class.h:477
@ BM_ELEM_TAG
Definition: bmesh_class.h:484
void BM_vert_kill(BMesh *bm, BMVert *v)
Definition: bmesh_core.c:939
void BM_edge_kill(BMesh *bm, BMEdge *e)
Definition: bmesh_core.c:927
void BM_mesh_decimate_dissolve(BMesh *bm, const float angle_limit, const bool do_dissolve_boundaries, const BMO_Delimit delimit)
static bool bm_edge_is_contiguous_loop_cd_all(const BMEdge *e, const struct DelimitData *delimit_data)
static float bm_vert_edge_face_angle(BMVert *v, const BMO_Delimit delimit, const struct DelimitData *delimit_data)
#define ANGLE_TO_UNIT
#define UNIT_TO_ANGLE
static float bm_edge_calc_dissolve_error(const BMEdge *e, const BMO_Delimit delimit, const struct DelimitData *delimit_data)
static bool bm_vert_is_delimiter(const BMVert *v, const BMO_Delimit delimit, const struct DelimitData *delimit_data)
static bool bm_loop_collapse_is_degenerate(BMLoop *l_ear)
static void mul_v2_m3v3_center(float r[2], const float m[3][3], const float a[3], const float center[3])
#define COST_INVALID
static bool bm_edge_is_delimiter(const BMEdge *e, const BMO_Delimit delimit, const struct DelimitData *delimit_data)
static bool bm_vert_collapse_is_degenerate(BMVert *v)
void BM_mesh_decimate_dissolve_ex(BMesh *bm, const float angle_limit, const bool do_dissolve_boundaries, BMO_Delimit delimit, BMVert **vinput_arr, const int vinput_len, BMEdge **einput_arr, const int einput_len, const short oflag_out)
#define USE_DEGENERATE_CHECK
#define BM_elem_index_get(ele)
Definition: bmesh_inline.h:110
#define BM_elem_flag_set(ele, hflag, val)
Definition: bmesh_inline.h:16
#define BM_elem_index_set(ele, index)
Definition: bmesh_inline.h:111
#define BM_elem_flag_test(ele, hflag)
Definition: bmesh_inline.h:12
void * BM_iter_as_arrayN(BMesh *bm, const char itype, void *data, int *r_len, void **stack_array, int stack_array_size)
Iterator as Array.
#define BM_ITER_ELEM(ele, iter, data, itype)
#define BM_ITER_MESH(ele, iter, bm, itype)
#define BM_ITER_MESH_INDEX(ele, iter, bm, itype, indexvar)
@ BM_EDGES_OF_MESH
@ BM_VERTS_OF_MESH
@ BM_VERTS_OF_EDGE
ATTR_WARN_UNUSED_RESULT BMesh * bm
void BM_mesh_elem_index_ensure(BMesh *bm, const char htype)
Definition: bmesh_mesh.cc:446
BMFace * BM_faces_join_pair(BMesh *bm, BMLoop *l_a, BMLoop *l_b, const bool do_del)
Faces Join Pair.
Definition: bmesh_mods.c:166
BMEdge * BM_vert_collapse_edge(BMesh *bm, BMEdge *e_kill, BMVert *v_kill, const bool do_del, const bool kill_degenerate_faces, const bool kill_duplicate_faces)
Vert Collapse Faces.
Definition: bmesh_mods.c:402
#define BMO_face_flag_enable(bm, e, oflag)
@ BMO_DELIM_NORMAL
@ BMO_DELIM_MATERIAL
@ BMO_DELIM_SEAM
@ BMO_DELIM_SHARP
@ BMO_DELIM_UV
void BM_face_normal_update(BMFace *f)
float BM_vert_calc_edge_angle(const BMVert *v)
Definition: bmesh_query.c:1415
bool BM_edge_is_contiguous_loop_cd(const BMEdge *e, const int cd_loop_type, const int cd_loop_offset)
Definition: bmesh_query.c:875
float BM_edge_calc_face_angle(const BMEdge *e)
Definition: bmesh_query.c:1338
bool BM_vert_edge_pair(BMVert *v, BMEdge **r_e_a, BMEdge **r_e_b)
Definition: bmesh_query.c:590
bool BM_vert_is_edge_pair(const BMVert *v)
Definition: bmesh_query.c:568
BLI_INLINE bool BM_edge_is_contiguous(const BMEdge *e) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
BLI_INLINE bool BM_edge_is_manifold(const BMEdge *e) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
BLI_INLINE BMVert * BM_edge_other_vert(BMEdge *e, const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
BLI_INLINE bool BM_edge_is_wire(const BMEdge *e) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
ATTR_WARN_UNUSED_RESULT const BMVert * v2
ATTR_WARN_UNUSED_RESULT const BMVert const BMEdge * e
ATTR_WARN_UNUSED_RESULT const BMVert * v
SIMD_FORCE_INLINE btScalar angle(const btVector3 &v) const
Return the angle between this and another vector.
Definition: btVector3.h:356
#define cosf(x)
Definition: cuda/compat.h:101
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:27
void *(* MEM_mallocN)(size_t len, const char *str)
Definition: mallocn.c:33
#define fabsf(x)
Definition: metal/compat.h:219
static unsigned a[3]
Definition: RandGen.cpp:78
BMVert * v1
Definition: bmesh_class.h:122
BMVert * v2
Definition: bmesh_class.h:122
struct BMLoop * l
Definition: bmesh_class.h:128
int len
Definition: bmesh_class.h:267
float no[3]
Definition: bmesh_class.h:271
struct BMVert * v
Definition: bmesh_class.h:153
struct BMEdge * e
Definition: bmesh_class.h:164
struct BMLoop * radial_next
Definition: bmesh_class.h:204
struct BMLoop * prev
Definition: bmesh_class.h:233
struct BMFace * f
Definition: bmesh_class.h:171
struct BMLoop * next
Definition: bmesh_class.h:233
float co[3]
Definition: bmesh_class.h:87
struct BMEdge * e
Definition: bmesh_class.h:97
float no[3]
Definition: bmesh_class.h:88
int totvert
Definition: bmesh_class.h:297
char elem_index_dirty
Definition: bmesh_class.h:305
int totedge
Definition: bmesh_class.h:297
CustomData ldata
Definition: bmesh_class.h:337
Definition: BLI_heap.c:43