77c2fc971ac26814338964da16817ee847e3aae9
[blender.git] / source / blender / collada / DocumentImporter.cpp
1 /*
2  * $Id$
3  *
4  * ***** BEGIN GPL LICENSE BLOCK *****
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software Foundation,
18  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19  *
20  * Contributor(s): Chingiz Dyussenov, Arystanbek Dyussenov, Nathan Letwory.
21  *
22  * ***** END GPL LICENSE BLOCK *****
23  */
24
25 /** \file blender/collada/DocumentImporter.cpp
26  *  \ingroup collada
27  */
28
29 // TODO:
30 // * name imported objects
31 // * import object rotation as euler
32
33 #include <string>
34 #include <map>
35 #include <algorithm> // sort()
36
37 #include "COLLADAFWRoot.h"
38 #include "COLLADAFWStableHeaders.h"
39 #include "COLLADAFWColorOrTexture.h"
40 #include "COLLADAFWIndexList.h"
41 #include "COLLADAFWMeshPrimitiveWithFaceVertexCount.h"
42 #include "COLLADAFWPolygons.h"
43 #include "COLLADAFWSampler.h"
44 #include "COLLADAFWTypes.h"
45 #include "COLLADAFWVisualScene.h"
46 #include "COLLADAFWArrayPrimitiveType.h"
47 #include "COLLADAFWLibraryNodes.h"
48 #include "COLLADAFWCamera.h"
49 #include "COLLADAFWLight.h"
50
51 #include "COLLADASaxFWLLoader.h"
52 #include "COLLADASaxFWLIExtraDataCallbackHandler.h"
53
54 #include "BLI_listbase.h"
55 #include "BLI_math.h"
56 #include "BLI_string.h"
57 #include "BLI_utildefines.h"
58
59 #include "BKE_main.h"
60 #include "BKE_library.h"
61 #include "BKE_texture.h"
62 #include "BKE_fcurve.h"
63 #include "BKE_depsgraph.h"
64 #include "BLI_path_util.h"
65 #include "BKE_scene.h"
66 #include "BKE_global.h"
67 #include "BKE_material.h"
68 #include "BKE_utildefines.h"
69 #include "BKE_image.h"
70
71 #include "DNA_camera_types.h"
72 #include "DNA_lamp_types.h"
73
74 #include "RNA_access.h"
75
76 #include "MEM_guardedalloc.h"
77
78 #include "ExtraHandler.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 bool DocumentImporter::import()
107 {
108         /** TODO Add error handler (implement COLLADASaxFWL::IErrorHandler */
109         COLLADASaxFWL::Loader loader;
110         COLLADAFW::Root root(&loader, this);
111         ExtraHandler *ehandler = new ExtraHandler(this);
112         
113         loader.registerExtraDataCallbackHandler(ehandler);
114         
115
116         if (!root.loadDocument(mFilename))
117                 return false;
118         
119         /** TODO set up scene graph and such here */
120         
121         mImportStage = Controller;
122         
123         COLLADASaxFWL::Loader loader2;
124         COLLADAFW::Root root2(&loader2, this);
125         
126         if (!root2.loadDocument(mFilename))
127                 return false;
128         
129         
130         delete ehandler;
131
132         return true;
133 }
134
135 void DocumentImporter::cancel(const COLLADAFW::String& errorMessage)
136 {
137         // TODO: if possible show error info
138         //
139         // Should we get rid of invisible Meshes that were created so far
140         // or maybe create objects at coordinate space origin?
141         //
142         // The latter sounds better.
143 }
144
145 void DocumentImporter::start(){}
146
147 void DocumentImporter::finish()
148 {
149         if(mImportStage!=General)
150                 return;
151                 
152         /** TODO Break up and put into 2-pass parsing of DAE */
153         std::vector<const COLLADAFW::VisualScene*>::iterator it;
154         for (it = vscenes.begin(); it != vscenes.end(); it++) {
155                 PointerRNA sceneptr, unit_settings;
156                 PropertyRNA *system, *scale;
157                 // TODO: create a new scene except the selected <visual_scene> - use current blender scene for it
158                 Scene *sce = CTX_data_scene(mContext);
159                 
160                 // for scene unit settings: system, scale_length
161                 RNA_id_pointer_create(&sce->id, &sceneptr);
162                 unit_settings = RNA_pointer_get(&sceneptr, "unit_settings");
163                 system = RNA_struct_find_property(&unit_settings, "system");
164                 scale = RNA_struct_find_property(&unit_settings, "scale_length");
165                 
166                 switch(unit_converter.isMetricSystem()) {
167                         case UnitConverter::Metric:
168                                 RNA_property_enum_set(&unit_settings, system, USER_UNIT_METRIC);
169                                 break;
170                         case UnitConverter::Imperial:
171                                 RNA_property_enum_set(&unit_settings, system, USER_UNIT_IMPERIAL);
172                                 break;
173                         default:
174                                 RNA_property_enum_set(&unit_settings, system, USER_UNIT_NONE);
175                                 break;
176                 }
177                 RNA_property_float_set(&unit_settings, scale, unit_converter.getLinearMeter());
178                 
179                 const COLLADAFW::NodePointerArray& roots = (*it)->getRootNodes();
180
181                 for (unsigned int i = 0; i < roots.getCount(); i++) {
182                         write_node(roots[i], NULL, sce, NULL, false);
183                 }
184         }
185
186         armature_importer.make_armatures(mContext);
187
188 #if 0
189         armature_importer.fix_animation();
190 #endif
191
192         for (std::vector<const COLLADAFW::VisualScene*>::iterator it = vscenes.begin(); it != vscenes.end(); it++) {
193                 const COLLADAFW::NodePointerArray& roots = (*it)->getRootNodes();
194
195                 for (unsigned int i = 0; i < roots.getCount(); i++)
196                         translate_anim_recursive(roots[i],NULL,NULL);
197         }
198
199         if (libnode_ob.size()) {
200                 Scene *sce = CTX_data_scene(mContext);
201
202                 fprintf(stderr, "got %d library nodes to free\n", (int)libnode_ob.size());
203                 // free all library_nodes
204                 std::vector<Object*>::iterator it;
205                 for (it = libnode_ob.begin(); it != libnode_ob.end(); it++) {
206                         Object *ob = *it;
207
208                         Base *base = object_in_scene(ob, sce);
209                         if (base) {
210                                 BLI_remlink(&sce->base, base);
211                                 free_libblock_us(&G.main->object, base->object);
212                                 if (sce->basact==base)
213                                         sce->basact= NULL;
214                                 MEM_freeN(base);
215                         }
216                 }
217                 libnode_ob.clear();
218
219                 DAG_scene_sort(CTX_data_main(mContext), sce);
220                 DAG_ids_flush_update(CTX_data_main(mContext), 0);
221         }
222 }
223
224
225 void DocumentImporter::translate_anim_recursive(COLLADAFW::Node *node, COLLADAFW::Node *par = NULL, Object *parob = NULL)
226 {
227         if (par && par->getType() == COLLADAFW::Node::JOINT) {
228                 // par is root if there's no corresp. key in root_map
229                 if (root_map.find(par->getUniqueId()) == root_map.end())
230                         root_map[node->getUniqueId()] = par;
231                 else
232                         root_map[node->getUniqueId()] = root_map[par->getUniqueId()];
233         }
234
235         COLLADAFW::Transformation::TransformationType types[] = {
236                 COLLADAFW::Transformation::ROTATE,
237                 COLLADAFW::Transformation::SCALE,
238                 COLLADAFW::Transformation::TRANSLATE,
239                 COLLADAFW::Transformation::MATRIX
240         };
241
242         unsigned int i;
243         Object *ob;
244
245         for (i = 0; i < 4; i++)
246                 ob = anim_importer.translate_animation(node, object_map, root_map, types[i]);
247
248         COLLADAFW::NodePointerArray &children = node->getChildNodes();
249         for (i = 0; i < children.getCount(); i++) {
250                 translate_anim_recursive(children[i], node, ob);
251         }
252 }
253
254 /** When this method is called, the writer must write the global document asset.
255         @return The writer should return true, if writing succeeded, false otherwise.*/
256 bool DocumentImporter::writeGlobalAsset ( const COLLADAFW::FileInfo* asset ) 
257 {
258         unit_converter.read_asset(asset);
259
260         return true;
261 }
262
263 /** When this method is called, the writer must write the scene.
264         @return The writer should return true, if writing succeeded, false otherwise.*/
265 bool DocumentImporter::writeScene ( const COLLADAFW::Scene* scene ) 
266 {
267         // XXX could store the scene id, but do nothing for now
268         return true;
269 }
270 Object* DocumentImporter::create_camera_object(COLLADAFW::InstanceCamera *camera, Scene *sce)
271 {
272         const COLLADAFW::UniqueId& cam_uid = camera->getInstanciatedObjectId();
273         if (uid_camera_map.find(cam_uid) == uid_camera_map.end()) {     
274                 fprintf(stderr, "Couldn't find camera by UID.\n");
275                 return NULL;
276         }
277         Object *ob = add_object(sce, OB_CAMERA);
278         Camera *cam = uid_camera_map[cam_uid];
279         Camera *old_cam = (Camera*)ob->data;
280         ob->data = cam;
281         old_cam->id.us--;
282         if (old_cam->id.us == 0)
283                 free_libblock(&G.main->camera, old_cam);
284         return ob;
285 }
286
287 Object* DocumentImporter::create_lamp_object(COLLADAFW::InstanceLight *lamp, Scene *sce)
288 {
289         const COLLADAFW::UniqueId& lamp_uid = lamp->getInstanciatedObjectId();
290         if (uid_lamp_map.find(lamp_uid) == uid_lamp_map.end()) {        
291                 fprintf(stderr, "Couldn't find lamp by UID. \n");
292                 return NULL;
293         }
294         Object *ob = add_object(sce, OB_LAMP);
295         Lamp *la = uid_lamp_map[lamp_uid];
296         Lamp *old_lamp = (Lamp*)ob->data;
297         ob->data = la;
298         old_lamp->id.us--;
299         if (old_lamp->id.us == 0)
300                 free_libblock(&G.main->lamp, old_lamp);
301         return ob;
302 }
303
304 Object* DocumentImporter::create_instance_node(Object *source_ob, COLLADAFW::Node *source_node, COLLADAFW::Node *instance_node, Scene *sce, bool is_library_node)
305 {
306         Object *obn = copy_object(source_ob);
307         obn->recalc |= OB_RECALC_OB|OB_RECALC_DATA|OB_RECALC_TIME;
308         scene_add_base(sce, obn);
309
310         if (instance_node) {
311                 anim_importer.read_node_transform(instance_node, obn);
312                 // if we also have a source_node (always ;), take its
313                 // transformation matrix and apply it to the newly instantiated
314                 // object to account for node hierarchy transforms in
315                 // .dae
316                 if(source_node) {
317                         COLLADABU::Math::Matrix4 mat4 = source_node->getTransformationMatrix();
318                         COLLADABU::Math::Matrix4 bmat4 = mat4.transpose(); // transpose to get blender row-major order
319                         float mat[4][4];
320                         for (int i = 0; i < 4; i++) {
321                                 for (int j = 0; j < 4; j++) {
322                                         mat[i][j] = bmat4[i][j];
323                                 }
324                         }
325                         // calc new matrix and apply
326                         mul_m4_m4m4(obn->obmat, mat, obn->obmat);
327                         object_apply_mat4(obn, obn->obmat, 0, 0);
328                 }
329         }
330         else {
331                 anim_importer.read_node_transform(source_node, obn);
332         }
333
334         DAG_scene_sort(CTX_data_main(mContext), sce);
335         DAG_ids_flush_update(CTX_data_main(mContext), 0);
336
337         COLLADAFW::NodePointerArray &children = source_node->getChildNodes();
338         if (children.getCount()) {
339                 for (unsigned int i = 0; i < children.getCount(); i++) {
340                         COLLADAFW::Node *child_node = children[i];
341                         const COLLADAFW::UniqueId& child_id = child_node->getUniqueId();
342                         if (object_map.find(child_id) == object_map.end())
343                                 continue;
344                         COLLADAFW::InstanceNodePointerArray &inodes = child_node->getInstanceNodes();
345                         Object *new_child = NULL;
346                         if (inodes.getCount()) { // \todo loop through instance nodes
347                                 const COLLADAFW::UniqueId& id = inodes[0]->getInstanciatedObjectId();
348                                 new_child = create_instance_node(object_map[id], node_map[id], child_node, sce, is_library_node);
349                         }
350                         else {
351                                 new_child = create_instance_node(object_map[child_id], child_node, NULL, sce, is_library_node);
352                         }
353                         bc_set_parent(new_child, obn, mContext, true);
354
355                         if (is_library_node)
356                                 libnode_ob.push_back(new_child);
357                 }
358         }
359
360         // when we have an instance_node, don't return the object, because otherwise
361         // its correct location gets overwritten in write_node(). Fixes bug #26012.
362         if(instance_node) return NULL;
363         else return obn;
364 }
365
366 void DocumentImporter::write_node (COLLADAFW::Node *node, COLLADAFW::Node *parent_node, Scene *sce, Object *par, bool is_library_node)
367 {
368         Object *ob = NULL;
369         bool is_joint = node->getType() == COLLADAFW::Node::JOINT;
370
371         if (is_joint) {
372                 armature_importer.add_joint(node, parent_node == NULL || parent_node->getType() != COLLADAFW::Node::JOINT, par);
373         }
374         else {
375                 COLLADAFW::InstanceGeometryPointerArray &geom = node->getInstanceGeometries();
376                 COLLADAFW::InstanceCameraPointerArray &camera = node->getInstanceCameras();
377                 COLLADAFW::InstanceLightPointerArray &lamp = node->getInstanceLights();
378                 COLLADAFW::InstanceControllerPointerArray &controller = node->getInstanceControllers();
379                 COLLADAFW::InstanceNodePointerArray &inst_node = node->getInstanceNodes();
380                 int geom_done = 0;
381                 int camera_done = 0;
382                 int lamp_done = 0;
383                 int controller_done = 0;
384                 int inst_done = 0;
385
386                 // XXX linking object with the first <instance_geometry>, though a node may have more of them...
387                 // maybe join multiple <instance_...> meshes into 1, and link object with it? not sure...
388                 // <instance_geometry>
389                 while (geom_done < geom.getCount()) {
390                         ob = mesh_importer.create_mesh_object(node, geom[geom_done], false, uid_material_map,
391                                                                                                   material_texture_mapping_map);
392                         ++geom_done;
393                 }
394                 while (camera_done < camera.getCount()) {
395                         ob = create_camera_object(camera[camera_done], sce);
396                         ++camera_done;
397                 }
398                 while (lamp_done < lamp.getCount()) {
399                         ob = create_lamp_object(lamp[lamp_done], sce);
400                         ++lamp_done;
401                 }
402                 while (controller_done < controller.getCount()) {
403                         COLLADAFW::InstanceGeometry *geom = (COLLADAFW::InstanceGeometry*)controller[controller_done];
404                         ob = mesh_importer.create_mesh_object(node, geom, true, uid_material_map, material_texture_mapping_map);
405                         ++controller_done;
406                 }
407                 // XXX instance_node is not supported yet
408                 while (inst_done < inst_node.getCount()) {
409                         const COLLADAFW::UniqueId& node_id = inst_node[inst_done]->getInstanciatedObjectId();
410                         if (object_map.find(node_id) == object_map.end()) {
411                                 fprintf(stderr, "Cannot find node to instanciate.\n");
412                                 ob = NULL;
413                         }
414                         else {
415                                 Object *source_ob = object_map[node_id];
416                                 COLLADAFW::Node *source_node = node_map[node_id];
417
418                                 ob = create_instance_node(source_ob, source_node, node, sce, is_library_node);
419                         }
420                         ++inst_done;
421                 }
422                 // if node is empty - create empty object
423                 // XXX empty node may not mean it is empty object, not sure about this
424                 if ( (geom_done + camera_done + lamp_done + controller_done + inst_done) < 1) {
425                         ob = add_object(sce, OB_EMPTY);
426                 }
427                 
428                 // check if object is not NULL
429                 if (!ob) return;
430                 
431                 rename_id(&ob->id, (char*)node->getOriginalId().c_str());
432
433                 object_map[node->getUniqueId()] = ob;
434                 node_map[node->getUniqueId()] = node;
435
436                 if (is_library_node)
437                         libnode_ob.push_back(ob);
438         }
439
440         anim_importer.read_node_transform(node, ob); // overwrites location set earlier
441
442         if (!is_joint) {
443                 // if par was given make this object child of the previous 
444                 if (par && ob)
445                         bc_set_parent(ob, par, mContext);
446         }
447
448         // if node has child nodes write them
449         COLLADAFW::NodePointerArray &child_nodes = node->getChildNodes();
450         for (unsigned int i = 0; i < child_nodes.getCount(); i++) {     
451                 write_node(child_nodes[i], node, sce, ob, is_library_node);
452         }
453 }
454
455 /** When this method is called, the writer must write the entire visual scene.
456         @return The writer should return true, if writing succeeded, false otherwise.*/
457 bool DocumentImporter::writeVisualScene ( const COLLADAFW::VisualScene* visualScene ) 
458 {
459         if(mImportStage!=General)
460                 return true;
461                 
462         // this method called on post process after writeGeometry, writeMaterial, etc.
463
464         // for each <node> in <visual_scene>:
465         // create an Object
466         // if Mesh (previously created in writeGeometry) to which <node> corresponds exists, link Object with that mesh
467
468         // update: since we cannot link a Mesh with Object in
469         // writeGeometry because <geometry> does not reference <node>,
470         // we link Objects with Meshes here
471
472         vscenes.push_back(visualScene);
473         
474         return true;
475 }
476
477 /** When this method is called, the writer must handle all nodes contained in the 
478         library nodes.
479         @return The writer should return true, if writing succeeded, false otherwise.*/
480 bool DocumentImporter::writeLibraryNodes ( const COLLADAFW::LibraryNodes* libraryNodes ) 
481 {
482         if(mImportStage!=General)
483                 return true;
484                 
485         Scene *sce = CTX_data_scene(mContext);
486
487         const COLLADAFW::NodePointerArray& nodes = libraryNodes->getNodes();
488
489         for (unsigned int i = 0; i < nodes.getCount(); i++) {
490                 write_node(nodes[i], NULL, sce, NULL, true);
491         }
492
493         return true;
494 }
495
496 /** When this method is called, the writer must write the geometry.
497         @return The writer should return true, if writing succeeded, false otherwise.*/
498 bool DocumentImporter::writeGeometry ( const COLLADAFW::Geometry* geom ) 
499 {
500         if(mImportStage!=General)
501                 return true;
502                 
503         return mesh_importer.write_geometry(geom);
504 }
505
506 /** When this method is called, the writer must write the material.
507         @return The writer should return true, if writing succeeded, false otherwise.*/
508 bool DocumentImporter::writeMaterial( const COLLADAFW::Material* cmat ) 
509 {
510         if(mImportStage!=General)
511                 return true;
512                 
513         const std::string& str_mat_id = cmat->getOriginalId();
514         Material *ma = add_material((char*)str_mat_id.c_str());
515         
516         this->uid_effect_map[cmat->getInstantiatedEffect()] = ma;
517         this->uid_material_map[cmat->getUniqueId()] = ma;
518         
519         return true;
520 }
521
522 // create mtex, create texture, set texture image
523 MTex* DocumentImporter::create_texture(COLLADAFW::EffectCommon *ef, COLLADAFW::Texture &ctex, Material *ma,
524                                          int i, TexIndexTextureArrayMap &texindex_texarray_map)
525 {
526         COLLADAFW::SamplerPointerArray& samp_array = ef->getSamplerPointerArray();
527         COLLADAFW::Sampler *sampler = samp_array[ctex.getSamplerId()];
528                 
529         const COLLADAFW::UniqueId& ima_uid = sampler->getSourceImage();
530         
531         if (uid_image_map.find(ima_uid) == uid_image_map.end()) {
532                 fprintf(stderr, "Couldn't find an image by UID.\n");
533                 return NULL;
534         }
535         
536         ma->mtex[i] = add_mtex();
537         ma->mtex[i]->texco = TEXCO_UV;
538         ma->mtex[i]->tex = add_texture("Texture");
539         ma->mtex[i]->tex->type = TEX_IMAGE;
540         ma->mtex[i]->tex->imaflag &= ~TEX_USEALPHA;
541         ma->mtex[i]->tex->ima = uid_image_map[ima_uid];
542         
543         texindex_texarray_map[ctex.getTextureMapId()].push_back(ma->mtex[i]);
544         
545         return ma->mtex[i];
546 }
547
548 void DocumentImporter::write_profile_COMMON(COLLADAFW::EffectCommon *ef, Material *ma)
549 {
550         COLLADAFW::EffectCommon::ShaderType shader = ef->getShaderType();
551         
552         // blinn
553         if (shader == COLLADAFW::EffectCommon::SHADER_BLINN) {
554                 ma->spec_shader = MA_SPEC_BLINN;
555                 ma->spec = ef->getShininess().getFloatValue();
556         }
557         // phong
558         else if (shader == COLLADAFW::EffectCommon::SHADER_PHONG) {
559                 ma->spec_shader = MA_SPEC_PHONG;
560                 ma->har = ef->getShininess().getFloatValue();
561         }
562         // lambert
563         else if (shader == COLLADAFW::EffectCommon::SHADER_LAMBERT) {
564                 ma->diff_shader = MA_DIFF_LAMBERT;
565         }
566         // default - lambert
567         else {
568                 ma->diff_shader = MA_DIFF_LAMBERT;
569                 fprintf(stderr, "Current shader type is not supported, default to lambert.\n");
570         }
571         // reflectivity
572         ma->ray_mirror = ef->getReflectivity().getFloatValue();
573         // index of refraction
574         ma->ang = ef->getIndexOfRefraction().getFloatValue();
575         
576         int i = 0;
577         COLLADAFW::Color col;
578         MTex *mtex = NULL;
579         TexIndexTextureArrayMap texindex_texarray_map;
580         
581         // DIFFUSE
582         // color
583         if (ef->getDiffuse().isColor()) {
584                 col = ef->getDiffuse().getColor();
585                 ma->r = col.getRed();
586                 ma->g = col.getGreen();
587                 ma->b = col.getBlue();
588         }
589         // texture
590         else if (ef->getDiffuse().isTexture()) {
591                 COLLADAFW::Texture ctex = ef->getDiffuse().getTexture(); 
592                 mtex = create_texture(ef, ctex, ma, i, texindex_texarray_map);
593                 if (mtex != NULL) {
594                         mtex->mapto = MAP_COL;
595                         ma->texact = (int)i;
596                         i++;
597                 }
598         }
599         // AMBIENT
600         // color
601         if (ef->getAmbient().isColor()) {
602                 col = ef->getAmbient().getColor();
603                 ma->ambr = col.getRed();
604                 ma->ambg = col.getGreen();
605                 ma->ambb = col.getBlue();
606         }
607         // texture
608         else if (ef->getAmbient().isTexture()) {
609                 COLLADAFW::Texture ctex = ef->getAmbient().getTexture(); 
610                 mtex = create_texture(ef, ctex, ma, i, texindex_texarray_map);
611                 if (mtex != NULL) {
612                         mtex->mapto = MAP_AMB; 
613                         i++;
614                 }
615         }
616         // SPECULAR
617         // color
618         if (ef->getSpecular().isColor()) {
619                 col = ef->getSpecular().getColor();
620                 ma->specr = col.getRed();
621                 ma->specg = col.getGreen();
622                 ma->specb = col.getBlue();
623         }
624         // texture
625         else if (ef->getSpecular().isTexture()) {
626                 COLLADAFW::Texture ctex = ef->getSpecular().getTexture(); 
627                 mtex = create_texture(ef, ctex, ma, i, texindex_texarray_map);
628                 if (mtex != NULL) {
629                         mtex->mapto = MAP_SPEC; 
630                         i++;
631                 }
632         }
633         // REFLECTIVE
634         // color
635         if (ef->getReflective().isColor()) {
636                 col = ef->getReflective().getColor();
637                 ma->mirr = col.getRed();
638                 ma->mirg = col.getGreen();
639                 ma->mirb = col.getBlue();
640         }
641         // texture
642         else if (ef->getReflective().isTexture()) {
643                 COLLADAFW::Texture ctex = ef->getReflective().getTexture(); 
644                 mtex = create_texture(ef, ctex, ma, i, texindex_texarray_map);
645                 if (mtex != NULL) {
646                         mtex->mapto = MAP_REF; 
647                         i++;
648                 }
649         }
650         // EMISSION
651         // color
652         if (ef->getEmission().isColor()) {
653                 // XXX there is no emission color in blender
654                 // but I am not sure
655         }
656         // texture
657         else if (ef->getEmission().isTexture()) {
658                 COLLADAFW::Texture ctex = ef->getEmission().getTexture(); 
659                 mtex = create_texture(ef, ctex, ma, i, texindex_texarray_map);
660                 if (mtex != NULL) {
661                         mtex->mapto = MAP_EMIT; 
662                         i++;
663                 }
664         }
665         // TRANSPARENT
666         // color
667 //      if (ef->getOpacity().isColor()) {
668 //                      // XXX don't know what to do here
669 //              }
670 //              // texture
671 //              else if (ef->getOpacity().isTexture()) {
672 //                      ctex = ef->getOpacity().getTexture();
673 //                      if (mtex != NULL) mtex->mapto &= MAP_ALPHA;
674 //                      else {
675 //                              mtex = create_texture(ef, ctex, ma, i, texindex_texarray_map);
676 //                              if (mtex != NULL) mtex->mapto = MAP_ALPHA;
677 //                      }
678 //              }
679         material_texture_mapping_map[ma] = texindex_texarray_map;
680 }
681
682 /** When this method is called, the writer must write the effect.
683         @return The writer should return true, if writing succeeded, false otherwise.*/
684
685 bool DocumentImporter::writeEffect( const COLLADAFW::Effect* effect ) 
686 {
687         if(mImportStage!=General)
688                 return true;
689         
690         const COLLADAFW::UniqueId& uid = effect->getUniqueId();
691         if (uid_effect_map.find(uid) == uid_effect_map.end()) {
692                 fprintf(stderr, "Couldn't find a material by UID.\n");
693                 return true;
694         }
695         
696         Material *ma = uid_effect_map[uid];
697         
698         COLLADAFW::CommonEffectPointerArray common_efs = effect->getCommonEffects();
699         if (common_efs.getCount() < 1) {
700                 fprintf(stderr, "Couldn't find <profile_COMMON>.\n");
701                 return true;
702         }
703         // XXX TODO: Take all <profile_common>s
704         // Currently only first <profile_common> is supported
705         COLLADAFW::EffectCommon *ef = common_efs[0];
706         write_profile_COMMON(ef, ma);
707         
708         return true;
709 }
710
711
712 /** When this method is called, the writer must write the camera.
713         @return The writer should return true, if writing succeeded, false otherwise.*/
714 bool DocumentImporter::writeCamera( const COLLADAFW::Camera* camera ) 
715 {
716         if(mImportStage!=General)
717                 return true;
718                 
719         Camera *cam = NULL;
720         std::string cam_id, cam_name;
721         
722         cam_id = camera->getOriginalId();
723         cam_name = camera->getName();
724         if (cam_name.size()) cam = (Camera*)add_camera((char*)cam_name.c_str());
725         else cam = (Camera*)add_camera((char*)cam_id.c_str());
726         
727         if (!cam) {
728                 fprintf(stderr, "Cannot create camera. \n");
729                 return true;
730         }
731         cam->clipsta = camera->getNearClippingPlane().getValue();
732         cam->clipend = camera->getFarClippingPlane().getValue();
733         
734         COLLADAFW::Camera::CameraType type = camera->getCameraType();
735         switch(type) {
736         case COLLADAFW::Camera::ORTHOGRAPHIC:
737                 {
738                         cam->type = CAM_ORTHO;
739                 }
740                 break;
741         case COLLADAFW::Camera::PERSPECTIVE:
742                 {
743                         cam->type = CAM_PERSP;
744                 }
745                 break;
746         case COLLADAFW::Camera::UNDEFINED_CAMERATYPE:
747                 {
748                         fprintf(stderr, "Current camera type is not supported. \n");
749                         cam->type = CAM_PERSP;
750                 }
751                 break;
752         }
753         
754         switch(camera->getDescriptionType()) {
755         case COLLADAFW::Camera::ASPECTRATIO_AND_Y:
756                 {
757                         switch(cam->type) {
758                                 case CAM_ORTHO:
759                                         {
760                                                 double ymag = camera->getYMag().getValue();
761                                                 double aspect = camera->getAspectRatio().getValue();
762                                                 double xmag = aspect*ymag;
763                                                 cam->ortho_scale = (float)xmag;
764                                         }
765                                         break;
766                                 case CAM_PERSP:
767                                 default:
768                                         {
769                                                 double yfov = camera->getYFov().getValue();
770                                                 double aspect = camera->getAspectRatio().getValue();
771                                                 double xfov = aspect*yfov;
772                                                 // xfov is in degrees, cam->lens is in millimiters
773                                                 cam->lens = angle_to_lens((float)xfov*(M_PI/180.0f));
774                                         }
775                                         break;
776                         }
777                 }
778                 break;
779         /* XXX correct way to do following four is probably to get also render
780            size and determine proper settings from that somehow */
781         case COLLADAFW::Camera::ASPECTRATIO_AND_X:
782         case COLLADAFW::Camera::SINGLE_X:
783         case COLLADAFW::Camera::X_AND_Y:
784                 {
785                         switch(cam->type) {
786                                 case CAM_ORTHO:
787                                         cam->ortho_scale = (float)camera->getXMag().getValue();
788                                         break;
789                                 case CAM_PERSP:
790                                 default:
791                                         {
792                                                 double x = camera->getXFov().getValue();
793                                                 // x is in degrees, cam->lens is in millimiters
794                                                 cam->lens = angle_to_lens((float)x*(M_PI/180.0f));
795                                         }
796                                         break;
797                         }
798                 }
799                 break;
800         case COLLADAFW::Camera::SINGLE_Y:
801                 {
802                         switch(cam->type) {
803                                 case CAM_ORTHO:
804                                         cam->ortho_scale = (float)camera->getYMag().getValue();
805                                         break;
806                                 case CAM_PERSP:
807                                 default:
808                                         {
809                                         double yfov = camera->getYFov().getValue();
810                                         // yfov is in degrees, cam->lens is in millimiters
811                                         cam->lens = angle_to_lens((float)yfov*(M_PI/180.0f));
812                                         }
813                                         break;
814                         }
815                 }
816                 break;
817         case COLLADAFW::Camera::UNDEFINED:
818                 // read nothing, use blender defaults.
819                 break;
820         }
821         
822         this->uid_camera_map[camera->getUniqueId()] = cam;
823         // XXX import camera options
824         return true;
825 }
826
827 /** When this method is called, the writer must write the image.
828         @return The writer should return true, if writing succeeded, false otherwise.*/
829 bool DocumentImporter::writeImage( const COLLADAFW::Image* image ) 
830 {
831         if(mImportStage!=General)
832                 return true;
833                 
834         // XXX maybe it is necessary to check if the path is absolute or relative
835         const std::string& filepath = image->getImageURI().toNativePath();
836         const char *filename = (const char*)mFilename.c_str();
837         char dir[FILE_MAX];
838         char full_path[FILE_MAX];
839         
840         BLI_split_dirfile(filename, dir, NULL);
841         BLI_join_dirfile(full_path, sizeof(full_path), dir, filepath.c_str());
842         Image *ima = BKE_add_image_file(full_path);
843         if (!ima) {
844                 fprintf(stderr, "Cannot create image. \n");
845                 return true;
846         }
847         this->uid_image_map[image->getUniqueId()] = ima;
848         
849         return true;
850 }
851
852 /** When this method is called, the writer must write the light.
853         @return The writer should return true, if writing succeeded, false otherwise.*/
854 bool DocumentImporter::writeLight( const COLLADAFW::Light* light ) 
855 {
856         if(mImportStage!=General)
857                 return true;
858                 
859         Lamp *lamp = NULL;
860         std::string la_id, la_name;
861         
862         la_id = light->getOriginalId();
863         la_name = light->getName();
864         if (la_name.size()) lamp = (Lamp*)add_lamp((char*)la_name.c_str());
865         else lamp = (Lamp*)add_lamp((char*)la_id.c_str());
866         
867         if (!lamp) {
868                 fprintf(stderr, "Cannot create lamp. \n");
869                 return true;
870         }
871         if (light->getColor().isValid()) {
872                 COLLADAFW::Color col = light->getColor();
873                 lamp->r = col.getRed();
874                 lamp->g = col.getGreen();
875                 lamp->b = col.getBlue();
876         }
877         float constatt = light->getConstantAttenuation().getValue();
878         float linatt = light->getLinearAttenuation().getValue();
879         float quadatt = light->getQuadraticAttenuation().getValue();
880         float d = 25.0f;
881         float att1 = 0.0f;
882         float att2 = 0.0f;
883         
884         float e = 1.0f/constatt;
885         
886         /* NOTE: We assume for now that inv square is used for quadratic light
887          * and inv linear for linear light. Exported blender lin/quad weighted
888          * most likely will result in wrong import. */
889         /* quadratic light */
890         if(IS_EQ(linatt, 0.0f) && quadatt > 0.0f) {
891                 //quadatt = att2/(d*d*(e*2));
892                 float invquadatt = 1.0f/quadatt;
893                 float d2 = invquadatt / (2 * e);
894                 d = sqrtf(d2);
895         }
896         // linear light
897         else if(IS_EQ(quadatt, 0.0f) && linatt > 0.0f) {
898                 //linatt = att1/(d*e);
899                 float invlinatt = 1.0f/linatt;
900                 d = invlinatt / e;
901         } else {
902                 printf("no linear nor quad light, using defaults for attenuation, import will be incorrect: Lamp %s\n", lamp->id.name);
903                 att2 = 1.0f;
904         }
905         
906         lamp->dist = d;
907         lamp->energy = e;
908         
909         COLLADAFW::Light::LightType type = light->getLightType();
910         switch(type) {
911         case COLLADAFW::Light::AMBIENT_LIGHT:
912                 {
913                         lamp->type = LA_HEMI;
914                 }
915                 break;
916         case COLLADAFW::Light::SPOT_LIGHT:
917                 {
918                         lamp->type = LA_SPOT;
919                         lamp->falloff_type = LA_FALLOFF_INVSQUARE;
920                         lamp->att1 = att1;
921                         lamp->att2 = att2;
922                         lamp->spotsize = light->getFallOffAngle().getValue();
923                         lamp->spotblend = light->getFallOffExponent().getValue();
924                 }
925                 break;
926         case COLLADAFW::Light::DIRECTIONAL_LIGHT:
927                 {
928                         /* our sun is very strong, so pick a smaller energy level */
929                         lamp->type = LA_SUN;
930                         lamp->energy = 1.0;
931                         lamp->mode |= LA_NO_SPEC;
932                 }
933                 break;
934         case COLLADAFW::Light::POINT_LIGHT:
935                 {
936                         lamp->type = LA_LOCAL;
937                         lamp->falloff_type = LA_FALLOFF_INVSQUARE;
938                         lamp->att1 = att1;
939                         lamp->att2 = att2;
940                 }
941                 break;
942         case COLLADAFW::Light::UNDEFINED:
943                 {
944                         fprintf(stderr, "Current lamp type is not supported. \n");
945                         lamp->type = LA_LOCAL;
946                 }
947                 break;
948         }
949                 
950         this->uid_lamp_map[light->getUniqueId()] = lamp;
951         return true;
952 }
953
954 // this function is called only for animations that pass COLLADAFW::validate
955 bool DocumentImporter::writeAnimation( const COLLADAFW::Animation* anim ) 
956 {
957         if(mImportStage!=General)
958                 return true;
959                 
960         // return true;
961         return anim_importer.write_animation(anim);
962 }
963
964 // called on post-process stage after writeVisualScenes
965 bool DocumentImporter::writeAnimationList( const COLLADAFW::AnimationList* animationList ) 
966 {
967         if(mImportStage!=General)
968                 return true;
969                 
970         // return true;
971         return anim_importer.write_animation_list(animationList);
972 }
973
974 /** When this method is called, the writer must write the skin controller data.
975         @return The writer should return true, if writing succeeded, false otherwise.*/
976 bool DocumentImporter::writeSkinControllerData( const COLLADAFW::SkinControllerData* skin ) 
977 {
978         return armature_importer.write_skin_controller_data(skin);
979 }
980
981 // this is called on postprocess, before writeVisualScenes
982 bool DocumentImporter::writeController( const COLLADAFW::Controller* controller ) 
983 {
984         if(mImportStage!=General)
985                 return true;
986                 
987         return armature_importer.write_controller(controller);
988 }
989
990 bool DocumentImporter::writeFormulas( const COLLADAFW::Formulas* formulas )
991 {
992         return true;
993 }
994
995 bool DocumentImporter::writeKinematicsScene( const COLLADAFW::KinematicsScene* kinematicsScene )
996 {
997         return true;
998 }
999
1000 bool DocumentImporter::addElementData( const COLLADAFW::UniqueId &uid)
1001 {
1002         return true;
1003 }
1004