update Collada Importer: reworked export and import of Materials
[blender.git] / source / blender / collada / collada_utils.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 /* COLLADABU_ASSERT, may be able to remove later */
22 #include "COLLADABUPlatform.h"
23
24 #include "COLLADAFWGeometry.h"
25 #include "COLLADAFWMeshPrimitive.h"
26 #include "COLLADAFWMeshVertexData.h"
27
28 #include <set>
29 #include <string>
30 extern "C" {
31 #include "DNA_modifier_types.h"
32 #include "DNA_customdata_types.h"
33 #include "DNA_key_types.h"
34 #include "DNA_object_types.h"
35 #include "DNA_constraint_types.h"
36 #include "DNA_mesh_types.h"
37 #include "DNA_scene_types.h"
38 #include "DNA_armature_types.h"
39
40 #include "BLI_math.h"
41 #include "BLI_linklist.h"
42 #include "BLI_listbase.h"
43
44 #include "BKE_action.h"
45 #include "BKE_context.h"
46 #include "BKE_customdata.h"
47 #include "BKE_constraint.h"
48 #include "BKE_key.h"
49 #include "BKE_material.h"
50 #include "BKE_node.h"
51 #include "BKE_object.h"
52 #include "BKE_global.h"
53 #include "BKE_layer.h"
54 #include "BKE_library.h"
55 #include "BKE_mesh.h"
56 #include "BKE_mesh_runtime.h"
57 #include "BKE_object.h"
58 #include "BKE_scene.h"
59
60 #include "ED_armature.h"
61 #include "ED_screen.h"
62 #include "ED_node.h"
63 #include "ED_object.h"
64
65 #include "MEM_guardedalloc.h"
66
67 #include "WM_api.h" /* XXX hrm, see if we can do without this */
68 #include "WM_types.h"
69
70 #include "bmesh.h"
71 #include "bmesh_tools.h"
72
73 #include "DEG_depsgraph.h"
74 #include "DEG_depsgraph_query.h"
75 #if 0
76 #  include "NOD_common.h"
77 #endif
78 }
79
80 #include "collada_utils.h"
81 #include "ExportSettings.h"
82 #include "BlenderContext.h"
83
84 float bc_get_float_value(const COLLADAFW::FloatOrDoubleArray &array, unsigned int index)
85 {
86   if (index >= array.getValuesCount()) {
87     return 0.0f;
88   }
89
90   if (array.getType() == COLLADAFW::MeshVertexData::DATA_TYPE_FLOAT) {
91     return array.getFloatValues()->getData()[index];
92   }
93   else {
94     return array.getDoubleValues()->getData()[index];
95   }
96 }
97
98 /* copied from /editors/object/object_relations.c */
99 int bc_test_parent_loop(Object *par, Object *ob)
100 {
101   /* test if 'ob' is a parent somewhere in par's parents */
102
103   if (par == NULL) {
104     return 0;
105   }
106   if (ob == par) {
107     return 1;
108   }
109
110   return bc_test_parent_loop(par->parent, ob);
111 }
112
113 bool bc_validateConstraints(bConstraint *con)
114 {
115   const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
116
117   /* these we can skip completely (invalid constraints...) */
118   if (cti == NULL) {
119     return false;
120   }
121   if (con->flag & (CONSTRAINT_DISABLE | CONSTRAINT_OFF)) {
122     return false;
123   }
124
125   /* these constraints can't be evaluated anyway */
126   if (cti->evaluate_constraint == NULL) {
127     return false;
128   }
129
130   /* influence == 0 should be ignored */
131   if (con->enforce == 0.0f) {
132     return false;
133   }
134
135   /* validation passed */
136   return true;
137 }
138
139 bool bc_set_parent(Object *ob, Object *par, bContext *C, bool is_parent_space)
140 {
141   Scene *scene = CTX_data_scene(C);
142   int partype = PAR_OBJECT;
143   const bool xmirror = false;
144   const bool keep_transform = false;
145
146   if (par && is_parent_space) {
147     mul_m4_m4m4(ob->obmat, par->obmat, ob->obmat);
148   }
149
150   bool ok = ED_object_parent_set(NULL, C, scene, ob, par, partype, xmirror, keep_transform, NULL);
151   return ok;
152 }
153
154 std::vector<bAction *> bc_getSceneActions(const bContext *C, Object *ob, bool all_actions)
155 {
156   std::vector<bAction *> actions;
157   if (all_actions) {
158     Main *bmain = CTX_data_main(C);
159     ID *id;
160
161     for (id = (ID *)bmain->actions.first; id; id = (ID *)(id->next)) {
162       bAction *act = (bAction *)id;
163       /* XXX This currently creates too many actions.
164        * TODO Need to check if the action is compatible to the given object. */
165       actions.push_back(act);
166     }
167   }
168   else {
169     bAction *action = bc_getSceneObjectAction(ob);
170     actions.push_back(action);
171   }
172
173   return actions;
174 }
175
176 std::string bc_get_action_id(std::string action_name,
177                              std::string ob_name,
178                              std::string channel_type,
179                              std::string axis_name,
180                              std::string axis_separator)
181 {
182   std::string result = action_name + "_" + channel_type;
183   if (ob_name.length() > 0) {
184     result = ob_name + "_" + result;
185   }
186   if (axis_name.length() > 0) {
187     result += axis_separator + axis_name;
188   }
189   return translate_id(result);
190 }
191
192 void bc_update_scene(BlenderContext &blender_context, float ctime)
193 {
194   Main *bmain = blender_context.get_main();
195   Scene *scene = blender_context.get_scene();
196   Depsgraph *depsgraph = blender_context.get_depsgraph();
197
198   /* See remark in physics_fluid.c lines 395...) */
199   // BKE_scene_update_for_newframe(ev_context, bmain, scene, scene->lay);
200   BKE_scene_frame_set(scene, ctime);
201   ED_update_for_newframe(bmain, depsgraph);
202 }
203
204 Object *bc_add_object(Main *bmain, Scene *scene, ViewLayer *view_layer, int type, const char *name)
205 {
206   Object *ob = BKE_object_add_only_object(bmain, type, name);
207
208   ob->data = BKE_object_obdata_add_from_type(bmain, type, name);
209   DEG_id_tag_update(&ob->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY | ID_RECALC_ANIMATION);
210
211   LayerCollection *layer_collection = BKE_layer_collection_get_active(view_layer);
212   BKE_collection_object_add(bmain, layer_collection->collection, ob);
213
214   Base *base = BKE_view_layer_base_find(view_layer, ob);
215   /* TODO: is setting active needed? */
216   BKE_view_layer_base_select_and_set_active(view_layer, base);
217
218   return ob;
219 }
220
221 Mesh *bc_get_mesh_copy(BlenderContext &blender_context,
222                        Object *ob,
223                        BC_export_mesh_type export_mesh_type,
224                        bool apply_modifiers,
225                        bool triangulate)
226 {
227   CustomData_MeshMasks mask = CD_MASK_MESH;
228   Mesh *tmpmesh = NULL;
229   if (apply_modifiers) {
230 #if 0 /* Not supported by new system currently... */
231     switch (export_mesh_type) {
232       case BC_MESH_TYPE_VIEW: {
233         dm = mesh_create_derived_view(depsgraph, scene, ob, &mask);
234         break;
235       }
236       case BC_MESH_TYPE_RENDER: {
237         dm = mesh_create_derived_render(depsgraph, scene, ob, &mask);
238         break;
239       }
240     }
241 #else
242     Depsgraph *depsgraph = blender_context.get_depsgraph();
243     Scene *scene_eval = blender_context.get_evaluated_scene();
244     Object *ob_eval = blender_context.get_evaluated_object(ob);
245     tmpmesh = mesh_get_eval_final(depsgraph, scene_eval, ob_eval, &mask);
246 #endif
247   }
248   else {
249     tmpmesh = (Mesh *)ob->data;
250   }
251
252   BKE_id_copy_ex(NULL, &tmpmesh->id, (ID **)&tmpmesh, LIB_ID_COPY_LOCALIZE);
253
254   if (triangulate) {
255     bc_triangulate_mesh(tmpmesh);
256   }
257   BKE_mesh_tessface_ensure(tmpmesh);
258   return tmpmesh;
259 }
260
261 Object *bc_get_assigned_armature(Object *ob)
262 {
263   Object *ob_arm = NULL;
264
265   if (ob->parent && ob->partype == PARSKEL && ob->parent->type == OB_ARMATURE) {
266     ob_arm = ob->parent;
267   }
268   else {
269     ModifierData *mod;
270     for (mod = (ModifierData *)ob->modifiers.first; mod; mod = mod->next) {
271       if (mod->type == eModifierType_Armature) {
272         ob_arm = ((ArmatureModifierData *)mod)->object;
273       }
274     }
275   }
276
277   return ob_arm;
278 }
279
280 bool bc_has_object_type(LinkNode *export_set, short obtype)
281 {
282   LinkNode *node;
283
284   for (node = export_set; node; node = node->next) {
285     Object *ob = (Object *)node->link;
286     /* XXX - why is this checking for ob->data? - we could be looking for empties */
287     if (ob->type == obtype && ob->data) {
288       return true;
289     }
290   }
291   return false;
292 }
293
294 /* Use bubble sort algorithm for sorting the export set */
295 void bc_bubble_sort_by_Object_name(LinkNode *export_set)
296 {
297   bool sorted = false;
298   LinkNode *node;
299   for (node = export_set; node->next && !sorted; node = node->next) {
300
301     sorted = true;
302
303     LinkNode *current;
304     for (current = export_set; current->next; current = current->next) {
305       Object *a = (Object *)current->link;
306       Object *b = (Object *)current->next->link;
307
308       if (strcmp(a->id.name, b->id.name) > 0) {
309         current->link = b;
310         current->next->link = a;
311         sorted = false;
312       }
313     }
314   }
315 }
316
317 /* Check if a bone is the top most exportable bone in the bone hierarchy.
318  * When deform_bones_only == false, then only bones with NO parent
319  * can be root bones. Otherwise the top most deform bones in the hierarchy
320  * are root bones.
321  */
322 bool bc_is_root_bone(Bone *aBone, bool deform_bones_only)
323 {
324   if (deform_bones_only) {
325     Bone *root = NULL;
326     Bone *bone = aBone;
327     while (bone) {
328       if (!(bone->flag & BONE_NO_DEFORM)) {
329         root = bone;
330       }
331       bone = bone->parent;
332     }
333     return (aBone == root);
334   }
335   else {
336     return !(aBone->parent);
337   }
338 }
339
340 int bc_get_active_UVLayer(Object *ob)
341 {
342   Mesh *me = (Mesh *)ob->data;
343   return CustomData_get_active_layer_index(&me->ldata, CD_MLOOPUV);
344 }
345
346 std::string bc_url_encode(std::string data)
347 {
348   /* XXX We probably do not need to do a full encoding.
349    * But in case that is necessary,then it can be added here.
350    */
351   return bc_replace_string(data, "#", "%23");
352 }
353
354 std::string bc_replace_string(std::string data,
355                               const std::string &pattern,
356                               const std::string &replacement)
357 {
358   size_t pos = 0;
359   while ((pos = data.find(pattern, pos)) != std::string::npos) {
360     data.replace(pos, pattern.length(), replacement);
361     pos += replacement.length();
362   }
363   return data;
364 }
365
366 /**
367  * Calculate a rescale factor such that the imported scene's scale
368  * is preserved. I.e. 1 meter in the import will also be
369  * 1 meter in the current scene.
370  */
371
372 void bc_match_scale(Object *ob, UnitConverter &bc_unit, bool scale_to_scene)
373 {
374   if (scale_to_scene) {
375     mul_m4_m4m4(ob->obmat, bc_unit.get_scale(), ob->obmat);
376   }
377   mul_m4_m4m4(ob->obmat, bc_unit.get_rotation(), ob->obmat);
378   BKE_object_apply_mat4(ob, ob->obmat, 0, 0);
379 }
380
381 void bc_match_scale(std::vector<Object *> *objects_done,
382                     UnitConverter &bc_unit,
383                     bool scale_to_scene)
384 {
385   for (std::vector<Object *>::iterator it = objects_done->begin(); it != objects_done->end();
386        ++it) {
387     Object *ob = *it;
388     if (ob->parent == NULL) {
389       bc_match_scale(*it, bc_unit, scale_to_scene);
390     }
391   }
392 }
393
394 /*
395  * Convenience function to get only the needed components of a matrix
396  */
397 void bc_decompose(float mat[4][4], float *loc, float eul[3], float quat[4], float *size)
398 {
399   if (size) {
400     mat4_to_size(size, mat);
401   }
402
403   if (eul) {
404     mat4_to_eul(eul, mat);
405   }
406
407   if (quat) {
408     mat4_to_quat(quat, mat);
409   }
410
411   if (loc) {
412     copy_v3_v3(loc, mat[3]);
413   }
414 }
415
416 /*
417  * Create rotation_quaternion from a delta rotation and a reference quat
418  *
419  * Input:
420  * mat_from: The rotation matrix before rotation
421  * mat_to  : The rotation matrix after rotation
422  * qref    : the quat corresponding to mat_from
423  *
424  * Output:
425  * rot     : the calculated result (quaternion)
426  */
427 void bc_rotate_from_reference_quat(float quat_to[4], float quat_from[4], float mat_to[4][4])
428 {
429   float qd[4];
430   float matd[4][4];
431   float mati[4][4];
432   float mat_from[4][4];
433   quat_to_mat4(mat_from, quat_from);
434
435   /* Calculate the difference matrix matd between mat_from and mat_to */
436   invert_m4_m4(mati, mat_from);
437   mul_m4_m4m4(matd, mati, mat_to);
438
439   mat4_to_quat(qd, matd);
440
441   mul_qt_qtqt(quat_to, qd, quat_from); /* rot is the final rotation corresponding to mat_to */
442 }
443
444 void bc_triangulate_mesh(Mesh *me)
445 {
446   bool use_beauty = false;
447   bool tag_only = false;
448
449   /* XXX: The triangulation method selection could be offered in the UI. */
450   int quad_method = MOD_TRIANGULATE_QUAD_SHORTEDGE;
451
452   const struct BMeshCreateParams bm_create_params = {0};
453   BMesh *bm = BM_mesh_create(&bm_mesh_allocsize_default, &bm_create_params);
454   BMeshFromMeshParams bm_from_me_params = {0};
455   bm_from_me_params.calc_face_normal = true;
456   BM_mesh_bm_from_me(bm, me, &bm_from_me_params);
457   BM_mesh_triangulate(bm, quad_method, use_beauty, 4, tag_only, NULL, NULL, NULL);
458
459   BMeshToMeshParams bm_to_me_params = {0};
460   bm_to_me_params.calc_object_remap = false;
461   BM_mesh_bm_to_me(NULL, bm, me, &bm_to_me_params);
462   BM_mesh_free(bm);
463 }
464
465 /*
466  * A bone is a leaf when it has no children or all children are not connected.
467  */
468 bool bc_is_leaf_bone(Bone *bone)
469 {
470   for (Bone *child = (Bone *)bone->childbase.first; child; child = child->next) {
471     if (child->flag & BONE_CONNECTED) {
472       return false;
473     }
474   }
475   return true;
476 }
477
478 EditBone *bc_get_edit_bone(bArmature *armature, char *name)
479 {
480   EditBone *eBone;
481
482   for (eBone = (EditBone *)armature->edbo->first; eBone; eBone = eBone->next) {
483     if (STREQ(name, eBone->name)) {
484       return eBone;
485     }
486   }
487
488   return NULL;
489 }
490 int bc_set_layer(int bitfield, int layer)
491 {
492   return bc_set_layer(bitfield, layer, true); /* enable */
493 }
494
495 int bc_set_layer(int bitfield, int layer, bool enable)
496 {
497   int bit = 1u << layer;
498
499   if (enable) {
500     bitfield |= bit;
501   }
502   else {
503     bitfield &= ~bit;
504   }
505
506   return bitfield;
507 }
508
509 /**
510  * This method creates a new extension map when needed.
511  * \note The ~BoneExtensionManager destructor takes care
512  * to delete the created maps when the manager is removed.
513  */
514 BoneExtensionMap &BoneExtensionManager::getExtensionMap(bArmature *armature)
515 {
516   std::string key = armature->id.name;
517   BoneExtensionMap *result = extended_bone_maps[key];
518   if (result == NULL) {
519     result = new BoneExtensionMap();
520     extended_bone_maps[key] = result;
521   }
522   return *result;
523 }
524
525 BoneExtensionManager::~BoneExtensionManager()
526 {
527   std::map<std::string, BoneExtensionMap *>::iterator map_it;
528   for (map_it = extended_bone_maps.begin(); map_it != extended_bone_maps.end(); ++map_it) {
529     BoneExtensionMap *extended_bones = map_it->second;
530     for (BoneExtensionMap::iterator ext_it = extended_bones->begin();
531          ext_it != extended_bones->end();
532          ++ext_it) {
533       if (ext_it->second != NULL) {
534         delete ext_it->second;
535       }
536     }
537     extended_bones->clear();
538     delete extended_bones;
539   }
540 }
541
542 /**
543  * BoneExtended is a helper class needed for the Bone chain finder
544  * See ArmatureImporter::fix_leaf_bones()
545  * and ArmatureImporter::connect_bone_chains()
546  */
547
548 BoneExtended::BoneExtended(EditBone *aBone)
549 {
550   this->set_name(aBone->name);
551   this->chain_length = 0;
552   this->is_leaf = false;
553   this->tail[0] = 0.0f;
554   this->tail[1] = 0.5f;
555   this->tail[2] = 0.0f;
556   this->use_connect = -1;
557   this->roll = 0;
558   this->bone_layers = 0;
559
560   this->has_custom_tail = false;
561   this->has_custom_roll = false;
562 }
563
564 char *BoneExtended::get_name()
565 {
566   return name;
567 }
568
569 void BoneExtended::set_name(char *aName)
570 {
571   BLI_strncpy(name, aName, MAXBONENAME);
572 }
573
574 int BoneExtended::get_chain_length()
575 {
576   return chain_length;
577 }
578
579 void BoneExtended::set_chain_length(const int aLength)
580 {
581   chain_length = aLength;
582 }
583
584 void BoneExtended::set_leaf_bone(bool state)
585 {
586   is_leaf = state;
587 }
588
589 bool BoneExtended::is_leaf_bone()
590 {
591   return is_leaf;
592 }
593
594 void BoneExtended::set_roll(float roll)
595 {
596   this->roll = roll;
597   this->has_custom_roll = true;
598 }
599
600 bool BoneExtended::has_roll()
601 {
602   return this->has_custom_roll;
603 }
604
605 float BoneExtended::get_roll()
606 {
607   return this->roll;
608 }
609
610 void BoneExtended::set_tail(float vec[])
611 {
612   this->tail[0] = vec[0];
613   this->tail[1] = vec[1];
614   this->tail[2] = vec[2];
615   this->has_custom_tail = true;
616 }
617
618 bool BoneExtended::has_tail()
619 {
620   return this->has_custom_tail;
621 }
622
623 float *BoneExtended::get_tail()
624 {
625   return this->tail;
626 }
627
628 inline bool isInteger(const std::string &s)
629 {
630   if (s.empty() || ((!isdigit(s[0])) && (s[0] != '-') && (s[0] != '+'))) {
631     return false;
632   }
633
634   char *p;
635   strtol(s.c_str(), &p, 10);
636
637   return (*p == 0);
638 }
639
640 void BoneExtended::set_bone_layers(std::string layerString, std::vector<std::string> &layer_labels)
641 {
642   std::stringstream ss(layerString);
643   std::string layer;
644   int pos;
645
646   while (ss >> layer) {
647
648     /* Blender uses numbers to specify layers*/
649     if (isInteger(layer)) {
650       pos = atoi(layer.c_str());
651       if (pos >= 0 && pos < 32) {
652         this->bone_layers = bc_set_layer(this->bone_layers, pos);
653         continue;
654       }
655     }
656
657     /* layer uses labels (not supported by blender). Map to layer numbers:*/
658     pos = find(layer_labels.begin(), layer_labels.end(), layer) - layer_labels.begin();
659     if (pos >= layer_labels.size()) {
660       layer_labels.push_back(layer); /* remember layer number for future usage*/
661     }
662
663     if (pos > 31) {
664       fprintf(stderr,
665               "Too many layers in Import. Layer %s mapped to Blender layer 31\n",
666               layer.c_str());
667       pos = 31;
668     }
669
670     /* If numeric layers and labeled layers are used in parallel (unlikely),
671      * we get a potential mixup. Just leave as is for now.
672      */
673     this->bone_layers = bc_set_layer(this->bone_layers, pos);
674   }
675 }
676
677 std::string BoneExtended::get_bone_layers(int bitfield)
678 {
679   std::string result = "";
680   std::string sep = "";
681   int bit = 1u;
682
683   std::ostringstream ss;
684   for (int i = 0; i < 32; i++) {
685     if (bit & bitfield) {
686       ss << sep << i;
687       sep = " ";
688     }
689     bit = bit << 1;
690   }
691   return ss.str();
692 }
693
694 int BoneExtended::get_bone_layers()
695 {
696   /* ensure that the bone is in at least one bone layer! */
697   return (bone_layers == 0) ? 1 : bone_layers;
698 }
699
700 void BoneExtended::set_use_connect(int use_connect)
701 {
702   this->use_connect = use_connect;
703 }
704
705 int BoneExtended::get_use_connect()
706 {
707   return this->use_connect;
708 }
709
710 /**
711  * Stores a 4*4 matrix as a custom bone property array of size 16
712  */
713 void bc_set_IDPropertyMatrix(EditBone *ebone, const char *key, float mat[4][4])
714 {
715   IDProperty *idgroup = (IDProperty *)ebone->prop;
716   if (idgroup == NULL) {
717     IDPropertyTemplate val = {0};
718     idgroup = IDP_New(IDP_GROUP, &val, "RNA_EditBone ID properties");
719     ebone->prop = idgroup;
720   }
721
722   IDPropertyTemplate val = {0};
723   val.array.len = 16;
724   val.array.type = IDP_FLOAT;
725
726   IDProperty *data = IDP_New(IDP_ARRAY, &val, key);
727   float *array = (float *)IDP_Array(data);
728   for (int i = 0; i < 4; i++) {
729     for (int j = 0; j < 4; j++) {
730       array[4 * i + j] = mat[i][j];
731     }
732   }
733
734   IDP_AddToGroup(idgroup, data);
735 }
736
737 #if 0
738 /**
739  * Stores a Float value as a custom bone property
740  *
741  * Note: This function is currently not needed. Keep for future usage
742  */
743 static void bc_set_IDProperty(EditBone *ebone, const char *key, float value)
744 {
745   if (ebone->prop == NULL) {
746     IDPropertyTemplate val = {0};
747     ebone->prop = IDP_New(IDP_GROUP, &val, "RNA_EditBone ID properties");
748   }
749
750   IDProperty *pgroup = (IDProperty *)ebone->prop;
751   IDPropertyTemplate val = {0};
752   IDProperty *prop = IDP_New(IDP_FLOAT, &val, key);
753   IDP_Float(prop) = value;
754   IDP_AddToGroup(pgroup, prop);
755 }
756 #endif
757
758 /**
759  * Get a custom property when it exists.
760  * This function is also used to check if a property exists.
761  */
762 IDProperty *bc_get_IDProperty(Bone *bone, std::string key)
763 {
764   return (bone->prop == NULL) ? NULL : IDP_GetPropertyFromGroup(bone->prop, key.c_str());
765 }
766
767 /**
768  * Read a custom bone property and convert to float
769  * Return def if the property does not exist.
770  */
771 float bc_get_property(Bone *bone, std::string key, float def)
772 {
773   float result = def;
774   IDProperty *property = bc_get_IDProperty(bone, key);
775   if (property) {
776     switch (property->type) {
777       case IDP_INT:
778         result = (float)(IDP_Int(property));
779         break;
780       case IDP_FLOAT:
781         result = (float)(IDP_Float(property));
782         break;
783       case IDP_DOUBLE:
784         result = (float)(IDP_Double(property));
785         break;
786       default:
787         result = def;
788     }
789   }
790   return result;
791 }
792
793 /**
794  * Read a custom bone property and convert to matrix
795  * Return true if conversion was successful
796  *
797  * Return false if:
798  * - the property does not exist
799  * - is not an array of size 16
800  */
801 bool bc_get_property_matrix(Bone *bone, std::string key, float mat[4][4])
802 {
803   IDProperty *property = bc_get_IDProperty(bone, key);
804   if (property && property->type == IDP_ARRAY && property->len == 16) {
805     float *array = (float *)IDP_Array(property);
806     for (int i = 0; i < 4; i++) {
807       for (int j = 0; j < 4; j++) {
808         mat[i][j] = array[4 * i + j];
809       }
810     }
811     return true;
812   }
813   return false;
814 }
815
816 /**
817  * get a vector that is stored in 3 custom properties (used in Blender <= 2.78)
818  */
819 void bc_get_property_vector(Bone *bone, std::string key, float val[3], const float def[3])
820 {
821   val[0] = bc_get_property(bone, key + "_x", def[0]);
822   val[1] = bc_get_property(bone, key + "_y", def[1]);
823   val[2] = bc_get_property(bone, key + "_z", def[2]);
824 }
825
826 /**
827  * Check if vector exist stored in 3 custom properties (used in Blender <= 2.78)
828  */
829 static bool has_custom_props(Bone *bone, bool enabled, std::string key)
830 {
831   if (!enabled) {
832     return false;
833   }
834
835   return (bc_get_IDProperty(bone, key + "_x") || bc_get_IDProperty(bone, key + "_y") ||
836           bc_get_IDProperty(bone, key + "_z"));
837 }
838
839 void bc_enable_fcurves(bAction *act, char *bone_name)
840 {
841   FCurve *fcu;
842   char prefix[200];
843
844   if (bone_name) {
845     BLI_snprintf(prefix, sizeof(prefix), "pose.bones[\"%s\"]", bone_name);
846   }
847
848   for (fcu = (FCurve *)act->curves.first; fcu; fcu = fcu->next) {
849     if (bone_name) {
850       if (STREQLEN(fcu->rna_path, prefix, strlen(prefix))) {
851         fcu->flag &= ~FCURVE_DISABLED;
852       }
853       else {
854         fcu->flag |= FCURVE_DISABLED;
855       }
856     }
857     else {
858       fcu->flag &= ~FCURVE_DISABLED;
859     }
860   }
861 }
862
863 bool bc_bone_matrix_local_get(Object *ob, Bone *bone, Matrix &mat, bool for_opensim)
864 {
865
866   /* Ok, lets be super cautious and check if the bone exists */
867   bPose *pose = ob->pose;
868   bPoseChannel *pchan = BKE_pose_channel_find_name(pose, bone->name);
869   if (!pchan) {
870     return false;
871   }
872
873   bAction *action = bc_getSceneObjectAction(ob);
874   bPoseChannel *parchan = pchan->parent;
875
876   bc_enable_fcurves(action, bone->name);
877   float ipar[4][4];
878
879   if (bone->parent) {
880     invert_m4_m4(ipar, parchan->pose_mat);
881     mul_m4_m4m4(mat, ipar, pchan->pose_mat);
882   }
883   else {
884     copy_m4_m4(mat, pchan->pose_mat);
885   }
886
887   /* OPEN_SIM_COMPATIBILITY
888    * AFAIK animation to second life is via BVH, but no
889    * reason to not have the collada-animation be correct */
890   if (for_opensim) {
891     float temp[4][4];
892     copy_m4_m4(temp, bone->arm_mat);
893     temp[3][0] = temp[3][1] = temp[3][2] = 0.0f;
894     invert_m4(temp);
895
896     mul_m4_m4m4(mat, mat, temp);
897
898     if (bone->parent) {
899       copy_m4_m4(temp, bone->parent->arm_mat);
900       temp[3][0] = temp[3][1] = temp[3][2] = 0.0f;
901
902       mul_m4_m4m4(mat, temp, mat);
903     }
904   }
905   bc_enable_fcurves(action, NULL);
906   return true;
907 }
908
909 bool bc_is_animated(BCMatrixSampleMap &values)
910 {
911   static float MIN_DISTANCE = 0.00001;
912
913   if (values.size() < 2) {
914     return false; /* need at least 2 entries to be not flat */
915   }
916
917   BCMatrixSampleMap::iterator it;
918   const BCMatrix *refmat = NULL;
919   for (it = values.begin(); it != values.end(); ++it) {
920     const BCMatrix *matrix = it->second;
921
922     if (refmat == NULL) {
923       refmat = matrix;
924       continue;
925     }
926
927     if (!matrix->in_range(*refmat, MIN_DISTANCE)) {
928       return true;
929     }
930   }
931   return false;
932 }
933
934 bool bc_has_animations(Object *ob)
935 {
936   /* Check for object, light and camera transform animations */
937   if ((bc_getSceneObjectAction(ob) && bc_getSceneObjectAction(ob)->curves.first) ||
938       (bc_getSceneLightAction(ob) && bc_getSceneLightAction(ob)->curves.first) ||
939       (bc_getSceneCameraAction(ob) && bc_getSceneCameraAction(ob)->curves.first)) {
940     return true;
941   }
942
943   /* Check Material Effect parameter animations. */
944   for (int a = 0; a < ob->totcol; a++) {
945     Material *ma = give_current_material(ob, a + 1);
946     if (!ma) {
947       continue;
948     }
949     if (ma->adt && ma->adt->action && ma->adt->action->curves.first) {
950       return true;
951     }
952   }
953
954   Key *key = BKE_key_from_object(ob);
955   if ((key && key->adt && key->adt->action) && key->adt->action->curves.first) {
956     return true;
957   }
958
959   return false;
960 }
961
962 bool bc_has_animations(Scene *sce, LinkNode *export_set)
963 {
964   LinkNode *node;
965   if (export_set) {
966     for (node = export_set; node; node = node->next) {
967       Object *ob = (Object *)node->link;
968
969       if (bc_has_animations(ob)) {
970         return true;
971       }
972     }
973   }
974   return false;
975 }
976
977 void bc_add_global_transform(Matrix &to_mat,
978                              const Matrix &from_mat,
979                              const BCMatrix &global_transform,
980                              const bool invert)
981 {
982   copy_m4_m4(to_mat, from_mat);
983   bc_add_global_transform(to_mat, global_transform, invert);
984 }
985
986 void bc_add_global_transform(Vector &to_vec,
987                              const Vector &from_vec,
988                              const BCMatrix &global_transform,
989                              const bool invert)
990 {
991   copy_v3_v3(to_vec, from_vec);
992   bc_add_global_transform(to_vec, global_transform, invert);
993 }
994
995 void bc_add_global_transform(Matrix &to_mat, const BCMatrix &global_transform, const bool invert)
996 {
997   BCMatrix mat(to_mat);
998   mat.add_transform(global_transform, invert);
999   mat.get_matrix(to_mat);
1000 }
1001
1002 void bc_add_global_transform(Vector &to_vec, const BCMatrix &global_transform, const bool invert)
1003 {
1004   Matrix mat;
1005   Vector from_vec;
1006   copy_v3_v3(from_vec, to_vec);
1007   global_transform.get_matrix(mat, false, 6, invert);
1008   mul_v3_m4v3(to_vec, mat, from_vec);
1009 }
1010
1011 void bc_apply_global_transform(Matrix &to_mat, const BCMatrix &global_transform, const bool invert)
1012 {
1013   BCMatrix mat(to_mat);
1014   mat.apply_transform(global_transform, invert);
1015   mat.get_matrix(to_mat);
1016 }
1017
1018 void bc_apply_global_transform(Vector &to_vec, const BCMatrix &global_transform, const bool invert)
1019 {
1020   Matrix transform;
1021   global_transform.get_matrix(transform);
1022   mul_v3_m4v3(to_vec, transform, to_vec);
1023 }
1024
1025 /**
1026  * Check if custom information about bind matrix exists and modify the from_mat
1027  * accordingly.
1028  *
1029  * Note: This is old style for Blender <= 2.78 only kept for compatibility
1030  */
1031 void bc_create_restpose_mat(BCExportSettings &export_settings,
1032                             Bone *bone,
1033                             float to_mat[4][4],
1034                             float from_mat[4][4],
1035                             bool use_local_space)
1036 {
1037   float loc[3];
1038   float rot[3];
1039   float scale[3];
1040   static const float V0[3] = {0, 0, 0};
1041
1042   if (!has_custom_props(bone, export_settings.get_keep_bind_info(), "restpose_loc") &&
1043       !has_custom_props(bone, export_settings.get_keep_bind_info(), "restpose_rot") &&
1044       !has_custom_props(bone, export_settings.get_keep_bind_info(), "restpose_scale")) {
1045     /* No need */
1046     copy_m4_m4(to_mat, from_mat);
1047     return;
1048   }
1049
1050   bc_decompose(from_mat, loc, rot, NULL, scale);
1051   loc_eulO_size_to_mat4(to_mat, loc, rot, scale, 6);
1052
1053   if (export_settings.get_keep_bind_info()) {
1054     bc_get_property_vector(bone, "restpose_loc", loc, loc);
1055
1056     if (use_local_space && bone->parent) {
1057       Bone *b = bone;
1058       while (b->parent) {
1059         b = b->parent;
1060         float ploc[3];
1061         bc_get_property_vector(b, "restpose_loc", ploc, V0);
1062         loc[0] += ploc[0];
1063         loc[1] += ploc[1];
1064         loc[2] += ploc[2];
1065       }
1066     }
1067   }
1068
1069   if (export_settings.get_keep_bind_info()) {
1070     if (bc_get_IDProperty(bone, "restpose_rot_x")) {
1071       rot[0] = DEG2RADF(bc_get_property(bone, "restpose_rot_x", 0));
1072     }
1073     if (bc_get_IDProperty(bone, "restpose_rot_y")) {
1074       rot[1] = DEG2RADF(bc_get_property(bone, "restpose_rot_y", 0));
1075     }
1076     if (bc_get_IDProperty(bone, "restpose_rot_z")) {
1077       rot[2] = DEG2RADF(bc_get_property(bone, "restpose_rot_z", 0));
1078     }
1079   }
1080
1081   if (export_settings.get_keep_bind_info()) {
1082     bc_get_property_vector(bone, "restpose_scale", scale, scale);
1083   }
1084
1085   loc_eulO_size_to_mat4(to_mat, loc, rot, scale, 6);
1086 }
1087
1088 void bc_sanitize_v3(float v[3], int precision)
1089 {
1090   for (int i = 0; i < 3; i++) {
1091     double val = (double)v[i];
1092     val = double_round(val, precision);
1093     v[i] = (float)val;
1094   }
1095 }
1096
1097 void bc_sanitize_v3(double v[3], int precision)
1098 {
1099   for (int i = 0; i < 3; i++) {
1100     v[i] = double_round(v[i], precision);
1101   }
1102 }
1103
1104 void bc_copy_m4_farray(float r[4][4], float *a)
1105 {
1106   for (int i = 0; i < 4; i++) {
1107     for (int j = 0; j < 4; j++) {
1108       r[i][j] = *a++;
1109     }
1110   }
1111 }
1112
1113 void bc_copy_farray_m4(float *r, float a[4][4])
1114 {
1115   for (int i = 0; i < 4; i++) {
1116     for (int j = 0; j < 4; j++) {
1117       *r++ = a[i][j];
1118     }
1119   }
1120 }
1121
1122 void bc_copy_darray_m4d(double *r, double a[4][4])
1123 {
1124   for (int i = 0; i < 4; i++) {
1125     for (int j = 0; j < 4; j++) {
1126       *r++ = a[i][j];
1127     }
1128   }
1129 }
1130
1131 void bc_copy_v44_m4d(std::vector<std::vector<double>> &r, double (&a)[4][4])
1132 {
1133   for (int i = 0; i < 4; i++) {
1134     for (int j = 0; j < 4; j++) {
1135       r[i][j] = a[i][j];
1136     }
1137   }
1138 }
1139
1140 void bc_copy_m4d_v44(double (&r)[4][4], std::vector<std::vector<double>> &a)
1141 {
1142   for (int i = 0; i < 4; i++) {
1143     for (int j = 0; j < 4; j++) {
1144       r[i][j] = a[i][j];
1145     }
1146   }
1147 }
1148
1149 /**
1150  * Returns name of Active UV Layer or empty String if no active UV Layer defined
1151  */
1152 std::string bc_get_active_uvlayer_name(Mesh *me)
1153 {
1154   int num_layers = CustomData_number_of_layers(&me->ldata, CD_MLOOPUV);
1155   if (num_layers) {
1156     char *layer_name = bc_CustomData_get_active_layer_name(&me->ldata, CD_MLOOPUV);
1157     if (layer_name) {
1158       return std::string(layer_name);
1159     }
1160   }
1161   return "";
1162 }
1163
1164 /**
1165  * Returns name of Active UV Layer or empty String if no active UV Layer defined.
1166  * Assuming the Object is of type MESH
1167  */
1168 std::string bc_get_active_uvlayer_name(Object *ob)
1169 {
1170   Mesh *me = (Mesh *)ob->data;
1171   return bc_get_active_uvlayer_name(me);
1172 }
1173
1174 /**
1175  * Returns UV Layer name or empty string if layer index is out of range
1176  */
1177 std::string bc_get_uvlayer_name(Mesh *me, int layer)
1178 {
1179   int num_layers = CustomData_number_of_layers(&me->ldata, CD_MLOOPUV);
1180   if (num_layers && layer < num_layers) {
1181     char *layer_name = bc_CustomData_get_layer_name(&me->ldata, CD_MLOOPUV, layer);
1182     if (layer_name) {
1183       return std::string(layer_name);
1184     }
1185   }
1186   return "";
1187 }
1188
1189 std::string bc_find_bonename_in_path(std::string path, std::string probe)
1190 {
1191   std::string result;
1192   char *boneName = BLI_str_quoted_substrN(path.c_str(), probe.c_str());
1193   if (boneName) {
1194     result = std::string(boneName);
1195     MEM_freeN(boneName);
1196   }
1197   return result;
1198 }
1199
1200 static bNodeTree *prepare_material_nodetree(Material *ma)
1201 {
1202   if (ma->nodetree == NULL) {
1203     ma->nodetree = ntreeAddTree(NULL, "Shader Nodetree", "ShaderNodeTree");
1204     ma->use_nodes = true;
1205   }
1206   return ma->nodetree;
1207 }
1208
1209 bNode *bc_add_node(
1210     bContext *C, bNodeTree *ntree, int node_type, int locx, int locy, std::string label)
1211 {
1212   bNode *node = nodeAddStaticNode(C, ntree, node_type);
1213   if (node) {
1214     if (label.length() > 0) {
1215       strcpy(node->label, label.c_str());
1216     }
1217     node->locx = locx;
1218     node->locy = locy;
1219     node->flag |= NODE_SELECT;
1220   }
1221   return node;
1222 }
1223
1224 bNode *bc_add_node(bContext *C, bNodeTree *ntree, int node_type, int locx, int locy)
1225 {
1226   return bc_add_node(C, ntree, node_type, locx, locy, "");
1227 }
1228
1229 #if 0
1230 /* experimental, probably not used */
1231 static bNodeSocket *bc_group_add_input_socket(bNodeTree *ntree,
1232                                               bNode *to_node,
1233                                               int to_index,
1234                                               std::string label)
1235 {
1236   bNodeSocket *to_socket = (bNodeSocket *)BLI_findlink(&to_node->inputs, to_index);
1237
1238   //bNodeSocket *socket = ntreeAddSocketInterfaceFromSocket(ntree, to_node, to_socket);
1239   //return socket;
1240
1241   bNodeSocket *gsock = ntreeAddSocketInterfaceFromSocket(ntree, to_node, to_socket);
1242   bNode *inputGroup = ntreeFindType(ntree, NODE_GROUP_INPUT);
1243   node_group_input_verify(ntree, inputGroup, (ID *)ntree);
1244   bNodeSocket *newsock = node_group_input_find_socket(inputGroup, gsock->identifier);
1245   nodeAddLink(ntree, inputGroup, newsock, to_node, to_socket);
1246   strcpy(newsock->name, label.c_str());
1247   return newsock;
1248 }
1249
1250 static bNodeSocket *bc_group_add_output_socket(bNodeTree *ntree,
1251                                                bNode *from_node,
1252                                                int from_index,
1253                                                std::string label)
1254 {
1255   bNodeSocket *from_socket = (bNodeSocket *)BLI_findlink(&from_node->outputs, from_index);
1256
1257   //bNodeSocket *socket = ntreeAddSocketInterfaceFromSocket(ntree, to_node, to_socket);
1258   //return socket;
1259
1260   bNodeSocket *gsock = ntreeAddSocketInterfaceFromSocket(ntree, from_node, from_socket);
1261   bNode *outputGroup = ntreeFindType(ntree, NODE_GROUP_OUTPUT);
1262   node_group_output_verify(ntree, outputGroup, (ID *)ntree);
1263   bNodeSocket *newsock = node_group_output_find_socket(outputGroup, gsock->identifier);
1264   nodeAddLink(ntree, from_node, from_socket, outputGroup, newsock);
1265   strcpy(newsock->name, label.c_str());
1266   return newsock;
1267 }
1268
1269 void bc_make_group(bContext *C, bNodeTree *ntree, std::map<std::string, bNode *> nmap)
1270 {
1271   bNode *gnode = node_group_make_from_selected(C, ntree, "ShaderNodeGroup", "ShaderNodeTree");
1272   bNodeTree *gtree = (bNodeTree *)gnode->id;
1273
1274   bc_group_add_input_socket(gtree, nmap["main"], 0, "Diffuse");
1275   bc_group_add_input_socket(gtree, nmap["emission"], 0, "Emission");
1276   bc_group_add_input_socket(gtree, nmap["mix"], 0, "Transparency");
1277   bc_group_add_input_socket(gtree, nmap["emission"], 1, "Emission");
1278   bc_group_add_input_socket(gtree, nmap["main"], 4, "Metallic");
1279   bc_group_add_input_socket(gtree, nmap["main"], 5, "Specular");
1280
1281   bc_group_add_output_socket(gtree, nmap["mix"], 0, "Shader");
1282 }
1283 #endif
1284
1285 static void bc_node_add_link(
1286     bNodeTree *ntree, bNode *from_node, int from_index, bNode *to_node, int to_index)
1287 {
1288   bNodeSocket *from_socket = (bNodeSocket *)BLI_findlink(&from_node->outputs, from_index);
1289   bNodeSocket *to_socket = (bNodeSocket *)BLI_findlink(&to_node->inputs, to_index);
1290
1291   nodeAddLink(ntree, from_node, from_socket, to_node, to_socket);
1292 }
1293
1294 void bc_add_default_shader(bContext *C, Material *ma)
1295 {
1296   bNodeTree *ntree = prepare_material_nodetree(ma);
1297   std::map<std::string, bNode *> nmap;
1298 #if 0
1299   nmap["main"] = bc_add_node(C, ntree, SH_NODE_BSDF_PRINCIPLED, -300, 300);
1300   nmap["emission"] = bc_add_node(C, ntree, SH_NODE_EMISSION, -300, 500, "emission");
1301   nmap["add"] = bc_add_node(C, ntree, SH_NODE_ADD_SHADER, 100, 400);
1302   nmap["transparent"] = bc_add_node(C, ntree, SH_NODE_BSDF_TRANSPARENT, 100, 200);
1303   nmap["mix"] = bc_add_node(C, ntree, SH_NODE_MIX_SHADER, 400, 300, "transparency");
1304   nmap["out"] = bc_add_node(C, ntree, SH_NODE_OUTPUT_MATERIAL, 600, 300);
1305   nmap["out"]->flag &= ~NODE_SELECT;
1306
1307   bc_node_add_link(ntree, nmap["emission"], 0, nmap["add"], 0);
1308   bc_node_add_link(ntree, nmap["main"], 0, nmap["add"], 1);
1309   bc_node_add_link(ntree, nmap["add"], 0, nmap["mix"], 1);
1310   bc_node_add_link(ntree, nmap["transparent"], 0, nmap["mix"], 2);
1311
1312   bc_node_add_link(ntree, nmap["mix"], 0, nmap["out"], 0);
1313   /* experimental, probably not used. */
1314   bc_make_group(C, ntree, nmap);
1315 #else
1316   nmap["main"] = bc_add_node(C, ntree, SH_NODE_BSDF_PRINCIPLED, 0, 300);
1317   nmap["out"] = bc_add_node(C, ntree, SH_NODE_OUTPUT_MATERIAL, 300, 300);
1318   bc_node_add_link(ntree, nmap["main"], 0, nmap["out"], 0);
1319 #endif
1320 }
1321
1322 COLLADASW::ColorOrTexture bc_get_base_color(Material *ma)
1323 {
1324   Color default_color = {0.8, 0.8, 0.8, 1.0};
1325   bNode *shader = bc_get_master_shader(ma);
1326   if (ma->use_nodes && shader) {
1327     return bc_get_cot_from_shader(shader, "Base Color", default_color);
1328   }
1329   else {
1330     return bc_get_cot(default_color);
1331   }
1332 }
1333
1334 COLLADASW::ColorOrTexture bc_get_emission(Material *ma)
1335 {
1336   Color default_color = {0, 0, 0, 1};
1337   bNode *shader = bc_get_master_shader(ma);
1338   if (ma->use_nodes && shader) {
1339     return bc_get_cot_from_shader(shader, "Emission", default_color);
1340   }
1341   else {
1342     return bc_get_cot(default_color); /* default black */
1343   }
1344 }
1345
1346 COLLADASW::ColorOrTexture bc_get_ambient(Material *ma)
1347 {
1348   Color default_color = {0, 0, 0, 1.0};
1349   return bc_get_cot(default_color);
1350 }
1351
1352 COLLADASW::ColorOrTexture bc_get_specular(Material *ma)
1353 {
1354   Color default_color = {0, 0, 0, 1.0};
1355   return bc_get_cot(default_color);
1356 }
1357
1358 COLLADASW::ColorOrTexture bc_get_reflective(Material *ma)
1359 {
1360   Color default_color = {0, 0, 0, 1.0};
1361   return bc_get_cot(default_color);
1362 }
1363
1364 double bc_get_alpha(Material *ma)
1365 {
1366   double alpha = ma->a; /* fallback if no socket found */
1367   bNode *master_shader = bc_get_master_shader(ma);
1368   if (ma->use_nodes && master_shader) {
1369     bc_get_float_from_shader(master_shader, alpha, "Alpha");
1370   }
1371   return alpha;
1372 }
1373
1374 double bc_get_ior(Material *ma)
1375 {
1376   double ior = -1; /* fallback if no socket found */
1377   bNode *master_shader = bc_get_master_shader(ma);
1378   if (ma->use_nodes && master_shader) {
1379     bc_get_float_from_shader(master_shader, ior, "IOR");
1380   }
1381   return ior;
1382 }
1383
1384 double bc_get_shininess(Material *ma)
1385 {
1386   double ior = -1; /* fallback if no socket found */
1387   bNode *master_shader = bc_get_master_shader(ma);
1388   if (ma->use_nodes && master_shader) {
1389     bc_get_float_from_shader(master_shader, ior, "Roughness");
1390   }
1391   return ior;
1392 }
1393
1394 double bc_get_reflectivity(Material *ma)
1395 {
1396   double reflectivity = ma->spec; /* fallback if no socket found */
1397   bNode *master_shader = bc_get_master_shader(ma);
1398   if (ma->use_nodes && master_shader) {
1399     bc_get_float_from_shader(master_shader, reflectivity, "Metallic");
1400   }
1401   return reflectivity;
1402 }
1403
1404 double bc_get_float_from_shader(bNode *shader, double &val, std::string nodeid)
1405 {
1406   bNodeSocket *socket = nodeFindSocket(shader, SOCK_IN, nodeid.c_str());
1407   if (socket) {
1408     bNodeSocketValueFloat *ref = (bNodeSocketValueFloat *)socket->default_value;
1409     val = (double)ref->value;
1410     return true;
1411   }
1412   return false;
1413 }
1414
1415 COLLADASW::ColorOrTexture bc_get_cot_from_shader(bNode *shader,
1416                                                  std::string nodeid,
1417                                                  Color &default_color)
1418 {
1419   bNodeSocket *socket = nodeFindSocket(shader, SOCK_IN, nodeid.c_str());
1420   if (socket) {
1421     bNodeSocketValueRGBA *dcol = (bNodeSocketValueRGBA *)socket->default_value;
1422     float *col = dcol->value;
1423     return bc_get_cot(col);
1424   }
1425   else {
1426     return bc_get_cot(default_color); /* default black */
1427   }
1428 }
1429
1430 bNode *bc_get_master_shader(Material *ma)
1431 {
1432   bNodeTree *nodetree = ma->nodetree;
1433   if (nodetree) {
1434     for (bNode *node = (bNode *)nodetree->nodes.first; node; node = node->next) {
1435       if (node->typeinfo->type == SH_NODE_BSDF_PRINCIPLED) {
1436         return node;
1437       }
1438     }
1439   }
1440   return NULL;
1441 }
1442
1443 COLLADASW::ColorOrTexture bc_get_cot(float r, float g, float b, float a)
1444 {
1445   COLLADASW::Color color(r, g, b, a);
1446   COLLADASW::ColorOrTexture cot(color);
1447   return cot;
1448 }
1449
1450 COLLADASW::ColorOrTexture bc_get_cot(Color col)
1451 {
1452   COLLADASW::Color color(col[0], col[1], col[2], col[3]);
1453   COLLADASW::ColorOrTexture cot(color);
1454   return cot;
1455 }