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