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