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