Blender V4.5
DocumentImporter.cpp
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2009-2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
8
9/* TODO:
10 * * name imported objects
11 * * import object rotation as euler */
12
13#include <map>
14#include <string>
15
16#include "COLLADAFWArrayPrimitiveType.h"
17#include "COLLADAFWCamera.h"
18#include "COLLADAFWLibraryNodes.h"
19#include "COLLADAFWLight.h"
20#include "COLLADAFWRoot.h"
21#include "COLLADAFWVisualScene.h"
22
23#include "COLLADASaxFWLLoader.h"
24
25#include "BLI_fileops.h"
26#include "BLI_math_matrix.h"
27
28#include "BKE_camera.h"
29#include "BKE_collection.hh"
30#include "BKE_constraint.h"
31#include "BKE_fcurve.hh"
32#include "BKE_global.hh"
33#include "BKE_image.hh"
34#include "BKE_layer.hh"
35#include "BKE_lib_id.hh"
36#include "BKE_light.h"
37#include "BKE_material.hh"
38#include "BKE_scene.hh"
39
40#include "BLI_path_utils.hh"
41
42#include "DNA_camera_types.h"
43#include "DNA_light_types.h"
44
45#include "RNA_access.hh"
46
47#include "WM_api.hh"
48#include "WM_types.hh"
49
50#include "DEG_depsgraph.hh"
52
53#include "DocumentImporter.h"
54#include "ErrorHandler.h"
55#include "ExtraHandler.h"
56
57#include "Materials.h"
58#include "collada_internal.h"
59#include "collada_utils.h"
60
61/*
62 * COLLADA Importer limitations:
63 * - no multiple scene import, all objects are added to active scene
64 */
65
67 : import_settings(import_settings),
68 mImportStage(Fetching_Scene_data),
69 mContext(C),
70 view_layer(CTX_data_view_layer(mContext)),
71 armature_importer(&unit_converter,
72 &mesh_importer,
75 view_layer,
76 import_settings),
77 mesh_importer(&unit_converter,
78 import_settings->custom_normals,
79 &armature_importer,
82 view_layer),
83 anim_importer(C, &unit_converter, &armature_importer, CTX_data_scene(C))
84{
85}
86
88{
89 TagsMap::iterator etit;
90 etit = uid_tags_map.begin();
91 while (etit != uid_tags_map.end()) {
92 delete etit->second;
93 etit++;
94 }
95}
96
98{
99 ErrorHandler errorHandler;
100 COLLADASaxFWL::Loader loader(&errorHandler);
101 COLLADAFW::Root root(&loader, this);
102 ExtraHandler *ehandler = new ExtraHandler(this, &(this->anim_importer));
103
104 loader.registerExtraDataCallbackHandler(ehandler);
105
106 /* deselect all to select new objects */
108
109 std::string mFilename = std::string(this->import_settings->filepath);
110 const std::string encodedFilename = bc_url_encode(mFilename);
111 if (!root.loadDocument(encodedFilename)) {
112 fprintf(stderr, "COLLADAFW::Root::loadDocument() returned false on 1st pass\n");
113 delete ehandler;
114 return false;
115 }
116
117 if (errorHandler.hasError()) {
118 delete ehandler;
119 return false;
120 }
121
123 mImportStage = Fetching_Controller_data;
124 COLLADASaxFWL::Loader loader2;
125 COLLADAFW::Root root2(&loader2, this);
126
127 if (!root2.loadDocument(encodedFilename)) {
128 fprintf(stderr, "COLLADAFW::Root::loadDocument() returned false on 2nd pass\n");
129 delete ehandler;
130 return false;
131 }
132
133 delete ehandler;
134
135 return true;
136}
137
138void DocumentImporter::cancel(const COLLADAFW::String &errorMessage)
139{
140 /* TODO: if possible show error info
141 *
142 * Should we get rid of invisible Meshes that were created so far
143 * or maybe create objects at coordinate space origin?
144 *
145 * The latter sounds better. */
146}
147
149
151{
152 if (mImportStage == Fetching_Controller_data) {
153 return;
154 }
155
156 Main *bmain = CTX_data_main(mContext);
157 /* TODO: create a new scene except the selected <visual_scene> -
158 * use current blender scene for it */
159 Scene *sce = CTX_data_scene(mContext);
160 unit_converter.calculate_scale(*sce);
161
162 std::vector<Object *> *objects_to_scale = new std::vector<Object *>();
163
165 std::vector<const COLLADAFW::VisualScene *>::iterator sit;
166 for (sit = vscenes.begin(); sit != vscenes.end(); sit++) {
167 PointerRNA unit_settings;
168 PropertyRNA *system, *scale;
169
170 /* for scene unit settings: system, scale_length */
171
172 PointerRNA sceneptr = RNA_id_pointer_create(&sce->id);
173 unit_settings = RNA_pointer_get(&sceneptr, "unit_settings");
174 system = RNA_struct_find_property(&unit_settings, "system");
175 scale = RNA_struct_find_property(&unit_settings, "scale_length");
176
177 if (this->import_settings->import_units) {
178
179 switch (unit_converter.isMetricSystem()) {
181 RNA_property_enum_set(&unit_settings, system, USER_UNIT_METRIC);
182 break;
184 RNA_property_enum_set(&unit_settings, system, USER_UNIT_IMPERIAL);
185 break;
186 default:
187 RNA_property_enum_set(&unit_settings, system, USER_UNIT_NONE);
188 break;
189 }
190 float unit_factor = unit_converter.getLinearMeter();
191 RNA_property_float_set(&unit_settings, scale, unit_factor);
192 fprintf(stdout, "Collada: Adjusting Blender units to Importset units: %f.\n", unit_factor);
193 }
194
195 /* Write nodes to scene */
196 fprintf(stderr, "+-- Import Scene --------\n");
197 const COLLADAFW::NodePointerArray &roots = (*sit)->getRootNodes();
198 for (uint i = 0; i < roots.getCount(); i++) {
199 std::vector<Object *> *objects_done = write_node(roots[i], nullptr, sce, nullptr, false);
200 objects_to_scale->insert(
201 objects_to_scale->end(), objects_done->begin(), objects_done->end());
202 delete objects_done;
203 }
204 }
205
206 mesh_importer.optimize_material_assignements();
207
208 armature_importer.set_tags_map(this->uid_tags_map);
209 armature_importer.make_armatures(mContext, *objects_to_scale);
210 armature_importer.make_shape_keys(mContext);
211
212#if 0
213 armature_importer.fix_animation();
214#endif
215
216 for (const COLLADAFW::VisualScene *vscene : vscenes) {
217 const COLLADAFW::NodePointerArray &roots = vscene->getRootNodes();
218
219 for (uint i = 0; i < roots.getCount(); i++) {
220 translate_anim_recursive(roots[i], nullptr, nullptr);
221 }
222 }
223
224 if (!libnode_ob.empty()) {
225
226 fprintf(stderr, "| Cleanup: free %d library nodes\n", int(libnode_ob.size()));
227 /* free all library_nodes */
228 std::vector<Object *>::iterator it;
229 for (it = libnode_ob.begin(); it != libnode_ob.end(); it++) {
230 Object *ob = *it;
231 BKE_scene_collections_object_remove(bmain, sce, ob, true);
232 }
233 libnode_ob.clear();
234 }
235
236 bc_match_scale(objects_to_scale, unit_converter, !this->import_settings->import_units);
237
238 delete objects_to_scale;
239
240 /* update scene */
243 WM_event_add_notifier(mContext, NC_OBJECT | ND_TRANSFORM, nullptr);
244}
245
247 COLLADAFW::Node *par = nullptr,
248 Object *parob = nullptr)
249{
250 /* The split in #29246, root_map must point at actual root when
251 * calculating bones in apply_curves_as_matrix. - actual root is the root node.
252 * This has to do with inverse bind poses being world space
253 * (the sources for skinned bones' rest-poses) and the way
254 * non-skinning nodes have their "rest-pose" recursively calculated.
255 * XXX TODO: design issue, how to support unrelated joints taking
256 * part in skinning. */
257 if (par) { // && par->getType() == COLLADAFW::Node::JOINT) {
258 /* If par is root if there's no corresponding key in root_map. */
259 if (root_map.find(par->getUniqueId()) == root_map.end()) {
260 root_map[node->getUniqueId()] = node;
261 }
262 else {
263 root_map[node->getUniqueId()] = root_map[par->getUniqueId()];
264 }
265 }
266
267#if 0
268 COLLADAFW::Transformation::TransformationType types[] = {
269 COLLADAFW::Transformation::ROTATE,
270 COLLADAFW::Transformation::SCALE,
271 COLLADAFW::Transformation::TRANSLATE,
272 COLLADAFW::Transformation::MATRIX,
273 };
274
275 Object *ob;
276#endif
277 uint i;
278
279 if (node->getType() == COLLADAFW::Node::JOINT && par == nullptr) {
280 /* For Skeletons without root node we have to simulate the
281 * root node here and recursively enter the same function
282 * XXX: maybe this can be made more elegant. */
283 translate_anim_recursive(node, node, parob);
284 }
285 else {
286 anim_importer.translate_Animations(
287 node, root_map, object_map, FW_object_map, uid_material_map);
288 COLLADAFW::NodePointerArray &children = node->getChildNodes();
289 for (i = 0; i < children.getCount(); i++) {
290 translate_anim_recursive(children[i], node, nullptr);
291 }
292 }
293}
294
295std::string DocumentImporter::get_import_version(const COLLADAFW::FileInfo *asset)
296{
297 const char AUTORING_TOOL[] = "authoring_tool";
298 const std::string BLENDER("Blender ");
299 const COLLADAFW::FileInfo::ValuePairPointerArray &valuePairs = asset->getValuePairArray();
300 for (size_t i = 0, count = valuePairs.getCount(); i < count; i++) {
301 const COLLADAFW::FileInfo::ValuePair *valuePair = valuePairs[i];
302 const COLLADAFW::String &key = valuePair->first;
303 const COLLADAFW::String &value = valuePair->second;
304 if (key == AUTORING_TOOL) {
305 if (value.compare(0, BLENDER.length(), BLENDER) == 0) {
306 /* Was made with Blender, now get version string */
307 std::string v = value.substr(BLENDER.length());
308 std::string::size_type n = v.find(" ");
309 if (n > 0) {
310 return v.substr(0, n);
311 }
312 }
313 }
314 }
315 return "";
316}
317
318bool DocumentImporter::writeGlobalAsset(const COLLADAFW::FileInfo *asset)
319{
320 unit_converter.read_asset(asset);
321 import_from_version = get_import_version(asset);
322 anim_importer.set_import_from_version(import_from_version);
323 return true;
324}
325
326bool DocumentImporter::writeScene(const COLLADAFW::Scene *scene)
327{
328 /* XXX could store the scene id, but do nothing for now */
329 return true;
330}
331Object *DocumentImporter::create_camera_object(COLLADAFW::InstanceCamera *camera, Scene *sce)
332{
333 const COLLADAFW::UniqueId &cam_uid = camera->getInstanciatedObjectId();
334 if (uid_camera_map.find(cam_uid) == uid_camera_map.end()) {
335 // fprintf(stderr, "Couldn't find camera by UID.\n");
336 return nullptr;
337 }
338
339 Main *bmain = CTX_data_main(mContext);
340 Object *ob = bc_add_object(bmain, sce, view_layer, OB_CAMERA, nullptr);
341 Camera *cam = uid_camera_map[cam_uid];
342 Camera *old_cam = (Camera *)ob->data;
343 ob->data = cam;
344 BKE_id_free_us(bmain, old_cam);
345 return ob;
346}
347
348Object *DocumentImporter::create_light_object(COLLADAFW::InstanceLight *lamp, Scene *sce)
349{
350 const COLLADAFW::UniqueId &lamp_uid = lamp->getInstanciatedObjectId();
351 if (uid_light_map.find(lamp_uid) == uid_light_map.end()) {
352 fprintf(stderr, "Couldn't find light by UID.\n");
353 return nullptr;
354 }
355
356 Main *bmain = CTX_data_main(mContext);
357 Object *ob = bc_add_object(bmain, sce, view_layer, OB_LAMP, nullptr);
358 Light *la = uid_light_map[lamp_uid];
359 Light *old_light = (Light *)ob->data;
360 ob->data = la;
361 BKE_id_free_us(bmain, old_light);
362 return ob;
363}
364
366 COLLADAFW::Node *source_node,
367 COLLADAFW::Node *instance_node,
368 Scene *sce,
369 bool is_library_node)
370{
371 // fprintf(stderr, "create <instance_node> under node id=%s from node id=%s\n", instance_node ?
372 // instance_node->getOriginalId().c_str() : nullptr, source_node ?
373 // source_node->getOriginalId().c_str() : nullptr);
374
375 Main *bmain = CTX_data_main(mContext);
376 Object *obn = (Object *)BKE_id_copy(bmain, &source_ob->id);
377 id_us_min(&obn->id);
379 BKE_collection_object_add_from(bmain, sce, source_ob, obn);
380
381 if (instance_node) {
382 anim_importer.read_node_transform(instance_node, obn);
383 /* if we also have a source_node (always ;), take its
384 * transformation matrix and apply it to the newly instantiated
385 * object to account for node hierarchy transforms in `.dae`. */
386 if (source_node) {
387 COLLADABU::Math::Matrix4 mat4 = source_node->getTransformationMatrix();
388 COLLADABU::Math::Matrix4 bmat4 =
389 mat4.transpose(); /* transpose to get blender row-major order */
390 float mat[4][4];
391 for (int i = 0; i < 4; i++) {
392 for (int j = 0; j < 4; j++) {
393 mat[i][j] = bmat4[i][j];
394 }
395 }
396 /* calc new matrix and apply */
397 mul_m4_m4m4(obn->runtime->object_to_world.ptr(), obn->object_to_world().ptr(), mat);
398 BKE_object_apply_mat4(obn, obn->object_to_world().ptr(), false, false);
399 }
400 }
401 else {
402 anim_importer.read_node_transform(source_node, obn);
403 }
404
405 /*DAG_relations_tag_update(CTX_data_main(mContext));*/
406
407 COLLADAFW::NodePointerArray &children = source_node->getChildNodes();
408 if (children.getCount()) {
409 for (uint i = 0; i < children.getCount(); i++) {
410 COLLADAFW::Node *child_node = children[i];
411 const COLLADAFW::UniqueId &child_id = child_node->getUniqueId();
412 if (object_map.find(child_id) == object_map.end()) {
413 continue;
414 }
415 COLLADAFW::InstanceNodePointerArray &inodes = child_node->getInstanceNodes();
416 Object *new_child = nullptr;
417 if (inodes.getCount()) { /* \todo loop through instance nodes */
418 const COLLADAFW::UniqueId &id = inodes[0]->getInstanciatedObjectId();
419 fprintf(stderr, "Doing %d child nodes\n", int(node_map.count(id)));
420 new_child = create_instance_node(
421 object_map.find(id)->second, node_map[id], child_node, sce, is_library_node);
422 }
423 else {
424 new_child = create_instance_node(
425 object_map.find(child_id)->second, child_node, nullptr, sce, is_library_node);
426 }
427 bc_set_parent(new_child, obn, mContext, true);
428
429 if (is_library_node) {
430 libnode_ob.push_back(new_child);
431 }
432 }
433 }
434
435 return obn;
436}
437
439{
440 if (et && et->isProfile("blender")) {
441 short type = 0;
442 et->setData("type", &type);
443 BKE_constraint_add_for_object(ob, "Test_con", type);
444 }
445}
446
447void DocumentImporter::report_unknown_reference(const COLLADAFW::Node &node,
448 const std::string object_type)
449{
450 std::string id = node.getOriginalId();
451 std::string name = node.getName();
452 fprintf(stderr,
453 "error: node id=\"%s\", name=\"%s\" refers to an undefined %s.\n",
454 id.c_str(),
455 name.c_str(),
456 object_type.c_str());
457}
458
459std::vector<Object *> *DocumentImporter::write_node(COLLADAFW::Node *node,
460 COLLADAFW::Node *parent_node,
461 Scene *sce,
462 Object *par,
463 bool is_library_node)
464{
465 Main *bmain = CTX_data_main(mContext);
466 Object *ob = nullptr;
467 bool is_joint = node->getType() == COLLADAFW::Node::JOINT;
468 bool read_transform = true;
469 std::string id = node->getOriginalId();
470 std::string name = node->getName();
471
472 /* if node has child nodes write them */
473 COLLADAFW::NodePointerArray &child_nodes = node->getChildNodes();
474
475 std::vector<Object *> *objects_done = new std::vector<Object *>();
476 std::vector<Object *> *root_objects = new std::vector<Object *>();
477
478 fprintf(
479 stderr, "| %s id='%s', name='%s'\n", is_joint ? "JOINT" : "NODE ", id.c_str(), name.c_str());
480
481 if (is_joint) {
482 if (parent_node == nullptr && !is_library_node) {
483 /* A Joint on root level is a skeleton without root node.
484 * Here we add the armature "on the fly": */
485 par = bc_add_object(bmain, sce, view_layer, OB_ARMATURE, std::string("Armature").c_str());
486 objects_done->push_back(par);
487 root_objects->push_back(par);
488 object_map.insert(std::pair<COLLADAFW::UniqueId, Object *>(node->getUniqueId(), par));
489 node_map[node->getUniqueId()] = node;
490 }
491 if (parent_node == nullptr || parent_node->getType() != COLLADAFW::Node::JOINT) {
492 armature_importer.add_root_joint(node, par);
493 }
494
495 if (parent_node == nullptr) {
496 /* for skeletons without root node all has been done above.
497 * Skeletons with root node are handled further down. */
498 goto finally;
499 }
500 }
501 else {
502 COLLADAFW::InstanceGeometryPointerArray &geom = node->getInstanceGeometries();
503 COLLADAFW::InstanceCameraPointerArray &camera = node->getInstanceCameras();
504 COLLADAFW::InstanceLightPointerArray &lamp = node->getInstanceLights();
505 COLLADAFW::InstanceControllerPointerArray &controller = node->getInstanceControllers();
506 COLLADAFW::InstanceNodePointerArray &inst_node = node->getInstanceNodes();
507 size_t geom_done = 0;
508 size_t camera_done = 0;
509 size_t lamp_done = 0;
510 size_t controller_done = 0;
511 size_t inst_done = 0;
512
513 /* XXX linking object with the first <instance_geometry>, though a node may have more of
514 * them... maybe join multiple <instance_...> meshes into 1, and link object with it? not
515 * sure... <instance_geometry> */
516 while (geom_done < geom.getCount()) {
517 ob = mesh_importer.create_mesh_object(node, geom[geom_done], false, uid_material_map);
518 if (ob == nullptr) {
519 report_unknown_reference(*node, "instance_mesh");
520 }
521 else {
522 objects_done->push_back(ob);
523 if (parent_node == nullptr) {
524 root_objects->push_back(ob);
525 }
526 }
527 geom_done++;
528 }
529 while (camera_done < camera.getCount()) {
530 ob = create_camera_object(camera[camera_done], sce);
531 if (ob == nullptr) {
532 report_unknown_reference(*node, "instance_camera");
533 }
534 else {
535 objects_done->push_back(ob);
536 if (parent_node == nullptr) {
537 root_objects->push_back(ob);
538 }
539 }
540 camera_done++;
541 }
542 while (lamp_done < lamp.getCount()) {
543 ob = create_light_object(lamp[lamp_done], sce);
544 if (ob == nullptr) {
545 report_unknown_reference(*node, "instance_light");
546 }
547 else {
548 objects_done->push_back(ob);
549 if (parent_node == nullptr) {
550 root_objects->push_back(ob);
551 }
552 }
553 lamp_done++;
554 }
555 while (controller_done < controller.getCount()) {
556 COLLADAFW::InstanceGeometry *geometry = (COLLADAFW::InstanceGeometry *)
557 controller[controller_done];
558 ob = mesh_importer.create_mesh_object(node, geometry, true, uid_material_map);
559 if (ob == nullptr) {
560 report_unknown_reference(*node, "instance_controller");
561 }
562 else {
563 objects_done->push_back(ob);
564 if (parent_node == nullptr) {
565 root_objects->push_back(ob);
566 }
567 }
568 controller_done++;
569 }
570 /* XXX instance_node is not supported yet */
571 while (inst_done < inst_node.getCount()) {
572 const COLLADAFW::UniqueId &node_id = inst_node[inst_done]->getInstanciatedObjectId();
573 if (object_map.find(node_id) == object_map.end()) {
574 fprintf(stderr,
575 "Cannot find object for node referenced by <instance_node name=\"%s\">.\n",
576 inst_node[inst_done]->getName().c_str());
577 ob = nullptr;
578 }
579 else {
580 std::pair<std::multimap<COLLADAFW::UniqueId, Object *>::iterator,
581 std::multimap<COLLADAFW::UniqueId, Object *>::iterator>
582 pair_iter = object_map.equal_range(node_id);
583 for (std::multimap<COLLADAFW::UniqueId, Object *>::iterator it2 = pair_iter.first;
584 it2 != pair_iter.second;
585 it2++)
586 {
587 Object *source_ob = (Object *)it2->second;
588 COLLADAFW::Node *source_node = node_map[node_id];
589 ob = create_instance_node(source_ob, source_node, node, sce, is_library_node);
590 objects_done->push_back(ob);
591 if (parent_node == nullptr) {
592 root_objects->push_back(ob);
593 }
594 }
595 }
596 inst_done++;
597
598 read_transform = false;
599 }
600
601 /* if node is empty - create empty object
602 * XXX empty node may not mean it is empty object, not sure about this */
603 if ((geom_done + camera_done + lamp_done + controller_done + inst_done) < 1) {
604 /* Check if Object is armature, by checking if immediate child is a JOINT node. */
605 if (is_armature(node)) {
606 ExtraTags *et = getExtraTags(node->getUniqueId());
607 ob = bc_add_armature(node, et, bmain, sce, view_layer, OB_ARMATURE, name.c_str());
608 }
609 else {
610 ob = bc_add_object(bmain, sce, view_layer, OB_EMPTY, nullptr);
611 }
612 objects_done->push_back(ob);
613 if (parent_node == nullptr) {
614 root_objects->push_back(ob);
615 }
616 }
617
618 /* XXX: if there are multiple instances, only one is stored. */
619
620 if (!ob) {
621 goto finally;
622 }
623
624 for (Object *ob : *objects_done) {
625 std::string nodename = node->getName().empty() ? node->getOriginalId() : node->getName();
626 BKE_libblock_rename(*bmain, ob->id, (char *)nodename.c_str());
627 object_map.insert(std::pair<COLLADAFW::UniqueId, Object *>(node->getUniqueId(), ob));
628 node_map[node->getUniqueId()] = node;
629
630 if (is_library_node) {
631 libnode_ob.push_back(ob);
632 }
633 }
634
635 // create_constraints(et, ob);
636 }
637
638 for (Object *ob : *objects_done) {
639 if (read_transform) {
640 anim_importer.read_node_transform(node, ob); /* overwrites location set earlier */
641 }
642
643 if (!is_joint) {
644 if (par && ob) {
645 ob->parent = par;
646 ob->partype = PAROBJECT;
647 ob->parsubstr[0] = 0;
648
649 // bc_set_parent(ob, par, mContext, false);
650 }
651 }
652 }
653
654 if (objects_done->empty()) {
655 ob = nullptr;
656 }
657 else {
658 ob = *objects_done->begin();
659 }
660
661 for (uint i = 0; i < child_nodes.getCount(); i++) {
662 std::vector<Object *> *child_objects;
663 child_objects = write_node(child_nodes[i], node, sce, ob, is_library_node);
664 delete child_objects;
665 }
666
667finally:
668 delete objects_done;
669
670 return root_objects;
671}
672
673bool DocumentImporter::writeVisualScene(const COLLADAFW::VisualScene *visualScene)
674{
675 if (mImportStage == Fetching_Controller_data) {
676 return true;
677 }
678
679 /* This method called on post process after writeGeometry, writeMaterial, etc. */
680
681 /* For each <node> in <visual_scene>:
682 * create an Object
683 * if Mesh (previously created in writeGeometry) to which <node> corresponds exists,
684 * link Object with that mesh.
685 *
686 * Update: since we cannot link a Mesh with Object in
687 * writeGeometry because <geometry> does not reference <node>,
688 * we link Objects with Meshes here.
689 */
690 vscenes.push_back(visualScene);
691
692 return true;
693}
694
695bool DocumentImporter::writeLibraryNodes(const COLLADAFW::LibraryNodes *libraryNodes)
696{
697 if (mImportStage == Fetching_Controller_data) {
698 return true;
699 }
700
701 Scene *sce = CTX_data_scene(mContext);
702
703 const COLLADAFW::NodePointerArray &nodes = libraryNodes->getNodes();
704
705 fprintf(stderr, "+-- Read Library nodes ----------\n");
706 for (uint i = 0; i < nodes.getCount(); i++) {
707 std::vector<Object *> *child_objects;
708 child_objects = write_node(nodes[i], nullptr, sce, nullptr, true);
709 delete child_objects;
710 }
711 return true;
712}
713
714bool DocumentImporter::writeGeometry(const COLLADAFW::Geometry *geom)
715{
716 if (mImportStage == Fetching_Controller_data) {
717 return true;
718 }
719
720 return mesh_importer.write_geometry(geom);
721}
722
723bool DocumentImporter::writeMaterial(const COLLADAFW::Material *cmat)
724{
725 if (mImportStage == Fetching_Controller_data) {
726 return true;
727 }
728
729 Main *bmain = CTX_data_main(mContext);
730 const std::string &str_mat_id = cmat->getName().empty() ? cmat->getOriginalId() :
731 cmat->getName();
732 Material *ma = BKE_material_add(bmain, (char *)str_mat_id.c_str());
733 id_us_min(&ma->id);
734
735 this->uid_effect_map[cmat->getInstantiatedEffect()] = ma;
736 this->uid_material_map[cmat->getUniqueId()] = ma;
737
738 return true;
739}
740
741void DocumentImporter::write_profile_COMMON(COLLADAFW::EffectCommon *ef, Material *ma)
742{
743 MaterialNode matNode = MaterialNode(mContext, ef, ma, uid_image_map);
744
745 /* Direct mapping to principled BSDF Shader */
746 matNode.set_diffuse(ef->getDiffuse());
747 matNode.set_emission(ef->getEmission());
748 matNode.set_ior(ef->getIndexOfRefraction());
749 matNode.set_alpha(ef->getOpaqueMode(), ef->getTransparent(), ef->getTransparency());
750
751 /* following mapping still needs to be verified */
752#if 0
753 /* needs rework to be done for 2.81 */
754 matNode.set_shininess(ef->getShininess());
755#endif
756 matNode.set_reflectivity(ef->getReflectivity());
757
758 /* not supported by principled BSDF */
759 matNode.set_ambient(ef->getAmbient());
760 matNode.set_specular(ef->getSpecular());
761 matNode.set_reflective(ef->getReflective());
762
763 matNode.update_material_nodetree();
764}
765
766bool DocumentImporter::writeEffect(const COLLADAFW::Effect *effect)
767{
768 if (mImportStage == Fetching_Controller_data) {
769 return true;
770 }
771
772 const COLLADAFW::UniqueId &uid = effect->getUniqueId();
773
774 if (uid_effect_map.find(uid) == uid_effect_map.end()) {
775 fprintf(stderr, "Couldn't find a material by UID.\n");
776 return true;
777 }
778
779 Material *ma = uid_effect_map[uid];
780 std::map<COLLADAFW::UniqueId, Material *>::iterator iter;
781 for (iter = uid_material_map.begin(); iter != uid_material_map.end(); iter++) {
782 if (iter->second == ma) {
783 this->FW_object_map[iter->first] = effect;
784 break;
785 }
786 }
787 COLLADAFW::CommonEffectPointerArray common_efs = effect->getCommonEffects();
788 if (common_efs.getCount() < 1) {
789 fprintf(stderr, "Couldn't find <profile_COMMON>.\n");
790 return true;
791 }
792 /* XXX TODO: Take all <profile_common>s
793 * Currently only first <profile_common> is supported */
794 COLLADAFW::EffectCommon *ef = common_efs[0];
795 write_profile_COMMON(ef, ma);
796 this->FW_object_map[effect->getUniqueId()] = effect;
797
798 return true;
799}
800
801bool DocumentImporter::writeCamera(const COLLADAFW::Camera *camera)
802{
803 if (mImportStage == Fetching_Controller_data) {
804 return true;
805 }
806
807 Main *bmain = CTX_data_main(mContext);
808 Camera *cam = nullptr;
809 std::string cam_id, cam_name;
810
811 ExtraTags *et = getExtraTags(camera->getUniqueId());
812 cam_id = camera->getOriginalId();
813 cam_name = camera->getName();
814 if (cam_name.empty()) {
815 cam = (Camera *)BKE_camera_add(bmain, (char *)cam_id.c_str());
816 }
817 else {
818 cam = (Camera *)BKE_camera_add(bmain, (char *)cam_name.c_str());
819 }
820
821 if (!cam) {
822 fprintf(stderr, "Cannot create camera.\n");
823 return true;
824 }
825
826 if (et && et->isProfile("blender")) {
827 et->setData("shiftx", &(cam->shiftx));
828 et->setData("shifty", &(cam->shifty));
829 et->setData("dof_distance", &(cam->dof.focus_distance));
830 }
831 cam->clip_start = camera->getNearClippingPlane().getValue();
832 cam->clip_end = camera->getFarClippingPlane().getValue();
833
834 COLLADAFW::Camera::CameraType type = camera->getCameraType();
835 switch (type) {
836 case COLLADAFW::Camera::ORTHOGRAPHIC: {
837 cam->type = CAM_ORTHO;
838 break;
839 }
840 case COLLADAFW::Camera::PERSPECTIVE: {
841 cam->type = CAM_PERSP;
842 break;
843 }
844 case COLLADAFW::Camera::UNDEFINED_CAMERATYPE: {
845 fprintf(stderr, "Current camera type is not supported.\n");
846 cam->type = CAM_PERSP;
847 break;
848 }
849 }
850
851 switch (camera->getDescriptionType()) {
852 case COLLADAFW::Camera::ASPECTRATIO_AND_Y: {
853 switch (cam->type) {
854 case CAM_ORTHO: {
855 double ymag = 2 * camera->getYMag().getValue();
856 double aspect = camera->getAspectRatio().getValue();
857 double xmag = aspect * ymag;
858 cam->ortho_scale = float(xmag);
859 break;
860 }
861 case CAM_PERSP:
862 default: {
863 double yfov = camera->getYFov().getValue();
864 double aspect = camera->getAspectRatio().getValue();
865
866 /* NOTE: Needs more testing (As we currently have no official test data for this) */
867
868 double xfov = 2.0f * atanf(aspect * tanf(DEG2RADF(yfov) * 0.5f));
869 cam->lens = fov_to_focallength(xfov, cam->sensor_x);
870 break;
871 }
872 }
873 break;
874 }
875 /* XXX correct way to do following four is probably to get also render
876 * size and determine proper settings from that somehow */
877 case COLLADAFW::Camera::ASPECTRATIO_AND_X:
878 case COLLADAFW::Camera::SINGLE_X:
879 case COLLADAFW::Camera::X_AND_Y: {
880 switch (cam->type) {
881 case CAM_ORTHO:
882 cam->ortho_scale = float(camera->getXMag().getValue() * 2.0);
883 break;
884 case CAM_PERSP:
885 default: {
886 double x = camera->getXFov().getValue();
887 /* X is in degrees, cam->lens is in millimeters. */
889 break;
890 }
891 }
892 break;
893 }
894 case COLLADAFW::Camera::SINGLE_Y: {
895 switch (cam->type) {
896 case CAM_ORTHO:
897 cam->ortho_scale = float(camera->getYMag().getValue());
898 break;
899 case CAM_PERSP:
900 default: {
901 double yfov = camera->getYFov().getValue();
902 /* yfov is in degrees, cam->lens is in millimeters. */
903 cam->lens = fov_to_focallength(DEG2RADF(yfov), cam->sensor_x);
904 break;
905 }
906 }
907 break;
908 }
909 case COLLADAFW::Camera::UNDEFINED:
910 /* read nothing, use blender defaults. */
911 break;
912 }
913
914 this->uid_camera_map[camera->getUniqueId()] = cam;
915 this->FW_object_map[camera->getUniqueId()] = camera;
916 /* XXX import camera options */
917 return true;
918}
919
920bool DocumentImporter::writeImage(const COLLADAFW::Image *image)
921{
922 if (mImportStage == Fetching_Controller_data) {
923 return true;
924 }
925
926 const std::string &imagepath = image->getImageURI().toNativePath();
927
928 char dir[FILE_MAX];
929 char absolute_path[FILE_MAX];
930 const char *workpath;
931
932 BLI_path_split_dir_part(this->import_settings->filepath, dir, sizeof(dir));
933 BLI_path_join(absolute_path, sizeof(absolute_path), dir, imagepath.c_str());
934 if (BLI_exists(absolute_path)) {
935 workpath = absolute_path;
936 }
937 else {
938 /* Maybe imagepath was already absolute ? */
939 if (!BLI_exists(imagepath.c_str())) {
940 fprintf(stderr, "|! Image not found: %s\n", imagepath.c_str());
941 return true;
942 }
943 workpath = imagepath.c_str();
944 }
945
946 Image *ima = BKE_image_load_exists(CTX_data_main(mContext), workpath);
947 if (!ima) {
948 fprintf(stderr, "|! Cannot create image: %s\n", workpath);
949 return true;
950 }
951 this->uid_image_map[image->getUniqueId()] = ima;
952 fprintf(stderr, "| import Image: %s\n", workpath);
953 return true;
954}
955
956bool DocumentImporter::writeLight(const COLLADAFW::Light *light)
957{
958 if (mImportStage == Fetching_Controller_data) {
959 return true;
960 }
961
962 Main *bmain = CTX_data_main(mContext);
963 Light *lamp = nullptr;
964 std::string la_id, la_name;
965
966 ExtraTags *et = getExtraTags(light->getUniqueId());
967#if 0
968 TagsMap::iterator etit;
969 ExtraTags *et = 0;
970 etit = uid_tags_map.find(light->getUniqueId().toAscii());
971 if (etit != uid_tags_map.end()) {
972 et = etit->second;
973 }
974#endif
975
976 la_id = light->getOriginalId();
977 la_name = light->getName();
978 if (la_name.empty()) {
979 lamp = (Light *)BKE_light_add(bmain, (char *)la_id.c_str());
980 }
981 else {
982 lamp = (Light *)BKE_light_add(bmain, (char *)la_name.c_str());
983 }
984
985 if (!lamp) {
986 fprintf(stderr, "Cannot create light.\n");
987 return true;
988 }
989
990 /* if we find an ExtraTags for this, use that instead. */
991 if (et && et->isProfile("blender")) {
992 et->setData("type", &(lamp->type));
993 et->setData("flag", &(lamp->flag));
994 et->setData("mode", &(lamp->mode));
995 et->setData("red", &(lamp->r));
996 et->setData("green", &(lamp->g));
997 et->setData("blue", &(lamp->b));
998 et->setData("energy", &(lamp->energy));
999 et->setData("spotsize", &(lamp->spotsize));
1000 lamp->spotsize = DEG2RADF(lamp->spotsize);
1001 et->setData("spotblend", &(lamp->spotblend));
1002 et->setData("clipsta", &(lamp->clipsta));
1003 et->setData("clipend", &(lamp->att_dist));
1004 et->setData("radius", &(lamp->radius));
1005 et->setData("area_shape", &(lamp->area_shape));
1006 et->setData("area_size", &(lamp->area_size));
1007 et->setData("area_sizey", &(lamp->area_sizey));
1008 et->setData("area_sizez", &(lamp->area_sizez));
1009 }
1010 else {
1011 // float d = 25.0f; /* UNUSED. */
1012 float e = 1.0f;
1013
1014 if (light->getColor().isValid()) {
1015 COLLADAFW::Color col = light->getColor();
1016 lamp->r = col.getRed();
1017 lamp->g = col.getGreen();
1018 lamp->b = col.getBlue();
1019 }
1020
1021 lamp->energy = e;
1022
1023 switch (light->getLightType()) {
1024 case COLLADAFW::Light::AMBIENT_LIGHT: {
1025 lamp->type = LA_SUN; /* TODO: needs more thoughts. */
1026 break;
1027 }
1028 case COLLADAFW::Light::SPOT_LIGHT: {
1029 lamp->type = LA_SPOT;
1030 lamp->spotsize = DEG2RADF(light->getFallOffAngle().getValue());
1031 lamp->spotblend = light->getFallOffExponent().getValue();
1032 break;
1033 }
1034 case COLLADAFW::Light::DIRECTIONAL_LIGHT: {
1035 /* our sun is very strong, so pick a smaller energy level */
1036 lamp->type = LA_SUN;
1037 break;
1038 }
1039 case COLLADAFW::Light::POINT_LIGHT: {
1040 lamp->type = LA_LOCAL;
1041 break;
1042 }
1043 case COLLADAFW::Light::UNDEFINED: {
1044 fprintf(stderr, "Current light type is not supported.\n");
1045 lamp->type = LA_LOCAL;
1046 break;
1047 }
1048 }
1049 }
1050
1051 this->uid_light_map[light->getUniqueId()] = lamp;
1052 this->FW_object_map[light->getUniqueId()] = light;
1053 return true;
1054}
1055
1056bool DocumentImporter::writeAnimation(const COLLADAFW::Animation *anim)
1057{
1058 if (mImportStage == Fetching_Controller_data) {
1059 return true;
1060 }
1061
1062 return anim_importer.write_animation(anim);
1063}
1064
1065bool DocumentImporter::writeAnimationList(const COLLADAFW::AnimationList *animationList)
1066{
1067 if (mImportStage == Fetching_Controller_data) {
1068 return true;
1069 }
1070
1071 // return true;
1072 return anim_importer.write_animation_list(animationList);
1073}
1074
1075#if WITH_OPENCOLLADA_ANIMATION_CLIP
1076bool DocumentImporter::writeAnimationClip(const COLLADAFW::AnimationClip *animationClip)
1077{
1078 /* Since opencollada 1.6.68: called on post-process stage after writeVisualScenes. */
1079
1080 if (mImportStage == Fetching_Controller_data) {
1081 return true;
1082 }
1083
1084 return true;
1085 /* TODO: implement import of AnimationClips */
1086 // return animation_clip_importer.write_animation_clip(animationClip);
1087}
1088#endif
1089
1090bool DocumentImporter::writeSkinControllerData(const COLLADAFW::SkinControllerData *skin)
1091{
1092 return armature_importer.write_skin_controller_data(skin);
1093}
1094
1095bool DocumentImporter::writeController(const COLLADAFW::Controller *controller)
1096{
1097 if (mImportStage == Fetching_Controller_data) {
1098 return true;
1099 }
1100
1101 return armature_importer.write_controller(controller);
1102}
1103
1104bool DocumentImporter::writeFormulas(const COLLADAFW::Formulas *formulas)
1105{
1106 return true;
1107}
1108
1109bool DocumentImporter::writeKinematicsScene(const COLLADAFW::KinematicsScene *kinematicsScene)
1110{
1111 return true;
1112}
1113
1114ExtraTags *DocumentImporter::getExtraTags(const COLLADAFW::UniqueId &uid)
1115{
1116 if (uid_tags_map.find(uid.toAscii()) == uid_tags_map.end()) {
1117 return nullptr;
1118 }
1119 return uid_tags_map[uid.toAscii()];
1120}
1121
1122bool DocumentImporter::addExtraTags(const COLLADAFW::UniqueId &uid, ExtraTags *extra_tags)
1123{
1124 uid_tags_map[uid.toAscii()] = extra_tags;
1125 return true;
1126}
1127
1128bool DocumentImporter::is_armature(COLLADAFW::Node *node)
1129{
1130 COLLADAFW::NodePointerArray &child_nodes = node->getChildNodes();
1131 for (uint i = 0; i < child_nodes.getCount(); i++) {
1132 if (child_nodes[i]->getType() == COLLADAFW::Node::JOINT) {
1133 return true;
1134 }
1135 }
1136
1137 /* no child is JOINT */
1138 return false;
1139}
Camera data-block and utility functions.
struct Camera * BKE_camera_add(struct Main *bmain, const char *name)
bool BKE_scene_collections_object_remove(Main *bmain, Scene *scene, Object *ob, bool free_us)
void BKE_collection_object_add_from(Main *bmain, Scene *scene, Object *ob_src, Object *ob_dst)
struct bConstraint * BKE_constraint_add_for_object(struct Object *ob, const char *name, short type)
Scene * CTX_data_scene(const bContext *C)
Main * CTX_data_main(const bContext *C)
ViewLayer * CTX_data_view_layer(const bContext *C)
Image * BKE_image_load_exists(Main *bmain, const char *filepath, bool *r_exists=nullptr)
void BKE_view_layer_base_deselect_all(const Scene *scene, ViewLayer *view_layer)
void BKE_id_free_us(Main *bmain, void *idv) ATTR_NONNULL()
IDNewNameResult BKE_libblock_rename(Main &bmain, ID &id, blender::StringRefNull name, const IDNewNameMode mode=IDNewNameMode::RenameExistingNever)
Definition lib_id.cc:2350
ID * BKE_id_copy(Main *bmain, const ID *id)
Definition lib_id.cc:772
void id_us_min(ID *id)
Definition lib_id.cc:361
General operations, lookup, etc. for blender lights.
Light * BKE_light_add(Main *bmain, const char *name) ATTR_WARN_UNUSED_RESULT
General operations, lookup, etc. for materials.
Material * BKE_material_add(Main *bmain, const char *name)
void BKE_object_apply_mat4(Object *ob, const float mat[4][4], bool use_compat, bool use_parent)
File and directory operations.
int BLI_exists(const char *path) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition storage.cc:373
#define DEG2RADF(_deg)
void mul_m4_m4m4(float R[4][4], const float A[4][4], const float B[4][4])
float fov_to_focallength(float hfov, float sensor)
#define FILE_MAX
#define BLI_path_join(...)
void void BLI_path_split_dir_part(const char *filepath, char *dir, size_t dir_maxncpy) ATTR_NONNULL(1
unsigned int uint
void DEG_id_tag_update(ID *id, unsigned int flags)
void DEG_relations_tag_update(Main *bmain)
@ ID_RECALC_TRANSFORM
Definition DNA_ID.h:962
@ ID_RECALC_SYNC_TO_EVAL
Definition DNA_ID.h:1026
@ ID_RECALC_ANIMATION
Definition DNA_ID.h:985
@ ID_RECALC_GEOMETRY
Definition DNA_ID.h:982
@ CAM_PERSP
@ CAM_ORTHO
@ LA_LOCAL
@ LA_SPOT
@ LA_SUN
@ OB_EMPTY
@ OB_CAMERA
@ OB_ARMATURE
@ OB_LAMP
@ PAROBJECT
@ USER_UNIT_IMPERIAL
@ USER_UNIT_METRIC
@ USER_UNIT_NONE
static Controller * controller
#define C
Definition RandGen.cpp:29
#define ND_TRANSFORM
Definition WM_types.hh:453
#define NC_OBJECT
Definition WM_types.hh:376
ATTR_WARN_UNUSED_RESULT const BMVert const BMEdge * e
ATTR_WARN_UNUSED_RESULT const BMVert * v
virtual const char * getName() const
bool writeScene(const COLLADAFW::Scene *) override
void write_profile_COMMON(COLLADAFW::EffectCommon *, Material *)
std::vector< Object * > * write_node(COLLADAFW::Node *, COLLADAFW::Node *, Scene *, Object *, bool)
std::string get_import_version(const COLLADAFW::FileInfo *asset)
bool addExtraTags(const COLLADAFW::UniqueId &uid, ExtraTags *extra_tags)
Object * create_light_object(COLLADAFW::InstanceLight *, Scene *)
bool writeVisualScene(const COLLADAFW::VisualScene *) override
bool writeSkinControllerData(const COLLADAFW::SkinControllerData *) override
bool writeImage(const COLLADAFW::Image *) override
bool writeGlobalAsset(const COLLADAFW::FileInfo *) override
~DocumentImporter() override
bool writeMaterial(const COLLADAFW::Material *) override
void finish() override
void translate_anim_recursive(COLLADAFW::Node *, COLLADAFW::Node *, Object *)
void cancel(const COLLADAFW::String &errorMessage) override
bool writeAnimationList(const COLLADAFW::AnimationList *) override
Object * create_instance_node(Object *, COLLADAFW::Node *, COLLADAFW::Node *, Scene *, bool)
bool writeLight(const COLLADAFW::Light *) override
bool writeGeometry(const COLLADAFW::Geometry *) override
bool writeLibraryNodes(const COLLADAFW::LibraryNodes *) override
bool writeController(const COLLADAFW::Controller *) override
bool writeKinematicsScene(const COLLADAFW::KinematicsScene *) override
bool writeCamera(const COLLADAFW::Camera *) override
void create_constraints(ExtraTags *et, Object *ob)
DocumentImporter(bContext *C, const ImportSettings *import_settings)
ExtraTags * getExtraTags(const COLLADAFW::UniqueId &uid)
void start() override
bool writeEffect(const COLLADAFW::Effect *) override
Object * create_camera_object(COLLADAFW::InstanceCamera *, Scene *)
bool writeFormulas(const COLLADAFW::Formulas *) override
bool is_armature(COLLADAFW::Node *node)
bool writeAnimation(const COLLADAFW::Animation *) override
Handler class for parser errors.
bool hasError()
Handler class for <extra> data, through which different profiles can be handled.
Class for saving <extra> tags for a specific UniqueId.
Definition ExtraTags.h:17
bool isProfile(std::string profile)
Definition ExtraTags.cpp:24
bool setData(std::string tag, short *data)
Definition ExtraTags.cpp:66
void set_reflectivity(COLLADAFW::FloatOrParam &val)
void set_shininess(COLLADAFW::FloatOrParam &val)
void set_specular(COLLADAFW::ColorOrTexture &cot)
void update_material_nodetree()
void set_ior(COLLADAFW::FloatOrParam &val)
void set_reflective(COLLADAFW::ColorOrTexture &cot)
void set_emission(COLLADAFW::ColorOrTexture &cot)
void set_alpha(COLLADAFW::EffectCommon::OpaqueMode mode, COLLADAFW::ColorOrTexture &cot, COLLADAFW::FloatOrParam &val)
void set_diffuse(COLLADAFW::ColorOrTexture &cot)
void set_ambient(COLLADAFW::ColorOrTexture &cot)
Object * bc_add_object(Main *bmain, Scene *scene, ViewLayer *view_layer, int type, const char *name)
bool bc_set_parent(Object *ob, Object *par, bContext *C, bool is_parent_space)
std::string bc_url_encode(const std::string &data)
void bc_match_scale(Object *ob, UnitConverter &bc_unit, bool scale_to_scene)
Object * bc_add_armature(COLLADAFW::Node *node, ExtraTags *node_extra_tags, Main *bmain, Scene *scene, ViewLayer *view_layer, int type, const char *name)
#define tanf(x)
#define atanf(x)
uint col
int count
static char ** types
Definition makesdna.cc:71
PointerRNA RNA_pointer_get(PointerRNA *ptr, const char *name)
PropertyRNA * RNA_struct_find_property(PointerRNA *ptr, const char *identifier)
void RNA_property_enum_set(PointerRNA *ptr, PropertyRNA *prop, int value)
void RNA_property_float_set(PointerRNA *ptr, PropertyRNA *prop, float value)
PointerRNA RNA_id_pointer_create(ID *id)
float clip_end
float sensor_x
float clip_start
struct CameraDOFSettings dof
float ortho_scale
float energy
float att_dist
float area_sizez
float area_sizey
short area_shape
float clipsta
float spotblend
float spotsize
float radius
float area_size
short type
short flag
ObjectRuntimeHandle * runtime
struct Object * parent
char parsubstr[64]
i
Definition text_draw.cc:230
void WM_event_add_notifier(const bContext *C, uint type, void *reference)