8017790572f6c3f194e192c6d2384833e2c13172
[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 }
27
28 #include "SceneExporter.h"
29 #include "collada_utils.h"
30
31 void SceneExporter::exportScene()
32 {
33   Scene *scene = blender_context.get_scene();
34
35   /* <library_visual_scenes> <visual_scene> */
36   std::string name = id_name(scene);
37   openVisualScene(translate_id(name), encode_xml(name));
38   exportHierarchy();
39   closeVisualScene();
40   closeLibrary();
41 }
42
43 void SceneExporter::exportHierarchy()
44 {
45   LinkNode *node;
46   std::vector<Object *> base_objects;
47
48   /* Ensure all objects in the export_set are marked */
49   for (node = this->export_settings->export_set; node; node = node->next) {
50     Object *ob = (Object *)node->link;
51     ob->id.tag |= LIB_TAG_DOIT;
52   }
53
54   /* Now find all exportable base objects (highest in export hierarchy) */
55   for (node = this->export_settings->export_set; node; node = node->next) {
56     Object *ob = (Object *)node->link;
57     if (bc_is_base_node(this->export_settings->export_set, ob)) {
58       switch (ob->type) {
59         case OB_MESH:
60         case OB_CAMERA:
61         case OB_LAMP:
62         case OB_EMPTY:
63         case OB_GPENCIL:
64         case OB_ARMATURE:
65           base_objects.push_back(ob);
66           break;
67       }
68     }
69   }
70
71   /* And now export the base objects: */
72   for (int index = 0; index < base_objects.size(); index++) {
73     Object *ob = base_objects[index];
74     if (bc_is_marked(ob)) {
75       bc_remove_mark(ob);
76       writeNodes(ob);
77     }
78   }
79 }
80
81 void SceneExporter::writeNodeList(std::vector<Object *> &child_objects, Object *parent)
82 {
83   /* TODO: Handle the case where a parent is not exported
84    * Actually i am not even sure if this can be done at all
85    * in a good way.
86    * I really prefer to enforce the export of hidden
87    * elements in an object hierarchy. When the children of
88    * the hidden elements are exported as well. */
89   for (int i = 0; i < child_objects.size(); ++i) {
90     Object *child = child_objects[i];
91     if (bc_is_marked(child)) {
92       bc_remove_mark(child);
93       writeNodes(child);
94     }
95   }
96 }
97
98 void SceneExporter::writeNodes(Object *ob)
99 {
100   ViewLayer *view_layer = blender_context.get_view_layer();
101
102   std::vector<Object *> child_objects;
103   bc_get_children(child_objects, ob, view_layer);
104   bool can_export = bc_is_in_Export_set(this->export_settings->export_set, ob, view_layer);
105
106   /* Add associated armature first if available */
107   bool armature_exported = false;
108   Object *ob_arm = bc_get_assigned_armature(ob);
109
110   if (ob_arm != NULL) {
111     armature_exported = bc_is_in_Export_set(this->export_settings->export_set, ob_arm, view_layer);
112     if (armature_exported && bc_is_marked(ob_arm)) {
113       bc_remove_mark(ob_arm);
114       writeNodes(ob_arm);
115       armature_exported = true;
116     }
117   }
118
119   if (can_export) {
120     COLLADASW::Node colladaNode(mSW);
121     colladaNode.setNodeId(translate_id(id_name(ob)));
122     colladaNode.setNodeName(encode_xml(id_name(ob)));
123     colladaNode.setType(COLLADASW::Node::NODE);
124
125     colladaNode.start();
126
127     if (ob->type == OB_MESH && armature_exported) {
128       /* for skinned mesh we write obmat in <bind_shape_matrix> */
129       TransformWriter::add_node_transform_identity(colladaNode);
130     }
131     else {
132       TransformWriter::add_node_transform_ob(colladaNode,
133                                              ob,
134                                              this->export_settings->export_transformation_type,
135                                              this->export_settings->limit_precision);
136     }
137
138     /* <instance_geometry> */
139     if (ob->type == OB_MESH) {
140       bool instance_controller_created = false;
141       if (armature_exported) {
142         instance_controller_created = arm_exporter->add_instance_controller(ob);
143       }
144       if (!instance_controller_created) {
145         COLLADASW::InstanceGeometry instGeom(mSW);
146         instGeom.setUrl(
147             COLLADASW::URI(COLLADABU::Utils::EMPTY_STRING,
148                            get_geometry_id(ob, this->export_settings->use_object_instantiation)));
149         instGeom.setName(encode_xml(id_name(ob)));
150         InstanceWriter::add_material_bindings(
151             instGeom.getBindMaterial(), ob, this->export_settings->active_uv_only);
152         instGeom.add();
153       }
154     }
155
156     /* <instance_controller> */
157     else if (ob->type == OB_ARMATURE) {
158       arm_exporter->add_armature_bones(ob, view_layer, this, child_objects);
159     }
160
161     /* <instance_camera> */
162     else if (ob->type == OB_CAMERA) {
163       COLLADASW::InstanceCamera instCam(
164           mSW, COLLADASW::URI(COLLADABU::Utils::EMPTY_STRING, get_camera_id(ob)));
165       instCam.add();
166     }
167
168     /* <instance_light> */
169     else if (ob->type == OB_LAMP) {
170       COLLADASW::InstanceLight instLa(
171           mSW, COLLADASW::URI(COLLADABU::Utils::EMPTY_STRING, get_light_id(ob)));
172       instLa.add();
173     }
174
175     /* empty object */
176     else if (ob->type == OB_EMPTY) { /* TODO: handle groups (OB_DUPLICOLLECTION */
177       if ((ob->transflag & OB_DUPLICOLLECTION) == OB_DUPLICOLLECTION && ob->instance_collection) {
178         Collection *collection = ob->instance_collection;
179         /* printf("group detected '%s'\n", group->id.name + 2); */
180         FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN (collection, object) {
181           printf("\t%s\n", object->id.name);
182         }
183         FOREACH_COLLECTION_OBJECT_RECURSIVE_END;
184       }
185
186       if (BLI_listbase_is_empty(&ob->constraints) == false) {
187         bConstraint *con = (bConstraint *)ob->constraints.first;
188         while (con) {
189           std::string con_name(encode_xml(con->name));
190           std::string con_tag = con_name + "_constraint";
191           printf("%s\n", con_name.c_str());
192           printf("%s\n\n", con_tag.c_str());
193           colladaNode.addExtraTechniqueChildParameter("blender", con_tag, "type", con->type);
194           colladaNode.addExtraTechniqueChildParameter("blender", con_tag, "enforce", con->enforce);
195           colladaNode.addExtraTechniqueChildParameter("blender", con_tag, "flag", con->flag);
196           colladaNode.addExtraTechniqueChildParameter(
197               "blender", con_tag, "headtail", con->headtail);
198           colladaNode.addExtraTechniqueChildParameter(
199               "blender", con_tag, "lin_error", con->lin_error);
200           colladaNode.addExtraTechniqueChildParameter(
201               "blender", con_tag, "own_space", con->ownspace);
202           colladaNode.addExtraTechniqueChildParameter(
203               "blender", con_tag, "rot_error", con->rot_error);
204           colladaNode.addExtraTechniqueChildParameter(
205               "blender", con_tag, "tar_space", con->tarspace);
206           colladaNode.addExtraTechniqueChildParameter(
207               "blender", con_tag, "lin_error", con->lin_error);
208
209           /* not ideal: add the target object name as another parameter.
210            * No real mapping in the .dae
211            * Need support for multiple target objects also. */
212           const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
213           ListBase targets = {NULL, NULL};
214           if (cti && cti->get_constraint_targets) {
215
216             bConstraintTarget *ct;
217             Object *obtar;
218
219             cti->get_constraint_targets(con, &targets);
220
221             for (ct = (bConstraintTarget *)targets.first; ct; ct = ct->next) {
222               obtar = ct->tar;
223               std::string tar_id((obtar) ? id_name(obtar) : "");
224               colladaNode.addExtraTechniqueChildParameter("blender", con_tag, "target_id", tar_id);
225             }
226
227             if (cti->flush_constraint_targets)
228               cti->flush_constraint_targets(con, &targets, 1);
229           }
230
231           con = con->next;
232         }
233       }
234     }
235     writeNodeList(child_objects, ob);
236     colladaNode.end();
237   }
238 }