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