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