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