Blender  V3.3
obj_export_mesh.cc
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2 
6 /* Silence warnings from copying deprecated fields. Needed for an Object copy constructor use. */
7 #define DNA_DEPRECATED_ALLOW
8 
9 #include "BKE_customdata.h"
10 #include "BKE_deform.h"
11 #include "BKE_lib_id.h"
12 #include "BKE_material.h"
13 #include "BKE_mesh.h"
14 #include "BKE_mesh_mapping.h"
15 #include "BKE_object.h"
16 
17 #include "BLI_listbase.h"
18 #include "BLI_map.hh"
19 #include "BLI_math.h"
20 #include "BLI_sort.hh"
21 
22 #include "DEG_depsgraph_query.h"
23 
24 #include "DNA_material_types.h"
25 #include "DNA_mesh_types.h"
26 #include "DNA_modifier_types.h"
27 #include "DNA_object_types.h"
28 
29 #include "obj_export_mesh.hh"
30 
31 namespace blender::io::obj {
32 OBJMesh::OBJMesh(Depsgraph *depsgraph, const OBJExportParams &export_params, Object *mesh_object)
33 {
34  /* We need to copy the object because it may be in temporary space. */
35  Object *obj_eval = DEG_get_evaluated_object(depsgraph, mesh_object);
36  export_object_eval_ = dna::shallow_copy(*obj_eval);
37  export_mesh_eval_ = export_params.apply_modifiers ?
38  BKE_object_get_evaluated_mesh(&export_object_eval_) :
39  BKE_object_get_pre_modified_mesh(&export_object_eval_);
40  mesh_eval_needs_free_ = false;
41 
42  if (!export_mesh_eval_) {
43  /* Curves and NURBS surfaces need a new mesh when they're
44  * exported in the form of vertices and edges.
45  */
46  export_mesh_eval_ = BKE_mesh_new_from_object(depsgraph, &export_object_eval_, true, true);
47  /* Since a new mesh been allocated, it needs to be freed in the destructor. */
48  mesh_eval_needs_free_ = true;
49  }
50  if (export_params.export_triangulated_mesh && ELEM(export_object_eval_.type, OB_MESH, OB_SURF)) {
51  std::tie(export_mesh_eval_, mesh_eval_needs_free_) = triangulate_mesh_eval();
52  }
53  set_world_axes_transform(export_params.forward_axis, export_params.up_axis);
54 }
55 
60 {
61  clear();
62 }
63 
64 void OBJMesh::free_mesh_if_needed()
65 {
66  if (mesh_eval_needs_free_ && export_mesh_eval_) {
67  BKE_id_free(nullptr, export_mesh_eval_);
68  export_mesh_eval_ = nullptr;
69  mesh_eval_needs_free_ = false;
70  }
71 }
72 
74 {
75  free_mesh_if_needed();
76  uv_indices_.clear_and_make_inline();
77  uv_coords_.clear_and_make_inline();
78  loop_to_normal_index_.clear_and_make_inline();
79  normal_coords_.clear_and_make_inline();
80  poly_order_.clear_and_make_inline();
81  if (poly_smooth_groups_) {
82  MEM_freeN(poly_smooth_groups_);
83  poly_smooth_groups_ = nullptr;
84  }
85 }
86 
87 std::pair<Mesh *, bool> OBJMesh::triangulate_mesh_eval()
88 {
89  if (export_mesh_eval_->totpoly <= 0) {
90  return {export_mesh_eval_, false};
91  }
92  const BMeshCreateParams bm_create_params = {false};
93  BMeshFromMeshParams bm_convert_params{};
94  bm_convert_params.calc_face_normal = true;
95  bm_convert_params.calc_vert_normal = true;
96  bm_convert_params.add_key_index = false;
97  bm_convert_params.use_shapekey = false;
98 
99  /* Lower threshold where triangulation of a polygon starts, i.e. a quadrilateral will be
100  * triangulated here. */
101  const int triangulate_min_verts = 4;
102 
103  unique_bmesh_ptr bmesh(
104  BKE_mesh_to_bmesh_ex(export_mesh_eval_, &bm_create_params, &bm_convert_params));
105  BM_mesh_triangulate(bmesh.get(),
108  triangulate_min_verts,
109  false,
110  nullptr,
111  nullptr,
112  nullptr);
113 
115  bmesh.get(), nullptr, export_mesh_eval_);
116  free_mesh_if_needed();
117  return {triangulated, true};
118 }
119 
120 void OBJMesh::set_world_axes_transform(const eIOAxis forward, const eIOAxis up)
121 {
122  float axes_transform[3][3];
123  unit_m3(axes_transform);
124  /* +Y-forward and +Z-up are the default Blender axis settings. */
125  mat3_from_axis_conversion(forward, up, IO_AXIS_Y, IO_AXIS_Z, axes_transform);
126  mul_m4_m3m4(world_and_axes_transform_, axes_transform, export_object_eval_.obmat);
127  /* mul_m4_m3m4 does not transform last row of obmat, i.e. location data. */
128  mul_v3_m3v3(world_and_axes_transform_[3], axes_transform, export_object_eval_.obmat[3]);
129  world_and_axes_transform_[3][3] = export_object_eval_.obmat[3][3];
130 
131  /* Normals need inverse transpose of the regular matrix to handle non-uniform scale. */
132  float normal_matrix[3][3];
133  copy_m3_m4(normal_matrix, world_and_axes_transform_);
134  invert_m3_m3(world_and_axes_normal_transform_, normal_matrix);
135  transpose_m3(world_and_axes_normal_transform_);
136  mirrored_transform_ = determinant_m3_array(world_and_axes_normal_transform_) < 0;
137 }
138 
140 {
141  return export_mesh_eval_->totvert;
142 }
143 
145 {
146  return export_mesh_eval_->totpoly;
147 }
148 
150 {
151  return tot_uv_vertices_;
152 }
153 
155 {
156  return export_mesh_eval_->totedge;
157 }
158 
160 {
161  return export_mesh_eval_->totcol;
162 }
163 
165 {
166  return tot_normal_indices_;
167 }
168 
169 int OBJMesh::ith_smooth_group(const int poly_index) const
170 {
171  /* Calculate smooth groups first: #OBJMesh::calc_smooth_groups. */
172  BLI_assert(tot_smooth_groups_ != -NEGATIVE_INIT);
173  BLI_assert(poly_smooth_groups_);
174  return poly_smooth_groups_[poly_index];
175 }
176 
178 {
179  BKE_mesh_calc_normals_split(export_mesh_eval_);
180 }
181 
183 {
184  BKE_mesh_calc_edges(export_mesh_eval_, true, false);
185  BKE_mesh_calc_edges_loose(export_mesh_eval_);
186 }
187 
188 void OBJMesh::calc_smooth_groups(const bool use_bitflags)
189 {
190  poly_smooth_groups_ = BKE_mesh_calc_smoothgroups(export_mesh_eval_->medge,
191  export_mesh_eval_->totedge,
192  export_mesh_eval_->mpoly,
193  export_mesh_eval_->totpoly,
194  export_mesh_eval_->mloop,
195  export_mesh_eval_->totloop,
196  &tot_smooth_groups_,
197  use_bitflags);
198 }
199 
201 {
202  const int tot_polys = tot_polygons();
203  poly_order_.resize(tot_polys);
204  for (int i = 0; i < tot_polys; ++i) {
205  poly_order_[i] = i;
206  }
207  const MPoly *mpolys = export_mesh_eval_->mpoly;
208  /* Sort polygons by their material index. */
209  blender::parallel_sort(poly_order_.begin(), poly_order_.end(), [&](int a, int b) {
210  int mat_a = mpolys[a].mat_nr;
211  int mat_b = mpolys[b].mat_nr;
212  if (mat_a != mat_b) {
213  return mat_a < mat_b;
214  }
215  return a < b;
216  });
217 }
218 
219 const Material *OBJMesh::get_object_material(const int16_t mat_nr) const
220 {
227  Object *obj = const_cast<Object *>(&export_object_eval_);
228  const Material *r_mat = BKE_object_material_get_eval(obj, mat_nr + 1);
229  return r_mat;
230 }
231 
232 bool OBJMesh::is_ith_poly_smooth(const int poly_index) const
233 {
234  return export_mesh_eval_->mpoly[poly_index].flag & ME_SMOOTH;
235 }
236 
237 int16_t OBJMesh::ith_poly_matnr(const int poly_index) const
238 {
239  BLI_assert(poly_index < export_mesh_eval_->totpoly);
240  const int16_t r_mat_nr = export_mesh_eval_->mpoly[poly_index].mat_nr;
241  return r_mat_nr >= 0 ? r_mat_nr : NOT_FOUND;
242 }
243 
244 const char *OBJMesh::get_object_name() const
245 {
246  return export_object_eval_.id.name + 2;
247 }
248 
249 const char *OBJMesh::get_object_mesh_name() const
250 {
251  return export_mesh_eval_->id.name + 2;
252 }
253 
254 const char *OBJMesh::get_object_material_name(const int16_t mat_nr) const
255 {
256  const Material *mat = get_object_material(mat_nr);
257  if (!mat) {
258  return nullptr;
259  }
260  return mat->id.name + 2;
261 }
262 
263 float3 OBJMesh::calc_vertex_coords(const int vert_index, const float scaling_factor) const
264 {
265  float3 r_coords;
266  copy_v3_v3(r_coords, export_mesh_eval_->mvert[vert_index].co);
267  mul_m4_v3(world_and_axes_transform_, r_coords);
268  mul_v3_fl(r_coords, scaling_factor);
269  return r_coords;
270 }
271 
272 Vector<int> OBJMesh::calc_poly_vertex_indices(const int poly_index) const
273 {
274  const MPoly &mpoly = export_mesh_eval_->mpoly[poly_index];
275  const MLoop *mloop = &export_mesh_eval_->mloop[mpoly.loopstart];
276  const int totloop = mpoly.totloop;
277  Vector<int> r_poly_vertex_indices(totloop);
278  for (int loop_index = 0; loop_index < totloop; loop_index++) {
279  r_poly_vertex_indices[loop_index] = mloop[loop_index].v;
280  }
281  return r_poly_vertex_indices;
282 }
283 
284 void OBJMesh::store_uv_coords_and_indices()
285 {
286  const MPoly *mpoly = export_mesh_eval_->mpoly;
287  const MLoop *mloop = export_mesh_eval_->mloop;
288  const int totpoly = export_mesh_eval_->totpoly;
289  const int totvert = export_mesh_eval_->totvert;
290  const MLoopUV *mloopuv = static_cast<const MLoopUV *>(
291  CustomData_get_layer(&export_mesh_eval_->ldata, CD_MLOOPUV));
292  if (!mloopuv) {
293  tot_uv_vertices_ = 0;
294  return;
295  }
296  const float limit[2] = {STD_UV_CONNECT_LIMIT, STD_UV_CONNECT_LIMIT};
297 
298  UvVertMap *uv_vert_map = BKE_mesh_uv_vert_map_create(
299  mpoly, mloop, mloopuv, totpoly, totvert, limit, false, false);
300 
301  uv_indices_.resize(totpoly);
302  /* At least total vertices of a mesh will be present in its texture map. So
303  * reserve minimum space early. */
304  uv_coords_.reserve(totvert);
305 
306  tot_uv_vertices_ = 0;
307  for (int vertex_index = 0; vertex_index < totvert; vertex_index++) {
308  const UvMapVert *uv_vert = BKE_mesh_uv_vert_map_get_vert(uv_vert_map, vertex_index);
309  for (; uv_vert; uv_vert = uv_vert->next) {
310  if (uv_vert->separate) {
311  tot_uv_vertices_ += 1;
312  }
313  const int vertices_in_poly = mpoly[uv_vert->poly_index].totloop;
314 
315  /* Store UV vertex coordinates. */
316  uv_coords_.resize(tot_uv_vertices_);
317  const int loopstart = mpoly[uv_vert->poly_index].loopstart;
318  Span<float> vert_uv_coords(mloopuv[loopstart + uv_vert->loop_of_poly_index].uv, 2);
319  uv_coords_[tot_uv_vertices_ - 1] = float2(vert_uv_coords[0], vert_uv_coords[1]);
320 
321  /* Store UV vertex indices. */
322  uv_indices_[uv_vert->poly_index].resize(vertices_in_poly);
323  /* Keep indices zero-based and let the writer handle the "+ 1" as per OBJ spec. */
324  uv_indices_[uv_vert->poly_index][uv_vert->loop_of_poly_index] = tot_uv_vertices_ - 1;
325  }
326  }
327  BKE_mesh_uv_vert_map_free(uv_vert_map);
328 }
329 
330 Span<int> OBJMesh::calc_poly_uv_indices(const int poly_index) const
331 {
332  if (uv_indices_.size() <= 0) {
333  return {};
334  }
335  BLI_assert(poly_index < export_mesh_eval_->totpoly);
336  BLI_assert(poly_index < uv_indices_.size());
337  return uv_indices_[poly_index];
338 }
339 
340 float3 OBJMesh::calc_poly_normal(const int poly_index) const
341 {
342  float3 r_poly_normal;
343  const MPoly &poly = export_mesh_eval_->mpoly[poly_index];
344  const MLoop &mloop = export_mesh_eval_->mloop[poly.loopstart];
345  const MVert &mvert = *(export_mesh_eval_->mvert);
346  BKE_mesh_calc_poly_normal(&poly, &mloop, &mvert, r_poly_normal);
347  mul_m3_v3(world_and_axes_normal_transform_, r_poly_normal);
348  normalize_v3(r_poly_normal);
349  return r_poly_normal;
350 }
351 
353 static float round_float_to_n_digits(const float f, int round_digits)
354 {
355  float scale = powf(10.0, round_digits);
356  return ceilf((scale * f - 0.49999999f)) / scale;
357 }
358 
359 static float3 round_float3_to_n_digits(const float3 &v, int round_digits)
360 {
361  float3 ans;
362  ans.x = round_float_to_n_digits(v.x, round_digits);
363  ans.y = round_float_to_n_digits(v.y, round_digits);
364  ans.z = round_float_to_n_digits(v.z, round_digits);
365  return ans;
366 }
367 
368 void OBJMesh::store_normal_coords_and_indices()
369 {
370  /* We'll round normal components to 4 digits.
371  * This will cover up some minor differences
372  * between floating point calculations on different platforms.
373  * Since normals are normalized, there will be no perceptible loss
374  * of precision when rounding to 4 digits. */
375  constexpr int round_digits = 4;
376  int cur_normal_index = 0;
377  Map<float3, int> normal_to_index;
378  /* We don't know how many unique normals there will be, but this is a guess. */
379  normal_to_index.reserve(export_mesh_eval_->totpoly);
380  loop_to_normal_index_.resize(export_mesh_eval_->totloop);
381  loop_to_normal_index_.fill(-1);
382  const float(*lnors)[3] = static_cast<const float(*)[3]>(
383  CustomData_get_layer(&export_mesh_eval_->ldata, CD_NORMAL));
384  for (int poly_index = 0; poly_index < export_mesh_eval_->totpoly; ++poly_index) {
385  const MPoly &mpoly = export_mesh_eval_->mpoly[poly_index];
386  bool need_per_loop_normals = lnors != nullptr || (mpoly.flag & ME_SMOOTH);
387  if (need_per_loop_normals) {
388  for (int loop_of_poly = 0; loop_of_poly < mpoly.totloop; ++loop_of_poly) {
389  float3 loop_normal;
390  int loop_index = mpoly.loopstart + loop_of_poly;
391  BLI_assert(loop_index < export_mesh_eval_->totloop);
392  copy_v3_v3(loop_normal, lnors[loop_index]);
393  mul_m3_v3(world_and_axes_normal_transform_, loop_normal);
394  normalize_v3(loop_normal);
395  float3 rounded_loop_normal = round_float3_to_n_digits(loop_normal, round_digits);
396  int loop_norm_index = normal_to_index.lookup_default(rounded_loop_normal, -1);
397  if (loop_norm_index == -1) {
398  loop_norm_index = cur_normal_index++;
399  normal_to_index.add(rounded_loop_normal, loop_norm_index);
400  normal_coords_.append(rounded_loop_normal);
401  }
402  loop_to_normal_index_[loop_index] = loop_norm_index;
403  }
404  }
405  else {
406  float3 poly_normal = calc_poly_normal(poly_index);
407  float3 rounded_poly_normal = round_float3_to_n_digits(poly_normal, round_digits);
408  int poly_norm_index = normal_to_index.lookup_default(rounded_poly_normal, -1);
409  if (poly_norm_index == -1) {
410  poly_norm_index = cur_normal_index++;
411  normal_to_index.add(rounded_poly_normal, poly_norm_index);
412  normal_coords_.append(rounded_poly_normal);
413  }
414  for (int i = 0; i < mpoly.totloop; ++i) {
415  int loop_index = mpoly.loopstart + i;
416  BLI_assert(loop_index < export_mesh_eval_->totloop);
417  loop_to_normal_index_[loop_index] = poly_norm_index;
418  }
419  }
420  }
421  tot_normal_indices_ = cur_normal_index;
422 }
423 
424 Vector<int> OBJMesh::calc_poly_normal_indices(const int poly_index) const
425 {
426  if (loop_to_normal_index_.is_empty()) {
427  return {};
428  }
429  const MPoly &mpoly = export_mesh_eval_->mpoly[poly_index];
430  const int totloop = mpoly.totloop;
431  Vector<int> r_poly_normal_indices(totloop);
432  for (int poly_loop_index = 0; poly_loop_index < totloop; poly_loop_index++) {
433  int loop_index = mpoly.loopstart + poly_loop_index;
434  r_poly_normal_indices[poly_loop_index] = loop_to_normal_index_[loop_index];
435  }
436  return r_poly_normal_indices;
437 }
438 
439 int OBJMesh::tot_deform_groups() const
440 {
441  if (!BKE_object_supports_vertex_groups(&export_object_eval_)) {
442  return 0;
443  }
444  return BKE_object_defgroup_count(&export_object_eval_);
445 }
446 
447 int16_t OBJMesh::get_poly_deform_group_index(const int poly_index,
448  MutableSpan<float> group_weights) const
449 {
450  BLI_assert(poly_index < export_mesh_eval_->totpoly);
451  BLI_assert(group_weights.size() == BKE_object_defgroup_count(&export_object_eval_));
452 
453  const MDeformVert *dvert_layer = static_cast<const MDeformVert *>(
454  CustomData_get_layer(&export_mesh_eval_->vdata, CD_MDEFORMVERT));
455  if (!dvert_layer) {
456  return NOT_FOUND;
457  }
458 
459  group_weights.fill(0);
460  bool found_any_group = false;
461  const MPoly &mpoly = export_mesh_eval_->mpoly[poly_index];
462  const MLoop *mloop = &export_mesh_eval_->mloop[mpoly.loopstart];
463  for (int loop_i = 0; loop_i < mpoly.totloop; ++loop_i, ++mloop) {
464  const MDeformVert &dvert = dvert_layer[mloop->v];
465  for (int weight_i = 0; weight_i < dvert.totweight; ++weight_i) {
466  const auto group = dvert.dw[weight_i].def_nr;
467  if (group < group_weights.size()) {
468  group_weights[group] += dvert.dw[weight_i].weight;
469  found_any_group = true;
470  }
471  }
472  }
473 
474  if (!found_any_group) {
475  return NOT_FOUND;
476  }
477  /* Index of the group with maximum vertices. */
478  int16_t max_idx = std::max_element(group_weights.begin(), group_weights.end()) -
479  group_weights.begin();
480  return max_idx;
481 }
482 
483 const char *OBJMesh::get_poly_deform_group_name(const int16_t def_group_index) const
484 {
485  const bDeformGroup &vertex_group = *(static_cast<bDeformGroup *>(
486  BLI_findlink(BKE_object_defgroup_list(&export_object_eval_), def_group_index)));
487  return vertex_group.name;
488 }
489 
490 std::optional<std::array<int, 2>> OBJMesh::calc_loose_edge_vert_indices(const int edge_index) const
491 {
492  const MEdge &edge = export_mesh_eval_->medge[edge_index];
493  if (edge.flag & ME_LOOSEEDGE) {
494  return std::array<int, 2>{static_cast<int>(edge.v1), static_cast<int>(edge.v2)};
495  }
496  return std::nullopt;
497 }
498 } // namespace blender::io::obj
typedef float(TangentPoint)[2]
CustomData interface, see also DNA_customdata_types.h.
void * CustomData_get_layer(const struct CustomData *data, int type)
support for deformation groups and hooks.
bool BKE_object_supports_vertex_groups(const struct Object *ob)
const struct ListBase * BKE_object_defgroup_list(const struct Object *ob)
int BKE_object_defgroup_count(const struct Object *ob)
void BKE_id_free(struct Main *bmain, void *idv)
General operations, lookup, etc. for materials.
struct Material * BKE_object_material_get_eval(struct Object *ob, short act)
Definition: material.c:707
void BKE_mesh_calc_edges_loose(struct Mesh *mesh)
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)
void BKE_mesh_calc_poly_normal(const struct MPoly *mpoly, const struct MLoop *loopstart, const struct MVert *mvarray, float r_no[3])
void BKE_mesh_calc_normals_split(struct Mesh *mesh)
Definition: mesh.cc:1911
struct Mesh * BKE_mesh_new_from_object(struct Depsgraph *depsgraph, struct Object *object, bool preserve_all_data_layers, bool preserve_origindex)
void BKE_mesh_calc_edges(struct Mesh *mesh, bool keep_existing_edges, bool select_new_edges)
UvMapVert * BKE_mesh_uv_vert_map_get_vert(UvVertMap *vmap, unsigned int v)
Definition: mesh_mapping.c:162
int * BKE_mesh_calc_smoothgroups(const struct MEdge *medge, int totedge, const struct MPoly *mpoly, int totpoly, const struct MLoop *mloop, int totloop, int *r_totgroup, bool use_bitflags)
UvVertMap * BKE_mesh_uv_vert_map_create(const struct MPoly *mpoly, const struct MLoop *mloop, const struct MLoopUV *mloopuv, unsigned int totpoly, unsigned int totvert, const float limit[2], bool selected, bool use_winding)
void BKE_mesh_uv_vert_map_free(UvVertMap *vmap)
Definition: mesh_mapping.c:167
#define STD_UV_CONNECT_LIMIT
General operations, lookup, etc. for blender objects.
struct Mesh * BKE_object_get_pre_modified_mesh(const struct Object *object)
struct Mesh * BKE_object_get_evaluated_mesh(const struct Object *object)
#define BLI_assert(a)
Definition: BLI_assert.h:46
void * BLI_findlink(const struct ListBase *listbase, int number) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
void mul_m3_v3(const float M[3][3], float r[3])
Definition: math_matrix.c:926
void unit_m3(float m[3][3])
Definition: math_matrix.c:40
void copy_m3_m4(float m1[3][3], const float m2[4][4])
Definition: math_matrix.c:87
void mul_m4_v3(const float M[4][4], float r[3])
Definition: math_matrix.c:729
bool invert_m3_m3(float R[3][3], const float A[3][3])
Definition: math_matrix.c:1180
float determinant_m3_array(const float m[3][3])
Definition: math_matrix.c:1098
void mul_v3_m3v3(float r[3], const float M[3][3], const float a[3])
Definition: math_matrix.c:897
void transpose_m3(float R[3][3])
Definition: math_matrix.c:1332
void mul_m4_m3m4(float R[4][4], const float A[3][3], const float B[4][4])
Definition: math_matrix.c:500
bool mat3_from_axis_conversion(int src_forward, int src_up, int dst_forward, int dst_up, float r_mat[3][3])
MINLINE float normalize_v3(float r[3])
MINLINE void mul_v3_fl(float r[3], float f)
MINLINE void copy_v3_v3(float r[3], const float a[3])
#define ELEM(...)
struct Depsgraph Depsgraph
Definition: DEG_depsgraph.h:35
struct Object * DEG_get_evaluated_object(const struct Depsgraph *depsgraph, struct Object *object)
@ CD_MDEFORMVERT
@ CD_MLOOPUV
@ ME_SMOOTH
@ ME_LOOSEEDGE
@ MOD_TRIANGULATE_NGON_BEAUTY
@ MOD_TRIANGULATE_QUAD_SHORTEDGE
Object is a sort of wrapper for general info.
@ OB_SURF
@ OB_MESH
eIOAxis
Definition: IO_orientation.h:7
@ IO_AXIS_Y
Definition: IO_orientation.h:9
@ IO_AXIS_Z
ATTR_WARN_UNUSED_RESULT const BMVert * v
void BM_mesh_triangulate(BMesh *bm, const int quad_method, const int ngon_method, const int min_vertices, const bool tag_only, BMOperator *op, BMOpSlot *slot_facemap_out, BMOpSlot *slot_facemap_double_out)
bool add(const Key &key, const Value &value)
Definition: BLI_map.hh:250
Value lookup_default(const Key &key, const Value &default_value) const
Definition: BLI_map.hh:510
void reserve(int64_t n)
Definition: BLI_map.hh:953
constexpr int64_t size() const
Definition: BLI_span.hh:511
constexpr T * end() const
Definition: BLI_span.hh:557
constexpr void fill(const T &value)
Definition: BLI_span.hh:527
constexpr T * begin() const
Definition: BLI_span.hh:553
void resize(const int64_t new_size)
Definition: BLI_vector.hh:353
void clear_and_make_inline()
Definition: BLI_vector.hh:414
int ith_smooth_group(int poly_index) const
void calc_smooth_groups(bool use_bitflags)
OBJMesh(Depsgraph *depsgraph, const OBJExportParams &export_params, Object *mesh_object)
#define powf(x, y)
Definition: cuda/compat.h:103
const Depsgraph * depsgraph
#define NOT_FOUND
Definition: dynamicpaint.c:106
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:27
#define ceilf(x)
Definition: metal/compat.h:225
static unsigned a[3]
Definition: RandGen.cpp:78
static float round_float_to_n_digits(const float f, int round_digits)
const int NEGATIVE_INIT
std::unique_ptr< BMesh, CustomBMeshDeleter > unique_bmesh_ptr
static float3 round_float3_to_n_digits(const float3 &v, int round_digits)
void parallel_sort(RandomAccessIterator begin, RandomAccessIterator end)
Definition: BLI_sort.hh:21
vec_base< float, 2 > float2
static const pxr::TfToken b("b", pxr::TfToken::Immortal)
signed short int16_t
Definition: stdint.h:76
char name[66]
Definition: DNA_ID.h:378
struct MDeformWeight * dw
unsigned int def_nr
unsigned int v
struct MEdge * medge
int totedge
int totvert
struct MLoop * mloop
int totpoly
short totcol
int totloop
struct MPoly * mpoly
float obmat[4][4]
struct UvMapVert * next
unsigned short loop_of_poly_index
unsigned int poly_index