1 /*************************************************************************/
2 /* collada.cpp */
3 /*************************************************************************/
4 /* This file is part of: */
5 /* GODOT ENGINE */
6 /* https://godotengine.org */
7 /*************************************************************************/
8 /* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
9 /* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
10 /* */
11 /* Permission is hereby granted, free of charge, to any person obtaining */
12 /* a copy of this software and associated documentation files (the */
13 /* "Software"), to deal in the Software without restriction, including */
14 /* without limitation the rights to use, copy, modify, merge, publish, */
15 /* distribute, sublicense, and/or sell copies of the Software, and to */
16 /* permit persons to whom the Software is furnished to do so, subject to */
17 /* the following conditions: */
18 /* */
19 /* The above copyright notice and this permission notice shall be */
20 /* included in all copies or substantial portions of the Software. */
21 /* */
22 /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
23 /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
24 /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
25 /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
26 /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
27 /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
28 /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
29 /*************************************************************************/
30
31 #include "collada.h"
32
33 #include <stdio.h>
34
35 //#define DEBUG_DEFAULT_ANIMATION
36 //#define DEBUG_COLLADA
37 #ifdef DEBUG_COLLADA
38 #define COLLADA_PRINT(m_what) print_line(m_what)
39 #else
40 #define COLLADA_PRINT(m_what)
41 #endif
42
43 #define COLLADA_IMPORT_SCALE_SCENE
44
45 /* HELPERS */
46
get_texture_path(const String & p_source,Collada & state) const47 String Collada::Effect::get_texture_path(const String &p_source, Collada &state) const {
48
49 const String &image = p_source;
50 ERR_FAIL_COND_V(!state.state.image_map.has(image), "");
51 return state.state.image_map[image].path;
52 }
53
get_root_transform() const54 Transform Collada::get_root_transform() const {
55
56 Transform unit_scale_transform;
57 #ifndef COLLADA_IMPORT_SCALE_SCENE
58 unit_scale_transform.scale(Vector3(state.unit_scale, state.unit_scale, state.unit_scale));
59 #endif
60 return unit_scale_transform;
61 }
62
fix_unit_scale(Collada & state)63 void Collada::Vertex::fix_unit_scale(Collada &state) {
64 #ifdef COLLADA_IMPORT_SCALE_SCENE
65 vertex *= state.state.unit_scale;
66 #endif
67 }
68
_uri_to_id(const String & p_uri)69 static String _uri_to_id(const String &p_uri) {
70
71 if (p_uri.begins_with("#"))
72 return p_uri.substr(1, p_uri.size() - 1);
73 else
74 return p_uri;
75 }
76
77 /** HELPER FUNCTIONS **/
78
fix_transform(const Transform & p_transform)79 Transform Collada::fix_transform(const Transform &p_transform) {
80
81 Transform tr = p_transform;
82
83 #ifndef NO_UP_AXIS_SWAP
84
85 if (state.up_axis != Vector3::AXIS_Y) {
86
87 for (int i = 0; i < 3; i++)
88 SWAP(tr.basis[1][i], tr.basis[state.up_axis][i]);
89 for (int i = 0; i < 3; i++)
90 SWAP(tr.basis[i][1], tr.basis[i][state.up_axis]);
91
92 SWAP(tr.origin[1], tr.origin[state.up_axis]);
93
94 tr.basis[state.up_axis][0] = -tr.basis[state.up_axis][0];
95 tr.basis[state.up_axis][1] = -tr.basis[state.up_axis][1];
96 tr.basis[0][state.up_axis] = -tr.basis[0][state.up_axis];
97 tr.basis[1][state.up_axis] = -tr.basis[1][state.up_axis];
98 tr.origin[state.up_axis] = -tr.origin[state.up_axis];
99 }
100 #endif
101
102 //tr.scale(Vector3(state.unit_scale.unit_scale.unit_scale));
103 return tr;
104 //return state.matrix_fix * p_transform;
105 }
106
_read_transform_from_array(const Vector<float> & array,int ofs=0)107 static Transform _read_transform_from_array(const Vector<float> &array, int ofs = 0) {
108
109 Transform tr;
110 // i wonder why collada matrices are transposed, given that's opposed to opengl..
111 tr.basis.elements[0][0] = array[0 + ofs];
112 tr.basis.elements[0][1] = array[1 + ofs];
113 tr.basis.elements[0][2] = array[2 + ofs];
114 tr.basis.elements[1][0] = array[4 + ofs];
115 tr.basis.elements[1][1] = array[5 + ofs];
116 tr.basis.elements[1][2] = array[6 + ofs];
117 tr.basis.elements[2][0] = array[8 + ofs];
118 tr.basis.elements[2][1] = array[9 + ofs];
119 tr.basis.elements[2][2] = array[10 + ofs];
120 tr.origin.x = array[3 + ofs];
121 tr.origin.y = array[7 + ofs];
122 tr.origin.z = array[11 + ofs];
123 return tr;
124 }
125
126 /* STRUCTURES */
127
compute_transform(Collada & state) const128 Transform Collada::Node::compute_transform(Collada &state) const {
129
130 Transform xform;
131
132 for (int i = 0; i < xform_list.size(); i++) {
133
134 Transform xform_step;
135 const XForm &xf = xform_list[i];
136 switch (xf.op) {
137
138 case XForm::OP_ROTATE: {
139 if (xf.data.size() >= 4) {
140
141 xform_step.rotate(Vector3(xf.data[0], xf.data[1], xf.data[2]), Math::deg2rad(xf.data[3]));
142 }
143 } break;
144 case XForm::OP_SCALE: {
145
146 if (xf.data.size() >= 3) {
147
148 xform_step.scale(Vector3(xf.data[0], xf.data[1], xf.data[2]));
149 }
150
151 } break;
152 case XForm::OP_TRANSLATE: {
153
154 if (xf.data.size() >= 3) {
155
156 xform_step.origin = Vector3(xf.data[0], xf.data[1], xf.data[2]);
157 }
158
159 } break;
160 case XForm::OP_MATRIX: {
161
162 if (xf.data.size() >= 16) {
163 xform_step = _read_transform_from_array(xf.data, 0);
164 }
165
166 } break;
167 default: {
168 }
169 }
170
171 xform = xform * xform_step;
172 }
173
174 #ifdef COLLADA_IMPORT_SCALE_SCENE
175 xform.origin *= state.state.unit_scale;
176 #endif
177 return xform;
178 }
179
get_transform() const180 Transform Collada::Node::get_transform() const {
181
182 return default_transform;
183 }
184
get_global_transform() const185 Transform Collada::Node::get_global_transform() const {
186
187 if (parent)
188 return parent->get_global_transform() * default_transform;
189 else
190 return default_transform;
191 }
192
get_value_at_time(float p_time) const193 Vector<float> Collada::AnimationTrack::get_value_at_time(float p_time) const {
194
195 ERR_FAIL_COND_V(keys.size() == 0, Vector<float>());
196 int i = 0;
197
198 for (i = 0; i < keys.size(); i++) {
199
200 if (keys[i].time > p_time)
201 break;
202 }
203
204 if (i == 0)
205 return keys[0].data;
206 if (i == keys.size())
207 return keys[keys.size() - 1].data;
208
209 switch (keys[i].interp_type) {
210
211 case INTERP_BEZIER: //wait for bezier
212 case INTERP_LINEAR: {
213
214 float c = (p_time - keys[i - 1].time) / (keys[i].time - keys[i - 1].time);
215
216 if (keys[i].data.size() == 16) {
217 //interpolate a matrix
218 Transform src = _read_transform_from_array(keys[i - 1].data);
219 Transform dst = _read_transform_from_array(keys[i].data);
220
221 Transform interp = c < 0.001 ? src : src.interpolate_with(dst, c);
222
223 Vector<float> ret;
224 ret.resize(16);
225 Transform tr;
226 // i wonder why collada matrices are transposed, given that's opposed to opengl..
227 ret.write[0] = interp.basis.elements[0][0];
228 ret.write[1] = interp.basis.elements[0][1];
229 ret.write[2] = interp.basis.elements[0][2];
230 ret.write[4] = interp.basis.elements[1][0];
231 ret.write[5] = interp.basis.elements[1][1];
232 ret.write[6] = interp.basis.elements[1][2];
233 ret.write[8] = interp.basis.elements[2][0];
234 ret.write[9] = interp.basis.elements[2][1];
235 ret.write[10] = interp.basis.elements[2][2];
236 ret.write[3] = interp.origin.x;
237 ret.write[7] = interp.origin.y;
238 ret.write[11] = interp.origin.z;
239 ret.write[12] = 0;
240 ret.write[13] = 0;
241 ret.write[14] = 0;
242 ret.write[15] = 1;
243
244 return ret;
245 } else {
246
247 Vector<float> dest;
248 dest.resize(keys[i].data.size());
249 for (int j = 0; j < dest.size(); j++) {
250
251 dest.write[j] = keys[i].data[j] * c + keys[i - 1].data[j] * (1.0 - c);
252 }
253 return dest;
254 //interpolate one by one
255 }
256 } break;
257 }
258
259 ERR_FAIL_V(Vector<float>());
260 }
261
_parse_asset(XMLParser & parser)262 void Collada::_parse_asset(XMLParser &parser) {
263
264 while (parser.read() == OK) {
265
266 if (parser.get_node_type() == XMLParser::NODE_ELEMENT) {
267
268 String name = parser.get_node_name();
269
270 if (name == "up_axis") {
271
272 parser.read();
273 if (parser.get_node_data() == "X_UP")
274 state.up_axis = Vector3::AXIS_X;
275 if (parser.get_node_data() == "Y_UP")
276 state.up_axis = Vector3::AXIS_Y;
277 if (parser.get_node_data() == "Z_UP")
278 state.up_axis = Vector3::AXIS_Z;
279
280 COLLADA_PRINT("up axis: " + parser.get_node_data());
281 } else if (name == "unit") {
282
283 state.unit_scale = parser.get_attribute_value("meter").to_double();
284 COLLADA_PRINT("unit scale: " + rtos(state.unit_scale));
285 }
286
287 } else if (parser.get_node_type() == XMLParser::NODE_ELEMENT_END && parser.get_node_name() == "asset")
288 break; //end of <asset>
289 }
290 }
291
_parse_image(XMLParser & parser)292 void Collada::_parse_image(XMLParser &parser) {
293
294 String id = parser.get_attribute_value("id");
295
296 if (!(state.import_flags & IMPORT_FLAG_SCENE)) {
297 if (!parser.is_empty())
298 parser.skip_section();
299 return;
300 }
301
302 Image image;
303
304 if (state.version < State::Version(1, 4, 0)) {
305 /* <1.4 */
306 String path = parser.get_attribute_value("source").strip_edges();
307 if (path.find("://") == -1 && path.is_rel_path()) {
308 // path is relative to file being loaded, so convert to a resource path
309 image.path = ProjectSettings::get_singleton()->localize_path(state.local_path.get_base_dir().plus_file(path.percent_decode()));
310 }
311 } else {
312
313 while (parser.read() == OK) {
314
315 if (parser.get_node_type() == XMLParser::NODE_ELEMENT) {
316
317 String name = parser.get_node_name();
318
319 if (name == "init_from") {
320
321 parser.read();
322 String path = parser.get_node_data().strip_edges().percent_decode();
323
324 if (path.find("://") == -1 && path.is_rel_path()) {
325 // path is relative to file being loaded, so convert to a resource path
326 path = ProjectSettings::get_singleton()->localize_path(state.local_path.get_base_dir().plus_file(path));
327
328 } else if (path.find("file:///") == 0) {
329 path = path.replace_first("file:///", "");
330 path = ProjectSettings::get_singleton()->localize_path(path);
331 }
332
333 image.path = path;
334
335 } else if (name == "data") {
336
337 ERR_PRINT("COLLADA Embedded image data not supported!");
338
339 } else if (name == "extra" && !parser.is_empty())
340 parser.skip_section();
341
342 } else if (parser.get_node_type() == XMLParser::NODE_ELEMENT_END && parser.get_node_name() == "image")
343 break; //end of <asset>
344 }
345 }
346
347 state.image_map[id] = image;
348 }
349
_parse_material(XMLParser & parser)350 void Collada::_parse_material(XMLParser &parser) {
351
352 if (!(state.import_flags & IMPORT_FLAG_SCENE)) {
353 if (!parser.is_empty())
354 parser.skip_section();
355 return;
356 }
357
358 Material material;
359
360 String id = parser.get_attribute_value("id");
361 if (parser.has_attribute("name"))
362 material.name = parser.get_attribute_value("name");
363
364 if (state.version < State::Version(1, 4, 0)) {
365 /* <1.4 */
366 ERR_PRINT("Collada Materials < 1.4 are not supported (yet)");
367 } else {
368
369 while (parser.read() == OK) {
370
371 if (parser.get_node_type() == XMLParser::NODE_ELEMENT && parser.get_node_name() == "instance_effect") {
372
373 material.instance_effect = _uri_to_id(parser.get_attribute_value("url"));
374 } else if (parser.get_node_type() == XMLParser::NODE_ELEMENT_END && parser.get_node_name() == "material")
375 break; //end of <asset>
376 }
377 }
378
379 state.material_map[id] = material;
380 }
381
382 //! reads floats from inside of xml element until end of xml element
_read_float_array(XMLParser & parser)383 Vector<float> Collada::_read_float_array(XMLParser &parser) {
384
385 if (parser.is_empty())
386 return Vector<float>();
387
388 Vector<String> splitters;
389 splitters.push_back(" ");
390 splitters.push_back("\n");
391 splitters.push_back("\r");
392 splitters.push_back("\t");
393
394 Vector<float> array;
395 while (parser.read() == OK) {
396 // TODO: check for comments inside the element
397 // and ignore them.
398
399 if (parser.get_node_type() == XMLParser::NODE_TEXT) {
400 // parse float data
401 String str = parser.get_node_data();
402 array = str.split_floats_mk(splitters, false);
403 //array=str.split_floats(" ",false);
404 } else if (parser.get_node_type() == XMLParser::NODE_ELEMENT_END)
405 break; // end parsing text
406 }
407
408 return array;
409 }
410
_read_string_array(XMLParser & parser)411 Vector<String> Collada::_read_string_array(XMLParser &parser) {
412
413 if (parser.is_empty())
414 return Vector<String>();
415
416 Vector<String> array;
417 while (parser.read() == OK) {
418 // TODO: check for comments inside the element
419 // and ignore them.
420
421 if (parser.get_node_type() == XMLParser::NODE_TEXT) {
422 // parse String data
423 String str = parser.get_node_data();
424 array = str.split_spaces();
425 } else if (parser.get_node_type() == XMLParser::NODE_ELEMENT_END)
426 break; // end parsing text
427 }
428
429 return array;
430 }
431
_read_transform(XMLParser & parser)432 Transform Collada::_read_transform(XMLParser &parser) {
433
434 if (parser.is_empty())
435 return Transform();
436
437 Vector<String> array;
438 while (parser.read() == OK) {
439 // TODO: check for comments inside the element
440 // and ignore them.
441
442 if (parser.get_node_type() == XMLParser::NODE_TEXT) {
443 // parse float data
444 String str = parser.get_node_data();
445 array = str.split_spaces();
446 } else if (parser.get_node_type() == XMLParser::NODE_ELEMENT_END)
447 break; // end parsing text
448 }
449
450 ERR_FAIL_COND_V(array.size() != 16, Transform());
451 Vector<float> farr;
452 farr.resize(16);
453 for (int i = 0; i < 16; i++) {
454 farr.write[i] = array[i].to_double();
455 }
456
457 return _read_transform_from_array(farr);
458 }
459
_read_empty_draw_type(XMLParser & parser)460 String Collada::_read_empty_draw_type(XMLParser &parser) {
461
462 String empty_draw_type = "";
463
464 if (parser.is_empty())
465 return empty_draw_type;
466
467 while (parser.read() == OK) {
468 if (parser.get_node_type() == XMLParser::NODE_TEXT) {
469 empty_draw_type = parser.get_node_data();
470 } else if (parser.get_node_type() == XMLParser::NODE_ELEMENT_END)
471 break; // end parsing text
472 }
473 return empty_draw_type;
474 }
475
_parse_param(XMLParser & parser)476 Variant Collada::_parse_param(XMLParser &parser) {
477
478 if (parser.is_empty())
479 return Variant();
480
481 String from = parser.get_node_name();
482 Variant data;
483
484 while (parser.read() == OK) {
485 if (parser.get_node_type() == XMLParser::NODE_ELEMENT) {
486
487 if (parser.get_node_name() == "float") {
488
489 parser.read();
490 if (parser.get_node_type() == XMLParser::NODE_TEXT) {
491
492 data = parser.get_node_data().to_double();
493 }
494 } else if (parser.get_node_name() == "float2") {
495
496 Vector<float> v2 = _read_float_array(parser);
497
498 if (v2.size() >= 2) {
499
500 data = Vector2(v2[0], v2[1]);
501 }
502 } else if (parser.get_node_name() == "float3") {
503
504 Vector<float> v3 = _read_float_array(parser);
505
506 if (v3.size() >= 3) {
507
508 data = Vector3(v3[0], v3[1], v3[2]);
509 }
510 } else if (parser.get_node_name() == "float4") {
511
512 Vector<float> v4 = _read_float_array(parser);
513
514 if (v4.size() >= 4) {
515
516 data = Color(v4[0], v4[1], v4[2], v4[3]);
517 }
518 } else if (parser.get_node_name() == "sampler2D") {
519
520 while (parser.read() == OK) {
521
522 if (parser.get_node_type() == XMLParser::NODE_ELEMENT) {
523
524 if (parser.get_node_name() == "source") {
525
526 parser.read();
527
528 if (parser.get_node_type() == XMLParser::NODE_TEXT) {
529
530 data = parser.get_node_data();
531 }
532 }
533 } else if (parser.get_node_type() == XMLParser::NODE_ELEMENT_END && parser.get_node_name() == "sampler2D")
534 break;
535 }
536 } else if (parser.get_node_name() == "surface") {
537
538 while (parser.read() == OK) {
539
540 if (parser.get_node_type() == XMLParser::NODE_ELEMENT) {
541
542 if (parser.get_node_name() == "init_from") {
543
544 parser.read();
545
546 if (parser.get_node_type() == XMLParser::NODE_TEXT) {
547
548 data = parser.get_node_data();
549 }
550 }
551 } else if (parser.get_node_type() == XMLParser::NODE_ELEMENT_END && parser.get_node_name() == "surface")
552 break;
553 }
554 }
555
556 } else if (parser.get_node_type() == XMLParser::NODE_ELEMENT_END && parser.get_node_name() == from)
557 break;
558 }
559
560 COLLADA_PRINT("newparam ending " + parser.get_node_name());
561 return data;
562 }
563
_parse_effect_material(XMLParser & parser,Effect & effect,String & id)564 void Collada::_parse_effect_material(XMLParser &parser, Effect &effect, String &id) {
565
566 if (!(state.import_flags & IMPORT_FLAG_SCENE)) {
567 if (!parser.is_empty())
568 parser.skip_section();
569 return;
570 }
571
572 while (parser.read() == OK) {
573
574 if (parser.get_node_type() == XMLParser::NODE_ELEMENT) {
575
576 // first come the tags we descend, but ignore the top-levels
577
578 COLLADA_PRINT("node name: " + parser.get_node_name());
579
580 if (!parser.is_empty() && (parser.get_node_name() == "profile_COMMON" || parser.get_node_name() == "technique" || parser.get_node_name() == "extra")) {
581
582 _parse_effect_material(parser, effect, id); // try again
583
584 } else if (parser.get_node_name() == "newparam") {
585 String name = parser.get_attribute_value("sid");
586 Variant value = _parse_param(parser);
587 effect.params[name] = value;
588 COLLADA_PRINT("param: " + name + " value:" + String(value));
589
590 } else if (parser.get_node_name() == "constant" ||
591 parser.get_node_name() == "lambert" ||
592 parser.get_node_name() == "phong" ||
593 parser.get_node_name() == "blinn") {
594
595 COLLADA_PRINT("shade model: " + parser.get_node_name());
596 while (parser.read() == OK) {
597
598 if (parser.get_node_type() == XMLParser::NODE_ELEMENT) {
599
600 String what = parser.get_node_name();
601
602 if (what == "emission" ||
603 what == "diffuse" ||
604 what == "specular" ||
605 what == "reflective") {
606
607 // color or texture types
608 while (parser.read() == OK) {
609
610 if (parser.get_node_type() == XMLParser::NODE_ELEMENT) {
611
612 if (parser.get_node_name() == "color") {
613
614 Vector<float> colorarr = _read_float_array(parser);
615 COLLADA_PRINT("colorarr size: " + rtos(colorarr.size()));
616
617 if (colorarr.size() >= 3) {
618
619 // alpha strangely not alright? maybe it needs to be multiplied by value as a channel intensity
620 Color color(colorarr[0], colorarr[1], colorarr[2], 1.0);
621 if (what == "diffuse")
622 effect.diffuse.color = color;
623 if (what == "specular")
624 effect.specular.color = color;
625 if (what == "emission")
626 effect.emission.color = color;
627
628 COLLADA_PRINT(what + " color: " + color);
629 }
630
631 } else if (parser.get_node_name() == "texture") {
632
633 String sampler = parser.get_attribute_value("texture");
634 if (!effect.params.has(sampler)) {
635 ERR_PRINT(String("Couldn't find sampler: " + sampler + " in material:" + id).utf8().get_data());
636 } else {
637 String surface = effect.params[sampler];
638
639 if (!effect.params.has(surface)) {
640 ERR_PRINT(String("Couldn't find surface: " + surface + " in material:" + id).utf8().get_data());
641 } else {
642 String uri = effect.params[surface];
643
644 if (what == "diffuse") {
645 effect.diffuse.texture = uri;
646 } else if (what == "specular") {
647 effect.specular.texture = uri;
648 } else if (what == "emission") {
649 effect.emission.texture = uri;
650 } else if (what == "bump") {
651 if (parser.has_attribute("bumptype") && parser.get_attribute_value("bumptype") != "NORMALMAP") {
652 WARN_PRINT("'bump' texture type is not NORMALMAP, only NORMALMAP is supported.");
653 }
654
655 effect.bump.texture = uri;
656 }
657
658 COLLADA_PRINT(what + " texture: " + uri);
659 }
660 }
661 } else if (!parser.is_empty())
662 parser.skip_section();
663
664 } else if (parser.get_node_type() == XMLParser::NODE_ELEMENT_END && parser.get_node_name() == what)
665 break;
666 }
667
668 } else if (what == "shininess") {
669 effect.shininess = _parse_param(parser);
670 }
671 } else if (parser.get_node_type() == XMLParser::NODE_ELEMENT_END && (parser.get_node_name() == "constant" ||
672 parser.get_node_name() == "lambert" ||
673 parser.get_node_name() == "phong" ||
674 parser.get_node_name() == "blinn"))
675 break;
676 }
677 } else if (parser.get_node_name() == "double_sided" || parser.get_node_name() == "show_double_sided") { // colladamax / google earth
678
679 // 3DS Max / Google Earth double sided extension
680 parser.read();
681 effect.found_double_sided = true;
682 effect.double_sided = parser.get_node_data().to_int();
683 COLLADA_PRINT("double sided: " + itos(parser.get_node_data().to_int()));
684 } else if (parser.get_node_name() == "unshaded") {
685 parser.read();
686 effect.unshaded = parser.get_node_data().to_int();
687 } else if (parser.get_node_name() == "bump") {
688
689 // color or texture types
690 while (parser.read() == OK) {
691
692 if (parser.get_node_type() == XMLParser::NODE_ELEMENT) {
693
694 if (parser.get_node_name() == "texture") {
695
696 String sampler = parser.get_attribute_value("texture");
697 if (!effect.params.has(sampler)) {
698 ERR_PRINT(String("Couldn't find sampler: " + sampler + " in material:" + id).utf8().get_data());
699 } else {
700 String surface = effect.params[sampler];
701
702 if (!effect.params.has(surface)) {
703 ERR_PRINT(String("Couldn't find surface: " + surface + " in material:" + id).utf8().get_data());
704 } else {
705 String uri = effect.params[surface];
706
707 if (parser.has_attribute("bumptype") && parser.get_attribute_value("bumptype") != "NORMALMAP") {
708 WARN_PRINT("'bump' texture type is not NORMALMAP, only NORMALMAP is supported.");
709 }
710
711 effect.bump.texture = uri;
712 COLLADA_PRINT(" bump: " + uri);
713 }
714 }
715 } else if (!parser.is_empty())
716 parser.skip_section();
717
718 } else if (parser.get_node_type() == XMLParser::NODE_ELEMENT_END && parser.get_node_name() == "bump")
719 break;
720 }
721
722 } else if (!parser.is_empty())
723 parser.skip_section();
724 } else if (parser.get_node_type() == XMLParser::NODE_ELEMENT_END &&
725 (parser.get_node_name() == "effect" ||
726 parser.get_node_name() == "profile_COMMON" ||
727 parser.get_node_name() == "technique" ||
728 parser.get_node_name() == "extra"))
729 break;
730 }
731 }
732
_parse_effect(XMLParser & parser)733 void Collada::_parse_effect(XMLParser &parser) {
734
735 if (!(state.import_flags & IMPORT_FLAG_SCENE)) {
736 if (!parser.is_empty())
737 parser.skip_section();
738 return;
739 }
740
741 String id = parser.get_attribute_value("id");
742
743 Effect effect;
744 if (parser.has_attribute("name"))
745 effect.name = parser.get_attribute_value("name");
746 _parse_effect_material(parser, effect, id);
747
748 state.effect_map[id] = effect;
749
750 COLLADA_PRINT("Effect ID:" + id);
751 }
752
_parse_camera(XMLParser & parser)753 void Collada::_parse_camera(XMLParser &parser) {
754
755 if (!(state.import_flags & IMPORT_FLAG_SCENE)) {
756 if (!parser.is_empty())
757 parser.skip_section();
758 return;
759 }
760
761 String id = parser.get_attribute_value("id");
762
763 state.camera_data_map[id] = CameraData();
764 CameraData &camera = state.camera_data_map[id];
765
766 while (parser.read() == OK) {
767
768 if (parser.get_node_type() == XMLParser::NODE_ELEMENT) {
769
770 String name = parser.get_node_name();
771
772 if (name == "perspective") {
773
774 camera.mode = CameraData::MODE_PERSPECTIVE;
775 } else if (name == "orthographic") {
776
777 camera.mode = CameraData::MODE_ORTHOGONAL;
778 } else if (name == "xfov") {
779
780 parser.read();
781 camera.perspective.x_fov = parser.get_node_data().to_double();
782
783 } else if (name == "yfov") {
784
785 parser.read();
786 camera.perspective.y_fov = parser.get_node_data().to_double();
787 } else if (name == "xmag") {
788
789 parser.read();
790 camera.orthogonal.x_mag = parser.get_node_data().to_double();
791
792 } else if (name == "ymag") {
793
794 parser.read();
795 camera.orthogonal.y_mag = parser.get_node_data().to_double();
796 } else if (name == "aspect_ratio") {
797
798 parser.read();
799 camera.aspect = parser.get_node_data().to_double();
800
801 } else if (name == "znear") {
802
803 parser.read();
804 camera.z_near = parser.get_node_data().to_double();
805
806 } else if (name == "zfar") {
807
808 parser.read();
809 camera.z_far = parser.get_node_data().to_double();
810 }
811
812 } else if (parser.get_node_type() == XMLParser::NODE_ELEMENT_END && parser.get_node_name() == "camera")
813 break; //end of <asset>
814 }
815
816 COLLADA_PRINT("Camera ID:" + id);
817 }
818
_parse_light(XMLParser & parser)819 void Collada::_parse_light(XMLParser &parser) {
820
821 if (!(state.import_flags & IMPORT_FLAG_SCENE)) {
822 if (!parser.is_empty())
823 parser.skip_section();
824 return;
825 }
826
827 String id = parser.get_attribute_value("id");
828
829 state.light_data_map[id] = LightData();
830 LightData &light = state.light_data_map[id];
831
832 while (parser.read() == OK) {
833
834 if (parser.get_node_type() == XMLParser::NODE_ELEMENT) {
835
836 String name = parser.get_node_name();
837
838 if (name == "ambient") {
839
840 light.mode = LightData::MODE_AMBIENT;
841 } else if (name == "directional") {
842
843 light.mode = LightData::MODE_DIRECTIONAL;
844 } else if (name == "point") {
845
846 light.mode = LightData::MODE_OMNI;
847 } else if (name == "spot") {
848
849 light.mode = LightData::MODE_SPOT;
850 } else if (name == "color") {
851
852 parser.read();
853 Vector<float> colorarr = _read_float_array(parser);
854 COLLADA_PRINT("colorarr size: " + rtos(colorarr.size()));
855
856 if (colorarr.size() >= 4) {
857 // alpha strangely not alright? maybe it needs to be multiplied by value as a channel intensity
858 Color color(colorarr[0], colorarr[1], colorarr[2], 1.0);
859 light.color = color;
860 }
861
862 } else if (name == "constant_attenuation") {
863
864 parser.read();
865 light.constant_att = parser.get_node_data().to_double();
866 } else if (name == "linear_attenuation") {
867
868 parser.read();
869 light.linear_att = parser.get_node_data().to_double();
870 } else if (name == "quadratic_attenuation") {
871
872 parser.read();
873 light.quad_att = parser.get_node_data().to_double();
874 } else if (name == "falloff_angle") {
875
876 parser.read();
877 light.spot_angle = parser.get_node_data().to_double();
878
879 } else if (name == "falloff_exponent") {
880
881 parser.read();
882 light.spot_exp = parser.get_node_data().to_double();
883 }
884
885 } else if (parser.get_node_type() == XMLParser::NODE_ELEMENT_END && parser.get_node_name() == "light")
886 break; //end of <asset>
887 }
888
889 COLLADA_PRINT("Light ID:" + id);
890 }
891
_parse_curve_geometry(XMLParser & parser,String p_id,String p_name)892 void Collada::_parse_curve_geometry(XMLParser &parser, String p_id, String p_name) {
893
894 if (!(state.import_flags & IMPORT_FLAG_SCENE)) {
895 if (!parser.is_empty())
896 parser.skip_section();
897 return;
898 }
899
900 //load everything into a pre dictionary
901
902 state.curve_data_map[p_id] = CurveData();
903
904 CurveData &curvedata = state.curve_data_map[p_id];
905 curvedata.name = p_name;
906
907 COLLADA_PRINT("curve name: " + p_name);
908
909 String current_source;
910 // handles geometry node and the curve children in this loop
911 // read sources with arrays and accessor for each curve
912 if (parser.is_empty()) {
913 return;
914 }
915
916 while (parser.read() == OK) {
917
918 if (parser.get_node_type() == XMLParser::NODE_ELEMENT) {
919
920 String section = parser.get_node_name();
921
922 if (section == "source") {
923
924 String id = parser.get_attribute_value("id");
925 curvedata.sources[id] = CurveData::Source();
926 current_source = id;
927 COLLADA_PRINT("source data: " + id);
928
929 } else if (section == "float_array" || section == "array") {
930 // create a new array and read it.
931 if (curvedata.sources.has(current_source)) {
932
933 curvedata.sources[current_source].array = _read_float_array(parser);
934 COLLADA_PRINT("section: " + current_source + " read " + itos(curvedata.sources[current_source].array.size()) + " values.");
935 }
936 } else if (section == "Name_array") {
937 // create a new array and read it.
938 if (curvedata.sources.has(current_source)) {
939
940 curvedata.sources[current_source].sarray = _read_string_array(parser);
941 COLLADA_PRINT("section: " + current_source + " read " + itos(curvedata.sources[current_source].array.size()) + " values.");
942 }
943
944 } else if (section == "technique_common") {
945 //skip it
946 } else if (section == "accessor") { // child of source (below a technique tag)
947
948 if (curvedata.sources.has(current_source)) {
949 curvedata.sources[current_source].stride = parser.get_attribute_value("stride").to_int();
950 COLLADA_PRINT("section: " + current_source + " stride " + itos(curvedata.sources[current_source].stride));
951 }
952 } else if (section == "control_vertices") {
953
954 while (parser.read() == OK) {
955
956 if (parser.get_node_type() == XMLParser::NODE_ELEMENT) {
957
958 if (parser.get_node_name() == "input") {
959
960 String semantic = parser.get_attribute_value("semantic");
961 String source = _uri_to_id(parser.get_attribute_value("source"));
962
963 curvedata.control_vertices[semantic] = source;
964
965 COLLADA_PRINT(section + " input semantic: " + semantic + " source: " + source);
966 }
967 } else if (parser.get_node_type() == XMLParser::NODE_ELEMENT_END && parser.get_node_name() == section)
968 break;
969 }
970
971 } else if (!parser.is_empty()) {
972
973 parser.skip_section();
974 }
975 } else if (parser.get_node_type() == XMLParser::NODE_ELEMENT_END && parser.get_node_name() == "spline")
976 break;
977 }
978 }
979
_parse_mesh_geometry(XMLParser & parser,String p_id,String p_name)980 void Collada::_parse_mesh_geometry(XMLParser &parser, String p_id, String p_name) {
981
982 if (!(state.import_flags & IMPORT_FLAG_SCENE)) {
983 if (!parser.is_empty())
984 parser.skip_section();
985 return;
986 }
987
988 //load everything into a pre dictionary
989
990 state.mesh_data_map[p_id] = MeshData();
991
992 MeshData &meshdata = state.mesh_data_map[p_id];
993 meshdata.name = p_name;
994
995 COLLADA_PRINT("mesh name: " + p_name);
996
997 String current_source;
998 // handles geometry node and the mesh children in this loop
999 // read sources with arrays and accessor for each mesh
1000 if (parser.is_empty()) {
1001 return;
1002 }
1003
1004 while (parser.read() == OK) {
1005
1006 if (parser.get_node_type() == XMLParser::NODE_ELEMENT) {
1007
1008 String section = parser.get_node_name();
1009
1010 if (section == "source") {
1011
1012 String id = parser.get_attribute_value("id");
1013 meshdata.sources[id] = MeshData::Source();
1014 current_source = id;
1015 COLLADA_PRINT("source data: " + id);
1016
1017 } else if (section == "float_array" || section == "array") {
1018 // create a new array and read it.
1019 if (meshdata.sources.has(current_source)) {
1020
1021 meshdata.sources[current_source].array = _read_float_array(parser);
1022 COLLADA_PRINT("section: " + current_source + " read " + itos(meshdata.sources[current_source].array.size()) + " values.");
1023 }
1024 } else if (section == "technique_common") {
1025 //skip it
1026 } else if (section == "accessor") { // child of source (below a technique tag)
1027
1028 if (meshdata.sources.has(current_source)) {
1029 meshdata.sources[current_source].stride = parser.get_attribute_value("stride").to_int();
1030 COLLADA_PRINT("section: " + current_source + " stride " + itos(meshdata.sources[current_source].stride));
1031 }
1032 } else if (section == "vertices") {
1033
1034 MeshData::Vertices vert;
1035 String id = parser.get_attribute_value("id");
1036
1037 while (parser.read() == OK) {
1038
1039 if (parser.get_node_type() == XMLParser::NODE_ELEMENT) {
1040
1041 if (parser.get_node_name() == "input") {
1042
1043 String semantic = parser.get_attribute_value("semantic");
1044 String source = _uri_to_id(parser.get_attribute_value("source"));
1045
1046 vert.sources[semantic] = source;
1047
1048 COLLADA_PRINT(section + " input semantic: " + semantic + " source: " + source);
1049 }
1050 } else if (parser.get_node_type() == XMLParser::NODE_ELEMENT_END && parser.get_node_name() == section)
1051 break;
1052 }
1053
1054 meshdata.vertices[id] = vert;
1055
1056 } else if (section == "triangles" || section == "polylist" || section == "polygons") {
1057
1058 bool polygons = (section == "polygons");
1059 if (polygons) {
1060 WARN_PRINT("Primitive type \"polygons\" is not well supported (concave shapes may fail). To ensure that the geometry is properly imported, please re-export using \"triangles\" or \"polylist\".");
1061 }
1062 MeshData::Primitives prim;
1063
1064 if (parser.has_attribute("material"))
1065 prim.material = parser.get_attribute_value("material");
1066 prim.count = parser.get_attribute_value("count").to_int();
1067 prim.vertex_size = 0;
1068 int last_ref = 0;
1069
1070 while (parser.read() == OK) {
1071
1072 if (parser.get_node_type() == XMLParser::NODE_ELEMENT) {
1073
1074 if (parser.get_node_name() == "input") {
1075
1076 String semantic = parser.get_attribute_value("semantic");
1077 String source = _uri_to_id(parser.get_attribute_value("source"));
1078
1079 if (semantic == "TEXCOORD") {
1080 /*
1081 if (parser.has_attribute("set"))// a texcoord
1082 semantic+=parser.get_attribute_value("set");
1083 else
1084 semantic="TEXCOORD0";*/
1085 semantic = "TEXCOORD" + itos(last_ref++);
1086 }
1087 int offset = parser.get_attribute_value("offset").to_int();
1088
1089 MeshData::Primitives::SourceRef sref;
1090 sref.source = source;
1091 sref.offset = offset;
1092 prim.sources[semantic] = sref;
1093 prim.vertex_size = MAX(prim.vertex_size, offset + 1);
1094
1095 COLLADA_PRINT(section + " input semantic: " + semantic + " source: " + source + " offset: " + itos(offset));
1096
1097 } else if (parser.get_node_name() == "p") { //indices
1098
1099 Vector<float> values = _read_float_array(parser);
1100 if (polygons) {
1101
1102 ERR_CONTINUE(prim.vertex_size == 0);
1103 prim.polygons.push_back(values.size() / prim.vertex_size);
1104 int from = prim.indices.size();
1105 prim.indices.resize(from + values.size());
1106 for (int i = 0; i < values.size(); i++)
1107 prim.indices.write[from + i] = values[i];
1108
1109 } else if (prim.vertex_size > 0) {
1110 prim.indices = values;
1111 }
1112
1113 COLLADA_PRINT("read " + itos(values.size()) + " index values");
1114
1115 } else if (parser.get_node_name() == "vcount") { // primitive
1116
1117 Vector<float> values = _read_float_array(parser);
1118 prim.polygons = values;
1119 COLLADA_PRINT("read " + itos(values.size()) + " polygon values");
1120 }
1121 } else if (parser.get_node_type() == XMLParser::NODE_ELEMENT_END && parser.get_node_name() == section)
1122 break;
1123 }
1124
1125 meshdata.primitives.push_back(prim);
1126
1127 } else if (parser.get_node_name() == "double_sided") {
1128
1129 parser.read();
1130 meshdata.found_double_sided = true;
1131 meshdata.double_sided = parser.get_node_data().to_int();
1132
1133 } else if (parser.get_node_name() == "polygons") {
1134 ERR_PRINT("Primitive type \"polygons\" not supported, re-export using \"polylist\" or \"triangles\".");
1135 } else if (!parser.is_empty()) {
1136
1137 parser.skip_section();
1138 }
1139 } else if (parser.get_node_type() == XMLParser::NODE_ELEMENT_END && parser.get_node_name() == "mesh")
1140 break;
1141 }
1142 }
1143
_parse_skin_controller(XMLParser & parser,String p_id)1144 void Collada::_parse_skin_controller(XMLParser &parser, String p_id) {
1145
1146 state.skin_controller_data_map[p_id] = SkinControllerData();
1147 SkinControllerData &skindata = state.skin_controller_data_map[p_id];
1148
1149 skindata.base = _uri_to_id(parser.get_attribute_value("source"));
1150
1151 String current_source;
1152
1153 while (parser.read() == OK) {
1154
1155 if (parser.get_node_type() == XMLParser::NODE_ELEMENT) {
1156
1157 String section = parser.get_node_name();
1158
1159 if (section == "bind_shape_matrix") {
1160
1161 skindata.bind_shape = _read_transform(parser);
1162 #ifdef COLLADA_IMPORT_SCALE_SCENE
1163 skindata.bind_shape.origin *= state.unit_scale;
1164
1165 #endif
1166 COLLADA_PRINT("skeleton bind shape transform: " + skindata.bind_shape);
1167
1168 } else if (section == "source") {
1169
1170 String id = parser.get_attribute_value("id");
1171 skindata.sources[id] = SkinControllerData::Source();
1172 current_source = id;
1173 COLLADA_PRINT("source data: " + id);
1174
1175 } else if (section == "float_array" || section == "array") {
1176 // create a new array and read it.
1177 if (skindata.sources.has(current_source)) {
1178
1179 skindata.sources[current_source].array = _read_float_array(parser);
1180 COLLADA_PRINT("section: " + current_source + " read " + itos(skindata.sources[current_source].array.size()) + " values.");
1181 }
1182 } else if (section == "Name_array" || section == "IDREF_array") {
1183 // create a new array and read it.
1184
1185 if (section == "IDREF_array")
1186 skindata.use_idrefs = true;
1187 if (skindata.sources.has(current_source)) {
1188
1189 skindata.sources[current_source].sarray = _read_string_array(parser);
1190 if (section == "IDREF_array") {
1191 Vector<String> sa = skindata.sources[current_source].sarray;
1192 for (int i = 0; i < sa.size(); i++)
1193 state.idref_joints.insert(sa[i]);
1194 }
1195 COLLADA_PRINT("section: " + current_source + " read " + itos(skindata.sources[current_source].array.size()) + " values.");
1196 }
1197 } else if (section == "technique_common") {
1198 //skip it
1199 } else if (section == "accessor") { // child of source (below a technique tag)
1200
1201 if (skindata.sources.has(current_source)) {
1202
1203 int stride = 1;
1204 if (parser.has_attribute("stride"))
1205 stride = parser.get_attribute_value("stride").to_int();
1206
1207 skindata.sources[current_source].stride = stride;
1208 COLLADA_PRINT("section: " + current_source + " stride " + itos(skindata.sources[current_source].stride));
1209 }
1210
1211 } else if (section == "joints") {
1212
1213 SkinControllerData::Joints joint;
1214
1215 while (parser.read() == OK) {
1216
1217 if (parser.get_node_type() == XMLParser::NODE_ELEMENT) {
1218
1219 if (parser.get_node_name() == "input") {
1220
1221 String semantic = parser.get_attribute_value("semantic");
1222 String source = _uri_to_id(parser.get_attribute_value("source"));
1223
1224 joint.sources[semantic] = source;
1225
1226 COLLADA_PRINT(section + " input semantic: " + semantic + " source: " + source);
1227 }
1228 } else if (parser.get_node_type() == XMLParser::NODE_ELEMENT_END && parser.get_node_name() == section)
1229 break;
1230 }
1231
1232 skindata.joints = joint;
1233
1234 } else if (section == "vertex_weights") {
1235
1236 SkinControllerData::Weights weights;
1237
1238 weights.count = parser.get_attribute_value("count").to_int();
1239
1240 while (parser.read() == OK) {
1241
1242 if (parser.get_node_type() == XMLParser::NODE_ELEMENT) {
1243
1244 if (parser.get_node_name() == "input") {
1245
1246 String semantic = parser.get_attribute_value("semantic");
1247 String source = _uri_to_id(parser.get_attribute_value("source"));
1248
1249 int offset = parser.get_attribute_value("offset").to_int();
1250
1251 SkinControllerData::Weights::SourceRef sref;
1252 sref.source = source;
1253 sref.offset = offset;
1254 weights.sources[semantic] = sref;
1255
1256 COLLADA_PRINT(section + " input semantic: " + semantic + " source: " + source + " offset: " + itos(offset));
1257
1258 } else if (parser.get_node_name() == "v") { //indices
1259
1260 Vector<float> values = _read_float_array(parser);
1261 weights.indices = values;
1262 COLLADA_PRINT("read " + itos(values.size()) + " index values");
1263
1264 } else if (parser.get_node_name() == "vcount") { // weightsitive
1265
1266 Vector<float> values = _read_float_array(parser);
1267 weights.sets = values;
1268 COLLADA_PRINT("read " + itos(values.size()) + " polygon values");
1269 }
1270 } else if (parser.get_node_type() == XMLParser::NODE_ELEMENT_END && parser.get_node_name() == section)
1271 break;
1272 }
1273
1274 skindata.weights = weights;
1275 }
1276 /*
1277 else if (!parser.is_empty())
1278 parser.skip_section();
1279 */
1280
1281 } else if (parser.get_node_type() == XMLParser::NODE_ELEMENT_END && parser.get_node_name() == "skin")
1282 break;
1283 }
1284
1285 /* STORE REST MATRICES */
1286
1287 Vector<Transform> rests;
1288 ERR_FAIL_COND(!skindata.joints.sources.has("JOINT"));
1289 ERR_FAIL_COND(!skindata.joints.sources.has("INV_BIND_MATRIX"));
1290
1291 String joint_arr = skindata.joints.sources["JOINT"];
1292 String ibm = skindata.joints.sources["INV_BIND_MATRIX"];
1293
1294 ERR_FAIL_COND(!skindata.sources.has(joint_arr));
1295 ERR_FAIL_COND(!skindata.sources.has(ibm));
1296
1297 SkinControllerData::Source &joint_source = skindata.sources[joint_arr];
1298 SkinControllerData::Source &ibm_source = skindata.sources[ibm];
1299
1300 ERR_FAIL_COND(joint_source.sarray.size() != ibm_source.array.size() / 16);
1301
1302 for (int i = 0; i < joint_source.sarray.size(); i++) {
1303
1304 String name = joint_source.sarray[i];
1305 Transform xform = _read_transform_from_array(ibm_source.array, i * 16); //<- this is a mistake, it must be applied to vertices
1306 xform.affine_invert(); // inverse for rest, because it's an inverse
1307 #ifdef COLLADA_IMPORT_SCALE_SCENE
1308 xform.origin *= state.unit_scale;
1309 #endif
1310 skindata.bone_rest_map[name] = xform;
1311 }
1312 }
1313
_parse_morph_controller(XMLParser & parser,String p_id)1314 void Collada::_parse_morph_controller(XMLParser &parser, String p_id) {
1315
1316 state.morph_controller_data_map[p_id] = MorphControllerData();
1317 MorphControllerData &morphdata = state.morph_controller_data_map[p_id];
1318
1319 morphdata.mesh = _uri_to_id(parser.get_attribute_value("source"));
1320 morphdata.mode = parser.get_attribute_value("method");
1321 String current_source;
1322
1323 while (parser.read() == OK) {
1324
1325 if (parser.get_node_type() == XMLParser::NODE_ELEMENT) {
1326
1327 String section = parser.get_node_name();
1328
1329 if (section == "source") {
1330
1331 String id = parser.get_attribute_value("id");
1332 morphdata.sources[id] = MorphControllerData::Source();
1333 current_source = id;
1334 COLLADA_PRINT("source data: " + id);
1335
1336 } else if (section == "float_array" || section == "array") {
1337 // create a new array and read it.
1338 if (morphdata.sources.has(current_source)) {
1339
1340 morphdata.sources[current_source].array = _read_float_array(parser);
1341 COLLADA_PRINT("section: " + current_source + " read " + itos(morphdata.sources[current_source].array.size()) + " values.");
1342 }
1343 } else if (section == "Name_array" || section == "IDREF_array") {
1344 // create a new array and read it.
1345
1346 /*
1347 if (section=="IDREF_array")
1348 morphdata.use_idrefs=true;
1349 */
1350 if (morphdata.sources.has(current_source)) {
1351
1352 morphdata.sources[current_source].sarray = _read_string_array(parser);
1353 /*
1354 if (section=="IDREF_array") {
1355 Vector<String> sa = morphdata.sources[current_source].sarray;
1356 for(int i=0;i<sa.size();i++)
1357 state.idref_joints.insert(sa[i]);
1358 }*/
1359 COLLADA_PRINT("section: " + current_source + " read " + itos(morphdata.sources[current_source].array.size()) + " values.");
1360 }
1361 } else if (section == "technique_common") {
1362 //skip it
1363 } else if (section == "accessor") { // child of source (below a technique tag)
1364
1365 if (morphdata.sources.has(current_source)) {
1366
1367 int stride = 1;
1368 if (parser.has_attribute("stride"))
1369 stride = parser.get_attribute_value("stride").to_int();
1370
1371 morphdata.sources[current_source].stride = stride;
1372 COLLADA_PRINT("section: " + current_source + " stride " + itos(morphdata.sources[current_source].stride));
1373 }
1374
1375 } else if (section == "targets") {
1376
1377 while (parser.read() == OK) {
1378
1379 if (parser.get_node_type() == XMLParser::NODE_ELEMENT) {
1380
1381 if (parser.get_node_name() == "input") {
1382
1383 String semantic = parser.get_attribute_value("semantic");
1384 String source = _uri_to_id(parser.get_attribute_value("source"));
1385
1386 morphdata.targets[semantic] = source;
1387
1388 COLLADA_PRINT(section + " input semantic: " + semantic + " source: " + source);
1389 }
1390 } else if (parser.get_node_type() == XMLParser::NODE_ELEMENT_END && parser.get_node_name() == section)
1391 break;
1392 }
1393 }
1394 /*
1395 else if (!parser.is_empty())
1396 parser.skip_section();
1397 */
1398
1399 } else if (parser.get_node_type() == XMLParser::NODE_ELEMENT_END && parser.get_node_name() == "morph")
1400 break;
1401 }
1402
1403 if (morphdata.targets.has("MORPH_WEIGHT")) {
1404
1405 state.morph_name_map[morphdata.targets["MORPH_WEIGHT"]] = p_id;
1406 }
1407 }
1408
_parse_controller(XMLParser & parser)1409 void Collada::_parse_controller(XMLParser &parser) {
1410
1411 String id = parser.get_attribute_value("id");
1412
1413 if (parser.is_empty()) {
1414 return;
1415 }
1416
1417 while (parser.read() == OK) {
1418
1419 if (parser.get_node_type() == XMLParser::NODE_ELEMENT) {
1420
1421 String section = parser.get_node_name();
1422
1423 if (section == "skin") {
1424 _parse_skin_controller(parser, id);
1425 } else if (section == "morph") {
1426 _parse_morph_controller(parser, id);
1427 }
1428 } else if (parser.get_node_type() == XMLParser::NODE_ELEMENT_END && parser.get_node_name() == "controller")
1429 break;
1430 }
1431 }
1432
_parse_visual_instance_geometry(XMLParser & parser)1433 Collada::Node *Collada::_parse_visual_instance_geometry(XMLParser &parser) {
1434
1435 String type = parser.get_node_name();
1436 NodeGeometry *geom = memnew(NodeGeometry);
1437 geom->controller = type == "instance_controller";
1438 geom->source = _uri_to_id(parser.get_attribute_value_safe("url"));
1439
1440 if (parser.is_empty()) //nothing else to parse...
1441 return geom;
1442 // try to find also many materials and skeletons!
1443 while (parser.read() == OK) {
1444
1445 if (parser.get_node_type() == XMLParser::NODE_ELEMENT) {
1446
1447 if (parser.get_node_name() == "instance_material") {
1448
1449 String symbol = parser.get_attribute_value("symbol");
1450 String target = _uri_to_id(parser.get_attribute_value("target"));
1451
1452 NodeGeometry::Material mat;
1453 mat.target = target;
1454 geom->material_map[symbol] = mat;
1455 COLLADA_PRINT("uses material: '" + target + "' on primitive'" + symbol + "'");
1456 } else if (parser.get_node_name() == "skeleton") {
1457
1458 parser.read();
1459 String uri = _uri_to_id(parser.get_node_data());
1460 if (uri != "") {
1461 geom->skeletons.push_back(uri);
1462 }
1463 }
1464
1465 } else if (parser.get_node_type() == XMLParser::NODE_ELEMENT_END && parser.get_node_name() == type)
1466 break;
1467 }
1468
1469 if (geom->controller) {
1470
1471 if (geom->skeletons.empty()) {
1472 //XSI style
1473
1474 if (state.skin_controller_data_map.has(geom->source)) {
1475 SkinControllerData *skin = &state.skin_controller_data_map[geom->source];
1476 //case where skeletons reference bones with IDREF (XSI)
1477 ERR_FAIL_COND_V(!skin->joints.sources.has("JOINT"), geom);
1478 String joint_arr = skin->joints.sources["JOINT"];
1479 ERR_FAIL_COND_V(!skin->sources.has(joint_arr), geom);
1480 Collada::SkinControllerData::Source &joint_source = skin->sources[joint_arr];
1481 geom->skeletons = joint_source.sarray; //quite crazy, but should work.
1482 }
1483 }
1484 }
1485
1486 return geom;
1487 }
1488
_parse_visual_instance_camera(XMLParser & parser)1489 Collada::Node *Collada::_parse_visual_instance_camera(XMLParser &parser) {
1490
1491 NodeCamera *cam = memnew(NodeCamera);
1492 cam->camera = _uri_to_id(parser.get_attribute_value_safe("url"));
1493
1494 if (state.up_axis == Vector3::AXIS_Z) //collada weirdness
1495 cam->post_transform.basis.rotate(Vector3(1, 0, 0), -Math_PI * 0.5);
1496
1497 if (parser.is_empty()) //nothing else to parse...
1498 return cam;
1499
1500 while (parser.read() == OK) {
1501
1502 if (parser.get_node_type() == XMLParser::NODE_ELEMENT_END && parser.get_node_name() == "instance_camera")
1503 break;
1504 }
1505
1506 return cam;
1507 }
1508
_parse_visual_instance_light(XMLParser & parser)1509 Collada::Node *Collada::_parse_visual_instance_light(XMLParser &parser) {
1510
1511 NodeLight *cam = memnew(NodeLight);
1512 cam->light = _uri_to_id(parser.get_attribute_value_safe("url"));
1513
1514 if (state.up_axis == Vector3::AXIS_Z) //collada weirdness
1515 cam->post_transform.basis.rotate(Vector3(1, 0, 0), -Math_PI * 0.5);
1516
1517 if (parser.is_empty()) //nothing else to parse...
1518 return cam;
1519
1520 while (parser.read() == OK) {
1521
1522 if (parser.get_node_type() == XMLParser::NODE_ELEMENT_END && parser.get_node_name() == "instance_light")
1523 break;
1524 }
1525
1526 return cam;
1527 }
1528
_parse_visual_node_instance_data(XMLParser & parser)1529 Collada::Node *Collada::_parse_visual_node_instance_data(XMLParser &parser) {
1530
1531 String instance_type = parser.get_node_name();
1532
1533 if (instance_type == "instance_geometry" || instance_type == "instance_controller") {
1534 return _parse_visual_instance_geometry(parser);
1535 } else if (instance_type == "instance_camera") {
1536
1537 return _parse_visual_instance_camera(parser);
1538 } else if (instance_type == "instance_light") {
1539 return _parse_visual_instance_light(parser);
1540 }
1541
1542 if (parser.is_empty()) //nothing else to parse...
1543 return NULL;
1544
1545 while (parser.read() == OK) {
1546
1547 if (parser.get_node_type() == XMLParser::NODE_ELEMENT_END && parser.get_node_name() == instance_type)
1548 break;
1549 }
1550
1551 return NULL;
1552 }
1553
_parse_visual_scene_node(XMLParser & parser)1554 Collada::Node *Collada::_parse_visual_scene_node(XMLParser &parser) {
1555
1556 String name;
1557
1558 String id = parser.get_attribute_value_safe("id");
1559
1560 bool found_name = false;
1561
1562 if (id == "") {
1563
1564 id = "%NODEID%" + itos(Math::rand());
1565
1566 } else {
1567 found_name = true;
1568 }
1569
1570 Vector<Node::XForm> xform_list;
1571 Vector<Node *> children;
1572
1573 String empty_draw_type = "";
1574
1575 Node *node = NULL;
1576
1577 name = parser.has_attribute("name") ? parser.get_attribute_value_safe("name") : parser.get_attribute_value_safe("id");
1578 if (name == "") {
1579
1580 name = id;
1581 } else {
1582 found_name = true;
1583 }
1584
1585 if ((parser.has_attribute("type") && parser.get_attribute_value("type") == "JOINT") || state.idref_joints.has(name)) {
1586 // handle a bone
1587
1588 NodeJoint *joint = memnew(NodeJoint);
1589
1590 if (parser.has_attribute("sid")) { //bones may not have sid
1591 joint->sid = parser.get_attribute_value("sid");
1592 //state.bone_map[joint->sid]=joint;
1593 } else if (state.idref_joints.has(name)) {
1594 joint->sid = name; //kind of a cheat but..
1595 } else if (parser.has_attribute("name")) {
1596 joint->sid = parser.get_attribute_value_safe("name");
1597 }
1598
1599 if (joint->sid != "") {
1600 state.sid_to_node_map[joint->sid] = id;
1601 }
1602
1603 node = joint;
1604 }
1605
1606 while (parser.read() == OK) {
1607
1608 if (parser.get_node_type() == XMLParser::NODE_ELEMENT) {
1609
1610 String section = parser.get_node_name();
1611
1612 if (section == "translate") {
1613 Node::XForm xf;
1614 if (parser.has_attribute("sid")) {
1615 xf.id = parser.get_attribute_value("sid");
1616 }
1617 xf.op = Node::XForm::OP_TRANSLATE;
1618
1619 Vector<float> xlt = _read_float_array(parser);
1620 xf.data = xlt;
1621 xform_list.push_back(xf);
1622
1623 } else if (section == "rotate") {
1624 Node::XForm xf;
1625 if (parser.has_attribute("sid")) {
1626 xf.id = parser.get_attribute_value("sid");
1627 }
1628 xf.op = Node::XForm::OP_ROTATE;
1629
1630 Vector<float> rot = _read_float_array(parser);
1631 xf.data = rot;
1632
1633 xform_list.push_back(xf);
1634
1635 } else if (section == "scale") {
1636 Node::XForm xf;
1637 if (parser.has_attribute("sid")) {
1638 xf.id = parser.get_attribute_value("sid");
1639 }
1640
1641 xf.op = Node::XForm::OP_SCALE;
1642
1643 Vector<float> scale = _read_float_array(parser);
1644
1645 xf.data = scale;
1646
1647 xform_list.push_back(xf);
1648
1649 } else if (section == "matrix") {
1650 Node::XForm xf;
1651 if (parser.has_attribute("sid")) {
1652 xf.id = parser.get_attribute_value("sid");
1653 }
1654 xf.op = Node::XForm::OP_MATRIX;
1655
1656 Vector<float> matrix = _read_float_array(parser);
1657
1658 xf.data = matrix;
1659 String mtx;
1660 for (int i = 0; i < matrix.size(); i++)
1661 mtx += " " + rtos(matrix[i]);
1662
1663 xform_list.push_back(xf);
1664
1665 } else if (section == "visibility") {
1666 Node::XForm xf;
1667 if (parser.has_attribute("sid")) {
1668 xf.id = parser.get_attribute_value("sid");
1669 }
1670 xf.op = Node::XForm::OP_VISIBILITY;
1671
1672 Vector<float> visible = _read_float_array(parser);
1673
1674 xf.data = visible;
1675
1676 xform_list.push_back(xf);
1677
1678 } else if (section == "empty_draw_type") {
1679 empty_draw_type = _read_empty_draw_type(parser);
1680 } else if (section == "technique" || section == "extra") {
1681
1682 } else if (section != "node") {
1683 //usually what defines the type of node
1684 if (section.begins_with("instance_")) {
1685
1686 if (!node) {
1687
1688 node = _parse_visual_node_instance_data(parser);
1689
1690 } else {
1691 ERR_PRINT("Multiple instance_* not supported.");
1692 }
1693 }
1694
1695 } else {
1696
1697 /* Found a child node!! what to do..*/
1698
1699 Node *child = _parse_visual_scene_node(parser);
1700 children.push_back(child);
1701 }
1702
1703 } else if (parser.get_node_type() == XMLParser::NODE_ELEMENT_END && parser.get_node_name() == "node")
1704 break;
1705 }
1706
1707 if (!node) {
1708
1709 node = memnew(Node); //generic node, nothing of relevance found
1710 }
1711
1712 node->noname = !found_name;
1713 node->xform_list = xform_list;
1714 node->children = children;
1715 for (int i = 0; i < children.size(); i++) {
1716 node->children[i]->parent = node;
1717 }
1718
1719 node->name = name;
1720 node->id = id;
1721 node->empty_draw_type = empty_draw_type;
1722
1723 if (node->children.size() == 1) {
1724 if (node->children[0]->noname && !node->noname) {
1725 node->children[0]->name = node->name;
1726 node->name = node->name + "-base";
1727 }
1728 }
1729
1730 node->default_transform = node->compute_transform(*this);
1731 state.scene_map[id] = node;
1732
1733 return node;
1734 }
1735
_parse_visual_scene(XMLParser & parser)1736 void Collada::_parse_visual_scene(XMLParser &parser) {
1737
1738 String id = parser.get_attribute_value("id");
1739
1740 if (parser.is_empty()) {
1741 return;
1742 }
1743
1744 state.visual_scene_map[id] = VisualScene();
1745 VisualScene &vscene = state.visual_scene_map[id];
1746
1747 if (parser.has_attribute("name"))
1748 vscene.name = parser.get_attribute_value("name");
1749
1750 while (parser.read() == OK) {
1751
1752 if (parser.get_node_type() == XMLParser::NODE_ELEMENT) {
1753
1754 String section = parser.get_node_name();
1755
1756 if (section == "node") {
1757 vscene.root_nodes.push_back(_parse_visual_scene_node(parser));
1758 }
1759
1760 } else if (parser.get_node_type() == XMLParser::NODE_ELEMENT_END && parser.get_node_name() == "visual_scene")
1761 break;
1762 }
1763
1764 COLLADA_PRINT("Scene ID:" + id);
1765 }
1766
_parse_animation(XMLParser & parser)1767 void Collada::_parse_animation(XMLParser &parser) {
1768
1769 if (!(state.import_flags & IMPORT_FLAG_ANIMATION)) {
1770 if (!parser.is_empty())
1771 parser.skip_section();
1772
1773 return;
1774 }
1775
1776 Map<String, Vector<float> > float_sources;
1777 Map<String, Vector<String> > string_sources;
1778 Map<String, int> source_strides;
1779 Map<String, Map<String, String> > samplers;
1780 Map<String, Vector<String> > source_param_names;
1781 Map<String, Vector<String> > source_param_types;
1782
1783 String id = "";
1784 if (parser.has_attribute("id"))
1785 id = parser.get_attribute_value("id");
1786
1787 String current_source;
1788 String current_sampler;
1789 Vector<String> channel_sources;
1790 Vector<String> channel_targets;
1791
1792 while (parser.read() == OK) {
1793
1794 if (parser.get_node_type() == XMLParser::NODE_ELEMENT) {
1795
1796 String name = parser.get_node_name();
1797 if (name == "source") {
1798
1799 current_source = parser.get_attribute_value("id");
1800 source_param_names[current_source] = Vector<String>();
1801 source_param_types[current_source] = Vector<String>();
1802
1803 } else if (name == "float_array") {
1804
1805 if (current_source != "") {
1806 float_sources[current_source] = _read_float_array(parser);
1807 }
1808
1809 } else if (name == "Name_array") {
1810
1811 if (current_source != "") {
1812 string_sources[current_source] = _read_string_array(parser);
1813 }
1814 } else if (name == "accessor") {
1815
1816 if (current_source != "" && parser.has_attribute("stride")) {
1817 source_strides[current_source] = parser.get_attribute_value("stride").to_int();
1818 }
1819 } else if (name == "sampler") {
1820
1821 current_sampler = parser.get_attribute_value("id");
1822 samplers[current_sampler] = Map<String, String>();
1823 } else if (name == "param") {
1824
1825 if (parser.has_attribute("name"))
1826 source_param_names[current_source].push_back(parser.get_attribute_value("name"));
1827 else
1828 source_param_names[current_source].push_back("");
1829
1830 if (parser.has_attribute("type"))
1831 source_param_types[current_source].push_back(parser.get_attribute_value("type"));
1832 else
1833 source_param_types[current_source].push_back("");
1834
1835 } else if (name == "input") {
1836
1837 if (current_sampler != "") {
1838
1839 samplers[current_sampler][parser.get_attribute_value("semantic")] = parser.get_attribute_value("source");
1840 }
1841
1842 } else if (name == "channel") {
1843
1844 channel_sources.push_back(parser.get_attribute_value("source"));
1845 channel_targets.push_back(parser.get_attribute_value("target"));
1846 }
1847
1848 } else if (parser.get_node_type() == XMLParser::NODE_ELEMENT_END && parser.get_node_name() == "animation")
1849 break; //end of <asset>
1850 }
1851
1852 for (int i = 0; i < channel_sources.size(); i++) {
1853
1854 String source = _uri_to_id(channel_sources[i]);
1855 String target = channel_targets[i];
1856 ERR_CONTINUE(!samplers.has(source));
1857 Map<String, String> &sampler = samplers[source];
1858
1859 ERR_CONTINUE(!sampler.has("INPUT")); //no input semantic? wtf?
1860 String input_id = _uri_to_id(sampler["INPUT"]);
1861 COLLADA_PRINT("input id is " + input_id);
1862 ERR_CONTINUE(!float_sources.has(input_id));
1863
1864 ERR_CONTINUE(!sampler.has("OUTPUT"));
1865 String output_id = _uri_to_id(sampler["OUTPUT"]);
1866 ERR_CONTINUE(!float_sources.has(output_id));
1867
1868 ERR_CONTINUE(!source_param_names.has(output_id));
1869
1870 Vector<String> &names = source_param_names[output_id];
1871
1872 for (int l = 0; l < names.size(); l++) {
1873
1874 String name = names[l];
1875
1876 Vector<float> &time_keys = float_sources[input_id];
1877 int key_count = time_keys.size();
1878
1879 AnimationTrack track; //begin crating track
1880 track.id = id;
1881
1882 track.keys.resize(key_count);
1883
1884 for (int j = 0; j < key_count; j++) {
1885 track.keys.write[j].time = time_keys[j];
1886 state.animation_length = MAX(state.animation_length, time_keys[j]);
1887 }
1888
1889 //now read actual values
1890
1891 int stride = 1;
1892
1893 if (source_strides.has(output_id))
1894 stride = source_strides[output_id];
1895 int output_len = stride / names.size();
1896
1897 ERR_CONTINUE(output_len == 0);
1898 ERR_CONTINUE(!float_sources.has(output_id));
1899
1900 Vector<float> &output = float_sources[output_id];
1901
1902 ERR_CONTINUE_MSG((output.size() / stride) != key_count, "Wrong number of keys in output.");
1903
1904 for (int j = 0; j < key_count; j++) {
1905 track.keys.write[j].data.resize(output_len);
1906 for (int k = 0; k < output_len; k++)
1907 track.keys.write[j].data.write[k] = output[l + j * stride + k]; //super weird but should work:
1908 }
1909
1910 if (sampler.has("INTERPOLATION")) {
1911
1912 String interp_id = _uri_to_id(sampler["INTERPOLATION"]);
1913 ERR_CONTINUE(!string_sources.has(interp_id));
1914 Vector<String> &interps = string_sources[interp_id];
1915 ERR_CONTINUE(interps.size() != key_count);
1916
1917 for (int j = 0; j < key_count; j++) {
1918 if (interps[j] == "BEZIER")
1919 track.keys.write[j].interp_type = AnimationTrack::INTERP_BEZIER;
1920 else
1921 track.keys.write[j].interp_type = AnimationTrack::INTERP_LINEAR;
1922 }
1923 }
1924
1925 if (sampler.has("IN_TANGENT") && sampler.has("OUT_TANGENT")) {
1926 //bezier control points..
1927 String intangent_id = _uri_to_id(sampler["IN_TANGENT"]);
1928 ERR_CONTINUE(!float_sources.has(intangent_id));
1929 Vector<float> &intangents = float_sources[intangent_id];
1930
1931 ERR_CONTINUE(intangents.size() != key_count * 2 * names.size());
1932
1933 String outangent_id = _uri_to_id(sampler["OUT_TANGENT"]);
1934 ERR_CONTINUE(!float_sources.has(outangent_id));
1935 Vector<float> &outangents = float_sources[outangent_id];
1936 ERR_CONTINUE(outangents.size() != key_count * 2 * names.size());
1937
1938 for (int j = 0; j < key_count; j++) {
1939 track.keys.write[j].in_tangent = Vector2(intangents[j * 2 * names.size() + 0 + l * 2], intangents[j * 2 * names.size() + 1 + l * 2]);
1940 track.keys.write[j].out_tangent = Vector2(outangents[j * 2 * names.size() + 0 + l * 2], outangents[j * 2 * names.size() + 1 + l * 2]);
1941 }
1942 }
1943
1944 if (target.find("/") != -1) { //transform component
1945 track.target = target.get_slicec('/', 0);
1946 track.param = target.get_slicec('/', 1);
1947 if (track.param.find(".") != -1)
1948 track.component = track.param.get_slice(".", 1).to_upper();
1949 track.param = track.param.get_slice(".", 0);
1950 if (names.size() > 1 && track.component == "") {
1951 //this is a guess because the collada spec is ambiguous here...
1952 //i suppose if you have many names (outputs) you can't use a component and i should abide to that.
1953 track.component = name;
1954 }
1955 } else {
1956 track.target = target;
1957 }
1958
1959 state.animation_tracks.push_back(track);
1960
1961 if (!state.referenced_tracks.has(target))
1962 state.referenced_tracks[target] = Vector<int>();
1963
1964 state.referenced_tracks[target].push_back(state.animation_tracks.size() - 1);
1965
1966 if (id != "") {
1967 if (!state.by_id_tracks.has(id))
1968 state.by_id_tracks[id] = Vector<int>();
1969
1970 state.by_id_tracks[id].push_back(state.animation_tracks.size() - 1);
1971 }
1972
1973 COLLADA_PRINT("loaded animation with " + itos(key_count) + " keys");
1974 }
1975 }
1976 }
1977
_parse_animation_clip(XMLParser & parser)1978 void Collada::_parse_animation_clip(XMLParser &parser) {
1979
1980 if (!(state.import_flags & IMPORT_FLAG_ANIMATION)) {
1981 if (!parser.is_empty())
1982 parser.skip_section();
1983
1984 return;
1985 }
1986
1987 AnimationClip clip;
1988
1989 if (parser.has_attribute("name"))
1990 clip.name = parser.get_attribute_value("name");
1991 else if (parser.has_attribute("id"))
1992 clip.name = parser.get_attribute_value("id");
1993 if (parser.has_attribute("start"))
1994 clip.begin = parser.get_attribute_value("start").to_double();
1995 if (parser.has_attribute("end"))
1996 clip.end = parser.get_attribute_value("end").to_double();
1997
1998 while (parser.read() == OK) {
1999
2000 if (parser.get_node_type() == XMLParser::NODE_ELEMENT) {
2001
2002 String name = parser.get_node_name();
2003 if (name == "instance_animation") {
2004
2005 String url = _uri_to_id(parser.get_attribute_value("url"));
2006 clip.tracks.push_back(url);
2007 }
2008
2009 } else if (parser.get_node_type() == XMLParser::NODE_ELEMENT_END && parser.get_node_name() == "animation_clip")
2010 break; //end of <asset>
2011 }
2012
2013 state.animation_clips.push_back(clip);
2014 }
2015
_parse_scene(XMLParser & parser)2016 void Collada::_parse_scene(XMLParser &parser) {
2017
2018 if (parser.is_empty()) {
2019 return;
2020 }
2021
2022 while (parser.read() == OK) {
2023
2024 if (parser.get_node_type() == XMLParser::NODE_ELEMENT) {
2025
2026 String name = parser.get_node_name();
2027
2028 if (name == "instance_visual_scene") {
2029
2030 state.root_visual_scene = _uri_to_id(parser.get_attribute_value("url"));
2031 } else if (name == "instance_physics_scene") {
2032
2033 state.root_physics_scene = _uri_to_id(parser.get_attribute_value("url"));
2034 }
2035
2036 } else if (parser.get_node_type() == XMLParser::NODE_ELEMENT_END && parser.get_node_name() == "scene")
2037 break; //end of <asset>
2038 }
2039 }
2040
_parse_library(XMLParser & parser)2041 void Collada::_parse_library(XMLParser &parser) {
2042
2043 if (parser.is_empty()) {
2044 return;
2045 }
2046
2047 while (parser.read() == OK) {
2048
2049 if (parser.get_node_type() == XMLParser::NODE_ELEMENT) {
2050
2051 String name = parser.get_node_name();
2052 COLLADA_PRINT("library name is: " + name);
2053 if (name == "image") {
2054
2055 _parse_image(parser);
2056 } else if (name == "material") {
2057
2058 _parse_material(parser);
2059 } else if (name == "effect") {
2060
2061 _parse_effect(parser);
2062 } else if (name == "camera") {
2063
2064 _parse_camera(parser);
2065 } else if (name == "light") {
2066
2067 _parse_light(parser);
2068 } else if (name == "geometry") {
2069
2070 String id = parser.get_attribute_value("id");
2071 String name2 = parser.get_attribute_value_safe("name");
2072 while (parser.read() == OK) {
2073
2074 if (parser.get_node_type() == XMLParser::NODE_ELEMENT) {
2075
2076 if (parser.get_node_name() == "mesh") {
2077 state.mesh_name_map[id] = (name2 != "") ? name2 : id;
2078 _parse_mesh_geometry(parser, id, name2);
2079 } else if (parser.get_node_name() == "spline") {
2080 state.mesh_name_map[id] = (name2 != "") ? name2 : id;
2081 _parse_curve_geometry(parser, id, name2);
2082 } else if (!parser.is_empty())
2083 parser.skip_section();
2084 } else if (parser.get_node_type() == XMLParser::NODE_ELEMENT_END && parser.get_node_name() == "geometry")
2085 break;
2086 }
2087
2088 } else if (name == "controller") {
2089
2090 _parse_controller(parser);
2091 } else if (name == "animation") {
2092
2093 _parse_animation(parser);
2094 } else if (name == "animation_clip") {
2095
2096 _parse_animation_clip(parser);
2097 } else if (name == "visual_scene") {
2098
2099 COLLADA_PRINT("visual scene");
2100 _parse_visual_scene(parser);
2101 } else if (!parser.is_empty())
2102 parser.skip_section();
2103
2104 } else if (parser.get_node_type() == XMLParser::NODE_ELEMENT_END && parser.get_node_name().begins_with("library_"))
2105 break; //end of <asset>
2106 }
2107 }
2108
_joint_set_owner(Collada::Node * p_node,NodeSkeleton * p_owner)2109 void Collada::_joint_set_owner(Collada::Node *p_node, NodeSkeleton *p_owner) {
2110
2111 if (p_node->type == Node::TYPE_JOINT) {
2112
2113 NodeJoint *nj = static_cast<NodeJoint *>(p_node);
2114 nj->owner = p_owner;
2115
2116 for (int i = 0; i < nj->children.size(); i++) {
2117
2118 _joint_set_owner(nj->children.write[i], p_owner);
2119 }
2120 }
2121 }
2122
_create_skeletons(Collada::Node ** p_node,NodeSkeleton * p_skeleton)2123 void Collada::_create_skeletons(Collada::Node **p_node, NodeSkeleton *p_skeleton) {
2124
2125 Node *node = *p_node;
2126
2127 if (node->type == Node::TYPE_JOINT) {
2128
2129 if (!p_skeleton) {
2130
2131 // ohohohoohoo it's a joint node, time to work!
2132 NodeSkeleton *sk = memnew(NodeSkeleton);
2133 *p_node = sk;
2134 sk->children.push_back(node);
2135 sk->parent = node->parent;
2136 node->parent = sk;
2137 p_skeleton = sk;
2138 }
2139
2140 NodeJoint *nj = static_cast<NodeJoint *>(node);
2141 nj->owner = p_skeleton;
2142 } else {
2143 p_skeleton = NULL;
2144 }
2145
2146 for (int i = 0; i < node->children.size(); i++) {
2147 _create_skeletons(&node->children.write[i], p_skeleton);
2148 }
2149 }
2150
_remove_node(Node * p_parent,Node * p_node)2151 bool Collada::_remove_node(Node *p_parent, Node *p_node) {
2152
2153 for (int i = 0; i < p_parent->children.size(); i++) {
2154
2155 if (p_parent->children[i] == p_node) {
2156 p_parent->children.remove(i);
2157 return true;
2158 }
2159 if (_remove_node(p_parent->children[i], p_node))
2160 return true;
2161 }
2162
2163 return false;
2164 }
2165
_remove_node(VisualScene * p_vscene,Node * p_node)2166 void Collada::_remove_node(VisualScene *p_vscene, Node *p_node) {
2167
2168 for (int i = 0; i < p_vscene->root_nodes.size(); i++) {
2169 if (p_vscene->root_nodes[i] == p_node) {
2170
2171 p_vscene->root_nodes.remove(i);
2172 return;
2173 }
2174 if (_remove_node(p_vscene->root_nodes[i], p_node))
2175 return;
2176 }
2177
2178 ERR_PRINT("ERROR: Not found node to remove?");
2179 }
2180
_merge_skeletons(VisualScene * p_vscene,Node * p_node)2181 void Collada::_merge_skeletons(VisualScene *p_vscene, Node *p_node) {
2182
2183 if (p_node->type == Node::TYPE_GEOMETRY) {
2184
2185 NodeGeometry *gnode = static_cast<NodeGeometry *>(p_node);
2186 if (gnode->controller) {
2187
2188 // recount skeletons used
2189 Set<NodeSkeleton *> skeletons;
2190
2191 for (int i = 0; i < gnode->skeletons.size(); i++) {
2192
2193 String nodeid = gnode->skeletons[i];
2194
2195 ERR_CONTINUE(!state.scene_map.has(nodeid)); //weird, it should have it...
2196
2197 NodeJoint *nj = SAFE_CAST<NodeJoint *>(state.scene_map[nodeid]);
2198 ERR_CONTINUE(!nj); //broken collada
2199 ERR_CONTINUE(!nj->owner); //weird, node should have a skeleton owner
2200
2201 skeletons.insert(nj->owner);
2202 }
2203
2204 if (skeletons.size() > 1) {
2205
2206 //do the merger!!
2207 Set<NodeSkeleton *>::Element *E = skeletons.front();
2208 NodeSkeleton *base = E->get();
2209
2210 for (E = E->next(); E; E = E->next()) {
2211
2212 NodeSkeleton *merged = E->get();
2213 _remove_node(p_vscene, merged);
2214 for (int i = 0; i < merged->children.size(); i++) {
2215
2216 _joint_set_owner(merged->children[i], base);
2217 base->children.push_back(merged->children[i]);
2218 merged->children[i]->parent = base;
2219 }
2220
2221 merged->children.clear(); //take children from it
2222 memdelete(merged);
2223 }
2224 }
2225 }
2226 }
2227
2228 for (int i = 0; i < p_node->children.size(); i++) {
2229 _merge_skeletons(p_vscene, p_node->children[i]);
2230 }
2231 }
2232
_merge_skeletons2(VisualScene * p_vscene)2233 void Collada::_merge_skeletons2(VisualScene *p_vscene) {
2234
2235 for (Map<String, SkinControllerData>::Element *E = state.skin_controller_data_map.front(); E; E = E->next()) {
2236
2237 SkinControllerData &cd = E->get();
2238
2239 NodeSkeleton *skeleton = NULL;
2240
2241 for (Map<String, Transform>::Element *F = cd.bone_rest_map.front(); F; F = F->next()) {
2242
2243 String name;
2244
2245 if (!state.sid_to_node_map.has(F->key())) {
2246 continue;
2247 }
2248
2249 name = state.sid_to_node_map[F->key()];
2250
2251 ERR_CONTINUE(!state.scene_map.has(name));
2252
2253 Node *node = state.scene_map[name];
2254 ERR_CONTINUE(node->type != Node::TYPE_JOINT);
2255
2256 NodeSkeleton *sk = NULL;
2257
2258 while (node && !sk) {
2259
2260 if (node->type == Node::TYPE_SKELETON) {
2261 sk = static_cast<NodeSkeleton *>(node);
2262 }
2263 node = node->parent;
2264 }
2265
2266 ERR_CONTINUE(!sk);
2267
2268 if (!skeleton) {
2269 skeleton = sk;
2270 continue;
2271 }
2272
2273 if (skeleton != sk) {
2274 //whoa.. wtf, merge.
2275 _remove_node(p_vscene, sk);
2276 for (int i = 0; i < sk->children.size(); i++) {
2277
2278 _joint_set_owner(sk->children[i], skeleton);
2279 skeleton->children.push_back(sk->children[i]);
2280 sk->children[i]->parent = skeleton;
2281 }
2282
2283 sk->children.clear(); //take children from it
2284 memdelete(sk);
2285 }
2286 }
2287 }
2288 }
2289
_optimize_skeletons(VisualScene * p_vscene,Node * p_node)2290 bool Collada::_optimize_skeletons(VisualScene *p_vscene, Node *p_node) {
2291
2292 Node *node = p_node;
2293
2294 if (node->type == Node::TYPE_SKELETON && node->parent && node->parent->type == Node::TYPE_NODE && node->parent->children.size() == 1) {
2295 //replace parent by this...
2296 Node *parent = node->parent;
2297
2298 //i wonder if this is alright.. i think it is since created skeleton (first joint) is already animated by bone..
2299 node->id = parent->id;
2300 node->name = parent->name;
2301 node->xform_list = parent->xform_list;
2302 node->default_transform = parent->default_transform;
2303
2304 state.scene_map[node->id] = node;
2305 node->parent = parent->parent;
2306
2307 if (parent->parent) {
2308 Node *gp = parent->parent;
2309 bool found = false;
2310 for (int i = 0; i < gp->children.size(); i++) {
2311
2312 if (gp->children[i] == parent) {
2313 gp->children.write[i] = node;
2314 found = true;
2315 break;
2316 }
2317 }
2318 if (!found) {
2319 ERR_PRINT("BUG");
2320 }
2321 } else {
2322
2323 bool found = false;
2324
2325 for (int i = 0; i < p_vscene->root_nodes.size(); i++) {
2326
2327 if (p_vscene->root_nodes[i] == parent) {
2328
2329 p_vscene->root_nodes.write[i] = node;
2330 found = true;
2331 break;
2332 }
2333 }
2334 if (!found) {
2335 ERR_PRINT("BUG");
2336 }
2337 }
2338
2339 parent->children.clear();
2340 memdelete(parent);
2341 return true;
2342 }
2343
2344 for (int i = 0; i < node->children.size(); i++) {
2345
2346 if (_optimize_skeletons(p_vscene, node->children[i]))
2347 return false; //stop processing, go up
2348 }
2349
2350 return false;
2351 }
2352
_move_geometry_to_skeletons(VisualScene * p_vscene,Node * p_node,List<Node * > * p_mgeom)2353 bool Collada::_move_geometry_to_skeletons(VisualScene *p_vscene, Node *p_node, List<Node *> *p_mgeom) {
2354
2355 // Bind Shape Matrix scales the bones and makes them gigantic, so the matrix then shrinks the model?
2356 // Solution: apply the Bind Shape Matrix to the VERTICES, and if the object comes scaled, it seems to be left alone!
2357
2358 if (p_node->type == Node::TYPE_GEOMETRY) {
2359
2360 NodeGeometry *ng = static_cast<NodeGeometry *>(p_node);
2361 if (ng->ignore_anim)
2362 return false; //already made child of skeleton and processeg
2363
2364 if (ng->controller && ng->skeletons.size()) {
2365
2366 String nodeid = ng->skeletons[0];
2367
2368 ERR_FAIL_COND_V(!state.scene_map.has(nodeid), false); //weird, it should have it...
2369 NodeJoint *nj = SAFE_CAST<NodeJoint *>(state.scene_map[nodeid]);
2370 ERR_FAIL_COND_V(!nj, false);
2371 ERR_FAIL_COND_V(!nj->owner, false); //weird, node should have a skeleton owner
2372
2373 NodeSkeleton *sk = nj->owner;
2374
2375 Node *p = sk->parent;
2376 bool node_is_parent_of_skeleton = false;
2377
2378 while (p) {
2379 if (p == p_node) {
2380 node_is_parent_of_skeleton = true;
2381 break;
2382 }
2383 p = p->parent; // try again
2384 }
2385
2386 ERR_FAIL_COND_V(node_is_parent_of_skeleton, false);
2387
2388 //this should be correct
2389 ERR_FAIL_COND_V(!state.skin_controller_data_map.has(ng->source), false);
2390 SkinControllerData &skin = state.skin_controller_data_map[ng->source];
2391 Transform skel_inv = sk->get_global_transform().affine_inverse();
2392 p_node->default_transform = skel_inv * (skin.bind_shape /* p_node->get_global_transform()*/); // i honestly have no idea what to do with a previous model xform.. most exporters ignore it
2393
2394 //make rests relative to the skeleton (they seem to be always relative to world)
2395 for (Map<String, Transform>::Element *E = skin.bone_rest_map.front(); E; E = E->next()) {
2396
2397 E->get() = skel_inv * E->get(); //make the bone rest local to the skeleton
2398 state.bone_rest_map[E->key()] = E->get(); // make it remember where the bone is globally, now that it's relative
2399 }
2400
2401 //but most exporters seem to work only if i do this..
2402 //p_node->default_transform = p_node->get_global_transform();
2403
2404 //p_node->default_transform=Transform(); //this seems to be correct, because bind shape makes the object local to the skeleton
2405 p_node->ignore_anim = true; // collada may animate this later, if it does, then this is not supported (redo your original asset and don't animate the base mesh)
2406 p_node->parent = sk;
2407 //sk->children.push_back(0,p_node); //avoid INFINITE loop
2408 p_mgeom->push_back(p_node);
2409 return true;
2410 }
2411 }
2412
2413 for (int i = 0; i < p_node->children.size(); i++) {
2414
2415 if (_move_geometry_to_skeletons(p_vscene, p_node->children[i], p_mgeom)) {
2416 p_node->children.remove(i);
2417 i--;
2418 }
2419 }
2420
2421 return false;
2422 }
2423
_find_morph_nodes(VisualScene * p_vscene,Node * p_node)2424 void Collada::_find_morph_nodes(VisualScene *p_vscene, Node *p_node) {
2425
2426 if (p_node->type == Node::TYPE_GEOMETRY) {
2427
2428 NodeGeometry *nj = static_cast<NodeGeometry *>(p_node);
2429
2430 if (nj->controller) {
2431
2432 String base = nj->source;
2433
2434 while (base != "" && !state.mesh_data_map.has(base)) {
2435
2436 if (state.skin_controller_data_map.has(base)) {
2437
2438 SkinControllerData &sk = state.skin_controller_data_map[base];
2439 base = sk.base;
2440 } else if (state.morph_controller_data_map.has(base)) {
2441
2442 state.morph_ownership_map[base] = nj->id;
2443 break;
2444 } else {
2445 ERR_FAIL_MSG("Invalid scene.");
2446 }
2447 }
2448 }
2449 }
2450
2451 for (int i = 0; i < p_node->children.size(); i++) {
2452
2453 _find_morph_nodes(p_vscene, p_node->children[i]);
2454 }
2455 }
2456
_optimize()2457 void Collada::_optimize() {
2458
2459 for (Map<String, VisualScene>::Element *E = state.visual_scene_map.front(); E; E = E->next()) {
2460
2461 VisualScene &vs = E->get();
2462 for (int i = 0; i < vs.root_nodes.size(); i++) {
2463 _create_skeletons(&vs.root_nodes.write[i]);
2464 }
2465
2466 for (int i = 0; i < vs.root_nodes.size(); i++) {
2467 _merge_skeletons(&vs, vs.root_nodes[i]);
2468 }
2469
2470 _merge_skeletons2(&vs);
2471
2472 for (int i = 0; i < vs.root_nodes.size(); i++) {
2473 _optimize_skeletons(&vs, vs.root_nodes[i]);
2474 }
2475
2476 for (int i = 0; i < vs.root_nodes.size(); i++) {
2477
2478 List<Node *> mgeom;
2479 if (_move_geometry_to_skeletons(&vs, vs.root_nodes[i], &mgeom)) {
2480 vs.root_nodes.remove(i);
2481 i--;
2482 }
2483
2484 while (!mgeom.empty()) {
2485
2486 Node *n = mgeom.front()->get();
2487 n->parent->children.push_back(n);
2488 mgeom.pop_front();
2489 }
2490 }
2491
2492 for (int i = 0; i < vs.root_nodes.size(); i++) {
2493 _find_morph_nodes(&vs, vs.root_nodes[i]);
2494 }
2495 }
2496 }
2497
get_uv_channel(String p_name)2498 int Collada::get_uv_channel(String p_name) {
2499
2500 if (!channel_map.has(p_name)) {
2501
2502 ERR_FAIL_COND_V(channel_map.size() == 2, 0);
2503
2504 channel_map[p_name] = channel_map.size();
2505 }
2506
2507 return channel_map[p_name];
2508 }
2509
load(const String & p_path,int p_flags)2510 Error Collada::load(const String &p_path, int p_flags) {
2511
2512 Ref<XMLParser> parserr = memnew(XMLParser);
2513 XMLParser &parser = *parserr.ptr();
2514 Error err = parser.open(p_path);
2515 ERR_FAIL_COND_V_MSG(err, err, "Cannot open Collada file '" + p_path + "'.");
2516
2517 state.local_path = ProjectSettings::get_singleton()->localize_path(p_path);
2518 state.import_flags = p_flags;
2519 /* Skip headers */
2520 while ((err = parser.read()) == OK) {
2521
2522 if (parser.get_node_type() == XMLParser::NODE_ELEMENT) {
2523
2524 if (parser.get_node_name() == "COLLADA") {
2525 break;
2526 } else if (!parser.is_empty())
2527 parser.skip_section(); // unknown section, likely headers
2528 }
2529 }
2530
2531 ERR_FAIL_COND_V_MSG(err != OK, ERR_FILE_CORRUPT, "Corrupted Collada file '" + p_path + "'.");
2532
2533 /* Start loading Collada */
2534
2535 {
2536 //version
2537 String version = parser.get_attribute_value("version");
2538 state.version.major = version.get_slice(".", 0).to_int();
2539 state.version.minor = version.get_slice(".", 1).to_int();
2540 state.version.rev = version.get_slice(".", 2).to_int();
2541 COLLADA_PRINT("Collada VERSION: " + version);
2542 }
2543
2544 while ((err = parser.read()) == OK) {
2545
2546 /* Read all the main sections.. */
2547
2548 if (parser.get_node_type() != XMLParser::NODE_ELEMENT)
2549 continue; //no idea what this may be, but skipping anyway
2550
2551 String section = parser.get_node_name();
2552
2553 COLLADA_PRINT("section: " + section);
2554
2555 if (section == "asset") {
2556 _parse_asset(parser);
2557
2558 } else if (section.begins_with("library_")) {
2559
2560 _parse_library(parser);
2561 } else if (section == "scene") {
2562
2563 _parse_scene(parser);
2564 } else if (!parser.is_empty()) {
2565 parser.skip_section(); // unknown section, likely headers
2566 }
2567 }
2568
2569 _optimize();
2570 return OK;
2571 }
2572
Collada()2573 Collada::Collada() {
2574 }
2575