1/**************************************************************************/
2/* collada.h */
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#ifndef COLLADA_H
32#define COLLADA_H
33
34#include "core/config/project_settings.h"
35#include "core/io/xml_parser.h"
36#include "core/templates/rb_map.h"
37#include "scene/resources/material.h"
38
39class Collada {
40public:
41 enum ImportFlags {
42 IMPORT_FLAG_SCENE = 1,
43 IMPORT_FLAG_ANIMATION = 2
44 };
45
46 struct Image {
47 String path;
48 };
49
50 struct Material {
51 String name;
52 String instance_effect;
53 };
54
55 struct Effect {
56 String name;
57 HashMap<String, Variant> params;
58
59 struct Channel {
60 int uv_idx = 0;
61 String texture;
62 Color color;
63 Channel() {}
64 };
65
66 Channel diffuse, specular, emission, bump;
67 float shininess = 40;
68 bool found_double_sided = false;
69 bool double_sided = true;
70 bool unshaded = false;
71
72 String get_texture_path(const String &p_source, Collada &p_state) const;
73
74 Effect() {
75 diffuse.color = Color(1, 1, 1, 1);
76 }
77 };
78
79 struct CameraData {
80 enum Mode {
81 MODE_PERSPECTIVE,
82 MODE_ORTHOGONAL
83 };
84
85 Mode mode = MODE_PERSPECTIVE;
86
87 union {
88 struct {
89 float x_fov = 0;
90 float y_fov = 0;
91 } perspective;
92 struct {
93 float x_mag = 0;
94 float y_mag = 0;
95 } orthogonal;
96 };
97
98 float aspect = 1;
99 float z_near = 0.05;
100 float z_far = 4000;
101
102 CameraData() {}
103 };
104
105 struct LightData {
106 enum Mode {
107 MODE_AMBIENT,
108 MODE_DIRECTIONAL,
109 MODE_OMNI,
110 MODE_SPOT
111 };
112
113 Mode mode = MODE_AMBIENT;
114
115 Color color = Color(1, 1, 1, 1);
116
117 float constant_att = 0;
118 float linear_att = 0;
119 float quad_att = 0;
120
121 float spot_angle = 45;
122 float spot_exp = 1;
123
124 LightData() {}
125 };
126
127 struct MeshData {
128 String name;
129 struct Source {
130 Vector<float> array;
131 int stride = 0;
132 };
133
134 HashMap<String, Source> sources;
135
136 struct Vertices {
137 HashMap<String, String> sources;
138 };
139
140 HashMap<String, Vertices> vertices;
141
142 struct Primitives {
143 struct SourceRef {
144 String source;
145 int offset = 0;
146 };
147
148 String material;
149 HashMap<String, SourceRef> sources;
150 Vector<float> polygons;
151 Vector<float> indices;
152 int count = 0;
153 int vertex_size = 0;
154 };
155
156 Vector<Primitives> primitives;
157
158 bool found_double_sided = false;
159 bool double_sided = true;
160
161 MeshData() {}
162 };
163
164 struct CurveData {
165 String name;
166 bool closed = false;
167
168 struct Source {
169 Vector<String> sarray;
170 Vector<float> array;
171 int stride = 0;
172 };
173
174 HashMap<String, Source> sources;
175
176 HashMap<String, String> control_vertices;
177
178 CurveData() {}
179 };
180
181 struct SkinControllerData {
182 String base;
183 bool use_idrefs = false;
184
185 Transform3D bind_shape;
186
187 struct Source {
188 Vector<String> sarray; //maybe for names
189 Vector<float> array;
190 int stride = 1;
191 Source() {}
192 };
193
194 HashMap<String, Source> sources;
195
196 struct Joints {
197 HashMap<String, String> sources;
198 } joints;
199
200 struct Weights {
201 struct SourceRef {
202 String source;
203 int offset = 0;
204 };
205
206 String material;
207 HashMap<String, SourceRef> sources;
208 Vector<float> sets;
209 Vector<float> indices;
210 int count = 0;
211 } weights;
212
213 HashMap<String, Transform3D> bone_rest_map;
214
215 SkinControllerData() {}
216 };
217
218 struct MorphControllerData {
219 String mesh;
220 String mode;
221
222 struct Source {
223 int stride = 1;
224 Vector<String> sarray; //maybe for names
225 Vector<float> array;
226 Source() {}
227 };
228
229 HashMap<String, Source> sources;
230
231 HashMap<String, String> targets;
232 MorphControllerData() {}
233 };
234
235 struct Vertex {
236 int idx = 0;
237 Vector3 vertex;
238 Vector3 normal;
239 Vector3 uv;
240 Vector3 uv2;
241 Plane tangent;
242 Color color;
243 int uid = 0;
244 struct Weight {
245 int bone_idx = 0;
246 float weight = 0;
247 bool operator<(const Weight w) const { return weight > w.weight; } //heaviest first
248 };
249
250 Vector<Weight> weights;
251
252 void fix_weights() {
253 weights.sort();
254 if (weights.size() > 4) {
255 //cap to 4 and make weights add up 1
256 weights.resize(4);
257 float total = 0;
258 for (int i = 0; i < 4; i++) {
259 total += weights[i].weight;
260 }
261 if (total) {
262 for (int i = 0; i < 4; i++) {
263 weights.write[i].weight /= total;
264 }
265 }
266 }
267 }
268
269 void fix_unit_scale(const Collada &p_state);
270
271 bool operator<(const Vertex &p_vert) const {
272 if (uid == p_vert.uid) {
273 if (vertex == p_vert.vertex) {
274 if (normal == p_vert.normal) {
275 if (uv == p_vert.uv) {
276 if (uv2 == p_vert.uv2) {
277 if (!weights.is_empty() || !p_vert.weights.is_empty()) {
278 if (weights.size() == p_vert.weights.size()) {
279 for (int i = 0; i < weights.size(); i++) {
280 if (weights[i].bone_idx != p_vert.weights[i].bone_idx) {
281 return weights[i].bone_idx < p_vert.weights[i].bone_idx;
282 }
283
284 if (weights[i].weight != p_vert.weights[i].weight) {
285 return weights[i].weight < p_vert.weights[i].weight;
286 }
287 }
288 } else {
289 return weights.size() < p_vert.weights.size();
290 }
291 }
292
293 return (color < p_vert.color);
294 } else {
295 return (uv2 < p_vert.uv2);
296 }
297 } else {
298 return (uv < p_vert.uv);
299 }
300 } else {
301 return (normal < p_vert.normal);
302 }
303 } else {
304 return vertex < p_vert.vertex;
305 }
306 } else {
307 return uid < p_vert.uid;
308 }
309 }
310
311 Vertex() {}
312 };
313
314 struct Node {
315 enum Type {
316 TYPE_NODE,
317 TYPE_JOINT,
318 TYPE_SKELETON, //this bone is not collada, it's added afterwards as optimization
319 TYPE_LIGHT,
320 TYPE_CAMERA,
321 TYPE_GEOMETRY
322 };
323
324 struct XForm {
325 enum Op {
326 OP_ROTATE,
327 OP_SCALE,
328 OP_TRANSLATE,
329 OP_MATRIX,
330 OP_VISIBILITY
331 };
332
333 String id;
334 Op op = OP_ROTATE;
335 Vector<float> data;
336 };
337
338 Type type = TYPE_NODE;
339
340 String name;
341 String id;
342 String empty_draw_type;
343 bool noname = false;
344 Vector<XForm> xform_list;
345 Transform3D default_transform;
346 Transform3D post_transform;
347 Vector<Node *> children;
348
349 Node *parent = nullptr;
350
351 Transform3D compute_transform(const Collada &p_state) const;
352 Transform3D get_global_transform() const;
353 Transform3D get_transform() const;
354
355 bool ignore_anim = false;
356
357 Node() {}
358 virtual ~Node() {
359 for (int i = 0; i < children.size(); i++) {
360 memdelete(children[i]);
361 }
362 };
363 };
364
365 struct NodeSkeleton : public Node {
366 NodeSkeleton() { type = TYPE_SKELETON; }
367 };
368
369 struct NodeJoint : public Node {
370 NodeSkeleton *owner = nullptr;
371 String sid;
372 NodeJoint() {
373 type = TYPE_JOINT;
374 }
375 };
376
377 struct NodeGeometry : public Node {
378 bool controller = false;
379 String source;
380
381 struct Material {
382 String target;
383 };
384
385 HashMap<String, Material> material_map;
386 Vector<String> skeletons;
387
388 NodeGeometry() { type = TYPE_GEOMETRY; }
389 };
390
391 struct NodeCamera : public Node {
392 String camera;
393
394 NodeCamera() { type = TYPE_CAMERA; }
395 };
396
397 struct NodeLight : public Node {
398 String light;
399
400 NodeLight() { type = TYPE_LIGHT; }
401 };
402
403 struct VisualScene {
404 String name;
405 Vector<Node *> root_nodes;
406
407 ~VisualScene() {
408 for (int i = 0; i < root_nodes.size(); i++) {
409 memdelete(root_nodes[i]);
410 }
411 }
412 };
413
414 struct AnimationClip {
415 String name;
416 float begin = 0;
417 float end = 1;
418 Vector<String> tracks;
419
420 AnimationClip() {}
421 };
422
423 struct AnimationTrack {
424 String id;
425 String target;
426 String param;
427 String component;
428 bool property = false;
429
430 enum InterpolationType {
431 INTERP_LINEAR,
432 INTERP_BEZIER
433 };
434
435 struct Key {
436 enum Type {
437 TYPE_FLOAT,
438 TYPE_MATRIX
439 };
440
441 float time = 0;
442 Vector<float> data;
443 Point2 in_tangent;
444 Point2 out_tangent;
445 InterpolationType interp_type = INTERP_LINEAR;
446
447 Key() {}
448 };
449
450 Vector<float> get_value_at_time(float p_time) const;
451
452 Vector<Key> keys;
453
454 AnimationTrack() {}
455 };
456
457 /****************/
458 /* IMPORT STATE */
459 /****************/
460
461 struct State {
462 int import_flags = 0;
463
464 float unit_scale = 1.0;
465 Vector3::Axis up_axis = Vector3::AXIS_Y;
466 bool z_up = false;
467
468 struct Version {
469 int major = 0, minor = 0, rev = 0;
470
471 bool operator<(const Version &p_ver) const { return (major == p_ver.major) ? ((minor == p_ver.minor) ? (rev < p_ver.rev) : minor < p_ver.minor) : major < p_ver.major; }
472 Version(int p_major = 0, int p_minor = 0, int p_rev = 0) {
473 major = p_major;
474 minor = p_minor;
475 rev = p_rev;
476 }
477 } version;
478
479 HashMap<String, CameraData> camera_data_map;
480 HashMap<String, MeshData> mesh_data_map;
481 HashMap<String, LightData> light_data_map;
482 HashMap<String, CurveData> curve_data_map;
483
484 HashMap<String, String> mesh_name_map;
485 HashMap<String, String> morph_name_map;
486 HashMap<String, String> morph_ownership_map;
487 HashMap<String, SkinControllerData> skin_controller_data_map;
488 HashMap<String, MorphControllerData> morph_controller_data_map;
489
490 HashMap<String, Image> image_map;
491 HashMap<String, Material> material_map;
492 HashMap<String, Effect> effect_map;
493
494 HashMap<String, VisualScene> visual_scene_map;
495 HashMap<String, Node *> scene_map;
496 HashSet<String> idref_joints;
497 HashMap<String, String> sid_to_node_map;
498 //RBMap<String,NodeJoint*> bone_map;
499
500 HashMap<String, Transform3D> bone_rest_map;
501
502 String local_path;
503 String root_visual_scene;
504 String root_physics_scene;
505
506 Vector<AnimationClip> animation_clips;
507 Vector<AnimationTrack> animation_tracks;
508 HashMap<String, Vector<int>> referenced_tracks;
509 HashMap<String, Vector<int>> by_id_tracks;
510
511 float animation_length = 0;
512
513 State() {}
514 } state;
515
516 Error load(const String &p_path, int p_flags = 0);
517
518 Collada();
519
520 Transform3D fix_transform(const Transform3D &p_transform);
521
522 Transform3D get_root_transform() const;
523
524 int get_uv_channel(String p_name);
525
526private: // private stuff
527 HashMap<String, int> channel_map;
528
529 void _parse_asset(XMLParser &p_parser);
530 void _parse_image(XMLParser &p_parser);
531 void _parse_material(XMLParser &p_parser);
532 void _parse_effect_material(XMLParser &p_parser, Effect &p_effect, String &p_id);
533 void _parse_effect(XMLParser &p_parser);
534 void _parse_camera(XMLParser &p_parser);
535 void _parse_light(XMLParser &p_parser);
536 void _parse_animation_clip(XMLParser &p_parser);
537
538 void _parse_mesh_geometry(XMLParser &p_parser, String p_id, String p_name);
539 void _parse_curve_geometry(XMLParser &p_parser, String p_id, String p_name);
540
541 void _parse_skin_controller(XMLParser &p_parser, String p_id);
542 void _parse_morph_controller(XMLParser &p_parser, String p_id);
543 void _parse_controller(XMLParser &p_parser);
544
545 Node *_parse_visual_instance_geometry(XMLParser &p_parser);
546 Node *_parse_visual_instance_camera(XMLParser &p_parser);
547 Node *_parse_visual_instance_light(XMLParser &p_parser);
548
549 Node *_parse_visual_node_instance_data(XMLParser &p_parser);
550 Node *_parse_visual_scene_node(XMLParser &p_parser);
551 void _parse_visual_scene(XMLParser &p_parser);
552
553 void _parse_animation(XMLParser &p_parser);
554 void _parse_scene(XMLParser &p_parser);
555 void _parse_library(XMLParser &p_parser);
556
557 Variant _parse_param(XMLParser &p_parser);
558 Vector<float> _read_float_array(XMLParser &p_parser);
559 Vector<String> _read_string_array(XMLParser &p_parser);
560 Transform3D _read_transform(XMLParser &p_parser);
561 String _read_empty_draw_type(XMLParser &p_parser);
562
563 void _joint_set_owner(Collada::Node *p_node, NodeSkeleton *p_owner);
564 void _create_skeletons(Collada::Node **p_node, NodeSkeleton *p_skeleton = nullptr);
565 void _find_morph_nodes(VisualScene *p_vscene, Node *p_node);
566 bool _remove_node(Node *p_parent, Node *p_node);
567 void _remove_node(VisualScene *p_vscene, Node *p_node);
568 void _merge_skeletons2(VisualScene *p_vscene);
569 void _merge_skeletons(VisualScene *p_vscene, Node *p_node);
570 bool _optimize_skeletons(VisualScene *p_vscene, Node *p_node);
571
572 bool _move_geometry_to_skeletons(VisualScene *p_vscene, Node *p_node, List<Node *> *p_mgeom);
573
574 void _optimize();
575};
576
577#endif // COLLADA_H
578