Blender  V3.3
MeshImporter.cpp
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2 
7 #include <algorithm>
8 #include <iostream>
9 
10 /* COLLADABU_ASSERT, may be able to remove later */
11 #include "COLLADABUPlatform.h"
12 
13 #include "COLLADAFWMeshPrimitive.h"
14 #include "COLLADAFWMeshVertexData.h"
15 #include "COLLADAFWPolygons.h"
16 
17 #include "MEM_guardedalloc.h"
18 
19 #include "BKE_customdata.h"
20 #include "BKE_displist.h"
21 #include "BKE_global.h"
22 #include "BKE_lib_id.h"
23 #include "BKE_material.h"
24 #include "BKE_mesh.h"
25 #include "BKE_object.h"
26 
27 #include "BLI_edgehash.h"
28 #include "BLI_listbase.h"
29 #include "BLI_math.h"
30 #include "BLI_string.h"
31 
32 #include "ArmatureImporter.h"
33 #include "MeshImporter.h"
34 #include "collada_utils.h"
35 
36 /* get node name, or fall back to original id if not present (name is optional) */
37 template<class T> static std::string bc_get_dae_name(T *node)
38 {
39  return node->getName().empty() ? node->getOriginalId() : node->getName();
40 }
41 
43 {
44  switch (type) {
45  case COLLADAFW::MeshPrimitive::LINES:
46  return "LINES";
47  case COLLADAFW::MeshPrimitive::LINE_STRIPS:
48  return "LINESTRIPS";
49  case COLLADAFW::MeshPrimitive::POLYGONS:
50  return "POLYGONS";
51  case COLLADAFW::MeshPrimitive::POLYLIST:
52  return "POLYLIST";
53  case COLLADAFW::MeshPrimitive::TRIANGLES:
54  return "TRIANGLES";
55  case COLLADAFW::MeshPrimitive::TRIANGLE_FANS:
56  return "TRIANGLE_FANS";
57  case COLLADAFW::MeshPrimitive::TRIANGLE_STRIPS:
58  return "TRIANGLE_STRIPS";
59  case COLLADAFW::MeshPrimitive::POINTS:
60  return "POINTS";
61  case COLLADAFW::MeshPrimitive::UNDEFINED_PRIMITIVE_TYPE:
62  return "UNDEFINED_PRIMITIVE_TYPE";
63  }
64  return "UNKNOWN";
65 }
66 
67 static const char *bc_geomTypeToStr(COLLADAFW::Geometry::GeometryType type)
68 {
69  switch (type) {
70  case COLLADAFW::Geometry::GEO_TYPE_MESH:
71  return "MESH";
72  case COLLADAFW::Geometry::GEO_TYPE_SPLINE:
73  return "SPLINE";
74  case COLLADAFW::Geometry::GEO_TYPE_CONVEX_MESH:
75  return "CONVEX_MESH";
76  case COLLADAFW::Geometry::GEO_TYPE_UNKNOWN:
77  default:
78  return "UNKNOWN";
79  }
80 }
81 
82 UVDataWrapper::UVDataWrapper(COLLADAFW::MeshVertexData &vdata) : mVData(&vdata)
83 {
84 }
85 
86 #ifdef COLLADA_DEBUG
87 void WVDataWrapper::print()
88 {
89  fprintf(stderr, "UVs:\n");
90  switch (mVData->getType()) {
91  case COLLADAFW::MeshVertexData::DATA_TYPE_FLOAT: {
92  COLLADAFW::ArrayPrimitiveType<float> *values = mVData->getFloatValues();
93  if (values->getCount()) {
94  for (int i = 0; i < values->getCount(); i += 2) {
95  fprintf(stderr, "%.1f, %.1f\n", (*values)[i], (*values)[i + 1]);
96  }
97  }
98  } break;
99  case COLLADAFW::MeshVertexData::DATA_TYPE_DOUBLE: {
100  COLLADAFW::ArrayPrimitiveType<double> *values = mVData->getDoubleValues();
101  if (values->getCount()) {
102  for (int i = 0; i < values->getCount(); i += 2) {
103  fprintf(stderr, "%.1f, %.1f\n", (float)(*values)[i], (float)(*values)[i + 1]);
104  }
105  }
106  } break;
107  }
108  fprintf(stderr, "\n");
109 }
110 #endif
111 
112 void UVDataWrapper::getUV(int uv_index, float *uv)
113 {
114  int stride = mVData->getStride(0);
115  if (stride == 0) {
116  stride = 2;
117  }
118 
119  switch (mVData->getType()) {
120  case COLLADAFW::MeshVertexData::DATA_TYPE_FLOAT: {
121  COLLADAFW::ArrayPrimitiveType<float> *values = mVData->getFloatValues();
122  if (values->empty()) {
123  return;
124  }
125  uv[0] = (*values)[uv_index * stride];
126  uv[1] = (*values)[uv_index * stride + 1];
127 
128  } break;
129  case COLLADAFW::MeshVertexData::DATA_TYPE_DOUBLE: {
130  COLLADAFW::ArrayPrimitiveType<double> *values = mVData->getDoubleValues();
131  if (values->empty()) {
132  return;
133  }
134  uv[0] = (float)(*values)[uv_index * stride];
135  uv[1] = (float)(*values)[uv_index * stride + 1];
136 
137  } break;
138  case COLLADAFW::MeshVertexData::DATA_TYPE_UNKNOWN:
139  default:
140  fprintf(stderr, "MeshImporter.getUV(): unknown data type\n");
141  }
142 }
143 
144 VCOLDataWrapper::VCOLDataWrapper(COLLADAFW::MeshVertexData &vdata) : mVData(&vdata)
145 {
146 }
147 
148 template<typename T>
149 static void colladaAddColor(T values, MLoopCol *mloopcol, int v_index, int stride)
150 {
151  if (values->empty() || values->getCount() < (v_index + 1) * stride) {
152  fprintf(stderr,
153  "VCOLDataWrapper.getvcol(): Out of Bounds error: index %d points outside value "
154  "list of length %zd (with stride=%d) \n",
155  v_index,
156  values->getCount(),
157  stride);
158  return;
159  }
160 
161  mloopcol->r = unit_float_to_uchar_clamp((*values)[v_index * stride]);
162  mloopcol->g = unit_float_to_uchar_clamp((*values)[v_index * stride + 1]);
163  mloopcol->b = unit_float_to_uchar_clamp((*values)[v_index * stride + 2]);
164  if (stride == 4) {
165  mloopcol->a = unit_float_to_uchar_clamp((*values)[v_index * stride + 3]);
166  }
167 }
168 
169 void VCOLDataWrapper::get_vcol(int v_index, MLoopCol *mloopcol)
170 {
171  int stride = mVData->getStride(0);
172  if (stride == 0) {
173  stride = 3;
174  }
175 
176  switch (mVData->getType()) {
177  case COLLADAFW::MeshVertexData::DATA_TYPE_FLOAT: {
178  COLLADAFW::ArrayPrimitiveType<float> *values = mVData->getFloatValues();
179  colladaAddColor<COLLADAFW::ArrayPrimitiveType<float> *>(values, mloopcol, v_index, stride);
180  } break;
181 
182  case COLLADAFW::MeshVertexData::DATA_TYPE_DOUBLE: {
183  COLLADAFW::ArrayPrimitiveType<double> *values = mVData->getDoubleValues();
184  colladaAddColor<COLLADAFW::ArrayPrimitiveType<double> *>(values, mloopcol, v_index, stride);
185  } break;
186 
187  default:
188  fprintf(stderr, "VCOLDataWrapper.getvcol(): unknown data type\n");
189  }
190 }
191 
193  UnitConverter *unitconv, ArmatureImporter *arm, Main *bmain, Scene *sce, ViewLayer *view_layer)
194  : unitconverter(unitconv),
195  m_bmain(bmain),
196  scene(sce),
197  view_layer(view_layer),
198  armature_importer(arm)
199 {
200  /* pass */
201 }
202 
203 bool MeshImporter::set_poly_indices(
204  MPoly *mpoly, MLoop *mloop, int loop_index, const unsigned int *indices, int loop_count)
205 {
206  mpoly->loopstart = loop_index;
207  mpoly->totloop = loop_count;
208  bool broken_loop = false;
209  for (int index = 0; index < loop_count; index++) {
210 
211  /* Test if loop defines a hole */
212  if (!broken_loop) {
213  for (int i = 0; i < index; i++) {
214  if (indices[i] == indices[index]) {
215  /* duplicate index -> not good */
216  broken_loop = true;
217  }
218  }
219  }
220 
221  mloop->v = indices[index];
222  mloop++;
223  }
224  return broken_loop;
225 }
226 
227 void MeshImporter::set_vcol(MLoopCol *mloopcol,
228  VCOLDataWrapper &vob,
229  int loop_index,
230  COLLADAFW::IndexList &index_list,
231  int count)
232 {
233  int index;
234  for (index = 0; index < count; index++, mloopcol++) {
235  int v_index = index_list.getIndex(index + loop_index);
236  vob.get_vcol(v_index, mloopcol);
237  }
238 }
239 
240 void MeshImporter::set_face_uv(MLoopUV *mloopuv,
241  UVDataWrapper &uvs,
242  int start_index,
243  COLLADAFW::IndexList &index_list,
244  int count)
245 {
246  /* per face vertex indices, this means for quad we have 4 indices, not 8 */
247  COLLADAFW::UIntValuesArray &indices = index_list.getIndices();
248 
249  for (int index = 0; index < count; index++) {
250  int uv_index = indices[index + start_index];
251  uvs.getUV(uv_index, mloopuv[index].uv);
252  }
253 }
254 
255 #ifdef COLLADA_DEBUG
256 void MeshImporter::print_index_list(COLLADAFW::IndexList &index_list)
257 {
258  fprintf(stderr, "Index list for \"%s\":\n", index_list.getName().c_str());
259  for (int i = 0; i < index_list.getIndicesCount(); i += 2) {
260  fprintf(stderr, "%u, %u\n", index_list.getIndex(i), index_list.getIndex(i + 1));
261  }
262  fprintf(stderr, "\n");
263 }
264 #endif
265 
266 bool MeshImporter::is_nice_mesh(COLLADAFW::Mesh *mesh)
267 {
268  COLLADAFW::MeshPrimitiveArray &prim_arr = mesh->getMeshPrimitives();
269 
270  const std::string &name = bc_get_dae_name(mesh);
271 
272  for (unsigned int i = 0; i < prim_arr.getCount(); i++) {
273 
274  COLLADAFW::MeshPrimitive *mp = prim_arr[i];
275  COLLADAFW::MeshPrimitive::PrimitiveType type = mp->getPrimitiveType();
276 
277  const char *type_str = bc_primTypeToStr(type);
278 
279  /* OpenCollada passes POLYGONS type for <polylist> */
280  if (type == COLLADAFW::MeshPrimitive::POLYLIST || type == COLLADAFW::MeshPrimitive::POLYGONS) {
281 
282  COLLADAFW::Polygons *mpvc = (COLLADAFW::Polygons *)mp;
283  COLLADAFW::Polygons::VertexCountArray &vca = mpvc->getGroupedVerticesVertexCountArray();
284 
285  int hole_count = 0;
286  int nonface_count = 0;
287 
288  for (unsigned int j = 0; j < vca.getCount(); j++) {
289  int count = vca[j];
290  if (abs(count) < 3) {
291  nonface_count++;
292  }
293 
294  if (count < 0) {
295  hole_count++;
296  }
297  }
298 
299  if (hole_count > 0) {
300  fprintf(stderr,
301  "WARNING: Primitive %s in %s: %d holes not imported (unsupported)\n",
302  type_str,
303  name.c_str(),
304  hole_count);
305  }
306 
307  if (nonface_count > 0) {
308  fprintf(stderr,
309  "WARNING: Primitive %s in %s: %d faces with vertex count < 3 (rejected)\n",
310  type_str,
311  name.c_str(),
312  nonface_count);
313  }
314  }
315 
316  else if (type == COLLADAFW::MeshPrimitive::LINES) {
317  /* TODO: Add Checker for line syntax here */
318  }
319 
320  else if (type != COLLADAFW::MeshPrimitive::TRIANGLES &&
321  type != COLLADAFW::MeshPrimitive::TRIANGLE_FANS) {
322  fprintf(stderr, "ERROR: Primitive type %s is not supported.\n", type_str);
323  return false;
324  }
325  }
326 
327  return true;
328 }
329 
330 void MeshImporter::read_vertices(COLLADAFW::Mesh *mesh, Mesh *me)
331 {
332  /* vertices */
333  COLLADAFW::MeshVertexData &pos = mesh->getPositions();
334  if (pos.empty()) {
335  return;
336  }
337 
338  int stride = pos.getStride(0);
339  if (stride == 0) {
340  stride = 3;
341  }
342 
343  me->totvert = pos.getFloatValues()->getCount() / stride;
344  me->mvert = (MVert *)CustomData_add_layer(&me->vdata, CD_MVERT, CD_CALLOC, nullptr, me->totvert);
345 
346  MVert *mvert;
347  int i;
348 
349  for (i = 0, mvert = me->mvert; i < me->totvert; i++, mvert++) {
350  get_vector(mvert->co, pos, i, stride);
351  }
352 }
353 
354 bool MeshImporter::primitive_has_useable_normals(COLLADAFW::MeshPrimitive *mp)
355 {
356 
357  bool has_useable_normals = false;
358 
359  int normals_count = mp->getNormalIndices().getCount();
360  if (normals_count > 0) {
361  int index_count = mp->getPositionIndices().getCount();
362  if (index_count == normals_count) {
363  has_useable_normals = true;
364  }
365  else {
366  fprintf(stderr,
367  "Warning: Number of normals %d is different from the number of vertices %d, "
368  "skipping normals\n",
369  normals_count,
370  index_count);
371  }
372  }
373 
374  return has_useable_normals;
375 }
376 
377 bool MeshImporter::primitive_has_faces(COLLADAFW::MeshPrimitive *mp)
378 {
379 
380  bool has_faces = false;
381  int type = mp->getPrimitiveType();
382  switch (type) {
383  case COLLADAFW::MeshPrimitive::TRIANGLES:
384  case COLLADAFW::MeshPrimitive::TRIANGLE_FANS:
385  case COLLADAFW::MeshPrimitive::POLYLIST:
386  case COLLADAFW::MeshPrimitive::POLYGONS: {
387  has_faces = true;
388  break;
389  }
390  default: {
391  has_faces = false;
392  break;
393  }
394  }
395  return has_faces;
396 }
397 
398 static std::string extract_vcolname(const COLLADAFW::String &collada_id)
399 {
400  std::string colname = collada_id;
401  int spos = colname.find("-mesh-colors-");
402  if (spos != std::string::npos) {
403  colname = colname.substr(spos + 13);
404  }
405  return colname;
406 }
407 
408 void MeshImporter::allocate_poly_data(COLLADAFW::Mesh *collada_mesh, Mesh *me)
409 {
410  COLLADAFW::MeshPrimitiveArray &prim_arr = collada_mesh->getMeshPrimitives();
411  int total_poly_count = 0;
412  int total_loop_count = 0;
413 
414  /* collect edge_count and face_count from all parts */
415  for (int i = 0; i < prim_arr.getCount(); i++) {
416  COLLADAFW::MeshPrimitive *mp = prim_arr[i];
417  int type = mp->getPrimitiveType();
418  switch (type) {
419  case COLLADAFW::MeshPrimitive::TRIANGLES:
420  case COLLADAFW::MeshPrimitive::TRIANGLE_FANS:
421  case COLLADAFW::MeshPrimitive::POLYLIST:
422  case COLLADAFW::MeshPrimitive::POLYGONS: {
423  COLLADAFW::Polygons *mpvc = (COLLADAFW::Polygons *)mp;
424  size_t prim_poly_count = mpvc->getFaceCount();
425 
426  size_t prim_loop_count = 0;
427  for (int index = 0; index < prim_poly_count; index++) {
428  int vcount = get_vertex_count(mpvc, index);
429  if (vcount > 0) {
430  prim_loop_count += vcount;
431  total_poly_count++;
432  }
433  else {
434  /* TODO: this is a hole and not another polygon! */
435  }
436  }
437 
438  total_loop_count += prim_loop_count;
439 
440  break;
441  }
442  default:
443  break;
444  }
445  }
446 
447  /* Add the data containers */
448  if (total_poly_count > 0) {
449  me->totpoly = total_poly_count;
450  me->totloop = total_loop_count;
452  &me->pdata, CD_MPOLY, CD_CALLOC, nullptr, me->totpoly);
454  &me->ldata, CD_MLOOP, CD_CALLOC, nullptr, me->totloop);
455 
456  unsigned int totuvset = collada_mesh->getUVCoords().getInputInfosArray().getCount();
457  for (int i = 0; i < totuvset; i++) {
458  if (collada_mesh->getUVCoords().getLength(i) == 0) {
459  totuvset = 0;
460  break;
461  }
462  }
463 
464  if (totuvset > 0) {
465  for (int i = 0; i < totuvset; i++) {
466  COLLADAFW::MeshVertexData::InputInfos *info =
467  collada_mesh->getUVCoords().getInputInfosArray()[i];
468  COLLADAFW::String &uvname = info->mName;
469  /* Allocate space for UV_data */
471  &me->ldata, CD_MLOOPUV, CD_DEFAULT, nullptr, me->totloop, uvname.c_str());
472  }
473  /* activate the first uv map */
475  }
476 
477  int totcolset = collada_mesh->getColors().getInputInfosArray().getCount();
478  if (totcolset > 0) {
479  for (int i = 0; i < totcolset; i++) {
480  COLLADAFW::MeshVertexData::InputInfos *info =
481  collada_mesh->getColors().getInputInfosArray()[i];
482  COLLADAFW::String colname = extract_vcolname(info->mName);
484  &me->ldata, CD_PROP_BYTE_COLOR, CD_DEFAULT, nullptr, me->totloop, colname.c_str());
485  }
487  }
488  }
489 }
490 
491 unsigned int MeshImporter::get_vertex_count(COLLADAFW::Polygons *mp, int index)
492 {
493  int type = mp->getPrimitiveType();
494  int result;
495  switch (type) {
496  case COLLADAFW::MeshPrimitive::TRIANGLES:
497  case COLLADAFW::MeshPrimitive::TRIANGLE_FANS: {
498  result = 3;
499  break;
500  }
501  case COLLADAFW::MeshPrimitive::POLYLIST:
502  case COLLADAFW::MeshPrimitive::POLYGONS: {
503  result = mp->getGroupedVerticesVertexCountArray()[index];
504  break;
505  }
506  default: {
507  result = -1;
508  break;
509  }
510  }
511  return result;
512 }
513 
514 unsigned int MeshImporter::get_loose_edge_count(COLLADAFW::Mesh *mesh)
515 {
516  COLLADAFW::MeshPrimitiveArray &prim_arr = mesh->getMeshPrimitives();
517  int loose_edge_count = 0;
518 
519  /* collect edge_count and face_count from all parts */
520  for (int i = 0; i < prim_arr.getCount(); i++) {
521  COLLADAFW::MeshPrimitive *mp = prim_arr[i];
522  int type = mp->getPrimitiveType();
523  switch (type) {
524  case COLLADAFW::MeshPrimitive::LINES: {
525  size_t prim_totface = mp->getFaceCount();
526  loose_edge_count += prim_totface;
527  break;
528  }
529  default:
530  break;
531  }
532  }
533  return loose_edge_count;
534 }
535 
536 void MeshImporter::mesh_add_edges(Mesh *mesh, int len)
537 {
538  CustomData edata;
539  MEdge *medge;
540  int totedge;
541 
542  if (len == 0) {
543  return;
544  }
545 
546  totedge = mesh->totedge + len;
547 
548  /* Update custom-data. */
549  CustomData_copy(&mesh->edata, &edata, CD_MASK_MESH.emask, CD_DEFAULT, totedge);
550  CustomData_copy_data(&mesh->edata, &edata, 0, 0, mesh->totedge);
551 
552  if (!CustomData_has_layer(&edata, CD_MEDGE)) {
553  CustomData_add_layer(&edata, CD_MEDGE, CD_CALLOC, nullptr, totedge);
554  }
555 
557  mesh->edata = edata;
558  BKE_mesh_update_customdata_pointers(mesh, false); /* new edges don't change tessellation */
559 
560  /* set default flags */
561  medge = &mesh->medge[mesh->totedge];
562  for (int i = 0; i < len; i++, medge++) {
563  medge->flag = ME_EDGEDRAW | ME_EDGERENDER | SELECT;
564  }
565 
566  mesh->totedge = totedge;
567 }
568 
569 void MeshImporter::read_lines(COLLADAFW::Mesh *mesh, Mesh *me)
570 {
571  unsigned int loose_edge_count = get_loose_edge_count(mesh);
572  if (loose_edge_count > 0) {
573 
574  unsigned int face_edge_count = me->totedge;
575  /* unsigned int total_edge_count = loose_edge_count + face_edge_count; */ /* UNUSED */
576 
577  mesh_add_edges(me, loose_edge_count);
578  MEdge *med = me->medge + face_edge_count;
579 
580  COLLADAFW::MeshPrimitiveArray &prim_arr = mesh->getMeshPrimitives();
581 
582  for (int index = 0; index < prim_arr.getCount(); index++) {
583  COLLADAFW::MeshPrimitive *mp = prim_arr[index];
584 
585  int type = mp->getPrimitiveType();
586  if (type == COLLADAFW::MeshPrimitive::LINES) {
587  unsigned int edge_count = mp->getFaceCount();
588  unsigned int *indices = mp->getPositionIndices().getData();
589 
590  for (int j = 0; j < edge_count; j++, med++) {
591  med->bweight = 0;
592  med->crease = 0;
593  med->flag |= ME_LOOSEEDGE;
594  med->v1 = indices[2 * j];
595  med->v2 = indices[2 * j + 1];
596  }
597  }
598  }
599  }
600 }
601 
602 void MeshImporter::read_polys(COLLADAFW::Mesh *collada_mesh, Mesh *me)
603 {
604  unsigned int i;
605 
606  allocate_poly_data(collada_mesh, me);
607 
608  UVDataWrapper uvs(collada_mesh->getUVCoords());
609  VCOLDataWrapper vcol(collada_mesh->getColors());
610 
611  MPoly *mpoly = me->mpoly;
612  MLoop *mloop = me->mloop;
613  int loop_index = 0;
614 
615  MaterialIdPrimitiveArrayMap mat_prim_map;
616 
617  COLLADAFW::MeshPrimitiveArray &prim_arr = collada_mesh->getMeshPrimitives();
618  COLLADAFW::MeshVertexData &nor = collada_mesh->getNormals();
619 
620  for (i = 0; i < prim_arr.getCount(); i++) {
621 
622  COLLADAFW::MeshPrimitive *mp = prim_arr[i];
623 
624  /* faces */
625  size_t prim_totpoly = mp->getFaceCount();
626  unsigned int *position_indices = mp->getPositionIndices().getData();
627  unsigned int *normal_indices = mp->getNormalIndices().getData();
628 
629  bool mp_has_normals = primitive_has_useable_normals(mp);
630  bool mp_has_faces = primitive_has_faces(mp);
631 
632  int collada_meshtype = mp->getPrimitiveType();
633 
634  /* since we cannot set mpoly->mat_nr here, we store a portion of me->mpoly in Primitive */
635  Primitive prim = {mpoly, 0};
636 
637  /* If MeshPrimitive is TRIANGLE_FANS we split it into triangles
638  * The first triangle-fan vertex will be the first vertex in every triangle
639  * XXX The proper function of TRIANGLE_FANS is not tested!!!
640  * XXX In particular the handling of the normal_indices looks very wrong to me */
641  if (collada_meshtype == COLLADAFW::MeshPrimitive::TRIANGLE_FANS) {
642  unsigned int grouped_vertex_count = mp->getGroupedVertexElementsCount();
643  for (unsigned int group_index = 0; group_index < grouped_vertex_count; group_index++) {
644  unsigned int first_vertex = position_indices[0]; /* Store first trifan vertex */
645  unsigned int first_normal = normal_indices[0]; /* Store first trifan vertex normal */
646  unsigned int vertex_count = mp->getGroupedVerticesVertexCount(group_index);
647 
648  for (unsigned int vertex_index = 0; vertex_index < vertex_count - 2; vertex_index++) {
649  /* For each triangle store indices of its 3 vertices */
650  unsigned int triangle_vertex_indices[3] = {
651  first_vertex, position_indices[1], position_indices[2]};
652  set_poly_indices(mpoly, mloop, loop_index, triangle_vertex_indices, 3);
653 
654  if (mp_has_normals) { /* vertex normals, same implementation as for the triangles */
655  /* The same for vertices normals. */
656  unsigned int vertex_normal_indices[3] = {
657  first_normal, normal_indices[1], normal_indices[2]};
658  if (!is_flat_face(vertex_normal_indices, nor, 3)) {
659  mpoly->flag |= ME_SMOOTH;
660  }
661  normal_indices++;
662  }
663 
664  mpoly++;
665  mloop += 3;
666  loop_index += 3;
667  prim.totpoly++;
668  }
669 
670  /* Moving cursor to the next triangle fan. */
671  if (mp_has_normals) {
672  normal_indices += 2;
673  }
674 
675  position_indices += 2;
676  }
677  }
678 
679  if (collada_meshtype == COLLADAFW::MeshPrimitive::POLYLIST ||
680  collada_meshtype == COLLADAFW::MeshPrimitive::POLYGONS ||
681  collada_meshtype == COLLADAFW::MeshPrimitive::TRIANGLES) {
682  COLLADAFW::Polygons *mpvc = (COLLADAFW::Polygons *)mp;
683  unsigned int start_index = 0;
684 
685  COLLADAFW::IndexListArray &index_list_array_uvcoord = mp->getUVCoordIndicesArray();
686  COLLADAFW::IndexListArray &index_list_array_vcolor = mp->getColorIndicesArray();
687 
688  int invalid_loop_holes = 0;
689  for (unsigned int j = 0; j < prim_totpoly; j++) {
690 
691  /* Vertices in polygon: */
692  int vcount = get_vertex_count(mpvc, j);
693  if (vcount < 0) {
694  continue; /* TODO: add support for holes */
695  }
696 
697  bool broken_loop = set_poly_indices(mpoly, mloop, loop_index, position_indices, vcount);
698  if (broken_loop) {
699  invalid_loop_holes += 1;
700  }
701 
702  for (unsigned int uvset_index = 0; uvset_index < index_list_array_uvcoord.getCount();
703  uvset_index++) {
704  /* get mtface by face index and uv set index */
705  COLLADAFW::IndexList &index_list = *index_list_array_uvcoord[uvset_index];
707  &me->ldata, CD_MLOOPUV, index_list.getName().c_str());
708  if (mloopuv == nullptr) {
709  fprintf(stderr,
710  "Collada import: Mesh [%s] : Unknown reference to TEXCOORD [#%s].\n",
711  me->id.name,
712  index_list.getName().c_str());
713  }
714  else {
715  set_face_uv(mloopuv + loop_index,
716  uvs,
717  start_index,
718  *index_list_array_uvcoord[uvset_index],
719  vcount);
720  }
721  }
722 
723  if (mp_has_normals) {
724  if (!is_flat_face(normal_indices, nor, vcount)) {
725  mpoly->flag |= ME_SMOOTH;
726  }
727  }
728 
729  if (mp->hasColorIndices()) {
730  int vcolor_count = index_list_array_vcolor.getCount();
731 
732  for (unsigned int vcolor_index = 0; vcolor_index < vcolor_count; vcolor_index++) {
733 
734  COLLADAFW::IndexList &color_index_list = *mp->getColorIndices(vcolor_index);
735  COLLADAFW::String colname = extract_vcolname(color_index_list.getName());
737  &me->ldata, CD_PROP_BYTE_COLOR, colname.c_str());
738  if (mloopcol == nullptr) {
739  fprintf(stderr,
740  "Collada import: Mesh [%s] : Unknown reference to VCOLOR [#%s].\n",
741  me->id.name,
742  color_index_list.getName().c_str());
743  }
744  else {
745  set_vcol(mloopcol + loop_index, vcol, start_index, color_index_list, vcount);
746  }
747  }
748  }
749 
750  mpoly++;
751  mloop += vcount;
752  loop_index += vcount;
753  start_index += vcount;
754  prim.totpoly++;
755 
756  if (mp_has_normals) {
757  normal_indices += vcount;
758  }
759 
760  position_indices += vcount;
761  }
762 
763  if (invalid_loop_holes > 0) {
764  fprintf(stderr,
765  "Collada import: Mesh [%s] : contains %d unsupported loops (holes).\n",
766  me->id.name,
767  invalid_loop_holes);
768  }
769  }
770 
771  else if (collada_meshtype == COLLADAFW::MeshPrimitive::LINES) {
772  continue; /* read the lines later after all the rest is done */
773  }
774 
775  if (mp_has_faces) {
776  mat_prim_map[mp->getMaterialId()].push_back(prim);
777  }
778  }
779 
780  geom_uid_mat_mapping_map[collada_mesh->getUniqueId()] = mat_prim_map;
781 }
782 
783 void MeshImporter::get_vector(float v[3], COLLADAFW::MeshVertexData &arr, int i, int stride)
784 {
785  i *= stride;
786 
787  switch (arr.getType()) {
788  case COLLADAFW::MeshVertexData::DATA_TYPE_FLOAT: {
789  COLLADAFW::ArrayPrimitiveType<float> *values = arr.getFloatValues();
790  if (values->empty()) {
791  return;
792  }
793 
794  v[0] = (*values)[i++];
795  v[1] = (*values)[i++];
796  if (stride >= 3) {
797  v[2] = (*values)[i];
798  }
799  else {
800  v[2] = 0.0f;
801  }
802 
803  } break;
804  case COLLADAFW::MeshVertexData::DATA_TYPE_DOUBLE: {
805  COLLADAFW::ArrayPrimitiveType<double> *values = arr.getDoubleValues();
806  if (values->empty()) {
807  return;
808  }
809 
810  v[0] = (float)(*values)[i++];
811  v[1] = (float)(*values)[i++];
812  if (stride >= 3) {
813  v[2] = (float)(*values)[i];
814  }
815  else {
816  v[2] = 0.0f;
817  }
818  } break;
819  default:
820  break;
821  }
822 }
823 
824 bool MeshImporter::is_flat_face(unsigned int *nind, COLLADAFW::MeshVertexData &nor, int count)
825 {
826  float a[3], b[3];
827 
828  get_vector(a, nor, *nind, 3);
829  normalize_v3(a);
830 
831  nind++;
832 
833  for (int i = 1; i < count; i++, nind++) {
834  get_vector(b, nor, *nind, 3);
835  normalize_v3(b);
836 
837  float dp = dot_v3v3(a, b);
838 
839  if (dp < 0.99999f || dp > 1.00001f) {
840  return false;
841  }
842  }
843 
844  return true;
845 }
846 
847 Object *MeshImporter::get_object_by_geom_uid(const COLLADAFW::UniqueId &geom_uid)
848 {
849  if (uid_object_map.find(geom_uid) != uid_object_map.end()) {
850  return uid_object_map[geom_uid];
851  }
852  return nullptr;
853 }
854 
855 Mesh *MeshImporter::get_mesh_by_geom_uid(const COLLADAFW::UniqueId &geom_uid)
856 {
857  if (uid_mesh_map.find(geom_uid) != uid_mesh_map.end()) {
858  return uid_mesh_map[geom_uid];
859  }
860  return nullptr;
861 }
862 
863 std::string *MeshImporter::get_geometry_name(const std::string &mesh_name)
864 {
865  if (this->mesh_geom_map.find(mesh_name) != this->mesh_geom_map.end()) {
866  return &this->mesh_geom_map[mesh_name];
867  }
868  return nullptr;
869 }
870 
877 {
878  if (ob1->totcol != ob2->totcol) {
879  return false; /* not same number of materials */
880  }
881  if (ob1->totcol == 0) {
882  return false; /* no material at all */
883  }
884 
885  for (int index = 0; index < ob1->totcol; index++) {
886  if (ob1->matbits[index] != ob2->matbits[index]) {
887  return false; /* shouldn't happen */
888  }
889  if (ob1->matbits[index] == 0) {
890  return false; /* shouldn't happen */
891  }
892  if (ob1->mat[index] != ob2->mat[index]) {
893  return false; /* different material assignment */
894  }
895  }
896  return true;
897 }
898 
906 static void bc_copy_materials_to_data(Object *ob, Mesh *me)
907 {
908  for (int index = 0; index < ob->totcol; index++) {
909  ob->matbits[index] = 0;
910  me->mat[index] = ob->mat[index];
911  }
912 }
913 
920 {
921  for (int index = 0; index < ob->totcol; index++) {
922  ob->matbits[index] = 0;
923  ob->mat[index] = nullptr;
924  }
925 }
926 
927 std::vector<Object *> MeshImporter::get_all_users_of(Mesh *reference_mesh)
928 {
929  std::vector<Object *> mesh_users;
930  for (Object *ob : imported_objects) {
931  if (bc_is_marked(ob)) {
932  bc_remove_mark(ob);
933  Mesh *me = (Mesh *)ob->data;
934  if (me == reference_mesh) {
935  mesh_users.push_back(ob);
936  }
937  }
938  }
939  return mesh_users;
940 }
941 
943 {
944  for (Object *ob : imported_objects) {
945  Mesh *me = (Mesh *)ob->data;
946  if (ID_REAL_USERS(&me->id) == 1) {
949  bc_remove_mark(ob);
950  }
951  else if (ID_REAL_USERS(&me->id) > 1) {
952  bool can_move = true;
953  std::vector<Object *> mesh_users = get_all_users_of(me);
954  if (mesh_users.size() > 1) {
955  Object *ref_ob = mesh_users[0];
956  for (int index = 1; index < mesh_users.size(); index++) {
957  if (!bc_has_same_material_configuration(ref_ob, mesh_users[index])) {
958  can_move = false;
959  break;
960  }
961  }
962  if (can_move) {
963  bc_copy_materials_to_data(ref_ob, me);
964  for (Object *object : mesh_users) {
966  bc_remove_mark(object);
967  }
968  }
969  }
970  }
971  }
972 }
973 
975  COLLADAFW::MaterialBinding cmaterial,
976  std::map<COLLADAFW::UniqueId, Material *> &uid_material_map,
977  Object *ob,
978  const COLLADAFW::UniqueId *geom_uid,
979  short mat_index)
980 {
981  const COLLADAFW::UniqueId &ma_uid = cmaterial.getReferencedMaterial();
982 
983  /* do we know this material? */
984  if (uid_material_map.find(ma_uid) == uid_material_map.end()) {
985 
986  fprintf(stderr, "Cannot find material by UID.\n");
987  return;
988  }
989 
990  /* first time we get geom_uid, ma_uid pair. Save for later check. */
991  materials_mapped_to_geom.insert(
992  std::pair<COLLADAFW::UniqueId, COLLADAFW::UniqueId>(*geom_uid, ma_uid));
993 
994  Material *ma = uid_material_map[ma_uid];
995 
996  /* Attention! This temporarily assigns material to object on purpose!
997  * See note above. */
998  ob->actcol = 0;
999  BKE_object_material_assign(m_bmain, ob, ma, mat_index + 1, BKE_MAT_ASSIGN_OBJECT);
1000 
1001  MaterialIdPrimitiveArrayMap &mat_prim_map = geom_uid_mat_mapping_map[*geom_uid];
1002  COLLADAFW::MaterialId mat_id = cmaterial.getMaterialId();
1003 
1004  /* assign material indices to mesh faces */
1005  if (mat_prim_map.find(mat_id) != mat_prim_map.end()) {
1006 
1007  std::vector<Primitive> &prims = mat_prim_map[mat_id];
1008 
1009  std::vector<Primitive>::iterator it;
1010 
1011  for (it = prims.begin(); it != prims.end(); it++) {
1012  Primitive &prim = *it;
1013  MPoly *mpoly = prim.mpoly;
1014 
1015  for (int i = 0; i < prim.totpoly; i++, mpoly++) {
1016  mpoly->mat_nr = mat_index;
1017  }
1018  }
1019  }
1020 }
1021 
1023  COLLADAFW::Node *node,
1024  COLLADAFW::InstanceGeometry *geom,
1025  bool isController,
1026  std::map<COLLADAFW::UniqueId, Material *> &uid_material_map)
1027 {
1028  const COLLADAFW::UniqueId *geom_uid = &geom->getInstanciatedObjectId();
1029 
1030  /* check if node instantiates controller or geometry */
1031  if (isController) {
1032 
1033  geom_uid = armature_importer->get_geometry_uid(*geom_uid);
1034 
1035  if (!geom_uid) {
1036  fprintf(stderr, "Couldn't find a mesh UID by controller's UID.\n");
1037  return nullptr;
1038  }
1039  }
1040  else {
1041 
1042  if (uid_mesh_map.find(*geom_uid) == uid_mesh_map.end()) {
1043  /* this could happen if a mesh was not created
1044  * (e.g. if it contains unsupported geometry) */
1045  fprintf(stderr, "Couldn't find a mesh by UID.\n");
1046  return nullptr;
1047  }
1048  }
1049  if (!uid_mesh_map[*geom_uid]) {
1050  return nullptr;
1051  }
1052 
1053  /* name Object */
1054  const std::string &id = node->getName().empty() ? node->getOriginalId() : node->getName();
1055  const char *name = (id.length()) ? id.c_str() : nullptr;
1056 
1057  /* add object */
1058  Object *ob = bc_add_object(m_bmain, scene, view_layer, OB_MESH, name);
1059  bc_set_mark(ob); /* used later for material assignment optimization */
1060 
1061  /* store object pointer for ArmatureImporter */
1062  uid_object_map[*geom_uid] = ob;
1063  imported_objects.push_back(ob);
1064 
1065  /* replace ob->data freeing the old one */
1066  Mesh *old_mesh = (Mesh *)ob->data;
1067  Mesh *new_mesh = uid_mesh_map[*geom_uid];
1068 
1069  BKE_mesh_assign_object(m_bmain, ob, new_mesh);
1070 
1071  /* Because BKE_mesh_assign_object would have already decreased it... */
1072  id_us_plus(&old_mesh->id);
1073 
1074  BKE_id_free_us(m_bmain, old_mesh);
1075 
1076  COLLADAFW::MaterialBindingArray &mat_array = geom->getMaterialBindings();
1077 
1078  /* loop through geom's materials */
1079  for (unsigned int i = 0; i < mat_array.getCount(); i++) {
1080 
1081  if (mat_array[i].getReferencedMaterial().isValid()) {
1082  assign_material_to_geom(mat_array[i], uid_material_map, ob, geom_uid, i);
1083  }
1084  else {
1085  fprintf(stderr, "invalid referenced material for %s\n", mat_array[i].getName().c_str());
1086  }
1087  }
1088 
1089  /* clean up the mesh */
1090  BKE_mesh_validate((Mesh *)ob->data, false, false);
1091 
1092  return ob;
1093 }
1094 
1095 bool MeshImporter::write_geometry(const COLLADAFW::Geometry *geom)
1096 {
1097 
1098  if (geom->getType() != COLLADAFW::Geometry::GEO_TYPE_MESH) {
1099  /* TODO: report warning */
1100  fprintf(stderr, "Mesh type %s is not supported\n", bc_geomTypeToStr(geom->getType()));
1101  return true;
1102  }
1103 
1105 
1106  if (!is_nice_mesh(mesh)) {
1107  fprintf(stderr, "Ignoring mesh %s\n", bc_get_dae_name(mesh).c_str());
1108  return true;
1109  }
1110 
1111  const std::string &str_geom_id = mesh->getName().empty() ? mesh->getOriginalId() :
1112  mesh->getName();
1113  Mesh *me = BKE_mesh_add(m_bmain, (char *)str_geom_id.c_str());
1114  id_us_min(&me->id); /* is already 1 here, but will be set later in BKE_mesh_assign_object */
1115 
1116  /* store the Mesh pointer to link it later with an Object
1117  * mesh_geom_map needed to map mesh to its geometry name (for shape key naming) */
1118  this->uid_mesh_map[mesh->getUniqueId()] = me;
1119  this->mesh_geom_map[std::string(me->id.name)] = str_geom_id;
1120 
1121  read_vertices(mesh, me);
1122  read_polys(mesh, me);
1123  BKE_mesh_calc_edges(me, false, false);
1124  /* read_lines() must be called after the face edges have been generated.
1125  * Otherwise the loose edges will be silently deleted again. */
1126  read_lines(mesh, me);
1127 
1128  return true;
1129 }
typedef float(TangentPoint)[2]
CustomData interface, see also DNA_customdata_types.h.
void CustomData_free(struct CustomData *data, int totelem)
Definition: customdata.cc:2373
@ CD_CALLOC
@ CD_DEFAULT
void CustomData_copy(const struct CustomData *source, struct CustomData *dest, eCustomDataMask mask, eCDAllocType alloctype, int totelem)
bool CustomData_has_layer(const struct CustomData *data, int type)
void * CustomData_add_layer_named(struct CustomData *data, int type, eCDAllocType alloctype, void *layer, int totelem, const char *name)
Definition: customdata.cc:2792
void * CustomData_get_layer_named(const struct CustomData *data, int type, const char *name)
void * CustomData_get_layer_n(const struct CustomData *data, int type, int n)
void * CustomData_add_layer(struct CustomData *data, int type, eCDAllocType alloctype, void *layer, int totelem)
Definition: customdata.cc:2776
void CustomData_copy_data(const struct CustomData *source, struct CustomData *dest, int source_index, int dest_index, int count)
const CustomData_MeshMasks CD_MASK_MESH
Definition: customdata.cc:2065
display list (or rather multi purpose list) stuff.
void id_us_min(struct ID *id)
Definition: lib_id.c:313
void id_us_plus(struct ID *id)
Definition: lib_id.c:305
void BKE_id_free_us(struct Main *bmain, void *idv) ATTR_NONNULL()
General operations, lookup, etc. for materials.
void BKE_object_material_assign(struct Main *bmain, struct Object *ob, struct Material *ma, short act, int assign_type)
Definition: material.c:1047
@ BKE_MAT_ASSIGN_OBJECT
Definition: BKE_material.h:82
void BKE_mesh_assign_object(struct Main *bmain, struct Object *ob, struct Mesh *me)
Definition: mesh.cc:1377
struct Mesh * BKE_mesh_add(struct Main *bmain, const char *name)
Definition: mesh.cc:963
bool BKE_mesh_validate(struct Mesh *me, bool do_verbose, bool cddata_check_mask)
void BKE_mesh_update_customdata_pointers(struct Mesh *me, bool do_ensure_tess_cd)
Definition: mesh.cc:874
void BKE_mesh_calc_edges(struct Mesh *mesh, bool keep_existing_edges, bool select_new_edges)
General operations, lookup, etc. for blender objects.
MINLINE float normalize_v3(float r[3])
MINLINE float dot_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT
void bc_remove_mark(Object *ob)
int bc_is_marked(Object *ob)
void bc_set_mark(Object *ob)
#define ID_REAL_USERS(id)
Definition: DNA_ID.h:553
@ CD_PROP_BYTE_COLOR
@ CD_MEDGE
@ CD_MVERT
@ CD_MLOOPUV
struct Mesh Mesh
@ ME_SMOOTH
@ ME_EDGEDRAW
@ ME_EDGERENDER
@ ME_LOOSEEDGE
@ OB_MESH
_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 type
_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 stride
Read Guarded memory(de)allocation.
static bool bc_has_same_material_configuration(Object *ob1, Object *ob2)
static void bc_copy_materials_to_data(Object *ob, Mesh *me)
static const char * bc_geomTypeToStr(COLLADAFW::Geometry::GeometryType type)
static std::string extract_vcolname(const COLLADAFW::String &collada_id)
static void bc_remove_materials_from_object(Object *ob, Mesh *me)
static void colladaAddColor(T values, MLoopCol *mloopcol, int v_index, int stride)
static std::string bc_get_dae_name(T *node)
static const char * bc_primTypeToStr(COLLADAFW::MeshPrimitive::PrimitiveType type)
ATTR_WARN_UNUSED_RESULT const BMVert * v
virtual const char * getName() const
Definition: btBox2dShape.h:301
COLLADAFW::UniqueId * get_geometry_uid(const COLLADAFW::UniqueId &controller_uid)
virtual Mesh * get_mesh_by_geom_uid(const COLLADAFW::UniqueId &geom_uid)
virtual Object * get_object_by_geom_uid(const COLLADAFW::UniqueId &geom_uid)
void optimize_material_assignements()
bool write_geometry(const COLLADAFW::Geometry *geom)
void assign_material_to_geom(COLLADAFW::MaterialBinding cmaterial, std::map< COLLADAFW::UniqueId, Material * > &uid_material_map, Object *ob, const COLLADAFW::UniqueId *geom_uid, short mat_index)
Object * create_mesh_object(COLLADAFW::Node *node, COLLADAFW::InstanceGeometry *geom, bool isController, std::map< COLLADAFW::UniqueId, Material * > &uid_material_map)
MeshImporter(UnitConverter *unitconv, ArmatureImporter *arm, Main *bmain, Scene *sce, ViewLayer *view_layer)
std::string * get_geometry_name(const std::string &mesh_name)
UVDataWrapper(COLLADAFW::MeshVertexData &vdata)
void getUV(int uv_index, float *uv)
void get_vcol(int v_index, MLoopCol *mloopcol)
VCOLDataWrapper(COLLADAFW::MeshVertexData &vdata)
Object * bc_add_object(Main *bmain, Scene *scene, ViewLayer *view_layer, int type, const char *name)
#define SELECT
OperationNode * node
Scene scene
int len
Definition: draw_manager.c:108
uint pos
uint nor
int count
ccl_gpu_kernel_postfix int ccl_global int * indices
PrimitiveType
Definition: kernel/types.h:549
MINLINE unsigned char unit_float_to_uchar_clamp(float val)
#define T
static unsigned a[3]
Definition: RandGen.cpp:78
T abs(const T &a)
static const pxr::TfToken b("b", pxr::TfToken::Immortal)
char name[66]
Definition: DNA_ID.h:378
unsigned int v1
unsigned int v2
unsigned char a
unsigned char b
unsigned char r
unsigned char g
unsigned int v
short mat_nr
float co[3]
Definition: BKE_main.h:121
struct MEdge * medge
CustomData vdata
struct MVert * mvert
struct MLoopCol * mloopcol
struct Material ** mat
int totedge
struct MLoopUV * mloopuv
int totvert
struct MLoop * mloop
CustomData pdata
int totpoly
CustomData edata
int totloop
struct MPoly * mpoly
CustomData ldata
struct Material ** mat
char * matbits
void * data