Blender  V3.3
bmesh_wireframe.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 "DNA_meshdata_types.h"
12 
13 #include "BLI_math.h"
14 
15 #include "bmesh.h"
16 
17 #include "BKE_customdata.h"
18 #include "BKE_deform.h"
19 
20 #include "bmesh_wireframe.h"
21 
23 {
24  BMLoop *l, *l_first;
25 
26  l = l_first = e->l;
27  do {
29  return l;
30  }
31  } while ((l = l->radial_next) != l_first);
32 
33  /* in the case this is used, we know this will never happen */
34  return NULL;
35 }
36 
38  BMVert *v, float r_no[3], float r_no_face[3], BMVert **r_va_other, BMVert **r_vb_other)
39 {
40  BMIter iter;
41  BMEdge *e_iter;
42 
43  BMEdge *e_a = NULL, *e_b = NULL;
44  BMVert *v_a, *v_b;
45 
46  BMLoop *l_a, *l_b;
47 
48  float no_face[3], no_edge[3];
49  float tvec_a[3], tvec_b[3];
50 
51  /* get 2 boundary edges, there should only _be_ 2,
52  * in case there are more - results won't be valid of course */
53  BM_ITER_ELEM (e_iter, &iter, v, BM_EDGES_OF_VERT) {
54  if (BM_elem_flag_test(e_iter, BM_ELEM_TAG)) {
55  if (e_a == NULL) {
56  e_a = e_iter;
57  }
58  else {
59  e_b = e_iter;
60  break;
61  }
62  }
63  }
64 
65  if (e_a && e_b) {
66  /* NOTE: with an incorrectly flushed selection this can crash. */
67  l_a = bm_edge_tag_faceloop(e_a);
69 
70  /* average edge face normal */
71  add_v3_v3v3(no_face, l_a->f->no, l_b->f->no);
72  normalize_v3(no_face);
73 
74  /* average edge direction */
75  v_a = BM_edge_other_vert(e_a, v);
76  v_b = BM_edge_other_vert(e_b, v);
77 
78  sub_v3_v3v3(tvec_a, v->co, v_a->co);
79  sub_v3_v3v3(tvec_b, v_b->co, v->co);
80  normalize_v3(tvec_a);
81  normalize_v3(tvec_b);
82  add_v3_v3v3(no_edge, tvec_a, tvec_b); /* not unit length but this is ok */
83 
84  /* check are we flipped the right way */
85  BM_edge_calc_face_tangent(e_a, l_a, tvec_a);
86  BM_edge_calc_face_tangent(e_b, l_b, tvec_b);
87  add_v3_v3(tvec_a, tvec_b);
88 
89  *r_va_other = v_a;
90  *r_vb_other = v_b;
91  }
92  else {
93  /* degenerate case - vertex connects a boundary edged face to other faces,
94  * so we have only one boundary face - only use it for calculations */
95  l_a = bm_edge_tag_faceloop(e_a);
96 
97  copy_v3_v3(no_face, l_a->f->no);
98 
99  /* edge direction */
100  v_a = BM_edge_other_vert(e_a, v);
101  v_b = NULL;
102 
103  sub_v3_v3v3(no_edge, v->co, v_a->co);
104 
105  /* check are we flipped the right way */
106  BM_edge_calc_face_tangent(e_a, l_a, tvec_a);
107 
108  *r_va_other = NULL;
109  *r_vb_other = NULL;
110  }
111 
112  /* find the normal */
113  cross_v3_v3v3(r_no, no_edge, no_face);
114  normalize_v3(r_no);
115 
116  if (dot_v3v3(r_no, tvec_a) > 0.0f) {
117  negate_v3(r_no);
118  }
119 
120  copy_v3_v3(r_no_face, no_face);
121 }
122 
123 /* check if we are the only tagged loop-face around this edge */
124 static bool bm_loop_is_radial_boundary(BMLoop *l_first)
125 {
126  BMLoop *l = l_first->radial_next;
127 
128  if (l == l_first) {
129  return true; /* a real boundary */
130  }
131 
132  do {
133  if (BM_elem_flag_test(l->f, BM_ELEM_TAG)) {
134  return false;
135  }
136  } while ((l = l->radial_next) != l_first);
137 
138  return true;
139 }
140 
142  const float offset,
143  const float offset_fac,
144  const float offset_fac_vg,
145  const bool use_replace,
146  const bool use_boundary,
147  const bool use_even_offset,
148  const bool use_relative_offset,
149  const bool use_crease,
150  const float crease_weight,
151  const int defgrp_index,
152  const bool defgrp_invert,
153  const short mat_offset,
154  const short mat_max,
155  /* for operators */
156  const bool use_tag)
157 {
158  const float ofs_orig = -(((-offset_fac + 1.0f) * 0.5f) * offset);
159  const float ofs_new = offset + ofs_orig;
160  const float ofs_mid = (ofs_orig + ofs_new) / 2.0f;
161  const float inset = offset / 2.0f;
162  int cd_edge_crease_offset = use_crease ? CustomData_get_offset(&bm->edata, CD_CREASE) : -1;
163  const int cd_dvert_offset = (defgrp_index != -1) ?
165  -1;
166  const float offset_fac_vg_inv = 1.0f - offset_fac_vg;
167 
168  const int totvert_orig = bm->totvert;
169 
170  BMIter iter;
171  BMIter itersub;
172 
173  /* filled only with boundary verts */
174  BMVert **verts_src = MEM_mallocN(sizeof(BMVert *) * totvert_orig, __func__);
175  BMVert **verts_neg = MEM_mallocN(sizeof(BMVert *) * totvert_orig, __func__);
176  BMVert **verts_pos = MEM_mallocN(sizeof(BMVert *) * totvert_orig, __func__);
177 
178  /* Will over-alloc, but makes for easy lookups by index to keep aligned. */
179  BMVert **verts_boundary = use_boundary ? MEM_mallocN(sizeof(BMVert *) * totvert_orig, __func__) :
180  NULL;
181 
182  float *verts_relfac = (use_relative_offset || (cd_dvert_offset != -1)) ?
183  MEM_mallocN(sizeof(float) * totvert_orig, __func__) :
184  NULL;
185 
186  /* may over-alloc if not all faces have wire */
187  BMVert **verts_loop;
188  int verts_loop_tot = 0;
189 
190  BMVert *v_src;
191 
192  BMFace *f_src;
193  BMLoop *l;
194 
195  float tvec[3];
196  float fac, fac_shell;
197 
198  int i;
199 
200  if (use_crease && cd_edge_crease_offset == -1) {
202  cd_edge_crease_offset = CustomData_get_offset(&bm->edata, CD_CREASE);
203  }
204 
205  BM_ITER_MESH_INDEX (v_src, &iter, bm, BM_VERTS_OF_MESH, i) {
206  BM_elem_index_set(v_src, i); /* set_inline */
207 
208  verts_src[i] = v_src;
210  }
212 
213  /* setup tags, all faces and verts will be tagged which will be duplicated */
214 
215  BM_ITER_MESH_INDEX (f_src, &iter, bm, BM_FACES_OF_MESH, i) {
216  BM_elem_index_set(f_src, i); /* set_inline */
217 
218  if (use_tag) {
219  if (!BM_elem_flag_test(f_src, BM_ELEM_TAG)) {
220  continue;
221  }
222  }
223  else {
225  }
226 
227  verts_loop_tot += f_src->len;
228  BM_ITER_ELEM (l, &itersub, f_src, BM_LOOPS_OF_FACE) {
230 
231  /* also tag boundary edges */
233  }
234  }
236 
237  /* duplicate tagged verts */
238  for (i = 0; i < totvert_orig; i++) {
239  v_src = verts_src[i];
240  if (BM_elem_flag_test(v_src, BM_ELEM_TAG)) {
241  fac = 1.0f;
242 
243  if (verts_relfac) {
244  if (use_relative_offset) {
245  verts_relfac[i] = BM_vert_calc_median_tagged_edge_length(v_src);
246  }
247  else {
248  verts_relfac[i] = 1.0f;
249  }
250 
251  if (cd_dvert_offset != -1) {
252  MDeformVert *dvert = BM_ELEM_CD_GET_VOID_P(v_src, cd_dvert_offset);
253  float defgrp_fac = BKE_defvert_find_weight(dvert, defgrp_index);
254 
255  if (defgrp_invert) {
256  defgrp_fac = 1.0f - defgrp_fac;
257  }
258 
259  if (offset_fac_vg > 0.0f) {
260  defgrp_fac = (offset_fac_vg + (defgrp_fac * offset_fac_vg_inv));
261  }
262 
263  verts_relfac[i] *= defgrp_fac;
264  }
265 
266  fac *= verts_relfac[i];
267  }
268 
269  verts_neg[i] = BM_vert_create(bm, NULL, v_src, BM_CREATE_NOP);
270  verts_pos[i] = BM_vert_create(bm, NULL, v_src, BM_CREATE_NOP);
271 
272  if (offset == 0.0f) {
273  madd_v3_v3v3fl(verts_neg[i]->co, v_src->co, v_src->no, ofs_orig * fac);
274  madd_v3_v3v3fl(verts_pos[i]->co, v_src->co, v_src->no, ofs_new * fac);
275  }
276  else {
277  madd_v3_v3v3fl(tvec, v_src->co, v_src->no, ofs_mid * fac);
278 
279  madd_v3_v3v3fl(verts_neg[i]->co, tvec, v_src->no, (ofs_orig - ofs_mid) * fac);
280  madd_v3_v3v3fl(verts_pos[i]->co, tvec, v_src->no, (ofs_new - ofs_mid) * fac);
281  }
282  }
283  else {
284  /* could skip this */
285  verts_neg[i] = NULL;
286  verts_pos[i] = NULL;
287  }
288 
289  /* conflicts with BM_vert_calc_median_tagged_edge_length */
290  if (use_relative_offset == false) {
292  }
293  }
294 
295  if (use_relative_offset) {
297  }
298 
299  verts_loop = MEM_mallocN(sizeof(BMVert *) * verts_loop_tot, __func__);
300  verts_loop_tot = 0; /* count up again */
301 
302  BM_ITER_MESH (f_src, &iter, bm, BM_FACES_OF_MESH) {
303 
304  if (use_tag && !BM_elem_flag_test(f_src, BM_ELEM_TAG)) {
305  continue;
306  }
307 
308  BM_ITER_ELEM (l, &itersub, f_src, BM_LOOPS_OF_FACE) {
309  /* Because some faces might be skipped! */
310  BM_elem_index_set(l, verts_loop_tot); /* set_dirty */
311 
313 
314  /* create offset vert */
315  fac = 1.0f;
316 
317  if (verts_relfac) {
318  fac *= verts_relfac[BM_elem_index_get(l->v)];
319  }
320 
321  fac_shell = fac;
322  if (use_even_offset) {
323  fac_shell *= shell_angle_to_dist(((float)M_PI - BM_loop_calc_face_angle(l)) * 0.5f);
324  }
325 
326  madd_v3_v3v3fl(tvec, l->v->co, tvec, inset * fac_shell);
327  if (offset != 0.0f) {
328  madd_v3_v3fl(tvec, l->v->no, ofs_mid * fac);
329  }
330  verts_loop[verts_loop_tot] = BM_vert_create(bm, tvec, l->v, BM_CREATE_NOP);
331 
332  if (use_boundary) {
333  if (BM_elem_flag_test(l->e, BM_ELEM_TAG)) { /* is this a boundary? */
334  BMVert *v_pair[2] = {l->v, l->next->v};
335 
336  for (i = 0; i < 2; i++) {
337  BMVert *v_boundary = v_pair[i];
338  if (!BM_elem_flag_test(v_boundary, BM_ELEM_TAG)) {
339  const int v_boundary_index = BM_elem_index_get(v_boundary);
340  float no_face[3];
341  BMVert *va_other;
342  BMVert *vb_other;
343 
344  BM_elem_flag_enable(v_boundary, BM_ELEM_TAG);
345 
346  bm_vert_boundary_tangent(v_boundary, tvec, no_face, &va_other, &vb_other);
347 
348  /* create offset vert */
349  /* similar to code above but different angle calc */
350  fac = 1.0f;
351 
352  if (verts_relfac) {
353  fac *= verts_relfac[v_boundary_index];
354  }
355 
356  fac_shell = fac;
357  if (use_even_offset) {
358  if (va_other) { /* for verts with only one boundary edge - this will be NULL */
359  fac_shell *= shell_angle_to_dist(
360  ((float)M_PI - angle_on_axis_v3v3v3_v3(
361  va_other->co, v_boundary->co, vb_other->co, no_face)) *
362  0.5f);
363  }
364  }
365 
366  madd_v3_v3v3fl(tvec, v_boundary->co, tvec, inset * fac_shell);
367  if (offset != 0.0f) {
368  madd_v3_v3fl(tvec, v_boundary->no, ofs_mid * fac);
369  }
370  verts_boundary[v_boundary_index] = BM_vert_create(
371  bm, tvec, v_boundary, BM_CREATE_NOP);
372  }
373  }
374  }
375  }
376 
377  verts_loop_tot++;
378  }
379  }
381 
382  BM_ITER_MESH (f_src, &iter, bm, BM_FACES_OF_MESH) {
383 
384  /* skip recently added faces */
385  if (BM_elem_index_get(f_src) == -1) {
386  continue;
387  }
388 
389  if (use_tag && !BM_elem_flag_test(f_src, BM_ELEM_TAG)) {
390  continue;
391  }
392 
394 
395  BM_ITER_ELEM (l, &itersub, f_src, BM_LOOPS_OF_FACE) {
396  BMFace *f_new;
397  BMLoop *l_new;
398  BMLoop *l_next = l->next;
399  BMVert *v_l1 = verts_loop[BM_elem_index_get(l)];
400  BMVert *v_l2 = verts_loop[BM_elem_index_get(l_next)];
401 
402  BMVert *v_src_l1 = l->v;
403  BMVert *v_src_l2 = l_next->v;
404 
405  const int i_1 = BM_elem_index_get(v_src_l1);
406  const int i_2 = BM_elem_index_get(v_src_l2);
407 
408  BMVert *v_neg1 = verts_neg[i_1];
409  BMVert *v_neg2 = verts_neg[i_2];
410 
411  BMVert *v_pos1 = verts_pos[i_1];
412  BMVert *v_pos2 = verts_pos[i_2];
413 
414  f_new = BM_face_create_quad_tri(bm, v_l1, v_l2, v_neg2, v_neg1, f_src, BM_CREATE_NOP);
415  if (mat_offset) {
416  f_new->mat_nr = CLAMPIS(f_new->mat_nr + mat_offset, 0, mat_max);
417  }
419  l_new = BM_FACE_FIRST_LOOP(f_new);
420 
421  BM_elem_attrs_copy(bm, bm, l, l_new);
422  BM_elem_attrs_copy(bm, bm, l, l_new->prev);
423  BM_elem_attrs_copy(bm, bm, l_next, l_new->next);
424  BM_elem_attrs_copy(bm, bm, l_next, l_new->next->next);
425 
426  f_new = BM_face_create_quad_tri(bm, v_l2, v_l1, v_pos1, v_pos2, f_src, BM_CREATE_NOP);
427 
428  if (mat_offset) {
429  f_new->mat_nr = CLAMPIS(f_new->mat_nr + mat_offset, 0, mat_max);
430  }
432  l_new = BM_FACE_FIRST_LOOP(f_new);
433 
434  BM_elem_attrs_copy(bm, bm, l_next, l_new);
435  BM_elem_attrs_copy(bm, bm, l_next, l_new->prev);
436  BM_elem_attrs_copy(bm, bm, l, l_new->next);
437  BM_elem_attrs_copy(bm, bm, l, l_new->next->next);
438 
439  if (use_boundary) {
440  if (BM_elem_flag_test(l->e, BM_ELEM_TAG)) {
441  /* we know its a boundary and this is the only face user (which is being wire'd) */
442  /* we know we only touch this edge/face once */
443  BMVert *v_b1 = verts_boundary[i_1];
444  BMVert *v_b2 = verts_boundary[i_2];
445 
446  f_new = BM_face_create_quad_tri(bm, v_b2, v_b1, v_neg1, v_neg2, f_src, BM_CREATE_NOP);
447  if (mat_offset) {
448  f_new->mat_nr = CLAMPIS(f_new->mat_nr + mat_offset, 0, mat_max);
449  }
451  l_new = BM_FACE_FIRST_LOOP(f_new);
452 
453  BM_elem_attrs_copy(bm, bm, l_next, l_new);
454  BM_elem_attrs_copy(bm, bm, l_next, l_new->prev);
455  BM_elem_attrs_copy(bm, bm, l, l_new->next);
456  BM_elem_attrs_copy(bm, bm, l, l_new->next->next);
457 
458  f_new = BM_face_create_quad_tri(bm, v_b1, v_b2, v_pos2, v_pos1, f_src, BM_CREATE_NOP);
459  if (mat_offset) {
460  f_new->mat_nr = CLAMPIS(f_new->mat_nr + mat_offset, 0, mat_max);
461  }
463  l_new = BM_FACE_FIRST_LOOP(f_new);
464 
465  BM_elem_attrs_copy(bm, bm, l, l_new);
466  BM_elem_attrs_copy(bm, bm, l, l_new->prev);
467  BM_elem_attrs_copy(bm, bm, l_next, l_new->next);
468  BM_elem_attrs_copy(bm, bm, l_next, l_new->next->next);
469 
470  if (use_crease) {
471  BMEdge *e_new;
472  e_new = BM_edge_exists(v_pos1, v_b1);
473  BM_ELEM_CD_SET_FLOAT(e_new, cd_edge_crease_offset, crease_weight);
474 
475  e_new = BM_edge_exists(v_pos2, v_b2);
476  BM_ELEM_CD_SET_FLOAT(e_new, cd_edge_crease_offset, crease_weight);
477 
478  e_new = BM_edge_exists(v_neg1, v_b1);
479  BM_ELEM_CD_SET_FLOAT(e_new, cd_edge_crease_offset, crease_weight);
480 
481  e_new = BM_edge_exists(v_neg2, v_b2);
482  BM_ELEM_CD_SET_FLOAT(e_new, cd_edge_crease_offset, crease_weight);
483  }
484  }
485  }
486 
487  if (use_crease) {
488  BMEdge *e_new;
489  e_new = BM_edge_exists(v_pos1, v_l1);
490  BM_ELEM_CD_SET_FLOAT(e_new, cd_edge_crease_offset, crease_weight);
491 
492  e_new = BM_edge_exists(v_pos2, v_l2);
493  BM_ELEM_CD_SET_FLOAT(e_new, cd_edge_crease_offset, crease_weight);
494 
495  e_new = BM_edge_exists(v_neg1, v_l1);
496  BM_ELEM_CD_SET_FLOAT(e_new, cd_edge_crease_offset, crease_weight);
497 
498  e_new = BM_edge_exists(v_neg2, v_l2);
499  BM_ELEM_CD_SET_FLOAT(e_new, cd_edge_crease_offset, crease_weight);
500  }
501  }
502  }
503 
504  if (use_boundary) {
505  MEM_freeN(verts_boundary);
506  }
507 
508  if (verts_relfac) {
509  MEM_freeN(verts_relfac);
510  }
511 
512  if (use_replace) {
513 
514  if (use_tag) {
515  /* only remove faces which are original and used to make wire,
516  * use 'verts_pos' and 'verts_neg' to avoid a feedback loop. */
517 
518  /* vertex must be from 'verts_src' */
519 #define VERT_DUPE_TEST_ORIG(v) (verts_neg[BM_elem_index_get(v)] != NULL)
520 #define VERT_DUPE_TEST(v) (verts_pos[BM_elem_index_get(v)] != NULL)
521 #define VERT_DUPE_CLEAR(v) \
522  { \
523  verts_pos[BM_elem_index_get(v)] = NULL; \
524  } \
525  (void)0
526 
527  /* first ensure we keep all verts which are used in faces that weren't
528  * entirely made into wire. */
529  BM_ITER_MESH (f_src, &iter, bm, BM_FACES_OF_MESH) {
530  int mix_flag = 0;
531  BMLoop *l_iter, *l_first;
532 
533  /* skip new faces */
534  if (BM_elem_index_get(f_src) == -1) {
535  continue;
536  }
537 
538  l_iter = l_first = BM_FACE_FIRST_LOOP(f_src);
539  do {
540  mix_flag |= (VERT_DUPE_TEST_ORIG(l_iter->v) ? 1 : 2);
541  if (mix_flag == (1 | 2)) {
542  break;
543  }
544  } while ((l_iter = l_iter->next) != l_first);
545 
546  if (mix_flag == (1 | 2)) {
547  l_iter = l_first = BM_FACE_FIRST_LOOP(f_src);
548  do {
549  VERT_DUPE_CLEAR(l_iter->v);
550  } while ((l_iter = l_iter->next) != l_first);
551  }
552  }
553 
554  /* now remove any verts which were made into wire by all faces */
555  for (i = 0; i < totvert_orig; i++) {
556  v_src = verts_src[i];
557  BLI_assert(i == BM_elem_index_get(v_src));
558  if (VERT_DUPE_TEST(v_src)) {
559  BM_vert_kill(bm, v_src);
560  }
561  }
562 
563 #undef VERT_DUPE_TEST_ORIG
564 #undef VERT_DUPE_TEST
565 #undef VERT_DUPE_CLEAR
566  }
567  else {
568  /* simple case, no tags - replace all */
569  for (i = 0; i < totvert_orig; i++) {
570  BM_vert_kill(bm, verts_src[i]);
571  }
572  }
573  }
574 
575  MEM_freeN(verts_src);
576  MEM_freeN(verts_neg);
577  MEM_freeN(verts_pos);
578  MEM_freeN(verts_loop);
579 }
CustomData interface, see also DNA_customdata_types.h.
int CustomData_get_offset(const struct CustomData *data, int type)
support for deformation groups and hooks.
float BKE_defvert_find_weight(const struct MDeformVert *dvert, int defgroup)
Definition: deform.c:704
#define BLI_assert(a)
Definition: BLI_assert.h:46
#define M_PI
Definition: BLI_math_base.h:20
MINLINE float shell_angle_to_dist(float angle)
MINLINE void madd_v3_v3fl(float r[3], const float a[3], float f)
MINLINE float normalize_v3(float r[3])
MINLINE void sub_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE void copy_v3_v3(float r[3], const float a[3])
MINLINE float dot_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT
MINLINE void add_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE void cross_v3_v3v3(float r[3], const float a[3], const float b[3])
float angle_on_axis_v3v3v3_v3(const float v1[3], const float v2[3], const float v3[3], const float axis[3]) ATTR_WARN_UNUSED_RESULT
Definition: math_vector.c:508
MINLINE void negate_v3(float r[3])
MINLINE void madd_v3_v3v3fl(float r[3], const float a[3], const float b[3], float f)
MINLINE void add_v3_v3(float r[3], const float a[3])
#define CLAMPIS(a, b, c)
@ CD_MDEFORMVERT
Read Guarded memory(de)allocation.
#define BM_ELEM_CD_SET_FLOAT(ele, offset, f)
Definition: bmesh_class.h:545
#define BM_FACE_FIRST_LOOP(p)
Definition: bmesh_class.h:622
@ BM_LOOP
Definition: bmesh_class.h:385
@ BM_FACE
Definition: bmesh_class.h:386
@ BM_VERT
Definition: bmesh_class.h:383
@ BM_ELEM_TAG
Definition: bmesh_class.h:484
#define BM_ELEM_CD_GET_VOID_P(ele, offset)
Definition: bmesh_class.h:541
void BM_elem_attrs_copy(BMesh *bm_src, BMesh *bm_dst, const void *ele_src, void *ele_dst)
BMFace * BM_face_create_quad_tri(BMesh *bm, BMVert *v1, BMVert *v2, BMVert *v3, BMVert *v4, const BMFace *f_example, const eBMCreateFlag create_flag)
Make Quad/Triangle.
BMVert * BM_vert_create(BMesh *bm, const float co[3], const BMVert *v_example, const eBMCreateFlag create_flag)
Main function for creating a new vertex.
Definition: bmesh_core.c:41
void BM_vert_kill(BMesh *bm, BMVert *v)
Definition: bmesh_core.c:939
@ BM_CREATE_NOP
Definition: bmesh_core.h:12
#define BM_elem_index_get(ele)
Definition: bmesh_inline.h:110
#define BM_elem_flag_disable(ele, hflag)
Definition: bmesh_inline.h:15
#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
#define BM_elem_flag_enable(ele, hflag)
Definition: bmesh_inline.h:14
void BM_data_layer_add(BMesh *bm, CustomData *data, int type)
Definition: bmesh_interp.c:839
#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_VERTS_OF_MESH
@ BM_FACES_OF_MESH
@ BM_EDGES_OF_VERT
@ BM_LOOPS_OF_FACE
ATTR_WARN_UNUSED_RESULT BMesh * bm
void BM_mesh_elem_hflag_disable_all(BMesh *bm, const char htype, const char hflag, const bool respecthide)
BMEdge * BM_edge_exists(BMVert *v_a, BMVert *v_b)
Definition: bmesh_query.c:1553
float BM_vert_calc_median_tagged_edge_length(const BMVert *v)
Definition: bmesh_query.c:1467
void BM_loop_calc_face_tangent(const BMLoop *l, float r_tangent[3])
BM_loop_calc_face_tangent.
Definition: bmesh_query.c:1299
float BM_loop_calc_face_angle(const BMLoop *l)
Definition: bmesh_query.c:1192
void BM_edge_calc_face_tangent(const BMEdge *e, const BMLoop *e_loop, float r_tangent[3])
BMESH EDGE/FACE TANGENT.
Definition: bmesh_query.c:1384
BLI_INLINE BMVert * BM_edge_other_vert(BMEdge *e, const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
ATTR_WARN_UNUSED_RESULT const BMLoop * l
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 BMLoop * bm_edge_tag_faceloop(BMEdge *e)
void BM_mesh_wireframe(BMesh *bm, const float offset, const float offset_fac, const float offset_fac_vg, const bool use_replace, const bool use_boundary, const bool use_even_offset, const bool use_relative_offset, const bool use_crease, const float crease_weight, const int defgrp_index, const bool defgrp_invert, const short mat_offset, const short mat_max, const bool use_tag)
#define VERT_DUPE_CLEAR(v)
#define VERT_DUPE_TEST(v)
static void bm_vert_boundary_tangent(BMVert *v, float r_no[3], float r_no_face[3], BMVert **r_va_other, BMVert **r_vb_other)
#define VERT_DUPE_TEST_ORIG(v)
static bool bm_loop_is_radial_boundary(BMLoop *l_first)
ccl_gpu_kernel_postfix ccl_global float int int int int float bool int offset
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:27
void *(* MEM_mallocN)(size_t len, const char *str)
Definition: mallocn.c:33
short mat_nr
Definition: bmesh_class.h:281
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
float no[3]
Definition: bmesh_class.h:88
int totvert
Definition: bmesh_class.h:297
char elem_index_dirty
Definition: bmesh_class.h:305
CustomData vdata
Definition: bmesh_class.h:337
CustomData edata
Definition: bmesh_class.h:337