Blender  V2.93
bmesh_decimate_dissolve.c
Go to the documentation of this file.
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  */
16 
23 #include "MEM_guardedalloc.h"
24 
25 #include "BLI_heap.h"
26 #include "BLI_math.h"
27 
28 #include "BKE_customdata.h"
29 
30 #include "bmesh.h"
31 #include "bmesh_decimate.h" /* own include */
32 
33 /* check that collapsing a vertex between 2 edges doesn't cause a degenerate face. */
34 #define USE_DEGENERATE_CHECK
35 
36 #define COST_INVALID FLT_MAX
37 
38 struct DelimitData;
39 
40 static bool bm_edge_is_delimiter(const BMEdge *e,
41  const BMO_Delimit delimit,
42  const struct DelimitData *delimit_data);
43 static bool bm_vert_is_delimiter(const BMVert *v,
44  const BMO_Delimit delimit,
45  const struct DelimitData *delimit_data);
46 
47 /* multiply vertex edge angle by face angle
48  * this means we are not left with sharp corners between _almost_ planer faces
49  * convert angles [0-PI/2] -> [0-1], multiply together, then convert back to radians. */
51  const BMO_Delimit delimit,
52  const struct DelimitData *delimit_data)
53 {
54 #define UNIT_TO_ANGLE DEG2RADF(90.0f)
55 #define ANGLE_TO_UNIT (1.0f / UNIT_TO_ANGLE)
56 
57  const float angle = BM_vert_calc_edge_angle(v);
58  /* note: could be either edge, it doesn't matter */
59  if (v->e && BM_edge_is_manifold(v->e)) {
60  /* Checking delimited is important here,
61  * otherwise the boundary between two materials for e.g.
62  * will collapse if the faces on either side of the edge have a small angle.
63  *
64  * This way, delimiting edges are treated like boundary edges,
65  * the detail between two delimiting regions won't over-collapse. */
66  if (!bm_vert_is_delimiter(v, delimit, delimit_data)) {
69  }
70  }
71  return angle;
72 
73 #undef UNIT_TO_ANGLE
74 #undef ANGLE_TO_UNIT
75 }
76 
77 struct DelimitData {
82 };
83 
85  const struct DelimitData *delimit_data)
86 {
87  int cd_loop_offset;
88  for (cd_loop_offset = delimit_data->cd_loop_offset;
89  cd_loop_offset < delimit_data->cd_loop_offset_end;
90  cd_loop_offset += delimit_data->cd_loop_size) {
91  if (BM_edge_is_contiguous_loop_cd(e, delimit_data->cd_loop_type, cd_loop_offset) == false) {
92  return false;
93  }
94  }
95 
96  return true;
97 }
98 
99 static bool bm_edge_is_delimiter(const BMEdge *e,
100  const BMO_Delimit delimit,
101  const struct DelimitData *delimit_data)
102 {
103  /* Caller must ensure. */
105 
106  if (delimit != 0) {
107  if (delimit & BMO_DELIM_SEAM) {
109  return true;
110  }
111  }
112  if (delimit & BMO_DELIM_SHARP) {
113  if (BM_elem_flag_test(e, BM_ELEM_SMOOTH) == 0) {
114  return true;
115  }
116  }
117  if (delimit & BMO_DELIM_MATERIAL) {
118  if (e->l->f->mat_nr != e->l->radial_next->f->mat_nr) {
119  return true;
120  }
121  }
122  if (delimit & BMO_DELIM_NORMAL) {
123  if (!BM_edge_is_contiguous(e)) {
124  return true;
125  }
126  }
127  if (delimit & BMO_DELIM_UV) {
128  if (bm_edge_is_contiguous_loop_cd_all(e, delimit_data) == 0) {
129  return true;
130  }
131  }
132  }
133 
134  return false;
135 }
136 
137 static bool bm_vert_is_delimiter(const BMVert *v,
138  const BMO_Delimit delimit,
139  const struct DelimitData *delimit_data)
140 {
141  BLI_assert(v->e != NULL);
142 
143  if (delimit != 0) {
144  const BMEdge *e, *e_first;
145  e = e_first = v->e;
146  do {
147  if (BM_edge_is_manifold(e)) {
148  if (bm_edge_is_delimiter(e, delimit, delimit_data)) {
149  return true;
150  }
151  }
152  } while ((e = BM_DISK_EDGE_NEXT(e, v)) != e_first);
153  }
154  return false;
155 }
156 
158  const BMO_Delimit delimit,
159  const struct DelimitData *delimit_data)
160 {
161  if (BM_edge_is_manifold(e) && !bm_edge_is_delimiter(e, delimit, delimit_data)) {
162  float angle_cos_neg = dot_v3v3(e->l->f->no, e->l->radial_next->f->no);
163  if (BM_edge_is_contiguous(e)) {
164  angle_cos_neg *= -1;
165  }
166  return angle_cos_neg;
167  }
168 
169  return COST_INVALID;
170 }
171 
172 #ifdef USE_DEGENERATE_CHECK
173 
174 static void mul_v2_m3v3_center(float r[2],
175  const float m[3][3],
176  const float a[3],
177  const float center[3])
178 {
179  BLI_assert(r != a);
180  BLI_assert(r != center);
181 
182  float co[3];
183  sub_v3_v3v3(co, a, center);
184 
185  r[0] = m[0][0] * co[0] + m[1][0] * co[1] + m[2][0] * co[2];
186  r[1] = m[0][1] * co[0] + m[1][1] * co[1] + m[2][1] * co[2];
187 }
188 
190 {
191  /* Calculate relative to the central vertex for higher precision. */
192  const float *center = l_ear->v->co;
193 
194  float tri_2d[3][2];
195  float axis_mat[3][3];
196 
197  axis_dominant_v3_to_m3(axis_mat, l_ear->f->no);
198 
199  {
200  mul_v2_m3v3_center(tri_2d[0], axis_mat, l_ear->prev->v->co, center);
201 # if 0
202  mul_v2_m3v3_center(tri_2d[1], axis_mat, l_ear->v->co, center);
203 # else
204  zero_v2(tri_2d[1]);
205 # endif
206  mul_v2_m3v3_center(tri_2d[2], axis_mat, l_ear->next->v->co, center);
207  }
208 
209  /* check we're not flipping face corners before or after the ear */
210  {
211  float adjacent_2d[2];
212 
213  if (!BM_vert_is_edge_pair(l_ear->prev->v)) {
214  mul_v2_m3v3_center(adjacent_2d, axis_mat, l_ear->prev->prev->v->co, center);
215  if (signum_i(cross_tri_v2(adjacent_2d, tri_2d[0], tri_2d[1])) !=
216  signum_i(cross_tri_v2(adjacent_2d, tri_2d[0], tri_2d[2]))) {
217  return true;
218  }
219  }
220 
221  if (!BM_vert_is_edge_pair(l_ear->next->v)) {
222  mul_v2_m3v3_center(adjacent_2d, axis_mat, l_ear->next->next->v->co, center);
223  if (signum_i(cross_tri_v2(adjacent_2d, tri_2d[2], tri_2d[1])) !=
224  signum_i(cross_tri_v2(adjacent_2d, tri_2d[2], tri_2d[0]))) {
225  return true;
226  }
227  }
228  }
229 
230  /* check no existing verts are inside the triangle */
231  {
232  /* triangle may be concave, if so - flip so we can use clockwise check */
233  if (cross_tri_v2(UNPACK3(tri_2d)) < 0.0f) {
234  swap_v2_v2(tri_2d[1], tri_2d[2]);
235  }
236 
237  /* skip l_ear and adjacent verts */
238  BMLoop *l_iter, *l_first;
239 
240  l_iter = l_ear->next->next;
241  l_first = l_ear->prev;
242  do {
243  float co_2d[2];
244  mul_v2_m3v3_center(co_2d, axis_mat, l_iter->v->co, center);
245  if (isect_point_tri_v2_cw(co_2d, tri_2d[0], tri_2d[1], tri_2d[2])) {
246  return true;
247  }
248  } while ((l_iter = l_iter->next) != l_first);
249  }
250 
251  return false;
252 }
253 
255 {
256  BMEdge *e_pair[2];
257  BMVert *v_pair[2];
258 
259  if (BM_vert_edge_pair(v, &e_pair[0], &e_pair[1])) {
260 
261  /* allow wire edges */
262  if (BM_edge_is_wire(e_pair[0]) || BM_edge_is_wire(e_pair[1])) {
263  return false;
264  }
265 
266  v_pair[0] = BM_edge_other_vert(e_pair[0], v);
267  v_pair[1] = BM_edge_other_vert(e_pair[1], v);
268 
269  if (fabsf(cos_v3v3v3(v_pair[0]->co, v->co, v_pair[1]->co)) < (1.0f - FLT_EPSILON)) {
270  BMLoop *l_iter, *l_first;
271  l_iter = l_first = e_pair[1]->l;
272  do {
273  if (l_iter->f->len > 3) {
274  BMLoop *l_pivot = (l_iter->v == v ? l_iter : l_iter->next);
275  BLI_assert(v == l_pivot->v);
276  if (bm_loop_collapse_is_degenerate(l_pivot)) {
277  return true;
278  }
279  }
280  } while ((l_iter = l_iter->radial_next) != l_first);
281  }
282  return false;
283  }
284  return true;
285 }
286 #endif /* USE_DEGENERATE_CHECK */
287 
289  const float angle_limit,
290  const bool do_dissolve_boundaries,
291  BMO_Delimit delimit,
292  BMVert **vinput_arr,
293  const int vinput_len,
294  BMEdge **einput_arr,
295  const int einput_len,
296  const short oflag_out)
297 {
298  const float angle_limit_cos_neg = -cosf(angle_limit);
299  struct DelimitData delimit_data = {0};
300  const int eheap_table_len = do_dissolve_boundaries ? einput_len : max_ii(einput_len, vinput_len);
301  void *_heap_table = MEM_mallocN(sizeof(HeapNode *) * eheap_table_len, __func__);
302 
303  int i;
304 
305  if (delimit & BMO_DELIM_UV) {
306  const int layer_len = CustomData_number_of_layers(&bm->ldata, CD_MLOOPUV);
307  if (layer_len == 0) {
308  delimit &= ~BMO_DELIM_UV;
309  }
310  else {
311  delimit_data.cd_loop_type = CD_MLOOPUV;
312  delimit_data.cd_loop_size = CustomData_sizeof(delimit_data.cd_loop_type);
314  delimit_data.cd_loop_offset_end = delimit_data.cd_loop_size * layer_len;
315  }
316  }
317 
318  /* --- first edges --- */
319  if (1) {
320  BMEdge **earray;
321  Heap *eheap;
322  HeapNode **eheap_table = _heap_table;
323  HeapNode *enode_top;
324  int *vert_reverse_lookup;
325  BMIter iter;
326  BMEdge *e_iter;
327 
328  /* --- setup heap --- */
329  eheap = BLI_heap_new_ex(einput_len);
330 
331  /* wire -> tag */
332  BM_ITER_MESH (e_iter, &iter, bm, BM_EDGES_OF_MESH) {
333  BM_elem_flag_set(e_iter, BM_ELEM_TAG, BM_edge_is_wire(e_iter));
334  BM_elem_index_set(e_iter, -1); /* set dirty */
335  }
337 
338  /* build heap */
339  for (i = 0; i < einput_len; i++) {
340  BMEdge *e = einput_arr[i];
341  const float cost = bm_edge_calc_dissolve_error(e, delimit, &delimit_data);
342  eheap_table[i] = BLI_heap_insert(eheap, cost, e);
343  BM_elem_index_set(e, i); /* set dirty */
344  }
345 
346  while ((BLI_heap_is_empty(eheap) == false) &&
347  (BLI_heap_node_value((enode_top = BLI_heap_top(eheap))) < angle_limit_cos_neg)) {
348  BMFace *f_new = NULL;
349  BMEdge *e;
350 
351  e = BLI_heap_node_ptr(enode_top);
352  i = BM_elem_index_get(e);
353 
354  if (BM_edge_is_manifold(e)) {
355  f_new = BM_faces_join_pair(bm, e->l, e->l->radial_next, false);
356 
357  if (f_new) {
358  BMLoop *l_first, *l_iter;
359 
360  BLI_heap_remove(eheap, enode_top);
361  eheap_table[i] = NULL;
362 
363  /* update normal */
364  BM_face_normal_update(f_new);
365  if (oflag_out) {
366  BMO_face_flag_enable(bm, f_new, oflag_out);
367  }
368 
369  /* re-calculate costs */
370  l_iter = l_first = BM_FACE_FIRST_LOOP(f_new);
371  do {
372  const int j = BM_elem_index_get(l_iter->e);
373  if (j != -1 && eheap_table[j]) {
374  const float cost = bm_edge_calc_dissolve_error(l_iter->e, delimit, &delimit_data);
375  BLI_heap_node_value_update(eheap, eheap_table[j], cost);
376  }
377  } while ((l_iter = l_iter->next) != l_first);
378  }
379  else {
381  }
382  }
383 
384  if (UNLIKELY(f_new == NULL)) {
385  BLI_heap_node_value_update(eheap, enode_top, COST_INVALID);
386  }
387  }
388 
389  /* prepare for cleanup */
391  vert_reverse_lookup = MEM_mallocN(sizeof(int) * bm->totvert, __func__);
392  copy_vn_i(vert_reverse_lookup, bm->totvert, -1);
393  for (i = 0; i < vinput_len; i++) {
394  BMVert *v = vinput_arr[i];
395  vert_reverse_lookup[BM_elem_index_get(v)] = i;
396  }
397 
398  /* --- cleanup --- */
399  earray = MEM_mallocN(sizeof(BMEdge *) * bm->totedge, __func__);
400  BM_ITER_MESH_INDEX (e_iter, &iter, bm, BM_EDGES_OF_MESH, i) {
401  earray[i] = e_iter;
402  }
403  /* Remove all edges/verts left behind from dissolving,
404  * NULL'ing the vertex array so we don't re-use. */
405  for (i = bm->totedge - 1; i != -1; i--) {
406  e_iter = earray[i];
407 
408  if (BM_edge_is_wire(e_iter) && (BM_elem_flag_test(e_iter, BM_ELEM_TAG) == false)) {
409  /* edge has become wire */
410  int vidx_reverse;
411  BMVert *v1 = e_iter->v1;
412  BMVert *v2 = e_iter->v2;
413  BM_edge_kill(bm, e_iter);
414  if (v1->e == NULL) {
415  vidx_reverse = vert_reverse_lookup[BM_elem_index_get(v1)];
416  if (vidx_reverse != -1) {
417  vinput_arr[vidx_reverse] = NULL;
418  }
419  BM_vert_kill(bm, v1);
420  }
421  if (v2->e == NULL) {
422  vidx_reverse = vert_reverse_lookup[BM_elem_index_get(v2)];
423  if (vidx_reverse != -1) {
424  vinput_arr[vidx_reverse] = NULL;
425  }
426  BM_vert_kill(bm, v2);
427  }
428  }
429  }
430  MEM_freeN(vert_reverse_lookup);
431  MEM_freeN(earray);
432 
433  BLI_heap_free(eheap, NULL);
434  }
435 
436  /* --- second verts --- */
437  if (do_dissolve_boundaries) {
438  /* simple version of the branch below, since we will dissolve _all_ verts that use 2 edges */
439  for (i = 0; i < vinput_len; i++) {
440  BMVert *v = vinput_arr[i];
441  if (LIKELY(v != NULL) && BM_vert_is_edge_pair(v)) {
442  BM_vert_collapse_edge(bm, v->e, v, true, true, true); /* join edges */
443  }
444  }
445  }
446  else {
447  Heap *vheap;
448  HeapNode **vheap_table = _heap_table;
449  HeapNode *vnode_top;
450 
451  BMVert *v_iter;
452  BMIter iter;
453 
454  BM_ITER_MESH (v_iter, &iter, bm, BM_VERTS_OF_MESH) {
455  BM_elem_index_set(v_iter, -1); /* set dirty */
456  }
458 
459  vheap = BLI_heap_new_ex(vinput_len);
460 
461  for (i = 0; i < vinput_len; i++) {
462  BMVert *v = vinput_arr[i];
463  if (LIKELY(v != NULL)) {
464  const float cost = bm_vert_edge_face_angle(v, delimit, &delimit_data);
465  vheap_table[i] = BLI_heap_insert(vheap, cost, v);
466  BM_elem_index_set(v, i); /* set dirty */
467  }
468  }
469 
470  while ((BLI_heap_is_empty(vheap) == false) &&
471  (BLI_heap_node_value((vnode_top = BLI_heap_top(vheap))) < angle_limit)) {
472  BMEdge *e_new = NULL;
473  BMVert *v;
474 
475  v = BLI_heap_node_ptr(vnode_top);
476  i = BM_elem_index_get(v);
477 
478  if (
481 #else
483 #endif
484  ) {
485  e_new = BM_vert_collapse_edge(bm, v->e, v, true, true, true); /* join edges */
486 
487  if (e_new) {
488 
489  BLI_heap_remove(vheap, vnode_top);
490  vheap_table[i] = NULL;
491 
492  /* update normal */
493  if (e_new->l) {
494  BMLoop *l_first, *l_iter;
495  l_iter = l_first = e_new->l;
496  do {
497  BM_face_normal_update(l_iter->f);
498  } while ((l_iter = l_iter->radial_next) != l_first);
499  }
500 
501  /* re-calculate costs */
502  BM_ITER_ELEM (v_iter, &iter, e_new, BM_VERTS_OF_EDGE) {
503  const int j = BM_elem_index_get(v_iter);
504  if (j != -1 && vheap_table[j]) {
505  const float cost = bm_vert_edge_face_angle(v_iter, delimit, &delimit_data);
506  BLI_heap_node_value_update(vheap, vheap_table[j], cost);
507  }
508  }
509 
510 #ifdef USE_DEGENERATE_CHECK
511  /* dissolving a vertex may mean vertices we previously weren't able to dissolve
512  * can now be re-evaluated. */
513  if (e_new->l) {
514  BMLoop *l_first, *l_iter;
515  l_iter = l_first = e_new->l;
516  do {
517  /* skip vertices part of this edge, evaluated above */
518  BMLoop *l_cycle_first, *l_cycle_iter;
519  l_cycle_iter = l_iter->next->next;
520  l_cycle_first = l_iter->prev;
521  do {
522  const int j = BM_elem_index_get(l_cycle_iter->v);
523  if (j != -1 && vheap_table[j] &&
524  (BLI_heap_node_value(vheap_table[j]) == COST_INVALID)) {
525  const float cost = bm_vert_edge_face_angle(
526  l_cycle_iter->v, delimit, &delimit_data);
527  BLI_heap_node_value_update(vheap, vheap_table[j], cost);
528  }
529  } while ((l_cycle_iter = l_cycle_iter->next) != l_cycle_first);
530 
531  } while ((l_iter = l_iter->radial_next) != l_first);
532  }
533 #endif /* USE_DEGENERATE_CHECK */
534  }
535  }
536 
537  if (UNLIKELY(e_new == NULL)) {
538  BLI_heap_node_value_update(vheap, vnode_top, COST_INVALID);
539  }
540  }
541 
542  BLI_heap_free(vheap, NULL);
543  }
544 
545  MEM_freeN(_heap_table);
546 }
547 
549  const float angle_limit,
550  const bool do_dissolve_boundaries,
551  const BMO_Delimit delimit)
552 {
553  int vinput_len;
554  int einput_len;
555 
556  BMVert **vinput_arr = BM_iter_as_arrayN(bm, BM_VERTS_OF_MESH, NULL, &vinput_len, NULL, 0);
557  BMEdge **einput_arr = BM_iter_as_arrayN(bm, BM_EDGES_OF_MESH, NULL, &einput_len, NULL, 0);
558 
560  angle_limit,
561  do_dissolve_boundaries,
562  delimit,
563  vinput_arr,
564  vinput_len,
565  einput_arr,
566  einput_len,
567  0);
568 
569  MEM_freeN(vinput_arr);
570  MEM_freeN(einput_arr);
571 }
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.c:4277
int CustomData_get_n_offset(const struct CustomData *data, int type, int n)
#define BLI_assert(a)
Definition: BLI_assert.h:58
A min-heap / priority queue ADT.
void BLI_heap_free(Heap *heap, HeapFreeFP ptrfreefp) ATTR_NONNULL(1)
Definition: BLI_heap.c:221
Heap * BLI_heap_new_ex(unsigned int tot_reserve) ATTR_WARN_UNUSED_RESULT
Definition: BLI_heap.c:201
void void float BLI_heap_node_value(const HeapNode *heap) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
Definition: BLI_heap.c:399
void void bool BLI_heap_is_empty(const Heap *heap) ATTR_NONNULL(1)
Definition: BLI_heap.c:305
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:268
void * BLI_heap_node_ptr(const HeapNode *heap) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
Definition: BLI_heap.c:404
HeapNode * BLI_heap_top(const Heap *heap) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
Definition: BLI_heap.c:319
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:1579
void axis_dominant_v3_to_m3(float r_mat[3][3], const float normal[3])
Normal to x,y matrix.
Definition: math_geom.c:3752
void copy_vn_i(int *array_tar, const int size, const int val)
Definition: math_vector.c:1374
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:430
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
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:556
@ 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
#define BM_FACE_FIRST_LOOP(p)
Definition: bmesh_class.h:553
void BM_vert_kill(BMesh *bm, BMVert *v)
Definition: bmesh_core.c:1002
void BM_edge_kill(BMesh *bm, BMEdge *e)
Definition: bmesh_core.c:987
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
void BMO_error_clear(BMesh *bm)
#define BM_elem_index_get(ele)
Definition: bmesh_inline.h:124
#define BM_elem_flag_set(ele, hflag, val)
Definition: bmesh_inline.h:30
#define BM_elem_index_set(ele, index)
Definition: bmesh_inline.h:125
#define BM_elem_flag_test(ele, hflag)
Definition: bmesh_inline.h:26
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.c:2152
BMFace * BM_faces_join_pair(BMesh *bm, BMLoop *l_a, BMLoop *l_b, const bool do_del)
Faces Join Pair.
Definition: bmesh_mods.c:221
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:523
#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:1841
bool BM_edge_is_contiguous_loop_cd(const BMEdge *e, const int cd_loop_type, const int cd_loop_offset)
Definition: bmesh_query.c:1127
float BM_edge_calc_face_angle(const BMEdge *e)
Definition: bmesh_query.c:1728
bool BM_vert_edge_pair(BMVert *v, BMEdge **r_e_a, BMEdge **r_e_b)
Definition: bmesh_query.c:802
bool BM_vert_is_edge_pair(const BMVert *v)
Definition: bmesh_query.c:771
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)
#define fabsf(x)
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:41
void *(* MEM_mallocN)(size_t len, const char *str)
Definition: mallocn.c:47
static unsigned a[3]
Definition: RandGen.cpp:92
BMVert * v1
Definition: bmesh_class.h:134
BMVert * v2
Definition: bmesh_class.h:134
struct BMLoop * l
Definition: bmesh_class.h:140
int len
Definition: bmesh_class.h:279
float no[3]
Definition: bmesh_class.h:280
struct BMVert * v
Definition: bmesh_class.h:165
struct BMEdge * e
Definition: bmesh_class.h:176
struct BMLoop * radial_next
Definition: bmesh_class.h:216
struct BMLoop * prev
Definition: bmesh_class.h:245
struct BMFace * f
Definition: bmesh_class.h:183
struct BMLoop * next
Definition: bmesh_class.h:245
float co[3]
Definition: bmesh_class.h:99
struct BMEdge * e
Definition: bmesh_class.h:109
float no[3]
Definition: bmesh_class.h:100
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:57