Rename any instance of scene layer or render layer in code with view layer
[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 extern "C" {
36 #include "DNA_modifier_types.h"
37 #include "DNA_customdata_types.h"
38 #include "DNA_object_types.h"
39 #include "DNA_mesh_types.h"
40 #include "DNA_scene_types.h"
41 #include "DNA_armature_types.h"
42
43 #include "BLI_math.h"
44 #include "BLI_linklist.h"
45
46 #include "BKE_context.h"
47 #include "BKE_customdata.h"
48 #include "BKE_object.h"
49 #include "BKE_global.h"
50 #include "BKE_layer.h"
51 #include "BKE_mesh.h"
52 #include "BKE_scene.h"
53 #include "BKE_DerivedMesh.h"
54
55 #include "ED_armature.h"
56
57 #include "WM_api.h" // XXX hrm, see if we can do without this
58 #include "WM_types.h"
59
60 #include "bmesh.h"
61 #include "bmesh_tools.h"
62 }
63
64 #include "DEG_depsgraph.h"
65
66 #include "collada_utils.h"
67 #include "ExportSettings.h"
68
69 float bc_get_float_value(const COLLADAFW::FloatOrDoubleArray& array, unsigned int index)
70 {
71         if (index >= array.getValuesCount())
72                 return 0.0f;
73
74         if (array.getType() == COLLADAFW::MeshVertexData::DATA_TYPE_FLOAT)
75                 return array.getFloatValues()->getData()[index];
76         else 
77                 return array.getDoubleValues()->getData()[index];
78 }
79
80 // copied from /editors/object/object_relations.c
81 int bc_test_parent_loop(Object *par, Object *ob)
82 {
83         /* test if 'ob' is a parent somewhere in par's parents */
84         
85         if (par == NULL) return 0;
86         if (ob == par) return 1;
87         
88         return bc_test_parent_loop(par->parent, ob);
89 }
90
91 // a shortened version of parent_set_exec()
92 // if is_parent_space is true then ob->obmat will be multiplied by par->obmat before parenting
93 int bc_set_parent(Object *ob, Object *par, bContext *C, bool is_parent_space)
94 {
95         Object workob;
96         Scene *sce = CTX_data_scene(C);
97         EvaluationContext eval_ctx;
98
99         CTX_data_eval_ctx(C, &eval_ctx);
100         
101         if (!par || bc_test_parent_loop(par, ob))
102                 return false;
103
104         ob->parent = par;
105         ob->partype = PAROBJECT;
106
107         ob->parsubstr[0] = 0;
108
109         if (is_parent_space) {
110                 float mat[4][4];
111                 // calc par->obmat
112                 BKE_object_where_is_calc(&eval_ctx, sce, par);
113
114                 // move child obmat into world space
115                 mul_m4_m4m4(mat, par->obmat, ob->obmat);
116                 copy_m4_m4(ob->obmat, mat);
117         }
118         
119         // apply child obmat (i.e. decompose it into rot/loc/size)
120         BKE_object_apply_mat4(ob, ob->obmat, 0, 0);
121
122         // compute parentinv
123         BKE_object_workob_calc_parent(&eval_ctx, sce, ob, &workob);
124         invert_m4_m4(ob->parentinv, workob.obmat);
125
126         DEG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA);
127         DEG_id_tag_update(&par->id, OB_RECALC_OB);
128
129         /** done once after import */
130 #if 0
131         DEG_relations_tag_update(bmain);
132         WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL);
133 #endif
134
135         return true;
136 }
137
138 Object *bc_add_object(Scene *scene, int type, const char *name)
139 {
140         Object *ob = BKE_object_add_only_object(G.main, type, name);
141
142         ob->data = BKE_object_obdata_add_from_type(G.main, type, name);
143         ob->lay = scene->lay;
144         DEG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME);
145
146         /* XXX Collada should use the context scene layer, not the scene one. (dfelinto/gaia). */
147         ViewLayer *view_layer = BKE_view_layer_context_active_PLACEHOLDER(scene);
148
149         LayerCollection *layer_collection = BKE_layer_collection_get_active_ensure(scene, view_layer);
150         BKE_collection_object_add(scene, layer_collection->scene_collection, ob);
151
152         Base *base = BKE_view_layer_base_find(view_layer, ob);
153         BKE_view_layer_base_select(view_layer, base);
154
155         return ob;
156 }
157
158 Mesh *bc_get_mesh_copy(const struct EvaluationContext *eval_ctx, Scene *scene, Object *ob, BC_export_mesh_type export_mesh_type, bool apply_modifiers, bool triangulate)
159 {
160         Mesh *tmpmesh;
161         CustomDataMask mask = CD_MASK_MESH;
162         Mesh *mesh = (Mesh *)ob->data;
163         DerivedMesh *dm = NULL;
164         if (apply_modifiers) {
165                 switch (export_mesh_type) {
166                         case BC_MESH_TYPE_VIEW:
167                         {
168                                 dm = mesh_create_derived_view(eval_ctx, scene, ob, mask);
169                                 break;
170                         }
171                         case BC_MESH_TYPE_RENDER:
172                         {
173                                 dm = mesh_create_derived_render(eval_ctx, scene, ob, mask);
174                                 break;
175                         }
176                 }
177         }
178         else {
179                 dm = mesh_create_derived((Mesh *)ob->data, NULL);
180         }
181
182         tmpmesh = BKE_mesh_add(G.main, "ColladaMesh"); // name is not important here
183         DM_to_mesh(dm, tmpmesh, ob, CD_MASK_MESH, true);
184         tmpmesh->flag = mesh->flag;
185
186         if (triangulate) {
187                 bc_triangulate_mesh(tmpmesh);
188         }
189         BKE_mesh_tessface_ensure(tmpmesh);
190         return tmpmesh;
191 }
192
193 Object *bc_get_assigned_armature(Object *ob)
194 {
195         Object *ob_arm = NULL;
196
197         if (ob->parent && ob->partype == PARSKEL && ob->parent->type == OB_ARMATURE) {
198                 ob_arm = ob->parent;
199         }
200         else {
201                 ModifierData *mod;
202                 for (mod = (ModifierData *)ob->modifiers.first; mod; mod = mod->next) {
203                         if (mod->type == eModifierType_Armature) {
204                                 ob_arm = ((ArmatureModifierData *)mod)->object;
205                         }
206                 }
207         }
208
209         return ob_arm;
210 }
211
212 // Returns the highest selected ancestor
213 // returns NULL if no ancestor is selected
214 // IMPORTANT: This function expects that
215 // all exported objects have set:
216 // ob->id.tag & LIB_TAG_DOIT
217 Object *bc_get_highest_selected_ancestor_or_self(LinkNode *export_set, Object *ob) 
218 {
219         Object *ancestor = ob;
220         while (ob->parent && bc_is_marked(ob->parent)) {
221                 ob = ob->parent;
222                 ancestor = ob;
223         }
224         return ancestor;
225 }
226
227
228 bool bc_is_base_node(LinkNode *export_set, Object *ob)
229 {
230         Object *root = bc_get_highest_selected_ancestor_or_self(export_set, ob);
231         return (root == ob);
232 }
233
234 bool bc_is_in_Export_set(LinkNode *export_set, Object *ob)
235 {
236         return (BLI_linklist_index(export_set, ob) != -1);
237 }
238
239 bool bc_has_object_type(LinkNode *export_set, short obtype)
240 {
241         LinkNode *node;
242         
243         for (node = export_set; node; node = node->next) {
244                 Object *ob = (Object *)node->link;
245                 /* XXX - why is this checking for ob->data? - we could be looking for empties */
246                 if (ob->type == obtype && ob->data) {
247                         return true;
248                 }
249         }
250         return false;
251 }
252
253 int bc_is_marked(Object *ob)
254 {
255         return ob && (ob->id.tag & LIB_TAG_DOIT);
256 }
257
258 void bc_remove_mark(Object *ob)
259 {
260         ob->id.tag &= ~LIB_TAG_DOIT;
261 }
262
263 void bc_set_mark(Object *ob)
264 {
265         ob->id.tag |= LIB_TAG_DOIT;
266 }
267
268 // Use bubble sort algorithm for sorting the export set
269 void bc_bubble_sort_by_Object_name(LinkNode *export_set)
270 {
271         bool sorted = false;
272         LinkNode *node;
273         for (node = export_set; node->next && !sorted; node = node->next) {
274
275                 sorted = true;
276                 
277                 LinkNode *current;
278                 for (current = export_set; current->next; current = current->next) {
279                         Object *a = (Object *)current->link;
280                         Object *b = (Object *)current->next->link;
281
282                         if (strcmp(a->id.name, b->id.name) > 0) {
283                                 current->link       = b;
284                                 current->next->link = a;
285                                 sorted = false;
286                         }
287                         
288                 }
289         }
290 }
291
292 /* Check if a bone is the top most exportable bone in the bone hierarchy. 
293  * When deform_bones_only == false, then only bones with NO parent 
294  * can be root bones. Otherwise the top most deform bones in the hierarchy
295  * are root bones.
296  */
297 bool bc_is_root_bone(Bone *aBone, bool deform_bones_only)
298 {
299         if (deform_bones_only) {
300                 Bone *root = NULL;
301                 Bone *bone = aBone;
302                 while (bone) {
303                         if (!(bone->flag & BONE_NO_DEFORM))
304                                 root = bone;
305                         bone = bone->parent;
306                 }
307                 return (aBone == root);
308         }
309         else
310                 return !(aBone->parent);
311 }
312
313 int bc_get_active_UVLayer(Object *ob)
314 {
315         Mesh *me = (Mesh *)ob->data;
316         return CustomData_get_active_layer_index(&me->fdata, CD_MTFACE);
317 }
318
319 std::string bc_url_encode(std::string data)
320 {
321         /* XXX We probably do not need to do a full encoding.
322          * But in case that is necessary,then it can be added here.
323          */
324         return bc_replace_string(data,"#", "%23");
325 }
326
327 std::string bc_replace_string(std::string data, const std::string& pattern,
328                               const std::string& replacement)
329 {
330         size_t pos = 0;
331         while ((pos = data.find(pattern, pos)) != std::string::npos) {
332                 data.replace(pos, pattern.length(), replacement);
333                 pos += replacement.length();
334         }
335         return data;
336 }
337
338 /**
339  * Calculate a rescale factor such that the imported scene's scale
340  * is preserved. I.e. 1 meter in the import will also be
341  * 1 meter in the current scene.
342  */
343
344 void bc_match_scale(Object *ob, UnitConverter &bc_unit, bool scale_to_scene)
345 {
346         if (scale_to_scene) {
347                 mul_m4_m4m4(ob->obmat, bc_unit.get_scale(), ob->obmat);
348         }
349         mul_m4_m4m4(ob->obmat, bc_unit.get_rotation(), ob->obmat);
350         BKE_object_apply_mat4(ob, ob->obmat, 0, 0);
351 }
352
353 void bc_match_scale(std::vector<Object *> *objects_done, 
354                         UnitConverter &bc_unit,
355                         bool scale_to_scene)
356 {
357         for (std::vector<Object *>::iterator it = objects_done->begin();
358                         it != objects_done->end();
359                         ++it) 
360         {
361                 Object *ob = *it;
362                 if (ob -> parent == NULL) {
363                         bc_match_scale(*it, bc_unit, scale_to_scene);
364                 }
365         }
366 }
367
368 /*
369     Convenience function to get only the needed components of a matrix
370 */
371 void bc_decompose(float mat[4][4], float *loc, float eul[3], float quat[4], float *size)
372 {
373         if (size) {
374                 mat4_to_size(size, mat);
375         }
376
377         if (eul) {
378                 mat4_to_eul(eul, mat);
379         }
380
381         if (quat) {
382                 mat4_to_quat(quat, mat);
383         }
384
385         if (loc) {
386                 copy_v3_v3(loc, mat[3]);
387         }
388 }
389
390 void bc_triangulate_mesh(Mesh *me)
391 {
392         bool use_beauty  = false;
393         bool tag_only    = false;
394         int  quad_method = MOD_TRIANGULATE_QUAD_SHORTEDGE; /* XXX: The triangulation method selection could be offered in the UI */
395
396         const struct BMeshCreateParams bm_create_params = {0};
397         BMesh *bm = BM_mesh_create(
398                 &bm_mesh_allocsize_default,
399                 &bm_create_params);
400         BMeshFromMeshParams bm_from_me_params = {0};
401         bm_from_me_params.calc_face_normal = true;
402         BM_mesh_bm_from_me(bm, me, &bm_from_me_params);
403         BM_mesh_triangulate(bm, quad_method, use_beauty, tag_only, NULL, NULL, NULL);
404
405         BMeshToMeshParams bm_to_me_params = {0};
406         BM_mesh_bm_to_me(bm, me, &bm_to_me_params);
407         BM_mesh_free(bm);
408 }
409
410 /*
411  * A bone is a leaf when it has no children or all children are not connected.
412  */
413 bool bc_is_leaf_bone(Bone *bone)
414 {
415         for (Bone *child = (Bone *)bone->childbase.first; child; child = child->next) {
416                 if (child->flag & BONE_CONNECTED)
417                         return false;
418         }
419         return true;
420 }
421
422 EditBone *bc_get_edit_bone(bArmature * armature, char *name) {
423         EditBone  *eBone;
424
425         for (eBone = (EditBone *)armature->edbo->first; eBone; eBone = eBone->next) {
426                 if (STREQ(name, eBone->name))
427                         return eBone;
428         }
429
430         return NULL;
431
432 }
433 int bc_set_layer(int bitfield, int layer)
434 {
435         return bc_set_layer(bitfield, layer, true); /* enable */
436 }
437
438 int bc_set_layer(int bitfield, int layer, bool enable)
439 {
440         int bit = 1u << layer;
441
442         if (enable)
443                 bitfield |= bit;
444         else
445                 bitfield &= ~bit;
446
447         return bitfield;
448 }
449
450 /*
451  | This method creates a new extension map when needed.
452  | Note: The ~BoneExtensionManager destructor takes care
453  | to delete the created maps when the manager is removed.
454 */
455 BoneExtensionMap &BoneExtensionManager::getExtensionMap(bArmature *armature)
456 {
457         std::string key = armature->id.name;
458         BoneExtensionMap *result = extended_bone_maps[key];
459         if (result == NULL)
460         {
461                 result = new BoneExtensionMap();
462                 extended_bone_maps[key] = result;
463         }
464         return *result;
465 }
466
467 BoneExtensionManager::~BoneExtensionManager()
468 {
469         std::map<std::string, BoneExtensionMap *>::iterator map_it;
470         for (map_it = extended_bone_maps.begin(); map_it != extended_bone_maps.end(); ++map_it)
471         {
472                 BoneExtensionMap *extended_bones = map_it->second;
473                 for (BoneExtensionMap::iterator ext_it = extended_bones->begin(); ext_it != extended_bones->end(); ++ext_it) {
474                         if (ext_it->second != NULL)
475                                 delete ext_it->second;
476                 }
477                 extended_bones->clear();
478                 delete extended_bones;
479         }
480 }
481
482 /**
483  * BoneExtended is a helper class needed for the Bone chain finder
484  * See ArmatureImporter::fix_leaf_bones()
485  * and ArmatureImporter::connect_bone_chains()
486  */
487
488 BoneExtended::BoneExtended(EditBone *aBone)
489 {
490         this->set_name(aBone->name);
491         this->chain_length = 0;
492         this->is_leaf = false;
493         this->tail[0] = 0.0f;
494         this->tail[1] = 0.5f;
495         this->tail[2] = 0.0f;
496         this->use_connect = -1;
497         this->roll = 0;
498         this->bone_layers = 0;
499
500         this->has_custom_tail = false;
501         this->has_custom_roll = false;
502 }
503
504 char *BoneExtended::get_name()
505 {
506         return name;
507 }
508
509 void BoneExtended::set_name(char *aName)
510 {
511         BLI_strncpy(name, aName, MAXBONENAME);
512 }
513
514 int BoneExtended::get_chain_length()
515 {
516         return chain_length;
517 }
518
519 void BoneExtended::set_chain_length(const int aLength)
520 {
521         chain_length = aLength;
522 }
523
524 void BoneExtended::set_leaf_bone(bool state)
525 {
526         is_leaf = state;
527 }
528
529 bool BoneExtended::is_leaf_bone()
530 {
531         return is_leaf;
532 }
533
534 void BoneExtended::set_roll(float roll)
535 {
536         this->roll = roll;
537         this->has_custom_roll = true;
538 }
539
540 bool BoneExtended::has_roll()
541 {
542         return this->has_custom_roll;
543 }
544
545 float BoneExtended::get_roll()
546 {
547         return this->roll;
548 }
549
550 void BoneExtended::set_tail(float vec[])
551 {
552         this->tail[0] = vec[0];
553         this->tail[1] = vec[1];
554         this->tail[2] = vec[2];
555         this->has_custom_tail = true;
556 }
557
558 bool BoneExtended::has_tail()
559 {
560         return this->has_custom_tail;
561 }
562
563 float *BoneExtended::get_tail()
564 {
565         return this->tail;
566 }
567
568 inline bool isInteger(const std::string & s)
569 {
570         if (s.empty() || ((!isdigit(s[0])) && (s[0] != '-') && (s[0] != '+'))) return false;
571
572         char * p;
573         strtol(s.c_str(), &p, 10);
574
575         return (*p == 0);
576 }
577
578 void BoneExtended::set_bone_layers(std::string layerString, std::vector<std::string> &layer_labels)
579 {
580         std::stringstream ss(layerString);
581         std::string layer;
582         int pos;
583
584         while (ss >> layer) {
585
586                 /* Blender uses numbers to specify layers*/
587                 if (isInteger(layer))
588                 {
589                         pos = atoi(layer.c_str());
590                         if (pos >= 0 && pos < 32) {
591                                 this->bone_layers = bc_set_layer(this->bone_layers, pos);
592                                 continue;
593                         }
594                 }
595
596                 /* layer uses labels (not supported by blender). Map to layer numbers:*/
597                 pos = find(layer_labels.begin(), layer_labels.end(), layer) - layer_labels.begin();
598                 if (pos >= layer_labels.size()) {
599                         layer_labels.push_back(layer); /* remember layer number for future usage*/
600                 }
601
602                 if (pos > 31)
603                 {
604                         fprintf(stderr, "Too many layers in Import. Layer %s mapped to Blender layer 31\n", layer.c_str());
605                         pos = 31;
606                 }
607
608                 /* If numeric layers and labeled layers are used in parallel (unlikely),
609                  * we get a potential mixup. Just leave as is for now.
610                  */
611                 this->bone_layers = bc_set_layer(this->bone_layers, pos);
612
613         }
614 }
615
616 std::string BoneExtended::get_bone_layers(int bitfield)
617 {
618         std::string result = "";
619         std::string sep = "";
620         int bit = 1u;
621
622         std::ostringstream ss;
623         for (int i = 0; i < 32; i++)
624         {
625                 if (bit & bitfield)
626                 {
627                         ss << sep << i;
628                         sep = " ";
629                 }
630                 bit = bit << 1;
631         }
632         return ss.str();
633 }
634
635 int BoneExtended::get_bone_layers()
636 {
637         return (bone_layers == 0) ? 1 : bone_layers; // ensure that the bone is in at least one bone layer!
638 }
639
640
641 void BoneExtended::set_use_connect(int use_connect)
642 {
643         this->use_connect = use_connect;
644 }
645
646 int BoneExtended::get_use_connect()
647 {
648         return this->use_connect;
649 }
650
651 /**
652 * Stores a 4*4 matrix as a custom bone property array of size 16
653 */
654 void bc_set_IDPropertyMatrix(EditBone *ebone, const char *key, float mat[4][4])
655 {
656         IDProperty *idgroup = (IDProperty *)ebone->prop;
657         if (idgroup == NULL)
658         {
659                 IDPropertyTemplate val = { 0 };
660                 idgroup = IDP_New(IDP_GROUP, &val, "RNA_EditBone ID properties");
661                 ebone->prop = idgroup;
662         }
663
664         IDPropertyTemplate val = { 0 };
665         val.array.len = 16;
666         val.array.type = IDP_FLOAT;
667
668         IDProperty *data = IDP_New(IDP_ARRAY, &val, key);
669         float *array = (float *)IDP_Array(data);
670         for (int i = 0; i < 4; i++)
671                 for (int j = 0; j < 4; j++)
672                         array[4 * i + j] = mat[i][j];
673
674         IDP_AddToGroup(idgroup, data);
675 }
676
677 #if 0
678 /**
679 * Stores a Float value as a custom bone property
680 *
681 * Note: This function is currently not needed. Keep for future usage
682 */
683 static void bc_set_IDProperty(EditBone *ebone, const char *key, float value)
684 {
685         if (ebone->prop == NULL)
686         {
687                 IDPropertyTemplate val = { 0 };
688                 ebone->prop = IDP_New(IDP_GROUP, &val, "RNA_EditBone ID properties");
689         }
690
691         IDProperty *pgroup = (IDProperty *)ebone->prop;
692         IDPropertyTemplate val = { 0 };
693         IDProperty *prop = IDP_New(IDP_FLOAT, &val, key);
694         IDP_Float(prop) = value;
695         IDP_AddToGroup(pgroup, prop);
696
697 }
698 #endif
699
700 /*
701 * Get a custom property when it exists.
702 * This function is also used to check if a property exists.
703 */
704 IDProperty *bc_get_IDProperty(Bone *bone, std::string key)
705 {
706         return (bone->prop == NULL) ? NULL : IDP_GetPropertyFromGroup(bone->prop, key.c_str());
707 }
708
709 /**
710 * Read a custom bone property and convert to float
711 * Return def if the property does not exist.
712 */
713 float bc_get_property(Bone *bone, std::string key, float def)
714 {
715         float result = def;
716         IDProperty *property = bc_get_IDProperty(bone, key);
717         if (property) {
718                 switch (property->type) {
719                 case IDP_INT:
720                         result = (float)(IDP_Int(property));
721                         break;
722                 case IDP_FLOAT:
723                         result = (float)(IDP_Float(property));
724                         break;
725                 case IDP_DOUBLE:
726                         result = (float)(IDP_Double(property));
727                         break;
728                 default:
729                         result = def;
730                 }
731         }
732         return result;
733 }
734
735 /**
736 * Read a custom bone property and convert to matrix
737 * Return true if conversion was succesfull
738
739 * Return false if:
740 * - the property does not exist
741 * - is not an array of size 16
742 */
743 bool bc_get_property_matrix(Bone *bone, std::string key, float mat[4][4])
744 {
745         IDProperty *property = bc_get_IDProperty(bone, key);
746         if (property && property->type == IDP_ARRAY && property->len == 16) {
747                 float *array = (float *)IDP_Array(property);
748                 for (int i = 0; i < 4; i++)
749                         for (int j = 0; j < 4; j++)
750                                 mat[i][j] = array[4 * i + j];
751                 return true;
752         }
753         return false;
754 }
755
756 /**
757 * get a vector that is stored in 3 custom properties (used in Blender <= 2.78)
758 */
759 void bc_get_property_vector(Bone *bone, std::string key, float val[3], const float def[3])
760 {
761         val[0] = bc_get_property(bone, key + "_x", def[0]);
762         val[1] = bc_get_property(bone, key + "_y", def[1]);
763         val[2] = bc_get_property(bone, key + "_z", def[2]);
764 }
765
766 /**
767 * Check if vector exist stored in 3 custom properties (used in Blender <= 2.78)
768 */
769 static bool has_custom_props(Bone *bone, bool enabled, std::string key)
770 {
771         if (!enabled)
772                 return false;
773
774         return (bc_get_IDProperty(bone, key + "_x")
775                 ||      bc_get_IDProperty(bone, key + "_y")
776                 ||      bc_get_IDProperty(bone, key + "_z"));
777
778 }
779
780 /**
781 * Check if custom information about bind matrix exists and modify the from_mat
782 * accordingly.
783 *
784 * Note: This is old style for Blender <= 2.78 only kept for compatibility
785 */
786 void bc_create_restpose_mat(const ExportSettings *export_settings, Bone *bone, float to_mat[4][4], float from_mat[4][4], bool use_local_space)
787 {
788         float loc[3];
789         float rot[3];
790         float scale[3];
791         static const float V0[3] = { 0, 0, 0 };
792
793         if (!has_custom_props(bone, export_settings->keep_bind_info, "restpose_loc") &&
794                 !has_custom_props(bone, export_settings->keep_bind_info, "restpose_rot") &&
795                 !has_custom_props(bone, export_settings->keep_bind_info, "restpose_scale"))
796         {
797                 /* No need */
798                 copy_m4_m4(to_mat, from_mat);
799                 return;
800         }
801
802         bc_decompose(from_mat, loc, rot, NULL, scale);
803         loc_eulO_size_to_mat4(to_mat, loc, rot, scale, 6);
804
805         if (export_settings->keep_bind_info) {
806                 bc_get_property_vector(bone, "restpose_loc", loc, loc);
807
808                 if (use_local_space && bone->parent) {
809                         Bone *b = bone;
810                         while (b->parent) {
811                                 b = b->parent;
812                                 float ploc[3];
813                                 bc_get_property_vector(b, "restpose_loc", ploc, V0);
814                                 loc[0] += ploc[0];
815                                 loc[1] += ploc[1];
816                                 loc[2] += ploc[2];
817                         }
818                 }
819         }
820
821         if (export_settings->keep_bind_info) {
822                 if (bc_get_IDProperty(bone, "restpose_rot_x"))
823                     rot[0] = DEG2RADF(bc_get_property(bone, "restpose_rot_x", 0));
824                 if (bc_get_IDProperty(bone, "restpose_rot_y"))
825                         rot[1] = DEG2RADF(bc_get_property(bone, "restpose_rot_y", 0));
826                 if (bc_get_IDProperty(bone, "restpose_rot_z"))
827                         rot[2] = DEG2RADF(bc_get_property(bone, "restpose_rot_z", 0));
828         }
829
830         if (export_settings->keep_bind_info) {
831                 bc_get_property_vector(bone, "restpose_scale", scale, scale);
832         }
833
834         loc_eulO_size_to_mat4(to_mat, loc, rot, scale, 6);
835
836 }
837
838 /*
839     Make 4*4 matrices better readable
840 */
841 void bc_sanitize_mat(float mat[4][4], int precision)
842 {
843         for (int i = 0; i < 4; i++)
844                 for (int j = 0; j < 4; j++)
845                         mat[i][j] = double_round(mat[i][j], precision);
846 }