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