Blender  V3.3
bmo_hull.c
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2 
9 #ifdef WITH_BULLET
10 
11 # include "MEM_guardedalloc.h"
12 
13 # include "BLI_array.h"
14 # include "BLI_listbase.h"
15 # include "BLI_math.h"
16 
17 # include "RBI_hull_api.h"
18 
19 /* XXX: using 128 for totelem and `pchunk` of `mempool`, no idea what good
20  * values would be though */
21 
22 # include "bmesh.h"
23 
24 # include "intern/bmesh_operators_private.h" /* own include */
25 
26 /* Internal operator flags */
27 typedef enum {
28  HULL_FLAG_INPUT = (1 << 0),
29 
30  HULL_FLAG_INTERIOR_ELE = (1 << 1),
31  HULL_FLAG_OUTPUT_GEOM = (1 << 2),
32 
33  HULL_FLAG_DEL = (1 << 3),
34  HULL_FLAG_HOLE = (1 << 4),
35 } HullFlags;
36 
37 /* Store hull triangles separate from BMesh faces until the end; this
38  * way we don't have to worry about cleaning up extraneous edges or
39  * incorrectly deleting existing geometry. */
40 typedef struct HullTriangle {
41  BMVert *v[3];
42  float no[3];
43  int skip;
44 } HullTriangle;
45 
46 /*************************** Hull Triangles ***************************/
47 
48 static void hull_add_triangle(
49  BMesh *bm, BLI_mempool *hull_triangles, BMVert *v1, BMVert *v2, BMVert *v3)
50 {
51  HullTriangle *t;
52  int i;
53 
54  t = BLI_mempool_calloc(hull_triangles);
55  t->v[0] = v1;
56  t->v[1] = v2;
57  t->v[2] = v3;
58 
59  /* Mark triangles vertices as not interior */
60  for (i = 0; i < 3; i++) {
61  BMO_vert_flag_disable(bm, t->v[i], HULL_FLAG_INTERIOR_ELE);
62  }
63 
64  normal_tri_v3(t->no, v1->co, v2->co, v3->co);
65 }
66 
67 static BMFace *hull_find_example_face(BMesh *bm, BMEdge *e)
68 {
69  BMIter iter;
70  BMFace *f;
71 
72  BM_ITER_ELEM (f, &iter, e, BM_FACES_OF_EDGE) {
73  if (BMO_face_flag_test(bm, f, HULL_FLAG_INPUT) ||
74  BMO_face_flag_test(bm, f, HULL_FLAG_OUTPUT_GEOM) == false) {
75  return f;
76  }
77  }
78 
79  return NULL;
80 }
81 
82 static void hull_output_triangles(BMesh *bm, BLI_mempool *hull_triangles)
83 {
84  BLI_mempool_iter iter;
85  BLI_mempool_iternew(hull_triangles, &iter);
86  HullTriangle *t;
87 
88  while ((t = BLI_mempool_iterstep(&iter))) {
89  int i;
90 
91  if (!t->skip) {
92  BMEdge *edges[3] = {
93  BM_edge_create(bm, t->v[0], t->v[1], NULL, BM_CREATE_NO_DOUBLE),
94  BM_edge_create(bm, t->v[1], t->v[2], NULL, BM_CREATE_NO_DOUBLE),
95  BM_edge_create(bm, t->v[2], t->v[0], NULL, BM_CREATE_NO_DOUBLE),
96  };
97  BMFace *f, *example = NULL;
98 
99  f = BM_face_exists(t->v, 3);
100  if (f != NULL) {
101  /* If the operator is run with "use_existing_faces"
102  * disabled, but an output face in the hull is the
103  * same as a face in the existing mesh, it should not
104  * be marked as unused or interior. */
105  BMO_face_flag_enable(bm, f, HULL_FLAG_OUTPUT_GEOM);
106  BMO_face_flag_disable(bm, f, HULL_FLAG_HOLE);
107  BMO_face_flag_disable(bm, f, HULL_FLAG_INTERIOR_ELE);
108  }
109  else {
110  /* Look for an adjacent face that existed before the hull */
111  for (i = 0; i < 3; i++) {
112  if (!example) {
113  example = hull_find_example_face(bm, edges[i]);
114  }
115  }
116 
117  /* Create new hull face */
118  f = BM_face_create_verts(bm, t->v, 3, example, BM_CREATE_NO_DOUBLE, true);
120  }
121  /* Mark face for 'geom.out' slot and select */
122  BMO_face_flag_enable(bm, f, HULL_FLAG_OUTPUT_GEOM);
123  BM_face_select_set(bm, f, true);
124 
125  /* Mark edges for 'geom.out' slot */
126  for (i = 0; i < 3; i++) {
127  BMO_edge_flag_enable(bm, edges[i], HULL_FLAG_OUTPUT_GEOM);
128  }
129  }
130  else {
131  /* Mark input edges for 'geom.out' slot */
132  for (i = 0; i < 3; i++) {
133  const int next = (i == 2 ? 0 : i + 1);
134  BMEdge *e = BM_edge_exists(t->v[i], t->v[next]);
135  if (e && BMO_edge_flag_test(bm, e, HULL_FLAG_INPUT) &&
136  !BMO_edge_flag_test(bm, e, HULL_FLAG_HOLE)) {
137  BMO_edge_flag_enable(bm, e, HULL_FLAG_OUTPUT_GEOM);
138  }
139  }
140  }
141 
142  /* Mark verts for 'geom.out' slot */
143  for (i = 0; i < 3; i++) {
144  BMO_vert_flag_enable(bm, t->v[i], HULL_FLAG_OUTPUT_GEOM);
145  }
146  }
147 }
148 
149 /***************************** Final Edges ****************************/
150 
151 typedef struct {
152  GHash *edges;
153  BLI_mempool *base_pool, *link_pool;
154 } HullFinalEdges;
155 
156 static LinkData *final_edges_find_link(ListBase *adj, BMVert *v)
157 {
158  LinkData *link;
159 
160  for (link = adj->first; link; link = link->next) {
161  if (link->data == v) {
162  return link;
163  }
164  }
165 
166  return NULL;
167 }
168 
169 static int hull_final_edges_lookup(HullFinalEdges *final_edges, BMVert *v1, BMVert *v2)
170 {
171  ListBase *adj;
172 
173  /* Use lower vertex pointer for hash key */
174  if (v1 > v2) {
175  SWAP(BMVert *, v1, v2);
176  }
177 
178  adj = BLI_ghash_lookup(final_edges->edges, v1);
179  if (!adj) {
180  return false;
181  }
182 
183  return !!final_edges_find_link(adj, v2);
184 }
185 
186 /* Used for checking whether a pre-existing edge lies on the hull */
187 static HullFinalEdges *hull_final_edges(BLI_mempool *hull_triangles)
188 {
189  HullFinalEdges *final_edges;
190 
191  final_edges = MEM_callocN(sizeof(HullFinalEdges), "HullFinalEdges");
192  final_edges->edges = BLI_ghash_ptr_new("final edges ghash");
193  final_edges->base_pool = BLI_mempool_create(sizeof(ListBase), 0, 128, BLI_MEMPOOL_NOP);
194  final_edges->link_pool = BLI_mempool_create(sizeof(LinkData), 0, 128, BLI_MEMPOOL_NOP);
195 
196  BLI_mempool_iter iter;
197  BLI_mempool_iternew(hull_triangles, &iter);
198  HullTriangle *t;
199 
200  while ((t = BLI_mempool_iterstep(&iter))) {
201  LinkData *link;
202  int i;
203 
204  for (i = 0; i < 3; i++) {
205  BMVert *v1 = t->v[i];
206  BMVert *v2 = t->v[(i + 1) % 3];
207  ListBase *adj;
208 
209  /* Use lower vertex pointer for hash key */
210  if (v1 > v2) {
211  SWAP(BMVert *, v1, v2);
212  }
213 
214  adj = BLI_ghash_lookup(final_edges->edges, v1);
215  if (!adj) {
216  adj = BLI_mempool_calloc(final_edges->base_pool);
217  BLI_ghash_insert(final_edges->edges, v1, adj);
218  }
219 
220  if (!final_edges_find_link(adj, v2)) {
221  link = BLI_mempool_calloc(final_edges->link_pool);
222  link->data = v2;
223  BLI_addtail(adj, link);
224  }
225  }
226  }
227 
228  return final_edges;
229 }
230 
231 static void hull_final_edges_free(HullFinalEdges *final_edges)
232 {
233  BLI_ghash_free(final_edges->edges, NULL, NULL);
234  BLI_mempool_destroy(final_edges->base_pool);
235  BLI_mempool_destroy(final_edges->link_pool);
236  MEM_freeN(final_edges);
237 }
238 
239 /**************************** Final Output ****************************/
240 
241 static void hull_remove_overlapping(BMesh *bm,
242  BLI_mempool *hull_triangles,
243  HullFinalEdges *final_edges)
244 {
245  BLI_mempool_iter iter;
246  BLI_mempool_iternew(hull_triangles, &iter);
247  HullTriangle *t;
248 
249  while ((t = BLI_mempool_iterstep(&iter))) {
250  BMIter bm_iter1, bm_iter2;
251  BMFace *f;
252  bool f_on_hull;
253 
254  BM_ITER_ELEM (f, &bm_iter1, t->v[0], BM_FACES_OF_VERT) {
255  BMEdge *e;
256 
257  /* Check that all the face's edges are on the hull,
258  * otherwise can't reuse it */
259  f_on_hull = true;
260  BM_ITER_ELEM (e, &bm_iter2, f, BM_EDGES_OF_FACE) {
261  if (!hull_final_edges_lookup(final_edges, e->v1, e->v2)) {
262  f_on_hull = false;
263  break;
264  }
265  }
266 
267  /* NOTE: can't change ghash while iterating, so mark
268  * with 'skip' flag rather than deleting triangles */
269  if (BM_vert_in_face(t->v[1], f) && BM_vert_in_face(t->v[2], f) && f_on_hull) {
270  t->skip = true;
271  BMO_face_flag_disable(bm, f, HULL_FLAG_INTERIOR_ELE);
272  BMO_face_flag_enable(bm, f, HULL_FLAG_HOLE);
273  }
274  }
275  }
276 }
277 
278 static void hull_mark_interior_elements(BMesh *bm, BMOperator *op, HullFinalEdges *final_edges)
279 {
280  BMEdge *e;
281  BMFace *f;
282  BMOIter oiter;
283 
284  /* Check for interior edges too */
285  BMO_ITER (e, &oiter, op->slots_in, "input", BM_EDGE) {
286  if (!hull_final_edges_lookup(final_edges, e->v1, e->v2)) {
287  BMO_edge_flag_enable(bm, e, HULL_FLAG_INTERIOR_ELE);
288  }
289  }
290 
291  /* Mark all input faces as interior, some may be unmarked in
292  * hull_remove_overlapping() */
293  BMO_ITER (f, &oiter, op->slots_in, "input", BM_FACE) {
294  BMO_face_flag_enable(bm, f, HULL_FLAG_INTERIOR_ELE);
295  }
296 }
297 
298 static void hull_tag_unused(BMesh *bm, BMOperator *op)
299 {
300  BMIter iter;
301  BMOIter oiter;
302  BMVert *v;
303  BMEdge *e;
304  BMFace *f;
305 
306  /* Mark vertices, edges, and faces that are already marked
307  * interior (i.e. were already part of the input, but not part of
308  * the hull), but that aren't also used by elements outside the
309  * input set */
310  BMO_ITER (v, &oiter, op->slots_in, "input", BM_VERT) {
311  if (BMO_vert_flag_test(bm, v, HULL_FLAG_INTERIOR_ELE)) {
312  bool del = true;
313 
314  BM_ITER_ELEM (e, &iter, v, BM_EDGES_OF_VERT) {
315  if (!BMO_edge_flag_test(bm, e, HULL_FLAG_INPUT)) {
316  del = false;
317  break;
318  }
319  }
320 
321  BM_ITER_ELEM (f, &iter, v, BM_FACES_OF_VERT) {
322  if (!BMO_face_flag_test(bm, f, HULL_FLAG_INPUT)) {
323  del = false;
324  break;
325  }
326  }
327 
328  if (del) {
329  BMO_vert_flag_enable(bm, v, HULL_FLAG_DEL);
330  }
331  }
332  }
333 
334  BMO_ITER (e, &oiter, op->slots_in, "input", BM_EDGE) {
335  if (BMO_edge_flag_test(bm, e, HULL_FLAG_INTERIOR_ELE)) {
336  bool del = true;
337 
338  BM_ITER_ELEM (f, &iter, e, BM_FACES_OF_EDGE) {
339  if (!BMO_face_flag_test(bm, f, HULL_FLAG_INPUT)) {
340  del = false;
341  break;
342  }
343  }
344 
345  if (del) {
346  BMO_edge_flag_enable(bm, e, HULL_FLAG_DEL);
347  }
348  }
349  }
350 
351  BMO_ITER (f, &oiter, op->slots_in, "input", BM_FACE) {
352  if (BMO_face_flag_test(bm, f, HULL_FLAG_INTERIOR_ELE)) {
353  BMO_face_flag_enable(bm, f, HULL_FLAG_DEL);
354  }
355  }
356 }
357 
358 static void hull_tag_holes(BMesh *bm, BMOperator *op)
359 {
360  BMIter iter;
361  BMOIter oiter;
362  BMFace *f;
363  BMEdge *e;
364 
365  /* Unmark any hole faces if they are isolated or part of a
366  * border */
367  BMO_ITER (f, &oiter, op->slots_in, "input", BM_FACE) {
368  if (BMO_face_flag_test(bm, f, HULL_FLAG_HOLE)) {
369  BM_ITER_ELEM (e, &iter, f, BM_EDGES_OF_FACE) {
370  if (BM_edge_is_boundary(e)) {
371  BMO_face_flag_disable(bm, f, HULL_FLAG_HOLE);
372  break;
373  }
374  }
375  }
376  }
377 
378  /* Mark edges too if all adjacent faces are holes and the edge is
379  * not already isolated */
380  BMO_ITER (e, &oiter, op->slots_in, "input", BM_EDGE) {
381  bool hole = true;
382  bool any_faces = false;
383 
384  BM_ITER_ELEM (f, &iter, e, BM_FACES_OF_EDGE) {
385  any_faces = true;
386  if (!BMO_face_flag_test(bm, f, HULL_FLAG_HOLE)) {
387  hole = false;
388  break;
389  }
390  }
391 
392  if (hole && any_faces) {
393  BMO_edge_flag_enable(bm, e, HULL_FLAG_HOLE);
394  }
395  }
396 }
397 
398 static int hull_input_vert_count(BMOperator *op)
399 {
400  BMOIter oiter;
401  BMVert *v;
402  int count = 0;
403 
404  BMO_ITER (v, &oiter, op->slots_in, "input", BM_VERT) {
405  count++;
406  }
407 
408  return count;
409 }
410 
411 static BMVert **hull_input_verts_copy(BMOperator *op, const int num_input_verts)
412 {
413  BMOIter oiter;
414  BMVert *v;
415  BMVert **input_verts = MEM_callocN(sizeof(*input_verts) * num_input_verts, AT);
416  int i = 0;
417 
418  BMO_ITER (v, &oiter, op->slots_in, "input", BM_VERT) {
419  input_verts[i++] = v;
420  }
421 
422  return input_verts;
423 }
424 
425 static float (*hull_verts_for_bullet(BMVert **input_verts, const int num_input_verts))[3]
426 {
427  float(*coords)[3] = MEM_callocN(sizeof(*coords) * num_input_verts, __func__);
428  int i;
429 
430  for (i = 0; i < num_input_verts; i++) {
431  copy_v3_v3(coords[i], input_verts[i]->co);
432  }
433 
434  return coords;
435 }
436 
437 static BMVert **hull_verts_from_bullet(plConvexHull hull,
438  BMVert **input_verts,
439  const int num_input_verts)
440 {
441  const int num_verts = plConvexHullNumVertices(hull);
442  BMVert **hull_verts = MEM_mallocN(sizeof(*hull_verts) * num_verts, AT);
443  int i;
444 
445  for (i = 0; i < num_verts; i++) {
446  float co[3];
447  int original_index;
448  plConvexHullGetVertex(hull, i, co, &original_index);
449 
450  if (original_index >= 0 && original_index < num_input_verts) {
451  hull_verts[i] = input_verts[original_index];
452  }
453  else {
454  BLI_assert_msg(0, "Unexpected new vertex in hull output");
455  }
456  }
457 
458  return hull_verts;
459 }
460 
461 static void hull_from_bullet(BMesh *bm, BMOperator *op, BLI_mempool *hull_triangles)
462 {
463  int *fvi = NULL;
464  BLI_array_declare(fvi);
465 
466  BMVert **input_verts;
467  float(*coords)[3];
468  BMVert **hull_verts;
469 
470  plConvexHull hull;
471  int i, count = 0;
472 
473  const int num_input_verts = hull_input_vert_count(op);
474 
475  input_verts = hull_input_verts_copy(op, num_input_verts);
476  coords = hull_verts_for_bullet(input_verts, num_input_verts);
477 
478  hull = plConvexHullCompute(coords, num_input_verts);
479  hull_verts = hull_verts_from_bullet(hull, input_verts, num_input_verts);
480 
481  count = plConvexHullNumFaces(hull);
482  for (i = 0; i < count; i++) {
483  const int len = plConvexHullGetFaceSize(hull, i);
484 
485  if (len > 2) {
486  BMVert *fv[3];
487  int j;
488 
489  /* Get face vertex indices */
490  BLI_array_clear(fvi);
492  plConvexHullGetFaceVertices(hull, i, fvi);
493 
494  /* NOTE: here we throw away any NGons from Bullet and turn
495  * them into triangle fans. Would be nice to use these
496  * directly, but will have to wait until HullTriangle goes
497  * away (TODO) */
498  fv[0] = hull_verts[fvi[0]];
499  for (j = 2; j < len; j++) {
500  fv[1] = hull_verts[fvi[j - 1]];
501  fv[2] = hull_verts[fvi[j]];
502 
503  hull_add_triangle(bm, hull_triangles, fv[0], fv[1], fv[2]);
504  }
505  }
506  }
507 
508  BLI_array_free(fvi);
509 
510  plConvexHullDelete(hull);
511 
512  MEM_freeN(hull_verts);
513  MEM_freeN(coords);
514  MEM_freeN(input_verts);
515 }
516 
517 /* Check that there are at least three vertices in the input */
518 static bool hull_num_input_verts_is_ok(BMOperator *op)
519 {
520  BMOIter oiter;
521  BMVert *v;
522  int partial_num_verts = 0;
523 
524  BMO_ITER (v, &oiter, op->slots_in, "input", BM_VERT) {
525  partial_num_verts++;
526  if (partial_num_verts >= 3) {
527  break;
528  }
529  }
530 
531  return (partial_num_verts >= 3);
532 }
533 
535 {
536  HullFinalEdges *final_edges;
537  BLI_mempool *hull_triangles;
538  BMElemF *ele;
539  BMOIter oiter;
540 
541  /* Verify that at least three verts in the input */
542  if (!hull_num_input_verts_is_ok(op)) {
543  BMO_error_raise(bm, op, BMO_ERROR_CANCEL, "Requires at least three vertices");
544  return;
545  }
546 
547  /* Tag input elements */
548  BMO_ITER (ele, &oiter, op->slots_in, "input", BM_ALL) {
549 
550  /* Mark all vertices as interior to begin with */
551  if (ele->head.htype == BM_VERT) {
552  BMO_vert_flag_enable(bm, (BMVert *)ele, HULL_FLAG_INPUT | HULL_FLAG_INTERIOR_ELE);
553  }
554  else if (ele->head.htype == BM_EDGE) {
555  BMO_edge_flag_enable(bm, (BMEdge *)ele, HULL_FLAG_INPUT);
556  }
557  else {
558  BMO_face_flag_enable(bm, (BMFace *)ele, HULL_FLAG_INPUT);
559  }
560  }
561 
562  hull_triangles = BLI_mempool_create(sizeof(HullTriangle), 0, 128, BLI_MEMPOOL_ALLOW_ITER);
563 
564  hull_from_bullet(bm, op, hull_triangles);
565 
566  final_edges = hull_final_edges(hull_triangles);
567 
568  hull_mark_interior_elements(bm, op, final_edges);
569 
570  /* Remove hull triangles covered by an existing face */
571  if (BMO_slot_bool_get(op->slots_in, "use_existing_faces")) {
572  hull_remove_overlapping(bm, hull_triangles, final_edges);
573 
574  hull_tag_holes(bm, op);
575  }
576 
577  /* Done with edges */
578  hull_final_edges_free(final_edges);
579 
580  /* Convert hull triangles to BMesh faces */
581  hull_output_triangles(bm, hull_triangles);
582  BLI_mempool_destroy(hull_triangles);
583 
584  hull_tag_unused(bm, op);
585 
586  /* Output slot of input elements that ended up inside the hull
587  * rather than part of it */
589  bm, op, op->slots_out, "geom_interior.out", BM_ALL_NOLOOP, HULL_FLAG_INTERIOR_ELE);
590 
591  /* Output slot of input elements that ended up inside the hull and
592  * are unused by other geometry. */
594  bm, op, op->slots_out, "geom_unused.out", BM_ALL_NOLOOP, HULL_FLAG_DEL);
595 
596  /* Output slot of faces and edges that were in the input and on
597  * the hull (useful for cases like bridging where you want to
598  * delete some input geometry) */
600  bm, op, op->slots_out, "geom_holes.out", BM_ALL_NOLOOP, HULL_FLAG_HOLE);
601 
602  /* Output slot of all hull vertices, faces, and edges */
604  bm, op, op->slots_out, "geom.out", BM_ALL_NOLOOP, HULL_FLAG_OUTPUT_GEOM);
605 }
606 
607 #endif /* WITH_BULLET */
typedef float(TangentPoint)[2]
A (mainly) macro array library.
#define BLI_array_grow_items(arr, num)
Definition: BLI_array.h:91
#define BLI_array_declare(arr)
Definition: BLI_array.h:50
#define BLI_array_clear(arr)
Definition: BLI_array.h:128
#define BLI_array_free(arr)
Definition: BLI_array.h:113
#define BLI_assert_msg(a, msg)
Definition: BLI_assert.h:53
void * BLI_ghash_lookup(const GHash *gh, const void *key) ATTR_WARN_UNUSED_RESULT
Definition: BLI_ghash.c:734
void BLI_ghash_insert(GHash *gh, void *key, void *val)
Definition: BLI_ghash.c:710
void BLI_ghash_free(GHash *gh, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp)
Definition: BLI_ghash.c:863
GHash * BLI_ghash_ptr_new(const char *info) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT
void BLI_addtail(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition: listbase.c:80
float normal_tri_v3(float n[3], const float v1[3], const float v2[3], const float v3[3])
Definition: math_geom.c:33
MINLINE void copy_v3_v3(float r[3], const float a[3])
void BLI_mempool_iternew(BLI_mempool *pool, BLI_mempool_iter *iter) ATTR_NONNULL()
Definition: BLI_mempool.c:498
@ BLI_MEMPOOL_ALLOW_ITER
Definition: BLI_mempool.h:107
@ BLI_MEMPOOL_NOP
Definition: BLI_mempool.h:99
void * BLI_mempool_iterstep(BLI_mempool_iter *iter) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition: BLI_mempool.c:577
BLI_mempool * BLI_mempool_create(unsigned int esize, unsigned int elem_num, unsigned int pchunk, unsigned int flag) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT ATTR_RETURNS_NONNULL
Definition: BLI_mempool.c:253
void BLI_mempool_destroy(BLI_mempool *pool) ATTR_NONNULL(1)
Definition: BLI_mempool.c:707
void * BLI_mempool_calloc(BLI_mempool *pool) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT ATTR_RETURNS_NONNULL ATTR_NONNULL(1)
Definition: BLI_mempool.c:347
#define SWAP(type, a, b)
#define AT
_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 t
_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_ALL_NOLOOP
Definition: bmesh_class.h:411
#define BM_ALL
Definition: bmesh_class.h:410
@ BM_FACE
Definition: bmesh_class.h:386
@ BM_VERT
Definition: bmesh_class.h:383
@ BM_EDGE
Definition: bmesh_class.h:384
void BM_face_copy_shared(BMesh *bm, BMFace *f, BMLoopFilterFunc filter_fn, void *user_data)
copies face loop data from shared adjacent faces.
BMFace * BM_face_create_verts(BMesh *bm, BMVert **vert_arr, const int len, const BMFace *f_example, const eBMCreateFlag create_flag, const bool create_edges)
Definition: bmesh_core.c:464
BMEdge * BM_edge_create(BMesh *bm, BMVert *v1, BMVert *v2, const BMEdge *e_example, const eBMCreateFlag create_flag)
Main function for creating a new edge.
Definition: bmesh_core.c:123
@ BM_CREATE_NO_DOUBLE
Definition: bmesh_core.h:14
@ BMO_ERROR_CANCEL
Definition: bmesh_error.h:21
void BMO_error_raise(BMesh *bm, BMOperator *owner, eBMOpErrorLevel level, const char *msg) ATTR_NONNULL(1
#define BM_ITER_ELEM(ele, iter, data, itype)
@ BM_FACES_OF_EDGE
@ BM_FACES_OF_VERT
@ BM_EDGES_OF_VERT
@ BM_EDGES_OF_FACE
ATTR_WARN_UNUSED_RESULT BMesh * bm
void BM_face_select_set(BMesh *bm, BMFace *f, const bool select)
Select Face.
#define BMO_vert_flag_disable(bm, e, oflag)
#define BMO_edge_flag_test(bm, e, oflag)
#define BMO_edge_flag_enable(bm, e, oflag)
#define BMO_vert_flag_enable(bm, e, oflag)
void BMO_slot_buffer_from_enabled_flag(BMesh *bm, BMOperator *op, BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name, char htype, short oflag)
#define BMO_face_flag_enable(bm, e, oflag)
#define BMO_ITER(ele, iter, slot_args, slot_name, restrict_flag)
#define BMO_vert_flag_test(bm, e, oflag)
#define BMO_face_flag_disable(bm, e, oflag)
#define BMO_face_flag_test(bm, e, oflag)
bool BMO_slot_bool_get(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name)
void bmo_convex_hull_exec(BMesh *bm, BMOperator *op)
BMEdge * BM_edge_exists(BMVert *v_a, BMVert *v_b)
Definition: bmesh_query.c:1553
BMFace * BM_face_exists(BMVert **varr, int len)
Definition: bmesh_query.c:1612
bool BM_vert_in_face(BMVert *v, BMFace *f)
Definition: bmesh_query.c:306
BLI_INLINE bool BM_edge_is_boundary(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
int len
Definition: draw_manager.c:108
int count
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:27
void *(* MEM_callocN)(size_t len, const char *str)
Definition: mallocn.c:31
void *(* MEM_mallocN)(size_t len, const char *str)
Definition: mallocn.c:33
static ulong * next
int plConvexHullGetFaceSize(plConvexHull hull, int n)
void plConvexHullGetVertex(plConvexHull hull, int n, float coords[3], int *original_index)
int plConvexHullNumVertices(plConvexHull hull)
plConvexHull plConvexHullCompute(float(*coords)[3], int count)
void plConvexHullDelete(plConvexHull hull)
int plConvexHullNumFaces(plConvexHull hull)
void plConvexHullGetFaceVertices(plConvexHull hull, int n, int *vertices)
BMHeader head
Definition: bmesh_class.h:238
char htype
Definition: bmesh_class.h:64
struct BMOpSlot slots_out[BMO_OP_MAX_SLOTS]
struct BMOpSlot slots_in[BMO_OP_MAX_SLOTS]
float co[3]
Definition: bmesh_class.h:87
void * data
Definition: DNA_listBase.h:26
struct LinkData * next
Definition: DNA_listBase.h:25
void * first
Definition: DNA_listBase.h:31