Collada exporter update
[blender.git] / source / blender / collada / SceneExporter.cpp
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  */
16
17 /** \file
18  * \ingroup collada
19  */
20
21 extern "C" {
22 #include "BLI_utildefines.h"
23 #include "BKE_collection.h"
24 #include "BKE_object.h"
25 #include "BLI_listbase.h"
26 #include "BKE_library.h"
27 }
28
29 #include "SceneExporter.h"
30 #include "collada_utils.h"
31 #include "BCSampleData.h"
32
33 void SceneExporter::exportScene()
34 {
35   Scene *scene = blender_context.get_scene();
36
37   /* <library_visual_scenes> <visual_scene> */
38   std::string name = id_name(scene);
39   openVisualScene(translate_id(name), encode_xml(name));
40   exportHierarchy();
41   closeVisualScene();
42   closeLibrary();
43 }
44
45 void SceneExporter::exportHierarchy()
46 {
47   LinkNode *node;
48   ColladaBaseNodes base_objects;
49
50   /* Ensure all objects in the export_set are marked */
51   for (node = this->export_settings.get_export_set(); node; node = node->next) {
52     Object *ob = (Object *)node->link;
53     ob->id.tag |= LIB_TAG_DOIT;
54   }
55
56   /* Now find all exportable base objects (highest in export hierarchy) */
57   for (node = this->export_settings.get_export_set(); node; node = node->next) {
58     Object *ob = (Object *)node->link;
59     if (this->export_settings.is_export_root(ob)) {
60       switch (ob->type) {
61         case OB_MESH:
62         case OB_CAMERA:
63         case OB_LAMP:
64         case OB_EMPTY:
65         case OB_GPENCIL:
66         case OB_ARMATURE:
67           base_objects.add(ob);
68           break;
69       }
70     }
71   }
72
73   /* And now export the base objects: */
74   for (int index = 0; index < base_objects.size(); index++) {
75     Object *ob = base_objects.get(index);
76     writeNode(ob);
77     if (bc_is_marked(ob)) {
78       bc_remove_mark(ob);
79     }
80   }
81 }
82
83 void SceneExporter::writeNodeList(std::vector<Object *> &child_objects, Object *parent)
84 {
85   /* TODO: Handle the case where a parent is not exported
86    * Actually i am not even sure if this can be done at all
87    * in a good way.
88    * I really prefer to enforce the export of hidden
89    * elements in an object hierarchy. When the children of
90    * the hidden elements are exported as well. */
91   for (int i = 0; i < child_objects.size(); ++i) {
92     Object *child = child_objects[i];
93     writeNode(child);
94     if (bc_is_marked(child)) {
95       bc_remove_mark(child);
96     }
97   }
98 }
99
100 void SceneExporter::writeNode(Object *ob)
101 {
102   ViewLayer *view_layer = blender_context.get_view_layer();
103
104   std::vector<Object *> child_objects;
105   bc_get_children(child_objects, ob, view_layer);
106   bool can_export = bc_is_in_Export_set(this->export_settings.get_export_set(), ob, view_layer);
107
108   /* Add associated armature first if available */
109   bool armature_exported = false;
110   Object *ob_arm = bc_get_assigned_armature(ob);
111
112   if (ob_arm != NULL) {
113     armature_exported = bc_is_in_Export_set(
114         this->export_settings.get_export_set(), ob_arm, view_layer);
115     if (armature_exported && bc_is_marked(ob_arm)) {
116       writeNode(ob_arm);
117       bc_remove_mark(ob_arm);
118       armature_exported = true;
119     }
120   }
121
122   if (can_export) {
123     COLLADASW::Node colladaNode(mSW);
124     colladaNode.setNodeId(translate_id(id_name(ob)));
125     colladaNode.setNodeName(encode_xml(id_name(ob)));
126     colladaNode.setType(COLLADASW::Node::NODE);
127
128     colladaNode.start();
129     if (ob->type == OB_MESH && armature_exported) {
130       /* for skinned mesh we write obmat in <bind_shape_matrix> */
131       TransformWriter::add_node_transform_identity(colladaNode);
132     }
133     else {
134       TransformWriter::add_node_transform_ob(colladaNode, ob, this->export_settings);
135     }
136
137     /* <instance_geometry> */
138     if (ob->type == OB_MESH) {
139       bool instance_controller_created = false;
140       if (armature_exported) {
141         instance_controller_created = arm_exporter->add_instance_controller(ob);
142       }
143       if (!instance_controller_created) {
144         COLLADASW::InstanceGeometry instGeom(mSW);
145         instGeom.setUrl(COLLADASW::URI(
146             COLLADABU::Utils::EMPTY_STRING,
147             get_geometry_id(ob, this->export_settings.get_use_object_instantiation())));
148         instGeom.setName(encode_xml(id_name(ob)));
149         InstanceWriter::add_material_bindings(
150             instGeom.getBindMaterial(), ob, this->export_settings.get_active_uv_only());
151         instGeom.add();
152       }
153     }
154
155     /* <instance_controller> */
156     else if (ob->type == OB_ARMATURE) {
157       arm_exporter->add_armature_bones(ob, view_layer, this, child_objects);
158     }
159
160     /* <instance_camera> */
161     else if (ob->type == OB_CAMERA) {
162       COLLADASW::InstanceCamera instCam(
163           mSW, COLLADASW::URI(COLLADABU::Utils::EMPTY_STRING, get_camera_id(ob)));
164       instCam.add();
165     }
166
167     /* <instance_light> */
168     else if (ob->type == OB_LAMP) {
169       COLLADASW::InstanceLight instLa(
170           mSW, COLLADASW::URI(COLLADABU::Utils::EMPTY_STRING, get_light_id(ob)));
171       instLa.add();
172     }
173
174     /* empty object */
175     else if (ob->type == OB_EMPTY) { /* TODO: handle groups (OB_DUPLICOLLECTION */
176       if ((ob->transflag & OB_DUPLICOLLECTION) == OB_DUPLICOLLECTION && ob->instance_collection) {
177         Collection *collection = ob->instance_collection;
178         /* printf("group detected '%s'\n", group->id.name + 2); */
179         FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN (collection, object) {
180           printf("\t%s\n", object->id.name);
181         }
182         FOREACH_COLLECTION_OBJECT_RECURSIVE_END;
183       }
184
185       if (BLI_listbase_is_empty(&ob->constraints) == false) {
186         bConstraint *con = (bConstraint *)ob->constraints.first;
187         while (con) {
188           std::string con_name(encode_xml(con->name));
189           std::string con_tag = con_name + "_constraint";
190           printf("%s\n", con_name.c_str());
191           printf("%s\n\n", con_tag.c_str());
192           colladaNode.addExtraTechniqueChildParameter("blender", con_tag, "type", con->type);
193           colladaNode.addExtraTechniqueChildParameter("blender", con_tag, "enforce", con->enforce);
194           colladaNode.addExtraTechniqueChildParameter("blender", con_tag, "flag", con->flag);
195           colladaNode.addExtraTechniqueChildParameter(
196               "blender", con_tag, "headtail", con->headtail);
197           colladaNode.addExtraTechniqueChildParameter(
198               "blender", con_tag, "lin_error", con->lin_error);
199           colladaNode.addExtraTechniqueChildParameter(
200               "blender", con_tag, "own_space", con->ownspace);
201           colladaNode.addExtraTechniqueChildParameter(
202               "blender", con_tag, "rot_error", con->rot_error);
203           colladaNode.addExtraTechniqueChildParameter(
204               "blender", con_tag, "tar_space", con->tarspace);
205           colladaNode.addExtraTechniqueChildParameter(
206               "blender", con_tag, "lin_error", con->lin_error);
207
208           /* not ideal: add the target object name as another parameter.
209            * No real mapping in the .dae
210            * Need support for multiple target objects also. */
211           const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
212           ListBase targets = {NULL, NULL};
213           if (cti && cti->get_constraint_targets) {
214
215             bConstraintTarget *ct;
216             Object *obtar;
217
218             cti->get_constraint_targets(con, &targets);
219
220             for (ct = (bConstraintTarget *)targets.first; ct; ct = ct->next) {
221               obtar = ct->tar;
222               std::string tar_id((obtar) ? id_name(obtar) : "");
223               colladaNode.addExtraTechniqueChildParameter("blender", con_tag, "target_id", tar_id);
224             }
225
226             if (cti->flush_constraint_targets)
227               cti->flush_constraint_targets(con, &targets, 1);
228           }
229
230           con = con->next;
231         }
232       }
233     }
234     bc_remove_mark(ob);
235     writeNodeList(child_objects, ob);
236     colladaNode.end();
237   }
238   else {
239     writeNodeList(child_objects, ob);
240   }
241 }