1 | /**************************************************************************/ |
2 | /* animation_tree.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 ANIMATION_TREE_H |
32 | #define ANIMATION_TREE_H |
33 | |
34 | #include "animation_player.h" |
35 | #include "scene/3d/node_3d.h" |
36 | #include "scene/3d/skeleton_3d.h" |
37 | #include "scene/resources/animation.h" |
38 | #include "scene/resources/audio_stream_polyphonic.h" |
39 | |
40 | #define HUGE_LENGTH 31540000 // 31540000 seconds mean 1 year... is it too long? It must be longer than any Animation length and Transition xfade time to prevent time inversion. |
41 | |
42 | class AnimationNodeBlendTree; |
43 | class AnimationNodeStartState; |
44 | class AnimationNodeEndState; |
45 | class AnimationPlayer; |
46 | class AnimationTree; |
47 | |
48 | class AnimationNode : public Resource { |
49 | GDCLASS(AnimationNode, Resource); |
50 | |
51 | public: |
52 | enum FilterAction { |
53 | FILTER_IGNORE, |
54 | FILTER_PASS, |
55 | FILTER_STOP, |
56 | FILTER_BLEND |
57 | }; |
58 | |
59 | struct Input { |
60 | String name; |
61 | }; |
62 | |
63 | Vector<Input> inputs; |
64 | |
65 | friend class AnimationTree; |
66 | |
67 | struct AnimationState { |
68 | Ref<Animation> animation; |
69 | double time = 0.0; |
70 | double delta = 0.0; |
71 | Vector<real_t> track_blends; |
72 | real_t blend = 0.0; |
73 | bool seeked = false; |
74 | bool is_external_seeking = false; |
75 | Animation::LoopedFlag looped_flag = Animation::LOOPED_FLAG_NONE; |
76 | }; |
77 | |
78 | struct State { |
79 | int track_count = 0; |
80 | HashMap<NodePath, int> track_map; |
81 | List<AnimationState> animation_states; |
82 | bool valid = false; |
83 | AnimationPlayer *player = nullptr; |
84 | AnimationTree *tree = nullptr; |
85 | String invalid_reasons; |
86 | uint64_t last_pass = 0; |
87 | }; |
88 | |
89 | Vector<real_t> blends; |
90 | State *state = nullptr; |
91 | |
92 | bool is_testing = false; |
93 | |
94 | double _pre_process(const StringName &p_base_path, AnimationNode *p_parent, State *p_state, double p_time, bool p_seek, bool p_is_external_seeking, const Vector<StringName> &p_connections, bool p_test_only = false); |
95 | |
96 | //all this is temporary |
97 | StringName base_path; |
98 | Vector<StringName> connections; |
99 | AnimationNode *parent = nullptr; |
100 | |
101 | HashMap<NodePath, bool> filter; |
102 | bool filter_enabled = false; |
103 | |
104 | bool closable = false; |
105 | |
106 | Array _get_filters() const; |
107 | void _set_filters(const Array &p_filters); |
108 | friend class AnimationNodeBlendTree; |
109 | double _blend_node(const StringName &p_subpath, const Vector<StringName> &p_connections, AnimationNode *p_new_parent, Ref<AnimationNode> p_node, double p_time, bool p_seek, bool p_is_external_seeking, real_t p_blend, FilterAction p_filter = FILTER_IGNORE, bool p_sync = true, real_t *r_max = nullptr, bool p_test_only = false); |
110 | |
111 | protected: |
112 | virtual double _process(double p_time, bool p_seek, bool p_is_external_seeking, bool p_test_only = false); |
113 | double process(double p_time, bool p_seek, bool p_is_external_seeking, bool p_test_only = false); |
114 | |
115 | void blend_animation(const StringName &p_animation, double p_time, double p_delta, bool p_seeked, bool p_is_external_seeking, real_t p_blend, Animation::LoopedFlag p_looped_flag = Animation::LOOPED_FLAG_NONE); |
116 | double blend_node(const StringName &p_sub_path, Ref<AnimationNode> p_node, double p_time, bool p_seek, bool p_is_external_seeking, real_t p_blend, FilterAction p_filter = FILTER_IGNORE, bool p_sync = true, bool p_test_only = false); |
117 | double blend_input(int p_input, double p_time, bool p_seek, bool p_is_external_seeking, real_t p_blend, FilterAction p_filter = FILTER_IGNORE, bool p_sync = true, bool p_test_only = false); |
118 | |
119 | void make_invalid(const String &p_reason); |
120 | AnimationTree *get_animation_tree() const; |
121 | |
122 | static void _bind_methods(); |
123 | |
124 | void _validate_property(PropertyInfo &p_property) const; |
125 | |
126 | GDVIRTUAL0RC(Dictionary, _get_child_nodes) |
127 | GDVIRTUAL0RC(Array, _get_parameter_list) |
128 | GDVIRTUAL1RC(Ref<AnimationNode>, _get_child_by_name, StringName) |
129 | GDVIRTUAL1RC(Variant, _get_parameter_default_value, StringName) |
130 | GDVIRTUAL1RC(bool, _is_parameter_read_only, StringName) |
131 | GDVIRTUAL4RC(double, _process, double, bool, bool, bool) |
132 | GDVIRTUAL0RC(String, _get_caption) |
133 | GDVIRTUAL0RC(bool, _has_filter) |
134 | |
135 | public: |
136 | virtual void get_parameter_list(List<PropertyInfo> *r_list) const; |
137 | virtual Variant get_parameter_default_value(const StringName &p_parameter) const; |
138 | virtual bool is_parameter_read_only(const StringName &p_parameter) const; |
139 | |
140 | void set_parameter(const StringName &p_name, const Variant &p_value); |
141 | Variant get_parameter(const StringName &p_name) const; |
142 | |
143 | struct ChildNode { |
144 | StringName name; |
145 | Ref<AnimationNode> node; |
146 | }; |
147 | |
148 | virtual void get_child_nodes(List<ChildNode> *r_child_nodes); |
149 | |
150 | virtual String get_caption() const; |
151 | |
152 | virtual bool add_input(const String &p_name); |
153 | virtual void remove_input(int p_index); |
154 | virtual bool set_input_name(int p_input, const String &p_name); |
155 | virtual String get_input_name(int p_input) const; |
156 | int get_input_count() const; |
157 | int find_input(const String &p_name) const; |
158 | |
159 | void set_filter_path(const NodePath &p_path, bool p_enable); |
160 | bool is_path_filtered(const NodePath &p_path) const; |
161 | |
162 | void set_filter_enabled(bool p_enable); |
163 | bool is_filter_enabled() const; |
164 | |
165 | void set_closable(bool p_closable); |
166 | bool is_closable() const; |
167 | |
168 | virtual bool has_filter() const; |
169 | |
170 | virtual Ref<AnimationNode> get_child_by_name(const StringName &p_name) const; |
171 | Ref<AnimationNode> find_node_by_path(const String &p_name) const; |
172 | |
173 | AnimationNode(); |
174 | }; |
175 | |
176 | VARIANT_ENUM_CAST(AnimationNode::FilterAction) |
177 | |
178 | //root node does not allow inputs |
179 | class AnimationRootNode : public AnimationNode { |
180 | GDCLASS(AnimationRootNode, AnimationNode); |
181 | |
182 | protected: |
183 | virtual void _tree_changed(); |
184 | virtual void _animation_node_renamed(const ObjectID &p_oid, const String &p_old_name, const String &p_new_name); |
185 | virtual void _animation_node_removed(const ObjectID &p_oid, const StringName &p_node); |
186 | |
187 | public: |
188 | AnimationRootNode() {} |
189 | }; |
190 | |
191 | class AnimationNodeStartState : public AnimationRootNode { |
192 | GDCLASS(AnimationNodeStartState, AnimationRootNode); |
193 | }; |
194 | |
195 | class AnimationNodeEndState : public AnimationRootNode { |
196 | GDCLASS(AnimationNodeEndState, AnimationRootNode); |
197 | }; |
198 | |
199 | class AnimationTree : public Node { |
200 | GDCLASS(AnimationTree, Node); |
201 | |
202 | void _call_object(Object *p_object, const StringName &p_method, const Vector<Variant> &p_params, bool p_deferred); |
203 | |
204 | public: |
205 | enum AnimationProcessCallback { |
206 | ANIMATION_PROCESS_PHYSICS, |
207 | ANIMATION_PROCESS_IDLE, |
208 | ANIMATION_PROCESS_MANUAL, |
209 | }; |
210 | |
211 | private: |
212 | struct TrackCache { |
213 | bool root_motion = false; |
214 | uint64_t setup_pass = 0; |
215 | Animation::TrackType type = Animation::TrackType::TYPE_ANIMATION; |
216 | Object *object = nullptr; |
217 | ObjectID object_id; |
218 | |
219 | TrackCache() { |
220 | } |
221 | virtual ~TrackCache() {} |
222 | }; |
223 | |
224 | struct TrackCacheTransform : public TrackCache { |
225 | #ifndef _3D_DISABLED |
226 | Node3D *node_3d = nullptr; |
227 | Skeleton3D *skeleton = nullptr; |
228 | #endif // _3D_DISABLED |
229 | int bone_idx = -1; |
230 | bool loc_used = false; |
231 | bool rot_used = false; |
232 | bool scale_used = false; |
233 | Vector3 init_loc = Vector3(0, 0, 0); |
234 | Quaternion init_rot = Quaternion(0, 0, 0, 1); |
235 | Vector3 init_scale = Vector3(1, 1, 1); |
236 | Vector3 loc; |
237 | Quaternion rot; |
238 | Vector3 scale; |
239 | |
240 | TrackCacheTransform() { |
241 | type = Animation::TYPE_POSITION_3D; |
242 | } |
243 | }; |
244 | |
245 | struct RootMotionCache { |
246 | Vector3 loc = Vector3(0, 0, 0); |
247 | Quaternion rot = Quaternion(0, 0, 0, 1); |
248 | Vector3 scale = Vector3(1, 1, 1); |
249 | }; |
250 | |
251 | struct TrackCacheBlendShape : public TrackCache { |
252 | MeshInstance3D *mesh_3d = nullptr; |
253 | float init_value = 0; |
254 | float value = 0; |
255 | int shape_index = -1; |
256 | TrackCacheBlendShape() { type = Animation::TYPE_BLEND_SHAPE; } |
257 | }; |
258 | |
259 | struct TrackCacheValue : public TrackCache { |
260 | Variant init_value; |
261 | Variant value; |
262 | Vector<StringName> subpath; |
263 | bool is_discrete = false; |
264 | bool is_using_angle = false; |
265 | TrackCacheValue() { type = Animation::TYPE_VALUE; } |
266 | }; |
267 | |
268 | struct TrackCacheMethod : public TrackCache { |
269 | TrackCacheMethod() { type = Animation::TYPE_METHOD; } |
270 | }; |
271 | |
272 | struct TrackCacheBezier : public TrackCache { |
273 | real_t init_value = 0.0; |
274 | real_t value = 0.0; |
275 | Vector<StringName> subpath; |
276 | TrackCacheBezier() { |
277 | type = Animation::TYPE_BEZIER; |
278 | } |
279 | }; |
280 | |
281 | // Audio stream information for each audio stream placed on the track. |
282 | struct PlayingAudioStreamInfo { |
283 | AudioStreamPlaybackPolyphonic::ID index = -1; // ID retrieved from AudioStreamPlaybackPolyphonic. |
284 | double start = 0.0; |
285 | double len = 0.0; |
286 | }; |
287 | |
288 | // Audio track information for mixng and ending. |
289 | struct PlayingAudioTrackInfo { |
290 | HashMap<int, PlayingAudioStreamInfo> stream_info; |
291 | double length = 0.0; |
292 | double time = 0.0; |
293 | real_t volume = 0.0; |
294 | bool loop = false; |
295 | bool backward = false; |
296 | bool use_blend = false; |
297 | }; |
298 | |
299 | struct TrackCacheAudio : public TrackCache { |
300 | Ref<AudioStreamPolyphonic> audio_stream; |
301 | Ref<AudioStreamPlaybackPolyphonic> audio_stream_playback; |
302 | HashMap<ObjectID, PlayingAudioTrackInfo> playing_streams; // Key is Animation resource ObjectID. |
303 | |
304 | TrackCacheAudio() { |
305 | type = Animation::TYPE_AUDIO; |
306 | } |
307 | }; |
308 | |
309 | struct TrackCacheAnimation : public TrackCache { |
310 | bool playing = false; |
311 | |
312 | TrackCacheAnimation() { |
313 | type = Animation::TYPE_ANIMATION; |
314 | } |
315 | }; |
316 | |
317 | RootMotionCache root_motion_cache; |
318 | HashMap<NodePath, TrackCache *> track_cache; |
319 | HashSet<TrackCache *> playing_caches; |
320 | Vector<Node *> playing_audio_stream_players; |
321 | |
322 | Ref<AnimationNode> root; |
323 | NodePath advance_expression_base_node = NodePath(String("." )); |
324 | |
325 | AnimationProcessCallback process_callback = ANIMATION_PROCESS_IDLE; |
326 | bool active = false; |
327 | NodePath animation_player; |
328 | int audio_max_polyphony = 32; |
329 | |
330 | AnimationNode::State state; |
331 | bool cache_valid = false; |
332 | void _node_removed(Node *p_node); |
333 | |
334 | void _setup_animation_player(); |
335 | void _animation_player_changed(); |
336 | void _clear_caches(); |
337 | void _clear_playing_caches(); |
338 | void _clear_audio_streams(); |
339 | bool _update_caches(AnimationPlayer *player); |
340 | void _process_graph(double p_delta); |
341 | |
342 | uint64_t setup_pass = 1; |
343 | uint64_t process_pass = 1; |
344 | |
345 | bool started = true; |
346 | |
347 | NodePath root_motion_track; |
348 | Vector3 root_motion_position = Vector3(0, 0, 0); |
349 | Quaternion root_motion_rotation = Quaternion(0, 0, 0, 1); |
350 | Vector3 root_motion_scale = Vector3(0, 0, 0); |
351 | Vector3 root_motion_position_accumulator = Vector3(0, 0, 0); |
352 | Quaternion root_motion_rotation_accumulator = Quaternion(0, 0, 0, 1); |
353 | Vector3 root_motion_scale_accumulator = Vector3(1, 1, 1); |
354 | |
355 | friend class AnimationNode; |
356 | bool properties_dirty = true; |
357 | void _tree_changed(); |
358 | void _animation_node_renamed(const ObjectID &p_oid, const String &p_old_name, const String &p_new_name); |
359 | void _animation_node_removed(const ObjectID &p_oid, const StringName &p_node); |
360 | void _update_properties(); |
361 | List<PropertyInfo> properties; |
362 | HashMap<StringName, HashMap<StringName, StringName>> property_parent_map; |
363 | HashMap<ObjectID, StringName> property_reference_map; |
364 | HashMap<StringName, Pair<Variant, bool>> property_map; // Property value and read-only flag. |
365 | |
366 | struct Activity { |
367 | uint64_t last_pass = 0; |
368 | real_t activity = 0.0; |
369 | }; |
370 | |
371 | HashMap<StringName, Vector<Activity>> input_activity_map; |
372 | HashMap<StringName, Vector<Activity> *> input_activity_map_get; |
373 | |
374 | void _update_properties_for_node(const String &p_base_path, Ref<AnimationNode> node); |
375 | |
376 | ObjectID last_animation_player; |
377 | |
378 | protected: |
379 | bool _set(const StringName &p_name, const Variant &p_value); |
380 | bool _get(const StringName &p_name, Variant &r_ret) const; |
381 | void _get_property_list(List<PropertyInfo> *p_list) const; |
382 | |
383 | void _notification(int p_what); |
384 | static void _bind_methods(); |
385 | |
386 | GDVIRTUAL5RC(Variant, _post_process_key_value, Ref<Animation>, int, Variant, Object *, int); |
387 | Variant post_process_key_value(const Ref<Animation> &p_anim, int p_track, Variant p_value, const Object *p_object, int p_object_idx = -1); |
388 | virtual Variant _post_process_key_value(const Ref<Animation> &p_anim, int p_track, Variant p_value, const Object *p_object, int p_object_idx = -1); |
389 | |
390 | public: |
391 | void set_tree_root(const Ref<AnimationNode> &p_root); |
392 | Ref<AnimationNode> get_tree_root() const; |
393 | |
394 | void set_active(bool p_active); |
395 | bool is_active() const; |
396 | |
397 | void set_process_callback(AnimationProcessCallback p_mode); |
398 | AnimationProcessCallback get_process_callback() const; |
399 | |
400 | void set_animation_player(const NodePath &p_player); |
401 | NodePath get_animation_player() const; |
402 | |
403 | void set_advance_expression_base_node(const NodePath &p_advance_expression_base_node); |
404 | NodePath get_advance_expression_base_node() const; |
405 | |
406 | void set_audio_max_polyphony(int p_audio_max_polyphony); |
407 | int get_audio_max_polyphony() const; |
408 | |
409 | PackedStringArray get_configuration_warnings() const override; |
410 | |
411 | bool is_state_invalid() const; |
412 | String get_invalid_state_reason() const; |
413 | |
414 | void set_root_motion_track(const NodePath &p_track); |
415 | NodePath get_root_motion_track() const; |
416 | |
417 | Vector3 get_root_motion_position() const; |
418 | Quaternion get_root_motion_rotation() const; |
419 | Vector3 get_root_motion_scale() const; |
420 | |
421 | Vector3 get_root_motion_position_accumulator() const; |
422 | Quaternion get_root_motion_rotation_accumulator() const; |
423 | Vector3 get_root_motion_scale_accumulator() const; |
424 | |
425 | real_t get_connection_activity(const StringName &p_path, int p_connection) const; |
426 | void advance(double p_time); |
427 | |
428 | uint64_t get_last_process_pass() const; |
429 | AnimationTree(); |
430 | ~AnimationTree(); |
431 | }; |
432 | |
433 | VARIANT_ENUM_CAST(AnimationTree::AnimationProcessCallback) |
434 | |
435 | #endif // ANIMATION_TREE_H |
436 | |