1/**************************************************************************/
2/* skeleton_3d.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 SKELETON_3D_H
32#define SKELETON_3D_H
33
34#include "scene/3d/node_3d.h"
35#include "scene/resources/skin.h"
36
37typedef int BoneId;
38
39class PhysicalBone3D;
40class Skeleton3D;
41
42class SkinReference : public RefCounted {
43 GDCLASS(SkinReference, RefCounted)
44 friend class Skeleton3D;
45
46 Skeleton3D *skeleton_node = nullptr;
47 RID skeleton;
48 Ref<Skin> skin;
49 uint32_t bind_count = 0;
50 uint64_t skeleton_version = 0;
51 Vector<uint32_t> skin_bone_indices;
52 uint32_t *skin_bone_indices_ptrs = nullptr;
53
54protected:
55 static void _bind_methods();
56
57public:
58 // Public for use with callable_mp.
59 void _skin_changed();
60
61 RID get_skeleton() const;
62 Ref<Skin> get_skin() const;
63 ~SkinReference();
64};
65
66class Skeleton3D : public Node3D {
67 GDCLASS(Skeleton3D, Node3D);
68
69private:
70 friend class SkinReference;
71
72 struct Bone {
73 String name;
74
75 bool enabled;
76 int parent;
77
78 Transform3D rest;
79 Transform3D global_rest;
80
81 _FORCE_INLINE_ void update_pose_cache() {
82 if (pose_cache_dirty) {
83 pose_cache.basis.set_quaternion_scale(pose_rotation, pose_scale);
84 pose_cache.origin = pose_position;
85 pose_cache_dirty = false;
86 }
87 }
88 bool pose_cache_dirty = true;
89 Transform3D pose_cache;
90 Vector3 pose_position;
91 Quaternion pose_rotation;
92 Vector3 pose_scale = Vector3(1, 1, 1);
93
94 Transform3D pose_global;
95 Transform3D pose_global_no_override;
96
97 real_t global_pose_override_amount = 0.0;
98 bool global_pose_override_reset = false;
99 Transform3D global_pose_override;
100
101 PhysicalBone3D *physical_bone = nullptr;
102 PhysicalBone3D *cache_parent_physical_bone = nullptr;
103
104 Vector<int> child_bones;
105
106 Bone() {
107 parent = -1;
108 enabled = true;
109 global_pose_override_amount = 0;
110 global_pose_override_reset = false;
111#ifndef _3D_DISABLED
112 physical_bone = nullptr;
113 cache_parent_physical_bone = nullptr;
114#endif // _3D_DISABLED
115 child_bones = Vector<int>();
116 }
117 };
118
119 HashSet<SkinReference *> skin_bindings;
120
121 void _skin_changed();
122
123 bool animate_physical_bones = true;
124 Vector<Bone> bones;
125 bool process_order_dirty = false;
126
127 Vector<int> parentless_bones;
128 HashMap<String, int> name_to_bone_index;
129
130 void _make_dirty();
131 bool dirty = false;
132 bool rest_dirty = false;
133
134 bool show_rest_only = false;
135 float motion_scale = 1.0;
136
137 uint64_t version = 1;
138
139 void _update_process_order();
140
141protected:
142 bool _get(const StringName &p_path, Variant &r_ret) const;
143 bool _set(const StringName &p_path, const Variant &p_value);
144 void _get_property_list(List<PropertyInfo> *p_list) const;
145 void _validate_property(PropertyInfo &p_property) const;
146 void _notification(int p_what);
147 static void _bind_methods();
148
149public:
150 enum {
151 NOTIFICATION_UPDATE_SKELETON = 50
152 };
153
154 // skeleton creation api
155 uint64_t get_version() const;
156 void add_bone(const String &p_name);
157 int find_bone(const String &p_name) const;
158 String get_bone_name(int p_bone) const;
159 void set_bone_name(int p_bone, const String &p_name);
160
161 bool is_bone_parent_of(int p_bone_id, int p_parent_bone_id) const;
162
163 void set_bone_parent(int p_bone, int p_parent);
164 int get_bone_parent(int p_bone) const;
165
166 void unparent_bone_and_rest(int p_bone);
167
168 Vector<int> get_bone_children(int p_bone) const;
169 Vector<int> get_parentless_bones() const;
170
171 int get_bone_count() const;
172
173 void set_bone_rest(int p_bone, const Transform3D &p_rest);
174 Transform3D get_bone_rest(int p_bone) const;
175 Transform3D get_bone_global_rest(int p_bone) const;
176 Transform3D get_bone_global_pose(int p_bone) const;
177 Transform3D get_bone_global_pose_no_override(int p_bone) const;
178
179 void set_bone_enabled(int p_bone, bool p_enabled);
180 bool is_bone_enabled(int p_bone) const;
181
182 void set_show_rest_only(bool p_enabled);
183 bool is_show_rest_only() const;
184 void clear_bones();
185
186 void set_motion_scale(float p_motion_scale);
187 float get_motion_scale() const;
188
189 // posing api
190
191 void set_bone_pose_position(int p_bone, const Vector3 &p_position);
192 void set_bone_pose_rotation(int p_bone, const Quaternion &p_rotation);
193 void set_bone_pose_scale(int p_bone, const Vector3 &p_scale);
194
195 Transform3D get_bone_pose(int p_bone) const;
196
197 Vector3 get_bone_pose_position(int p_bone) const;
198 Quaternion get_bone_pose_rotation(int p_bone) const;
199 Vector3 get_bone_pose_scale(int p_bone) const;
200
201 void reset_bone_pose(int p_bone);
202 void reset_bone_poses();
203
204 void clear_bones_global_pose_override();
205 Transform3D get_bone_global_pose_override(int p_bone) const;
206 void set_bone_global_pose_override(int p_bone, const Transform3D &p_pose, real_t p_amount, bool p_persistent = false);
207
208 void localize_rests(); // used for loaders and tools
209
210 Ref<Skin> create_skin_from_rest_transforms();
211
212 Ref<SkinReference> register_skin(const Ref<Skin> &p_skin);
213
214 void force_update_all_dirty_bones();
215 void force_update_all_bone_transforms();
216 void force_update_bone_children_transforms(int bone_idx);
217
218 // Physical bone API
219
220 void set_animate_physical_bones(bool p_enabled);
221 bool get_animate_physical_bones() const;
222
223 void bind_physical_bone_to_bone(int p_bone, PhysicalBone3D *p_physical_bone);
224 void unbind_physical_bone_from_bone(int p_bone);
225
226 PhysicalBone3D *get_physical_bone(int p_bone);
227 PhysicalBone3D *get_physical_bone_parent(int p_bone);
228
229private:
230 /// This is a slow API, so it's cached
231 PhysicalBone3D *_get_physical_bone_parent(int p_bone);
232 void _rebuild_physical_bones_cache();
233
234public:
235 void physical_bones_stop_simulation();
236 void physical_bones_start_simulation_on(const TypedArray<StringName> &p_bones);
237 void physical_bones_add_collision_exception(RID p_exception);
238 void physical_bones_remove_collision_exception(RID p_exception);
239
240public:
241 Skeleton3D();
242 ~Skeleton3D();
243};
244
245#endif // SKELETON_3D_H
246