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