Blender  V2.93
blenkernel/intern/mesh_mirror.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  * The Original Code is Copyright (C) Blender Foundation.
17  * All rights reserved.
18  */
19 
24 #include "BLI_math.h"
25 
26 #include "DNA_mesh_types.h"
27 #include "DNA_meshdata_types.h"
28 #include "DNA_object_types.h"
29 
30 #include "BKE_deform.h"
31 #include "BKE_lib_id.h"
32 #include "BKE_lib_query.h"
33 #include "BKE_mesh.h"
34 #include "BKE_mesh_mirror.h"
35 #include "BKE_modifier.h"
36 
37 #include "bmesh.h"
38 #include "bmesh_tools.h"
39 
40 #include "MEM_guardedalloc.h"
41 
42 #include "MOD_modifiertypes.h"
43 
45  const Mesh *mesh,
46  int axis,
47  const float plane_co[3],
48  float plane_no[3])
49 {
50  bool do_bisect_flip_axis = ((axis == 0 && mmd->flag & MOD_MIR_BISECT_FLIP_AXIS_X) ||
51  (axis == 1 && mmd->flag & MOD_MIR_BISECT_FLIP_AXIS_Y) ||
52  (axis == 2 && mmd->flag & MOD_MIR_BISECT_FLIP_AXIS_Z));
53 
54  const float bisect_distance = mmd->bisect_threshold;
55 
56  Mesh *result;
57  BMesh *bm;
58  BMIter viter;
59  BMVert *v, *v_next;
60 
62  &(struct BMeshCreateParams){0},
63  &(struct BMeshFromMeshParams){
64  .calc_face_normal = true,
65  .cd_mask_extra = {.vmask = CD_MASK_ORIGINDEX,
66  .emask = CD_MASK_ORIGINDEX,
67  .pmask = CD_MASK_ORIGINDEX},
68  });
69 
70  /* Define bisecting plane (aka mirror plane). */
71  float plane[4];
72  if (!do_bisect_flip_axis) {
73  /* That reversed condition is a tad weird, but for some reason that's how you keep
74  * the part of the mesh which is on the non-mirrored side when flip option is disabled,
75  * think that that is the expected behavior. */
76  negate_v3(plane_no);
77  }
78  plane_from_point_normal_v3(plane, plane_co, plane_no);
79 
80  BM_mesh_bisect_plane(bm, plane, true, false, 0, 0, bisect_distance);
81 
82  /* Plane definitions for vert killing. */
83  float plane_offset[4];
84  copy_v3_v3(plane_offset, plane);
85  plane_offset[3] = plane[3] - bisect_distance;
86 
87  /* Delete verts across the mirror plane. */
88  BM_ITER_MESH_MUTABLE (v, v_next, &viter, bm, BM_VERTS_OF_MESH) {
89  if (plane_point_side_v3(plane_offset, v->co) > 0.0f) {
90  BM_vert_kill(bm, v);
91  }
92  }
93 
96 
97  return result;
98 }
99 
101  Mesh *mesh,
102  const int axis,
103  const float dist)
104 {
106  &(struct BMeshCreateParams){
107  .use_toolflags = 1,
108  },
109  &(struct BMeshFromMeshParams){
110  .calc_face_normal = true,
111  .cd_mask_extra =
112  {
113  .vmask = CD_MASK_SHAPEKEY,
114  },
115  });
118  "symmetrize input=%avef direction=%i dist=%f use_shapekey=%b",
119  axis,
120  dist,
121  true);
122 
123  BM_mesh_bm_to_me(bmain,
124  bm,
125  mesh,
126  (&(struct BMeshToMeshParams){
127  .calc_object_remap = true,
128 
129  }));
130  BM_mesh_free(bm);
131 }
132 
138  Object *ob,
139  const Mesh *mesh,
140  const int axis)
141 {
142  const float tolerance_sq = mmd->tolerance * mmd->tolerance;
143  const bool do_vtargetmap = (mmd->flag & MOD_MIR_NO_MERGE) == 0;
144  int tot_vtargetmap = 0; /* total merge vertices */
145 
146  const bool do_bisect = ((axis == 0 && mmd->flag & MOD_MIR_BISECT_AXIS_X) ||
147  (axis == 1 && mmd->flag & MOD_MIR_BISECT_AXIS_Y) ||
148  (axis == 2 && mmd->flag & MOD_MIR_BISECT_AXIS_Z));
149 
150  Mesh *result;
151  MVert *mv, *mv_prev;
152  MEdge *me;
153  MLoop *ml;
154  MPoly *mp;
155  float mtx[4][4];
156  float plane_co[3], plane_no[3];
157  int i;
158  int a, totshape;
159  int *vtargetmap = NULL, *vtmap_a = NULL, *vtmap_b = NULL;
160 
161  /* mtx is the mirror transformation */
162  unit_m4(mtx);
163  mtx[axis][axis] = -1.0f;
164 
165  Object *mirror_ob = mmd->mirror_ob;
166  if (mirror_ob != NULL) {
167  float tmp[4][4];
168  float itmp[4][4];
169 
170  /* tmp is a transform from coords relative to the object's own origin,
171  * to coords relative to the mirror object origin */
172  invert_m4_m4(tmp, mirror_ob->obmat);
173  mul_m4_m4m4(tmp, tmp, ob->obmat);
174 
175  /* itmp is the reverse transform back to origin-relative coordinates */
176  invert_m4_m4(itmp, tmp);
177 
178  /* combine matrices to get a single matrix that translates coordinates into
179  * mirror-object-relative space, does the mirror, and translates back to
180  * origin-relative space */
181  mul_m4_series(mtx, itmp, mtx, tmp);
182 
183  if (do_bisect) {
184  copy_v3_v3(plane_co, itmp[3]);
185  copy_v3_v3(plane_no, itmp[axis]);
186 
187  /* Account for non-uniform scale in `ob`, see: T87592. */
188  float ob_scale[3] = {
189  len_squared_v3(ob->obmat[0]),
190  len_squared_v3(ob->obmat[1]),
191  len_squared_v3(ob->obmat[2]),
192  };
193  /* Scale to avoid precision loss with extreme values. */
194  const float ob_scale_max = max_fff(UNPACK3(ob_scale));
195  if (LIKELY(ob_scale_max != 0.0f)) {
196  mul_v3_fl(ob_scale, 1.0f / ob_scale_max);
197  mul_v3_v3(plane_no, ob_scale);
198  }
199  }
200  }
201  else if (do_bisect) {
202  copy_v3_v3(plane_co, mtx[3]);
203  /* Need to negate here, since that axis is inverted (for mirror transform). */
204  negate_v3_v3(plane_no, mtx[axis]);
205  }
206 
207  Mesh *mesh_bisect = NULL;
208  if (do_bisect) {
210  mmd, mesh, axis, plane_co, plane_no);
211  mesh = mesh_bisect;
212  }
213 
214  const int maxVerts = mesh->totvert;
215  const int maxEdges = mesh->totedge;
216  const int maxLoops = mesh->totloop;
217  const int maxPolys = mesh->totpoly;
218 
220  mesh, maxVerts * 2, maxEdges * 2, 0, maxLoops * 2, maxPolys * 2);
221 
222  /* Copy custom-data to original geometry. */
223  CustomData_copy_data(&mesh->vdata, &result->vdata, 0, 0, maxVerts);
224  CustomData_copy_data(&mesh->edata, &result->edata, 0, 0, maxEdges);
225  CustomData_copy_data(&mesh->ldata, &result->ldata, 0, 0, maxLoops);
226  CustomData_copy_data(&mesh->pdata, &result->pdata, 0, 0, maxPolys);
227 
228  /* Subsurf for eg won't have mesh data in the custom-data arrays.
229  * now add mvert/medge/mpoly layers. */
230  if (!CustomData_has_layer(&mesh->vdata, CD_MVERT)) {
231  memcpy(result->mvert, mesh->mvert, sizeof(*result->mvert) * mesh->totvert);
232  }
233  if (!CustomData_has_layer(&mesh->edata, CD_MEDGE)) {
234  memcpy(result->medge, mesh->medge, sizeof(*result->medge) * mesh->totedge);
235  }
236  if (!CustomData_has_layer(&mesh->pdata, CD_MPOLY)) {
237  memcpy(result->mloop, mesh->mloop, sizeof(*result->mloop) * mesh->totloop);
238  memcpy(result->mpoly, mesh->mpoly, sizeof(*result->mpoly) * mesh->totpoly);
239  }
240 
241  /* Copy custom-data to new geometry,
242  * copy from its self because this data may have been created in the checks above. */
243  CustomData_copy_data(&result->vdata, &result->vdata, 0, maxVerts, maxVerts);
244  CustomData_copy_data(&result->edata, &result->edata, 0, maxEdges, maxEdges);
245  /* loops are copied later */
246  CustomData_copy_data(&result->pdata, &result->pdata, 0, maxPolys, maxPolys);
247 
248  if (do_vtargetmap) {
249  /* second half is filled with -1 */
250  vtargetmap = MEM_malloc_arrayN(maxVerts, sizeof(int[2]), "MOD_mirror tarmap");
251 
252  vtmap_a = vtargetmap;
253  vtmap_b = vtargetmap + maxVerts;
254  }
255 
256  /* mirror vertex coordinates */
257  mv_prev = result->mvert;
258  mv = mv_prev + maxVerts;
259  for (i = 0; i < maxVerts; i++, mv++, mv_prev++) {
260  mul_m4_v3(mtx, mv->co);
261 
262  if (do_vtargetmap) {
263  /* compare location of the original and mirrored vertex, to see if they
264  * should be mapped for merging */
265  if (UNLIKELY(len_squared_v3v3(mv_prev->co, mv->co) < tolerance_sq)) {
266  *vtmap_a = maxVerts + i;
267  tot_vtargetmap++;
268 
269  /* average location */
270  mid_v3_v3v3(mv->co, mv_prev->co, mv->co);
271  copy_v3_v3(mv_prev->co, mv->co);
272  }
273  else {
274  *vtmap_a = -1;
275  }
276 
277  *vtmap_b = -1; /* fill here to avoid 2x loops */
278 
279  vtmap_a++;
280  vtmap_b++;
281  }
282  }
283 
284  /* handle shape keys */
285  totshape = CustomData_number_of_layers(&result->vdata, CD_SHAPEKEY);
286  for (a = 0; a < totshape; a++) {
288  for (i = maxVerts; i < result->totvert; i++) {
289  mul_m4_v3(mtx, cos[i]);
290  }
291  }
292 
293  /* adjust mirrored edge vertex indices */
294  me = result->medge + maxEdges;
295  for (i = 0; i < maxEdges; i++, me++) {
296  me->v1 += maxVerts;
297  me->v2 += maxVerts;
298  }
299 
300  /* adjust mirrored poly loopstart indices, and reverse loop order (normals) */
301  mp = result->mpoly + maxPolys;
302  ml = result->mloop;
303  for (i = 0; i < maxPolys; i++, mp++) {
304  MLoop *ml2;
305  int j, e;
306 
307  /* reverse the loop, but we keep the first vertex in the face the same,
308  * to ensure that quads are split the same way as on the other side */
310  &result->ldata, &result->ldata, mp->loopstart, mp->loopstart + maxLoops, 1);
311 
312  for (j = 1; j < mp->totloop; j++) {
314  &result->ldata,
315  mp->loopstart + j,
316  mp->loopstart + maxLoops + mp->totloop - j,
317  1);
318  }
319 
320  ml2 = ml + mp->loopstart + maxLoops;
321  e = ml2[0].e;
322  for (j = 0; j < mp->totloop - 1; j++) {
323  ml2[j].e = ml2[j + 1].e;
324  }
325  ml2[mp->totloop - 1].e = e;
326 
327  mp->loopstart += maxLoops;
328  }
329 
330  /* adjust mirrored loop vertex and edge indices */
331  ml = result->mloop + maxLoops;
332  for (i = 0; i < maxLoops; i++, ml++) {
333  ml->v += maxVerts;
334  ml->e += maxEdges;
335  }
336 
337  /* handle uvs,
338  * let tessface recalc handle updating the MTFace data */
339  if (mmd->flag & (MOD_MIR_MIRROR_U | MOD_MIR_MIRROR_V) ||
340  (is_zero_v2(mmd->uv_offset_copy) == false)) {
341  const bool do_mirr_u = (mmd->flag & MOD_MIR_MIRROR_U) != 0;
342  const bool do_mirr_v = (mmd->flag & MOD_MIR_MIRROR_V) != 0;
343  /* If set, flip around center of each tile. */
344  const bool do_mirr_udim = (mmd->flag & MOD_MIR_MIRROR_UDIM) != 0;
345 
346  const int totuv = CustomData_number_of_layers(&result->ldata, CD_MLOOPUV);
347 
348  for (a = 0; a < totuv; a++) {
349  MLoopUV *dmloopuv = CustomData_get_layer_n(&result->ldata, CD_MLOOPUV, a);
350  int j = maxLoops;
351  dmloopuv += j; /* second set of loops only */
352  for (; j-- > 0; dmloopuv++) {
353  if (do_mirr_u) {
354  float u = dmloopuv->uv[0];
355  if (do_mirr_udim) {
356  dmloopuv->uv[0] = ceilf(u) - fmodf(u, 1.0f) + mmd->uv_offset[0];
357  }
358  else {
359  dmloopuv->uv[0] = 1.0f - u + mmd->uv_offset[0];
360  }
361  }
362  if (do_mirr_v) {
363  float v = dmloopuv->uv[1];
364  if (do_mirr_udim) {
365  dmloopuv->uv[1] = ceilf(v) - fmodf(v, 1.0f) + mmd->uv_offset[1];
366  }
367  else {
368  dmloopuv->uv[1] = 1.0f - v + mmd->uv_offset[1];
369  }
370  }
371  dmloopuv->uv[0] += mmd->uv_offset_copy[0];
372  dmloopuv->uv[1] += mmd->uv_offset_copy[1];
373  }
374  }
375  }
376 
377  /* handle custom split normals */
378  if (ob->type == OB_MESH && (((Mesh *)ob->data)->flag & ME_AUTOSMOOTH) &&
380  const int totloop = result->totloop;
381  const int totpoly = result->totpoly;
382  float(*loop_normals)[3] = MEM_calloc_arrayN((size_t)totloop, sizeof(*loop_normals), __func__);
383  CustomData *ldata = &result->ldata;
384  short(*clnors)[2] = CustomData_get_layer(ldata, CD_CUSTOMLOOPNORMAL);
385  MLoopNorSpaceArray lnors_spacearr = {NULL};
386  float(*poly_normals)[3] = MEM_mallocN(sizeof(*poly_normals) * totpoly, __func__);
387 
388  /* The transform matrix of a normal must be
389  * the transpose of inverse of transform matrix of the geometry... */
390  float mtx_nor[4][4];
391  invert_m4_m4(mtx_nor, mtx);
392  transpose_m4(mtx_nor);
393 
394  /* calculate custom normals into loop_normals, then mirror first half into second half */
395 
397  NULL,
398  result->totvert,
399  result->mloop,
400  result->mpoly,
401  totloop,
402  totpoly,
403  poly_normals,
404  false);
405 
407  result->totvert,
408  result->medge,
409  result->totedge,
410  result->mloop,
411  loop_normals,
412  totloop,
413  result->mpoly,
414  poly_normals,
415  totpoly,
416  true,
417  mesh->smoothresh,
418  &lnors_spacearr,
419  clnors,
420  NULL);
421 
422  /* mirroring has to account for loops being reversed in polys in second half */
423  mp = result->mpoly;
424  for (i = 0; i < maxPolys; i++, mp++) {
425  MPoly *mpmirror = result->mpoly + maxPolys + i;
426  int j;
427 
428  for (j = mp->loopstart; j < mp->loopstart + mp->totloop; j++) {
429  int mirrorj = mpmirror->loopstart;
430  if (j > mp->loopstart) {
431  mirrorj += mpmirror->totloop - (j - mp->loopstart);
432  }
433  copy_v3_v3(loop_normals[mirrorj], loop_normals[j]);
434  mul_m4_v3(mtx_nor, loop_normals[mirrorj]);
436  lnors_spacearr.lspacearr[mirrorj], loop_normals[mirrorj], clnors[mirrorj]);
437  }
438  }
439 
440  MEM_freeN(poly_normals);
441  MEM_freeN(loop_normals);
442  BKE_lnor_spacearr_free(&lnors_spacearr);
443  }
444 
445  /* handle vgroup stuff */
446  if ((mmd->flag & MOD_MIR_VGROUP) && CustomData_has_layer(&result->vdata, CD_MDEFORMVERT)) {
448  maxVerts;
449  int *flip_map = NULL, flip_map_len = 0;
450 
451  flip_map = BKE_object_defgroup_flip_map(ob, &flip_map_len, false);
452 
453  if (flip_map) {
454  for (i = 0; i < maxVerts; dvert++, i++) {
455  /* merged vertices get both groups, others get flipped */
456  if (do_vtargetmap && (vtargetmap[i] != -1)) {
457  BKE_defvert_flip_merged(dvert, flip_map, flip_map_len);
458  }
459  else {
460  BKE_defvert_flip(dvert, flip_map, flip_map_len);
461  }
462  }
463 
464  MEM_freeN(flip_map);
465  }
466  }
467 
468  if (do_vtargetmap) {
469  /* slow - so only call if one or more merge verts are found,
470  * users may leave this on and not realize there is nothing to merge - campbell */
471  if (tot_vtargetmap) {
473  result, vtargetmap, tot_vtargetmap, MESH_MERGE_VERTS_DUMP_IF_MAPPED);
474  }
475  MEM_freeN(vtargetmap);
476  }
477 
478  if (mesh_bisect != NULL) {
479  BKE_id_free(NULL, mesh_bisect);
480  }
481 
482  return result;
483 }
typedef float(TangentPoint)[2]
int CustomData_number_of_layers(const struct CustomData *data, int type)
bool CustomData_has_layer(const struct CustomData *data, int type)
void * CustomData_get_layer_n(const struct CustomData *data, int type, int n)
void * CustomData_get_layer(const struct CustomData *data, int type)
void CustomData_copy_data(const struct CustomData *source, struct CustomData *dest, int source_index, int dest_index, int count)
support for deformation groups and hooks.
void BKE_defvert_flip_merged(struct MDeformVert *dvert, const int *flip_map, const int flip_map_len)
Definition: deform.c:462
int * BKE_object_defgroup_flip_map(const struct Object *ob, int *flip_map_len, const bool use_default)
void BKE_defvert_flip(struct MDeformVert *dvert, const int *flip_map, const int flip_map_len)
Definition: deform.c:448
void BKE_id_free(struct Main *bmain, void *idv)
struct Mesh * BKE_mesh_new_nomain_from_template(const struct Mesh *me_src, int verts_len, int edges_len, int tessface_len, int loops_len, int polys_len)
struct BMesh * BKE_mesh_to_bmesh_ex(const struct Mesh *me, const struct BMeshCreateParams *create_params, const struct BMeshFromMeshParams *convert_params)
struct Mesh * BKE_mesh_from_bmesh_for_eval_nomain(struct BMesh *bm, const struct CustomData_MeshMasks *cd_mask_extra, const struct Mesh *me_settings)
@ MESH_MERGE_VERTS_DUMP_IF_MAPPED
Definition: BKE_mesh.h:585
struct Mesh * BKE_mesh_merge_verts(struct Mesh *mesh, const int *vtargetmap, const int tot_vtargetmap, const int merge_mode)
Definition: mesh_merge.c:239
void BKE_mesh_normals_loop_split(const struct MVert *mverts, const int numVerts, struct MEdge *medges, const int numEdges, struct MLoop *mloops, float(*r_loopnors)[3], const int numLoops, struct MPoly *mpolys, const float(*polynors)[3], const int numPolys, const bool use_split_normals, const float split_angle, MLoopNorSpaceArray *r_lnors_spacearr, short(*clnors_data)[2], int *r_loop_to_poly)
void BKE_lnor_spacearr_free(MLoopNorSpaceArray *lnors_spacearr)
void BKE_mesh_calc_normals_poly(struct MVert *mverts, float(*r_vertnors)[3], int numVerts, const struct MLoop *mloop, const struct MPoly *mpolys, int numLoops, int numPolys, float(*r_polyNors)[3], const bool only_face_normals)
void BKE_lnor_space_custom_normal_to_data(MLoopNorSpace *lnor_space, const float custom_lnor[3], short r_clnor_data[2])
MINLINE float max_fff(float a, float b, float c)
void plane_from_point_normal_v3(float r_plane[4], const float plane_co[3], const float plane_no[3])
Definition: math_geom.c:243
MINLINE float plane_point_side_v3(const float plane[4], const float co[3])
void mul_m4_m4m4(float R[4][4], const float A[4][4], const float B[4][4])
Definition: math_matrix.c:262
void unit_m4(float m[4][4])
Definition: rct.c:1140
bool invert_m4_m4(float R[4][4], const float A[4][4])
Definition: math_matrix.c:1278
void mul_m4_v3(const float M[4][4], float r[3])
Definition: math_matrix.c:732
#define mul_m4_series(...)
void transpose_m4(float R[4][4])
Definition: math_matrix.c:1358
MINLINE float len_squared_v3(const float v[3]) ATTR_WARN_UNUSED_RESULT
MINLINE void mul_v3_v3(float r[3], const float a[3])
MINLINE float len_squared_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT
MINLINE void mul_v3_fl(float r[3], float f)
MINLINE void copy_v3_v3(float r[3], const float a[3])
MINLINE void negate_v3_v3(float r[3], const float a[3])
MINLINE void negate_v3(float r[3])
void mid_v3_v3v3(float r[3], const float a[3], const float b[3])
Definition: math_vector.c:270
MINLINE bool is_zero_v2(const float a[3]) ATTR_WARN_UNUSED_RESULT
#define UNPACK3(a)
#define UNLIKELY(x)
#define LIKELY(x)
#define CD_MASK_ORIGINDEX
@ CD_CUSTOMLOOPNORMAL
@ CD_MDEFORMVERT
@ CD_SHAPEKEY
@ CD_MVERT
@ CD_MLOOPUV
#define CD_MASK_SHAPEKEY
@ ME_AUTOSMOOTH
@ MOD_MIR_BISECT_AXIS_Z
@ MOD_MIR_MIRROR_U
@ MOD_MIR_BISECT_AXIS_X
@ MOD_MIR_MIRROR_V
@ MOD_MIR_BISECT_FLIP_AXIS_X
@ MOD_MIR_VGROUP
@ MOD_MIR_BISECT_AXIS_Y
@ MOD_MIR_BISECT_FLIP_AXIS_Z
@ MOD_MIR_NO_MERGE
@ MOD_MIR_BISECT_FLIP_AXIS_Y
@ MOD_MIR_MIRROR_UDIM
Object is a sort of wrapper for general info.
@ OB_MESH
Read Guarded memory(de)allocation.
Mesh * BKE_mesh_mirror_bisect_on_mirror_plane_for_modifier(MirrorModifierData *mmd, const Mesh *mesh, int axis, const float plane_co[3], float plane_no[3])
Mesh * BKE_mesh_mirror_apply_mirror_on_axis_for_modifier(MirrorModifierData *mmd, Object *ob, const Mesh *mesh, const int axis)
void BKE_mesh_mirror_apply_mirror_on_axis(struct Main *bmain, Mesh *mesh, const int axis, const float dist)
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)
void BM_vert_kill(BMesh *bm, BMVert *v)
Definition: bmesh_core.c:1002
@ BM_VERTS_OF_MESH
#define BM_ITER_MESH_MUTABLE(ele, ele_next, iter, bm, itype)
ATTR_WARN_UNUSED_RESULT BMesh * bm
void BM_mesh_free(BMesh *bm)
BMesh Free Mesh.
Definition: bmesh_mesh.c:307
void BM_mesh_bm_to_me(Main *bmain, BMesh *bm, Mesh *me, const struct BMeshToMeshParams *params)
#define BMO_FLAG_DEFAULTS
@ BMO_FLAG_RESPECT_HIDE
bool BMO_op_callf(BMesh *bm, const int flag, const char *fmt,...)
ATTR_WARN_UNUSED_RESULT const BMVert const BMEdge * e
ATTR_WARN_UNUSED_RESULT const BMVert * v
#define ceilf(x)
#define fmodf(x, y)
void *(* MEM_malloc_arrayN)(size_t len, size_t size, const char *str)
Definition: mallocn.c:48
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:41
void *(* MEM_calloc_arrayN)(size_t len, size_t size, const char *str)
Definition: mallocn.c:46
void *(* MEM_mallocN)(size_t len, const char *str)
Definition: mallocn.c:47
static unsigned a[3]
Definition: RandGen.cpp:92
INLINE Rall1d< T, V, S > cos(const Rall1d< T, V, S > &arg)
Definition: rall1d.h:319
float co[3]
Definition: bmesh_class.h:99
unsigned int v1
unsigned int v2
MLoopNorSpace ** lspacearr
Definition: BKE_mesh.h:372
unsigned int e
unsigned int v
float co[3]
Definition: BKE_main.h:116
struct MEdge * medge
float smoothresh
struct CustomData pdata ldata
struct MVert * mvert
int totedge
int totvert
struct MLoop * mloop
int totpoly
int totloop
struct MPoly * mpoly
struct Object * mirror_ob
float obmat[4][4]
void * data