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