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