Blender V4.5
MeshImporter.cpp
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2010-2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
8
9#include <iostream>
10
11#include "COLLADAFWMeshPrimitive.h"
12#include "COLLADAFWMeshVertexData.h"
13#include "COLLADAFWPolygons.h"
14
15#include "BKE_attribute.hh"
16#include "BKE_customdata.hh"
17#include "BKE_global.hh"
18#include "BKE_lib_id.hh"
19#include "BKE_material.hh"
20#include "BKE_mesh.hh"
21#include "BKE_mesh_runtime.hh"
22#include "BKE_object.hh"
23
24#include "DNA_meshdata_types.h"
25
26#include "ArmatureImporter.h"
27#include "MeshImporter.h"
28#include "collada_utils.h"
29
30using blender::float3;
32
33/* get node name, or fall back to original id if not present (name is optional) */
34template<class T> static std::string bc_get_dae_name(T *node)
35{
36 return node->getName().empty() ? node->getOriginalId() : node->getName();
37}
38
39static const char *bc_primTypeToStr(COLLADAFW::MeshPrimitive::PrimitiveType type)
40{
41 switch (type) {
42 case COLLADAFW::MeshPrimitive::LINES:
43 return "LINES";
44 case COLLADAFW::MeshPrimitive::LINE_STRIPS:
45 return "LINESTRIPS";
46 case COLLADAFW::MeshPrimitive::POLYGONS:
47 return "POLYGONS";
48 case COLLADAFW::MeshPrimitive::POLYLIST:
49 return "POLYLIST";
50 case COLLADAFW::MeshPrimitive::TRIANGLES:
51 return "TRIANGLES";
52 case COLLADAFW::MeshPrimitive::TRIANGLE_FANS:
53 return "TRIANGLE_FANS";
54 case COLLADAFW::MeshPrimitive::TRIANGLE_STRIPS:
55 return "TRIANGLE_STRIPS";
56 case COLLADAFW::MeshPrimitive::POINTS:
57 return "POINTS";
58 case COLLADAFW::MeshPrimitive::UNDEFINED_PRIMITIVE_TYPE:
59 return "UNDEFINED_PRIMITIVE_TYPE";
60 }
61 return "UNKNOWN";
62}
63
64static const char *bc_geomTypeToStr(COLLADAFW::Geometry::GeometryType type)
65{
66 switch (type) {
67 case COLLADAFW::Geometry::GEO_TYPE_MESH:
68 return "MESH";
69 case COLLADAFW::Geometry::GEO_TYPE_SPLINE:
70 return "SPLINE";
71 case COLLADAFW::Geometry::GEO_TYPE_CONVEX_MESH:
72 return "CONVEX_MESH";
73 case COLLADAFW::Geometry::GEO_TYPE_UNKNOWN:
74 default:
75 return "UNKNOWN";
76 }
77}
78
79UVDataWrapper::UVDataWrapper(COLLADAFW::MeshVertexData &vdata) : mVData(&vdata) {}
80
81#ifdef COLLADA_DEBUG
82void WVDataWrapper::print()
83{
84 fprintf(stderr, "UVs:\n");
85 switch (mVData->getType()) {
86 case COLLADAFW::MeshVertexData::DATA_TYPE_FLOAT: {
87 COLLADAFW::ArrayPrimitiveType<float> *values = mVData->getFloatValues();
88 if (values->getCount()) {
89 for (int i = 0; i < values->getCount(); i += 2) {
90 fprintf(stderr, "%.1f, %.1f\n", (*values)[i], (*values)[i + 1]);
91 }
92 }
93 break;
94 }
95 case COLLADAFW::MeshVertexData::DATA_TYPE_DOUBLE: {
96 COLLADAFW::ArrayPrimitiveType<double> *values = mVData->getDoubleValues();
97 if (values->getCount()) {
98 for (int i = 0; i < values->getCount(); i += 2) {
99 fprintf(stderr, "%.1f, %.1f\n", float((*values)[i]), float((*values)[i + 1]));
100 }
101 }
102 break;
103 }
104 }
105 fprintf(stderr, "\n");
106}
107#endif
108
109void UVDataWrapper::getUV(int uv_index, float *uv)
110{
111 int stride = mVData->getStride(0);
112 if (stride == 0) {
113 stride = 2;
114 }
115
116 switch (mVData->getType()) {
117 case COLLADAFW::MeshVertexData::DATA_TYPE_FLOAT: {
118 COLLADAFW::ArrayPrimitiveType<float> *values = mVData->getFloatValues();
119 if (values->empty()) {
120 return;
121 }
122 uv[0] = (*values)[uv_index * stride];
123 uv[1] = (*values)[uv_index * stride + 1];
124 break;
125 }
126 case COLLADAFW::MeshVertexData::DATA_TYPE_DOUBLE: {
127 COLLADAFW::ArrayPrimitiveType<double> *values = mVData->getDoubleValues();
128 if (values->empty()) {
129 return;
130 }
131 uv[0] = float((*values)[uv_index * stride]);
132 uv[1] = float((*values)[uv_index * stride + 1]);
133 break;
134 }
135 case COLLADAFW::MeshVertexData::DATA_TYPE_UNKNOWN:
136 default:
137 fprintf(stderr, "MeshImporter.getUV(): unknown data type\n");
138 }
139}
140
141VCOLDataWrapper::VCOLDataWrapper(COLLADAFW::MeshVertexData &vdata) : mVData(&vdata) {}
142
143template<typename T>
144static void colladaAddColor(T values, MLoopCol *mloopcol, int v_index, int stride)
145{
146 if (values->empty() || values->getCount() < (v_index + 1) * stride) {
147 fprintf(stderr,
148 "VCOLDataWrapper.getvcol(): Out of Bounds error: index %d points outside value "
149 "list of length %zd (with stride=%d) \n",
150 v_index,
151 values->getCount(),
152 stride);
153 return;
154 }
155
156 mloopcol->r = unit_float_to_uchar_clamp((*values)[v_index * stride]);
157 mloopcol->g = unit_float_to_uchar_clamp((*values)[v_index * stride + 1]);
158 mloopcol->b = unit_float_to_uchar_clamp((*values)[v_index * stride + 2]);
159 if (stride == 4) {
160 mloopcol->a = unit_float_to_uchar_clamp((*values)[v_index * stride + 3]);
161 }
162}
163
164void VCOLDataWrapper::get_vcol(int v_index, MLoopCol *mloopcol)
165{
166 int stride = mVData->getStride(0);
167 if (stride == 0) {
168 stride = 3;
169 }
170
171 switch (mVData->getType()) {
172 case COLLADAFW::MeshVertexData::DATA_TYPE_FLOAT: {
173 COLLADAFW::ArrayPrimitiveType<float> *values = mVData->getFloatValues();
174 colladaAddColor<COLLADAFW::ArrayPrimitiveType<float> *>(values, mloopcol, v_index, stride);
175 break;
176 }
177 case COLLADAFW::MeshVertexData::DATA_TYPE_DOUBLE: {
178 COLLADAFW::ArrayPrimitiveType<double> *values = mVData->getDoubleValues();
179 colladaAddColor<COLLADAFW::ArrayPrimitiveType<double> *>(values, mloopcol, v_index, stride);
180 break;
181 }
182 default:
183 fprintf(stderr, "VCOLDataWrapper.getvcol(): unknown data type\n");
184 }
185}
186
188 bool use_custom_normals,
189 ArmatureImporter *arm,
190 Main *bmain,
191 Scene *sce,
192 ViewLayer *view_layer)
193 : unitconverter(unitconv),
194 use_custom_normals(use_custom_normals),
195 m_bmain(bmain),
196 scene(sce),
197 view_layer(view_layer),
198 armature_importer(arm)
199{
200 /* pass */
201}
202
203bool MeshImporter::set_poly_indices(int *face_verts,
204 int loop_index,
205 const uint *indices,
206 int loop_count)
207{
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 *face_verts = indices[index];
222 face_verts++;
223 }
224 return broken_loop;
225}
226
227void 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
240void MeshImporter::set_face_uv(blender::float2 *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]);
252 }
253}
254
255#ifdef COLLADA_DEBUG
256void 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
266bool 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 (uint 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 (ELEM(type, COLLADAFW::MeshPrimitive::POLYLIST, 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 (uint 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 (!ELEM(type,
321 COLLADAFW::MeshPrimitive::TRIANGLES,
322 COLLADAFW::MeshPrimitive::TRIANGLE_FANS))
323 {
324 fprintf(stderr, "ERROR: Primitive type %s is not supported.\n", type_str);
325 return false;
326 }
327 }
328
329 return true;
330}
331
332void MeshImporter::read_vertices(COLLADAFW::Mesh *mesh, Mesh *blender_mesh)
333{
334 /* vertices */
335 COLLADAFW::MeshVertexData &pos = mesh->getPositions();
336 if (pos.empty()) {
337 return;
338 }
339
340 int stride = pos.getStride(0);
341 if (stride == 0) {
342 stride = 3;
343 }
344
345 blender_mesh->verts_num = pos.getFloatValues()->getCount() / stride;
347 &blender_mesh->vert_data, CD_PROP_FLOAT3, CD_CONSTRUCT, blender_mesh->verts_num, "position");
348 MutableSpan<float3> positions = blender_mesh->vert_positions_for_write();
349 for (const int i : positions.index_range()) {
350 get_vector(positions[i], pos, i, stride);
351 }
352}
353
354bool 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
377bool 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
398static 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
408void MeshImporter::allocate_poly_data(COLLADAFW::Mesh *collada_mesh, Mesh *mesh)
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 mesh->faces_num = total_poly_count;
450 mesh->corners_num = total_loop_count;
453 &mesh->corner_data, CD_PROP_INT32, CD_SET_DEFAULT, mesh->corners_num, ".corner_vert");
454
455 uint totuvset = collada_mesh->getUVCoords().getInputInfosArray().getCount();
456 for (int i = 0; i < totuvset; i++) {
457 if (collada_mesh->getUVCoords().getLength(i) == 0) {
458 totuvset = 0;
459 break;
460 }
461 }
462
463 if (totuvset > 0) {
464 for (int i = 0; i < totuvset; i++) {
465 COLLADAFW::MeshVertexData::InputInfos *info =
466 collada_mesh->getUVCoords().getInputInfosArray()[i];
467 COLLADAFW::String &uvname = info->mName;
468 /* Allocate space for UV_data */
470 &mesh->corner_data, CD_PROP_FLOAT2, CD_SET_DEFAULT, mesh->corners_num, uvname);
471 }
472 /* activate the first uv map */
474 }
475
476 int totcolset = collada_mesh->getColors().getInputInfosArray().getCount();
477 if (totcolset > 0) {
478 for (int i = 0; i < totcolset; i++) {
479 COLLADAFW::MeshVertexData::InputInfos *info =
480 collada_mesh->getColors().getInputInfosArray()[i];
481 COLLADAFW::String colname = extract_vcolname(info->mName);
484 }
489 }
490 }
491}
492
493uint MeshImporter::get_vertex_count(COLLADAFW::Polygons *mp, int index)
494{
495 int type = mp->getPrimitiveType();
496 int result;
497 switch (type) {
498 case COLLADAFW::MeshPrimitive::TRIANGLES:
499 case COLLADAFW::MeshPrimitive::TRIANGLE_FANS: {
500 result = 3;
501 break;
502 }
503 case COLLADAFW::MeshPrimitive::POLYLIST:
504 case COLLADAFW::MeshPrimitive::POLYGONS: {
505 result = mp->getGroupedVerticesVertexCountArray()[index];
506 break;
507 }
508 default: {
509 result = -1;
510 break;
511 }
512 }
513 return result;
514}
515
516uint MeshImporter::get_loose_edge_count(COLLADAFW::Mesh *mesh)
517{
518 COLLADAFW::MeshPrimitiveArray &prim_arr = mesh->getMeshPrimitives();
519 int loose_edge_count = 0;
520
521 /* collect edge_count and face_count from all parts */
522 for (int i = 0; i < prim_arr.getCount(); i++) {
523 COLLADAFW::MeshPrimitive *mp = prim_arr[i];
524 int type = mp->getPrimitiveType();
525 switch (type) {
526 case COLLADAFW::MeshPrimitive::LINES: {
527 size_t prim_totface = mp->getFaceCount();
528 loose_edge_count += prim_totface;
529 break;
530 }
531 default:
532 break;
533 }
534 }
535 return loose_edge_count;
536}
537
538void MeshImporter::mesh_add_edges(Mesh *mesh, int len)
539{
540 CustomData edge_data;
541 int totedge;
542
543 if (len == 0) {
544 return;
545 }
546
547 totedge = mesh->edges_num + len;
548
549 /* Update custom-data. */
551 &mesh->edge_data, &edge_data, CD_MASK_MESH.emask, CD_SET_DEFAULT, totedge);
552 CustomData_copy_data(&mesh->edge_data, &edge_data, 0, 0, mesh->edges_num);
553
554 if (!CustomData_has_layer_named(&edge_data, CD_PROP_INT32_2D, ".edge_verts")) {
555 CustomData_add_layer_named(&edge_data, CD_PROP_INT32_2D, CD_CONSTRUCT, totedge, ".edge_verts");
556 }
557
559 mesh->edge_data = edge_data;
560
562
563 mesh->edges_num = totedge;
564}
565
566void MeshImporter::read_lines(COLLADAFW::Mesh *mesh, Mesh *blender_mesh)
567{
568 uint loose_edge_count = get_loose_edge_count(mesh);
569 if (loose_edge_count > 0) {
570
571 uint face_edge_count = blender_mesh->edges_num;
572 // uint total_edge_count = loose_edge_count + face_edge_count; /* UNUSED. */
573
574 mesh_add_edges(blender_mesh, loose_edge_count);
575 MutableSpan<blender::int2> edges = blender_mesh->edges_for_write();
576 blender::int2 *edge = edges.data() + face_edge_count;
577
578 COLLADAFW::MeshPrimitiveArray &prim_arr = mesh->getMeshPrimitives();
579
580 for (int index = 0; index < prim_arr.getCount(); index++) {
581 COLLADAFW::MeshPrimitive *mp = prim_arr[index];
582
583 int type = mp->getPrimitiveType();
584 if (type == COLLADAFW::MeshPrimitive::LINES) {
585 uint edge_count = mp->getFaceCount();
586 uint *indices = mp->getPositionIndices().getData();
587
588 for (int j = 0; j < edge_count; j++, edge++) {
589 (*edge)[0] = indices[2 * j];
590 (*edge)[1] = indices[2 * j + 1];
591 }
592 }
593 }
594 }
595}
596
597void MeshImporter::read_polys(COLLADAFW::Mesh *collada_mesh,
598 Mesh *mesh,
600{
601 using namespace blender;
602 uint i;
603
604 allocate_poly_data(collada_mesh, mesh);
605
606 UVDataWrapper uvs(collada_mesh->getUVCoords());
607 VCOLDataWrapper vcol(collada_mesh->getColors());
608
609 MutableSpan<int> face_offsets = mesh->face_offsets_for_write();
610 MutableSpan<int> corner_verts = mesh->corner_verts_for_write();
611 int face_index = 0;
612 int loop_index = 0;
613
614 MaterialIdPrimitiveArrayMap mat_prim_map;
615
616 bke::MutableAttributeAccessor attributes = mesh->attributes_for_write();
617 bke::SpanAttributeWriter material_indices = attributes.lookup_or_add_for_write_span<int>(
618 "material_index", bke::AttrDomain::Face);
619 bke::SpanAttributeWriter sharp_faces = attributes.lookup_or_add_for_write_span<bool>(
620 "sharp_face", bke::AttrDomain::Face);
621
622 COLLADAFW::MeshPrimitiveArray &prim_arr = collada_mesh->getMeshPrimitives();
623 COLLADAFW::MeshVertexData &nor = collada_mesh->getNormals();
624
625 for (i = 0; i < prim_arr.getCount(); i++) {
626
627 COLLADAFW::MeshPrimitive *mp = prim_arr[i];
628
629 /* faces */
630 size_t prim_faces_num = mp->getFaceCount();
631 uint *position_indices = mp->getPositionIndices().getData();
632 uint *normal_indices = mp->getNormalIndices().getData();
633
634 bool mp_has_normals = primitive_has_useable_normals(mp);
635 bool mp_has_faces = primitive_has_faces(mp);
636
637 int collada_meshtype = mp->getPrimitiveType();
638
639 if (collada_meshtype == COLLADAFW::MeshPrimitive::LINES) {
640 continue; /* read the lines later after all the rest is done */
641 }
642
643 /* Since we cannot set `poly->mat_nr` here, we store a portion of `mesh->mpoly` in Primitive.
644 */
645 Primitive prim = {face_index, &material_indices.span[face_index], 0};
646
647 /* If MeshPrimitive is TRIANGLE_FANS we split it into triangles
648 * The first triangle-fan vertex will be the first vertex in every triangle
649 * XXX The proper function of TRIANGLE_FANS is not tested!!!
650 * XXX In particular the handling of the normal_indices is very wrong */
651 /* TODO: UV, vertex color and custom normal support */
652 if (collada_meshtype == COLLADAFW::MeshPrimitive::TRIANGLE_FANS) {
653 uint grouped_vertex_count = mp->getGroupedVertexElementsCount();
654 for (uint group_index = 0; group_index < grouped_vertex_count; group_index++) {
655 uint first_vertex = position_indices[0]; /* Store first triangle-fan vertex. */
656 uint first_normal = normal_indices[0]; /* Store first triangle-fan vertex normal. */
657 uint vertex_count = mp->getGroupedVerticesVertexCount(group_index);
658
659 for (uint vertex_index = 0; vertex_index < vertex_count - 2; vertex_index++) {
660 /* For each triangle store indices of its 3 vertices */
661 uint triangle_vertex_indices[3] = {
662 first_vertex, position_indices[1], position_indices[2]};
663 face_offsets[face_index] = loop_index;
664 set_poly_indices(&corner_verts[loop_index], loop_index, triangle_vertex_indices, 3);
665
666 if (mp_has_normals) { /* vertex normals, same implementation as for the triangles */
667 /* The same for vertices normals. */
668 uint vertex_normal_indices[3] = {first_normal, normal_indices[1], normal_indices[2]};
669 sharp_faces.span[face_index] = is_flat_face(vertex_normal_indices, nor, 3);
670 normal_indices++;
671 }
672
673 face_index++;
674 loop_index += 3;
675 prim.faces_num++;
676 }
677
678 /* Moving cursor to the next triangle fan. */
679 if (mp_has_normals) {
680 normal_indices += 2;
681 }
682
683 position_indices += 2;
684 }
685 }
686
687 if (ELEM(collada_meshtype,
688 COLLADAFW::MeshPrimitive::POLYLIST,
689 COLLADAFW::MeshPrimitive::POLYGONS,
690 COLLADAFW::MeshPrimitive::TRIANGLES))
691 {
692 COLLADAFW::Polygons *mpvc = (COLLADAFW::Polygons *)mp;
693 uint start_index = 0;
694
695 COLLADAFW::IndexListArray &index_list_array_uvcoord = mp->getUVCoordIndicesArray();
696 COLLADAFW::IndexListArray &index_list_array_vcolor = mp->getColorIndicesArray();
697
698 int invalid_loop_holes = 0;
699 for (uint j = 0; j < prim_faces_num; j++) {
700
701 /* Vertices in polygon: */
702 int vcount = get_vertex_count(mpvc, j);
703 if (vcount < 0) {
704 continue; /* TODO: add support for holes */
705 }
706
707 face_offsets[face_index] = loop_index;
708 bool broken_loop = set_poly_indices(
709 &corner_verts[loop_index], loop_index, position_indices, vcount);
710 if (broken_loop) {
711 invalid_loop_holes += 1;
712 }
713
714 for (uint uvset_index = 0; uvset_index < index_list_array_uvcoord.getCount();
715 uvset_index++)
716 {
717 COLLADAFW::IndexList &index_list = *index_list_array_uvcoord[uvset_index];
718 blender::float2 *mloopuv = static_cast<blender::float2 *>(
720 &mesh->corner_data, CD_PROP_FLOAT2, index_list.getName(), mesh->corners_num));
721 if (mloopuv == nullptr) {
722 fprintf(stderr,
723 "Collada import: Mesh [%s] : Unknown reference to TEXCOORD [#%s].\n",
724 mesh->id.name,
725 index_list.getName().c_str());
726 }
727 else {
728 set_face_uv(mloopuv + loop_index,
729 uvs,
730 start_index,
731 *index_list_array_uvcoord[uvset_index],
732 vcount);
733 }
734 }
735
736 if (mp_has_normals) {
737 /* If it turns out that we have complete custom normals for each poly
738 * and we want to use custom normals, this will be overridden. */
739 sharp_faces.span[face_index] = is_flat_face(normal_indices, nor, vcount);
740
741 if (use_custom_normals) {
742 /* Store the custom normals for later application. */
743 float vert_normal[3];
744 uint *cur_normal = normal_indices;
745 for (int k = 0; k < vcount; k++, cur_normal++) {
746 get_vector(vert_normal, nor, *cur_normal, 3);
747 normalize_v3(vert_normal);
748 loop_normals.append(vert_normal);
749 }
750 }
751 }
752
753 if (mp->hasColorIndices()) {
754 int vcolor_count = index_list_array_vcolor.getCount();
755
756 for (uint vcolor_index = 0; vcolor_index < vcolor_count; vcolor_index++) {
757
758 COLLADAFW::IndexList &color_index_list = *mp->getColorIndices(vcolor_index);
759 COLLADAFW::String colname = extract_vcolname(color_index_list.getName());
761 &mesh->corner_data, CD_PROP_BYTE_COLOR, colname, mesh->corners_num);
762 if (mloopcol == nullptr) {
763 fprintf(stderr,
764 "Collada import: Mesh [%s] : Unknown reference to VCOLOR [#%s].\n",
765 mesh->id.name,
766 color_index_list.getName().c_str());
767 }
768 else {
769 set_vcol(mloopcol + loop_index, vcol, start_index, color_index_list, vcount);
770 }
771 }
772 }
773
774 face_index++;
775 loop_index += vcount;
776 start_index += vcount;
777 prim.faces_num++;
778
779 if (mp_has_normals) {
780 normal_indices += vcount;
781 }
782
783 position_indices += vcount;
784 }
785
786 if (invalid_loop_holes > 0) {
787 fprintf(stderr,
788 "Collada import: Mesh [%s] : contains %d unsupported loops (holes).\n",
789 mesh->id.name,
790 invalid_loop_holes);
791 }
792 }
793
794 if (mp_has_faces) {
795 mat_prim_map[mp->getMaterialId()].push_back(prim);
796 }
797 }
798
799 geom_uid_mat_mapping_map[collada_mesh->getUniqueId()] = mat_prim_map;
800 material_indices.finish();
801 sharp_faces.finish();
802}
803
804void MeshImporter::get_vector(float v[3], COLLADAFW::MeshVertexData &arr, int i, int stride)
805{
806 i *= stride;
807
808 switch (arr.getType()) {
809 case COLLADAFW::MeshVertexData::DATA_TYPE_FLOAT: {
810 COLLADAFW::ArrayPrimitiveType<float> *values = arr.getFloatValues();
811 if (values->empty()) {
812 return;
813 }
814
815 v[0] = (*values)[i++];
816 v[1] = (*values)[i++];
817 if (stride >= 3) {
818 v[2] = (*values)[i];
819 }
820 else {
821 v[2] = 0.0f;
822 }
823 break;
824 }
825 case COLLADAFW::MeshVertexData::DATA_TYPE_DOUBLE: {
826 COLLADAFW::ArrayPrimitiveType<double> *values = arr.getDoubleValues();
827 if (values->empty()) {
828 return;
829 }
830
831 v[0] = float((*values)[i++]);
832 v[1] = float((*values)[i++]);
833 if (stride >= 3) {
834 v[2] = float((*values)[i]);
835 }
836 else {
837 v[2] = 0.0f;
838 }
839 break;
840 }
841 default:
842 break;
843 }
844}
845
846bool MeshImporter::is_flat_face(uint *nind, COLLADAFW::MeshVertexData &nor, int count)
847{
848 float a[3], b[3];
849
850 get_vector(a, nor, *nind, 3);
851 normalize_v3(a);
852
853 nind++;
854
855 for (int i = 1; i < count; i++, nind++) {
856 get_vector(b, nor, *nind, 3);
858
859 float dp = dot_v3v3(a, b);
860
861 if (dp < 0.99999f || dp > 1.00001f) {
862 return false;
863 }
864 }
865
866 return true;
867}
868
869Object *MeshImporter::get_object_by_geom_uid(const COLLADAFW::UniqueId &geom_uid)
870{
871 if (uid_object_map.find(geom_uid) != uid_object_map.end()) {
872 return uid_object_map[geom_uid];
873 }
874 return nullptr;
875}
876
877Mesh *MeshImporter::get_mesh_by_geom_uid(const COLLADAFW::UniqueId &geom_uid)
878{
879 if (uid_mesh_map.find(geom_uid) != uid_mesh_map.end()) {
880 return uid_mesh_map[geom_uid];
881 }
882 return nullptr;
883}
884
885std::string *MeshImporter::get_geometry_name(const std::string &mesh_name)
886{
887 if (this->mesh_geom_map.find(mesh_name) != this->mesh_geom_map.end()) {
888 return &this->mesh_geom_map[mesh_name];
889 }
890 return nullptr;
891}
892
894{
895 for (const int vert_i : mesh->corner_verts()) {
896 if (vert_i >= mesh->verts_num) {
897 return true;
898 }
899 }
900 return false;
901}
902
909{
910 if (ob1->totcol != ob2->totcol) {
911 return false; /* not same number of materials */
912 }
913 if (ob1->totcol == 0) {
914 return false; /* no material at all */
915 }
916
917 for (int index = 0; index < ob1->totcol; index++) {
918 if (ob1->matbits[index] != ob2->matbits[index]) {
919 return false; /* shouldn't happen */
920 }
921 if (ob1->matbits[index] == 0) {
922 return false; /* shouldn't happen */
923 }
924 if (ob1->mat[index] != ob2->mat[index]) {
925 return false; /* different material assignment */
926 }
927 }
928 return true;
929}
930
936static void bc_copy_materials_to_data(Object *ob, Mesh *mesh)
937{
938 for (int index = 0; index < ob->totcol; index++) {
939 ob->matbits[index] = 0;
940 mesh->mat[index] = ob->mat[index];
941 }
942}
943
948{
949 for (int index = 0; index < ob->totcol; index++) {
950 ob->matbits[index] = 0;
951 ob->mat[index] = nullptr;
952 }
953}
954
955std::vector<Object *> MeshImporter::get_all_users_of(Mesh *reference_mesh)
956{
957 std::vector<Object *> mesh_users;
958 for (Object *ob : imported_objects) {
959 if (bc_is_marked(ob)) {
960 bc_remove_mark(ob);
961 Mesh *mesh = (Mesh *)ob->data;
962 if (mesh == reference_mesh) {
963 mesh_users.push_back(ob);
964 }
965 }
966 }
967 return mesh_users;
968}
969
971{
972 for (Object *ob : imported_objects) {
973 Mesh *mesh = (Mesh *)ob->data;
974 if (ID_REAL_USERS(&mesh->id) == 1) {
977 bc_remove_mark(ob);
978 }
979 else if (ID_REAL_USERS(&mesh->id) > 1) {
980 bool can_move = true;
981 std::vector<Object *> mesh_users = get_all_users_of(mesh);
982 if (mesh_users.size() > 1) {
983 Object *ref_ob = mesh_users[0];
984 for (int index = 1; index < mesh_users.size(); index++) {
985 if (!bc_has_same_material_configuration(ref_ob, mesh_users[index])) {
986 can_move = false;
987 break;
988 }
989 }
990 if (can_move) {
991 bc_copy_materials_to_data(ref_ob, mesh);
992 for (Object *object : mesh_users) {
994 bc_remove_mark(object);
995 }
996 }
997 }
998 }
999 }
1000}
1001
1003 COLLADAFW::MaterialBinding cmaterial,
1004 std::map<COLLADAFW::UniqueId, Material *> &uid_material_map,
1005 Object *ob,
1006 const COLLADAFW::UniqueId *geom_uid,
1007 short mat_index)
1008{
1009 const COLLADAFW::UniqueId &ma_uid = cmaterial.getReferencedMaterial();
1010
1011 /* do we know this material? */
1012 if (uid_material_map.find(ma_uid) == uid_material_map.end()) {
1013
1014 fprintf(stderr, "Cannot find material by UID.\n");
1015 return;
1016 }
1017
1018 /* first time we get geom_uid, ma_uid pair. Save for later check. */
1019 materials_mapped_to_geom.insert(
1020 std::pair<COLLADAFW::UniqueId, COLLADAFW::UniqueId>(*geom_uid, ma_uid));
1021
1022 Material *ma = uid_material_map[ma_uid];
1023
1024 /* Attention! This temporarily assigns material to object on purpose!
1025 * See note above. */
1026 ob->actcol = 0;
1027 BKE_object_material_assign(m_bmain, ob, ma, mat_index + 1, BKE_MAT_ASSIGN_OBJECT);
1028
1029 MaterialIdPrimitiveArrayMap &mat_prim_map = geom_uid_mat_mapping_map[*geom_uid];
1030 COLLADAFW::MaterialId mat_id = cmaterial.getMaterialId();
1031
1032 /* assign material indices to mesh faces */
1033 if (mat_prim_map.find(mat_id) != mat_prim_map.end()) {
1034
1035 std::vector<Primitive> &prims = mat_prim_map[mat_id];
1036
1037 std::vector<Primitive>::iterator it;
1038
1039 for (it = prims.begin(); it != prims.end(); it++) {
1040 Primitive &prim = *it;
1041
1042 for (int i = 0; i < prim.faces_num; i++) {
1043 prim.material_indices[i] = mat_index;
1044 }
1045 }
1046 }
1047}
1048
1050 COLLADAFW::Node *node,
1051 COLLADAFW::InstanceGeometry *geom,
1052 bool isController,
1053 std::map<COLLADAFW::UniqueId, Material *> &uid_material_map)
1054{
1055 const COLLADAFW::UniqueId *geom_uid = &geom->getInstanciatedObjectId();
1056
1057 /* check if node instantiates controller or geometry */
1058 if (isController) {
1059
1060 geom_uid = armature_importer->get_geometry_uid(*geom_uid);
1061
1062 if (!geom_uid) {
1063 fprintf(stderr, "Couldn't find a mesh UID by controller's UID.\n");
1064 return nullptr;
1065 }
1066 }
1067 else {
1068
1069 if (uid_mesh_map.find(*geom_uid) == uid_mesh_map.end()) {
1070 /* this could happen if a mesh was not created
1071 * (e.g. if it contains unsupported geometry) */
1072 fprintf(stderr, "Couldn't find a mesh by UID.\n");
1073 return nullptr;
1074 }
1075 }
1076 if (!uid_mesh_map[*geom_uid]) {
1077 return nullptr;
1078 }
1079
1080 /* name Object */
1081 const std::string &id = node->getName().empty() ? node->getOriginalId() : node->getName();
1082 const char *name = id.length() ? id.c_str() : nullptr;
1083
1084 /* add object */
1085 Object *ob = bc_add_object(m_bmain, scene, view_layer, OB_MESH, name);
1086 bc_set_mark(ob); /* used later for material assignment optimization */
1087
1088 /* store object pointer for ArmatureImporter */
1089 uid_object_map[*geom_uid] = ob;
1090 imported_objects.push_back(ob);
1091
1092 /* replace ob->data freeing the old one */
1093 Mesh *old_mesh = (Mesh *)ob->data;
1094 Mesh *new_mesh = uid_mesh_map[*geom_uid];
1095
1096 BKE_mesh_assign_object(m_bmain, ob, new_mesh);
1097
1098 /* Because BKE_mesh_assign_object would have already decreased it... */
1099 id_us_plus(&old_mesh->id);
1100
1101 BKE_id_free_us(m_bmain, old_mesh);
1102
1103 COLLADAFW::MaterialBindingArray &mat_array = geom->getMaterialBindings();
1104
1105 /* loop through geom's materials */
1106 for (uint i = 0; i < mat_array.getCount(); i++) {
1107
1108 if (mat_array[i].getReferencedMaterial().isValid()) {
1109 assign_material_to_geom(mat_array[i], uid_material_map, ob, geom_uid, i);
1110 }
1111 else {
1112 fprintf(stderr, "invalid referenced material for %s\n", mat_array[i].getName().c_str());
1113 }
1114 }
1115
1116 /* clean up the mesh */
1117 BKE_mesh_validate((Mesh *)ob->data, false, false);
1118
1119 return ob;
1120}
1121
1122bool MeshImporter::write_geometry(const COLLADAFW::Geometry *geom)
1123{
1124 using namespace blender;
1125 if (geom->getType() != COLLADAFW::Geometry::GEO_TYPE_MESH) {
1126 /* TODO: report warning */
1127 fprintf(stderr, "Mesh type %s is not supported\n", bc_geomTypeToStr(geom->getType()));
1128 return true;
1129 }
1130
1131 COLLADAFW::Mesh *mesh = (COLLADAFW::Mesh *)geom;
1132
1133 if (!is_nice_mesh(mesh)) {
1134 fprintf(stderr, "Ignoring mesh %s\n", bc_get_dae_name(mesh).c_str());
1135 return true;
1136 }
1137
1138 const std::string &str_geom_id = mesh->getName().empty() ? mesh->getOriginalId() :
1139 mesh->getName();
1140 Mesh *blender_mesh = BKE_mesh_add(m_bmain, (char *)str_geom_id.c_str());
1141 id_us_min(
1142 &blender_mesh->id); /* is already 1 here, but will be set later in BKE_mesh_assign_object */
1143
1144 /* store the Mesh pointer to link it later with an Object
1145 * mesh_geom_map needed to map mesh to its geometry name (for shape key naming) */
1146 this->uid_mesh_map[mesh->getUniqueId()] = blender_mesh;
1147 this->mesh_geom_map[std::string(blender_mesh->id.name)] = str_geom_id;
1148
1149 read_vertices(mesh, blender_mesh);
1150
1152 read_polys(mesh, blender_mesh, loop_normals);
1153
1154 blender::bke::mesh_calc_edges(*blender_mesh, false, false);
1155
1156 /* We must apply custom normals after edges have been calculated, because
1157 * bke::mesh_set_custom_normals()'s internals expect mesh->medge to be populated
1158 * and for the MLoops to have correct edge indices. */
1159 if (use_custom_normals && !loop_normals.is_empty()) {
1160 /* bke::mesh_set_custom_normals()'s internals also expect that each corner
1161 * has a valid vertex index, which may not be the case due to the existing
1162 * logic in read_faces(). This check isn't necessary in the no-custom-normals
1163 * case because the invalid MLoops get stripped in a later step. */
1164 if (bc_has_out_of_bound_indices(blender_mesh)) {
1165 fprintf(stderr, "Can't apply custom normals, encountered invalid loop vert indices!\n");
1166 }
1167 /* There may be a mismatch in lengths if one or more of the MeshPrimitives in
1168 * the Geometry had missing or otherwise invalid normals. */
1169 else if (blender_mesh->corners_num != loop_normals.size()) {
1170 fprintf(stderr,
1171 "Can't apply custom normals, mesh->corners_num != loop_normals.size() (%d != %d)\n",
1172 blender_mesh->corners_num,
1173 int(loop_normals.size()));
1174 }
1175 else {
1176 bke::mesh_set_custom_normals(*blender_mesh, loop_normals);
1177 }
1178 }
1179
1180 /* read_lines() must be called after the face edges have been generated.
1181 * Otherwise the loose edges will be silently deleted again. */
1182 read_lines(mesh, blender_mesh);
1183
1184 return true;
1185}
void BKE_id_attributes_default_color_set(struct ID *id, std::optional< blender::StringRef > name)
void BKE_id_attributes_active_color_set(struct ID *id, std::optional< blender::StringRef > name)
Definition attribute.cc:986
CustomData interface, see also DNA_customdata_types.h.
void * CustomData_get_layer_named_for_write(CustomData *data, eCustomDataType type, blender::StringRef name, int totelem)
@ CD_SET_DEFAULT
@ CD_CONSTRUCT
void * CustomData_add_layer_named(CustomData *data, eCustomDataType type, eCDAllocType alloctype, int totelem, blender::StringRef name)
bool CustomData_has_layer_named(const CustomData *data, eCustomDataType type, blender::StringRef name)
const char * CustomData_get_layer_name(const CustomData *data, eCustomDataType type, int n)
void CustomData_free(CustomData *data)
void CustomData_init_layout_from(const CustomData *source, CustomData *dest, eCustomDataMask mask, eCDAllocType alloctype, int totelem)
void CustomData_copy_data(const CustomData *source, CustomData *dest, int source_index, int dest_index, int count)
void CustomData_set_layer_active(CustomData *data, eCustomDataType type, int n)
const CustomData_MeshMasks CD_MASK_MESH
void BKE_id_free_us(Main *bmain, void *idv) ATTR_NONNULL()
void id_us_plus(ID *id)
Definition lib_id.cc:353
void id_us_min(ID *id)
Definition lib_id.cc:361
General operations, lookup, etc. for materials.
@ BKE_MAT_ASSIGN_OBJECT
void BKE_object_material_assign(Main *bmain, Object *ob, Material *ma, short act, int assign_type)
bool BKE_mesh_validate(Mesh *mesh, bool do_verbose, bool cddata_check_mask)
Mesh * BKE_mesh_add(Main *bmain, const char *name)
void BKE_mesh_assign_object(Main *bmain, Object *ob, Mesh *mesh)
void BKE_mesh_face_offsets_ensure_alloc(Mesh *mesh)
void BKE_mesh_runtime_clear_cache(Mesh *mesh)
General operations, lookup, etc. for blender objects.
MINLINE float dot_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT
MINLINE float normalize_v3(float n[3])
unsigned int uint
#define ELEM(...)
void bc_remove_mark(Object *ob)
int bc_is_marked(Object *ob)
void bc_set_mark(Object *ob)
@ CD_PROP_BYTE_COLOR
@ CD_PROP_FLOAT3
@ CD_PROP_INT32_2D
@ CD_PROP_INT32
@ CD_PROP_FLOAT2
struct CustomData CustomData
struct Mesh Mesh
struct MLoopCol MLoopCol
@ OB_MESH
struct Object Object
static bool bc_has_same_material_configuration(Object *ob1, Object *ob2)
static bool bc_has_out_of_bound_indices(Mesh *mesh)
static void bc_remove_materials_from_object(Object *ob, Mesh *mesh)
static void bc_copy_materials_to_data(Object *ob, Mesh *mesh)
static const char * bc_geomTypeToStr(COLLADAFW::Geometry::GeometryType type)
static std::string extract_vcolname(const COLLADAFW::String &collada_id)
static const char * bc_primTypeToStr(COLLADAFW::MeshPrimitive::PrimitiveType type)
static void colladaAddColor(T values, MLoopCol *mloopcol, int v_index, int stride)
static std::string bc_get_dae_name(T *node)
ATTR_WARN_UNUSED_RESULT const BMVert * v
virtual const char * getName() const
Mesh * get_mesh_by_geom_uid(const COLLADAFW::UniqueId &geom_uid) override
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)
MeshImporter(UnitConverter *unitconv, bool use_custom_normals, ArmatureImporter *arm, Main *bmain, Scene *sce, ViewLayer *view_layer)
Object * create_mesh_object(COLLADAFW::Node *node, COLLADAFW::InstanceGeometry *geom, bool isController, std::map< COLLADAFW::UniqueId, Material * > &uid_material_map)
std::string * get_geometry_name(const std::string &mesh_name) override
Object * get_object_by_geom_uid(const COLLADAFW::UniqueId &geom_uid) override
UVDataWrapper(COLLADAFW::MeshVertexData &vdata)
void getUV(int uv_index, float *uv)
void get_vcol(int v_index, MLoopCol *mloopcol)
VCOLDataWrapper(COLLADAFW::MeshVertexData &vdata)
constexpr T * data() const
Definition BLI_span.hh:539
constexpr IndexRange index_range() const
Definition BLI_span.hh:670
int64_t size() const
void append(const T &value)
bool is_empty() const
GSpanAttributeWriter lookup_or_add_for_write_span(StringRef attribute_id, AttrDomain domain, eCustomDataType data_type, const AttributeInit &initializer=AttributeInitDefaultValue())
Object * bc_add_object(Main *bmain, Scene *scene, ViewLayer *view_layer, int type, const char *name)
static ushort indices[]
uint pos
uint nor
#define this
#define abs
#define ID_REAL_USERS(id)
int count
MINLINE unsigned char unit_float_to_uchar_clamp(float val)
#define T
void mesh_calc_edges(Mesh &mesh, bool keep_existing_edges, bool select_new_edges)
void mesh_set_custom_normals(Mesh &mesh, MutableSpan< float3 > corner_normals)
VecBase< int32_t, 2 > int2
VecBase< float, 2 > float2
VecBase< float, 3 > float3
char name[66]
Definition DNA_ID.h:415
unsigned char a
unsigned char b
unsigned char r
unsigned char g
int corners_num
CustomData edge_data
int edges_num
struct Material ** mat
CustomData corner_data
CustomData vert_data
int faces_num
int verts_num
struct Material ** mat
char * matbits
i
Definition text_draw.cc:230
uint len