Blender V4.3
GeometryExporter.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 <sstream>
10
11#include "COLLADABUUtils.h"
12#include "COLLADASWPrimitves.h"
13#include "COLLADASWSource.h"
14#include "COLLADASWVertices.h"
15
16#include "GeometryExporter.h"
17
18#include "DNA_meshdata_types.h"
19
21#include "BLI_utildefines.h"
22
23#include "BKE_attribute.hh"
24#include "BKE_customdata.hh"
25#include "BKE_global.hh"
26#include "BKE_lib_id.hh"
27#include "BKE_material.h"
28#include "BKE_mesh.hh"
29
30#include "collada_internal.h"
31#include "collada_utils.h"
32
33using blender::float3;
34using blender::Span;
37{
38 Scene *sce = blender_context.get_scene();
39 openLibrary();
40
43 sce, *this, this->export_settings.get_export_set());
44
45 closeLibrary();
46}
47
49{
50 bool use_instantiation = this->export_settings.get_use_object_instantiation();
51 Mesh *mesh = bc_get_mesh_copy(blender_context,
52 ob,
53 this->export_settings.get_export_mesh_type(),
54 this->export_settings.get_apply_modifiers(),
55 this->export_settings.get_triangulate());
56
57 std::string geom_id = get_geometry_id(ob, use_instantiation);
58 std::vector<Normal> nor;
59 std::vector<BCPolygonNormalsIndices> norind;
60
61 /* Skip if linked geometry was already exported from another reference */
62 if (use_instantiation && exportedGeometry.find(geom_id) != exportedGeometry.end()) {
63 return;
64 }
65
66 std::string geom_name = (use_instantiation) ? id_name(ob->data) : id_name(ob);
67 geom_name = encode_xml(geom_name);
68
69 exportedGeometry.insert(geom_id);
70
71 bool has_color = bool(CustomData_has_layer(&mesh->fdata_legacy, CD_MCOL));
72
73 create_normals(nor, norind, mesh);
74
75 /* openMesh(geoId, geoName, meshId) */
76 openMesh(geom_id, geom_name);
77
78 /* writes <source> for vertex coords */
79 createVertsSource(geom_id, mesh);
80
81 /* writes <source> for normal coords */
82 createNormalsSource(geom_id, mesh, nor);
83
84 bool has_uvs = bool(CustomData_has_layer(&mesh->corner_data, CD_PROP_FLOAT2));
85
86 /* writes <source> for uv coords if mesh has uv coords */
87 if (has_uvs) {
88 createTexcoordsSource(geom_id, mesh);
89 }
90
91 if (has_color) {
92 createVertexColorSource(geom_id, mesh);
93 }
94 /* <vertices> */
95
96 COLLADASW::Vertices verts(mSW);
97 verts.setId(getIdBySemantics(geom_id, COLLADASW::InputSemantic::VERTEX));
98 COLLADASW::InputList &input_list = verts.getInputList();
99 COLLADASW::Input input(COLLADASW::InputSemantic::POSITION,
100 getUrlBySemantics(geom_id, COLLADASW::InputSemantic::POSITION));
101 input_list.push_back(input);
102 verts.add();
103
104 createLooseEdgeList(ob, mesh, geom_id);
105
106 /* Only create poly-lists if number of faces > 0. */
107 if (mesh->totface_legacy > 0) {
108 /* XXX slow */
109 if (ob->totcol) {
110 for (int a = 0; a < ob->totcol; a++) {
111 create_mesh_primitive_list(a, has_uvs, has_color, ob, mesh, geom_id, norind);
112 }
113 }
114 else {
115 create_mesh_primitive_list(0, has_uvs, has_color, ob, mesh, geom_id, norind);
116 }
117 }
118
119 closeMesh();
120
121 closeGeometry();
122
123 if (this->export_settings.get_include_shapekeys()) {
124 Key *key = BKE_key_from_object(ob);
125 if (key) {
126 blender::MutableSpan<float3> positions = mesh->vert_positions_for_write();
127 KeyBlock *kb = (KeyBlock *)key->block.first;
128 /* skip the basis */
129 kb = kb->next;
130 for (; kb; kb = kb->next) {
132 kb, reinterpret_cast<float(*)[3]>(positions.data()), mesh->verts_num);
133 export_key_mesh(ob, mesh, kb);
134 }
135 }
136 }
137
138 BKE_id_free(nullptr, mesh);
139}
140
142{
143 std::string geom_id = get_geometry_id(ob, false) + "_morph_" + translate_id(kb->name);
144 std::vector<Normal> nor;
145 std::vector<BCPolygonNormalsIndices> norind;
146
147 if (exportedGeometry.find(geom_id) != exportedGeometry.end()) {
148 return;
149 }
150
151 std::string geom_name = kb->name;
152
153 exportedGeometry.insert(geom_id);
154
155 bool has_color = bool(CustomData_has_layer(&mesh->fdata_legacy, CD_MCOL));
156
157 create_normals(nor, norind, mesh);
158
159 // openMesh(geoId, geoName, meshId)
160 openMesh(geom_id, geom_name);
161
162 /* writes <source> for vertex coords */
163 createVertsSource(geom_id, mesh);
164
165 /* writes <source> for normal coords */
166 createNormalsSource(geom_id, mesh, nor);
167
168 bool has_uvs = bool(CustomData_has_layer(&mesh->corner_data, CD_PROP_FLOAT2));
169
170 /* writes <source> for uv coords if mesh has uv coords */
171 if (has_uvs) {
172 createTexcoordsSource(geom_id, mesh);
173 }
174
175 if (has_color) {
176 createVertexColorSource(geom_id, mesh);
177 }
178
179 /* <vertices> */
180
181 COLLADASW::Vertices verts(mSW);
182 verts.setId(getIdBySemantics(geom_id, COLLADASW::InputSemantic::VERTEX));
183 COLLADASW::InputList &input_list = verts.getInputList();
184 COLLADASW::Input input(COLLADASW::InputSemantic::POSITION,
185 getUrlBySemantics(geom_id, COLLADASW::InputSemantic::POSITION));
186 input_list.push_back(input);
187 verts.add();
188
189 // createLooseEdgeList(ob, mesh, geom_id, norind);
190
191 /* XXX slow */
192 if (ob->totcol) {
193 for (int a = 0; a < ob->totcol; a++) {
194 create_mesh_primitive_list(a, has_uvs, has_color, ob, mesh, geom_id, norind);
195 }
196 }
197 else {
198 create_mesh_primitive_list(0, has_uvs, has_color, ob, mesh, geom_id, norind);
199 }
200
201 closeMesh();
202
203 closeGeometry();
204}
205
206void GeometryExporter::createLooseEdgeList(Object *ob, Mesh *mesh, std::string &geom_id)
207{
208 using namespace blender;
209 const Span<int2> edges = mesh->edges();
210 int edges_in_linelist = 0;
211 std::vector<uint> edge_list;
212 int index;
213
214 /* Find all loose edges in Mesh
215 * and save vertex indices in edge_list */
216 const bke::LooseEdgeCache &loose_edges = mesh->loose_edges();
217 if (loose_edges.count > 0) {
218 for (const int64_t i : edges.index_range()) {
219 if (loose_edges.is_loose_bits[i]) {
220 const int2 &edge = edges[i];
221 edges_in_linelist += 1;
222 edge_list.push_back(edge[0]);
223 edge_list.push_back(edge[1]);
224 }
225 }
226 }
227
228 if (edges_in_linelist > 0) {
229 /* Create the list of loose edges */
230 COLLADASW::Lines lines(mSW);
231
232 lines.setCount(edges_in_linelist);
233
234 COLLADASW::InputList &til = lines.getInputList();
235
236 /* creates <input> in <lines> for vertices */
237 COLLADASW::Input input1(COLLADASW::InputSemantic::VERTEX,
238 getUrlBySemantics(geom_id, COLLADASW::InputSemantic::VERTEX),
239 0);
240 til.push_back(input1);
241
242 lines.prepareToAppendValues();
243
244 for (index = 0; index < edges_in_linelist; index++) {
245 lines.appendValues(edge_list[2 * index + 1]);
246 lines.appendValues(edge_list[2 * index]);
247 }
248 lines.finish();
249 }
250}
251
252static void prepareToAppendValues(bool is_triangulated,
253 COLLADASW::PrimitivesBase &primitive_list,
254 std::vector<ulong> &vcount_list)
255{
256 /* performs the actual writing */
257 if (is_triangulated) {
258 ((COLLADASW::Triangles &)primitive_list).prepareToAppendValues();
259 }
260 else {
261 /* sets <vcount> */
262 primitive_list.setVCountList(vcount_list);
263 ((COLLADASW::Polylist &)primitive_list).prepareToAppendValues();
264 }
265}
266
267static void finish_and_delete_primitive_List(bool is_triangulated,
268 COLLADASW::PrimitivesBase *primitive_list)
269{
270 if (is_triangulated) {
271 ((COLLADASW::Triangles *)primitive_list)->finish();
272 }
273 else {
274 ((COLLADASW::Polylist *)primitive_list)->finish();
275 }
276 delete primitive_list;
277}
278
279static COLLADASW::PrimitivesBase *create_primitive_list(bool is_triangulated,
280 COLLADASW::StreamWriter *mSW)
281{
282 COLLADASW::PrimitivesBase *primitive_list;
283
284 if (is_triangulated) {
285 primitive_list = new COLLADASW::Triangles(mSW);
286 }
287 else {
288 primitive_list = new COLLADASW::Polylist(mSW);
289 }
290 return primitive_list;
291}
292
294 int material_index,
295 std::vector<ulong> &vcount_list)
296{
297 using namespace blender;
298 const blender::OffsetIndices faces = mesh->faces();
299 const blender::bke::AttributeAccessor attributes = mesh->attributes();
300 const blender::VArray<int> material_indices = *attributes.lookup_or_default<int>(
301 "material_index", bke::AttrDomain::Face, 0);
302 bool is_triangulated = true;
303
304 /* Expecting that the material index is always 0 if the mesh has no materials assigned */
305 for (const int i : faces.index_range()) {
306 if (material_indices[i] == material_index) {
307 const int vertex_count = faces[i].size();
308 vcount_list.push_back(vertex_count);
309 if (vertex_count != 3) {
310 is_triangulated = false;
311 }
312 }
313 }
314 return is_triangulated;
315}
316
317std::string GeometryExporter::makeVertexColorSourceId(std::string &geom_id, const char *layer_name)
318{
319 std::string result = getIdBySemantics(geom_id, COLLADASW::InputSemantic::COLOR) + "-" +
320 layer_name;
321 return result;
322}
323
325 bool has_uvs,
326 bool has_color,
327 Object *ob,
328 Mesh *mesh,
329 std::string &geom_id,
330 std::vector<BCPolygonNormalsIndices> &norind)
331{
332 using namespace blender;
333 const blender::OffsetIndices faces = mesh->faces();
334 const Span<int> corner_verts = mesh->corner_verts();
335
336 std::vector<ulong> vcount_list;
337
338 bool is_triangulated = collect_vertex_counts_per_poly(mesh, material_index, vcount_list);
339 int polygon_count = vcount_list.size();
340
341 /* no faces using this material */
342 if (polygon_count == 0) {
343 fprintf(
344 stderr, "%s: material with index %d is not used.\n", id_name(ob).c_str(), material_index);
345 return;
346 }
347
348 Material *ma = ob->totcol ? BKE_object_material_get(ob, material_index + 1) : nullptr;
349 COLLADASW::PrimitivesBase *primitive_list = create_primitive_list(is_triangulated, mSW);
350
351 /* sets count attribute in `<polylist>`. */
352 primitive_list->setCount(polygon_count);
353
354 /* sets material name */
355 if (ma) {
356 std::string material_id = get_material_id(ma);
357 std::ostringstream ostr;
358 ostr << translate_id(material_id);
359 primitive_list->setMaterial(ostr.str());
360 }
361
362 COLLADASW::Input vertex_input(COLLADASW::InputSemantic::VERTEX,
363 getUrlBySemantics(geom_id, COLLADASW::InputSemantic::VERTEX),
364 0);
365 COLLADASW::Input normals_input(COLLADASW::InputSemantic::NORMAL,
366 getUrlBySemantics(geom_id, COLLADASW::InputSemantic::NORMAL),
367 1);
368
369 COLLADASW::InputList &til = primitive_list->getInputList();
370 til.push_back(vertex_input);
371 til.push_back(normals_input);
372
373 /* if mesh has uv coords writes <input> for TEXCOORD */
374 int num_layers = CustomData_number_of_layers(&mesh->corner_data, CD_PROP_FLOAT2);
375 int active_uv = CustomData_get_active_layer(&mesh->corner_data, CD_PROP_FLOAT2);
376 for (int i = 0; i < num_layers; i++) {
377 if (!this->export_settings.get_active_uv_only() || i == active_uv) {
378
379 // char *name = CustomData_get_layer_name(&mesh->ldata, CD_PROP_FLOAT2, i);
380 COLLADASW::Input texcoord_input(
381 COLLADASW::InputSemantic::TEXCOORD,
382 makeUrl(makeTexcoordSourceId(geom_id, i, this->export_settings.get_active_uv_only())),
383 2, /* this is only until we have optimized UV sets */
384 this->export_settings.get_active_uv_only() ? 0 : i /* set (0,1,2,...) */
385 );
386 til.push_back(texcoord_input);
387 }
388 }
389
390 int totlayer_mcol = CustomData_number_of_layers(&mesh->corner_data, CD_PROP_BYTE_COLOR);
391 if (totlayer_mcol > 0) {
392 int map_index = 0;
393
394 for (int a = 0; a < totlayer_mcol; a++) {
395 const char *layer_name = bc_CustomData_get_layer_name(
396 &mesh->corner_data, CD_PROP_BYTE_COLOR, a);
397 COLLADASW::Input input4(COLLADASW::InputSemantic::COLOR,
398 makeUrl(makeVertexColorSourceId(geom_id, layer_name)),
399 (has_uvs) ? 3 : 2, /* all color layers have same index order */
400 map_index /* set number equals color map index */
401 );
402 til.push_back(input4);
403 map_index++;
404 }
405 }
406
407 /* performs the actual writing */
408 prepareToAppendValues(is_triangulated, *primitive_list, vcount_list);
409
410 const blender::bke::AttributeAccessor attributes = mesh->attributes();
411 const blender::VArray<int> material_indices = *attributes.lookup_or_default<int>(
412 "material_index", bke::AttrDomain::Face, 0);
413
414 /* <p> */
415 int texindex = 0;
416 for (const int i : faces.index_range()) {
417 const blender::IndexRange poly = faces[i];
418 int loop_count = poly.size();
419
420 if (material_indices[i] == material_index) {
421 BCPolygonNormalsIndices normal_indices = norind[i];
422
423 for (int j = 0; j < loop_count; j++) {
424 const int vert = corner_verts[poly[j]];
425 primitive_list->appendValues(vert);
426 primitive_list->appendValues(normal_indices[j]);
427 if (has_uvs) {
428 primitive_list->appendValues(texindex + j);
429 }
430
431 if (has_color) {
432 primitive_list->appendValues(texindex + j);
433 }
434 }
435 }
436
437 texindex += loop_count;
438 }
439
440 finish_and_delete_primitive_List(is_triangulated, primitive_list);
441}
442
443void GeometryExporter::createVertsSource(std::string geom_id, Mesh *mesh)
444{
445 const Span<float3> positions = mesh->vert_positions();
446
447 COLLADASW::FloatSourceF source(mSW);
448 source.setId(getIdBySemantics(geom_id, COLLADASW::InputSemantic::POSITION));
449 source.setArrayId(getIdBySemantics(geom_id, COLLADASW::InputSemantic::POSITION) +
450 ARRAY_ID_SUFFIX);
451 source.setAccessorCount(positions.size());
452 source.setAccessorStride(3);
453
454 COLLADASW::SourceBase::ParameterNameList &param = source.getParameterNameList();
455 param.push_back("X");
456 param.push_back("Y");
457 param.push_back("Z");
458 /* main function, it creates <source id = "">, <float_array id = ""
459 * count = ""> */
460 source.prepareToAppendValues();
461 /* appends data to <float_array> */
462 for (const int i : positions.index_range()) {
463 Vector co;
464 if (export_settings.get_apply_global_orientation()) {
465 float co_c[3];
466 copy_v3_v3(co_c, positions[i]);
467 bc_add_global_transform(co, co_c, export_settings.get_global_transform());
468 }
469 else {
470 copy_v3_v3(co, positions[i]);
471 }
472 source.appendValues(co[0], co[1], co[2]);
473 }
474
475 source.finish();
476}
477
478void GeometryExporter::createVertexColorSource(std::string geom_id, Mesh *mesh)
479{
480 /* Find number of vertex color layers */
481 int totlayer_mcol = CustomData_number_of_layers(&mesh->corner_data, CD_PROP_BYTE_COLOR);
482 if (totlayer_mcol == 0) {
483 return;
484 }
485
486 int map_index = 0;
487 for (int a = 0; a < totlayer_mcol; a++) {
488
489 map_index++;
490 const MLoopCol *mloopcol = (const MLoopCol *)CustomData_get_layer_n(
491 &mesh->corner_data, CD_PROP_BYTE_COLOR, a);
492
493 COLLADASW::FloatSourceF source(mSW);
494
495 const char *layer_name = bc_CustomData_get_layer_name(
496 &mesh->corner_data, CD_PROP_BYTE_COLOR, a);
497 std::string layer_id = makeVertexColorSourceId(geom_id, layer_name);
498 source.setId(layer_id);
499
500 source.setNodeName(layer_name);
501
502 source.setArrayId(layer_id + ARRAY_ID_SUFFIX);
503 source.setAccessorCount(mesh->corners_num);
504 source.setAccessorStride(4);
505
506 COLLADASW::SourceBase::ParameterNameList &param = source.getParameterNameList();
507 param.push_back("R");
508 param.push_back("G");
509 param.push_back("B");
510 param.push_back("A");
511
512 source.prepareToAppendValues();
513
514 const blender::OffsetIndices faces = mesh->faces();
515 for (const int i : faces.index_range()) {
516 for (const int corner : faces[i]) {
517 const MLoopCol *mlc = &mloopcol[corner];
518 source.appendValues(mlc->r / 255.0f, mlc->g / 255.0f, mlc->b / 255.0f, mlc->a / 255.0f);
519 }
520 }
521
522 source.finish();
523 }
524}
525
526std::string GeometryExporter::makeTexcoordSourceId(std::string &geom_id,
527 int layer_index,
528 bool is_single_layer)
529{
530 char suffix[20];
531 if (is_single_layer) {
532 suffix[0] = '\0';
533 }
534 else {
535 SNPRINTF(suffix, "-%d", layer_index);
536 }
537 return getIdBySemantics(geom_id, COLLADASW::InputSemantic::TEXCOORD) + suffix;
538}
539
540void GeometryExporter::createTexcoordsSource(std::string geom_id, Mesh *mesh)
541{
542 int totuv = mesh->corners_num;
543 const blender::OffsetIndices faces = mesh->faces();
544
545 int num_layers = CustomData_number_of_layers(&mesh->corner_data, CD_PROP_FLOAT2);
546
547 /* write <source> for each layer
548 * each <source> will get id like meshName + "map-channel-1" */
549 int active_uv_index = CustomData_get_active_layer_index(&mesh->corner_data, CD_PROP_FLOAT2);
550 for (int a = 0; a < num_layers; a++) {
551 int layer_index = CustomData_get_layer_index_n(&mesh->corner_data, CD_PROP_FLOAT2, a);
552 if (!this->export_settings.get_active_uv_only() || layer_index == active_uv_index) {
553 const blender::float2 *uv_map = static_cast<const blender::float2 *>(
554 CustomData_get_layer_n(&mesh->corner_data, CD_PROP_FLOAT2, a));
555
556 COLLADASW::FloatSourceF source(mSW);
557 std::string layer_id = makeTexcoordSourceId(
558 geom_id, a, this->export_settings.get_active_uv_only());
559 source.setId(layer_id);
560 source.setArrayId(layer_id + ARRAY_ID_SUFFIX);
561
562 source.setAccessorCount(totuv);
563 source.setAccessorStride(2);
564 COLLADASW::SourceBase::ParameterNameList &param = source.getParameterNameList();
565 param.push_back("S");
566 param.push_back("T");
567
568 source.prepareToAppendValues();
569
570 for (const int i : faces.index_range()) {
571 for (const int corner : faces[i]) {
572 source.appendValues(uv_map[corner][0], uv_map[corner][1]);
573 }
574 }
575
576 source.finish();
577 }
578 }
579}
580
581bool operator<(const Normal &a, const Normal &b)
582{
583 /* Only needed to sort normal vectors and find() them later in a map. */
584 return a.x < b.x || (a.x == b.x && (a.y < b.y || (a.y == b.y && a.z < b.z)));
585}
586
588 Mesh *mesh,
589 std::vector<Normal> &nor)
590{
591 COLLADASW::FloatSourceF source(mSW);
592 source.setId(getIdBySemantics(geom_id, COLLADASW::InputSemantic::NORMAL));
593 source.setArrayId(getIdBySemantics(geom_id, COLLADASW::InputSemantic::NORMAL) + ARRAY_ID_SUFFIX);
594 source.setAccessorCount(ulong(nor.size()));
595 source.setAccessorStride(3);
596 COLLADASW::SourceBase::ParameterNameList &param = source.getParameterNameList();
597 param.push_back("X");
598 param.push_back("Y");
599 param.push_back("Z");
600
601 source.prepareToAppendValues();
602
603 std::vector<Normal>::iterator it;
604 for (it = nor.begin(); it != nor.end(); it++) {
605 Normal &n = *it;
606
607 Vector no{n.x, n.y, n.z};
608 if (export_settings.get_apply_global_orientation()) {
609 bc_add_global_transform(no, export_settings.get_global_transform());
610 }
611 source.appendValues(no[0], no[1], no[2]);
612 }
613
614 source.finish();
615}
616
617void GeometryExporter::create_normals(std::vector<Normal> &normals,
618 std::vector<BCPolygonNormalsIndices> &polygons_normals,
619 Mesh *mesh)
620{
621 using namespace blender;
622 std::map<Normal, uint> shared_normal_indices;
623 int last_normal_index = -1;
624
625 const Span<float3> positions = mesh->vert_positions();
626 const Span<float3> vert_normals = mesh->vert_normals();
627 const blender::OffsetIndices faces = mesh->faces();
628 const Span<int> corner_verts = mesh->corner_verts();
629
630 const bke::AttributeAccessor attributes = mesh->attributes();
631 const VArray<bool> sharp_faces = *attributes.lookup_or_default<bool>(
632 "sharp_face", bke::AttrDomain::Face, false);
633
634 blender::Span<blender::float3> corner_normals;
635 if (mesh->normals_domain() == blender::bke::MeshNormalDomain::Corner) {
636 corner_normals = mesh->corner_normals();
637 }
638
639 for (const int face_index : faces.index_range()) {
640 const IndexRange face = faces[face_index];
641 bool use_vert_normals = !corner_normals.is_empty() || !sharp_faces[face_index];
642
643 if (!use_vert_normals) {
644 /* For flat faces use face normal as vertex normal: */
645
647 corner_verts.slice(face));
648
649 Normal n = {vector[0], vector[1], vector[2]};
650 normals.push_back(n);
651 last_normal_index++;
652 }
653
654 BCPolygonNormalsIndices poly_indices;
655 for (const int corner : face) {
656 if (use_vert_normals) {
657 float normalized[3];
658
659 if (!corner_normals.is_empty()) {
660 normalize_v3_v3(normalized, corner_normals[corner]);
661 }
662 else {
663 copy_v3_v3(normalized, vert_normals[corner_verts[corner]]);
665 }
666 Normal n = {normalized[0], normalized[1], normalized[2]};
667
668 if (shared_normal_indices.find(n) != shared_normal_indices.end()) {
669 poly_indices.add_index(shared_normal_indices[n]);
670 }
671 else {
672 last_normal_index++;
673 poly_indices.add_index(last_normal_index);
674 shared_normal_indices[n] = last_normal_index;
675 normals.push_back(n);
676 }
677 }
678 else {
679 poly_indices.add_index(last_normal_index);
680 }
681 }
682
683 polygons_normals.push_back(poly_indices);
684 }
685}
686
687std::string GeometryExporter::getIdBySemantics(std::string geom_id,
688 COLLADASW::InputSemantic::Semantics type,
689 std::string other_suffix)
690{
691 return geom_id + getSuffixBySemantic(type) + other_suffix;
692}
693
694COLLADASW::URI GeometryExporter::getUrlBySemantics(std::string geom_id,
695 COLLADASW::InputSemantic::Semantics type,
696 std::string other_suffix)
697{
698
699 std::string id(getIdBySemantics(geom_id, type, other_suffix));
700 return COLLADASW::URI(COLLADABU::Utils::EMPTY_STRING, id);
701}
702
703COLLADASW::URI GeometryExporter::makeUrl(std::string id)
704{
705 return COLLADASW::URI(COLLADABU::Utils::EMPTY_STRING, id);
706}
CustomData interface, see also DNA_customdata_types.h.
int CustomData_get_layer_index_n(const CustomData *data, eCustomDataType type, int n)
const void * CustomData_get_layer_n(const CustomData *data, eCustomDataType type, int n)
int CustomData_get_active_layer(const CustomData *data, eCustomDataType type)
bool CustomData_has_layer(const CustomData *data, eCustomDataType type)
int CustomData_get_active_layer_index(const CustomData *data, eCustomDataType type)
int CustomData_number_of_layers(const CustomData *data, eCustomDataType type)
void BKE_keyblock_convert_to_mesh(const KeyBlock *kb, float(*vert_positions)[3], int totvert)
Definition key.cc:2202
Key * BKE_key_from_object(Object *ob)
Definition key.cc:1820
void BKE_id_free(Main *bmain, void *idv)
General operations, lookup, etc. for materials.
struct Material * BKE_object_material_get(struct Object *ob, short act)
MINLINE void copy_v3_v3(float r[3], const float a[3])
MINLINE float normalize_v3_v3(float r[3], const float a[3])
MINLINE float normalize_v3(float n[3])
#define SNPRINTF(dst, format,...)
Definition BLI_string.h:597
unsigned long ulong
@ CD_PROP_BYTE_COLOR
@ CD_PROP_FLOAT2
static void prepareToAppendValues(bool is_triangulated, COLLADASW::PrimitivesBase &primitive_list, std::vector< ulong > &vcount_list)
static void finish_and_delete_primitive_List(bool is_triangulated, COLLADASW::PrimitivesBase *primitive_list)
static bool collect_vertex_counts_per_poly(Mesh *mesh, int material_index, std::vector< ulong > &vcount_list)
bool operator<(const Normal &a, const Normal &b)
static COLLADASW::PrimitivesBase * create_primitive_list(bool is_triangulated, COLLADASW::StreamWriter *mSW)
SIMD_FORCE_INLINE btVector3 normalized() const
Return a normalized version of this vector.
void add_index(unsigned int index)
void createVertsSource(std::string geom_id, Mesh *mesh)
void createLooseEdgeList(Object *ob, Mesh *mesh, std::string &geom_id)
void createTexcoordsSource(std::string geom_id, Mesh *mesh)
COLLADASW::URI getUrlBySemantics(std::string geom_id, COLLADASW::InputSemantic::Semantics type, std::string other_suffix="")
COLLADASW::URI makeUrl(std::string id)
std::string makeTexcoordSourceId(std::string &geom_id, int layer_index, bool is_single_layer)
void createNormalsSource(std::string geom_id, Mesh *mesh, std::vector< Normal > &nor)
void operator()(Object *ob)
void create_mesh_primitive_list(short material_index, bool has_uvs, bool has_color, Object *ob, Mesh *mesh, std::string &geom_id, std::vector< BCPolygonNormalsIndices > &norind)
std::string getIdBySemantics(std::string geom_id, COLLADASW::InputSemantic::Semantics type, std::string other_suffix="")
void create_normals(std::vector< Normal > &nor, std::vector< BCPolygonNormalsIndices > &polygons_normals, Mesh *mesh)
std::string makeVertexColorSourceId(std::string &geom_id, const char *layer_name)
void export_key_mesh(Object *ob, Mesh *mesh, KeyBlock *kb)
void createVertexColorSource(std::string geom_id, Mesh *mesh)
constexpr int64_t size() const
constexpr bool is_empty() const
constexpr Span slice(int64_t start, int64_t size) const
Definition BLI_span.hh:138
std::string encode_xml(const std::string &xml)
std::string translate_id(const char *idString)
std::string get_geometry_id(Object *ob)
std::string get_material_id(Material *mat)
std::string id_name(void *id)
void bc_add_global_transform(Matrix &to_mat, const Matrix &from_mat, const BCMatrix &global_transform, const bool invert)
Mesh * bc_get_mesh_copy(BlenderContext &blender_context, Object *ob, BC_export_mesh_type export_mesh_type, bool apply_modifiers, bool triangulate)
const char * bc_CustomData_get_layer_name(const CustomData *data, eCustomDataType type, int n)
local_group_size(16, 16) .push_constant(Type b
static float verts[][3]
float3 face_normal_calc(Span< float3 > vert_positions, Span< int > face_verts)
Frequency::GEOMETRY nor[]
__int64 int64_t
Definition stdint.h:89
void forEachMeshObjectInExportSet(Scene *sce, Functor &f, LinkNode *export_set)
char name[64]
struct KeyBlock * next
ListBase block
void * first
unsigned char a
unsigned char b
unsigned char r
unsigned char g
blender::BitVector is_loose_bits