f3844be525e38e6fa29100461a52eec5edc9bb36
[blender.git] / source / blender / collada / SceneExporter.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, Jan Diederich, Tod Liverseed.
19  *
20  * ***** END GPL LICENSE BLOCK *****
21  */
22
23 /** \file blender/collada/SceneExporter.cpp
24  *  \ingroup collada
25  */
26
27 extern "C" {
28         #include "BLI_utildefines.h"
29         #include "BKE_object.h"
30 }
31
32 #include "SceneExporter.h"
33 #include "collada_utils.h"
34
35 SceneExporter::SceneExporter(COLLADASW::StreamWriter *sw, ArmatureExporter *arm, const ExportSettings *export_settings)
36         : COLLADASW::LibraryVisualScenes(sw), arm_exporter(arm), export_settings(export_settings)
37 {
38 }
39
40 void SceneExporter::setExportTransformationType(BC_export_transformation_type transformation_type)
41 {
42         this->transformation_type = transformation_type;
43 }
44
45 void SceneExporter::exportScene(Scene *sce)
46 {
47         // <library_visual_scenes> <visual_scene>
48         std::string id_naming = id_name(sce);
49         openVisualScene(translate_id(id_naming), id_naming);
50         exportHierarchy(sce);
51         closeVisualScene();
52         closeLibrary();
53 }
54
55 void SceneExporter::exportHierarchy(Scene *sce)
56 {       
57         LinkNode *node;
58         std::vector<Object *> base_objects;
59
60         // Ensure all objects in the export_set are marked
61         for (node = this->export_settings->export_set; node; node = node->next) {
62                 Object *ob = (Object *) node->link;
63                 ob->id.flag |= LIB_DOIT;
64         }
65         
66         // Now find all exportable base ojects (highest in export hierarchy)
67         for (node = this->export_settings->export_set; node; node = node->next) {
68                 Object *ob = (Object *) node->link;
69                 if (bc_is_base_node(this->export_settings->export_set, ob)) {
70                         switch (ob->type) {
71                                 case OB_MESH:
72                                 case OB_CAMERA:
73                                 case OB_LAMP:
74                                 case OB_EMPTY:
75                                 case OB_ARMATURE:
76                                         base_objects.push_back(ob);
77                                         break;
78                         }
79                 }
80         }
81
82         // And now export the base objects:
83         for (int index = 0; index < base_objects.size(); index++) {
84                 Object *ob = base_objects[index];
85                 if (bc_is_marked(ob)) {
86                         bc_remove_mark(ob);
87                         writeNodes(ob, sce);
88                 }
89         }
90 }
91
92
93 void SceneExporter::writeNodes(Object *ob, Scene *sce)
94 {
95         // Add associated armature first if available
96         bool armature_exported = false;
97         Object *ob_arm = bc_get_assigned_armature(ob);
98         if (ob_arm != NULL) {
99                 armature_exported = bc_is_in_Export_set(this->export_settings->export_set, ob_arm);
100                 if (armature_exported && bc_is_marked(ob_arm)) {
101                         bc_remove_mark(ob_arm);
102                         writeNodes(ob_arm, sce);
103                         armature_exported = true;
104                 }
105         }
106
107         COLLADASW::Node colladaNode(mSW);
108         colladaNode.setNodeId(translate_id(id_name(ob)));
109         colladaNode.setNodeName(translate_id(id_name(ob)));
110         colladaNode.setType(COLLADASW::Node::NODE);
111
112         colladaNode.start();
113
114         std::list<Object *> child_objects;
115
116         // list child objects
117         LinkNode *node;
118         for (node=this->export_settings->export_set; node; node=node->next) {
119                 // cob - child object
120                 Object *cob = (Object *)node->link;
121
122                 if (cob->parent == ob) {
123                         switch (cob->type) {
124                                 case OB_MESH:
125                                 case OB_CAMERA:
126                                 case OB_LAMP:
127                                 case OB_EMPTY:
128                                 case OB_ARMATURE:
129                                         if (bc_is_marked(cob))
130                                                 child_objects.push_back(cob);
131                                         break;
132                         }
133                 }
134         }
135
136         if (ob->type == OB_MESH && armature_exported)
137                 // for skinned mesh we write obmat in <bind_shape_matrix>
138                 TransformWriter::add_node_transform_identity(colladaNode);
139         else {
140                 TransformWriter::add_node_transform_ob(colladaNode, ob, this->transformation_type);
141         }
142
143         // <instance_geometry>
144         if (ob->type == OB_MESH) {
145                 bool instance_controller_created = false;
146                 if (armature_exported) {
147                         instance_controller_created = arm_exporter->add_instance_controller(ob);
148                 }
149                 if (!instance_controller_created) {
150                         COLLADASW::InstanceGeometry instGeom(mSW);
151                         instGeom.setUrl(COLLADASW::URI(COLLADABU::Utils::EMPTY_STRING, get_geometry_id(ob, this->export_settings->use_object_instantiation)));
152
153                         InstanceWriter::add_material_bindings(instGeom.getBindMaterial(), ob, this->export_settings->active_uv_only);
154
155                         instGeom.add();
156                 }
157         }
158
159         // <instance_controller>
160         else if (ob->type == OB_ARMATURE) {
161                 arm_exporter->add_armature_bones(ob, sce, this, child_objects);
162         }
163
164         // <instance_camera>
165         else if (ob->type == OB_CAMERA) {
166                 COLLADASW::InstanceCamera instCam(mSW, COLLADASW::URI(COLLADABU::Utils::EMPTY_STRING, get_camera_id(ob)));
167                 instCam.add();
168         }
169
170         // <instance_light>
171         else if (ob->type == OB_LAMP) {
172                 COLLADASW::InstanceLight instLa(mSW, COLLADASW::URI(COLLADABU::Utils::EMPTY_STRING, get_light_id(ob)));
173                 instLa.add();
174         }
175
176         // empty object
177         else if (ob->type == OB_EMPTY) { // TODO: handle groups (OB_DUPLIGROUP
178                 if ((ob->transflag & OB_DUPLIGROUP) == OB_DUPLIGROUP && ob->dup_group) {
179                         GroupObject *go = NULL;
180                         Group *gr = ob->dup_group;
181                         /* printf("group detected '%s'\n", gr->id.name+2); */
182                         for (go = (GroupObject *)(gr->gobject.first); go; go = go->next) {
183                                 printf("\t%s\n", go->ob->id.name);
184                         }
185                 }
186         }
187
188         if (ob->type == OB_ARMATURE) {
189                 colladaNode.end();
190         }
191
192         if (ob->constraints.first != NULL ) {
193                 bConstraint *con = (bConstraint*) ob->constraints.first;
194                 while (con) {
195                         std::string con_name(id_name(con));
196                         std::string con_tag = con_name + "_constraint";
197                         colladaNode.addExtraTechniqueChildParameter("blender",con_tag,"type",con->type);
198                         colladaNode.addExtraTechniqueChildParameter("blender",con_tag,"enforce",con->enforce);
199                         colladaNode.addExtraTechniqueChildParameter("blender",con_tag,"flag",con->flag);
200                         colladaNode.addExtraTechniqueChildParameter("blender",con_tag,"headtail",con->headtail);
201                         colladaNode.addExtraTechniqueChildParameter("blender",con_tag,"lin_error",con->lin_error);
202                         colladaNode.addExtraTechniqueChildParameter("blender",con_tag,"own_space",con->ownspace);
203                         colladaNode.addExtraTechniqueChildParameter("blender",con_tag,"rot_error",con->rot_error);
204                         colladaNode.addExtraTechniqueChildParameter("blender",con_tag,"tar_space",con->tarspace);
205                         colladaNode.addExtraTechniqueChildParameter("blender",con_tag,"lin_error",con->lin_error);
206                         
207                         //not ideal: add the target object name as another parameter. 
208                         //No real mapping in the .dae
209                         //Need support for multiple target objects also.
210                         bConstraintTypeInfo *cti = BKE_constraint_get_typeinfo(con);
211                         ListBase targets = {NULL, NULL};
212                         if (cti && cti->get_constraint_targets) {
213                         
214                                 bConstraintTarget *ct;
215                                 Object *obtar;
216                         
217                                 cti->get_constraint_targets(con, &targets);
218                                 if (cti) {
219                                         for (ct = (bConstraintTarget*)targets.first; ct; ct = ct->next) {
220                                                 obtar = ct->tar;
221                                                 std::string tar_id(id_name(obtar));
222                                                 colladaNode.addExtraTechniqueChildParameter("blender",con_tag,"target_id",tar_id);
223                                         }
224                                 }
225                         }
226
227                         con = con->next;
228                 }
229         }
230
231         for (std::list<Object *>::iterator i = child_objects.begin(); i != child_objects.end(); ++i) {
232                 if (bc_is_marked(*i)) {
233                         bc_remove_mark(*i);
234                         writeNodes(*i, sce);
235                 }
236         }
237
238         if (ob->type != OB_ARMATURE)
239                 colladaNode.end();
240 }
241