Blender  V2.93
bmesh_bisect_plane.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 
30 #include <limits.h>
31 
32 #include "MEM_guardedalloc.h"
33 
34 #include "BLI_alloca.h"
35 #include "BLI_linklist.h"
36 #include "BLI_linklist_stack.h"
37 #include "BLI_math.h"
38 #include "BLI_utildefines.h"
39 #include "BLI_utildefines_stack.h"
40 
41 #include "bmesh.h"
42 #include "bmesh_bisect_plane.h" /* own include */
43 
44 #include "BLI_strict_flags.h" /* keep last */
45 
46 /* -------------------------------------------------------------------- */
47 /* Math utils */
48 
49 static short plane_point_test_v3(const float plane[4],
50  const float co[3],
51  const float eps,
52  float *r_depth)
53 {
54  const float f = plane_point_side_v3(plane, co);
55  *r_depth = f;
56 
57  if (f <= -eps) {
58  return -1;
59  }
60  if (f >= eps) {
61  return 1;
62  }
63  return 0;
64 }
65 
66 /* -------------------------------------------------------------------- */
67 /* Wrappers to hide internal data-structure abuse,
68  * later we may want to move this into some hash lookup
69  * to a separate struct, but for now we can store in BMesh data */
70 
71 #define BM_VERT_DIR(v) ((short *)(&(v)->head.index))[0] /* Direction -1/0/1 */
72 #define BM_VERT_SKIP(v) ((short *)(&(v)->head.index))[1] /* Skip Vert 0/1 */
73 #define BM_VERT_DIST(v) ((v)->no[0]) /* Distance from the plane. */
74 #define BM_VERT_SORTVAL(v) ((v)->no[1]) /* Temp value for sorting. */
75 #define BM_VERT_LOOPINDEX(v) /* The verts index within a face (temp var) */ \
76  (*((uint *)(&(v)->no[2])))
77 
83 /* enable when vertex is in the center and its faces have been added to the stack */
85 {
87 }
89 {
91 }
93 {
94  return (BM_elem_flag_test(v, BM_ELEM_TAG) != 0);
95 }
96 
97 BLI_INLINE bool vert_pair_adjacent_in_orig_face(BMVert *v_a, BMVert *v_b, const uint f_len_orig)
98 {
99  const uint delta = (uint)abs((int)BM_VERT_LOOPINDEX(v_a) - (int)BM_VERT_LOOPINDEX(v_b));
100  return ELEM(delta, 1, (uint)(f_len_orig - 1));
101 }
102 
103 /* enable when the edge can be cut */
105 {
107 }
109 {
111 }
113 {
114  return (BM_elem_flag_test(e, BM_ELEM_TAG) != 0);
115 }
116 
117 /* enable when the faces are added to the stack */
119 {
121 }
123 {
125 }
127 {
128  return (BM_elem_flag_test(f, BM_ELEM_TAG) == 0);
129 }
130 
131 /* -------------------------------------------------------------------- */
132 /* BMesh utils */
133 
134 static int bm_vert_sortval_cb(const void *v_a_v, const void *v_b_v)
135 {
136  const float val_a = BM_VERT_SORTVAL(*((BMVert **)v_a_v));
137  const float val_b = BM_VERT_SORTVAL(*((BMVert **)v_b_v));
138 
139  if (val_a > val_b) {
140  return 1;
141  }
142  if (val_a < val_b) {
143  return -1;
144  }
145  return 0;
146 }
147 
149  BMesh *bm, BMFace *f, const float plane[4], const short oflag_center, const short oflag_new)
150 {
151  /* unlikely more than 2 verts are needed */
152  const uint f_len_orig = (uint)f->len;
153  BMVert **vert_split_arr = BLI_array_alloca(vert_split_arr, f_len_orig);
154  STACK_DECLARE(vert_split_arr);
155  BMLoop *l_iter, *l_first;
156  bool use_dirs[3] = {false, false, false};
157  bool is_inside = false;
158  /* True when the face contains one or more edges with both it's vertices on the plane.
159  * When set, centered loops are walked over to check if they need to be skipped. */
160  bool face_has_center_edge = false;
161 
162  STACK_INIT(vert_split_arr, f_len_orig);
163 
164  l_first = BM_FACE_FIRST_LOOP(f);
165 
166  /* add plane-aligned verts to the stack
167  * and check we have verts from both sides in this face,
168  * ... that the face doesn't only have boundary verts on the plane for eg. */
169  l_iter = l_first;
170  do {
171  if (vert_is_center_test(l_iter->v)) {
172  BLI_assert(BM_VERT_DIR(l_iter->v) == 0);
173 
174  /* if both are -1 or 1, or both are zero:
175  * don't flip 'inside' var while walking */
176  BM_VERT_SKIP(l_iter->v) = (((BM_VERT_DIR(l_iter->prev->v) ^ BM_VERT_DIR(l_iter->next->v))) ==
177  0);
178 
179  STACK_PUSH(vert_split_arr, l_iter->v);
180 
181  if (face_has_center_edge == false) {
182  if (vert_is_center_test(l_iter->prev->v)) {
183  face_has_center_edge = true;
184  }
185  }
186  }
187  use_dirs[BM_VERT_DIR(l_iter->v) + 1] = true;
188  } while ((l_iter = l_iter->next) != l_first);
189 
190  if ((STACK_SIZE(vert_split_arr) > 1) && (use_dirs[0] && use_dirs[2])) {
191  if (LIKELY(STACK_SIZE(vert_split_arr) == 2)) {
192  BMLoop *l_new;
193  BMLoop *l_a, *l_b;
194 
195  l_a = BM_face_vert_share_loop(f, vert_split_arr[0]);
196  l_b = BM_face_vert_share_loop(f, vert_split_arr[1]);
197 
198  /* common case, just cut the face once */
199  BM_face_split(bm, f, l_a, l_b, &l_new, NULL, true);
200  if (l_new) {
201  if (oflag_center | oflag_new) {
202  BMO_edge_flag_enable(bm, l_new->e, oflag_center | oflag_new);
203  }
204  if (oflag_new) {
205  BMO_face_flag_enable(bm, l_new->f, oflag_new);
206  }
207  }
208  }
209  else {
210 
211  uint i = 0;
212 
213  /* ---- */
214  /* Check contiguous spans of centered vertices (skipping when necessary). */
215  if (face_has_center_edge) {
216 
217  /* Loop indices need to be set for adjacency checks. */
218  l_iter = l_first;
219  do {
220  BM_VERT_LOOPINDEX(l_iter->v) = i++;
221  } while ((l_iter = l_iter->next) != l_first);
222 
223  /* Start out on a non-centered vertex so a span of centered vertices can be looped over
224  * without having to scan backwards as well as forwards. */
225  BMLoop *l_first_non_center = l_first;
226  while (vert_is_center_test(l_first_non_center->v)) {
227  l_first_non_center = l_first_non_center->next;
228  }
229 
230  l_iter = l_first_non_center;
231  do {
232  if (BM_VERT_SKIP(l_iter->v)) {
233  continue;
234  }
235  /* No need to check the previous as the iteration starts on a non-centered vertex. */
236  if (!(vert_is_center_test(l_iter->v) && vert_is_center_test(l_iter->next->v))) {
237  continue;
238  }
239 
240  /* Walk over the next loops as long as they are centered. */
241  BMLoop *l_prev = l_iter->prev;
242  BMLoop *l_next = l_iter->next->next;
243  /* No need to scan the previous vertices,
244  * these will have been dealt with in previous steps. */
245  BLI_assert(!vert_is_center_test(l_prev->v));
246  while (vert_is_center_test(l_next->v)) {
247  l_next = l_next->next;
248  }
249 
250  /* Skip all vertices when the edges connected to the beginning/end
251  * of the range are on a different side of the bisecting plane. */
252  if (!(BM_VERT_DIR(l_prev->v) ^ BM_VERT_DIR(l_next->v))) {
253  BLI_assert(!vert_is_center_test(l_prev->v));
254  l_iter = l_prev->next;
255  while (l_iter != l_next) {
256  BLI_assert(vert_is_center_test(l_iter->v));
257  BM_VERT_SKIP(l_iter->v) = true;
258  l_iter = l_iter->next;
259  }
260  }
261  /* Step over the span already handled, even if skip wasn't set. */
262  l_iter = l_next->prev;
263  } while ((l_iter = l_iter->next) != l_first_non_center);
264  }
265 
266  /* less common case, _complicated_ we need to calculate how to do multiple cuts */
267  float(*face_verts_proj_2d)[2] = BLI_array_alloca(face_verts_proj_2d, f_len_orig);
268  float axis_mat[3][3];
269 
270  BMFace **face_split_arr = BLI_array_alloca(face_split_arr, STACK_SIZE(vert_split_arr));
271  STACK_DECLARE(face_split_arr);
272 
273  float sort_dir[3];
274 
275  /* ---- */
276  /* Calculate the direction to sort verts in the face intersecting the plane */
277 
278  /* exact dir isn't so important,
279  * just need a dir for sorting verts across face,
280  * 'sort_dir' could be flipped either way, it not important, we only need to order the array
281  */
282  cross_v3_v3v3(sort_dir, f->no, plane);
283  if (UNLIKELY(normalize_v3(sort_dir) == 0.0f)) {
284  /* find any 2 verts and get their direction */
285  for (i = 0; i < STACK_SIZE(vert_split_arr); i++) {
286  if (!equals_v3v3(vert_split_arr[0]->co, vert_split_arr[i]->co)) {
287  sub_v3_v3v3(sort_dir, vert_split_arr[0]->co, vert_split_arr[i]->co);
288  normalize_v3(sort_dir);
289  }
290  }
291  if (UNLIKELY(i == STACK_SIZE(vert_split_arr))) {
292  /* ok, we can't do anything useful here,
293  * face has no area or so, bail out, this is highly unlikely but not impossible */
294  goto finally;
295  }
296  }
297 
298  /* ---- */
299  /* Calculate 2d coords to use for intersection checks */
300 
301  /* get the faces 2d coords */
303  axis_dominant_v3_to_m3(axis_mat, f->no);
304 
305  l_iter = l_first;
306  i = 0;
307  do {
308  mul_v2_m3v3(face_verts_proj_2d[i], axis_mat, l_iter->v->co);
309  i++;
310  } while ((l_iter = l_iter->next) != l_first);
311 
312  /* ---- */
313  /* Sort the verts across the face from one side to another */
314  for (i = 0; i < STACK_SIZE(vert_split_arr); i++) {
315  BMVert *v = vert_split_arr[i];
316  BM_VERT_SORTVAL(v) = dot_v3v3(sort_dir, v->co);
317  }
318 
319  qsort(
320  vert_split_arr, STACK_SIZE(vert_split_arr), sizeof(*vert_split_arr), bm_vert_sortval_cb);
321 
322  /* ---- */
323  /* Split the face across sorted splits */
324 
325  /* note: we don't know which face gets which splits,
326  * so at the moment we have to search all faces for the vert pair,
327  * while not all that nice, typically there are < 5 resulting faces,
328  * so its not _that_ bad. */
329 
330  STACK_INIT(face_split_arr, STACK_SIZE(vert_split_arr));
331  STACK_PUSH(face_split_arr, f);
332 
333  for (i = 0; i < STACK_SIZE(vert_split_arr) - 1; i++) {
334  BMVert *v_a = vert_split_arr[i];
335  BMVert *v_b = vert_split_arr[i + 1];
336 
337  if (face_has_center_edge) {
338  if (vert_pair_adjacent_in_orig_face(v_a, v_b, f_len_orig)) {
339  continue;
340  }
341  }
342 
343  if (!BM_VERT_SKIP(v_a)) {
344  is_inside = !is_inside;
345  }
346 
347  if (is_inside) {
348  BMLoop *l_a, *l_b;
349  bool found = false;
350  uint j;
351 
352  for (j = 0; j < STACK_SIZE(face_split_arr); j++) {
353  /* would be nice to avoid loop lookup here,
354  * but we need to know which face the verts are in */
355  if ((l_a = BM_face_vert_share_loop(face_split_arr[j], v_a)) &&
356  (l_b = BM_face_vert_share_loop(face_split_arr[j], v_b))) {
357  found = true;
358  break;
359  }
360  }
361 
362  /* ideally wont happen, but it can for self intersecting faces */
363  // BLI_assert(found == true);
364 
365  /* in fact this simple test is good enough,
366  * test if the loops are adjacent */
367  if (found && !BM_loop_is_adjacent(l_a, l_b)) {
368  BMLoop *l_new;
369  BMFace *f_tmp;
370  f_tmp = BM_face_split(bm, face_split_arr[j], l_a, l_b, &l_new, NULL, true);
371 
372  if (l_new) {
373  if (oflag_center | oflag_new) {
374  BMO_edge_flag_enable(bm, l_new->e, oflag_center | oflag_new);
375  }
376  if (oflag_new) {
377  BMO_face_flag_enable(bm, l_new->f, oflag_new);
378  }
379  }
380 
381  if (f_tmp) {
382  if (f_tmp != face_split_arr[j]) {
383  STACK_PUSH(face_split_arr, f_tmp);
384  BLI_assert(STACK_SIZE(face_split_arr) <= STACK_SIZE(vert_split_arr));
385  }
386  }
387  }
388  }
389  else {
390  // printf("no intersect\n");
391  }
392  }
393  }
394  }
395 
396 finally:
397  (void)vert_split_arr;
398 }
399 
400 /* -------------------------------------------------------------------- */
401 /* Main logic */
402 
409  const float plane[4],
410  const bool use_snap_center,
411  const bool use_tag,
412  const short oflag_center,
413  const short oflag_new,
414  const float eps)
415 {
416  uint einput_len;
417  uint i;
418  BMEdge **edges_arr = MEM_mallocN(sizeof(*edges_arr) * (size_t)bm->totedge, __func__);
419 
420  BLI_LINKSTACK_DECLARE(face_stack, BMFace *);
421 
422  BMVert *v;
423  BMFace *f;
424 
425  BMIter iter;
426 
427  if (use_tag) {
428  /* build tagged edge array */
429  BMEdge *e;
430  einput_len = 0;
431 
432  /* flush edge tags to verts */
434 
435  /* keep face tags as is */
436  BM_ITER_MESH_INDEX (e, &iter, bm, BM_EDGES_OF_MESH, i) {
437  if (edge_is_cut_test(e)) {
438  edges_arr[einput_len++] = e;
439 
440  /* flush edge tags to verts */
443  }
444  }
445 
446  /* face tags are set by caller */
447  }
448  else {
449  BMEdge *e;
450  einput_len = (uint)bm->totedge;
451  BM_ITER_MESH_INDEX (e, &iter, bm, BM_EDGES_OF_MESH, i) {
453  edges_arr[i] = e;
454  }
455 
456  BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
458  }
459  }
460 
461  BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
462 
463  if (use_tag && !BM_elem_flag_test(v, BM_ELEM_TAG)) {
465 
466  /* these should never be accessed */
467  BM_VERT_DIR(v) = 0;
468  BM_VERT_DIST(v) = 0.0f;
469 
470  continue;
471  }
472 
475 
476  if (BM_VERT_DIR(v) == 0) {
477  if (oflag_center) {
478  BMO_vert_flag_enable(bm, v, oflag_center);
479  }
480  if (use_snap_center) {
481  closest_to_plane_v3(v->co, plane, v->co);
482  }
483  }
484  }
485 
486  /* store a stack of faces to be evaluated for splitting */
487  BLI_LINKSTACK_INIT(face_stack);
488 
489  for (i = 0; i < einput_len; i++) {
490  /* we could check edge_is_cut_test(e) but there is no point */
491  BMEdge *e = edges_arr[i];
492  const int side[2] = {BM_VERT_DIR(e->v1), BM_VERT_DIR(e->v2)};
493  const float dist[2] = {BM_VERT_DIST(e->v1), BM_VERT_DIST(e->v2)};
494 
495  if (side[0] && side[1] && (side[0] != side[1])) {
496  const float e_fac = dist[0] / (dist[0] - dist[1]);
497  BMVert *v_new;
498 
499  if (e->l) {
500  BMLoop *l_iter, *l_first;
501  l_iter = l_first = e->l;
502  do {
503  if (!face_in_stack_test(l_iter->f)) {
504  face_in_stack_enable(l_iter->f);
505  BLI_LINKSTACK_PUSH(face_stack, l_iter->f);
506  }
507  } while ((l_iter = l_iter->radial_next) != l_first);
508  }
509 
510  {
511  BMEdge *e_new;
512  v_new = BM_edge_split(bm, e, e->v1, &e_new, e_fac);
513  if (oflag_new) {
514  BMO_edge_flag_enable(bm, e_new, oflag_new);
515  }
516  }
517 
518  vert_is_center_enable(v_new);
519  if (oflag_new | oflag_center) {
520  BMO_vert_flag_enable(bm, v_new, oflag_new | oflag_center);
521  }
522 
523  BM_VERT_DIR(v_new) = 0;
524  BM_VERT_DIST(v_new) = 0.0f;
525  }
526  else if (side[0] == 0 || side[1] == 0) {
527  /* check if either edge verts are aligned,
528  * if so - tag and push all faces that use it into the stack */
529  uint j;
530  BM_ITER_ELEM_INDEX (v, &iter, e, BM_VERTS_OF_EDGE, j) {
531  if (side[j] == 0) {
532  if (vert_is_center_test(v) == 0) {
533  BMIter itersub;
534  BMLoop *l_iter;
535 
537 
538  BM_ITER_ELEM (l_iter, &itersub, v, BM_LOOPS_OF_VERT) {
539  if (!face_in_stack_test(l_iter->f)) {
540  face_in_stack_enable(l_iter->f);
541  BLI_LINKSTACK_PUSH(face_stack, l_iter->f);
542  }
543  }
544  }
545  }
546  }
547 
548  /* if both verts are on the center - tag it */
549  if (oflag_center) {
550  if (side[0] == 0 && side[1] == 0) {
551  BMO_edge_flag_enable(bm, e, oflag_center);
552  }
553  }
554  }
555  }
556 
557  MEM_freeN(edges_arr);
558 
559  while ((f = BLI_LINKSTACK_POP(face_stack))) {
560  bm_face_bisect_verts(bm, f, plane, oflag_center, oflag_new);
561  }
562 
563  /* Caused by access macros: BM_VERT_DIR, BM_VERT_SKIP. */
565 
566  /* now we have all faces to split in the stack */
567  BLI_LINKSTACK_FREE(face_stack);
568 }
typedef float(TangentPoint)[2]
#define BLI_array_alloca(arr, realsize)
Definition: BLI_alloca.h:36
#define BLI_assert(a)
Definition: BLI_assert.h:58
#define BLI_INLINE
MINLINE float plane_point_side_v3(const float plane[4], const float co[3])
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 closest_to_plane_v3(float r_close[3], const float plane[4], const float pt[3])
Definition: math_geom.c:405
void mul_v2_m3v3(float r[2], const float M[3][3], const float a[3])
Definition: math_matrix.c:921
MINLINE float normalize_v3(float r[3])
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 cross_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE bool equals_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT
Strict compiler flags for areas of code we want to ensure don't do conversions without us knowing abo...
unsigned int uint
Definition: BLI_sys_types.h:83
#define UNLIKELY(x)
#define ELEM(...)
#define LIKELY(x)
#define STACK_PUSH(stack, val)
#define STACK_DECLARE(stack)
#define STACK_INIT(stack, tot)
#define STACK_SIZE(stack)
Read Guarded memory(de)allocation.
BLI_INLINE void vert_is_center_enable(BMVert *v)
static int bm_vert_sortval_cb(const void *v_a_v, const void *v_b_v)
void BM_mesh_bisect_plane(BMesh *bm, const float plane[4], const bool use_snap_center, const bool use_tag, const short oflag_center, const short oflag_new, const float eps)
BLI_INLINE void face_in_stack_enable(BMFace *f)
static void bm_face_bisect_verts(BMesh *bm, BMFace *f, const float plane[4], const short oflag_center, const short oflag_new)
#define BM_VERT_SKIP(v)
BLI_INLINE void vert_is_center_disable(BMVert *v)
BLI_INLINE bool edge_is_cut_test(BMEdge *e)
BLI_INLINE bool vert_is_center_test(BMVert *v)
BLI_INLINE void edge_is_cut_disable(BMEdge *e)
#define BM_VERT_DIR(v)
#define BM_VERT_LOOPINDEX(v)
#define BM_VERT_DIST(v)
static short plane_point_test_v3(const float plane[4], const float co[3], const float eps, float *r_depth)
BLI_INLINE bool face_in_stack_test(BMFace *f)
#define BM_VERT_SORTVAL(v)
BLI_INLINE void edge_is_cut_enable(BMEdge *e)
BLI_INLINE bool vert_pair_adjacent_in_orig_face(BMVert *v_a, BMVert *v_b, const uint f_len_orig)
BLI_INLINE void face_in_stack_disable(BMFace *f)
@ BM_VERT
Definition: bmesh_class.h:383
@ BM_ELEM_TAG
Definition: bmesh_class.h:484
#define BM_FACE_FIRST_LOOP(p)
Definition: bmesh_class.h:553
#define BM_elem_flag_disable(ele, hflag)
Definition: bmesh_inline.h:29
#define BM_elem_flag_test(ele, hflag)
Definition: bmesh_inline.h:26
#define BM_elem_flag_enable(ele, hflag)
Definition: bmesh_inline.h:28
#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
@ BM_FACES_OF_MESH
@ BM_LOOPS_OF_VERT
#define BM_ITER_ELEM_INDEX(ele, iter, data, itype, indexvar)
ATTR_WARN_UNUSED_RESULT BMesh * bm
void BM_mesh_elem_hflag_disable_all(BMesh *bm, const char htype, const char hflag, const bool respecthide)
BMVert * BM_edge_split(BMesh *bm, BMEdge *e, BMVert *v, BMEdge **r_e, float fac)
Edge Split.
Definition: bmesh_mods.c:591
BMFace * BM_face_split(BMesh *bm, BMFace *f, BMLoop *l_a, BMLoop *l_b, BMLoop **r_l, BMEdge *example, const bool no_double)
Face Split.
Definition: bmesh_mods.c:252
#define BMO_edge_flag_enable(bm, e, oflag)
#define BMO_vert_flag_enable(bm, e, oflag)
#define BMO_face_flag_enable(bm, e, oflag)
bool BM_face_is_normal_valid(const BMFace *f)
Definition: bmesh_query.c:2533
BMLoop * BM_face_vert_share_loop(BMFace *f, BMVert *v)
Return the Loop Shared by Face and Vertex.
Definition: bmesh_query.c:1403
BLI_INLINE bool BM_loop_is_adjacent(const BMLoop *l_a, const BMLoop *l_b) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
ATTR_WARN_UNUSED_RESULT const BMVert const BMEdge * e
ATTR_WARN_UNUSED_RESULT const BMLoop * l_b
ATTR_WARN_UNUSED_RESULT const BMVert * v
static bool is_inside(int x, int y, int cols, int rows)
Definition: filesel.c:663
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:41
void *(* MEM_mallocN)(size_t len, const char *str)
Definition: mallocn.c:47
const btScalar eps
Definition: poly34.cpp:11
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
char elem_index_dirty
Definition: bmesh_class.h:305
int totedge
Definition: bmesh_class.h:297
__forceinline const avxi abs(const avxi &a)
Definition: util_avxi.h:186