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