code cleanup:
[blender.git] / source / blender / collada / collada_utils.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, Nathan Letwory.
19  *
20  * ***** END GPL LICENSE BLOCK *****
21  */
22
23 /** \file blender/collada/collada_utils.cpp
24  *  \ingroup collada
25  */
26
27
28 /* COLLADABU_ASSERT, may be able to remove later */
29 #include "COLLADABUPlatform.h"
30
31 #include "COLLADAFWGeometry.h"
32 #include "COLLADAFWMeshPrimitive.h"
33 #include "COLLADAFWMeshVertexData.h"
34
35 #include "collada_utils.h"
36
37 extern "C" {
38 #include "DNA_modifier_types.h"
39 #include "DNA_customdata_types.h"
40 #include "DNA_object_types.h"
41 #include "DNA_mesh_types.h"
42 #include "DNA_scene_types.h"
43 #include "DNA_armature_types.h"
44
45 #include "BLI_math.h"
46 #include "BLI_linklist.h"
47
48 #include "BKE_context.h"
49 #include "BKE_customdata.h"
50 #include "BKE_depsgraph.h"
51 #include "BKE_object.h"
52 #include "BKE_global.h"
53 #include "BKE_mesh.h"
54 #include "BKE_scene.h"
55 #include "BKE_DerivedMesh.h"
56
57 #include "WM_api.h" // XXX hrm, see if we can do without this
58 #include "WM_types.h"
59 #include "bmesh.h"
60 }
61
62 float bc_get_float_value(const COLLADAFW::FloatOrDoubleArray& array, unsigned int index)
63 {
64         if (index >= array.getValuesCount())
65                 return 0.0f;
66
67         if (array.getType() == COLLADAFW::MeshVertexData::DATA_TYPE_FLOAT)
68                 return array.getFloatValues()->getData()[index];
69         else 
70                 return array.getDoubleValues()->getData()[index];
71 }
72
73 // copied from /editors/object/object_relations.c
74 int bc_test_parent_loop(Object *par, Object *ob)
75 {
76         /* test if 'ob' is a parent somewhere in par's parents */
77         
78         if (par == NULL) return 0;
79         if (ob == par) return 1;
80         
81         return bc_test_parent_loop(par->parent, ob);
82 }
83
84 // a shortened version of parent_set_exec()
85 // if is_parent_space is true then ob->obmat will be multiplied by par->obmat before parenting
86 int bc_set_parent(Object *ob, Object *par, bContext *C, bool is_parent_space)
87 {
88         Object workob;
89         Scene *sce = CTX_data_scene(C);
90         
91         if (!par || bc_test_parent_loop(par, ob))
92                 return false;
93
94         ob->parent = par;
95         ob->partype = PAROBJECT;
96
97         ob->parsubstr[0] = 0;
98
99         if (is_parent_space) {
100                 float mat[4][4];
101                 // calc par->obmat
102                 BKE_object_where_is_calc(sce, par);
103
104                 // move child obmat into world space
105                 mult_m4_m4m4(mat, par->obmat, ob->obmat);
106                 copy_m4_m4(ob->obmat, mat);
107         }
108         
109         // apply child obmat (i.e. decompose it into rot/loc/size)
110         BKE_object_apply_mat4(ob, ob->obmat, 0, 0);
111
112         // compute parentinv
113         BKE_object_workob_calc_parent(sce, ob, &workob);
114         invert_m4_m4(ob->parentinv, workob.obmat);
115
116         DAG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA);
117         DAG_id_tag_update(&par->id, OB_RECALC_OB);
118
119         /** done once after import */
120 #if 0
121         DAG_relations_tag_update(bmain);
122         WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL);
123 #endif
124
125         return true;
126 }
127
128 Object *bc_add_object(Scene *scene, int type, const char *name)
129 {
130         Object *ob = BKE_object_add_only_object(G.main, type, name);
131
132         ob->data = BKE_object_obdata_add_from_type(type);
133         ob->lay = scene->lay;
134         DAG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME);
135
136         BKE_scene_base_select(scene, BKE_scene_base_add(scene, ob));
137
138         return ob;
139 }
140
141 Mesh *bc_get_mesh_copy(Scene *scene, Object *ob, BC_export_mesh_type export_mesh_type, bool apply_modifiers, bool triangulate)
142 {
143         Mesh *tmpmesh;
144         CustomDataMask mask = CD_MASK_MESH;
145         DerivedMesh *dm = NULL;
146         if (apply_modifiers) {
147                 switch (export_mesh_type) {
148                         case BC_MESH_TYPE_VIEW: {
149                                 dm = mesh_create_derived_view(scene, ob, mask);
150                                 break;
151                         }
152                         case BC_MESH_TYPE_RENDER: {
153                                 dm = mesh_create_derived_render(scene, ob, mask);
154                                 break;
155                         }
156                 }
157         }
158         else {
159                 dm = mesh_create_derived((Mesh *)ob->data, ob, NULL);
160         }
161
162         tmpmesh = BKE_mesh_add(G.main, "ColladaMesh"); // name is not important here
163         DM_to_mesh(dm, tmpmesh, ob);
164         dm->release(dm);
165
166         if (triangulate) {
167                 bc_triangulate_mesh(tmpmesh);
168         }
169
170         // XXX Not sure if we need that for ngon_export as well.
171         BKE_mesh_tessface_ensure(tmpmesh);
172
173         return tmpmesh;
174 }
175
176 Object *bc_get_assigned_armature(Object *ob)
177 {
178         Object *ob_arm = NULL;
179
180         if (ob->parent && ob->partype == PARSKEL && ob->parent->type == OB_ARMATURE) {
181                 ob_arm = ob->parent;
182         }
183         else {
184                 ModifierData *mod;
185                 for (mod = (ModifierData *)ob->modifiers.first; mod; mod = mod->next) {
186                         if (mod->type == eModifierType_Armature) {
187                                 ob_arm = ((ArmatureModifierData *)mod)->object;
188                         }
189                 }
190         }
191
192         return ob_arm;
193 }
194
195 // Returns the highest selected ancestor
196 // returns NULL if no ancestor is selected
197 // IMPORTANT: This function expects that
198 // all exported objects have set:
199 // ob->id.flag & LIB_DOIT
200 Object *bc_get_highest_selected_ancestor_or_self(LinkNode *export_set, Object *ob) 
201 {
202         Object *ancestor = ob;
203         while (ob->parent && bc_is_marked(ob->parent)) {
204                 ob = ob->parent;
205                 ancestor = ob;
206         }
207         return ancestor;
208 }
209
210
211 bool bc_is_base_node(LinkNode *export_set, Object *ob)
212 {
213         Object *root = bc_get_highest_selected_ancestor_or_self(export_set, ob);
214         return (root == ob);
215 }
216
217 bool bc_is_in_Export_set(LinkNode *export_set, Object *ob)
218 {
219         return (BLI_linklist_index(export_set, ob) != -1);
220 }
221
222 bool bc_has_object_type(LinkNode *export_set, short obtype)
223 {
224         LinkNode *node;
225         
226         for (node = export_set; node; node = node->next) {
227                 Object *ob = (Object *)node->link;
228                 /* XXX - why is this checking for ob->data? - we could be looking for empties */
229                 if (ob->type == obtype && ob->data) {
230                         return true;
231                 }
232         }
233         return false;
234 }
235
236 int bc_is_marked(Object *ob)
237 {
238         return ob && (ob->id.flag & LIB_DOIT);
239 }
240
241 void bc_remove_mark(Object *ob)
242 {
243         ob->id.flag &= ~LIB_DOIT;
244 }
245
246 void bc_set_mark(Object *ob)
247 {
248         ob->id.flag |= LIB_DOIT;
249 }
250
251 // Use bubble sort algorithm for sorting the export set
252 void bc_bubble_sort_by_Object_name(LinkNode *export_set)
253 {
254         bool sorted = false;
255         LinkNode *node;
256         for (node = export_set; node->next && !sorted; node = node->next) {
257
258                 sorted = true;
259                 
260                 LinkNode *current;
261                 for (current = export_set; current->next; current = current->next) {
262                         Object *a = (Object *)current->link;
263                         Object *b = (Object *)current->next->link;
264
265                         if (strcmp(a->id.name, b->id.name) > 0) {
266                                 current->link       = b;
267                                 current->next->link = a;
268                                 sorted = false;
269                         }
270                         
271                 }
272         }
273 }
274
275 /* Check if a bone is the top most exportable bone in the bone hierarchy. 
276  * When deform_bones_only == false, then only bones with NO parent 
277  * can be root bones. Otherwise the top most deform bones in the hierarchy
278  * are root bones.
279  */
280 bool bc_is_root_bone(Bone *aBone, bool deform_bones_only)
281 {
282         if (deform_bones_only) {
283                 Bone *root = NULL;
284                 Bone *bone = aBone;
285                 while (bone) {
286                         if (!(bone->flag & BONE_NO_DEFORM))
287                                 root = bone;
288                         bone = bone->parent;
289                 }
290                 return (aBone == root);
291         }
292         else
293                 return !(aBone->parent);
294 }
295
296 int bc_get_active_UVLayer(Object *ob)
297 {
298         Mesh *me = (Mesh *)ob->data;
299         return CustomData_get_active_layer_index(&me->fdata, CD_MTFACE);
300 }
301
302 std::string bc_url_encode(std::string data)
303 {
304         /* XXX We probably do not need to do a full encoding.
305          * But in case that is necessary,then it can be added here.
306          */
307         return bc_replace_string(data,"#", "%23");
308 }
309
310 std::string bc_replace_string(std::string data, const std::string& pattern,
311                               const std::string& replacement)
312 {
313         size_t pos = 0;
314         while((pos = data.find(pattern, pos)) != std::string::npos) {
315                 data.replace(pos, pattern.length(), replacement);
316                 pos += replacement.length();
317         }
318         return data;
319 }
320
321 /**
322  * Calculate a rescale factor such that the imported scene's scale
323  * is preserved. I.e. 1 meter in the import will also be
324  * 1 meter in the current scene.
325  * XXX : I am not sure if it is correct to map 1 Blender Unit
326  * to 1 Meter for unit type NONE. But it looks reasonable to me.
327  */
328 void bc_match_scale(std::vector<Object *> *objects_done, 
329                     Scene &sce,
330                     UnitConverter &bc_unit)
331 {
332         Object *ob = NULL;
333
334         PointerRNA scene_ptr, unit_settings;
335         PropertyRNA *system_ptr, *scale_ptr;
336         RNA_id_pointer_create(&sce.id, &scene_ptr);
337
338         unit_settings = RNA_pointer_get(&scene_ptr, "unit_settings");
339         system_ptr = RNA_struct_find_property(&unit_settings, "system");
340         scale_ptr = RNA_struct_find_property(&unit_settings, "scale_length");
341
342         int   type  = RNA_property_enum_get(&unit_settings, system_ptr);
343
344         float bl_scale;
345         
346         switch (type) {
347                 case USER_UNIT_NONE:
348                         bl_scale = 1.0; // map 1 Blender unit to 1 Meter
349                         break;
350
351                 case USER_UNIT_METRIC:
352                         bl_scale = RNA_property_float_get(&unit_settings, scale_ptr);
353                         break;
354
355                 default :
356                         bl_scale = RNA_property_float_get(&unit_settings, scale_ptr);
357                         // it looks like the conversion to Imperial is done implicitly.
358                         // So nothing to do here.
359                         break;
360         }
361         
362         float scale_conv = bc_unit.getLinearMeter() / bl_scale;
363
364         float rescale[3];
365         rescale[0] = rescale[1] = rescale[2] = scale_conv;
366
367         float size_mat4[4][4];
368
369         float axis_mat4[4][4];
370         unit_m4(axis_mat4);
371
372         size_to_mat4(size_mat4, rescale);
373
374         for (std::vector<Object *>::iterator it = objects_done->begin();
375                         it != objects_done->end();
376                         ++it) 
377         {
378                 ob = *it;
379                 mult_m4_m4m4(ob->obmat, size_mat4, ob->obmat);
380                 mult_m4_m4m4(ob->obmat, bc_unit.get_rotation(), ob->obmat);
381                 BKE_object_apply_mat4(ob, ob->obmat, 0, 0);
382         }
383
384 }
385
386 void bc_triangulate_mesh(Mesh *me) {
387         bool use_beauty = false;
388         bool tag_only   = false;
389          
390         BMesh *bm = BM_mesh_create(&bm_mesh_allocsize_default);
391         BM_mesh_bm_from_me(bm, me, FALSE, 0);
392         BM_mesh_triangulate(bm, use_beauty, tag_only, NULL, NULL);
393         BM_mesh_bm_to_me(bm, me, FALSE);
394         BM_mesh_free(bm);
395 }