Merging from trunk up to r38119.
[blender-staging.git] / source / blender / collada / DocumentExporter.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, Jan Diederich, Tod Liverseed.
21  *
22  * ***** END GPL LICENSE BLOCK *****
23  */
24
25 /** \file blender/collada/DocumentExporter.cpp
26  *  \ingroup collada
27  */
28
29 #include <stdlib.h>
30 #include <stdio.h>
31 #include <math.h>
32
33 extern "C" 
34 {
35 #include "DNA_scene_types.h"
36 #include "DNA_object_types.h"
37 #include "DNA_meshdata_types.h"
38 #include "DNA_mesh_types.h"
39 #include "DNA_image_types.h"
40 #include "DNA_material_types.h"
41 #include "DNA_texture_types.h"
42 #include "DNA_anim_types.h"
43 #include "DNA_action_types.h"
44 #include "DNA_curve_types.h"
45 #include "DNA_armature_types.h"
46 #include "DNA_modifier_types.h"
47 #include "DNA_userdef_types.h"
48
49 #include "BKE_DerivedMesh.h"
50 #include "BKE_fcurve.h"
51 #include "BKE_animsys.h"
52 #include "BLI_path_util.h"
53 #include "BLI_fileops.h"
54 #include "ED_keyframing.h"
55 #ifdef NAN_BUILDINFO
56 extern char build_rev[];
57 #endif
58 }
59
60 #include "MEM_guardedalloc.h"
61
62 #include "BKE_blender.h" // version info
63 #include "BKE_scene.h"
64 #include "BKE_global.h"
65 #include "BKE_main.h"
66 #include "BKE_material.h"
67 #include "BKE_action.h" // pose functions
68 #include "BKE_armature.h"
69 #include "BKE_image.h"
70 #include "BKE_utildefines.h"
71 #include "BKE_object.h"
72
73 #include "BLI_math.h"
74 #include "BLI_string.h"
75 #include "BLI_listbase.h"
76
77 #include "RNA_access.h"
78
79 #include "COLLADASWAsset.h"
80 #include "COLLADASWLibraryVisualScenes.h"
81 #include "COLLADASWNode.h"
82 #include "COLLADASWSource.h"
83 #include "COLLADASWInstanceGeometry.h"
84 #include "COLLADASWInputList.h"
85 #include "COLLADASWPrimitves.h"
86 #include "COLLADASWVertices.h"
87 #include "COLLADASWLibraryAnimations.h"
88 #include "COLLADASWLibraryImages.h"
89 #include "COLLADASWLibraryEffects.h"
90 #include "COLLADASWImage.h"
91 #include "COLLADASWEffectProfile.h"
92 #include "COLLADASWColorOrTexture.h"
93 #include "COLLADASWParamTemplate.h"
94 #include "COLLADASWParamBase.h"
95 #include "COLLADASWSurfaceInitOption.h"
96 #include "COLLADASWSampler.h"
97 #include "COLLADASWScene.h"
98 #include "COLLADASWTechnique.h"
99 #include "COLLADASWTexture.h"
100 #include "COLLADASWLibraryMaterials.h"
101 #include "COLLADASWBindMaterial.h"
102 #include "COLLADASWInstanceCamera.h"
103 #include "COLLADASWInstanceLight.h"
104 #include "COLLADASWConstants.h"
105 #include "COLLADASWLibraryControllers.h"
106 #include "COLLADASWInstanceController.h"
107 #include "COLLADASWBaseInputElement.h"
108
109 #include "collada_internal.h"
110 #include "DocumentExporter.h"
111
112 // can probably go after refactor is complete
113 #include "InstanceWriter.h"
114 #include "TransformWriter.h"
115
116 #include "ArmatureExporter.h"
117 #include "AnimationExporter.h"
118 #include "CameraExporter.h"
119 #include "EffectExporter.h"
120 #include "GeometryExporter.h"
121 #include "ImageExporter.h"
122 #include "LightExporter.h"
123 #include "MaterialExporter.h"
124
125 #include <vector>
126 #include <algorithm> // std::find
127
128 char *bc_CustomData_get_layer_name(const struct CustomData *data, int type, int n)
129 {
130         int layer_index = CustomData_get_layer_index(data, type);
131         if(layer_index < 0) return NULL;
132
133         return data->layers[layer_index+n].name;
134 }
135
136 char *bc_CustomData_get_active_layer_name(const CustomData *data, int type)
137 {
138         /* get the layer index of the active layer of type */
139         int layer_index = CustomData_get_active_layer_index(data, type);
140         if(layer_index < 0) return NULL;
141
142         return data->layers[layer_index].name;
143 }
144
145
146 /*
147   Utilities to avoid code duplication.
148   Definition can take some time to understand, but they should be useful.
149 */
150
151
152 template<class Functor>
153 void forEachObjectInScene(Scene *sce, Functor &f)
154 {
155         Base *base= (Base*) sce->base.first;
156         while(base) {
157                 Object *ob = base->object;
158                         
159                 f(ob);
160
161                 base= base->next;
162         }
163 }
164
165
166
167 class SceneExporter: COLLADASW::LibraryVisualScenes, protected TransformWriter, protected InstanceWriter
168 {
169         ArmatureExporter *arm_exporter;
170 public:
171         SceneExporter(COLLADASW::StreamWriter *sw, ArmatureExporter *arm) : COLLADASW::LibraryVisualScenes(sw),
172                                                                                                                                                 arm_exporter(arm) {}
173         
174         void exportScene(Scene *sce, bool export_selected) {
175                 // <library_visual_scenes> <visual_scene>
176                 std::string id_naming = id_name(sce);
177                 openVisualScene(translate_id(id_naming), id_naming);
178
179                 // write <node>s
180                 //forEachMeshObjectInScene(sce, *this);
181                 //forEachCameraObjectInScene(sce, *this);
182                 //forEachLampObjectInScene(sce, *this);
183                 exportHierarchy(sce, export_selected);
184
185                 // </visual_scene> </library_visual_scenes>
186                 closeVisualScene();
187
188                 closeLibrary();
189         }
190
191         void exportHierarchy(Scene *sce, bool export_selected)
192         {
193                 Base *base= (Base*) sce->base.first;
194                 while(base) {
195                         Object *ob = base->object;
196
197                         if (!ob->parent) {
198                                 switch(ob->type) {
199                                 case OB_MESH:
200                                 case OB_CAMERA:
201                                 case OB_LAMP:
202                                 case OB_ARMATURE:
203                                 case OB_EMPTY:
204                                         if (export_selected && !(ob->flag & SELECT)) {
205                                                 break;
206                                         }
207                                         // write nodes....
208                                         writeNodes(ob, sce);
209                                         break;
210                                 }
211                         }
212
213                         base= base->next;
214                 }
215         }
216
217
218         // called for each object
219         //void operator()(Object *ob) {
220         void writeNodes(Object *ob, Scene *sce)
221         {
222                 COLLADASW::Node node(mSW);
223                 node.setNodeId(translate_id(id_name(ob)));
224                 node.setType(COLLADASW::Node::NODE);
225
226                 node.start();
227
228                 bool is_skinned_mesh = arm_exporter->is_skinned_mesh(ob);
229
230                 if (ob->type == OB_MESH && is_skinned_mesh)
231                         // for skinned mesh we write obmat in <bind_shape_matrix>
232                         TransformWriter::add_node_transform_identity(node);
233                 else
234                         TransformWriter::add_node_transform_ob(node, ob);
235                 
236                 // <instance_geometry>
237                 if (ob->type == OB_MESH) {
238                         if (is_skinned_mesh) {
239                                 arm_exporter->add_instance_controller(ob);
240                         }
241                         else {
242                                 COLLADASW::InstanceGeometry instGeom(mSW);
243                                 instGeom.setUrl(COLLADASW::URI(COLLADABU::Utils::EMPTY_STRING, get_geometry_id(ob)));
244
245                                 InstanceWriter::add_material_bindings(instGeom.getBindMaterial(), ob);
246                         
247                                 instGeom.add();
248                         }
249                 }
250
251                 // <instance_controller>
252                 else if (ob->type == OB_ARMATURE) {
253                         arm_exporter->add_armature_bones(ob, sce);
254
255                         // XXX this looks unstable...
256                         node.end();
257                 }
258                 
259                 // <instance_camera>
260                 else if (ob->type == OB_CAMERA) {
261                         COLLADASW::InstanceCamera instCam(mSW, COLLADASW::URI(COLLADABU::Utils::EMPTY_STRING, get_camera_id(ob)));
262                         instCam.add();
263                 }
264                 
265                 // <instance_light>
266                 else if (ob->type == OB_LAMP) {
267                         COLLADASW::InstanceLight instLa(mSW, COLLADASW::URI(COLLADABU::Utils::EMPTY_STRING, get_light_id(ob)));
268                         instLa.add();
269                 }
270
271                 // empty object
272                 else if (ob->type == OB_EMPTY) {
273                 }
274
275                 // write nodes for child objects
276                 Base *b = (Base*) sce->base.first;
277                 while(b) {
278                         // cob - child object
279                         Object *cob = b->object;
280
281                         if (cob->parent == ob) {
282                                 switch(cob->type) {
283                                 case OB_MESH:
284                                 case OB_CAMERA:
285                                 case OB_LAMP:
286                                 case OB_EMPTY:
287                                 case OB_ARMATURE:
288                                         // write node...
289                                         writeNodes(cob, sce);
290                                         break;
291                                 }
292                         }
293
294                         b = b->next;
295                 }
296
297                 if (ob->type != OB_ARMATURE)
298                         node.end();
299         }
300 };
301
302 // TODO: it would be better to instantiate animations rather than create a new one per object
303 // COLLADA allows this through multiple <channel>s in <animation>.
304 // For this to work, we need to know objects that use a certain action.
305
306 void DocumentExporter::exportCurrentScene(Scene *sce, const char* filename, bool selected)
307 {
308         PointerRNA sceneptr, unit_settings;
309         PropertyRNA *system; /* unused , *scale; */
310
311         clear_global_id_map();
312         
313         COLLADABU::NativeString native_filename =
314                 COLLADABU::NativeString(std::string(filename));
315         COLLADASW::StreamWriter sw(native_filename);
316
317         // open <collada>
318         sw.startDocument();
319
320         // <asset>
321         COLLADASW::Asset asset(&sw);
322
323         RNA_id_pointer_create(&(sce->id), &sceneptr);
324         unit_settings = RNA_pointer_get(&sceneptr, "unit_settings");
325         system = RNA_struct_find_property(&unit_settings, "system");
326         //scale = RNA_struct_find_property(&unit_settings, "scale_length");
327
328         std::string unitname = "meter";
329         float linearmeasure = 1.0f;
330
331         linearmeasure = RNA_float_get(&unit_settings, "scale_length");
332
333         switch(RNA_property_enum_get(&unit_settings, system)) {
334                 case USER_UNIT_NONE:
335                 case USER_UNIT_METRIC:
336                         if(linearmeasure == 0.001f) {
337                                 unitname = "millimeter";
338                         }
339                         else if(linearmeasure == 0.01f) {
340                                 unitname = "centimeter";
341                         }
342                         else if(linearmeasure == 0.1f) {
343                                 unitname = "decimeter";
344                         }
345                         else if(linearmeasure == 1.0f) {
346                                 unitname = "meter";
347                         }
348                         else if(linearmeasure == 1000.0f) {
349                                 unitname = "kilometer";
350                         }
351                         break;
352                 case USER_UNIT_IMPERIAL:
353                         if(linearmeasure == 0.0254f) {
354                                 unitname = "inch";
355                         }
356                         else if(linearmeasure == 0.3048f) {
357                                 unitname = "foot";
358                         }
359                         else if(linearmeasure == 0.9144f) {
360                                 unitname = "yard";
361                         }
362                         break;
363                 default:
364                         break;
365         }
366
367         asset.setUnit(unitname, linearmeasure);
368         asset.setUpAxisType(COLLADASW::Asset::Z_UP);
369         // TODO: need an Author field in userpref
370         if(strlen(U.author) > 0) {
371                 asset.getContributor().mAuthor = U.author;
372         }
373         else {
374                 asset.getContributor().mAuthor = "Blender User";
375         }
376 #ifdef NAN_BUILDINFO
377         char version_buf[128];
378         sprintf(version_buf, "Blender %d.%02d.%d r%s", BLENDER_VERSION/100, BLENDER_VERSION%100, BLENDER_SUBVERSION, build_rev);
379         asset.getContributor().mAuthoringTool = version_buf;
380 #else
381         asset.getContributor().mAuthoringTool = "Blender 2.5x";
382 #endif
383         asset.add();
384         
385         // <library_cameras>
386         if(has_object_type(sce, OB_CAMERA)) {
387                 CamerasExporter ce(&sw);
388                 ce.exportCameras(sce, selected);
389         }
390         
391         // <library_lights>
392         if(has_object_type(sce, OB_LAMP)) {
393                 LightsExporter le(&sw);
394                 le.exportLights(sce, selected);
395         }
396
397         // <library_images>
398         ImagesExporter ie(&sw, filename);
399         ie.exportImages(sce, selected);
400         
401         // <library_effects>
402         EffectsExporter ee(&sw);
403         ee.exportEffects(sce, selected);
404         
405         // <library_materials>
406         MaterialsExporter me(&sw);
407         me.exportMaterials(sce, selected);
408
409         // <library_geometries>
410         if(has_object_type(sce, OB_MESH)) {
411                 GeometryExporter ge(&sw);
412                 ge.exportGeom(sce, selected);
413         }
414
415         // <library_animations>
416         AnimationExporter ae(&sw);
417         ae.exportAnimations(sce);
418
419         // <library_controllers>
420         ArmatureExporter arm_exporter(&sw);
421         if(has_object_type(sce, OB_ARMATURE)) {
422                 arm_exporter.export_controllers(sce, selected);
423         }
424
425         // <library_visual_scenes>
426         SceneExporter se(&sw, &arm_exporter);
427         se.exportScene(sce, selected);
428         
429         // <scene>
430         std::string scene_name(translate_id(id_name(sce)));
431         COLLADASW::Scene scene(&sw, COLLADASW::URI(COLLADABU::Utils::EMPTY_STRING,
432                                                                                            scene_name));
433         scene.add();
434         
435         // close <Collada>
436         sw.endDocument();
437
438 }
439
440 void DocumentExporter::exportScenes(const char* filename)
441 {
442 }
443
444 /*
445
446 NOTES:
447
448 * AnimationExporter::sample_animation enables all curves on armature, this is undesirable for a user
449
450  */