godot/editor/import/collada.h
Rémi Verschelde d95794ec8a
One Copyright Update to rule them all
As many open source projects have started doing it, we're removing the
current year from the copyright notice, so that we don't need to bump
it every year.

It seems like only the first year of publication is technically
relevant for copyright notices, and even that seems to be something
that many companies stopped listing altogether (in a version controlled
codebase, the commits are a much better source of date of publication
than a hardcoded copyright statement).

We also now list Godot Engine contributors first as we're collectively
the current maintainers of the project, and we clarify that the
"exclusive" copyright of the co-founders covers the timespan before
opensourcing (their further contributions are included as part of Godot
Engine contributors).

Also fixed "cf." Frenchism - it's meant as "refer to / see".
2023-01-05 13:25:55 +01:00

578 lines
13 KiB
C++

/**************************************************************************/
/* collada.h */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef COLLADA_H
#define COLLADA_H
#include "core/config/project_settings.h"
#include "core/io/xml_parser.h"
#include "core/templates/rb_map.h"
#include "scene/resources/material.h"
class Collada {
public:
enum ImportFlags {
IMPORT_FLAG_SCENE = 1,
IMPORT_FLAG_ANIMATION = 2
};
struct Image {
String path;
};
struct Material {
String name;
String instance_effect;
};
struct Effect {
String name;
HashMap<String, Variant> params;
struct Channel {
int uv_idx = 0;
String texture;
Color color;
Channel() {}
};
Channel diffuse, specular, emission, bump;
float shininess = 40;
bool found_double_sided = false;
bool double_sided = true;
bool unshaded = false;
String get_texture_path(const String &p_source, Collada &state) const;
Effect() {
diffuse.color = Color(1, 1, 1, 1);
}
};
struct CameraData {
enum Mode {
MODE_PERSPECTIVE,
MODE_ORTHOGONAL
};
Mode mode = MODE_PERSPECTIVE;
union {
struct {
float x_fov = 0;
float y_fov = 0;
} perspective;
struct {
float x_mag = 0;
float y_mag = 0;
} orthogonal;
};
float aspect = 1;
float z_near = 0.05;
float z_far = 4000;
CameraData() {}
};
struct LightData {
enum Mode {
MODE_AMBIENT,
MODE_DIRECTIONAL,
MODE_OMNI,
MODE_SPOT
};
Mode mode = MODE_AMBIENT;
Color color = Color(1, 1, 1, 1);
float constant_att = 0;
float linear_att = 0;
float quad_att = 0;
float spot_angle = 45;
float spot_exp = 1;
LightData() {}
};
struct MeshData {
String name;
struct Source {
Vector<float> array;
int stride = 0;
};
HashMap<String, Source> sources;
struct Vertices {
HashMap<String, String> sources;
};
HashMap<String, Vertices> vertices;
struct Primitives {
struct SourceRef {
String source;
int offset = 0;
};
String material;
HashMap<String, SourceRef> sources;
Vector<float> polygons;
Vector<float> indices;
int count = 0;
int vertex_size = 0;
};
Vector<Primitives> primitives;
bool found_double_sided = false;
bool double_sided = true;
MeshData() {}
};
struct CurveData {
String name;
bool closed = false;
struct Source {
Vector<String> sarray;
Vector<float> array;
int stride = 0;
};
HashMap<String, Source> sources;
HashMap<String, String> control_vertices;
CurveData() {}
};
struct SkinControllerData {
String base;
bool use_idrefs = false;
Transform3D bind_shape;
struct Source {
Vector<String> sarray; //maybe for names
Vector<float> array;
int stride = 1;
Source() {}
};
HashMap<String, Source> sources;
struct Joints {
HashMap<String, String> sources;
} joints;
struct Weights {
struct SourceRef {
String source;
int offset = 0;
};
String material;
HashMap<String, SourceRef> sources;
Vector<float> sets;
Vector<float> indices;
int count = 0;
} weights;
HashMap<String, Transform3D> bone_rest_map;
SkinControllerData() {}
};
struct MorphControllerData {
String mesh;
String mode;
struct Source {
int stride = 1;
Vector<String> sarray; //maybe for names
Vector<float> array;
Source() {}
};
HashMap<String, Source> sources;
HashMap<String, String> targets;
MorphControllerData() {}
};
struct Vertex {
int idx = 0;
Vector3 vertex;
Vector3 normal;
Vector3 uv;
Vector3 uv2;
Plane tangent;
Color color;
int uid = 0;
struct Weight {
int bone_idx = 0;
float weight = 0;
bool operator<(const Weight w) const { return weight > w.weight; } //heaviest first
};
Vector<Weight> weights;
void fix_weights() {
weights.sort();
if (weights.size() > 4) {
//cap to 4 and make weights add up 1
weights.resize(4);
float total = 0;
for (int i = 0; i < 4; i++) {
total += weights[i].weight;
}
if (total) {
for (int i = 0; i < 4; i++) {
weights.write[i].weight /= total;
}
}
}
}
void fix_unit_scale(const Collada &state);
bool operator<(const Vertex &p_vert) const {
if (uid == p_vert.uid) {
if (vertex == p_vert.vertex) {
if (normal == p_vert.normal) {
if (uv == p_vert.uv) {
if (uv2 == p_vert.uv2) {
if (!weights.is_empty() || !p_vert.weights.is_empty()) {
if (weights.size() == p_vert.weights.size()) {
for (int i = 0; i < weights.size(); i++) {
if (weights[i].bone_idx != p_vert.weights[i].bone_idx) {
return weights[i].bone_idx < p_vert.weights[i].bone_idx;
}
if (weights[i].weight != p_vert.weights[i].weight) {
return weights[i].weight < p_vert.weights[i].weight;
}
}
} else {
return weights.size() < p_vert.weights.size();
}
}
return (color < p_vert.color);
} else {
return (uv2 < p_vert.uv2);
}
} else {
return (uv < p_vert.uv);
}
} else {
return (normal < p_vert.normal);
}
} else {
return vertex < p_vert.vertex;
}
} else {
return uid < p_vert.uid;
}
}
Vertex() {}
};
struct Node {
enum Type {
TYPE_NODE,
TYPE_JOINT,
TYPE_SKELETON, //this bone is not collada, it's added afterwards as optimization
TYPE_LIGHT,
TYPE_CAMERA,
TYPE_GEOMETRY
};
struct XForm {
enum Op {
OP_ROTATE,
OP_SCALE,
OP_TRANSLATE,
OP_MATRIX,
OP_VISIBILITY
};
String id;
Op op = OP_ROTATE;
Vector<float> data;
};
Type type = TYPE_NODE;
String name;
String id;
String empty_draw_type;
bool noname = false;
Vector<XForm> xform_list;
Transform3D default_transform;
Transform3D post_transform;
Vector<Node *> children;
Node *parent = nullptr;
Transform3D compute_transform(const Collada &state) const;
Transform3D get_global_transform() const;
Transform3D get_transform() const;
bool ignore_anim = false;
Node() {}
virtual ~Node() {
for (int i = 0; i < children.size(); i++) {
memdelete(children[i]);
}
};
};
struct NodeSkeleton : public Node {
NodeSkeleton() { type = TYPE_SKELETON; }
};
struct NodeJoint : public Node {
NodeSkeleton *owner = nullptr;
String sid;
NodeJoint() {
type = TYPE_JOINT;
}
};
struct NodeGeometry : public Node {
bool controller = false;
String source;
struct Material {
String target;
};
HashMap<String, Material> material_map;
Vector<String> skeletons;
NodeGeometry() { type = TYPE_GEOMETRY; }
};
struct NodeCamera : public Node {
String camera;
NodeCamera() { type = TYPE_CAMERA; }
};
struct NodeLight : public Node {
String light;
NodeLight() { type = TYPE_LIGHT; }
};
struct VisualScene {
String name;
Vector<Node *> root_nodes;
~VisualScene() {
for (int i = 0; i < root_nodes.size(); i++) {
memdelete(root_nodes[i]);
}
}
};
struct AnimationClip {
String name;
float begin = 0;
float end = 1;
Vector<String> tracks;
AnimationClip() {}
};
struct AnimationTrack {
String id;
String target;
String param;
String component;
bool property = false;
enum InterpolationType {
INTERP_LINEAR,
INTERP_BEZIER
};
struct Key {
enum Type {
TYPE_FLOAT,
TYPE_MATRIX
};
float time = 0;
Vector<float> data;
Point2 in_tangent;
Point2 out_tangent;
InterpolationType interp_type = INTERP_LINEAR;
Key() {}
};
Vector<float> get_value_at_time(float p_time) const;
Vector<Key> keys;
AnimationTrack() {}
};
/****************/
/* IMPORT STATE */
/****************/
struct State {
int import_flags = 0;
float unit_scale = 1.0;
Vector3::Axis up_axis = Vector3::AXIS_Y;
bool z_up = false;
struct Version {
int major = 0, minor = 0, rev = 0;
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; }
Version(int p_major = 0, int p_minor = 0, int p_rev = 0) {
major = p_major;
minor = p_minor;
rev = p_rev;
}
} version;
HashMap<String, CameraData> camera_data_map;
HashMap<String, MeshData> mesh_data_map;
HashMap<String, LightData> light_data_map;
HashMap<String, CurveData> curve_data_map;
HashMap<String, String> mesh_name_map;
HashMap<String, String> morph_name_map;
HashMap<String, String> morph_ownership_map;
HashMap<String, SkinControllerData> skin_controller_data_map;
HashMap<String, MorphControllerData> morph_controller_data_map;
HashMap<String, Image> image_map;
HashMap<String, Material> material_map;
HashMap<String, Effect> effect_map;
HashMap<String, VisualScene> visual_scene_map;
HashMap<String, Node *> scene_map;
HashSet<String> idref_joints;
HashMap<String, String> sid_to_node_map;
//RBMap<String,NodeJoint*> bone_map;
HashMap<String, Transform3D> bone_rest_map;
String local_path;
String root_visual_scene;
String root_physics_scene;
Vector<AnimationClip> animation_clips;
Vector<AnimationTrack> animation_tracks;
HashMap<String, Vector<int>> referenced_tracks;
HashMap<String, Vector<int>> by_id_tracks;
float animation_length = 0;
State() {}
} state;
Error load(const String &p_path, int p_flags = 0);
Collada();
Transform3D fix_transform(const Transform3D &p_transform);
Transform3D get_root_transform() const;
int get_uv_channel(String p_name);
private: // private stuff
HashMap<String, int> channel_map;
void _parse_asset(XMLParser &parser);
void _parse_image(XMLParser &parser);
void _parse_material(XMLParser &parser);
void _parse_effect_material(XMLParser &parser, Effect &effect, String &id);
void _parse_effect(XMLParser &parser);
void _parse_camera(XMLParser &parser);
void _parse_light(XMLParser &parser);
void _parse_animation_clip(XMLParser &parser);
void _parse_mesh_geometry(XMLParser &parser, String p_id, String p_name);
void _parse_curve_geometry(XMLParser &parser, String p_id, String p_name);
void _parse_skin_controller(XMLParser &parser, String p_id);
void _parse_morph_controller(XMLParser &parser, String p_id);
void _parse_controller(XMLParser &parser);
Node *_parse_visual_instance_geometry(XMLParser &parser);
Node *_parse_visual_instance_camera(XMLParser &parser);
Node *_parse_visual_instance_light(XMLParser &parser);
Node *_parse_visual_node_instance_data(XMLParser &parser);
Node *_parse_visual_scene_node(XMLParser &parser);
void _parse_visual_scene(XMLParser &parser);
void _parse_animation(XMLParser &parser);
void _parse_scene(XMLParser &parser);
void _parse_library(XMLParser &parser);
Variant _parse_param(XMLParser &parser);
Vector<float> _read_float_array(XMLParser &parser);
Vector<String> _read_string_array(XMLParser &parser);
Transform3D _read_transform(XMLParser &parser);
String _read_empty_draw_type(XMLParser &parser);
void _joint_set_owner(Collada::Node *p_node, NodeSkeleton *p_owner);
void _create_skeletons(Collada::Node **p_node, NodeSkeleton *p_skeleton = nullptr);
void _find_morph_nodes(VisualScene *p_vscene, Node *p_node);
bool _remove_node(Node *p_parent, Node *p_node);
void _remove_node(VisualScene *p_vscene, Node *p_node);
void _merge_skeletons2(VisualScene *p_vscene);
void _merge_skeletons(VisualScene *p_vscene, Node *p_node);
bool _optimize_skeletons(VisualScene *p_vscene, Node *p_node);
bool _move_geometry_to_skeletons(VisualScene *p_vscene, Node *p_node, List<Node *> *p_mgeom);
void _optimize();
};
#endif // COLLADA_H