1/**************************************************************************/
2/* animation_player.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 "animation_player.h"
32
33#include "core/config/engine.h"
34#include "core/object/message_queue.h"
35#include "scene/scene_string_names.h"
36#include "servers/audio/audio_stream.h"
37
38#ifdef TOOLS_ENABLED
39#include "editor/editor_node.h"
40#include "editor/editor_undo_redo_manager.h"
41#include "scene/2d/skeleton_2d.h"
42
43void AnimatedValuesBackup::update_skeletons() {
44 for (int i = 0; i < entries.size(); i++) {
45 if (entries[i].bone_idx != -1) {
46 // 3D bone
47 Object::cast_to<Skeleton3D>(entries[i].object)->notification(Skeleton3D::NOTIFICATION_UPDATE_SKELETON);
48 } else {
49 Bone2D *bone = Object::cast_to<Bone2D>(entries[i].object);
50 if (bone && bone->skeleton) {
51 // 2D bone
52 bone->skeleton->_update_transform();
53 }
54 }
55 }
56}
57
58void AnimatedValuesBackup::restore() const {
59 for (int i = 0; i < entries.size(); i++) {
60 const AnimatedValuesBackup::Entry *entry = &entries[i];
61 if (entry->bone_idx == -1) {
62 entry->object->set_indexed(entry->subpath, entry->value);
63 } else {
64 Array arr = entry->value;
65 if (arr.size() == 3) {
66 Object::cast_to<Skeleton3D>(entry->object)->set_bone_pose_position(entry->bone_idx, arr[0]);
67 Object::cast_to<Skeleton3D>(entry->object)->set_bone_pose_rotation(entry->bone_idx, arr[1]);
68 Object::cast_to<Skeleton3D>(entry->object)->set_bone_pose_scale(entry->bone_idx, arr[2]);
69 }
70 }
71 }
72}
73
74void AnimatedValuesBackup::_bind_methods() {
75 ClassDB::bind_method(D_METHOD("restore"), &AnimatedValuesBackup::restore);
76}
77#endif
78
79bool AnimationPlayer::_set(const StringName &p_name, const Variant &p_value) {
80 String name = p_name;
81
82 if (name.begins_with("playback/play")) { // bw compatibility
83
84 set_current_animation(p_value);
85
86 } else if (name.begins_with("anims/")) {
87 // Backwards compatibility with 3.x, add them to "default" library.
88 String which = name.get_slicec('/', 1);
89
90 Ref<Animation> anim = p_value;
91 Ref<AnimationLibrary> al;
92 if (!has_animation_library(StringName())) {
93 al.instantiate();
94 add_animation_library(StringName(), al);
95 } else {
96 al = get_animation_library(StringName());
97 }
98 al->add_animation(which, anim);
99
100 } else if (name.begins_with("libraries")) {
101 Dictionary d = p_value;
102 while (animation_libraries.size()) {
103 remove_animation_library(animation_libraries[0].name);
104 }
105 List<Variant> keys;
106 d.get_key_list(&keys);
107 for (const Variant &K : keys) {
108 StringName lib_name = K;
109 Ref<AnimationLibrary> lib = d[lib_name];
110 add_animation_library(lib_name, lib);
111 }
112 emit_signal("animation_libraries_updated");
113 } else if (name.begins_with("next/")) {
114 String which = name.get_slicec('/', 1);
115 animation_set_next(which, p_value);
116
117 } else if (p_name == SceneStringNames::get_singleton()->blend_times) {
118 Array array = p_value;
119 int len = array.size();
120 ERR_FAIL_COND_V(len % 3, false);
121
122 for (int i = 0; i < len / 3; i++) {
123 StringName from = array[i * 3 + 0];
124 StringName to = array[i * 3 + 1];
125 float time = array[i * 3 + 2];
126
127 set_blend_time(from, to, time);
128 }
129
130 } else {
131 return false;
132 }
133
134 return true;
135}
136
137bool AnimationPlayer::_get(const StringName &p_name, Variant &r_ret) const {
138 String name = p_name;
139
140 if (name == "playback/play") { // bw compatibility
141
142 r_ret = get_current_animation();
143
144 } else if (name.begins_with("libraries")) {
145 Dictionary d;
146 for (const AnimationLibraryData &lib : animation_libraries) {
147 d[lib.name] = lib.library;
148 }
149
150 r_ret = d;
151
152 } else if (name.begins_with("next/")) {
153 String which = name.get_slicec('/', 1);
154
155 r_ret = animation_get_next(which);
156
157 } else if (name == "blend_times") {
158 Vector<BlendKey> keys;
159 for (const KeyValue<BlendKey, double> &E : blend_times) {
160 keys.ordered_insert(E.key);
161 }
162
163 Array array;
164 for (int i = 0; i < keys.size(); i++) {
165 array.push_back(keys[i].from);
166 array.push_back(keys[i].to);
167 array.push_back(blend_times.get(keys[i]));
168 }
169
170 r_ret = array;
171 } else {
172 return false;
173 }
174
175 return true;
176}
177
178void AnimationPlayer::_validate_property(PropertyInfo &p_property) const {
179 if (p_property.name == "current_animation") {
180 List<String> names;
181
182 for (const KeyValue<StringName, AnimationData> &E : animation_set) {
183 names.push_back(E.key);
184 }
185 names.sort();
186 names.push_front("[stop]");
187 String hint;
188 for (List<String>::Element *E = names.front(); E; E = E->next()) {
189 if (E != names.front()) {
190 hint += ",";
191 }
192 hint += E->get();
193 }
194
195 p_property.hint_string = hint;
196 }
197}
198
199void AnimationPlayer::_get_property_list(List<PropertyInfo> *p_list) const {
200 List<PropertyInfo> anim_names;
201
202 anim_names.push_back(PropertyInfo(Variant::DICTIONARY, PNAME("libraries")));
203
204 for (const KeyValue<StringName, AnimationData> &E : animation_set) {
205 if (E.value.next != StringName()) {
206 anim_names.push_back(PropertyInfo(Variant::STRING, "next/" + String(E.key), PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL));
207 }
208 }
209
210 anim_names.sort();
211
212 for (const PropertyInfo &E : anim_names) {
213 p_list->push_back(E);
214 }
215
216 p_list->push_back(PropertyInfo(Variant::ARRAY, "blend_times", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL));
217}
218
219void AnimationPlayer::advance(double p_time) {
220 _animation_process(p_time);
221}
222
223void AnimationPlayer::_notification(int p_what) {
224 switch (p_what) {
225 case NOTIFICATION_ENTER_TREE: {
226 if (!processing) {
227 //make sure that a previous process state was not saved
228 //only process if "processing" is set
229 set_physics_process_internal(false);
230 set_process_internal(false);
231 }
232 clear_caches();
233 } break;
234
235 case NOTIFICATION_READY: {
236 if (!Engine::get_singleton()->is_editor_hint() && animation_set.has(autoplay)) {
237 play(autoplay);
238 _animation_process(0);
239 }
240 } break;
241
242 case NOTIFICATION_INTERNAL_PROCESS: {
243 if (process_callback == ANIMATION_PROCESS_PHYSICS) {
244 break;
245 }
246
247 if (processing) {
248 _animation_process(get_process_delta_time());
249 }
250 } break;
251
252 case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: {
253 if (process_callback == ANIMATION_PROCESS_IDLE) {
254 break;
255 }
256
257 if (processing) {
258 _animation_process(get_physics_process_delta_time());
259 }
260 } break;
261
262 case NOTIFICATION_EXIT_TREE: {
263 clear_caches();
264 } break;
265 }
266}
267
268void AnimationPlayer::_ensure_node_caches(AnimationData *p_anim, Node *p_root_override) {
269 // Already cached?
270 if (p_anim->node_cache.size() == p_anim->animation->get_track_count()) {
271 return;
272 }
273
274 Node *parent = p_root_override ? p_root_override : get_node_or_null(root);
275
276 ERR_FAIL_NULL(parent);
277
278 Animation *a = p_anim->animation.operator->();
279
280 p_anim->node_cache.resize(a->get_track_count());
281
282 setup_pass++;
283
284 for (int i = 0; i < a->get_track_count(); i++) {
285 p_anim->node_cache.write[i] = nullptr;
286
287 if (!a->track_is_enabled(i)) {
288 continue;
289 }
290
291 Ref<Resource> resource;
292 Vector<StringName> leftover_path;
293 Node *child = parent->get_node_and_resource(a->track_get_path(i), resource, leftover_path);
294 ERR_CONTINUE_MSG(!child, "On Animation: '" + p_anim->name + "', couldn't resolve track: '" + String(a->track_get_path(i)) + "'."); // couldn't find the child node
295 ObjectID id = resource.is_valid() ? resource->get_instance_id() : child->get_instance_id();
296 int bone_idx = -1;
297 int blend_shape_idx = -1;
298
299#ifndef _3D_DISABLED
300 if (a->track_get_path(i).get_subname_count() == 1 && Object::cast_to<Skeleton3D>(child)) {
301 Skeleton3D *sk = Object::cast_to<Skeleton3D>(child);
302 bone_idx = sk->find_bone(a->track_get_path(i).get_subname(0));
303 if (bone_idx == -1) {
304 continue;
305 }
306 }
307
308 if (a->track_get_type(i) == Animation::TYPE_BLEND_SHAPE) {
309 MeshInstance3D *mi_3d = Object::cast_to<MeshInstance3D>(child);
310 if (!mi_3d) {
311 continue;
312 }
313 if (a->track_get_path(i).get_subname_count() != 1) {
314 continue;
315 }
316
317 blend_shape_idx = mi_3d->find_blend_shape_by_name(a->track_get_path(i).get_subname(0));
318 if (blend_shape_idx == -1) {
319 continue;
320 }
321 }
322
323#endif // _3D_DISABLED
324
325 if (!child->is_connected("tree_exiting", callable_mp(this, &AnimationPlayer::_node_removed))) {
326 child->connect("tree_exiting", callable_mp(this, &AnimationPlayer::_node_removed).bind(child), CONNECT_ONE_SHOT);
327 }
328
329 TrackNodeCacheKey key;
330 key.id = id;
331 key.bone_idx = bone_idx;
332 key.blend_shape_idx = blend_shape_idx;
333
334 if (!node_cache_map.has(key)) {
335 node_cache_map[key] = TrackNodeCache();
336 }
337
338 TrackNodeCache *node_cache = &node_cache_map[key];
339 p_anim->node_cache.write[i] = node_cache;
340
341 node_cache->path = a->track_get_path(i);
342 node_cache->node = child;
343 node_cache->resource = resource;
344 node_cache->node_2d = Object::cast_to<Node2D>(child);
345#ifndef _3D_DISABLED
346 if (a->track_get_type(i) == Animation::TYPE_POSITION_3D || a->track_get_type(i) == Animation::TYPE_ROTATION_3D || a->track_get_type(i) == Animation::TYPE_SCALE_3D) {
347 // special cases and caches for transform tracks
348
349 if (node_cache->last_setup_pass != setup_pass) {
350 node_cache->loc_used = false;
351 node_cache->rot_used = false;
352 node_cache->scale_used = false;
353 }
354
355 // cache node_3d
356 node_cache->node_3d = Object::cast_to<Node3D>(child);
357 // cache skeleton
358 node_cache->skeleton = Object::cast_to<Skeleton3D>(child);
359 if (node_cache->skeleton) {
360 if (a->track_get_path(i).get_subname_count() == 1) {
361 StringName bone_name = a->track_get_path(i).get_subname(0);
362
363 node_cache->bone_idx = node_cache->skeleton->find_bone(bone_name);
364 if (node_cache->bone_idx < 0) {
365 // broken track (nonexistent bone)
366 node_cache->skeleton = nullptr;
367 node_cache->node_3d = nullptr;
368 ERR_CONTINUE(node_cache->bone_idx < 0);
369 }
370 Transform3D rest = node_cache->skeleton->get_bone_rest(bone_idx);
371 node_cache->init_loc = rest.origin;
372 node_cache->init_rot = rest.basis.get_rotation_quaternion();
373 node_cache->init_scale = rest.basis.get_scale();
374 } else {
375 // Not a skeleton, the node can be accessed with the node_3d member.
376 node_cache->skeleton = nullptr;
377 }
378 }
379
380 switch (a->track_get_type(i)) {
381 case Animation::TYPE_POSITION_3D: {
382 node_cache->loc_used = true;
383 } break;
384 case Animation::TYPE_ROTATION_3D: {
385 node_cache->rot_used = true;
386 } break;
387 case Animation::TYPE_SCALE_3D: {
388 node_cache->scale_used = true;
389 } break;
390 default: {
391 }
392 }
393 }
394
395 if (a->track_get_type(i) == Animation::TYPE_BLEND_SHAPE) {
396 // special cases and caches for transform tracks
397 node_cache->node_blend_shape = Object::cast_to<MeshInstance3D>(child);
398 node_cache->blend_shape_idx = blend_shape_idx;
399 }
400
401#endif // _3D_DISABLED
402
403 if (a->track_get_type(i) == Animation::TYPE_VALUE) {
404 if (!node_cache->property_anim.has(a->track_get_path(i).get_concatenated_subnames())) {
405 TrackNodeCache::PropertyAnim pa;
406 pa.subpath = leftover_path;
407 pa.object = resource.is_valid() ? (Object *)resource.ptr() : (Object *)child;
408 pa.special = SP_NONE;
409 pa.owner = p_anim->node_cache[i];
410 if (false && node_cache->node_2d) {
411 if (leftover_path.size() == 1 && leftover_path[0] == SceneStringNames::get_singleton()->transform_pos) {
412 pa.special = SP_NODE2D_POS;
413 } else if (leftover_path.size() == 1 && leftover_path[0] == SceneStringNames::get_singleton()->transform_rot) {
414 pa.special = SP_NODE2D_ROT;
415 } else if (leftover_path.size() == 1 && leftover_path[0] == SceneStringNames::get_singleton()->transform_scale) {
416 pa.special = SP_NODE2D_SCALE;
417 }
418 }
419 node_cache->property_anim[a->track_get_path(i).get_concatenated_subnames()] = pa;
420 }
421 }
422
423 if (a->track_get_type(i) == Animation::TYPE_BEZIER && leftover_path.size()) {
424 if (!node_cache->bezier_anim.has(a->track_get_path(i).get_concatenated_subnames())) {
425 TrackNodeCache::BezierAnim ba;
426 ba.bezier_property = leftover_path;
427 ba.object = resource.is_valid() ? (Object *)resource.ptr() : (Object *)child;
428 ba.owner = p_anim->node_cache[i];
429
430 node_cache->bezier_anim[a->track_get_path(i).get_concatenated_subnames()] = ba;
431 }
432 }
433
434 if (a->track_get_type(i) == Animation::TYPE_AUDIO) {
435 if (!node_cache->audio_anim.has(a->track_get_path(i).get_concatenated_names())) {
436 TrackNodeCache::AudioAnim aa;
437 aa.object = (Object *)child;
438 aa.audio_stream.instantiate();
439 aa.audio_stream->set_polyphony(audio_max_polyphony);
440
441 node_cache->audio_anim[a->track_get_path(i).get_concatenated_names()] = aa;
442 }
443 }
444
445 node_cache->last_setup_pass = setup_pass;
446 }
447}
448
449static void _call_object(Object *p_object, const StringName &p_method, const Vector<Variant> &p_params, bool p_deferred) {
450 // Separate function to use alloca() more efficiently
451 const Variant **argptrs = (const Variant **)alloca(sizeof(const Variant **) * p_params.size());
452 const Variant *args = p_params.ptr();
453 uint32_t argcount = p_params.size();
454 for (uint32_t i = 0; i < argcount; i++) {
455 argptrs[i] = &args[i];
456 }
457 if (p_deferred) {
458 MessageQueue::get_singleton()->push_callp(p_object, p_method, argptrs, argcount);
459 } else {
460 Callable::CallError ce;
461 p_object->callp(p_method, argptrs, argcount, ce);
462 }
463}
464
465Variant AnimationPlayer::post_process_key_value(const Ref<Animation> &p_anim, int p_track, Variant p_value, const Object *p_object, int p_object_idx) {
466 Variant res;
467 if (GDVIRTUAL_CALL(_post_process_key_value, p_anim, p_track, p_value, const_cast<Object *>(p_object), p_object_idx, res)) {
468 return res;
469 }
470
471 return _post_process_key_value(p_anim, p_track, p_value, p_object, p_object_idx);
472}
473
474Variant AnimationPlayer::_post_process_key_value(const Ref<Animation> &p_anim, int p_track, Variant p_value, const Object *p_object, int p_object_idx) {
475 switch (p_anim->track_get_type(p_track)) {
476#ifndef _3D_DISABLED
477 case Animation::TYPE_POSITION_3D: {
478 if (p_object_idx >= 0) {
479 const Skeleton3D *skel = Object::cast_to<Skeleton3D>(p_object);
480 return Vector3(p_value) * skel->get_motion_scale();
481 }
482 return p_value;
483 } break;
484#endif // _3D_DISABLED
485 default: {
486 } break;
487 }
488 return p_value;
489}
490
491void AnimationPlayer::_animation_process_animation(AnimationData *p_anim, double p_prev_time, double p_time, double p_delta, float p_interp, bool p_is_current, bool p_seeked, bool p_started, Animation::LoopedFlag p_looped_flag) {
492 _ensure_node_caches(p_anim);
493 ERR_FAIL_COND(p_anim->node_cache.size() != p_anim->animation->get_track_count());
494
495 Animation *a = p_anim->animation.operator->();
496#ifdef TOOLS_ENABLED
497 bool can_call = is_inside_tree() && !Engine::get_singleton()->is_editor_hint();
498#endif // TOOLS_ENABLED
499 bool backward = signbit(p_delta);
500
501 for (int i = 0; i < a->get_track_count(); i++) {
502 // If an animation changes this animation (or it animates itself)
503 // we need to recreate our animation cache
504 if (p_anim->node_cache.size() != a->get_track_count()) {
505 _ensure_node_caches(p_anim);
506 }
507
508 TrackNodeCache *nc = p_anim->node_cache[i];
509
510 if (!nc) {
511 continue; // no node cache for this track, skip it
512 }
513
514 if (!a->track_is_enabled(i)) {
515 continue; // do nothing if the track is disabled
516 }
517
518 if (a->track_get_key_count(i) == 0) {
519 continue; // do nothing if track is empty
520 }
521
522 switch (a->track_get_type(i)) {
523 case Animation::TYPE_POSITION_3D: {
524#ifndef _3D_DISABLED
525 if (!nc->node_3d) {
526 continue;
527 }
528
529 Vector3 loc;
530
531 Error err = a->try_position_track_interpolate(i, p_time, &loc);
532 //ERR_CONTINUE(err!=OK); //used for testing, should be removed
533
534 if (err != OK) {
535 continue;
536 }
537 loc = post_process_key_value(a, i, loc, nc->node_3d, nc->bone_idx);
538
539 if (nc->accum_pass != accum_pass) {
540 ERR_CONTINUE(cache_update_size >= NODE_CACHE_UPDATE_MAX);
541 cache_update[cache_update_size++] = nc;
542 nc->accum_pass = accum_pass;
543 nc->loc_accum = loc;
544 nc->rot_accum = nc->init_rot;
545 nc->scale_accum = nc->init_scale;
546 } else {
547 nc->loc_accum = nc->loc_accum.lerp(loc, p_interp);
548 }
549#endif // _3D_DISABLED
550 } break;
551 case Animation::TYPE_ROTATION_3D: {
552#ifndef _3D_DISABLED
553 if (!nc->node_3d) {
554 continue;
555 }
556
557 Quaternion rot;
558
559 Error err = a->try_rotation_track_interpolate(i, p_time, &rot);
560 //ERR_CONTINUE(err!=OK); //used for testing, should be removed
561
562 if (err != OK) {
563 continue;
564 }
565 rot = post_process_key_value(a, i, rot, nc->node_3d, nc->bone_idx);
566
567 if (nc->accum_pass != accum_pass) {
568 ERR_CONTINUE(cache_update_size >= NODE_CACHE_UPDATE_MAX);
569 cache_update[cache_update_size++] = nc;
570 nc->accum_pass = accum_pass;
571 nc->loc_accum = nc->init_loc;
572 nc->rot_accum = rot;
573 nc->scale_accum = nc->init_scale;
574 } else {
575 nc->rot_accum = nc->rot_accum.slerp(rot, p_interp);
576 }
577#endif // _3D_DISABLED
578 } break;
579 case Animation::TYPE_SCALE_3D: {
580#ifndef _3D_DISABLED
581 if (!nc->node_3d) {
582 continue;
583 }
584
585 Vector3 scale;
586
587 Error err = a->try_scale_track_interpolate(i, p_time, &scale);
588 //ERR_CONTINUE(err!=OK); //used for testing, should be removed
589
590 if (err != OK) {
591 continue;
592 }
593 scale = post_process_key_value(a, i, scale, nc->node_3d, nc->bone_idx);
594
595 if (nc->accum_pass != accum_pass) {
596 ERR_CONTINUE(cache_update_size >= NODE_CACHE_UPDATE_MAX);
597 cache_update[cache_update_size++] = nc;
598 nc->accum_pass = accum_pass;
599 nc->loc_accum = nc->init_loc;
600 nc->rot_accum = nc->init_rot;
601 nc->scale_accum = scale;
602 } else {
603 nc->scale_accum = nc->scale_accum.lerp(scale, p_interp);
604 }
605#endif // _3D_DISABLED
606 } break;
607 case Animation::TYPE_BLEND_SHAPE: {
608#ifndef _3D_DISABLED
609 if (!nc->node_blend_shape) {
610 continue;
611 }
612
613 float blend;
614
615 Error err = a->try_blend_shape_track_interpolate(i, p_time, &blend);
616 //ERR_CONTINUE(err!=OK); //used for testing, should be removed
617
618 if (err != OK) {
619 continue;
620 }
621 blend = post_process_key_value(a, i, blend, nc->node_blend_shape, nc->blend_shape_idx);
622
623 if (nc->accum_pass != accum_pass) {
624 ERR_CONTINUE(cache_update_size >= NODE_CACHE_UPDATE_MAX);
625 nc->accum_pass = accum_pass;
626 cache_update[cache_update_size++] = nc;
627 nc->blend_shape_accum = blend;
628 } else {
629 nc->blend_shape_accum = Math::lerp(nc->blend_shape_accum, blend, p_interp);
630 }
631#endif // _3D_DISABLED
632 } break;
633 case Animation::TYPE_VALUE: {
634 if (!nc->node) {
635 continue;
636 }
637
638 //StringName property=a->track_get_path(i).get_property();
639
640 HashMap<StringName, TrackNodeCache::PropertyAnim>::Iterator E = nc->property_anim.find(a->track_get_path(i).get_concatenated_subnames());
641 ERR_CONTINUE(!E); //should it continue, or create a new one?
642
643 TrackNodeCache::PropertyAnim *pa = &E->value;
644
645 Animation::UpdateMode update_mode = a->value_track_get_update_mode(i);
646
647 if (update_mode == Animation::UPDATE_CAPTURE) {
648 if (p_started || pa->capture == Variant()) {
649 pa->capture = pa->object->get_indexed(pa->subpath);
650 }
651
652 int key_count = a->track_get_key_count(i);
653 if (key_count == 0) {
654 continue; //eeh not worth it
655 }
656
657 double first_key_time = a->track_get_key_time(i, 0);
658 double transition = 1.0;
659 int first_key = 0;
660
661 if (first_key_time == 0.0) {
662 //ignore, use for transition
663 if (key_count == 1) {
664 continue; //with one key we can't do anything
665 }
666 transition = (double)a->track_get_key_transition(i, 0);
667 first_key_time = a->track_get_key_time(i, 1);
668 first_key = 1;
669 }
670
671 if (p_time < first_key_time) {
672 double c = Math::ease(p_time / first_key_time, transition);
673 Variant first_value = a->track_get_key_value(i, first_key);
674 first_value = post_process_key_value(a, i, first_value, nc->node);
675 Variant interp_value = Animation::interpolate_variant(pa->capture, first_value, c);
676 if (pa->accum_pass != accum_pass) {
677 ERR_CONTINUE(cache_update_prop_size >= NODE_CACHE_UPDATE_MAX);
678 cache_update_prop[cache_update_prop_size++] = pa;
679 pa->value_accum = interp_value;
680 pa->accum_pass = accum_pass;
681 } else {
682 pa->value_accum = Animation::interpolate_variant(pa->value_accum, interp_value, p_interp);
683 }
684
685 continue; //handled
686 }
687 }
688
689 if (update_mode == Animation::UPDATE_CONTINUOUS || update_mode == Animation::UPDATE_CAPTURE) {
690 Variant value = a->value_track_interpolate(i, p_time);
691
692 if (value == Variant()) {
693 continue;
694 }
695 value = post_process_key_value(a, i, value, nc->node);
696
697 if (pa->accum_pass != accum_pass) {
698 ERR_CONTINUE(cache_update_prop_size >= NODE_CACHE_UPDATE_MAX);
699 cache_update_prop[cache_update_prop_size++] = pa;
700 pa->value_accum = value;
701 pa->accum_pass = accum_pass;
702 } else {
703 pa->value_accum = Animation::interpolate_variant(pa->value_accum, value, p_interp);
704 }
705
706 } else {
707 List<int> indices;
708
709 if (p_seeked) {
710 int found_key = a->track_find_key(i, p_time);
711 if (found_key >= 0) {
712 indices.push_back(found_key);
713 }
714 } else {
715 if (p_started) {
716 int first_key = a->track_find_key(i, p_prev_time, Animation::FIND_MODE_EXACT);
717 if (first_key >= 0) {
718 indices.push_back(first_key);
719 }
720 }
721 a->track_get_key_indices_in_range(i, p_time, p_delta, &indices, p_looped_flag);
722 }
723
724 for (int &F : indices) {
725 Variant value = a->track_get_key_value(i, F);
726 value = post_process_key_value(a, i, value, nc->node);
727 switch (pa->special) {
728 case SP_NONE: {
729 bool valid;
730 pa->object->set_indexed(pa->subpath, value, &valid); //you are not speshul
731#ifdef DEBUG_ENABLED
732 if (!valid) {
733 ERR_PRINT("Failed setting track value '" + String(pa->owner->path) + "'. Check if the property exists or the type of key is valid. Animation '" + a->get_name() + "' at node '" + get_path() + "'.");
734 }
735#endif
736
737 } break;
738 case SP_NODE2D_POS: {
739#ifdef DEBUG_ENABLED
740 if (value.get_type() != Variant::VECTOR2) {
741 ERR_PRINT("Position key at time " + rtos(p_time) + " in Animation Track '" + String(pa->owner->path) + "' not of type Vector2(). Animation '" + a->get_name() + "' at node '" + get_path() + "'.");
742 }
743#endif
744 static_cast<Node2D *>(pa->object)->set_position(value);
745 } break;
746 case SP_NODE2D_ROT: {
747#ifdef DEBUG_ENABLED
748 if (value.is_num()) {
749 ERR_PRINT("Rotation key at time " + rtos(p_time) + " in Animation Track '" + String(pa->owner->path) + "' not numerical. Animation '" + a->get_name() + "' at node '" + get_path() + "'.");
750 }
751#endif
752
753 static_cast<Node2D *>(pa->object)->set_rotation((double)value);
754 } break;
755 case SP_NODE2D_SCALE: {
756#ifdef DEBUG_ENABLED
757 if (value.get_type() != Variant::VECTOR2) {
758 ERR_PRINT("Scale key at time " + rtos(p_time) + " in Animation Track '" + String(pa->owner->path) + "' not of type Vector2()." + a->get_name() + "' at node '" + get_path() + "'.");
759 }
760#endif
761
762 static_cast<Node2D *>(pa->object)->set_scale(value);
763 } break;
764 }
765 }
766 }
767
768 } break;
769 case Animation::TYPE_METHOD: {
770#ifdef TOOLS_ENABLED
771 if (!can_call) {
772 continue;
773 }
774#endif // TOOLS_ENABLED
775 if (!p_is_current || !nc->node || is_stopping) {
776 continue;
777 }
778
779 List<int> indices;
780
781 if (p_seeked) {
782 int found_key = a->track_find_key(i, p_time, Animation::FIND_MODE_EXACT);
783 if (found_key >= 0) {
784 indices.push_back(found_key);
785 }
786 } else {
787 if (p_started) {
788 int first_key = a->track_find_key(i, p_prev_time, Animation::FIND_MODE_EXACT);
789 if (first_key >= 0) {
790 indices.push_back(first_key);
791 }
792 }
793 a->track_get_key_indices_in_range(i, p_time, p_delta, &indices, p_looped_flag);
794 }
795
796 for (int &E : indices) {
797 StringName method = a->method_track_get_name(i, E);
798 Vector<Variant> params = a->method_track_get_params(i, E);
799#ifdef DEBUG_ENABLED
800 if (!nc->node->has_method(method)) {
801 ERR_PRINT("Invalid method call '" + method + "'. '" + a->get_name() + "' at node '" + get_path() + "'.");
802 }
803#endif
804 _call_object(nc->node, method, params, method_call_mode == ANIMATION_METHOD_CALL_DEFERRED);
805 }
806
807 } break;
808 case Animation::TYPE_BEZIER: {
809 if (!nc->node) {
810 continue;
811 }
812
813 HashMap<StringName, TrackNodeCache::BezierAnim>::Iterator E = nc->bezier_anim.find(a->track_get_path(i).get_concatenated_subnames());
814 ERR_CONTINUE(!E); //should it continue, or create a new one?
815
816 TrackNodeCache::BezierAnim *ba = &E->value;
817
818 real_t bezier = a->bezier_track_interpolate(i, p_time);
819 bezier = post_process_key_value(a, i, bezier, nc->node);
820 if (ba->accum_pass != accum_pass) {
821 ERR_CONTINUE(cache_update_bezier_size >= NODE_CACHE_UPDATE_MAX);
822 cache_update_bezier[cache_update_bezier_size++] = ba;
823 ba->bezier_accum = bezier;
824 ba->accum_pass = accum_pass;
825 } else {
826 ba->bezier_accum = Math::lerp(ba->bezier_accum, (float)bezier, p_interp);
827 }
828
829 } break;
830 case Animation::TYPE_AUDIO: {
831 if (!nc->node || is_stopping) {
832 continue;
833 }
834#ifdef TOOLS_ENABLED
835 if (p_seeked && !can_call) {
836 continue; // To avoid spamming the preview in editor.
837 }
838#endif // TOOLS_ENABLED
839 HashMap<StringName, TrackNodeCache::AudioAnim>::Iterator E = nc->audio_anim.find(a->track_get_path(i).get_concatenated_names());
840 ERR_CONTINUE(!E); //should it continue, or create a new one?
841
842 TrackNodeCache::AudioAnim *aa = &E->value;
843 Node *asp = Object::cast_to<Node>(aa->object);
844 if (!asp) {
845 continue;
846 }
847 aa->length = a->get_length();
848 aa->time = p_time;
849 aa->loop = a->get_loop_mode() != Animation::LOOP_NONE;
850 aa->backward = backward;
851 if (aa->accum_pass != accum_pass) {
852 ERR_CONTINUE(cache_update_audio_size >= NODE_CACHE_UPDATE_MAX);
853 cache_update_audio[cache_update_audio_size++] = aa;
854 aa->accum_pass = accum_pass;
855 }
856
857 HashMap<int, TrackNodeCache::PlayingAudioStreamInfo> &map = aa->playing_streams;
858 // Find stream.
859 int idx = -1;
860 if (p_seeked || p_started) {
861 idx = a->track_find_key(i, p_time);
862 // Discard previous stream when seeking.
863 if (map.has(idx)) {
864 aa->audio_stream_playback->stop_stream(map[idx].index);
865 map.erase(idx);
866 }
867 } else {
868 List<int> to_play;
869
870 a->track_get_key_indices_in_range(i, p_time, p_delta, &to_play, p_looped_flag);
871 if (to_play.size()) {
872 idx = to_play.back()->get();
873 }
874 }
875 if (idx < 0) {
876 continue;
877 }
878
879 // Play stream.
880 Ref<AudioStream> stream = a->audio_track_get_key_stream(i, idx);
881 if (stream.is_valid()) {
882 double start_ofs = a->audio_track_get_key_start_offset(i, idx);
883 double end_ofs = a->audio_track_get_key_end_offset(i, idx);
884 double len = stream->get_length();
885
886 if (p_seeked || p_started) {
887 start_ofs += p_time - a->track_get_key_time(i, idx);
888 }
889
890 if (aa->object->call(SNAME("get_stream")) != aa->audio_stream) {
891 aa->object->call(SNAME("set_stream"), aa->audio_stream);
892 aa->audio_stream_playback.unref();
893 if (!playing_audio_stream_players.has(asp)) {
894 playing_audio_stream_players.push_back(asp);
895 }
896 }
897 if (!aa->object->call(SNAME("is_playing"))) {
898 aa->object->call(SNAME("play"));
899 }
900 if (!aa->object->call(SNAME("has_stream_playback"))) {
901 aa->audio_stream_playback.unref();
902 continue;
903 }
904 if (aa->audio_stream_playback.is_null()) {
905 aa->audio_stream_playback = aa->object->call(SNAME("get_stream_playback"));
906 }
907
908 TrackNodeCache::PlayingAudioStreamInfo pasi;
909 pasi.index = aa->audio_stream_playback->play_stream(stream, start_ofs);
910 pasi.start = p_time;
911 if (len && end_ofs > 0) { // Force an end at a time.
912 pasi.len = len - start_ofs - end_ofs;
913 } else {
914 pasi.len = 0;
915 }
916 map[idx] = pasi;
917 }
918
919 } break;
920 case Animation::TYPE_ANIMATION: {
921 if (is_stopping) {
922 continue;
923 }
924
925 AnimationPlayer *player = Object::cast_to<AnimationPlayer>(nc->node);
926 if (!player) {
927 continue;
928 }
929
930 if (p_seeked) {
931 //seek
932 int idx = a->track_find_key(i, p_time);
933 if (idx < 0) {
934 continue;
935 }
936
937 double pos = a->track_get_key_time(i, idx);
938
939 StringName anim_name = a->animation_track_get_key_animation(i, idx);
940 if (String(anim_name) == "[stop]" || !player->has_animation(anim_name)) {
941 continue;
942 }
943
944 Ref<Animation> anim = player->get_animation(anim_name);
945
946 double at_anim_pos = 0.0;
947
948 switch (anim->get_loop_mode()) {
949 case Animation::LOOP_NONE: {
950 at_anim_pos = MIN((double)anim->get_length(), p_time - pos); //seek to end
951 } break;
952
953 case Animation::LOOP_LINEAR: {
954 at_anim_pos = Math::fposmod(p_time - pos, (double)anim->get_length()); //seek to loop
955 } break;
956
957 case Animation::LOOP_PINGPONG: {
958 at_anim_pos = Math::pingpong(p_time - pos, (double)anim->get_length());
959 } break;
960
961 default:
962 break;
963 }
964
965 if (player->is_playing()) {
966 player->seek(at_anim_pos);
967 player->play(anim_name);
968 nc->animation_playing = true;
969 playing_caches.insert(nc);
970 } else {
971 player->set_assigned_animation(anim_name);
972 player->seek(at_anim_pos, true);
973 }
974 } else {
975 //find stuff to play
976 List<int> to_play;
977 if (p_started) {
978 int first_key = a->track_find_key(i, p_prev_time, Animation::FIND_MODE_EXACT);
979 if (first_key >= 0) {
980 to_play.push_back(first_key);
981 }
982 }
983 a->track_get_key_indices_in_range(i, p_time, p_delta, &to_play, p_looped_flag);
984 if (to_play.size()) {
985 int idx = to_play.back()->get();
986
987 StringName anim_name = a->animation_track_get_key_animation(i, idx);
988 if (String(anim_name) == "[stop]" || !player->has_animation(anim_name)) {
989 if (playing_caches.has(nc)) {
990 playing_caches.erase(nc);
991 player->stop();
992 nc->animation_playing = false;
993 }
994 } else {
995 player->seek(0.0);
996 player->play(anim_name);
997 nc->animation_playing = true;
998 playing_caches.insert(nc);
999 }
1000 }
1001 }
1002
1003 } break;
1004 }
1005 }
1006}
1007
1008void AnimationPlayer::_animation_process_data(PlaybackData &cd, double p_delta, float p_blend, bool p_seeked, bool p_started) {
1009 double delta = p_delta * speed_scale * cd.speed_scale;
1010 double next_pos = cd.pos + delta;
1011 bool backwards = signbit(delta); // Negative zero means playing backwards too.
1012
1013 real_t len = cd.from->animation->get_length();
1014 Animation::LoopedFlag looped_flag = Animation::LOOPED_FLAG_NONE;
1015
1016 switch (cd.from->animation->get_loop_mode()) {
1017 case Animation::LOOP_NONE: {
1018 if (next_pos < 0) {
1019 next_pos = 0;
1020 } else if (next_pos > len) {
1021 next_pos = len;
1022 }
1023 delta = next_pos - cd.pos; // Fix delta (after determination of backwards because negative zero is lost here).
1024 } break;
1025
1026 case Animation::LOOP_LINEAR: {
1027 if (next_pos < 0 && cd.pos >= 0) {
1028 looped_flag = Animation::LOOPED_FLAG_START;
1029 }
1030 if (next_pos > len && cd.pos <= len) {
1031 looped_flag = Animation::LOOPED_FLAG_END;
1032 }
1033 next_pos = Math::fposmod(next_pos, (double)len);
1034 } break;
1035
1036 case Animation::LOOP_PINGPONG: {
1037 if (next_pos < 0 && cd.pos >= 0) {
1038 cd.speed_scale *= -1.0;
1039 looped_flag = Animation::LOOPED_FLAG_START;
1040 }
1041 if (next_pos > len && cd.pos <= len) {
1042 cd.speed_scale *= -1.0;
1043 looped_flag = Animation::LOOPED_FLAG_END;
1044 }
1045 next_pos = Math::pingpong(next_pos, (double)len);
1046 } break;
1047
1048 default:
1049 break;
1050 }
1051
1052 double prev_pos = cd.pos; // The animation may be changed during process, so it is safer that the state is changed before process.
1053 cd.pos = next_pos;
1054
1055 AnimationData *prev_from = cd.from;
1056 _animation_process_animation(cd.from, prev_pos, cd.pos, delta, p_blend, &cd == &playback.current, p_seeked, p_started, looped_flag);
1057
1058 // End detection.
1059 if (cd.from->animation->get_loop_mode() == Animation::LOOP_NONE) {
1060 if (prev_from != playback.current.from) {
1061 return; // Animation has been changed in the process (may be caused by method track), abort process.
1062 }
1063 if (!backwards && prev_pos <= len && next_pos == len) {
1064 // Playback finished.
1065 end_reached = true;
1066 end_notify = prev_pos < len; // Notify only if not already at the end.
1067 }
1068 if (backwards && prev_pos >= 0 && next_pos == 0) {
1069 // Playback finished.
1070 end_reached = true;
1071 end_notify = prev_pos > 0; // Notify only if not already at the beginning.
1072 }
1073 }
1074}
1075
1076void AnimationPlayer::_animation_process2(double p_delta, bool p_started) {
1077 Playback &c = playback;
1078
1079 accum_pass++;
1080
1081 bool seeked = c.seeked; // The animation may be changed during process, so it is safer that the state is changed before process.
1082
1083 if (p_delta != 0) {
1084 c.seeked = false;
1085 }
1086
1087 float blend = 1.0; // First animation we play at 100% blend
1088
1089 List<Blend>::Element *next = NULL;
1090 for (List<Blend>::Element *E = c.blend.front(); E; E = next) {
1091 Blend &b = E->get();
1092 // Note: There may be issues if an animation event triggers an animation change while this blend is active,
1093 // so it is best to use "deferred" calls instead of "immediate" for animation events that can trigger new animations.
1094 _animation_process_data(b.data, p_delta, blend, false, false);
1095 blend = 1.0 - b.blend_left / b.blend_time; // This is how much to blend the NEXT animation
1096 b.blend_left -= Math::absf(speed_scale * p_delta);
1097 next = E->next();
1098 if (b.blend_left < 0) {
1099 // If the blend of this has finished, we need to remove ALL the previous blends
1100 List<Blend>::Element *prev;
1101 while (E) {
1102 prev = E->prev();
1103 c.blend.erase(E);
1104 E = prev;
1105 }
1106 }
1107 }
1108
1109 _animation_process_data(c.current, p_delta, blend, seeked, p_started);
1110}
1111
1112void AnimationPlayer::_animation_update_transforms() {
1113 {
1114 Transform3D t;
1115 for (int i = 0; i < cache_update_size; i++) {
1116 TrackNodeCache *nc = cache_update[i];
1117
1118 ERR_CONTINUE(nc->accum_pass != accum_pass);
1119#ifndef _3D_DISABLED
1120 if (nc->skeleton && nc->bone_idx >= 0) {
1121 if (nc->loc_used) {
1122 nc->skeleton->set_bone_pose_position(nc->bone_idx, nc->loc_accum);
1123 }
1124 if (nc->rot_used) {
1125 nc->skeleton->set_bone_pose_rotation(nc->bone_idx, nc->rot_accum);
1126 }
1127 if (nc->scale_used) {
1128 nc->skeleton->set_bone_pose_scale(nc->bone_idx, nc->scale_accum);
1129 }
1130
1131 } else if (nc->node_blend_shape) {
1132 nc->node_blend_shape->set_blend_shape_value(nc->blend_shape_idx, nc->blend_shape_accum);
1133 } else if (nc->node_3d) {
1134 if (nc->loc_used) {
1135 nc->node_3d->set_position(nc->loc_accum);
1136 }
1137 if (nc->rot_used) {
1138 nc->node_3d->set_rotation(nc->rot_accum.get_euler());
1139 }
1140 if (nc->scale_used) {
1141 nc->node_3d->set_scale(nc->scale_accum);
1142 }
1143 }
1144
1145#endif // _3D_DISABLED
1146 }
1147 }
1148
1149 for (int i = 0; i < cache_update_prop_size; i++) {
1150 TrackNodeCache::PropertyAnim *pa = cache_update_prop[i];
1151
1152 ERR_CONTINUE(pa->accum_pass != accum_pass);
1153
1154 switch (pa->special) {
1155 case SP_NONE: {
1156 bool valid;
1157 pa->object->set_indexed(pa->subpath, pa->value_accum, &valid); //you are not speshul
1158#ifdef DEBUG_ENABLED
1159
1160 if (!valid) {
1161 // Get subpath as string for printing the error
1162 // Cannot use `String::join(Vector<String>)` because this is a vector of StringName
1163 String key_debug;
1164 if (pa->subpath.size() > 0) {
1165 key_debug = pa->subpath[0];
1166 for (int subpath_index = 1; subpath_index < pa->subpath.size(); ++subpath_index) {
1167 key_debug += ".";
1168 key_debug += pa->subpath[subpath_index];
1169 }
1170 }
1171 ERR_PRINT("Failed setting key '" + key_debug +
1172 "' at time " + rtos(playback.current.pos) +
1173 " in Animation '" + get_current_animation() +
1174 "' at Node '" + get_path() +
1175 "', Track '" + String(pa->owner->path) +
1176 "'. Check if the property exists or the type of key is right for the property.");
1177 }
1178#endif
1179
1180 } break;
1181 case SP_NODE2D_POS: {
1182#ifdef DEBUG_ENABLED
1183 if (pa->value_accum.get_type() != Variant::VECTOR2) {
1184 ERR_PRINT("Position key at time " + rtos(playback.current.pos) + " in Animation '" + get_current_animation() + "' at Node '" + get_path() + "', Track '" + String(pa->owner->path) + "' not of type Vector2()");
1185 }
1186#endif
1187 static_cast<Node2D *>(pa->object)->set_position(pa->value_accum);
1188 } break;
1189 case SP_NODE2D_ROT: {
1190#ifdef DEBUG_ENABLED
1191 if (pa->value_accum.is_num()) {
1192 ERR_PRINT("Rotation key at time " + rtos(playback.current.pos) + " in Animation '" + get_current_animation() + "' at Node '" + get_path() + "', Track '" + String(pa->owner->path) + "' not numerical");
1193 }
1194#endif
1195
1196 static_cast<Node2D *>(pa->object)->set_rotation(Math::deg_to_rad((double)pa->value_accum));
1197 } break;
1198 case SP_NODE2D_SCALE: {
1199#ifdef DEBUG_ENABLED
1200 if (pa->value_accum.get_type() != Variant::VECTOR2) {
1201 ERR_PRINT("Scale key at time " + rtos(playback.current.pos) + " in Animation '" + get_current_animation() + "' at Node '" + get_path() + "', Track '" + String(pa->owner->path) + "' not of type Vector2()");
1202 }
1203#endif
1204
1205 static_cast<Node2D *>(pa->object)->set_scale(pa->value_accum);
1206 } break;
1207 }
1208 }
1209
1210 for (int i = 0; i < cache_update_bezier_size; i++) {
1211 TrackNodeCache::BezierAnim *ba = cache_update_bezier[i];
1212
1213 ERR_CONTINUE(ba->accum_pass != accum_pass);
1214 ba->object->set_indexed(ba->bezier_property, ba->bezier_accum);
1215 }
1216
1217 for (int i = 0; i < cache_update_audio_size; i++) {
1218 TrackNodeCache::AudioAnim *aa = cache_update_audio[i];
1219
1220 ERR_CONTINUE(aa->accum_pass != accum_pass);
1221
1222 // Audio ending process.
1223 LocalVector<int> erase_list;
1224 for (const KeyValue<int, TrackNodeCache::PlayingAudioStreamInfo> &K : aa->playing_streams) {
1225 TrackNodeCache::PlayingAudioStreamInfo pasi = K.value;
1226
1227 bool stop = false;
1228 if (!aa->audio_stream_playback->is_stream_playing(pasi.index)) {
1229 stop = true;
1230 }
1231 if (!aa->loop) {
1232 if (!aa->backward) {
1233 if (aa->time < pasi.start) {
1234 stop = true;
1235 }
1236 } else {
1237 if (aa->time > pasi.start) {
1238 stop = true;
1239 }
1240 }
1241 }
1242 if (pasi.len > 0) {
1243 double len = 0.0;
1244 if (!aa->backward) {
1245 len = pasi.start > aa->time ? (aa->length - pasi.start) + aa->time : aa->time - pasi.start;
1246 } else {
1247 len = pasi.start < aa->time ? (aa->length - aa->time) + pasi.start : pasi.start - aa->time;
1248 }
1249 if (len > pasi.len) {
1250 stop = true;
1251 }
1252 }
1253 if (stop) {
1254 // Time to stop.
1255 aa->audio_stream_playback->stop_stream(pasi.index);
1256 erase_list.push_back(K.key);
1257 }
1258 }
1259 for (uint32_t erase_idx = 0; erase_idx < erase_list.size(); erase_idx++) {
1260 aa->playing_streams.erase(erase_list[erase_idx]);
1261 }
1262 }
1263}
1264
1265void AnimationPlayer::_animation_process(double p_delta) {
1266 if (playback.current.from) {
1267 end_reached = false;
1268 end_notify = false;
1269
1270 bool started = playback.started; // The animation may be changed during process, so it is safer that the state is changed before process.
1271 if (playback.started) {
1272 playback.started = false;
1273 }
1274
1275 cache_update_size = 0;
1276 cache_update_prop_size = 0;
1277 cache_update_bezier_size = 0;
1278 cache_update_audio_size = 0;
1279
1280 AnimationData *prev_from = playback.current.from;
1281 _animation_process2(p_delta, started);
1282 if (prev_from != playback.current.from) {
1283 return; // Animation has been changed in the process (may be caused by method track), abort process.
1284 }
1285 _animation_update_transforms();
1286
1287 if (end_reached) {
1288 _clear_audio_streams();
1289 _stop_playing_caches(false);
1290 if (queued.size()) {
1291 String old = playback.assigned;
1292 play(queued.front()->get());
1293 String new_name = playback.assigned;
1294 queued.pop_front();
1295 if (end_notify) {
1296 emit_signal(SceneStringNames::get_singleton()->animation_changed, old, new_name);
1297 }
1298 } else {
1299 playing = false;
1300 _set_process(false);
1301 if (end_notify) {
1302 emit_signal(SceneStringNames::get_singleton()->animation_finished, playback.assigned);
1303
1304 if (movie_quit_on_finish && OS::get_singleton()->has_feature("movie")) {
1305 print_line(vformat("Movie Maker mode is enabled. Quitting on animation finish as requested by: %s", get_path()));
1306 get_tree()->quit();
1307 }
1308 }
1309 }
1310 end_reached = false;
1311 }
1312
1313 } else {
1314 _set_process(false);
1315 }
1316}
1317
1318void AnimationPlayer::_animation_set_cache_update() {
1319 // Relatively fast function to update all animations.
1320
1321 animation_set_update_pass++;
1322 bool clear_cache_needed = false;
1323
1324 // Update changed and add otherwise
1325 for (const AnimationLibraryData &lib : animation_libraries) {
1326 for (const KeyValue<StringName, Ref<Animation>> &K : lib.library->animations) {
1327 StringName key = lib.name == StringName() ? K.key : StringName(String(lib.name) + "/" + String(K.key));
1328 if (!animation_set.has(key)) {
1329 AnimationData ad;
1330 ad.animation = K.value;
1331 ad.animation_library = lib.name;
1332 ad.name = key;
1333 ad.last_update = animation_set_update_pass;
1334 animation_set.insert(ad.name, ad);
1335 } else {
1336 AnimationData &ad = animation_set[key];
1337 if (ad.last_update != animation_set_update_pass) {
1338 // Was not updated, update. If the animation is duplicated, the second one will be ignored.
1339 if (ad.animation != K.value || ad.animation_library != lib.name) {
1340 // Animation changed, update and clear caches.
1341 clear_cache_needed = true;
1342 ad.animation = K.value;
1343 ad.animation_library = lib.name;
1344 }
1345
1346 ad.last_update = animation_set_update_pass;
1347 }
1348 }
1349 }
1350 }
1351
1352 // Check removed
1353 List<StringName> to_erase;
1354 for (const KeyValue<StringName, AnimationData> &E : animation_set) {
1355 if (E.value.last_update != animation_set_update_pass) {
1356 // Was not updated, must be erased
1357 to_erase.push_back(E.key);
1358 clear_cache_needed = true;
1359 }
1360 }
1361
1362 while (to_erase.size()) {
1363 animation_set.erase(to_erase.front()->get());
1364 to_erase.pop_front();
1365 }
1366
1367 if (clear_cache_needed) {
1368 // If something was modified or removed, caches need to be cleared
1369 clear_caches();
1370 }
1371
1372 emit_signal(SNAME("animation_list_changed"));
1373}
1374
1375void AnimationPlayer::_animation_added(const StringName &p_name, const StringName &p_library) {
1376 _animation_set_cache_update();
1377}
1378
1379void AnimationPlayer::_animation_removed(const StringName &p_name, const StringName &p_library) {
1380 StringName name = p_library == StringName() ? p_name : StringName(String(p_library) + "/" + String(p_name));
1381
1382 if (!animation_set.has(name)) {
1383 return; // No need to update because not the one from the library being used.
1384 }
1385
1386 _animation_set_cache_update();
1387
1388 // Erase blends if needed
1389 List<BlendKey> to_erase;
1390 for (const KeyValue<BlendKey, double> &E : blend_times) {
1391 BlendKey bk = E.key;
1392 if (bk.from == name || bk.to == name) {
1393 to_erase.push_back(bk);
1394 }
1395 }
1396
1397 while (to_erase.size()) {
1398 blend_times.erase(to_erase.front()->get());
1399 to_erase.pop_front();
1400 }
1401}
1402
1403void AnimationPlayer::_rename_animation(const StringName &p_from_name, const StringName &p_to_name) {
1404 // Rename autoplay or blends if needed.
1405 List<BlendKey> to_erase;
1406 HashMap<BlendKey, double, BlendKey> to_insert;
1407 for (const KeyValue<BlendKey, double> &E : blend_times) {
1408 BlendKey bk = E.key;
1409 BlendKey new_bk = bk;
1410 bool erase = false;
1411 if (bk.from == p_from_name) {
1412 new_bk.from = p_to_name;
1413 erase = true;
1414 }
1415 if (bk.to == p_from_name) {
1416 new_bk.to = p_to_name;
1417 erase = true;
1418 }
1419
1420 if (erase) {
1421 to_erase.push_back(bk);
1422 to_insert[new_bk] = E.value;
1423 }
1424 }
1425
1426 while (to_erase.size()) {
1427 blend_times.erase(to_erase.front()->get());
1428 to_erase.pop_front();
1429 }
1430
1431 while (to_insert.size()) {
1432 blend_times[to_insert.begin()->key] = to_insert.begin()->value;
1433 to_insert.remove(to_insert.begin());
1434 }
1435
1436 if (autoplay == p_from_name) {
1437 autoplay = p_to_name;
1438 }
1439}
1440
1441void AnimationPlayer::_animation_renamed(const StringName &p_name, const StringName &p_to_name, const StringName &p_library) {
1442 StringName from_name = p_library == StringName() ? p_name : StringName(String(p_library) + "/" + String(p_name));
1443 StringName to_name = p_library == StringName() ? p_to_name : StringName(String(p_library) + "/" + String(p_to_name));
1444
1445 if (!animation_set.has(from_name)) {
1446 return; // No need to update because not the one from the library being used.
1447 }
1448 _animation_set_cache_update();
1449
1450 _rename_animation(from_name, to_name);
1451}
1452
1453Error AnimationPlayer::add_animation_library(const StringName &p_name, const Ref<AnimationLibrary> &p_animation_library) {
1454 ERR_FAIL_COND_V(p_animation_library.is_null(), ERR_INVALID_PARAMETER);
1455#ifdef DEBUG_ENABLED
1456 ERR_FAIL_COND_V_MSG(String(p_name).contains("/") || String(p_name).contains(":") || String(p_name).contains(",") || String(p_name).contains("["), ERR_INVALID_PARAMETER, "Invalid animation name: " + String(p_name) + ".");
1457#endif
1458
1459 int insert_pos = 0;
1460
1461 for (const AnimationLibraryData &lib : animation_libraries) {
1462 ERR_FAIL_COND_V_MSG(lib.name == p_name, ERR_ALREADY_EXISTS, "Can't add animation library twice with name: " + String(p_name));
1463 ERR_FAIL_COND_V_MSG(lib.library == p_animation_library, ERR_ALREADY_EXISTS, "Can't add animation library twice (adding as '" + p_name.operator String() + "', exists as '" + lib.name.operator String() + "'.");
1464
1465 if (lib.name.operator String() >= p_name.operator String()) {
1466 break;
1467 }
1468
1469 insert_pos++;
1470 }
1471
1472 AnimationLibraryData ald;
1473 ald.name = p_name;
1474 ald.library = p_animation_library;
1475
1476 animation_libraries.insert(insert_pos, ald);
1477
1478 ald.library->connect(SNAME("animation_added"), callable_mp(this, &AnimationPlayer::_animation_added).bind(p_name));
1479 ald.library->connect(SNAME("animation_removed"), callable_mp(this, &AnimationPlayer::_animation_removed).bind(p_name));
1480 ald.library->connect(SNAME("animation_renamed"), callable_mp(this, &AnimationPlayer::_animation_renamed).bind(p_name));
1481 ald.library->connect(SNAME("animation_changed"), callable_mp(this, &AnimationPlayer::_animation_changed));
1482
1483 _animation_set_cache_update();
1484
1485 notify_property_list_changed();
1486
1487 return OK;
1488}
1489
1490void AnimationPlayer::remove_animation_library(const StringName &p_name) {
1491 int at_pos = -1;
1492
1493 for (uint32_t i = 0; i < animation_libraries.size(); i++) {
1494 if (animation_libraries[i].name == p_name) {
1495 at_pos = i;
1496 break;
1497 }
1498 }
1499
1500 ERR_FAIL_COND(at_pos == -1);
1501
1502 animation_libraries[at_pos].library->disconnect(SNAME("animation_added"), callable_mp(this, &AnimationPlayer::_animation_added));
1503 animation_libraries[at_pos].library->disconnect(SNAME("animation_removed"), callable_mp(this, &AnimationPlayer::_animation_removed));
1504 animation_libraries[at_pos].library->disconnect(SNAME("animation_renamed"), callable_mp(this, &AnimationPlayer::_animation_renamed));
1505 animation_libraries[at_pos].library->disconnect(SNAME("animation_changed"), callable_mp(this, &AnimationPlayer::_animation_changed));
1506
1507 stop();
1508
1509 animation_libraries.remove_at(at_pos);
1510 _animation_set_cache_update();
1511
1512 notify_property_list_changed();
1513}
1514
1515void AnimationPlayer::rename_animation_library(const StringName &p_name, const StringName &p_new_name) {
1516 if (p_name == p_new_name) {
1517 return;
1518 }
1519#ifdef DEBUG_ENABLED
1520 ERR_FAIL_COND_MSG(String(p_new_name).contains("/") || String(p_new_name).contains(":") || String(p_new_name).contains(",") || String(p_new_name).contains("["), "Invalid animation library name: " + String(p_new_name) + ".");
1521#endif
1522
1523 bool found = false;
1524 for (AnimationLibraryData &lib : animation_libraries) {
1525 ERR_FAIL_COND_MSG(lib.name == p_new_name, "Can't rename animation library to another existing name: " + String(p_new_name));
1526 if (lib.name == p_name) {
1527 found = true;
1528 lib.name = p_new_name;
1529 // rename connections
1530 lib.library->disconnect(SNAME("animation_added"), callable_mp(this, &AnimationPlayer::_animation_added));
1531 lib.library->disconnect(SNAME("animation_removed"), callable_mp(this, &AnimationPlayer::_animation_removed));
1532 lib.library->disconnect(SNAME("animation_renamed"), callable_mp(this, &AnimationPlayer::_animation_renamed));
1533
1534 lib.library->connect(SNAME("animation_added"), callable_mp(this, &AnimationPlayer::_animation_added).bind(p_new_name));
1535 lib.library->connect(SNAME("animation_removed"), callable_mp(this, &AnimationPlayer::_animation_removed).bind(p_new_name));
1536 lib.library->connect(SNAME("animation_renamed"), callable_mp(this, &AnimationPlayer::_animation_renamed).bind(p_new_name));
1537
1538 for (const KeyValue<StringName, Ref<Animation>> &K : lib.library->animations) {
1539 StringName old_name = p_name == StringName() ? K.key : StringName(String(p_name) + "/" + String(K.key));
1540 StringName new_name = p_new_name == StringName() ? K.key : StringName(String(p_new_name) + "/" + String(K.key));
1541 _rename_animation(old_name, new_name);
1542 }
1543 }
1544 }
1545
1546 ERR_FAIL_COND(!found);
1547
1548 stop();
1549
1550 animation_libraries.sort(); // Must keep alphabetical order.
1551
1552 _animation_set_cache_update(); // Update cache.
1553
1554 notify_property_list_changed();
1555}
1556
1557bool AnimationPlayer::has_animation_library(const StringName &p_name) const {
1558 for (const AnimationLibraryData &lib : animation_libraries) {
1559 if (lib.name == p_name) {
1560 return true;
1561 }
1562 }
1563
1564 return false;
1565}
1566
1567Ref<AnimationLibrary> AnimationPlayer::get_animation_library(const StringName &p_name) const {
1568 for (const AnimationLibraryData &lib : animation_libraries) {
1569 if (lib.name == p_name) {
1570 return lib.library;
1571 }
1572 }
1573 ERR_FAIL_V(Ref<AnimationLibrary>());
1574}
1575
1576TypedArray<StringName> AnimationPlayer::_get_animation_library_list() const {
1577 TypedArray<StringName> ret;
1578 for (const AnimationLibraryData &lib : animation_libraries) {
1579 ret.push_back(lib.name);
1580 }
1581 return ret;
1582}
1583
1584void AnimationPlayer::get_animation_library_list(List<StringName> *p_libraries) const {
1585 for (const AnimationLibraryData &lib : animation_libraries) {
1586 p_libraries->push_back(lib.name);
1587 }
1588}
1589
1590bool AnimationPlayer::has_animation(const StringName &p_name) const {
1591 return animation_set.has(p_name);
1592}
1593
1594Ref<Animation> AnimationPlayer::get_animation(const StringName &p_name) const {
1595 ERR_FAIL_COND_V_MSG(!animation_set.has(p_name), Ref<Animation>(), vformat("Animation not found: \"%s\".", p_name));
1596
1597 const AnimationData &anim_data = animation_set[p_name];
1598
1599 return anim_data.animation;
1600}
1601
1602void AnimationPlayer::get_animation_list(List<StringName> *p_animations) const {
1603 List<String> anims;
1604
1605 for (const KeyValue<StringName, AnimationData> &E : animation_set) {
1606 anims.push_back(E.key);
1607 }
1608
1609 anims.sort();
1610
1611 for (const String &E : anims) {
1612 p_animations->push_back(E);
1613 }
1614}
1615
1616void AnimationPlayer::set_blend_time(const StringName &p_animation1, const StringName &p_animation2, double p_time) {
1617 ERR_FAIL_COND_MSG(!animation_set.has(p_animation1), vformat("Animation not found: %s.", p_animation1));
1618 ERR_FAIL_COND_MSG(!animation_set.has(p_animation2), vformat("Animation not found: %s.", p_animation2));
1619 ERR_FAIL_COND_MSG(p_time < 0, "Blend time cannot be smaller than 0.");
1620
1621 BlendKey bk;
1622 bk.from = p_animation1;
1623 bk.to = p_animation2;
1624 if (p_time == 0) {
1625 blend_times.erase(bk);
1626 } else {
1627 blend_times[bk] = p_time;
1628 }
1629}
1630
1631double AnimationPlayer::get_blend_time(const StringName &p_animation1, const StringName &p_animation2) const {
1632 BlendKey bk;
1633 bk.from = p_animation1;
1634 bk.to = p_animation2;
1635
1636 if (blend_times.has(bk)) {
1637 return blend_times[bk];
1638 } else {
1639 return 0;
1640 }
1641}
1642
1643void AnimationPlayer::queue(const StringName &p_name) {
1644 if (!is_playing()) {
1645 play(p_name);
1646 } else {
1647 queued.push_back(p_name);
1648 }
1649}
1650
1651Vector<String> AnimationPlayer::get_queue() {
1652 Vector<String> ret;
1653 for (const StringName &E : queued) {
1654 ret.push_back(E);
1655 }
1656
1657 return ret;
1658}
1659
1660void AnimationPlayer::clear_queue() {
1661 queued.clear();
1662}
1663
1664void AnimationPlayer::play_backwards(const StringName &p_name, double p_custom_blend) {
1665 play(p_name, p_custom_blend, -1, true);
1666}
1667
1668void AnimationPlayer::play(const StringName &p_name, double p_custom_blend, float p_custom_scale, bool p_from_end) {
1669 StringName name = p_name;
1670
1671 if (String(name) == "") {
1672 name = playback.assigned;
1673 }
1674
1675 ERR_FAIL_COND_MSG(!animation_set.has(name), vformat("Animation not found: %s.", name));
1676
1677 Playback &c = playback;
1678
1679 if (c.current.from) {
1680 double blend_time = 0.0;
1681 // find if it can blend
1682 BlendKey bk;
1683 bk.from = c.current.from->name;
1684 bk.to = name;
1685
1686 if (p_custom_blend >= 0) {
1687 blend_time = p_custom_blend;
1688 } else if (blend_times.has(bk)) {
1689 blend_time = blend_times[bk];
1690 } else {
1691 bk.from = "*";
1692 if (blend_times.has(bk)) {
1693 blend_time = blend_times[bk];
1694 } else {
1695 bk.from = c.current.from->name;
1696 bk.to = "*";
1697
1698 if (blend_times.has(bk)) {
1699 blend_time = blend_times[bk];
1700 }
1701 }
1702 }
1703
1704 if (p_custom_blend < 0 && blend_time == 0 && default_blend_time) {
1705 blend_time = default_blend_time;
1706 }
1707 if (blend_time > 0) {
1708 Blend b;
1709 b.data = c.current;
1710 b.blend_time = b.blend_left = blend_time;
1711 c.blend.push_back(b);
1712 } else {
1713 c.blend.clear();
1714 }
1715 }
1716
1717 if (get_current_animation() != p_name) {
1718 _clear_audio_streams();
1719 _stop_playing_caches(false);
1720 }
1721
1722 c.current.from = &animation_set[name];
1723
1724 if (c.assigned != name) { // reset
1725 c.current.pos = p_from_end ? c.current.from->animation->get_length() : 0;
1726 } else {
1727 if (p_from_end && c.current.pos == 0) {
1728 // Animation reset BUT played backwards, set position to the end
1729 c.current.pos = c.current.from->animation->get_length();
1730 } else if (!p_from_end && c.current.pos == c.current.from->animation->get_length()) {
1731 // Animation resumed but already ended, set position to the beginning
1732 c.current.pos = 0;
1733 }
1734 }
1735
1736 c.current.speed_scale = p_custom_scale;
1737 c.assigned = name;
1738 c.seeked = false;
1739 c.started = true;
1740
1741 if (!end_reached) {
1742 queued.clear();
1743 }
1744 _set_process(true); // always process when starting an animation
1745 playing = true;
1746
1747 emit_signal(SceneStringNames::get_singleton()->animation_started, c.assigned);
1748
1749 if (is_inside_tree() && Engine::get_singleton()->is_editor_hint()) {
1750 return; // no next in this case
1751 }
1752
1753 StringName next = animation_get_next(p_name);
1754 if (next != StringName() && animation_set.has(next)) {
1755 queue(next);
1756 }
1757}
1758
1759bool AnimationPlayer::is_playing() const {
1760 return playing;
1761}
1762
1763void AnimationPlayer::set_current_animation(const String &p_anim) {
1764 if (p_anim == "[stop]" || p_anim.is_empty()) {
1765 stop();
1766 } else if (!is_playing()) {
1767 play(p_anim);
1768 } else if (playback.assigned != p_anim) {
1769 float speed = playback.current.speed_scale;
1770 play(p_anim, -1.0, speed, signbit(speed));
1771 } else {
1772 // Same animation, do not replay from start
1773 }
1774}
1775
1776String AnimationPlayer::get_current_animation() const {
1777 return (is_playing() ? playback.assigned : "");
1778}
1779
1780void AnimationPlayer::set_assigned_animation(const String &p_anim) {
1781 if (is_playing()) {
1782 float speed = playback.current.speed_scale;
1783 play(p_anim, -1.0, speed, signbit(speed));
1784 } else {
1785 ERR_FAIL_COND_MSG(!animation_set.has(p_anim), vformat("Animation not found: %s.", p_anim));
1786 playback.current.pos = 0;
1787 playback.current.from = &animation_set[p_anim];
1788 playback.assigned = p_anim;
1789 }
1790}
1791
1792String AnimationPlayer::get_assigned_animation() const {
1793 return playback.assigned;
1794}
1795
1796void AnimationPlayer::pause() {
1797 _stop_internal(false, false);
1798}
1799
1800void AnimationPlayer::stop(bool p_keep_state) {
1801 _stop_internal(true, p_keep_state);
1802}
1803
1804void AnimationPlayer::set_speed_scale(float p_speed) {
1805 speed_scale = p_speed;
1806}
1807
1808float AnimationPlayer::get_speed_scale() const {
1809 return speed_scale;
1810}
1811
1812float AnimationPlayer::get_playing_speed() const {
1813 if (!playing) {
1814 return 0;
1815 }
1816 return speed_scale * playback.current.speed_scale;
1817}
1818
1819void AnimationPlayer::seek(double p_time, bool p_update) {
1820 playback.current.pos = p_time;
1821
1822 if (!playback.current.from) {
1823 if (playback.assigned) {
1824 ERR_FAIL_COND_MSG(!animation_set.has(playback.assigned), vformat("Animation not found: %s.", playback.assigned));
1825 playback.current.from = &animation_set[playback.assigned];
1826 }
1827 if (!playback.current.from) {
1828 return; // There is no animation.
1829 }
1830 }
1831
1832 playback.seeked = true;
1833 if (p_update) {
1834 _animation_process(0);
1835 }
1836}
1837
1838void AnimationPlayer::seek_delta(double p_time, double p_delta) {
1839 playback.current.pos = p_time - p_delta;
1840
1841 if (!playback.current.from) {
1842 if (playback.assigned) {
1843 ERR_FAIL_COND_MSG(!animation_set.has(playback.assigned), vformat("Animation not found: %s.", playback.assigned));
1844 playback.current.from = &animation_set[playback.assigned];
1845 }
1846 if (!playback.current.from) {
1847 return; // There is no animation.
1848 }
1849 }
1850
1851 if (speed_scale != 0.0) {
1852 p_delta /= speed_scale;
1853 }
1854 _animation_process(p_delta);
1855}
1856
1857bool AnimationPlayer::is_valid() const {
1858 return (playback.current.from);
1859}
1860
1861double AnimationPlayer::get_current_animation_position() const {
1862 ERR_FAIL_COND_V_MSG(!playback.current.from, 0, "AnimationPlayer has no current animation");
1863 return playback.current.pos;
1864}
1865
1866double AnimationPlayer::get_current_animation_length() const {
1867 ERR_FAIL_COND_V_MSG(!playback.current.from, 0, "AnimationPlayer has no current animation");
1868 return playback.current.from->animation->get_length();
1869}
1870
1871void AnimationPlayer::_animation_changed(const StringName &p_name) {
1872 clear_caches();
1873 if (is_playing()) {
1874 playback.seeked = true; //need to restart stuff, like audio
1875 }
1876}
1877
1878void AnimationPlayer::_stop_playing_caches(bool p_reset) {
1879 for (TrackNodeCache *E : playing_caches) {
1880 if (E->node && E->audio_playing) {
1881 E->node->call(SNAME("stop"));
1882 }
1883 if (E->node && E->animation_playing) {
1884 AnimationPlayer *player = Object::cast_to<AnimationPlayer>(E->node);
1885 if (!player) {
1886 continue;
1887 }
1888
1889 if (p_reset) {
1890 player->stop();
1891 } else {
1892 player->pause();
1893 }
1894 }
1895 }
1896
1897 playing_caches.clear();
1898}
1899
1900void AnimationPlayer::_node_removed(Node *p_node) {
1901 clear_caches(); // nodes contained here are being removed, clear the caches
1902}
1903
1904void AnimationPlayer::clear_caches() {
1905 _clear_audio_streams();
1906 _stop_playing_caches(true);
1907
1908 node_cache_map.clear();
1909
1910 for (KeyValue<StringName, AnimationData> &E : animation_set) {
1911 E.value.node_cache.clear();
1912 }
1913
1914 cache_update_size = 0;
1915 cache_update_prop_size = 0;
1916 cache_update_bezier_size = 0;
1917 cache_update_audio_size = 0;
1918
1919 emit_signal(SNAME("caches_cleared"));
1920}
1921
1922void AnimationPlayer::_clear_audio_streams() {
1923 for (int i = 0; i < playing_audio_stream_players.size(); i++) {
1924 playing_audio_stream_players[i]->call(SNAME("stop"));
1925 playing_audio_stream_players[i]->call(SNAME("set_stream"), Ref<AudioStream>());
1926 }
1927 playing_audio_stream_players.clear();
1928}
1929
1930void AnimationPlayer::set_active(bool p_active) {
1931 if (active == p_active) {
1932 return;
1933 }
1934
1935 active = p_active;
1936 _set_process(processing, true);
1937}
1938
1939bool AnimationPlayer::is_active() const {
1940 return active;
1941}
1942
1943StringName AnimationPlayer::find_animation(const Ref<Animation> &p_animation) const {
1944 for (const KeyValue<StringName, AnimationData> &E : animation_set) {
1945 if (E.value.animation == p_animation) {
1946 return E.key;
1947 }
1948 }
1949
1950 return StringName();
1951}
1952
1953StringName AnimationPlayer::find_animation_library(const Ref<Animation> &p_animation) const {
1954 for (const KeyValue<StringName, AnimationData> &E : animation_set) {
1955 if (E.value.animation == p_animation) {
1956 return E.value.animation_library;
1957 }
1958 }
1959 return StringName();
1960}
1961
1962void AnimationPlayer::set_autoplay(const String &p_name) {
1963 if (is_inside_tree() && !Engine::get_singleton()->is_editor_hint()) {
1964 WARN_PRINT("Setting autoplay after the node has been added to the scene has no effect.");
1965 }
1966
1967 autoplay = p_name;
1968}
1969
1970String AnimationPlayer::get_autoplay() const {
1971 return autoplay;
1972}
1973
1974void AnimationPlayer::set_reset_on_save_enabled(bool p_enabled) {
1975 reset_on_save = p_enabled;
1976}
1977
1978bool AnimationPlayer::is_reset_on_save_enabled() const {
1979 return reset_on_save;
1980}
1981
1982void AnimationPlayer::set_process_callback(AnimationProcessCallback p_mode) {
1983 if (process_callback == p_mode) {
1984 return;
1985 }
1986
1987 bool pr = processing;
1988 if (pr) {
1989 _set_process(false);
1990 }
1991 process_callback = p_mode;
1992 if (pr) {
1993 _set_process(true);
1994 }
1995}
1996
1997AnimationPlayer::AnimationProcessCallback AnimationPlayer::get_process_callback() const {
1998 return process_callback;
1999}
2000
2001void AnimationPlayer::set_method_call_mode(AnimationMethodCallMode p_mode) {
2002 method_call_mode = p_mode;
2003}
2004
2005AnimationPlayer::AnimationMethodCallMode AnimationPlayer::get_method_call_mode() const {
2006 return method_call_mode;
2007}
2008
2009void AnimationPlayer::set_audio_max_polyphony(int p_audio_max_polyphony) {
2010 ERR_FAIL_COND(p_audio_max_polyphony < 0 || p_audio_max_polyphony > 128);
2011 audio_max_polyphony = p_audio_max_polyphony;
2012}
2013
2014int AnimationPlayer::get_audio_max_polyphony() const {
2015 return audio_max_polyphony;
2016}
2017
2018void AnimationPlayer::set_movie_quit_on_finish_enabled(bool p_enabled) {
2019 movie_quit_on_finish = p_enabled;
2020}
2021
2022bool AnimationPlayer::is_movie_quit_on_finish_enabled() const {
2023 return movie_quit_on_finish;
2024}
2025
2026void AnimationPlayer::_set_process(bool p_process, bool p_force) {
2027 if (processing == p_process && !p_force) {
2028 return;
2029 }
2030
2031 switch (process_callback) {
2032 case ANIMATION_PROCESS_PHYSICS:
2033 set_physics_process_internal(p_process && active);
2034 break;
2035 case ANIMATION_PROCESS_IDLE:
2036 set_process_internal(p_process && active);
2037 break;
2038 case ANIMATION_PROCESS_MANUAL:
2039 break;
2040 }
2041
2042 processing = p_process;
2043}
2044
2045void AnimationPlayer::_stop_internal(bool p_reset, bool p_keep_state) {
2046 _clear_audio_streams();
2047 _stop_playing_caches(p_reset);
2048 Playback &c = playback;
2049 c.blend.clear();
2050 if (p_reset) {
2051 if (p_keep_state) {
2052 c.current.pos = 0;
2053 } else {
2054 is_stopping = true;
2055 seek(0, true);
2056 is_stopping = false;
2057 }
2058 c.current.from = nullptr;
2059 c.current.speed_scale = 1;
2060 }
2061 _set_process(false);
2062 queued.clear();
2063 playing = false;
2064}
2065
2066void AnimationPlayer::animation_set_next(const StringName &p_animation, const StringName &p_next) {
2067 ERR_FAIL_COND_MSG(!animation_set.has(p_animation), vformat("Animation not found: %s.", p_animation));
2068 animation_set[p_animation].next = p_next;
2069}
2070
2071StringName AnimationPlayer::animation_get_next(const StringName &p_animation) const {
2072 if (!animation_set.has(p_animation)) {
2073 return StringName();
2074 }
2075 return animation_set[p_animation].next;
2076}
2077
2078void AnimationPlayer::set_default_blend_time(double p_default) {
2079 default_blend_time = p_default;
2080}
2081
2082double AnimationPlayer::get_default_blend_time() const {
2083 return default_blend_time;
2084}
2085
2086void AnimationPlayer::set_root(const NodePath &p_root) {
2087 root = p_root;
2088 clear_caches();
2089}
2090
2091NodePath AnimationPlayer::get_root() const {
2092 return root;
2093}
2094
2095void AnimationPlayer::get_argument_options(const StringName &p_function, int p_idx, List<String> *r_options) const {
2096 String pf = p_function;
2097 if (p_idx == 0 && (p_function == "play" || p_function == "play_backwards" || p_function == "has_animation" || p_function == "queue")) {
2098 List<StringName> al;
2099 get_animation_list(&al);
2100 for (const StringName &name : al) {
2101 r_options->push_back(String(name).quote());
2102 }
2103 }
2104 Node::get_argument_options(p_function, p_idx, r_options);
2105}
2106
2107#ifdef TOOLS_ENABLED
2108Ref<AnimatedValuesBackup> AnimationPlayer::backup_animated_values(Node *p_root_override) {
2109 Ref<AnimatedValuesBackup> backup;
2110 if (!playback.current.from) {
2111 return backup;
2112 }
2113
2114 _ensure_node_caches(playback.current.from, p_root_override);
2115
2116 backup.instantiate();
2117 for (int i = 0; i < playback.current.from->node_cache.size(); i++) {
2118 TrackNodeCache *nc = playback.current.from->node_cache[i];
2119 if (!nc) {
2120 continue;
2121 }
2122
2123 if (nc->skeleton) {
2124 if (nc->bone_idx == -1) {
2125 continue;
2126 }
2127
2128 AnimatedValuesBackup::Entry entry;
2129 entry.object = nc->skeleton;
2130 entry.bone_idx = nc->bone_idx;
2131 Array arr;
2132 arr.resize(3);
2133 arr[0] = nc->skeleton->get_bone_pose_position(nc->bone_idx);
2134 arr[1] = nc->skeleton->get_bone_pose_rotation(nc->bone_idx);
2135 arr[2] = nc->skeleton->get_bone_pose_scale(nc->bone_idx);
2136 entry.value = nc;
2137 backup->entries.push_back(entry);
2138 } else {
2139 if (nc->node_3d) {
2140 AnimatedValuesBackup::Entry entry;
2141 entry.object = nc->node_3d;
2142 entry.subpath.push_back("transform");
2143 entry.value = nc->node_3d->get_transform();
2144 entry.bone_idx = -1;
2145 backup->entries.push_back(entry);
2146 } else {
2147 for (const KeyValue<StringName, TrackNodeCache::PropertyAnim> &E : nc->property_anim) {
2148 AnimatedValuesBackup::Entry entry;
2149 entry.object = E.value.object;
2150 entry.subpath = E.value.subpath;
2151 bool valid;
2152 entry.value = E.value.object->get_indexed(E.value.subpath, &valid);
2153 entry.bone_idx = -1;
2154 if (valid) {
2155 backup->entries.push_back(entry);
2156 }
2157 }
2158 }
2159 }
2160 }
2161
2162 return backup;
2163}
2164
2165Ref<AnimatedValuesBackup> AnimationPlayer::apply_reset(bool p_user_initiated) {
2166 ERR_FAIL_COND_V(!can_apply_reset(), Ref<AnimatedValuesBackup>());
2167
2168 Ref<Animation> reset_anim = animation_set[SceneStringNames::get_singleton()->RESET].animation;
2169 ERR_FAIL_COND_V(reset_anim.is_null(), Ref<AnimatedValuesBackup>());
2170
2171 Node *root_node = get_node_or_null(root);
2172 ERR_FAIL_NULL_V(root_node, Ref<AnimatedValuesBackup>());
2173
2174 AnimationPlayer *aux_player = memnew(AnimationPlayer);
2175 EditorNode::get_singleton()->add_child(aux_player);
2176 Ref<AnimationLibrary> al;
2177 al.instantiate();
2178 al->add_animation(SceneStringNames::get_singleton()->RESET, reset_anim);
2179 aux_player->add_animation_library("", al);
2180 aux_player->set_assigned_animation(SceneStringNames::get_singleton()->RESET);
2181 // Forcing the use of the original root because the scene where original player belongs may be not the active one
2182 Ref<AnimatedValuesBackup> old_values = aux_player->backup_animated_values(get_node(get_root()));
2183 aux_player->seek(0.0f, true);
2184 aux_player->queue_free();
2185
2186 if (p_user_initiated) {
2187 Ref<AnimatedValuesBackup> new_values = aux_player->backup_animated_values();
2188 old_values->restore();
2189
2190 EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
2191 ur->create_action(TTR("Animation Apply Reset"));
2192 ur->add_do_method(new_values.ptr(), "restore");
2193 ur->add_undo_method(old_values.ptr(), "restore");
2194 ur->commit_action();
2195 }
2196
2197 return old_values;
2198}
2199
2200bool AnimationPlayer::can_apply_reset() const {
2201 return has_animation(SceneStringNames::get_singleton()->RESET) && playback.assigned != SceneStringNames::get_singleton()->RESET;
2202}
2203#endif // TOOLS_ENABLED
2204
2205void AnimationPlayer::_bind_methods() {
2206 ClassDB::bind_method(D_METHOD("add_animation_library", "name", "library"), &AnimationPlayer::add_animation_library);
2207 ClassDB::bind_method(D_METHOD("remove_animation_library", "name"), &AnimationPlayer::remove_animation_library);
2208 ClassDB::bind_method(D_METHOD("rename_animation_library", "name", "newname"), &AnimationPlayer::rename_animation_library);
2209 ClassDB::bind_method(D_METHOD("has_animation_library", "name"), &AnimationPlayer::has_animation_library);
2210 ClassDB::bind_method(D_METHOD("get_animation_library", "name"), &AnimationPlayer::get_animation_library);
2211 ClassDB::bind_method(D_METHOD("get_animation_library_list"), &AnimationPlayer::_get_animation_library_list);
2212
2213 ClassDB::bind_method(D_METHOD("has_animation", "name"), &AnimationPlayer::has_animation);
2214 ClassDB::bind_method(D_METHOD("get_animation", "name"), &AnimationPlayer::get_animation);
2215 ClassDB::bind_method(D_METHOD("get_animation_list"), &AnimationPlayer::_get_animation_list);
2216
2217 ClassDB::bind_method(D_METHOD("animation_set_next", "anim_from", "anim_to"), &AnimationPlayer::animation_set_next);
2218 ClassDB::bind_method(D_METHOD("animation_get_next", "anim_from"), &AnimationPlayer::animation_get_next);
2219
2220 ClassDB::bind_method(D_METHOD("set_blend_time", "anim_from", "anim_to", "sec"), &AnimationPlayer::set_blend_time);
2221 ClassDB::bind_method(D_METHOD("get_blend_time", "anim_from", "anim_to"), &AnimationPlayer::get_blend_time);
2222
2223 ClassDB::bind_method(D_METHOD("set_default_blend_time", "sec"), &AnimationPlayer::set_default_blend_time);
2224 ClassDB::bind_method(D_METHOD("get_default_blend_time"), &AnimationPlayer::get_default_blend_time);
2225
2226 ClassDB::bind_method(D_METHOD("play", "name", "custom_blend", "custom_speed", "from_end"), &AnimationPlayer::play, DEFVAL(""), DEFVAL(-1), DEFVAL(1.0), DEFVAL(false));
2227 ClassDB::bind_method(D_METHOD("play_backwards", "name", "custom_blend"), &AnimationPlayer::play_backwards, DEFVAL(""), DEFVAL(-1));
2228 ClassDB::bind_method(D_METHOD("pause"), &AnimationPlayer::pause);
2229 ClassDB::bind_method(D_METHOD("stop", "keep_state"), &AnimationPlayer::stop, DEFVAL(false));
2230 ClassDB::bind_method(D_METHOD("is_playing"), &AnimationPlayer::is_playing);
2231
2232 ClassDB::bind_method(D_METHOD("set_current_animation", "anim"), &AnimationPlayer::set_current_animation);
2233 ClassDB::bind_method(D_METHOD("get_current_animation"), &AnimationPlayer::get_current_animation);
2234 ClassDB::bind_method(D_METHOD("set_assigned_animation", "anim"), &AnimationPlayer::set_assigned_animation);
2235 ClassDB::bind_method(D_METHOD("get_assigned_animation"), &AnimationPlayer::get_assigned_animation);
2236 ClassDB::bind_method(D_METHOD("queue", "name"), &AnimationPlayer::queue);
2237 ClassDB::bind_method(D_METHOD("get_queue"), &AnimationPlayer::get_queue);
2238 ClassDB::bind_method(D_METHOD("clear_queue"), &AnimationPlayer::clear_queue);
2239
2240 ClassDB::bind_method(D_METHOD("set_active", "active"), &AnimationPlayer::set_active);
2241 ClassDB::bind_method(D_METHOD("is_active"), &AnimationPlayer::is_active);
2242
2243 ClassDB::bind_method(D_METHOD("set_speed_scale", "speed"), &AnimationPlayer::set_speed_scale);
2244 ClassDB::bind_method(D_METHOD("get_speed_scale"), &AnimationPlayer::get_speed_scale);
2245 ClassDB::bind_method(D_METHOD("get_playing_speed"), &AnimationPlayer::get_playing_speed);
2246
2247 ClassDB::bind_method(D_METHOD("set_autoplay", "name"), &AnimationPlayer::set_autoplay);
2248 ClassDB::bind_method(D_METHOD("get_autoplay"), &AnimationPlayer::get_autoplay);
2249
2250 ClassDB::bind_method(D_METHOD("set_reset_on_save_enabled", "enabled"), &AnimationPlayer::set_reset_on_save_enabled);
2251 ClassDB::bind_method(D_METHOD("is_reset_on_save_enabled"), &AnimationPlayer::is_reset_on_save_enabled);
2252
2253 ClassDB::bind_method(D_METHOD("set_root", "path"), &AnimationPlayer::set_root);
2254 ClassDB::bind_method(D_METHOD("get_root"), &AnimationPlayer::get_root);
2255
2256 ClassDB::bind_method(D_METHOD("find_animation", "animation"), &AnimationPlayer::find_animation);
2257 ClassDB::bind_method(D_METHOD("find_animation_library", "animation"), &AnimationPlayer::find_animation_library);
2258
2259 ClassDB::bind_method(D_METHOD("clear_caches"), &AnimationPlayer::clear_caches);
2260
2261 ClassDB::bind_method(D_METHOD("set_process_callback", "mode"), &AnimationPlayer::set_process_callback);
2262 ClassDB::bind_method(D_METHOD("get_process_callback"), &AnimationPlayer::get_process_callback);
2263
2264 ClassDB::bind_method(D_METHOD("set_method_call_mode", "mode"), &AnimationPlayer::set_method_call_mode);
2265 ClassDB::bind_method(D_METHOD("get_method_call_mode"), &AnimationPlayer::get_method_call_mode);
2266
2267 ClassDB::bind_method(D_METHOD("set_audio_max_polyphony", "max_polyphony"), &AnimationPlayer::set_audio_max_polyphony);
2268 ClassDB::bind_method(D_METHOD("get_audio_max_polyphony"), &AnimationPlayer::get_audio_max_polyphony);
2269
2270 ClassDB::bind_method(D_METHOD("set_movie_quit_on_finish_enabled", "enabled"), &AnimationPlayer::set_movie_quit_on_finish_enabled);
2271 ClassDB::bind_method(D_METHOD("is_movie_quit_on_finish_enabled"), &AnimationPlayer::is_movie_quit_on_finish_enabled);
2272
2273 ClassDB::bind_method(D_METHOD("get_current_animation_position"), &AnimationPlayer::get_current_animation_position);
2274 ClassDB::bind_method(D_METHOD("get_current_animation_length"), &AnimationPlayer::get_current_animation_length);
2275
2276 ClassDB::bind_method(D_METHOD("seek", "seconds", "update"), &AnimationPlayer::seek, DEFVAL(false));
2277 ClassDB::bind_method(D_METHOD("advance", "delta"), &AnimationPlayer::advance);
2278
2279 GDVIRTUAL_BIND(_post_process_key_value, "animation", "track", "value", "object", "object_idx");
2280
2281 ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "root_node"), "set_root", "get_root");
2282 ADD_PROPERTY(PropertyInfo(Variant::STRING_NAME, "current_animation", PROPERTY_HINT_ENUM, "", PROPERTY_USAGE_EDITOR), "set_current_animation", "get_current_animation");
2283 ADD_PROPERTY(PropertyInfo(Variant::STRING_NAME, "assigned_animation", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE), "set_assigned_animation", "get_assigned_animation");
2284 ADD_PROPERTY(PropertyInfo(Variant::STRING_NAME, "autoplay", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), "set_autoplay", "get_autoplay");
2285 ADD_PROPERTY(PropertyInfo(Variant::BOOL, "reset_on_save", PROPERTY_HINT_NONE, ""), "set_reset_on_save_enabled", "is_reset_on_save_enabled");
2286 ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "current_animation_length", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE), "", "get_current_animation_length");
2287 ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "current_animation_position", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE), "", "get_current_animation_position");
2288
2289 ADD_GROUP("Playback Options", "playback_");
2290 ADD_PROPERTY(PropertyInfo(Variant::INT, "playback_process_mode", PROPERTY_HINT_ENUM, "Physics,Idle,Manual"), "set_process_callback", "get_process_callback");
2291 ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "playback_default_blend_time", PROPERTY_HINT_RANGE, "0,4096,0.01,suffix:s"), "set_default_blend_time", "get_default_blend_time");
2292 ADD_PROPERTY(PropertyInfo(Variant::BOOL, "playback_active", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE), "set_active", "is_active");
2293 ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "speed_scale", PROPERTY_HINT_RANGE, "-64,64,0.01"), "set_speed_scale", "get_speed_scale");
2294 ADD_PROPERTY(PropertyInfo(Variant::INT, "method_call_mode", PROPERTY_HINT_ENUM, "Deferred,Immediate"), "set_method_call_mode", "get_method_call_mode");
2295 ADD_PROPERTY(PropertyInfo(Variant::INT, "audio_max_polyphony", PROPERTY_HINT_RANGE, "1,127,1"), "set_audio_max_polyphony", "get_audio_max_polyphony");
2296
2297 ADD_PROPERTY(PropertyInfo(Variant::BOOL, "movie_quit_on_finish"), "set_movie_quit_on_finish_enabled", "is_movie_quit_on_finish_enabled");
2298
2299 ADD_SIGNAL(MethodInfo("animation_finished", PropertyInfo(Variant::STRING_NAME, "anim_name")));
2300 ADD_SIGNAL(MethodInfo("animation_changed", PropertyInfo(Variant::STRING_NAME, "old_name"), PropertyInfo(Variant::STRING_NAME, "new_name")));
2301 ADD_SIGNAL(MethodInfo("animation_started", PropertyInfo(Variant::STRING_NAME, "anim_name")));
2302 ADD_SIGNAL(MethodInfo("animation_list_changed"));
2303 ADD_SIGNAL(MethodInfo("animation_libraries_updated"));
2304 ADD_SIGNAL(MethodInfo("caches_cleared"));
2305
2306 BIND_ENUM_CONSTANT(ANIMATION_PROCESS_PHYSICS);
2307 BIND_ENUM_CONSTANT(ANIMATION_PROCESS_IDLE);
2308 BIND_ENUM_CONSTANT(ANIMATION_PROCESS_MANUAL);
2309
2310 BIND_ENUM_CONSTANT(ANIMATION_METHOD_CALL_DEFERRED);
2311 BIND_ENUM_CONSTANT(ANIMATION_METHOD_CALL_IMMEDIATE);
2312}
2313
2314AnimationPlayer::AnimationPlayer() {
2315 root = SceneStringNames::get_singleton()->path_pp;
2316}
2317
2318AnimationPlayer::~AnimationPlayer() {
2319}
2320