Workbench: API Changes
[blender.git] / source / blender / collada / DocumentImporter.cpp
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * Contributor(s): Chingiz Dyussenov, Arystanbek Dyussenov, Nathan Letwory.
19  *
20  * ***** END GPL LICENSE BLOCK *****
21  */
22
23 /** \file blender/collada/DocumentImporter.cpp
24  *  \ingroup collada
25  */
26
27 // TODO:
28 // * name imported objects
29 // * import object rotation as euler
30
31 #include <string>
32 #include <map>
33 #include <algorithm> // sort()
34
35 #include "COLLADAFWRoot.h"
36 #include "COLLADAFWStableHeaders.h"
37 #include "COLLADAFWColorOrTexture.h"
38 #include "COLLADAFWIndexList.h"
39 #include "COLLADAFWMeshPrimitiveWithFaceVertexCount.h"
40 #include "COLLADAFWPolygons.h"
41 #include "COLLADAFWSampler.h"
42 #include "COLLADAFWTypes.h"
43 #include "COLLADAFWVisualScene.h"
44 #include "COLLADAFWArrayPrimitiveType.h"
45 #include "COLLADAFWLibraryNodes.h"
46 #include "COLLADAFWCamera.h"
47 #include "COLLADAFWLight.h"
48
49 #include "COLLADASaxFWLLoader.h"
50 #include "COLLADASaxFWLIExtraDataCallbackHandler.h"
51
52 extern "C" {
53 #include "BLI_listbase.h"
54 #include "BLI_math.h"
55 #include "BLI_string.h"
56 #include "BLI_utildefines.h"
57 #include "BLI_fileops.h"
58
59 #include "BKE_camera.h"
60 #include "BKE_collection.h"
61 #include "BKE_main.h"
62 #include "BKE_layer.h"
63 #include "BKE_lamp.h"
64 #include "BKE_library.h"
65 #include "BKE_fcurve.h"
66 #include "BKE_scene.h"
67 #include "BKE_global.h"
68 #include "BKE_material.h"
69 #include "BKE_image.h"
70
71 #include "BLI_path_util.h"
72
73 #include "DNA_camera_types.h"
74 #include "DNA_lamp_types.h"
75
76 #include "RNA_access.h"
77
78 #include "MEM_guardedalloc.h"
79
80 #include "WM_api.h"
81 #include "WM_types.h"
82
83 }
84
85 #include "DEG_depsgraph.h"
86 #include "DEG_depsgraph_build.h"
87
88 #include "ExtraHandler.h"
89 #include "ErrorHandler.h"
90 #include "DocumentImporter.h"
91 #include "TransformReader.h"
92
93 #include "collada_internal.h"
94 #include "collada_utils.h"
95
96
97 /*
98  * COLLADA Importer limitations:
99  * - no multiple scene import, all objects are added to active scene
100  */
101
102 // #define COLLADA_DEBUG
103 // creates empties for each imported bone on layer 2, for debugging
104 // #define ARMATURE_TEST
105
106 DocumentImporter::DocumentImporter(bContext *C, const ImportSettings *import_settings) :
107         import_settings(import_settings),
108         mImportStage(General),
109         mContext(C),
110         view_layer(CTX_data_view_layer(mContext)),
111         armature_importer(&unit_converter, &mesh_importer, CTX_data_scene(C), view_layer, import_settings),
112         mesh_importer(&unit_converter, &armature_importer, CTX_data_scene(C), view_layer),
113         anim_importer(&unit_converter, &armature_importer, CTX_data_scene(C))
114 {
115 }
116
117 DocumentImporter::~DocumentImporter()
118 {
119         TagsMap::iterator etit;
120         etit = uid_tags_map.begin();
121         while (etit != uid_tags_map.end()) {
122                 delete etit->second;
123                 etit++;
124         }
125 }
126
127 bool DocumentImporter::import()
128 {
129         ErrorHandler errorHandler;
130         COLLADASaxFWL::Loader loader(&errorHandler);
131         COLLADAFW::Root root(&loader, this);
132         ExtraHandler *ehandler = new ExtraHandler(this, &(this->anim_importer));
133
134         loader.registerExtraDataCallbackHandler(ehandler);
135
136         // deselect all to select new objects
137         BKE_view_layer_base_deselect_all(view_layer);
138
139         std::string mFilename = std::string(this->import_settings->filepath);
140         const std::string encodedFilename = bc_url_encode(mFilename);
141         if (!root.loadDocument(encodedFilename)) {
142                 fprintf(stderr, "COLLADAFW::Root::loadDocument() returned false on 1st pass\n");
143                 delete ehandler;
144                 return false;
145         }
146
147         if (errorHandler.hasError()) {
148                 delete ehandler;
149                 return false;
150         }
151
152         /** TODO set up scene graph and such here */
153
154         mImportStage = Controller;
155
156         COLLADASaxFWL::Loader loader2;
157         COLLADAFW::Root root2(&loader2, this);
158
159         if (!root2.loadDocument(encodedFilename)) {
160                 fprintf(stderr, "COLLADAFW::Root::loadDocument() returned false on 2nd pass\n");
161                 delete ehandler;
162                 return false;
163         }
164
165         delete ehandler;
166
167         return true;
168 }
169
170 void DocumentImporter::cancel(const COLLADAFW::String& errorMessage)
171 {
172         // TODO: if possible show error info
173         //
174         // Should we get rid of invisible Meshes that were created so far
175         // or maybe create objects at coordinate space origin?
176         //
177         // The latter sounds better.
178 }
179
180 void DocumentImporter::start()
181 {
182 }
183
184 void DocumentImporter::finish()
185 {
186         if (mImportStage != General)
187                 return;
188
189         Main *bmain = CTX_data_main(mContext);
190         // TODO: create a new scene except the selected <visual_scene> - use current blender scene for it
191         Scene *sce = CTX_data_scene(mContext);
192         unit_converter.calculate_scale(*sce);
193
194         std::vector<Object *> *objects_to_scale = new std::vector<Object *>();
195
196         /** TODO Break up and put into 2-pass parsing of DAE */
197         std::vector<const COLLADAFW::VisualScene *>::iterator sit;
198         for (sit = vscenes.begin(); sit != vscenes.end(); sit++) {
199                 PointerRNA sceneptr, unit_settings;
200                 PropertyRNA *system, *scale;
201
202                 // for scene unit settings: system, scale_length
203
204                 RNA_id_pointer_create(&sce->id, &sceneptr);
205                 unit_settings = RNA_pointer_get(&sceneptr, "unit_settings");
206                 system = RNA_struct_find_property(&unit_settings, "system");
207                 scale = RNA_struct_find_property(&unit_settings, "scale_length");
208
209                 if (this->import_settings->import_units) {
210
211                         switch (unit_converter.isMetricSystem()) {
212                                 case UnitConverter::Metric:
213                                         RNA_property_enum_set(&unit_settings, system, USER_UNIT_METRIC);
214                                         break;
215                                 case UnitConverter::Imperial:
216                                         RNA_property_enum_set(&unit_settings, system, USER_UNIT_IMPERIAL);
217                                         break;
218                                 default:
219                                         RNA_property_enum_set(&unit_settings, system, USER_UNIT_NONE);
220                                         break;
221                         }
222                         float unit_factor = unit_converter.getLinearMeter();
223                         RNA_property_float_set(&unit_settings, scale, unit_factor);
224                         fprintf(stdout, "Collada: Adjusting Blender units to Importset units: %f.\n", unit_factor);
225
226                 }
227
228                 // Write nodes to scene
229                 const COLLADAFW::NodePointerArray& roots = (*sit)->getRootNodes();
230                 for (unsigned int i = 0; i < roots.getCount(); i++) {
231                         std::vector<Object *> *objects_done = write_node(roots[i], NULL, sce, NULL, false);
232                         objects_to_scale->insert(objects_to_scale->end(), objects_done->begin(), objects_done->end());
233                         delete objects_done;
234                 }
235
236                 // update scene
237                 DEG_relations_tag_update(bmain);
238                 WM_event_add_notifier(mContext, NC_OBJECT | ND_TRANSFORM, NULL);
239
240         }
241
242
243         mesh_importer.optimize_material_assignements();
244
245         armature_importer.set_tags_map(this->uid_tags_map);
246         armature_importer.make_armatures(mContext, *objects_to_scale);
247         armature_importer.make_shape_keys();
248         DEG_relations_tag_update(bmain);
249
250 #if 0
251         armature_importer.fix_animation();
252 #endif
253
254         for (std::vector<const COLLADAFW::VisualScene *>::iterator vsit = vscenes.begin(); vsit != vscenes.end(); vsit++) {
255                 const COLLADAFW::NodePointerArray& roots = (*vsit)->getRootNodes();
256
257                 for (unsigned int i = 0; i < roots.getCount(); i++) {
258                         translate_anim_recursive(roots[i], NULL, NULL);
259                 }
260         }
261
262         if (libnode_ob.size()) {
263
264                 fprintf(stderr, "got %d library nodes to free\n", (int)libnode_ob.size());
265                 // free all library_nodes
266                 std::vector<Object *>::iterator it;
267                 for (it = libnode_ob.begin(); it != libnode_ob.end(); it++) {
268                         Object *ob = *it;
269                         BKE_scene_collections_object_remove(G.main, sce, ob, true);
270                 }
271                 libnode_ob.clear();
272
273                 DEG_relations_tag_update(bmain);
274         }
275
276         bc_match_scale(objects_to_scale, unit_converter, !this->import_settings->import_units);
277
278         delete objects_to_scale;
279 }
280
281
282 void DocumentImporter::translate_anim_recursive(COLLADAFW::Node *node, COLLADAFW::Node *par = NULL, Object *parob = NULL)
283 {
284         Main *bmain = CTX_data_main(mContext);
285         // The split in #29246, rootmap must point at actual root when
286         // calculating bones in apply_curves_as_matrix. - actual root is the root node.
287         // This has to do with inverse bind poses being world space
288         // (the sources for skinned bones' restposes) and the way
289         // non-skinning nodes have their "restpose" recursively calculated.
290         // XXX TODO: design issue, how to support unrelated joints taking
291         // part in skinning.
292         if (par) { // && par->getType() == COLLADAFW::Node::JOINT) {
293                 // par is root if there's no corresp. key in root_map
294                 if (root_map.find(par->getUniqueId()) == root_map.end())
295                         root_map[node->getUniqueId()] = node;
296                 else
297                         root_map[node->getUniqueId()] = root_map[par->getUniqueId()];
298         }
299
300 #if 0
301         COLLADAFW::Transformation::TransformationType types[] = {
302                 COLLADAFW::Transformation::ROTATE,
303                 COLLADAFW::Transformation::SCALE,
304                 COLLADAFW::Transformation::TRANSLATE,
305                 COLLADAFW::Transformation::MATRIX
306         };
307
308         Object *ob;
309 #endif
310         unsigned int i;
311
312         if (node->getType() == COLLADAFW::Node::JOINT && par == NULL) {
313                 // For Skeletons without root node we have to simulate the
314                 // root node here and recursively enter the same function
315                 // XXX: maybe this can be made more elegant.
316                 translate_anim_recursive(node, node, parob);
317         }
318         else {
319                 anim_importer.translate_Animations(bmain, node, root_map, object_map, FW_object_map, uid_material_map);
320                 COLLADAFW::NodePointerArray &children = node->getChildNodes();
321                 for (i = 0; i < children.getCount(); i++) {
322                         translate_anim_recursive(children[i], node, NULL);
323                 }
324         }
325 }
326
327 /**
328  * If the imported file was made with Blender, return the Blender version used,
329  * otherwise return an empty std::string
330  */
331 std::string DocumentImporter::get_import_version(const COLLADAFW::FileInfo *asset)
332 {
333         const char AUTORING_TOOL[] = "authoring_tool";
334         const std::string BLENDER("Blender ");
335         const COLLADAFW::FileInfo::ValuePairPointerArray &valuePairs = asset->getValuePairArray();
336         for ( size_t i = 0, count = valuePairs.getCount(); i < count; ++i)
337         {
338                 const COLLADAFW::FileInfo::ValuePair* valuePair = valuePairs[i];
339                 const COLLADAFW::String& key = valuePair->first;
340                 const COLLADAFW::String& value = valuePair->second;
341                 if ( key == AUTORING_TOOL )
342                 {
343                         if (value.compare(0, BLENDER.length(), BLENDER) == 0)
344                         {
345                                 // Was made with Blender, now get version string
346                                 std::string v            = value.substr(BLENDER.length());
347                                 std::string::size_type n = v.find(" ");
348                                 if (n > 0) {
349                                         return v.substr(0,n);
350                                 }
351                         }
352                 }
353         }
354         return "";
355 }
356
357 /** When this method is called, the writer must write the global document asset.
358  * \return The writer should return true, if writing succeeded, false otherwise.*/
359 bool DocumentImporter::writeGlobalAsset(const COLLADAFW::FileInfo *asset)
360 {
361         unit_converter.read_asset(asset);
362         import_from_version = get_import_version(asset);
363         anim_importer.set_import_from_version(import_from_version);
364         return true;
365 }
366
367 /** When this method is called, the writer must write the scene.
368  * \return The writer should return true, if writing succeeded, false otherwise.*/
369 bool DocumentImporter::writeScene(const COLLADAFW::Scene *scene)
370 {
371         // XXX could store the scene id, but do nothing for now
372         return true;
373 }
374 Object *DocumentImporter::create_camera_object(COLLADAFW::InstanceCamera *camera, Scene *sce)
375 {
376         const COLLADAFW::UniqueId& cam_uid = camera->getInstanciatedObjectId();
377         if (uid_camera_map.find(cam_uid) == uid_camera_map.end()) {
378                 // fprintf(stderr, "Couldn't find camera by UID.\n");
379                 return NULL;
380         }
381
382         Object *ob = bc_add_object(sce, view_layer, OB_CAMERA, NULL);
383         Camera *cam = uid_camera_map[cam_uid];
384         Camera *old_cam = (Camera *)ob->data;
385         ob->data = cam;
386         BKE_libblock_free_us(G.main, old_cam);
387         return ob;
388 }
389
390 Object *DocumentImporter::create_lamp_object(COLLADAFW::InstanceLight *lamp, Scene *sce)
391 {
392         const COLLADAFW::UniqueId& lamp_uid = lamp->getInstanciatedObjectId();
393         if (uid_lamp_map.find(lamp_uid) == uid_lamp_map.end()) {
394                 fprintf(stderr, "Couldn't find lamp by UID.\n");
395                 return NULL;
396         }
397
398         Object *ob = bc_add_object(sce, view_layer, OB_LAMP, NULL);
399         Lamp *la = uid_lamp_map[lamp_uid];
400         Lamp *old_lamp = (Lamp *)ob->data;
401         ob->data = la;
402         BKE_libblock_free_us(G.main, old_lamp);
403         return ob;
404 }
405
406 Object *DocumentImporter::create_instance_node(Object *source_ob, COLLADAFW::Node *source_node, COLLADAFW::Node *instance_node, Scene *sce, bool is_library_node)
407 {
408         fprintf(stderr, "create <instance_node> under node id=%s from node id=%s\n", instance_node ? instance_node->getOriginalId().c_str() : NULL, source_node ? source_node->getOriginalId().c_str() : NULL);
409
410         Object *obn = BKE_object_copy(G.main, source_ob);
411         DEG_id_tag_update(&obn->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME);
412         BKE_collection_object_add_from(G.main, sce, source_ob, obn);
413
414         if (instance_node) {
415                 anim_importer.read_node_transform(instance_node, obn);
416                 // if we also have a source_node (always ;), take its
417                 // transformation matrix and apply it to the newly instantiated
418                 // object to account for node hierarchy transforms in
419                 // .dae
420                 if (source_node) {
421                         COLLADABU::Math::Matrix4 mat4 = source_node->getTransformationMatrix();
422                         COLLADABU::Math::Matrix4 bmat4 = mat4.transpose(); // transpose to get blender row-major order
423                         float mat[4][4];
424                         for (int i = 0; i < 4; i++) {
425                                 for (int j = 0; j < 4; j++) {
426                                         mat[i][j] = bmat4[i][j];
427                                 }
428                         }
429                         // calc new matrix and apply
430                         mul_m4_m4m4(obn->obmat, obn->obmat, mat);
431                         BKE_object_apply_mat4(obn, obn->obmat, 0, 0);
432                 }
433         }
434         else {
435                 anim_importer.read_node_transform(source_node, obn);
436         }
437
438         /*DAG_relations_tag_update(CTX_data_main(mContext));*/
439
440         COLLADAFW::NodePointerArray &children = source_node->getChildNodes();
441         if (children.getCount()) {
442                 for (unsigned int i = 0; i < children.getCount(); i++) {
443                         COLLADAFW::Node *child_node = children[i];
444                         const COLLADAFW::UniqueId& child_id = child_node->getUniqueId();
445                         if (object_map.find(child_id) == object_map.end())
446                                 continue;
447                         COLLADAFW::InstanceNodePointerArray &inodes = child_node->getInstanceNodes();
448                         Object *new_child = NULL;
449                         if (inodes.getCount()) { // \todo loop through instance nodes
450                                 const COLLADAFW::UniqueId& id = inodes[0]->getInstanciatedObjectId();
451                                 fprintf(stderr, "Doing %d child nodes\n", (int)node_map.count(id));
452                                 new_child = create_instance_node(object_map.find(id)->second, node_map[id], child_node, sce, is_library_node);
453                         }
454                         else {
455                                 new_child = create_instance_node(object_map.find(child_id)->second, child_node, NULL, sce, is_library_node);
456                         }
457                         bc_set_parent(new_child, obn, mContext, true);
458
459                         if (is_library_node)
460                                 libnode_ob.push_back(new_child);
461                 }
462         }
463
464         return obn;
465 }
466
467 // to create constraints off node <extra> tags. Assumes only constraint data in
468 // current <extra> with blender profile.
469 void DocumentImporter::create_constraints(ExtraTags *et, Object *ob)
470 {
471         if (et && et->isProfile("blender")) {
472                 std::string name;
473                 short type = 0;
474                 et->setData("type", &type);
475                 BKE_constraint_add_for_object(ob, "Test_con", type);
476
477         }
478 }
479
480 void DocumentImporter::report_unknown_reference(const COLLADAFW::Node &node, const std::string object_type)
481 {
482         std::string id = node.getOriginalId();
483         std::string name = node.getName();
484         fprintf(stderr,
485                 "error: node id=\"%s\", name=\"%s\" refers to an undefined %s.\n",
486                 id.c_str(),
487                 name.c_str(),
488                 object_type.c_str());
489 }
490
491 std::vector<Object *> *DocumentImporter::write_node(COLLADAFW::Node *node, COLLADAFW::Node *parent_node, Scene *sce, Object *par, bool is_library_node)
492 {
493         Object *ob = NULL;
494         bool is_joint = node->getType() == COLLADAFW::Node::JOINT;
495         bool read_transform = true;
496         std::string id   = node->getOriginalId();
497         std::string name = node->getName();
498
499         // if node has child nodes write them
500         COLLADAFW::NodePointerArray &child_nodes = node->getChildNodes();
501
502         std::vector<Object *> *objects_done = new std::vector<Object *>();
503         std::vector<Object *> *root_objects = new std::vector<Object *>();
504
505         fprintf(stderr,
506                 "Writing node id='%s', name='%s'\n",
507                 id.c_str(),
508                 name.c_str());
509
510         if (is_joint) {
511                 if (parent_node == NULL && !is_library_node) {
512                         // A Joint on root level is a skeleton without root node.
513                         // Here we add the armature "on the fly":
514                         par = bc_add_object(sce, view_layer, OB_ARMATURE, std::string("Armature").c_str());
515                         objects_done->push_back(par);
516                         root_objects->push_back(par);
517                         object_map.insert(std::pair<COLLADAFW::UniqueId, Object *>(node->getUniqueId(), par));
518                         node_map[node->getUniqueId()] = node;
519                 }
520                 if (parent_node == NULL || parent_node->getType() != COLLADAFW::Node::JOINT) {
521                         armature_importer.add_root_joint(node, par);
522                 }
523
524                 if (parent_node == NULL) {
525                         // for skeletons without root node all has been done above.
526                         // Skeletons with root node are handled further down.
527                         goto finally;
528                 }
529         }
530         else {
531                 COLLADAFW::InstanceGeometryPointerArray &geom = node->getInstanceGeometries();
532                 COLLADAFW::InstanceCameraPointerArray &camera = node->getInstanceCameras();
533                 COLLADAFW::InstanceLightPointerArray &lamp = node->getInstanceLights();
534                 COLLADAFW::InstanceControllerPointerArray &controller = node->getInstanceControllers();
535                 COLLADAFW::InstanceNodePointerArray &inst_node = node->getInstanceNodes();
536                 size_t geom_done = 0;
537                 size_t camera_done = 0;
538                 size_t lamp_done = 0;
539                 size_t controller_done = 0;
540                 size_t inst_done = 0;
541
542                 // XXX linking object with the first <instance_geometry>, though a node may have more of them...
543                 // maybe join multiple <instance_...> meshes into 1, and link object with it? not sure...
544                 // <instance_geometry>
545                 while (geom_done < geom.getCount()) {
546                         ob = mesh_importer.create_mesh_object(node, geom[geom_done], false, uid_material_map);
547                         if (ob == NULL) {
548                                 report_unknown_reference(*node, "instance_mesh");
549                         }
550                         else {
551                                 objects_done->push_back(ob);
552                                 if (parent_node == NULL) {
553                                         root_objects->push_back(ob);
554                                 }
555                         }
556                         ++geom_done;
557                 }
558                 while (camera_done < camera.getCount()) {
559                         ob = create_camera_object(camera[camera_done], sce);
560                         if (ob == NULL) {
561                                 report_unknown_reference(*node, "instance_camera");
562                         }
563                         else {
564                                 objects_done->push_back(ob);
565                                 if (parent_node == NULL) {
566                                         root_objects->push_back(ob);
567                                 }
568                         }
569                         ++camera_done;
570                 }
571                 while (lamp_done < lamp.getCount()) {
572                         ob = create_lamp_object(lamp[lamp_done], sce);
573                         if (ob == NULL) {
574                                 report_unknown_reference(*node, "instance_lamp");
575                         }
576                         else {
577                                 objects_done->push_back(ob);
578                                 if (parent_node == NULL) {
579                                         root_objects->push_back(ob);
580                                 }
581                         }
582                         ++lamp_done;
583                 }
584                 while (controller_done < controller.getCount()) {
585                         COLLADAFW::InstanceGeometry *geometry = (COLLADAFW::InstanceGeometry *)controller[controller_done];
586                         ob = mesh_importer.create_mesh_object(node, geometry, true, uid_material_map);
587                         if (ob == NULL) {
588                                 report_unknown_reference(*node, "instance_controller");
589                         }
590                         else {
591                                 objects_done->push_back(ob);
592                                 if (parent_node == NULL) {
593                                         root_objects->push_back(ob);
594                                 }
595                         }
596                         ++controller_done;
597                 }
598                 // XXX instance_node is not supported yet
599                 while (inst_done < inst_node.getCount()) {
600                         const COLLADAFW::UniqueId& node_id = inst_node[inst_done]->getInstanciatedObjectId();
601                         if (object_map.find(node_id) == object_map.end()) {
602                                 fprintf(stderr, "Cannot find object for node referenced by <instance_node name=\"%s\">.\n", inst_node[inst_done]->getName().c_str());
603                                 ob = NULL;
604                         }
605                         else {
606                                 std::pair<std::multimap<COLLADAFW::UniqueId, Object *>::iterator, std::multimap<COLLADAFW::UniqueId, Object *>::iterator> pair_iter = object_map.equal_range(node_id);
607                                 for (std::multimap<COLLADAFW::UniqueId, Object *>::iterator it2 = pair_iter.first; it2 != pair_iter.second; it2++) {
608                                         Object *source_ob = (Object *)it2->second;
609                                         COLLADAFW::Node *source_node = node_map[node_id];
610                                         ob = create_instance_node(source_ob, source_node, node, sce, is_library_node);
611                                         objects_done->push_back(ob);
612                                         if (parent_node == NULL) {
613                                                 root_objects->push_back(ob);
614                                         }
615                                 }
616                         }
617                         ++inst_done;
618
619                         read_transform = false;
620                 }
621
622                 // if node is empty - create empty object
623                 // XXX empty node may not mean it is empty object, not sure about this
624                 if ( (geom_done + camera_done + lamp_done + controller_done + inst_done) < 1) {
625                         //Check if Object is armature, by checking if immediate child is a JOINT node.
626                         if (is_armature(node)) {
627                                 ob = bc_add_object(sce, view_layer, OB_ARMATURE, name.c_str());
628                         }
629                         else {
630                                 ob = bc_add_object(sce, view_layer, OB_EMPTY, NULL);
631                         }
632                         objects_done->push_back(ob);
633                         if (parent_node == NULL) {
634                                 root_objects->push_back(ob);
635                         }
636                 }
637
638                 // XXX: if there're multiple instances, only one is stored
639
640                 if (!ob) {
641                         goto finally;
642                 }
643
644                 for (std::vector<Object *>::iterator it = objects_done->begin(); it != objects_done->end(); ++it) {
645                         ob = *it;
646                         std::string nodename = node->getName().size() ? node->getName() : node->getOriginalId();
647                         BKE_libblock_rename(G.main, &ob->id, (char *)nodename.c_str());
648                         object_map.insert(std::pair<COLLADAFW::UniqueId, Object *>(node->getUniqueId(), ob));
649                         node_map[node->getUniqueId()] = node;
650
651                         if (is_library_node)
652                                 libnode_ob.push_back(ob);
653                 }
654
655
656                 //create_constraints(et,ob);
657
658         }
659
660         for (std::vector<Object *>::iterator it = objects_done->begin(); it != objects_done->end(); ++it) {
661                 ob = *it;
662
663                 if (read_transform)
664                         anim_importer.read_node_transform(node, ob);  // overwrites location set earlier
665
666                 if (!is_joint) {
667                         if (par && ob) {
668                                 ob->parent = par;
669                                 ob->partype = PAROBJECT;
670                                 ob->parsubstr[0] = 0;
671
672                                 //bc_set_parent(ob, par, mContext, false);
673                         }
674                 }
675         }
676
677         if (objects_done->size() > 0) {
678                 ob = *objects_done->begin();
679         }
680         else {
681                 ob = NULL;
682         }
683
684         for (unsigned int i = 0; i < child_nodes.getCount(); i++) {
685                 std::vector<Object *> *child_objects;
686                 child_objects = write_node(child_nodes[i], node, sce, ob, is_library_node);
687                 delete child_objects;
688         }
689
690
691 finally:
692         delete objects_done;
693
694         return root_objects;
695 }
696
697 /** When this method is called, the writer must write the entire visual scene.
698  *  Return The writer should return true, if writing succeeded, false otherwise. */
699 bool DocumentImporter::writeVisualScene(const COLLADAFW::VisualScene *visualScene)
700 {
701         if (mImportStage != General)
702                 return true;
703
704         // this method called on post process after writeGeometry, writeMaterial, etc.
705
706         // for each <node> in <visual_scene>:
707         // create an Object
708         // if Mesh (previously created in writeGeometry) to which <node> corresponds exists, link Object with that mesh
709
710         // update: since we cannot link a Mesh with Object in
711         // writeGeometry because <geometry> does not reference <node>,
712         // we link Objects with Meshes here
713
714         vscenes.push_back(visualScene);
715
716         return true;
717 }
718
719 /** When this method is called, the writer must handle all nodes contained in the
720  * library nodes.
721  * \return The writer should return true, if writing succeeded, false otherwise.*/
722 bool DocumentImporter::writeLibraryNodes(const COLLADAFW::LibraryNodes *libraryNodes)
723 {
724         if (mImportStage != General)
725                 return true;
726
727         Scene *sce = CTX_data_scene(mContext);
728
729         const COLLADAFW::NodePointerArray& nodes = libraryNodes->getNodes();
730
731         for (unsigned int i = 0; i < nodes.getCount(); i++) {
732                 std::vector<Object *> *child_objects;
733                 child_objects = write_node(nodes[i], NULL, sce, NULL, true);
734                 delete child_objects;
735         }
736
737         return true;
738 }
739
740 /** When this method is called, the writer must write the geometry.
741  * \return The writer should return true, if writing succeeded, false otherwise.*/
742 bool DocumentImporter::writeGeometry(const COLLADAFW::Geometry *geom)
743 {
744         if (mImportStage != General)
745                 return true;
746
747         return mesh_importer.write_geometry(geom);
748 }
749
750 /** When this method is called, the writer must write the material.
751  * \return The writer should return true, if writing succeeded, false otherwise.*/
752 bool DocumentImporter::writeMaterial(const COLLADAFW::Material *cmat)
753 {
754         if (mImportStage != General)
755                 return true;
756
757         const std::string& str_mat_id = cmat->getName().size() ? cmat->getName() : cmat->getOriginalId();
758         Material *ma = BKE_material_add(G.main, (char *)str_mat_id.c_str());
759
760         this->uid_effect_map[cmat->getInstantiatedEffect()] = ma;
761         this->uid_material_map[cmat->getUniqueId()] = ma;
762
763         return true;
764 }
765
766 void DocumentImporter::write_profile_COMMON(COLLADAFW::EffectCommon *ef, Material *ma)
767 {
768         COLLADAFW::EffectCommon::ShaderType shader = ef->getShaderType();
769
770         // TODO: add back texture and extended material parameter support
771
772         // blinn
773         if (shader == COLLADAFW::EffectCommon::SHADER_BLINN) {
774 #if 0
775                 ma->spec_shader = MA_SPEC_BLINN;
776                 ma->spec = ef->getShininess().getFloatValue();
777 #endif
778         }
779         // phong
780         else if (shader == COLLADAFW::EffectCommon::SHADER_PHONG) {
781 #if 0
782                 ma->spec_shader = MA_SPEC_PHONG;
783                 ma->har = ef->getShininess().getFloatValue();
784 #endif
785         }
786         // lambert
787         else if (shader == COLLADAFW::EffectCommon::SHADER_LAMBERT) {
788 #if 0
789                 ma->diff_shader = MA_DIFF_LAMBERT;
790 #endif
791         }
792         // default - lambert
793         else {
794 #if 0
795                 ma->diff_shader = MA_DIFF_LAMBERT;
796                 fprintf(stderr, "Current shader type is not supported, default to lambert.\n");
797 #endif
798         }
799         // reflectivity
800         ma->metallic = ef->getReflectivity().getFloatValue();
801         // index of refraction
802 #if 0
803         ma->ang = ef->getIndexOfRefraction().getFloatValue();
804 #endif
805
806         COLLADAFW::Color col;
807
808         // DIFFUSE
809         // color
810         if (ef->getDiffuse().isColor()) {
811                 col = ef->getDiffuse().getColor();
812                 ma->r = col.getRed();
813                 ma->g = col.getGreen();
814                 ma->b = col.getBlue();
815         }
816         // texture
817         else if (ef->getDiffuse().isTexture()) {
818 #if 0
819                 COLLADAFW::Texture ctex = ef->getDiffuse().getTexture();
820 #endif
821         }
822         // AMBIENT
823         // color
824         if (ef->getAmbient().isColor()) {
825 #if 0
826                 col = ef->getAmbient().getColor();
827 #endif
828         }
829         // texture
830         else if (ef->getAmbient().isTexture()) {
831 #if 0
832                 COLLADAFW::Texture ctex = ef->getAmbient().getTexture();
833 #endif
834         }
835         // SPECULAR
836         // color
837         if (ef->getSpecular().isColor()) {
838                 col = ef->getSpecular().getColor();
839                 ma->specr = col.getRed();
840                 ma->specg = col.getGreen();
841                 ma->specb = col.getBlue();
842         }
843         // texture
844         else if (ef->getSpecular().isTexture()) {
845 #if 0
846                 COLLADAFW::Texture ctex = ef->getSpecular().getTexture();
847 #endif
848         }
849         // REFLECTIVE
850         // color
851         if (ef->getReflective().isColor()) {
852 #if 0
853                 col = ef->getReflective().getColor();
854 #endif
855         }
856         // texture
857         else if (ef->getReflective().isTexture()) {
858 #if 0
859                 COLLADAFW::Texture ctex = ef->getReflective().getTexture();
860 #endif
861         }
862
863         // EMISSION
864         // color
865         if (ef->getEmission().isColor()) {
866                 // XXX there is no emission color in blender
867                 // but I am not sure
868         }
869         // texture
870         else if (ef->getEmission().isTexture()) {
871 #if 0
872                 COLLADAFW::Texture ctex = ef->getEmission().getTexture();
873 #endif
874         }
875
876         // TRANSPARENT
877         // color
878         if (ef->getOpacity().isColor()) {
879 #if 0
880                 col = ef->getTransparent().getColor();
881                 float alpha = ef->getTransparency().getFloatValue();
882                 if (col.isValid()) {
883                         alpha *= col.getAlpha(); // Assuming A_ONE opaque mode
884                 }
885                 if (col.isValid() || alpha < 1.0) {
886                         ...
887                 }
888 #endif
889         }
890         // texture
891         else if (ef->getOpacity().isTexture()) {
892 #if 0
893                 COLLADAFW::Texture ctex = ef->getOpacity().getTexture();
894 #endif
895         }
896 }
897
898 /** When this method is called, the writer must write the effect.
899  * \return The writer should return true, if writing succeeded, false otherwise.*/
900
901 bool DocumentImporter::writeEffect(const COLLADAFW::Effect *effect)
902 {
903         if (mImportStage != General)
904                 return true;
905
906         const COLLADAFW::UniqueId& uid = effect->getUniqueId();
907
908         if (uid_effect_map.find(uid) == uid_effect_map.end()) {
909                 fprintf(stderr, "Couldn't find a material by UID.\n");
910                 return true;
911         }
912
913         Material *ma = uid_effect_map[uid];
914         std::map<COLLADAFW::UniqueId, Material *>::iterator iter;
915         for (iter = uid_material_map.begin(); iter != uid_material_map.end(); iter++) {
916                 if (iter->second == ma) {
917                         this->FW_object_map[iter->first] = effect;
918                         break;
919                 }
920         }
921         COLLADAFW::CommonEffectPointerArray common_efs = effect->getCommonEffects();
922         if (common_efs.getCount() < 1) {
923                 fprintf(stderr, "Couldn't find <profile_COMMON>.\n");
924                 return true;
925         }
926         // XXX TODO: Take all <profile_common>s
927         // Currently only first <profile_common> is supported
928         COLLADAFW::EffectCommon *ef = common_efs[0];
929         write_profile_COMMON(ef, ma);
930         this->FW_object_map[effect->getUniqueId()] = effect;
931
932         return true;
933 }
934
935
936 /** When this method is called, the writer must write the camera.
937  * \return The writer should return true, if writing succeeded, false otherwise.*/
938 bool DocumentImporter::writeCamera(const COLLADAFW::Camera *camera)
939 {
940         if (mImportStage != General)
941                 return true;
942
943         Camera *cam = NULL;
944         std::string cam_id, cam_name;
945
946         ExtraTags *et=getExtraTags(camera->getUniqueId());
947         cam_id = camera->getOriginalId();
948         cam_name = camera->getName();
949         if (cam_name.size()) cam = (Camera *)BKE_camera_add(G.main, (char *)cam_name.c_str());
950         else cam = (Camera *)BKE_camera_add(G.main, (char *)cam_id.c_str());
951
952         if (!cam) {
953                 fprintf(stderr, "Cannot create camera.\n");
954                 return true;
955         }
956
957         if (et && et->isProfile("blender")) {
958                 et->setData("shiftx",&(cam->shiftx));
959                 et->setData("shifty",&(cam->shifty));
960                 et->setData("YF_dofdist",&(cam->YF_dofdist));
961         }
962         cam->clipsta = camera->getNearClippingPlane().getValue();
963         cam->clipend = camera->getFarClippingPlane().getValue();
964
965         COLLADAFW::Camera::CameraType type = camera->getCameraType();
966         switch (type) {
967                 case COLLADAFW::Camera::ORTHOGRAPHIC:
968                 {
969                         cam->type = CAM_ORTHO;
970                 }
971                 break;
972                 case COLLADAFW::Camera::PERSPECTIVE:
973                 {
974                         cam->type = CAM_PERSP;
975                 }
976                 break;
977                 case COLLADAFW::Camera::UNDEFINED_CAMERATYPE:
978                 {
979                         fprintf(stderr, "Current camera type is not supported.\n");
980                         cam->type = CAM_PERSP;
981                 }
982                 break;
983         }
984
985         switch (camera->getDescriptionType()) {
986                 case COLLADAFW::Camera::ASPECTRATIO_AND_Y:
987                 {
988                         switch (cam->type) {
989                                 case CAM_ORTHO:
990                                 {
991                                         double ymag = 2 * camera->getYMag().getValue();
992                                         double aspect = camera->getAspectRatio().getValue();
993                                         double xmag = aspect * ymag;
994                                         cam->ortho_scale = (float)xmag;
995                                 }
996                                 break;
997                                 case CAM_PERSP:
998                                 default:
999                                 {
1000                                         double yfov = camera->getYFov().getValue();
1001                                         double aspect = camera->getAspectRatio().getValue();
1002
1003                                         // NOTE: Needs more testing (As we curretnly have no official test data for this)
1004
1005                                         double xfov = 2.0f * atanf(aspect * tanf(DEG2RADF(yfov) * 0.5f));
1006                                         cam->lens = fov_to_focallength(xfov, cam->sensor_x);
1007                                 }
1008                                 break;
1009                         }
1010                 }
1011                 break;
1012                 /* XXX correct way to do following four is probably to get also render
1013                  * size and determine proper settings from that somehow */
1014                 case COLLADAFW::Camera::ASPECTRATIO_AND_X:
1015                 case COLLADAFW::Camera::SINGLE_X:
1016                 case COLLADAFW::Camera::X_AND_Y:
1017                 {
1018                         switch (cam->type) {
1019                                 case CAM_ORTHO:
1020                                         cam->ortho_scale = (float)camera->getXMag().getValue() * 2;
1021                                         break;
1022                                 case CAM_PERSP:
1023                                 default:
1024                                 {
1025                                         double x = camera->getXFov().getValue();
1026                                         // x is in degrees, cam->lens is in millimiters
1027                                         cam->lens = fov_to_focallength(DEG2RADF(x), cam->sensor_x);
1028                                 }
1029                                 break;
1030                         }
1031                 }
1032                 break;
1033                 case COLLADAFW::Camera::SINGLE_Y:
1034                 {
1035                         switch (cam->type) {
1036                                 case CAM_ORTHO:
1037                                         cam->ortho_scale = (float)camera->getYMag().getValue();
1038                                         break;
1039                                 case CAM_PERSP:
1040                                 default:
1041                                 {
1042                                         double yfov = camera->getYFov().getValue();
1043                                         // yfov is in degrees, cam->lens is in millimiters
1044                                         cam->lens = fov_to_focallength(DEG2RADF(yfov), cam->sensor_x);
1045                                 }
1046                                 break;
1047                         }
1048                 }
1049                 break;
1050                 case COLLADAFW::Camera::UNDEFINED:
1051                         // read nothing, use blender defaults.
1052                         break;
1053         }
1054
1055         this->uid_camera_map[camera->getUniqueId()] = cam;
1056         this->FW_object_map[camera->getUniqueId()] = camera;
1057         // XXX import camera options
1058         return true;
1059 }
1060
1061 /** When this method is called, the writer must write the image.
1062  * \return The writer should return true, if writing succeeded, false otherwise.*/
1063 bool DocumentImporter::writeImage(const COLLADAFW::Image *image)
1064 {
1065         if (mImportStage != General)
1066                 return true;
1067
1068         const std::string& imagepath = image->getImageURI().toNativePath();
1069
1070         char dir[FILE_MAX];
1071         char absolute_path[FILE_MAX];
1072         const char *workpath;
1073
1074         BLI_split_dir_part(this->import_settings->filepath, dir, sizeof(dir));
1075         BLI_join_dirfile(absolute_path, sizeof(absolute_path), dir, imagepath.c_str());
1076         if (BLI_exists(absolute_path)) {
1077                 workpath = absolute_path;
1078         }
1079         else {
1080                 // Maybe imagepath was already absolute ?
1081                 if (!BLI_exists(imagepath.c_str())) {
1082                         fprintf(stderr, "Image not found: %s.\n", imagepath.c_str() );
1083                         return true;
1084                 }
1085                 workpath = imagepath.c_str();
1086         }
1087
1088         Image *ima = BKE_image_load_exists(workpath);
1089         if (!ima) {
1090                 fprintf(stderr, "Cannot create image: %s\n", workpath);
1091                 return true;
1092         }
1093         this->uid_image_map[image->getUniqueId()] = ima;
1094
1095         return true;
1096 }
1097
1098 /** When this method is called, the writer must write the light.
1099  * \return The writer should return true, if writing succeeded, false otherwise.*/
1100 bool DocumentImporter::writeLight(const COLLADAFW::Light *light)
1101 {
1102         if (mImportStage != General)
1103                 return true;
1104
1105         Lamp *lamp = NULL;
1106         std::string la_id, la_name;
1107
1108         ExtraTags *et = getExtraTags(light->getUniqueId());
1109         /*TagsMap::iterator etit;
1110         ExtraTags *et = 0;
1111         etit = uid_tags_map.find(light->getUniqueId().toAscii());
1112         if (etit != uid_tags_map.end())
1113                 et = etit->second;*/
1114
1115         la_id = light->getOriginalId();
1116         la_name = light->getName();
1117         if (la_name.size()) lamp = (Lamp *)BKE_lamp_add(G.main, (char *)la_name.c_str());
1118         else lamp = (Lamp *)BKE_lamp_add(G.main, (char *)la_id.c_str());
1119
1120         if (!lamp) {
1121                 fprintf(stderr, "Cannot create lamp.\n");
1122                 return true;
1123         }
1124
1125         // if we find an ExtraTags for this, use that instead.
1126         if (et && et->isProfile("blender")) {
1127                 et->setData("type", &(lamp->type));
1128                 et->setData("flag", &(lamp->flag));
1129                 et->setData("mode", &(lamp->mode));
1130                 et->setData("gamma", &(lamp->k));
1131                 et->setData("red", &(lamp->r));
1132                 et->setData("green", &(lamp->g));
1133                 et->setData("blue", &(lamp->b));
1134                 et->setData("shadow_r", &(lamp->shdwr));
1135                 et->setData("shadow_g", &(lamp->shdwg));
1136                 et->setData("shadow_b", &(lamp->shdwb));
1137                 et->setData("energy", &(lamp->energy));
1138                 et->setData("dist", &(lamp->dist));
1139                 et->setData("spotsize", &(lamp->spotsize));
1140                 lamp->spotsize = DEG2RADF(lamp->spotsize);
1141                 et->setData("spotblend", &(lamp->spotblend));
1142                 et->setData("att1", &(lamp->att1));
1143                 et->setData("att2", &(lamp->att2));
1144                 et->setData("falloff_type", &(lamp->falloff_type));
1145                 et->setData("clipsta", &(lamp->clipsta));
1146                 et->setData("clipend", &(lamp->clipend));
1147                 et->setData("bias", &(lamp->bias));
1148                 et->setData("soft", &(lamp->soft));
1149                 et->setData("bufsize", &(lamp->bufsize));
1150                 et->setData("buffers", &(lamp->buffers));
1151                 et->setData("area_shape", &(lamp->area_shape));
1152                 et->setData("area_size", &(lamp->area_size));
1153                 et->setData("area_sizey", &(lamp->area_sizey));
1154                 et->setData("area_sizez", &(lamp->area_sizez));
1155         }
1156         else {
1157                 float constatt = light->getConstantAttenuation().getValue();
1158                 float linatt = light->getLinearAttenuation().getValue();
1159                 float quadatt = light->getQuadraticAttenuation().getValue();
1160                 float d = 25.0f;
1161                 float att1 = 0.0f;
1162                 float att2 = 0.0f;
1163                 float e = 1.0f;
1164
1165                 if (light->getColor().isValid()) {
1166                         COLLADAFW::Color col = light->getColor();
1167                         lamp->r = col.getRed();
1168                         lamp->g = col.getGreen();
1169                         lamp->b = col.getBlue();
1170                 }
1171
1172                 if (IS_EQ(linatt, 0.0f) && quadatt > 0.0f) {
1173                         att2 = quadatt;
1174                         d = sqrt(1.0f / quadatt);
1175                 }
1176                 // linear light
1177                 else if (IS_EQ(quadatt, 0.0f) && linatt > 0.0f) {
1178                         att1 = linatt;
1179                         d = (1.0f / linatt);
1180                 }
1181                 else if (IS_EQ(constatt, 1.0f)) {
1182                         att1 = 1.0f;
1183                 }
1184                 else {
1185                         // assuming point light (const att = 1.0);
1186                         att1 = 1.0f;
1187                 }
1188
1189                 d *= (1.0f / unit_converter.getLinearMeter());
1190
1191                 lamp->energy = e;
1192                 lamp->dist = d;
1193
1194                 COLLADAFW::Light::LightType type = light->getLightType();
1195                 switch (type) {
1196                         case COLLADAFW::Light::AMBIENT_LIGHT:
1197                         {
1198                                 lamp->type = LA_HEMI;
1199                         }
1200                         break;
1201                         case COLLADAFW::Light::SPOT_LIGHT:
1202                         {
1203                                 lamp->type = LA_SPOT;
1204                                 lamp->att1 = att1;
1205                                 lamp->att2 = att2;
1206                                 if (IS_EQ(att1, 0.0f) && att2 > 0)
1207                                         lamp->falloff_type = LA_FALLOFF_INVSQUARE;
1208                                 if (IS_EQ(att2, 0.0f) && att1 > 0)
1209                                         lamp->falloff_type = LA_FALLOFF_INVLINEAR;
1210                                 lamp->spotsize = DEG2RADF(light->getFallOffAngle().getValue());
1211                                 lamp->spotblend = light->getFallOffExponent().getValue();
1212                         }
1213                         break;
1214                         case COLLADAFW::Light::DIRECTIONAL_LIGHT:
1215                         {
1216                                 /* our sun is very strong, so pick a smaller energy level */
1217                                 lamp->type = LA_SUN;
1218                         }
1219                         break;
1220                         case COLLADAFW::Light::POINT_LIGHT:
1221                         {
1222                                 lamp->type = LA_LOCAL;
1223                                 lamp->att1 = att1;
1224                                 lamp->att2 = att2;
1225                                 if (IS_EQ(att1, 0.0f) && att2 > 0)
1226                                         lamp->falloff_type = LA_FALLOFF_INVSQUARE;
1227                                 if (IS_EQ(att2, 0.0f) && att1 > 0)
1228                                         lamp->falloff_type = LA_FALLOFF_INVLINEAR;
1229                         }
1230                         break;
1231                         case COLLADAFW::Light::UNDEFINED:
1232                         {
1233                                 fprintf(stderr, "Current lamp type is not supported.\n");
1234                                 lamp->type = LA_LOCAL;
1235                         }
1236                         break;
1237                 }
1238         }
1239
1240         this->uid_lamp_map[light->getUniqueId()] = lamp;
1241         this->FW_object_map[light->getUniqueId()] = light;
1242         return true;
1243 }
1244
1245 // this function is called only for animations that pass COLLADAFW::validate
1246 bool DocumentImporter::writeAnimation(const COLLADAFW::Animation *anim)
1247 {
1248         if (mImportStage != General)
1249                 return true;
1250
1251         // return true;
1252         return anim_importer.write_animation(anim);
1253 }
1254
1255 // called on post-process stage after writeVisualScenes
1256 bool DocumentImporter::writeAnimationList(const COLLADAFW::AnimationList *animationList)
1257 {
1258         if (mImportStage != General)
1259                 return true;
1260
1261         // return true;
1262         return anim_importer.write_animation_list(animationList);
1263 }
1264
1265 /** When this method is called, the writer must write the skin controller data.
1266  * \return The writer should return true, if writing succeeded, false otherwise.*/
1267 bool DocumentImporter::writeSkinControllerData(const COLLADAFW::SkinControllerData *skin)
1268 {
1269         return armature_importer.write_skin_controller_data(skin);
1270 }
1271
1272 // this is called on postprocess, before writeVisualScenes
1273 bool DocumentImporter::writeController(const COLLADAFW::Controller *controller)
1274 {
1275         if (mImportStage != General)
1276                 return true;
1277
1278         return armature_importer.write_controller(controller);
1279 }
1280
1281 bool DocumentImporter::writeFormulas(const COLLADAFW::Formulas *formulas)
1282 {
1283         return true;
1284 }
1285
1286 bool DocumentImporter::writeKinematicsScene(const COLLADAFW::KinematicsScene *kinematicsScene)
1287 {
1288         return true;
1289 }
1290
1291 ExtraTags *DocumentImporter::getExtraTags(const COLLADAFW::UniqueId &uid)
1292 {
1293         if (uid_tags_map.find(uid.toAscii()) == uid_tags_map.end()) {
1294                 return NULL;
1295         }
1296         return uid_tags_map[uid.toAscii()];
1297 }
1298
1299 bool DocumentImporter::addExtraTags(const COLLADAFW::UniqueId &uid, ExtraTags *extra_tags)
1300 {
1301         uid_tags_map[uid.toAscii()] = extra_tags;
1302         return true;
1303 }
1304
1305 bool DocumentImporter::is_armature(COLLADAFW::Node *node)
1306 {
1307         COLLADAFW::NodePointerArray &child_nodes = node->getChildNodes();
1308         for (unsigned int i = 0; i < child_nodes.getCount(); i++) {
1309                 if (child_nodes[i]->getType() == COLLADAFW::Node::JOINT) {
1310                         return true;
1311                 }
1312                 else {
1313                         continue;
1314                 }
1315         }
1316
1317         //no child is JOINT
1318         return false;
1319 }