svn merge -r39781:39792 https://svn.blender.org/svnroot/bf-blender/trunk/blender...
[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 WITH_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                                 if(sce->lay & ob->lay) {
199                                 switch(ob->type) {
200                                 case OB_MESH:
201                                 case OB_CAMERA:
202                                 case OB_LAMP:
203                                 case OB_ARMATURE:
204                                 case OB_EMPTY:
205                                         if (export_selected && !(ob->flag & SELECT)) {
206                                                 break;
207                                         }
208                                         // write nodes....
209                                         writeNodes(ob, sce);
210                                         break;
211                                 }
212                                 }
213                         }
214
215                         base= base->next;
216                 }
217         }
218
219
220         // called for each object
221         //void operator()(Object *ob) {
222         void writeNodes(Object *ob, Scene *sce)
223         {
224                 COLLADASW::Node node(mSW);
225                 node.setNodeId(translate_id(id_name(ob)));
226                 node.setType(COLLADASW::Node::NODE);
227
228                 node.start();
229
230                 bool is_skinned_mesh = arm_exporter->is_skinned_mesh(ob);
231
232                 if (ob->type == OB_MESH && is_skinned_mesh)
233                         // for skinned mesh we write obmat in <bind_shape_matrix>
234                         TransformWriter::add_node_transform_identity(node);
235                 else
236                         TransformWriter::add_node_transform_ob(node, ob);
237                 
238                 // <instance_geometry>
239                 if (ob->type == OB_MESH) {
240                         if (is_skinned_mesh) {
241                                 arm_exporter->add_instance_controller(ob);
242                         }
243                         else {
244                                 COLLADASW::InstanceGeometry instGeom(mSW);
245                                 instGeom.setUrl(COLLADASW::URI(COLLADABU::Utils::EMPTY_STRING, get_geometry_id(ob)));
246
247                                 InstanceWriter::add_material_bindings(instGeom.getBindMaterial(), ob);
248                         
249                                 instGeom.add();
250                         }
251                 }
252
253                 // <instance_controller>
254                 else if (ob->type == OB_ARMATURE) {
255                         arm_exporter->add_armature_bones(ob, sce);
256
257                         // XXX this looks unstable...
258                         node.end();
259                 }
260                 
261                 // <instance_camera>
262                 else if (ob->type == OB_CAMERA) {
263                         COLLADASW::InstanceCamera instCam(mSW, COLLADASW::URI(COLLADABU::Utils::EMPTY_STRING, get_camera_id(ob)));
264                         instCam.add();
265                 }
266                 
267                 // <instance_light>
268                 else if (ob->type == OB_LAMP) {
269                         COLLADASW::InstanceLight instLa(mSW, COLLADASW::URI(COLLADABU::Utils::EMPTY_STRING, get_light_id(ob)));
270                         instLa.add();
271                 }
272
273                 // empty object
274                 else if (ob->type == OB_EMPTY) {
275                 }
276
277                 // write nodes for child objects
278                 Base *b = (Base*) sce->base.first;
279                 while(b) {
280                         // cob - child object
281                         Object *cob = b->object;
282
283                         if (cob->parent == ob) {
284                                 switch(cob->type) {
285                                 case OB_MESH:
286                                 case OB_CAMERA:
287                                 case OB_LAMP:
288                                 case OB_EMPTY:
289                                 case OB_ARMATURE:
290                                         // write node...
291                                         writeNodes(cob, sce);
292                                         break;
293                                 }
294                         }
295
296                         b = b->next;
297                 }
298
299                 if (ob->type != OB_ARMATURE)
300                         node.end();
301         }
302 };
303
304 // TODO: it would be better to instantiate animations rather than create a new one per object
305 // COLLADA allows this through multiple <channel>s in <animation>.
306 // For this to work, we need to know objects that use a certain action.
307
308 void DocumentExporter::exportCurrentScene(Scene *sce, const char* filename, bool selected)
309 {
310         PointerRNA sceneptr, unit_settings;
311         PropertyRNA *system; /* unused , *scale; */
312
313         clear_global_id_map();
314         
315         COLLADABU::NativeString native_filename =
316                 COLLADABU::NativeString(std::string(filename));
317         COLLADASW::StreamWriter sw(native_filename);
318
319         // open <collada>
320         sw.startDocument();
321
322         // <asset>
323         COLLADASW::Asset asset(&sw);
324
325         RNA_id_pointer_create(&(sce->id), &sceneptr);
326         unit_settings = RNA_pointer_get(&sceneptr, "unit_settings");
327         system = RNA_struct_find_property(&unit_settings, "system");
328         //scale = RNA_struct_find_property(&unit_settings, "scale_length");
329
330         std::string unitname = "meter";
331         float linearmeasure = 1.0f;
332
333         linearmeasure = RNA_float_get(&unit_settings, "scale_length");
334
335         switch(RNA_property_enum_get(&unit_settings, system)) {
336                 case USER_UNIT_NONE:
337                 case USER_UNIT_METRIC:
338                         if(linearmeasure == 0.001f) {
339                                 unitname = "millimeter";
340                         }
341                         else if(linearmeasure == 0.01f) {
342                                 unitname = "centimeter";
343                         }
344                         else if(linearmeasure == 0.1f) {
345                                 unitname = "decimeter";
346                         }
347                         else if(linearmeasure == 1.0f) {
348                                 unitname = "meter";
349                         }
350                         else if(linearmeasure == 1000.0f) {
351                                 unitname = "kilometer";
352                         }
353                         break;
354                 case USER_UNIT_IMPERIAL:
355                         if(linearmeasure == 0.0254f) {
356                                 unitname = "inch";
357                         }
358                         else if(linearmeasure == 0.3048f) {
359                                 unitname = "foot";
360                         }
361                         else if(linearmeasure == 0.9144f) {
362                                 unitname = "yard";
363                         }
364                         break;
365                 default:
366                         break;
367         }
368
369         asset.setUnit(unitname, linearmeasure);
370         asset.setUpAxisType(COLLADASW::Asset::Z_UP);
371         // TODO: need an Author field in userpref
372         if(strlen(U.author) > 0) {
373                 asset.getContributor().mAuthor = U.author;
374         }
375         else {
376                 asset.getContributor().mAuthor = "Blender User";
377         }
378 #ifdef WITH_BUILDINFO
379         char version_buf[128];
380         sprintf(version_buf, "Blender %d.%02d.%d r%s", BLENDER_VERSION/100, BLENDER_VERSION%100, BLENDER_SUBVERSION, build_rev);
381         asset.getContributor().mAuthoringTool = version_buf;
382 #else
383         asset.getContributor().mAuthoringTool = "Blender 2.5x";
384 #endif
385         asset.add();
386         
387         // <library_cameras>
388         if(has_object_type(sce, OB_CAMERA)) {
389                 CamerasExporter ce(&sw);
390                 ce.exportCameras(sce, selected);
391         }
392         
393         // <library_lights>
394         if(has_object_type(sce, OB_LAMP)) {
395                 LightsExporter le(&sw);
396                 le.exportLights(sce, selected);
397         }
398
399         // <library_images>
400         ImagesExporter ie(&sw, filename);
401         ie.exportImages(sce, selected);
402         
403         // <library_effects>
404         EffectsExporter ee(&sw);
405         ee.exportEffects(sce, selected);
406         
407         // <library_materials>
408         MaterialsExporter me(&sw);
409         me.exportMaterials(sce, selected);
410
411         // <library_geometries>
412         if(has_object_type(sce, OB_MESH)) {
413                 GeometryExporter ge(&sw);
414                 ge.exportGeom(sce, selected);
415         }
416
417         // <library_animations>
418         AnimationExporter ae(&sw);
419         ae.exportAnimations(sce);
420
421         // <library_controllers>
422         ArmatureExporter arm_exporter(&sw);
423         if(has_object_type(sce, OB_ARMATURE)) {
424                 arm_exporter.export_controllers(sce, selected);
425         }
426
427         // <library_visual_scenes>
428         SceneExporter se(&sw, &arm_exporter);
429         se.exportScene(sce, selected);
430         
431         // <scene>
432         std::string scene_name(translate_id(id_name(sce)));
433         COLLADASW::Scene scene(&sw, COLLADASW::URI(COLLADABU::Utils::EMPTY_STRING,
434                                                                                            scene_name));
435         scene.add();
436         
437         // close <Collada>
438         sw.endDocument();
439
440 }
441
442 void DocumentExporter::exportScenes(const char* filename)
443 {
444 }
445
446 /*
447
448 NOTES:
449
450 * AnimationExporter::sample_animation enables all curves on armature, this is undesirable for a user
451
452  */