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