Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
godotengine
GitHub Repository: godotengine/godot
Path: blob/master/scene/animation/animation_blend_tree.cpp
20956 views
1
/**************************************************************************/
2
/* animation_blend_tree.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_blend_tree.h"
32
33
#include "scene/resources/animation.h"
34
35
void AnimationNodeAnimation::set_animation(const StringName &p_name) {
36
animation = p_name;
37
}
38
39
StringName AnimationNodeAnimation::get_animation() const {
40
return animation;
41
}
42
43
Vector<String> (*AnimationNodeAnimation::get_editable_animation_list)() = nullptr;
44
45
void AnimationNodeAnimation::get_parameter_list(List<PropertyInfo> *r_list) const {
46
AnimationNode::get_parameter_list(r_list);
47
r_list->push_back(PropertyInfo(Variant::BOOL, backward, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE));
48
}
49
50
Variant AnimationNodeAnimation::get_parameter_default_value(const StringName &p_parameter) const {
51
Variant ret = AnimationNode::get_parameter_default_value(p_parameter);
52
if (ret != Variant()) {
53
return ret;
54
}
55
if (p_parameter == backward) {
56
return false;
57
}
58
return 0.0;
59
}
60
61
AnimationNode::NodeTimeInfo AnimationNodeAnimation::get_node_time_info() const {
62
NodeTimeInfo nti;
63
if (!process_state->tree->has_animation(animation)) {
64
return nti;
65
}
66
67
if (use_custom_timeline) {
68
nti.length = timeline_length;
69
nti.loop_mode = loop_mode;
70
} else {
71
Ref<Animation> anim = process_state->tree->get_animation(animation);
72
nti.length = (double)anim->get_length();
73
nti.loop_mode = anim->get_loop_mode();
74
}
75
nti.position = get_parameter(current_position);
76
77
return nti;
78
}
79
80
void AnimationNodeAnimation::_validate_property(PropertyInfo &p_property) const {
81
if (Engine::get_singleton()->is_editor_hint() && p_property.name == "animation" && get_editable_animation_list) {
82
Vector<String> names = get_editable_animation_list();
83
String anims;
84
for (int i = 0; i < names.size(); i++) {
85
if (i > 0) {
86
anims += ",";
87
}
88
anims += String(names[i]);
89
}
90
if (!anims.is_empty()) {
91
p_property.hint = PROPERTY_HINT_ENUM;
92
p_property.hint_string = anims;
93
}
94
}
95
96
if (!use_custom_timeline) {
97
if (p_property.name == "timeline_length" || p_property.name == "start_offset" || p_property.name == "loop_mode" || p_property.name == "stretch_time_scale") {
98
p_property.usage = PROPERTY_USAGE_NONE;
99
}
100
}
101
}
102
103
AnimationNode::NodeTimeInfo AnimationNodeAnimation::process(const AnimationMixer::PlaybackInfo p_playback_info, bool p_test_only) {
104
process_state->is_testing = p_test_only;
105
106
AnimationMixer::PlaybackInfo pi = p_playback_info;
107
if (p_playback_info.seeked) {
108
if (p_playback_info.is_external_seeking) {
109
pi.delta = get_node_time_info().position - p_playback_info.time;
110
}
111
} else {
112
pi.time = get_node_time_info().position + (get_parameter(backward) ? -p_playback_info.delta : p_playback_info.delta);
113
}
114
115
NodeTimeInfo nti = _process(pi, p_test_only);
116
117
if (!p_test_only) {
118
set_node_time_info(nti);
119
}
120
121
return nti;
122
}
123
124
AnimationNode::NodeTimeInfo AnimationNodeAnimation::_process(const AnimationMixer::PlaybackInfo p_playback_info, bool p_test_only) {
125
if (!process_state->tree->has_animation(animation)) {
126
AnimationNodeBlendTree *tree = Object::cast_to<AnimationNodeBlendTree>(node_state.parent);
127
if (tree) {
128
String node_name = tree->get_node_name(Ref<AnimationNodeAnimation>(this));
129
make_invalid(vformat(RTR("On BlendTree node '%s', animation not found: '%s'"), node_name, animation));
130
131
} else {
132
make_invalid(vformat(RTR("Animation not found: '%s'"), animation));
133
}
134
135
return NodeTimeInfo();
136
}
137
138
Ref<Animation> anim = process_state->tree->get_animation(animation);
139
double anim_size = (double)anim->get_length();
140
141
NodeTimeInfo cur_nti = get_node_time_info();
142
double cur_len = cur_nti.length;
143
double cur_time = p_playback_info.time;
144
double cur_delta = p_playback_info.delta;
145
bool cur_backward = get_parameter(backward);
146
147
Animation::LoopMode cur_loop_mode = cur_nti.loop_mode;
148
double prev_time = cur_nti.position;
149
150
Animation::LoopedFlag looped_flag = Animation::LOOPED_FLAG_NONE;
151
bool node_backward = play_mode == PLAY_MODE_BACKWARD;
152
153
bool p_seek = p_playback_info.seeked;
154
bool p_is_external_seeking = p_playback_info.is_external_seeking;
155
156
// 1. Progress for AnimationNode.
157
bool will_end = Animation::is_greater_or_equal_approx(cur_time + cur_delta, cur_len);
158
bool is_started = p_seek && !p_is_external_seeking && Math::is_zero_approx(cur_time);
159
bool immediately_after_start = is_started && advance_on_start;
160
161
// 1. Progress for AnimationNode.
162
if (immediately_after_start) {
163
cur_time = cur_delta;
164
}
165
if (cur_loop_mode != Animation::LOOP_NONE) {
166
if (cur_loop_mode == Animation::LOOP_LINEAR) {
167
if (!Math::is_zero_approx(cur_len)) {
168
cur_time = Math::fposmod(cur_time, cur_len);
169
}
170
cur_backward = false;
171
} else {
172
if (!Math::is_zero_approx(cur_len)) {
173
if (Animation::is_greater_or_equal_approx(prev_time, 0) && Animation::is_less_approx(cur_time, 0)) {
174
cur_backward = !cur_backward;
175
} else if (Animation::is_less_or_equal_approx(prev_time, cur_len) && Animation::is_greater_approx(cur_time, cur_len)) {
176
cur_backward = !cur_backward;
177
}
178
cur_time = Math::pingpong(cur_time, cur_len);
179
}
180
}
181
} else {
182
if (Animation::is_less_approx(cur_time, 0)) {
183
cur_delta += cur_time;
184
cur_time = 0;
185
} else if (Animation::is_greater_approx(cur_time, cur_len)) {
186
cur_delta += cur_time - cur_len;
187
cur_time = cur_len;
188
}
189
cur_backward = false;
190
// If ended, don't progress AnimationNode. So set delta to 0.
191
if (!Math::is_zero_approx(cur_delta)) {
192
if (play_mode == PLAY_MODE_FORWARD) {
193
if (Animation::is_greater_or_equal_approx(prev_time, cur_len)) {
194
cur_delta = 0;
195
}
196
} else {
197
if (Animation::is_less_or_equal_approx(prev_time, 0)) {
198
cur_delta = 0;
199
}
200
}
201
}
202
}
203
204
// 2. For return, store "AnimationNode" time info here, not "Animation" time info as below.
205
NodeTimeInfo nti;
206
nti.length = cur_len;
207
nti.position = cur_time;
208
nti.delta = cur_delta;
209
nti.loop_mode = cur_loop_mode;
210
nti.will_end = will_end;
211
212
// 3. Progress for Animation.
213
double prev_playback_time = prev_time + start_offset;
214
double cur_playback_time = cur_time + start_offset;
215
if (stretch_time_scale) {
216
double mlt = anim_size / cur_len;
217
prev_playback_time *= mlt;
218
cur_playback_time *= mlt;
219
cur_delta *= mlt;
220
}
221
if (cur_loop_mode == Animation::LOOP_LINEAR) {
222
if (!Math::is_zero_approx(anim_size)) {
223
prev_playback_time = Math::fposmod(prev_playback_time, anim_size);
224
cur_playback_time = Math::fposmod(cur_playback_time, anim_size);
225
if (Animation::is_greater_or_equal_approx(prev_playback_time, 0) && Animation::is_less_approx(cur_playback_time, 0)) {
226
looped_flag = node_backward ? Animation::LOOPED_FLAG_END : Animation::LOOPED_FLAG_START;
227
}
228
if (Animation::is_less_or_equal_approx(prev_playback_time, anim_size) && Animation::is_greater_approx(cur_playback_time, anim_size)) {
229
looped_flag = node_backward ? Animation::LOOPED_FLAG_START : Animation::LOOPED_FLAG_END;
230
}
231
}
232
} else if (cur_loop_mode == Animation::LOOP_PINGPONG) {
233
if (!Math::is_zero_approx(anim_size)) {
234
if (Animation::is_greater_or_equal_approx(Math::fposmod(cur_playback_time, anim_size * 2.0), anim_size)) {
235
cur_delta = -cur_delta; // Needed for retrieving discrete keys correctly.
236
}
237
prev_playback_time = Math::pingpong(prev_playback_time, anim_size);
238
cur_playback_time = Math::pingpong(cur_playback_time, anim_size);
239
if (Animation::is_greater_or_equal_approx(prev_playback_time, 0) && Animation::is_less_approx(cur_playback_time, 0)) {
240
looped_flag = node_backward ? Animation::LOOPED_FLAG_END : Animation::LOOPED_FLAG_START;
241
}
242
if (Animation::is_less_or_equal_approx(prev_playback_time, anim_size) && Animation::is_greater_approx(cur_playback_time, anim_size)) {
243
looped_flag = node_backward ? Animation::LOOPED_FLAG_START : Animation::LOOPED_FLAG_END;
244
}
245
}
246
} else {
247
if (Animation::is_less_approx(cur_playback_time, 0)) {
248
cur_playback_time = 0;
249
} else if (Animation::is_greater_approx(cur_playback_time, anim_size)) {
250
cur_playback_time = anim_size;
251
}
252
253
// Emit start & finish signal. Internally, the detections are the same for backward.
254
// We should use call_deferred since the track keys are still being processed.
255
if (process_state->tree && !p_test_only) {
256
// AnimationTree uses seek to 0 "internally" to process the first key of the animation, which is used as the start detection.
257
if (is_started) {
258
process_state->tree->call_deferred(SNAME("emit_signal"), SceneStringName(animation_started), animation);
259
}
260
// Finished.
261
if (Animation::is_less_approx(prev_playback_time, anim_size) && Animation::is_greater_or_equal_approx(cur_playback_time, anim_size)) {
262
cur_playback_time = anim_size;
263
process_state->tree->call_deferred(SNAME("emit_signal"), SceneStringName(animation_finished), animation);
264
}
265
}
266
}
267
268
if (!p_test_only) {
269
// Force process first key for Discrete/Method/Audio/AnimationPlayback.
270
if (immediately_after_start) {
271
AnimationMixer::PlaybackInfo pi = p_playback_info;
272
pi.start = 0.0;
273
pi.end = cur_len;
274
if (play_mode == PLAY_MODE_FORWARD) {
275
pi.time = 0;
276
} else {
277
pi.time = anim_size;
278
}
279
pi.delta = 0;
280
pi.weight = CMP_EPSILON;
281
blend_animation(animation, pi);
282
}
283
284
AnimationMixer::PlaybackInfo pi = p_playback_info;
285
pi.start = 0.0;
286
pi.end = cur_len;
287
if (play_mode == PLAY_MODE_FORWARD) {
288
pi.time = cur_playback_time;
289
} else {
290
pi.time = anim_size - cur_playback_time;
291
}
292
if (node_backward ? cur_backward : !cur_backward) {
293
pi.delta = cur_delta;
294
} else {
295
pi.delta = -cur_delta;
296
}
297
pi.weight = 1.0;
298
pi.looped_flag = looped_flag;
299
blend_animation(animation, pi);
300
301
set_parameter(backward, cur_backward);
302
}
303
304
return nti;
305
}
306
307
String AnimationNodeAnimation::get_caption() const {
308
return "Animation";
309
}
310
311
void AnimationNodeAnimation::set_play_mode(PlayMode p_play_mode) {
312
play_mode = p_play_mode;
313
}
314
315
AnimationNodeAnimation::PlayMode AnimationNodeAnimation::get_play_mode() const {
316
return play_mode;
317
}
318
319
void AnimationNodeAnimation::set_backward(bool p_backward) {
320
set_parameter(backward, p_backward);
321
}
322
323
bool AnimationNodeAnimation::is_backward() const {
324
return get_parameter(backward);
325
}
326
327
void AnimationNodeAnimation::set_advance_on_start(bool p_advance_on_start) {
328
advance_on_start = p_advance_on_start;
329
}
330
331
bool AnimationNodeAnimation::is_advance_on_start() const {
332
return advance_on_start;
333
}
334
335
void AnimationNodeAnimation::set_use_custom_timeline(bool p_use_custom_timeline) {
336
use_custom_timeline = p_use_custom_timeline;
337
notify_property_list_changed();
338
}
339
340
bool AnimationNodeAnimation::is_using_custom_timeline() const {
341
return use_custom_timeline;
342
}
343
344
void AnimationNodeAnimation::set_timeline_length(double p_length) {
345
timeline_length = p_length;
346
}
347
348
double AnimationNodeAnimation::get_timeline_length() const {
349
return timeline_length;
350
}
351
352
void AnimationNodeAnimation::set_stretch_time_scale(bool p_stretch_time_scale) {
353
stretch_time_scale = p_stretch_time_scale;
354
notify_property_list_changed();
355
}
356
357
bool AnimationNodeAnimation::is_stretching_time_scale() const {
358
return stretch_time_scale;
359
}
360
361
void AnimationNodeAnimation::set_start_offset(double p_offset) {
362
start_offset = p_offset;
363
}
364
365
double AnimationNodeAnimation::get_start_offset() const {
366
return start_offset;
367
}
368
369
void AnimationNodeAnimation::set_loop_mode(Animation::LoopMode p_loop_mode) {
370
loop_mode = p_loop_mode;
371
}
372
373
Animation::LoopMode AnimationNodeAnimation::get_loop_mode() const {
374
return loop_mode;
375
}
376
377
void AnimationNodeAnimation::_bind_methods() {
378
ClassDB::bind_method(D_METHOD("set_animation", "name"), &AnimationNodeAnimation::set_animation);
379
ClassDB::bind_method(D_METHOD("get_animation"), &AnimationNodeAnimation::get_animation);
380
381
ClassDB::bind_method(D_METHOD("set_play_mode", "mode"), &AnimationNodeAnimation::set_play_mode);
382
ClassDB::bind_method(D_METHOD("get_play_mode"), &AnimationNodeAnimation::get_play_mode);
383
384
ClassDB::bind_method(D_METHOD("set_advance_on_start", "advance_on_start"), &AnimationNodeAnimation::set_advance_on_start);
385
ClassDB::bind_method(D_METHOD("is_advance_on_start"), &AnimationNodeAnimation::is_advance_on_start);
386
387
ClassDB::bind_method(D_METHOD("set_use_custom_timeline", "use_custom_timeline"), &AnimationNodeAnimation::set_use_custom_timeline);
388
ClassDB::bind_method(D_METHOD("is_using_custom_timeline"), &AnimationNodeAnimation::is_using_custom_timeline);
389
390
ClassDB::bind_method(D_METHOD("set_timeline_length", "timeline_length"), &AnimationNodeAnimation::set_timeline_length);
391
ClassDB::bind_method(D_METHOD("get_timeline_length"), &AnimationNodeAnimation::get_timeline_length);
392
393
ClassDB::bind_method(D_METHOD("set_stretch_time_scale", "stretch_time_scale"), &AnimationNodeAnimation::set_stretch_time_scale);
394
ClassDB::bind_method(D_METHOD("is_stretching_time_scale"), &AnimationNodeAnimation::is_stretching_time_scale);
395
396
ClassDB::bind_method(D_METHOD("set_start_offset", "start_offset"), &AnimationNodeAnimation::set_start_offset);
397
ClassDB::bind_method(D_METHOD("get_start_offset"), &AnimationNodeAnimation::get_start_offset);
398
399
ClassDB::bind_method(D_METHOD("set_loop_mode", "loop_mode"), &AnimationNodeAnimation::set_loop_mode);
400
ClassDB::bind_method(D_METHOD("get_loop_mode"), &AnimationNodeAnimation::get_loop_mode);
401
402
ADD_PROPERTY(PropertyInfo(Variant::STRING_NAME, "animation"), "set_animation", "get_animation");
403
ADD_PROPERTY(PropertyInfo(Variant::INT, "play_mode", PROPERTY_HINT_ENUM, "Forward,Backward"), "set_play_mode", "get_play_mode");
404
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "advance_on_start"), "set_advance_on_start", "is_advance_on_start");
405
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_custom_timeline"), "set_use_custom_timeline", "is_using_custom_timeline");
406
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "timeline_length", PROPERTY_HINT_RANGE, "0.001,60,0.001,or_greater,or_less,hide_control,suffix:s"), "set_timeline_length", "get_timeline_length");
407
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "stretch_time_scale"), "set_stretch_time_scale", "is_stretching_time_scale");
408
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "start_offset", PROPERTY_HINT_RANGE, "-60,60,0.001,or_greater,or_less,hide_control,suffix:s"), "set_start_offset", "get_start_offset");
409
ADD_PROPERTY(PropertyInfo(Variant::INT, "loop_mode", PROPERTY_HINT_ENUM, "None,Linear,Ping-Pong"), "set_loop_mode", "get_loop_mode");
410
411
BIND_ENUM_CONSTANT(PLAY_MODE_FORWARD);
412
BIND_ENUM_CONSTANT(PLAY_MODE_BACKWARD);
413
}
414
415
AnimationNodeAnimation::AnimationNodeAnimation() {
416
}
417
418
////////////////////////////////////////////////////////
419
420
void AnimationNodeSync::_bind_methods() {
421
ClassDB::bind_method(D_METHOD("set_use_sync", "enable"), &AnimationNodeSync::set_use_sync);
422
ClassDB::bind_method(D_METHOD("is_using_sync"), &AnimationNodeSync::is_using_sync);
423
424
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "sync"), "set_use_sync", "is_using_sync");
425
}
426
427
void AnimationNodeSync::set_use_sync(bool p_sync) {
428
sync = p_sync;
429
}
430
431
bool AnimationNodeSync::is_using_sync() const {
432
return sync;
433
}
434
435
AnimationNodeSync::AnimationNodeSync() {
436
}
437
438
////////////////////////////////////////////////////////
439
void AnimationNodeOneShot::get_parameter_list(List<PropertyInfo> *r_list) const {
440
AnimationNode::get_parameter_list(r_list);
441
r_list->push_back(PropertyInfo(Variant::BOOL, active, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_READ_ONLY));
442
r_list->push_back(PropertyInfo(Variant::BOOL, internal_active, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_READ_ONLY));
443
r_list->push_back(PropertyInfo(Variant::INT, request, PROPERTY_HINT_ENUM, ",Fire,Abort,Fade Out"));
444
r_list->push_back(PropertyInfo(Variant::FLOAT, fade_in_remaining, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE));
445
r_list->push_back(PropertyInfo(Variant::FLOAT, fade_out_remaining, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE));
446
r_list->push_back(PropertyInfo(Variant::FLOAT, time_to_restart, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE));
447
}
448
449
Variant AnimationNodeOneShot::get_parameter_default_value(const StringName &p_parameter) const {
450
Variant ret = AnimationNode::get_parameter_default_value(p_parameter);
451
if (ret != Variant()) {
452
return ret;
453
}
454
455
if (p_parameter == request) {
456
return ONE_SHOT_REQUEST_NONE;
457
} else if (p_parameter == active || p_parameter == internal_active) {
458
return false;
459
} else if (p_parameter == time_to_restart) {
460
return -1.0;
461
}
462
463
return 0.0;
464
}
465
466
bool AnimationNodeOneShot::is_parameter_read_only(const StringName &p_parameter) const {
467
if (AnimationNode::is_parameter_read_only(p_parameter)) {
468
return true;
469
}
470
471
if (p_parameter == active || p_parameter == internal_active) {
472
return true;
473
}
474
return false;
475
}
476
477
void AnimationNodeOneShot::set_fade_in_time(double p_time) {
478
fade_in = p_time;
479
}
480
481
double AnimationNodeOneShot::get_fade_in_time() const {
482
return fade_in;
483
}
484
485
void AnimationNodeOneShot::set_fade_out_time(double p_time) {
486
fade_out = p_time;
487
}
488
489
double AnimationNodeOneShot::get_fade_out_time() const {
490
return fade_out;
491
}
492
493
void AnimationNodeOneShot::set_fade_in_curve(const Ref<Curve> &p_curve) {
494
fade_in_curve = p_curve;
495
}
496
497
Ref<Curve> AnimationNodeOneShot::get_fade_in_curve() const {
498
return fade_in_curve;
499
}
500
501
void AnimationNodeOneShot::set_fade_out_curve(const Ref<Curve> &p_curve) {
502
fade_out_curve = p_curve;
503
}
504
505
Ref<Curve> AnimationNodeOneShot::get_fade_out_curve() const {
506
return fade_out_curve;
507
}
508
509
void AnimationNodeOneShot::set_auto_restart_enabled(bool p_enabled) {
510
auto_restart = p_enabled;
511
}
512
513
void AnimationNodeOneShot::set_auto_restart_delay(double p_time) {
514
auto_restart_delay = p_time;
515
}
516
517
void AnimationNodeOneShot::set_auto_restart_random_delay(double p_time) {
518
auto_restart_random_delay = p_time;
519
}
520
521
bool AnimationNodeOneShot::is_auto_restart_enabled() const {
522
return auto_restart;
523
}
524
525
double AnimationNodeOneShot::get_auto_restart_delay() const {
526
return auto_restart_delay;
527
}
528
529
double AnimationNodeOneShot::get_auto_restart_random_delay() const {
530
return auto_restart_random_delay;
531
}
532
533
void AnimationNodeOneShot::set_mix_mode(MixMode p_mix) {
534
mix = p_mix;
535
}
536
537
AnimationNodeOneShot::MixMode AnimationNodeOneShot::get_mix_mode() const {
538
return mix;
539
}
540
541
void AnimationNodeOneShot::set_break_loop_at_end(bool p_enable) {
542
break_loop_at_end = p_enable;
543
}
544
545
bool AnimationNodeOneShot::is_loop_broken_at_end() const {
546
return break_loop_at_end;
547
}
548
549
void AnimationNodeOneShot::set_abort_on_reset(bool p_enable) {
550
abort_on_reset = p_enable;
551
}
552
553
bool AnimationNodeOneShot::is_aborted_on_reset() const {
554
return abort_on_reset;
555
}
556
557
String AnimationNodeOneShot::get_caption() const {
558
return "OneShot";
559
}
560
561
bool AnimationNodeOneShot::has_filter() const {
562
return true;
563
}
564
565
AnimationNode::NodeTimeInfo AnimationNodeOneShot::_process(const AnimationMixer::PlaybackInfo p_playback_info, bool p_test_only) {
566
OneShotRequest cur_request = static_cast<OneShotRequest>((int)get_parameter(request));
567
bool cur_active = get_parameter(active);
568
bool cur_internal_active = get_parameter(internal_active);
569
NodeTimeInfo cur_nti = get_node_time_info();
570
double cur_time_to_restart = get_parameter(time_to_restart);
571
double cur_fade_in_remaining = get_parameter(fade_in_remaining);
572
double cur_fade_out_remaining = get_parameter(fade_out_remaining);
573
574
set_parameter(request, ONE_SHOT_REQUEST_NONE);
575
576
bool is_shooting = true;
577
bool is_fading_out = cur_active == true && cur_internal_active == false;
578
579
double p_time = p_playback_info.time;
580
double p_delta = p_playback_info.delta;
581
double abs_delta = Math::abs(p_delta);
582
bool p_seek = p_playback_info.seeked;
583
bool p_is_external_seeking = p_playback_info.is_external_seeking;
584
585
bool do_start = cur_request == ONE_SHOT_REQUEST_FIRE;
586
587
bool is_reset = Math::is_zero_approx(p_time) && p_seek && !p_is_external_seeking;
588
if (is_reset && cur_internal_active) {
589
do_start = true;
590
}
591
592
bool is_abort = cur_request == ONE_SHOT_REQUEST_ABORT;
593
if (is_reset && !do_start && (is_fading_out || (abort_on_reset && cur_active))) {
594
is_abort = true;
595
}
596
597
if (is_abort) {
598
set_parameter(internal_active, false);
599
set_parameter(active, false);
600
set_parameter(time_to_restart, -1);
601
set_parameter(fade_out_remaining, 0);
602
cur_fade_out_remaining = 0;
603
is_fading_out = false;
604
is_shooting = false;
605
} else if (cur_request == ONE_SHOT_REQUEST_FADE_OUT && !is_fading_out) { // If fading, keep current fade.
606
if (cur_active) {
607
// Request fading.
608
is_fading_out = true;
609
cur_fade_out_remaining = fade_out;
610
cur_fade_in_remaining = 0;
611
} else {
612
// Shot is ended, do nothing.
613
is_shooting = false;
614
}
615
set_parameter(internal_active, false);
616
set_parameter(time_to_restart, -1);
617
} else if (!do_start && !cur_active) {
618
if (Animation::is_greater_or_equal_approx(cur_time_to_restart, 0) && !p_seek) {
619
cur_time_to_restart -= abs_delta;
620
if (Animation::is_less_approx(cur_time_to_restart, 0)) {
621
do_start = true; // Restart.
622
}
623
set_parameter(time_to_restart, cur_time_to_restart);
624
}
625
if (!do_start) {
626
is_shooting = false;
627
}
628
}
629
630
bool os_seek = p_seek;
631
632
if (!is_shooting) {
633
AnimationMixer::PlaybackInfo pi = p_playback_info;
634
pi.weight = 1.0;
635
return blend_input(0, pi, FILTER_IGNORE, sync, p_test_only);
636
}
637
638
if (do_start) {
639
os_seek = true;
640
if (!cur_internal_active) {
641
cur_fade_in_remaining = fade_in; // If already active, don't fade-in again.
642
}
643
cur_internal_active = true;
644
set_parameter(request, ONE_SHOT_REQUEST_NONE);
645
set_parameter(internal_active, true);
646
set_parameter(active, true);
647
}
648
649
real_t blend = 1.0;
650
bool use_blend = sync;
651
652
if (Animation::is_greater_approx(cur_fade_in_remaining, 0)) {
653
if (Animation::is_greater_approx(fade_in, 0)) {
654
use_blend = true;
655
blend = (fade_in - cur_fade_in_remaining) / fade_in;
656
if (fade_in_curve.is_valid()) {
657
blend = fade_in_curve->sample(blend);
658
}
659
} else {
660
blend = 0; // Should not happen.
661
}
662
}
663
664
if (is_fading_out) {
665
use_blend = true;
666
if (Animation::is_greater_approx(fade_out, 0)) {
667
blend = cur_fade_out_remaining / fade_out;
668
if (fade_out_curve.is_valid()) {
669
blend = 1.0 - fade_out_curve->sample(1.0 - blend);
670
}
671
} else {
672
blend = 0;
673
}
674
}
675
676
AnimationMixer::PlaybackInfo pi = p_playback_info;
677
NodeTimeInfo main_nti;
678
if (mix == MIX_MODE_ADD) {
679
pi.weight = 1.0;
680
main_nti = blend_input(0, pi, FILTER_IGNORE, sync, p_test_only);
681
} else {
682
pi.seeked &= use_blend;
683
pi.weight = 1.0 - blend;
684
main_nti = blend_input(0, pi, FILTER_BLEND, sync, p_test_only); // Unlike below, processing this edge is a corner case.
685
}
686
687
pi = p_playback_info;
688
if (do_start) {
689
pi.time = 0;
690
} else if (os_seek) {
691
pi.time = cur_nti.position;
692
}
693
pi.seeked = os_seek;
694
pi.weight = Math::is_zero_approx(blend) ? CMP_EPSILON : blend;
695
696
NodeTimeInfo os_nti = blend_input(1, pi, FILTER_PASS, true, p_test_only); // Blend values must be more than CMP_EPSILON to process discrete keys in edge.
697
698
if (Animation::is_less_or_equal_approx(cur_fade_in_remaining, 0) && !do_start && !is_fading_out) {
699
// Predict time scale by difference of delta times to estimate input animation's remain time in self time scale.
700
// TODO: Time scale should be included into NodeTimeInfo for Godot 5.0.
701
double abs_os_delta = Math::abs(os_nti.delta);
702
double tscl = Math::is_zero_approx(abs_delta) || Math::is_zero_approx(abs_os_delta) || Math::is_equal_approx(abs_delta, abs_os_delta) ? 1.0 : (abs_delta / abs_os_delta);
703
double os_rem = os_nti.get_remain(break_loop_at_end) * tscl;
704
if (Animation::is_less_or_equal_approx(os_rem, fade_out)) {
705
is_fading_out = true;
706
cur_fade_out_remaining = os_rem + abs_delta;
707
cur_fade_in_remaining = 0;
708
set_parameter(internal_active, false);
709
}
710
}
711
712
if (!p_seek) {
713
if (Animation::is_less_or_equal_approx(os_nti.get_remain(break_loop_at_end), 0) || (is_fading_out && Animation::is_less_or_equal_approx(cur_fade_out_remaining, 0))) {
714
set_parameter(internal_active, false);
715
set_parameter(active, false);
716
if (auto_restart) {
717
double restart_sec = auto_restart_delay + Math::randd() * auto_restart_random_delay;
718
set_parameter(time_to_restart, restart_sec);
719
}
720
}
721
if (!do_start) {
722
cur_fade_in_remaining = MAX(0, cur_fade_in_remaining - abs_delta); // Don't consider seeked delta by restart.
723
}
724
cur_fade_out_remaining = MAX(0, cur_fade_out_remaining - abs_delta);
725
}
726
727
set_parameter(fade_in_remaining, cur_fade_in_remaining);
728
set_parameter(fade_out_remaining, cur_fade_out_remaining);
729
730
return cur_internal_active ? os_nti : main_nti;
731
}
732
733
void AnimationNodeOneShot::_bind_methods() {
734
ClassDB::bind_method(D_METHOD("set_fadein_time", "time"), &AnimationNodeOneShot::set_fade_in_time);
735
ClassDB::bind_method(D_METHOD("get_fadein_time"), &AnimationNodeOneShot::get_fade_in_time);
736
737
ClassDB::bind_method(D_METHOD("set_fadein_curve", "curve"), &AnimationNodeOneShot::set_fade_in_curve);
738
ClassDB::bind_method(D_METHOD("get_fadein_curve"), &AnimationNodeOneShot::get_fade_in_curve);
739
740
ClassDB::bind_method(D_METHOD("set_fadeout_time", "time"), &AnimationNodeOneShot::set_fade_out_time);
741
ClassDB::bind_method(D_METHOD("get_fadeout_time"), &AnimationNodeOneShot::get_fade_out_time);
742
743
ClassDB::bind_method(D_METHOD("set_fadeout_curve", "curve"), &AnimationNodeOneShot::set_fade_out_curve);
744
ClassDB::bind_method(D_METHOD("get_fadeout_curve"), &AnimationNodeOneShot::get_fade_out_curve);
745
746
ClassDB::bind_method(D_METHOD("set_break_loop_at_end", "enable"), &AnimationNodeOneShot::set_break_loop_at_end);
747
ClassDB::bind_method(D_METHOD("is_loop_broken_at_end"), &AnimationNodeOneShot::is_loop_broken_at_end);
748
749
ClassDB::bind_method(D_METHOD("set_abort_on_reset", "enable"), &AnimationNodeOneShot::set_abort_on_reset);
750
ClassDB::bind_method(D_METHOD("is_aborted_on_reset"), &AnimationNodeOneShot::is_aborted_on_reset);
751
752
ClassDB::bind_method(D_METHOD("set_autorestart", "active"), &AnimationNodeOneShot::set_auto_restart_enabled);
753
ClassDB::bind_method(D_METHOD("has_autorestart"), &AnimationNodeOneShot::is_auto_restart_enabled);
754
755
ClassDB::bind_method(D_METHOD("set_autorestart_delay", "time"), &AnimationNodeOneShot::set_auto_restart_delay);
756
ClassDB::bind_method(D_METHOD("get_autorestart_delay"), &AnimationNodeOneShot::get_auto_restart_delay);
757
758
ClassDB::bind_method(D_METHOD("set_autorestart_random_delay", "time"), &AnimationNodeOneShot::set_auto_restart_random_delay);
759
ClassDB::bind_method(D_METHOD("get_autorestart_random_delay"), &AnimationNodeOneShot::get_auto_restart_random_delay);
760
761
ClassDB::bind_method(D_METHOD("set_mix_mode", "mode"), &AnimationNodeOneShot::set_mix_mode);
762
ClassDB::bind_method(D_METHOD("get_mix_mode"), &AnimationNodeOneShot::get_mix_mode);
763
764
ADD_PROPERTY(PropertyInfo(Variant::INT, "mix_mode", PROPERTY_HINT_ENUM, "Blend,Add"), "set_mix_mode", "get_mix_mode");
765
766
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "fadein_time", PROPERTY_HINT_RANGE, "0,60,0.01,or_greater,suffix:s"), "set_fadein_time", "get_fadein_time");
767
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "fadein_curve", PROPERTY_HINT_RESOURCE_TYPE, Curve::get_class_static()), "set_fadein_curve", "get_fadein_curve");
768
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "fadeout_time", PROPERTY_HINT_RANGE, "0,60,0.01,or_greater,suffix:s"), "set_fadeout_time", "get_fadeout_time");
769
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "fadeout_curve", PROPERTY_HINT_RESOURCE_TYPE, Curve::get_class_static()), "set_fadeout_curve", "get_fadeout_curve");
770
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "break_loop_at_end"), "set_break_loop_at_end", "is_loop_broken_at_end");
771
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "abort_on_reset"), "set_abort_on_reset", "is_aborted_on_reset");
772
773
ADD_GROUP("Auto Restart", "autorestart_");
774
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "autorestart"), "set_autorestart", "has_autorestart");
775
776
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "autorestart_delay", PROPERTY_HINT_RANGE, "0,60,0.01,or_greater,suffix:s"), "set_autorestart_delay", "get_autorestart_delay");
777
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "autorestart_random_delay", PROPERTY_HINT_RANGE, "0,60,0.01,or_greater,suffix:s"), "set_autorestart_random_delay", "get_autorestart_random_delay");
778
779
BIND_ENUM_CONSTANT(ONE_SHOT_REQUEST_NONE);
780
BIND_ENUM_CONSTANT(ONE_SHOT_REQUEST_FIRE);
781
BIND_ENUM_CONSTANT(ONE_SHOT_REQUEST_ABORT);
782
BIND_ENUM_CONSTANT(ONE_SHOT_REQUEST_FADE_OUT);
783
784
BIND_ENUM_CONSTANT(MIX_MODE_BLEND);
785
BIND_ENUM_CONSTANT(MIX_MODE_ADD);
786
}
787
788
AnimationNodeOneShot::AnimationNodeOneShot() {
789
add_input("in");
790
add_input("shot");
791
}
792
793
////////////////////////////////////////////////
794
795
void AnimationNodeAdd2::get_parameter_list(List<PropertyInfo> *r_list) const {
796
AnimationNode::get_parameter_list(r_list);
797
r_list->push_back(PropertyInfo(Variant::FLOAT, add_amount, PROPERTY_HINT_RANGE, "0,1,0.01,or_less,or_greater"));
798
}
799
800
Variant AnimationNodeAdd2::get_parameter_default_value(const StringName &p_parameter) const {
801
Variant ret = AnimationNode::get_parameter_default_value(p_parameter);
802
if (ret != Variant()) {
803
return ret;
804
}
805
806
return 0.0;
807
}
808
809
String AnimationNodeAdd2::get_caption() const {
810
return "Add2";
811
}
812
813
bool AnimationNodeAdd2::has_filter() const {
814
return true;
815
}
816
817
AnimationNode::NodeTimeInfo AnimationNodeAdd2::_process(const AnimationMixer::PlaybackInfo p_playback_info, bool p_test_only) {
818
double amount = get_parameter(add_amount);
819
820
AnimationMixer::PlaybackInfo pi = p_playback_info;
821
pi.weight = 1.0;
822
NodeTimeInfo nti = blend_input(0, pi, FILTER_IGNORE, sync, p_test_only);
823
pi.weight = amount;
824
blend_input(1, pi, FILTER_PASS, sync, p_test_only);
825
826
return nti;
827
}
828
829
AnimationNodeAdd2::AnimationNodeAdd2() {
830
add_input("in");
831
add_input("add");
832
}
833
834
////////////////////////////////////////////////
835
836
void AnimationNodeAdd3::get_parameter_list(List<PropertyInfo> *r_list) const {
837
AnimationNode::get_parameter_list(r_list);
838
r_list->push_back(PropertyInfo(Variant::FLOAT, add_amount, PROPERTY_HINT_RANGE, "-1,1,0.01,or_less,or_greater"));
839
}
840
841
Variant AnimationNodeAdd3::get_parameter_default_value(const StringName &p_parameter) const {
842
Variant ret = AnimationNode::get_parameter_default_value(p_parameter);
843
if (ret != Variant()) {
844
return ret;
845
}
846
847
return 0.0;
848
}
849
850
String AnimationNodeAdd3::get_caption() const {
851
return "Add3";
852
}
853
854
bool AnimationNodeAdd3::has_filter() const {
855
return true;
856
}
857
858
AnimationNode::NodeTimeInfo AnimationNodeAdd3::_process(const AnimationMixer::PlaybackInfo p_playback_info, bool p_test_only) {
859
double amount = get_parameter(add_amount);
860
861
AnimationMixer::PlaybackInfo pi = p_playback_info;
862
pi.weight = MAX(0, -amount);
863
blend_input(0, pi, FILTER_PASS, sync, p_test_only);
864
pi.weight = 1.0;
865
NodeTimeInfo nti = blend_input(1, pi, FILTER_IGNORE, sync, p_test_only);
866
pi.weight = MAX(0, amount);
867
blend_input(2, pi, FILTER_PASS, sync, p_test_only);
868
869
return nti;
870
}
871
872
AnimationNodeAdd3::AnimationNodeAdd3() {
873
add_input("-add");
874
add_input("in");
875
add_input("+add");
876
}
877
878
/////////////////////////////////////////////
879
880
void AnimationNodeBlend2::get_parameter_list(List<PropertyInfo> *r_list) const {
881
AnimationNode::get_parameter_list(r_list);
882
r_list->push_back(PropertyInfo(Variant::FLOAT, blend_amount, PROPERTY_HINT_RANGE, "0,1,0.01,or_less,or_greater"));
883
}
884
885
Variant AnimationNodeBlend2::get_parameter_default_value(const StringName &p_parameter) const {
886
Variant ret = AnimationNode::get_parameter_default_value(p_parameter);
887
if (ret != Variant()) {
888
return ret;
889
}
890
891
return 0.0; // For blend amount.
892
}
893
894
String AnimationNodeBlend2::get_caption() const {
895
return "Blend2";
896
}
897
898
AnimationNode::NodeTimeInfo AnimationNodeBlend2::_process(const AnimationMixer::PlaybackInfo p_playback_info, bool p_test_only) {
899
double amount = get_parameter(blend_amount);
900
901
AnimationMixer::PlaybackInfo pi = p_playback_info;
902
pi.weight = 1.0 - amount;
903
NodeTimeInfo nti0 = blend_input(0, pi, FILTER_BLEND, sync, p_test_only);
904
pi.weight = amount;
905
NodeTimeInfo nti1 = blend_input(1, pi, FILTER_PASS, sync, p_test_only);
906
907
return amount > 0.5 ? nti1 : nti0; // Hacky but good enough.
908
}
909
910
bool AnimationNodeBlend2::has_filter() const {
911
return true;
912
}
913
914
AnimationNodeBlend2::AnimationNodeBlend2() {
915
add_input("in");
916
add_input("blend");
917
}
918
919
//////////////////////////////////////
920
921
void AnimationNodeBlend3::get_parameter_list(List<PropertyInfo> *r_list) const {
922
AnimationNode::get_parameter_list(r_list);
923
r_list->push_back(PropertyInfo(Variant::FLOAT, blend_amount, PROPERTY_HINT_RANGE, "-1,1,0.01,or_less,or_greater"));
924
}
925
926
Variant AnimationNodeBlend3::get_parameter_default_value(const StringName &p_parameter) const {
927
Variant ret = AnimationNode::get_parameter_default_value(p_parameter);
928
if (ret != Variant()) {
929
return ret;
930
}
931
932
return 0.0; // For blend amount.
933
}
934
935
String AnimationNodeBlend3::get_caption() const {
936
return "Blend3";
937
}
938
939
AnimationNode::NodeTimeInfo AnimationNodeBlend3::_process(const AnimationMixer::PlaybackInfo p_playback_info, bool p_test_only) {
940
double amount = get_parameter(blend_amount);
941
942
AnimationMixer::PlaybackInfo pi = p_playback_info;
943
pi.weight = MAX(0, -amount);
944
NodeTimeInfo nti0 = blend_input(0, pi, FILTER_IGNORE, sync, p_test_only);
945
pi.weight = 1.0 - Math::abs(amount);
946
NodeTimeInfo nti1 = blend_input(1, pi, FILTER_IGNORE, sync, p_test_only);
947
pi.weight = MAX(0, amount);
948
NodeTimeInfo nti2 = blend_input(2, pi, FILTER_IGNORE, sync, p_test_only);
949
950
return amount > 0.5 ? nti2 : (amount < -0.5 ? nti0 : nti1); // Hacky but good enough.
951
}
952
953
AnimationNodeBlend3::AnimationNodeBlend3() {
954
add_input("-blend");
955
add_input("in");
956
add_input("+blend");
957
}
958
959
////////////////////////////////////////////////
960
961
void AnimationNodeSub2::get_parameter_list(List<PropertyInfo> *r_list) const {
962
AnimationNode::get_parameter_list(r_list);
963
r_list->push_back(PropertyInfo(Variant::FLOAT, sub_amount, PROPERTY_HINT_RANGE, "0,1,0.01,or_less,or_greater"));
964
}
965
966
Variant AnimationNodeSub2::get_parameter_default_value(const StringName &p_parameter) const {
967
Variant ret = AnimationNode::get_parameter_default_value(p_parameter);
968
if (ret != Variant()) {
969
return ret;
970
}
971
972
return 0.0;
973
}
974
975
String AnimationNodeSub2::get_caption() const {
976
return "Sub2";
977
}
978
979
bool AnimationNodeSub2::has_filter() const {
980
return true;
981
}
982
983
AnimationNode::NodeTimeInfo AnimationNodeSub2::_process(const AnimationMixer::PlaybackInfo p_playback_info, bool p_test_only) {
984
double amount = get_parameter(sub_amount);
985
986
AnimationMixer::PlaybackInfo pi = p_playback_info;
987
// Out = Sub.Transform3D^(-1) * In.Transform3D
988
pi.weight = -amount;
989
blend_input(1, pi, FILTER_PASS, sync, p_test_only);
990
pi.weight = 1.0;
991
992
return blend_input(0, pi, FILTER_IGNORE, sync, p_test_only);
993
}
994
995
AnimationNodeSub2::AnimationNodeSub2() {
996
add_input("in");
997
add_input("sub");
998
}
999
1000
/////////////////////////////////
1001
1002
void AnimationNodeTimeScale::get_parameter_list(List<PropertyInfo> *r_list) const {
1003
AnimationNode::get_parameter_list(r_list);
1004
r_list->push_back(PropertyInfo(Variant::FLOAT, scale, PROPERTY_HINT_RANGE, "-32,32,0.01,or_less,or_greater"));
1005
}
1006
1007
Variant AnimationNodeTimeScale::get_parameter_default_value(const StringName &p_parameter) const {
1008
Variant ret = AnimationNode::get_parameter_default_value(p_parameter);
1009
if (ret != Variant()) {
1010
return ret;
1011
}
1012
1013
return 1.0; // Initial timescale.
1014
}
1015
1016
String AnimationNodeTimeScale::get_caption() const {
1017
return "TimeScale";
1018
}
1019
1020
AnimationNode::NodeTimeInfo AnimationNodeTimeScale::_process(const AnimationMixer::PlaybackInfo p_playback_info, bool p_test_only) {
1021
double cur_scale = get_parameter(scale);
1022
1023
AnimationMixer::PlaybackInfo pi = p_playback_info;
1024
pi.weight = 1.0;
1025
if (!pi.seeked) {
1026
pi.delta *= cur_scale;
1027
}
1028
1029
return blend_input(0, pi, FILTER_IGNORE, true, p_test_only);
1030
}
1031
1032
AnimationNodeTimeScale::AnimationNodeTimeScale() {
1033
add_input("in");
1034
}
1035
1036
////////////////////////////////////
1037
1038
void AnimationNodeTimeSeek::get_parameter_list(List<PropertyInfo> *r_list) const {
1039
AnimationNode::get_parameter_list(r_list);
1040
r_list->push_back(PropertyInfo(Variant::FLOAT, seek_pos_request, PROPERTY_HINT_RANGE, "-1,3600,0.01,or_greater")); // It will be reset to -1 after seeking the position immediately.
1041
}
1042
1043
Variant AnimationNodeTimeSeek::get_parameter_default_value(const StringName &p_parameter) const {
1044
Variant ret = AnimationNode::get_parameter_default_value(p_parameter);
1045
if (ret != Variant()) {
1046
return ret;
1047
}
1048
1049
return -1.0; // Initial seek request.
1050
}
1051
1052
String AnimationNodeTimeSeek::get_caption() const {
1053
return "TimeSeek";
1054
}
1055
1056
void AnimationNodeTimeSeek::set_explicit_elapse(bool p_enable) {
1057
explicit_elapse = p_enable;
1058
}
1059
1060
bool AnimationNodeTimeSeek::is_explicit_elapse() const {
1061
return explicit_elapse;
1062
}
1063
1064
AnimationNode::NodeTimeInfo AnimationNodeTimeSeek::_process(const AnimationMixer::PlaybackInfo p_playback_info, bool p_test_only) {
1065
double cur_seek_pos = get_parameter(seek_pos_request);
1066
1067
AnimationMixer::PlaybackInfo pi = p_playback_info;
1068
pi.weight = 1.0;
1069
if (Animation::is_greater_or_equal_approx(cur_seek_pos, 0)) {
1070
pi.time = cur_seek_pos;
1071
pi.seeked = true;
1072
pi.is_external_seeking = explicit_elapse;
1073
set_parameter(seek_pos_request, -1.0); // Reset.
1074
}
1075
1076
return blend_input(0, pi, FILTER_IGNORE, true, p_test_only);
1077
}
1078
1079
AnimationNodeTimeSeek::AnimationNodeTimeSeek() {
1080
add_input("in");
1081
}
1082
1083
void AnimationNodeTimeSeek::_bind_methods() {
1084
ClassDB::bind_method(D_METHOD("set_explicit_elapse", "enable"), &AnimationNodeTimeSeek::set_explicit_elapse);
1085
ClassDB::bind_method(D_METHOD("is_explicit_elapse"), &AnimationNodeTimeSeek::is_explicit_elapse);
1086
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "explicit_elapse"), "set_explicit_elapse", "is_explicit_elapse");
1087
}
1088
1089
/////////////////////////////////////////////////
1090
1091
bool AnimationNodeTransition::_set(const StringName &p_path, const Variant &p_value) {
1092
String path = p_path;
1093
1094
if (!path.begins_with("input_")) {
1095
return false;
1096
}
1097
1098
int which = path.get_slicec('/', 0).get_slicec('_', 1).to_int();
1099
String what = path.get_slicec('/', 1);
1100
1101
if (which == get_input_count() && what == "name") {
1102
if (add_input(p_value)) {
1103
return true;
1104
}
1105
return false;
1106
}
1107
1108
ERR_FAIL_INDEX_V(which, get_input_count(), false);
1109
1110
if (what == "name") {
1111
set_input_name(which, p_value);
1112
} else if (what == "auto_advance") {
1113
set_input_as_auto_advance(which, p_value);
1114
} else if (what == "break_loop_at_end") {
1115
set_input_break_loop_at_end(which, p_value);
1116
} else if (what == "reset") {
1117
set_input_reset(which, p_value);
1118
} else {
1119
return false;
1120
}
1121
1122
return true;
1123
}
1124
1125
bool AnimationNodeTransition::_get(const StringName &p_path, Variant &r_ret) const {
1126
String path = p_path;
1127
1128
if (!path.begins_with("input_")) {
1129
return false;
1130
}
1131
1132
int which = path.get_slicec('/', 0).get_slicec('_', 1).to_int();
1133
String what = path.get_slicec('/', 1);
1134
1135
ERR_FAIL_INDEX_V(which, get_input_count(), false);
1136
1137
if (what == "name") {
1138
r_ret = get_input_name(which);
1139
} else if (what == "auto_advance") {
1140
r_ret = is_input_set_as_auto_advance(which);
1141
} else if (what == "break_loop_at_end") {
1142
r_ret = is_input_loop_broken_at_end(which);
1143
} else if (what == "reset") {
1144
r_ret = is_input_reset(which);
1145
} else {
1146
return false;
1147
}
1148
1149
return true;
1150
}
1151
1152
void AnimationNodeTransition::get_parameter_list(List<PropertyInfo> *r_list) const {
1153
AnimationNode::get_parameter_list(r_list);
1154
String anims;
1155
for (int i = 0; i < get_input_count(); i++) {
1156
if (i > 0) {
1157
anims += ",";
1158
}
1159
anims += inputs[i].name;
1160
}
1161
1162
r_list->push_back(PropertyInfo(Variant::STRING, current_state, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_READ_ONLY)); // For interface.
1163
r_list->push_back(PropertyInfo(Variant::STRING, transition_request, PROPERTY_HINT_ENUM, anims)); // For transition request. It will be cleared after setting the value immediately.
1164
r_list->push_back(PropertyInfo(Variant::INT, current_index, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_READ_ONLY)); // To avoid finding the index every frame, use this internally.
1165
r_list->push_back(PropertyInfo(Variant::INT, prev_index, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE));
1166
r_list->push_back(PropertyInfo(Variant::FLOAT, prev_xfading, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE));
1167
}
1168
1169
Variant AnimationNodeTransition::get_parameter_default_value(const StringName &p_parameter) const {
1170
Variant ret = AnimationNode::get_parameter_default_value(p_parameter);
1171
if (ret != Variant()) {
1172
return ret;
1173
}
1174
1175
if (p_parameter == prev_xfading) {
1176
return 0.0;
1177
} else if (p_parameter == prev_index || p_parameter == current_index) {
1178
return (int)-1;
1179
} else {
1180
return String();
1181
}
1182
}
1183
1184
bool AnimationNodeTransition::is_parameter_read_only(const StringName &p_parameter) const {
1185
if (AnimationNode::is_parameter_read_only(p_parameter)) {
1186
return true;
1187
}
1188
1189
if (p_parameter == current_state || p_parameter == current_index) {
1190
return true;
1191
}
1192
return false;
1193
}
1194
1195
String AnimationNodeTransition::get_caption() const {
1196
return "Transition";
1197
}
1198
1199
void AnimationNodeTransition::set_input_count(int p_inputs) {
1200
for (int i = get_input_count(); i < p_inputs; i++) {
1201
add_input("state_" + itos(i));
1202
}
1203
while (get_input_count() > p_inputs) {
1204
remove_input(get_input_count() - 1);
1205
}
1206
1207
pending_update = true;
1208
1209
emit_signal(SNAME("tree_changed")); // For updating connect activity map.
1210
notify_property_list_changed();
1211
}
1212
1213
bool AnimationNodeTransition::add_input(const String &p_name) {
1214
if (AnimationNode::add_input(p_name)) {
1215
input_data.push_back(InputData());
1216
return true;
1217
}
1218
return false;
1219
}
1220
1221
void AnimationNodeTransition::remove_input(int p_index) {
1222
input_data.remove_at(p_index);
1223
AnimationNode::remove_input(p_index);
1224
}
1225
1226
bool AnimationNodeTransition::set_input_name(int p_input, const String &p_name) {
1227
pending_update = true;
1228
if (!AnimationNode::set_input_name(p_input, p_name)) {
1229
return false;
1230
}
1231
emit_signal(SNAME("tree_changed")); // For updating enum options.
1232
return true;
1233
}
1234
1235
void AnimationNodeTransition::set_input_as_auto_advance(int p_input, bool p_enable) {
1236
ERR_FAIL_INDEX(p_input, get_input_count());
1237
input_data[p_input].auto_advance = p_enable;
1238
}
1239
1240
bool AnimationNodeTransition::is_input_set_as_auto_advance(int p_input) const {
1241
ERR_FAIL_INDEX_V(p_input, get_input_count(), false);
1242
return input_data[p_input].auto_advance;
1243
}
1244
1245
void AnimationNodeTransition::set_input_break_loop_at_end(int p_input, bool p_enable) {
1246
ERR_FAIL_INDEX(p_input, get_input_count());
1247
input_data[p_input].break_loop_at_end = p_enable;
1248
}
1249
1250
bool AnimationNodeTransition::is_input_loop_broken_at_end(int p_input) const {
1251
ERR_FAIL_INDEX_V(p_input, get_input_count(), false);
1252
return input_data[p_input].break_loop_at_end;
1253
}
1254
1255
void AnimationNodeTransition::set_input_reset(int p_input, bool p_enable) {
1256
ERR_FAIL_INDEX(p_input, get_input_count());
1257
input_data[p_input].reset = p_enable;
1258
}
1259
1260
bool AnimationNodeTransition::is_input_reset(int p_input) const {
1261
ERR_FAIL_INDEX_V(p_input, get_input_count(), true);
1262
return input_data[p_input].reset;
1263
}
1264
1265
void AnimationNodeTransition::set_xfade_time(double p_fade) {
1266
xfade_time = p_fade;
1267
}
1268
1269
double AnimationNodeTransition::get_xfade_time() const {
1270
return xfade_time;
1271
}
1272
1273
void AnimationNodeTransition::set_xfade_curve(const Ref<Curve> &p_curve) {
1274
xfade_curve = p_curve;
1275
}
1276
1277
Ref<Curve> AnimationNodeTransition::get_xfade_curve() const {
1278
return xfade_curve;
1279
}
1280
1281
void AnimationNodeTransition::set_allow_transition_to_self(bool p_enable) {
1282
allow_transition_to_self = p_enable;
1283
}
1284
1285
bool AnimationNodeTransition::is_allow_transition_to_self() const {
1286
return allow_transition_to_self;
1287
}
1288
1289
AnimationNode::NodeTimeInfo AnimationNodeTransition::_process(const AnimationMixer::PlaybackInfo p_playback_info, bool p_test_only) {
1290
String cur_transition_request = get_parameter(transition_request);
1291
int cur_current_index = get_parameter(current_index);
1292
int cur_prev_index = get_parameter(prev_index);
1293
1294
NodeTimeInfo cur_nti = get_node_time_info();
1295
double cur_prev_xfading = get_parameter(prev_xfading);
1296
1297
bool switched = false;
1298
bool restart = false;
1299
bool clear_remaining_fade = false;
1300
1301
if (pending_update) {
1302
if (cur_current_index < 0 || cur_current_index >= get_input_count()) {
1303
set_parameter(prev_index, -1);
1304
if (get_input_count() > 0) {
1305
set_parameter(current_index, 0);
1306
set_parameter(current_state, get_input_name(0));
1307
} else {
1308
set_parameter(current_index, -1);
1309
set_parameter(current_state, StringName());
1310
}
1311
} else {
1312
set_parameter(current_state, get_input_name(cur_current_index));
1313
}
1314
pending_update = false;
1315
}
1316
1317
double p_time = p_playback_info.time;
1318
bool p_seek = p_playback_info.seeked;
1319
bool p_is_external_seeking = p_playback_info.is_external_seeking;
1320
1321
if (Math::is_zero_approx(p_time) && p_seek && !p_is_external_seeking) {
1322
clear_remaining_fade = true; // Reset occurs.
1323
}
1324
1325
if (!cur_transition_request.is_empty()) {
1326
int new_idx = find_input(cur_transition_request);
1327
if (new_idx >= 0) {
1328
if (cur_current_index == new_idx) {
1329
if (allow_transition_to_self) {
1330
// Transition to same state.
1331
restart = input_data[cur_current_index].reset;
1332
clear_remaining_fade = true;
1333
}
1334
} else {
1335
switched = true;
1336
cur_prev_index = cur_current_index;
1337
set_parameter(prev_index, cur_current_index);
1338
cur_current_index = new_idx;
1339
set_parameter(current_index, cur_current_index);
1340
set_parameter(current_state, cur_transition_request);
1341
}
1342
} else {
1343
ERR_PRINT("No such input: '" + cur_transition_request + "'");
1344
}
1345
cur_transition_request = String();
1346
set_parameter(transition_request, cur_transition_request);
1347
}
1348
1349
if (clear_remaining_fade) {
1350
cur_prev_xfading = 0;
1351
set_parameter(prev_xfading, 0);
1352
cur_prev_index = -1;
1353
set_parameter(prev_index, -1);
1354
}
1355
1356
AnimationMixer::PlaybackInfo pi = p_playback_info;
1357
1358
// Special case for restart.
1359
if (restart) {
1360
pi.time = 0;
1361
pi.seeked = true;
1362
pi.weight = 1.0;
1363
return blend_input(cur_current_index, pi, FILTER_IGNORE, true, p_test_only);
1364
}
1365
1366
if (switched) {
1367
cur_prev_xfading = xfade_time;
1368
}
1369
1370
if (cur_current_index < 0 || cur_current_index >= get_input_count() || cur_prev_index >= get_input_count()) {
1371
return NodeTimeInfo();
1372
}
1373
1374
if (sync) {
1375
pi.weight = 0;
1376
for (int i = 0; i < get_input_count(); i++) {
1377
if (i != cur_current_index && i != cur_prev_index) {
1378
blend_input(i, pi, FILTER_IGNORE, true, p_test_only);
1379
}
1380
}
1381
}
1382
1383
if (cur_prev_index < 0) { // Process current animation, check for transition.
1384
pi.weight = 1.0;
1385
cur_nti = blend_input(cur_current_index, pi, FILTER_IGNORE, true, p_test_only);
1386
if (input_data[cur_current_index].auto_advance && Animation::is_less_or_equal_approx(cur_nti.get_remain(input_data[cur_current_index].break_loop_at_end), xfade_time)) {
1387
set_parameter(transition_request, get_input_name((cur_current_index + 1) % get_input_count()));
1388
}
1389
} else { // Cross-fading from prev to current.
1390
1391
real_t blend = 0.0;
1392
real_t blend_inv = 1.0;
1393
bool use_blend = sync;
1394
if (xfade_time > 0) {
1395
use_blend = true;
1396
blend = cur_prev_xfading / xfade_time;
1397
if (xfade_curve.is_valid()) {
1398
blend = xfade_curve->sample(blend);
1399
}
1400
blend_inv = 1.0 - blend;
1401
blend = Math::is_zero_approx(blend) ? CMP_EPSILON : blend;
1402
blend_inv = Math::is_zero_approx(blend_inv) ? CMP_EPSILON : blend_inv;
1403
}
1404
1405
// Blend values must be more than CMP_EPSILON to process discrete keys in edge.
1406
pi.weight = blend_inv;
1407
if (input_data[cur_current_index].reset && !p_seek && switched) { // Just switched, seek to start of current.
1408
pi.time = 0;
1409
pi.seeked = true;
1410
}
1411
cur_nti = blend_input(cur_current_index, pi, FILTER_IGNORE, true, p_test_only);
1412
1413
pi = p_playback_info;
1414
pi.seeked &= use_blend;
1415
pi.weight = blend;
1416
blend_input(cur_prev_index, pi, FILTER_IGNORE, true, p_test_only);
1417
if (!p_seek) {
1418
if (Animation::is_less_or_equal_approx(cur_prev_xfading, 0)) {
1419
set_parameter(prev_index, -1);
1420
}
1421
cur_prev_xfading -= Math::abs(p_playback_info.delta);
1422
}
1423
}
1424
1425
set_parameter(prev_xfading, cur_prev_xfading);
1426
1427
return cur_nti;
1428
}
1429
1430
void AnimationNodeTransition::_get_property_list(List<PropertyInfo> *p_list) const {
1431
for (int i = 0; i < get_input_count(); i++) {
1432
p_list->push_back(PropertyInfo(Variant::STRING, "input_" + itos(i) + "/name", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_INTERNAL));
1433
p_list->push_back(PropertyInfo(Variant::BOOL, "input_" + itos(i) + "/auto_advance", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_INTERNAL));
1434
p_list->push_back(PropertyInfo(Variant::BOOL, "input_" + itos(i) + "/break_loop_at_end", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_INTERNAL));
1435
p_list->push_back(PropertyInfo(Variant::BOOL, "input_" + itos(i) + "/reset", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_INTERNAL));
1436
}
1437
}
1438
1439
void AnimationNodeTransition::_bind_methods() {
1440
ClassDB::bind_method(D_METHOD("set_input_count", "input_count"), &AnimationNodeTransition::set_input_count);
1441
1442
ClassDB::bind_method(D_METHOD("set_input_as_auto_advance", "input", "enable"), &AnimationNodeTransition::set_input_as_auto_advance);
1443
ClassDB::bind_method(D_METHOD("is_input_set_as_auto_advance", "input"), &AnimationNodeTransition::is_input_set_as_auto_advance);
1444
1445
ClassDB::bind_method(D_METHOD("set_input_break_loop_at_end", "input", "enable"), &AnimationNodeTransition::set_input_break_loop_at_end);
1446
ClassDB::bind_method(D_METHOD("is_input_loop_broken_at_end", "input"), &AnimationNodeTransition::is_input_loop_broken_at_end);
1447
1448
ClassDB::bind_method(D_METHOD("set_input_reset", "input", "enable"), &AnimationNodeTransition::set_input_reset);
1449
ClassDB::bind_method(D_METHOD("is_input_reset", "input"), &AnimationNodeTransition::is_input_reset);
1450
1451
ClassDB::bind_method(D_METHOD("set_xfade_time", "time"), &AnimationNodeTransition::set_xfade_time);
1452
ClassDB::bind_method(D_METHOD("get_xfade_time"), &AnimationNodeTransition::get_xfade_time);
1453
1454
ClassDB::bind_method(D_METHOD("set_xfade_curve", "curve"), &AnimationNodeTransition::set_xfade_curve);
1455
ClassDB::bind_method(D_METHOD("get_xfade_curve"), &AnimationNodeTransition::get_xfade_curve);
1456
1457
ClassDB::bind_method(D_METHOD("set_allow_transition_to_self", "enable"), &AnimationNodeTransition::set_allow_transition_to_self);
1458
ClassDB::bind_method(D_METHOD("is_allow_transition_to_self"), &AnimationNodeTransition::is_allow_transition_to_self);
1459
1460
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "xfade_time", PROPERTY_HINT_RANGE, "0,120,0.01,suffix:s"), "set_xfade_time", "get_xfade_time");
1461
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "xfade_curve", PROPERTY_HINT_RESOURCE_TYPE, Curve::get_class_static()), "set_xfade_curve", "get_xfade_curve");
1462
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "allow_transition_to_self"), "set_allow_transition_to_self", "is_allow_transition_to_self");
1463
ADD_PROPERTY(PropertyInfo(Variant::INT, "input_count", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_ARRAY | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED, "Inputs,input_"), "set_input_count", "get_input_count");
1464
}
1465
1466
AnimationNodeTransition::AnimationNodeTransition() {
1467
}
1468
1469
/////////////////////
1470
1471
String AnimationNodeOutput::get_caption() const {
1472
return "Output";
1473
}
1474
1475
AnimationNode::NodeTimeInfo AnimationNodeOutput::_process(const AnimationMixer::PlaybackInfo p_playback_info, bool p_test_only) {
1476
AnimationMixer::PlaybackInfo pi = p_playback_info;
1477
pi.weight = 1.0;
1478
return blend_input(0, pi, FILTER_IGNORE, true, p_test_only);
1479
}
1480
1481
AnimationNodeOutput::AnimationNodeOutput() {
1482
add_input("output");
1483
}
1484
1485
///////////////////////////////////////////////////////
1486
void AnimationNodeBlendTree::add_node(const StringName &p_name, Ref<AnimationNode> p_node, const Vector2 &p_position) {
1487
ERR_FAIL_COND(nodes.has(p_name));
1488
ERR_FAIL_COND(p_node.is_null());
1489
ERR_FAIL_COND(p_name == SceneStringName(output));
1490
ERR_FAIL_COND(String(p_name).contains_char('/'));
1491
1492
Node n;
1493
n.node = p_node;
1494
n.position = p_position;
1495
n.connections.resize(n.node->get_input_count());
1496
nodes[p_name] = n;
1497
1498
emit_changed();
1499
emit_signal(SNAME("tree_changed"));
1500
1501
p_node->connect(SNAME("tree_changed"), callable_mp(this, &AnimationNodeBlendTree::_tree_changed), CONNECT_REFERENCE_COUNTED);
1502
p_node->connect(SNAME("animation_node_renamed"), callable_mp(this, &AnimationNodeBlendTree::_animation_node_renamed), CONNECT_REFERENCE_COUNTED);
1503
p_node->connect(SNAME("animation_node_removed"), callable_mp(this, &AnimationNodeBlendTree::_animation_node_removed), CONNECT_REFERENCE_COUNTED);
1504
p_node->connect_changed(callable_mp(this, &AnimationNodeBlendTree::_node_changed).bind(p_name), CONNECT_REFERENCE_COUNTED);
1505
}
1506
1507
Ref<AnimationNode> AnimationNodeBlendTree::get_node(const StringName &p_name) const {
1508
ERR_FAIL_COND_V(!nodes.has(p_name), Ref<AnimationNode>());
1509
1510
return nodes[p_name].node;
1511
}
1512
1513
StringName AnimationNodeBlendTree::get_node_name(const Ref<AnimationNode> &p_node) const {
1514
for (const KeyValue<StringName, Node> &E : nodes) {
1515
if (E.value.node == p_node) {
1516
return E.key;
1517
}
1518
}
1519
1520
ERR_FAIL_V(StringName());
1521
}
1522
1523
void AnimationNodeBlendTree::set_node_position(const StringName &p_node, const Vector2 &p_position) {
1524
ERR_FAIL_COND(!nodes.has(p_node));
1525
nodes[p_node].position = p_position;
1526
}
1527
1528
Vector2 AnimationNodeBlendTree::get_node_position(const StringName &p_node) const {
1529
ERR_FAIL_COND_V(!nodes.has(p_node), Vector2());
1530
return nodes[p_node].position;
1531
}
1532
1533
void AnimationNodeBlendTree::get_child_nodes(List<ChildNode> *r_child_nodes) {
1534
Vector<StringName> ns;
1535
1536
for (const KeyValue<StringName, Node> &E : nodes) {
1537
ns.push_back(E.key);
1538
}
1539
1540
for (int i = 0; i < ns.size(); i++) {
1541
ChildNode cn;
1542
cn.name = ns[i];
1543
cn.node = nodes[cn.name].node;
1544
r_child_nodes->push_back(cn);
1545
}
1546
}
1547
1548
bool AnimationNodeBlendTree::has_node(const StringName &p_name) const {
1549
return nodes.has(p_name);
1550
}
1551
1552
Vector<StringName> AnimationNodeBlendTree::get_node_connection_array(const StringName &p_name) const {
1553
ERR_FAIL_COND_V(!nodes.has(p_name), Vector<StringName>());
1554
return nodes[p_name].connections;
1555
}
1556
1557
void AnimationNodeBlendTree::remove_node(const StringName &p_name) {
1558
ERR_FAIL_COND(!nodes.has(p_name));
1559
ERR_FAIL_COND(p_name == SceneStringName(output)); //can't delete output
1560
1561
{
1562
Ref<AnimationNode> node = nodes[p_name].node;
1563
node->disconnect(SNAME("tree_changed"), callable_mp(this, &AnimationNodeBlendTree::_tree_changed));
1564
node->disconnect(SNAME("animation_node_renamed"), callable_mp(this, &AnimationNodeBlendTree::_animation_node_renamed));
1565
node->disconnect(SNAME("animation_node_removed"), callable_mp(this, &AnimationNodeBlendTree::_animation_node_removed));
1566
node->disconnect_changed(callable_mp(this, &AnimationNodeBlendTree::_node_changed));
1567
}
1568
1569
nodes.erase(p_name);
1570
1571
// Erase connections to name.
1572
for (KeyValue<StringName, Node> &E : nodes) {
1573
for (int i = 0; i < E.value.connections.size(); i++) {
1574
if (E.value.connections[i] == p_name) {
1575
E.value.connections.write[i] = StringName();
1576
}
1577
}
1578
}
1579
1580
emit_signal(SNAME("animation_node_removed"), get_instance_id(), p_name);
1581
emit_changed();
1582
emit_signal(SNAME("tree_changed"));
1583
}
1584
1585
void AnimationNodeBlendTree::rename_node(const StringName &p_name, const StringName &p_new_name) {
1586
ERR_FAIL_COND(!nodes.has(p_name));
1587
ERR_FAIL_COND(nodes.has(p_new_name));
1588
ERR_FAIL_COND(p_name == SceneStringName(output));
1589
ERR_FAIL_COND(p_new_name == SceneStringName(output));
1590
1591
nodes[p_name].node->disconnect_changed(callable_mp(this, &AnimationNodeBlendTree::_node_changed));
1592
1593
const Node temp_copy = nodes[p_name];
1594
nodes[p_new_name] = temp_copy; // might realloc
1595
nodes.erase(p_name);
1596
1597
// Rename connections.
1598
for (KeyValue<StringName, Node> &E : nodes) {
1599
for (int i = 0; i < E.value.connections.size(); i++) {
1600
if (E.value.connections[i] == p_name) {
1601
E.value.connections.write[i] = p_new_name;
1602
}
1603
}
1604
}
1605
// Connection must be done with new name.
1606
nodes[p_new_name].node->connect_changed(callable_mp(this, &AnimationNodeBlendTree::_node_changed).bind(p_new_name), CONNECT_REFERENCE_COUNTED);
1607
1608
emit_signal(SNAME("animation_node_renamed"), get_instance_id(), p_name, p_new_name);
1609
emit_signal(SNAME("tree_changed"));
1610
}
1611
1612
void AnimationNodeBlendTree::connect_node(const StringName &p_input_node, int p_input_index, const StringName &p_output_node) {
1613
ERR_FAIL_COND(!nodes.has(p_output_node));
1614
ERR_FAIL_COND(!nodes.has(p_input_node));
1615
ERR_FAIL_COND(p_output_node == SceneStringName(output));
1616
ERR_FAIL_COND(p_input_node == p_output_node);
1617
1618
Ref<AnimationNode> input = nodes[p_input_node].node;
1619
ERR_FAIL_INDEX(p_input_index, nodes[p_input_node].connections.size());
1620
1621
for (KeyValue<StringName, Node> &E : nodes) {
1622
for (int i = 0; i < E.value.connections.size(); i++) {
1623
StringName output = E.value.connections[i];
1624
ERR_FAIL_COND(output == p_output_node);
1625
}
1626
}
1627
1628
nodes[p_input_node].connections.write[p_input_index] = p_output_node;
1629
1630
emit_changed();
1631
}
1632
1633
void AnimationNodeBlendTree::disconnect_node(const StringName &p_node, int p_input_index) {
1634
ERR_FAIL_COND(!nodes.has(p_node));
1635
1636
Ref<AnimationNode> input = nodes[p_node].node;
1637
ERR_FAIL_INDEX(p_input_index, nodes[p_node].connections.size());
1638
1639
nodes[p_node].connections.write[p_input_index] = StringName();
1640
}
1641
1642
AnimationNodeBlendTree::ConnectionError AnimationNodeBlendTree::can_connect_node(const StringName &p_input_node, int p_input_index, const StringName &p_output_node) const {
1643
if (!nodes.has(p_output_node) || p_output_node == SceneStringName(output)) {
1644
return CONNECTION_ERROR_NO_OUTPUT;
1645
}
1646
1647
if (!nodes.has(p_input_node)) {
1648
return CONNECTION_ERROR_NO_INPUT;
1649
}
1650
1651
if (p_input_node == p_output_node) {
1652
return CONNECTION_ERROR_SAME_NODE;
1653
}
1654
1655
Ref<AnimationNode> input = nodes[p_input_node].node;
1656
1657
if (p_input_index < 0 || p_input_index >= nodes[p_input_node].connections.size()) {
1658
return CONNECTION_ERROR_NO_INPUT_INDEX;
1659
}
1660
1661
if (nodes[p_input_node].connections[p_input_index] != StringName()) {
1662
return CONNECTION_ERROR_CONNECTION_EXISTS;
1663
}
1664
1665
for (const KeyValue<StringName, Node> &E : nodes) {
1666
for (int i = 0; i < E.value.connections.size(); i++) {
1667
const StringName output = E.value.connections[i];
1668
if (output == p_output_node) {
1669
return CONNECTION_ERROR_CONNECTION_EXISTS;
1670
}
1671
}
1672
}
1673
return CONNECTION_OK;
1674
}
1675
1676
void AnimationNodeBlendTree::get_node_connections(List<NodeConnection> *r_connections) const {
1677
for (const KeyValue<StringName, Node> &E : nodes) {
1678
for (int i = 0; i < E.value.connections.size(); i++) {
1679
const StringName output = E.value.connections[i];
1680
if (output != StringName()) {
1681
NodeConnection nc;
1682
nc.input_node = E.key;
1683
nc.input_index = i;
1684
nc.output_node = output;
1685
r_connections->push_back(nc);
1686
}
1687
}
1688
}
1689
}
1690
1691
String AnimationNodeBlendTree::get_caption() const {
1692
return "BlendTree";
1693
}
1694
1695
AnimationNode::NodeTimeInfo AnimationNodeBlendTree::_process(const AnimationMixer::PlaybackInfo p_playback_info, bool p_test_only) {
1696
Ref<AnimationNodeOutput> output = nodes[SceneStringName(output)].node;
1697
node_state.connections = nodes[SceneStringName(output)].connections;
1698
ERR_FAIL_COND_V(output.is_null(), NodeTimeInfo());
1699
1700
AnimationMixer::PlaybackInfo pi = p_playback_info;
1701
pi.weight = 1.0;
1702
1703
return _blend_node(output, "output", this, pi, FILTER_IGNORE, true, p_test_only, nullptr);
1704
}
1705
1706
LocalVector<StringName> AnimationNodeBlendTree::get_node_list() const {
1707
LocalVector<StringName> list;
1708
list.reserve(nodes.size());
1709
for (const KeyValue<StringName, Node> &E : nodes) {
1710
list.push_back(E.key);
1711
}
1712
list.sort_custom<StringName::AlphCompare>();
1713
return list;
1714
}
1715
1716
TypedArray<StringName> AnimationNodeBlendTree::get_node_list_as_typed_array() const {
1717
TypedArray<StringName> typed_arr;
1718
LocalVector<StringName> vec = get_node_list();
1719
typed_arr.resize(vec.size());
1720
for (uint32_t i = 0; i < vec.size(); i++) {
1721
typed_arr[i] = vec[i];
1722
}
1723
return typed_arr;
1724
}
1725
1726
void AnimationNodeBlendTree::set_graph_offset(const Vector2 &p_graph_offset) {
1727
graph_offset = p_graph_offset;
1728
}
1729
1730
Vector2 AnimationNodeBlendTree::get_graph_offset() const {
1731
return graph_offset;
1732
}
1733
1734
Ref<AnimationNode> AnimationNodeBlendTree::get_child_by_name(const StringName &p_name) const {
1735
return get_node(p_name);
1736
}
1737
1738
bool AnimationNodeBlendTree::_set(const StringName &p_name, const Variant &p_value) {
1739
String prop_name = p_name;
1740
if (prop_name.begins_with("nodes/")) {
1741
String node_name = prop_name.get_slicec('/', 1);
1742
String what = prop_name.get_slicec('/', 2);
1743
1744
if (what == "node") {
1745
Ref<AnimationNode> anode = p_value;
1746
if (anode.is_valid()) {
1747
add_node(node_name, p_value);
1748
}
1749
return true;
1750
}
1751
1752
if (what == "position") {
1753
if (nodes.has(node_name)) {
1754
nodes[node_name].position = p_value;
1755
}
1756
return true;
1757
}
1758
} else if (prop_name == "node_connections") {
1759
Array conns = p_value;
1760
ERR_FAIL_COND_V(conns.size() % 3 != 0, false);
1761
1762
for (int i = 0; i < conns.size(); i += 3) {
1763
connect_node(conns[i], conns[i + 1], conns[i + 2]);
1764
}
1765
return true;
1766
}
1767
1768
return false;
1769
}
1770
1771
bool AnimationNodeBlendTree::_get(const StringName &p_name, Variant &r_ret) const {
1772
String prop_name = p_name;
1773
if (prop_name.begins_with("nodes/")) {
1774
String node_name = prop_name.get_slicec('/', 1);
1775
String what = prop_name.get_slicec('/', 2);
1776
1777
if (what == "node") {
1778
if (nodes.has(node_name)) {
1779
r_ret = nodes[node_name].node;
1780
return true;
1781
}
1782
}
1783
1784
if (what == "position") {
1785
if (nodes.has(node_name)) {
1786
r_ret = nodes[node_name].position;
1787
return true;
1788
}
1789
}
1790
} else if (prop_name == "node_connections") {
1791
List<NodeConnection> nc;
1792
get_node_connections(&nc);
1793
Array conns;
1794
conns.resize(nc.size() * 3);
1795
1796
int idx = 0;
1797
for (const NodeConnection &E : nc) {
1798
conns[idx * 3 + 0] = E.input_node;
1799
conns[idx * 3 + 1] = E.input_index;
1800
conns[idx * 3 + 2] = E.output_node;
1801
idx++;
1802
}
1803
1804
r_ret = conns;
1805
return true;
1806
}
1807
1808
return false;
1809
}
1810
1811
void AnimationNodeBlendTree::_get_property_list(List<PropertyInfo> *p_list) const {
1812
List<StringName> names;
1813
for (const KeyValue<StringName, Node> &E : nodes) {
1814
names.push_back(E.key);
1815
}
1816
1817
for (const StringName &E : names) {
1818
String prop_name = E;
1819
if (prop_name != "output") {
1820
p_list->push_back(PropertyInfo(Variant::OBJECT, "nodes/" + prop_name + "/node", PROPERTY_HINT_RESOURCE_TYPE, AnimationNode::get_class_static(), PROPERTY_USAGE_NO_EDITOR));
1821
}
1822
p_list->push_back(PropertyInfo(Variant::VECTOR2, "nodes/" + prop_name + "/position", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR));
1823
}
1824
1825
p_list->push_back(PropertyInfo(Variant::ARRAY, "node_connections", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR));
1826
}
1827
1828
void AnimationNodeBlendTree::_tree_changed() {
1829
AnimationRootNode::_tree_changed();
1830
}
1831
1832
void AnimationNodeBlendTree::_animation_node_renamed(const ObjectID &p_oid, const String &p_old_name, const String &p_new_name) {
1833
AnimationRootNode::_animation_node_renamed(p_oid, p_old_name, p_new_name);
1834
}
1835
1836
void AnimationNodeBlendTree::_animation_node_removed(const ObjectID &p_oid, const StringName &p_node) {
1837
AnimationRootNode::_animation_node_removed(p_oid, p_node);
1838
}
1839
1840
void AnimationNodeBlendTree::reset_state() {
1841
graph_offset = Vector2();
1842
nodes.clear();
1843
_initialize_node_tree();
1844
emit_changed();
1845
emit_signal(SNAME("tree_changed"));
1846
}
1847
1848
void AnimationNodeBlendTree::_node_changed(const StringName &p_node) {
1849
ERR_FAIL_COND(!nodes.has(p_node));
1850
nodes[p_node].connections.resize(nodes[p_node].node->get_input_count());
1851
emit_signal(SNAME("node_changed"), p_node);
1852
}
1853
1854
#ifdef TOOLS_ENABLED
1855
void AnimationNodeBlendTree::get_argument_options(const StringName &p_function, int p_idx, List<String> *r_options) const {
1856
const String pf = p_function;
1857
bool add_node_options = false;
1858
if (p_idx == 0) {
1859
add_node_options = (pf == "get_node" || pf == "has_node" || pf == "rename_node" || pf == "remove_node" || pf == "set_node_position" || pf == "get_node_position" || pf == "connect_node" || pf == "disconnect_node");
1860
} else if (p_idx == 2) {
1861
add_node_options = (pf == "connect_node" || pf == "disconnect_node");
1862
}
1863
if (add_node_options) {
1864
for (const KeyValue<StringName, Node> &E : nodes) {
1865
r_options->push_back(String(E.key).quote());
1866
}
1867
}
1868
AnimationRootNode::get_argument_options(p_function, p_idx, r_options);
1869
}
1870
#endif
1871
1872
void AnimationNodeBlendTree::_bind_methods() {
1873
ClassDB::bind_method(D_METHOD("add_node", "name", "node", "position"), &AnimationNodeBlendTree::add_node, DEFVAL(Vector2()));
1874
ClassDB::bind_method(D_METHOD("get_node", "name"), &AnimationNodeBlendTree::get_node);
1875
ClassDB::bind_method(D_METHOD("remove_node", "name"), &AnimationNodeBlendTree::remove_node);
1876
ClassDB::bind_method(D_METHOD("rename_node", "name", "new_name"), &AnimationNodeBlendTree::rename_node);
1877
ClassDB::bind_method(D_METHOD("has_node", "name"), &AnimationNodeBlendTree::has_node);
1878
ClassDB::bind_method(D_METHOD("connect_node", "input_node", "input_index", "output_node"), &AnimationNodeBlendTree::connect_node);
1879
ClassDB::bind_method(D_METHOD("disconnect_node", "input_node", "input_index"), &AnimationNodeBlendTree::disconnect_node);
1880
ClassDB::bind_method(D_METHOD("get_node_list"), &AnimationNodeBlendTree::get_node_list_as_typed_array);
1881
1882
ClassDB::bind_method(D_METHOD("set_node_position", "name", "position"), &AnimationNodeBlendTree::set_node_position);
1883
ClassDB::bind_method(D_METHOD("get_node_position", "name"), &AnimationNodeBlendTree::get_node_position);
1884
1885
ClassDB::bind_method(D_METHOD("set_graph_offset", "offset"), &AnimationNodeBlendTree::set_graph_offset);
1886
ClassDB::bind_method(D_METHOD("get_graph_offset"), &AnimationNodeBlendTree::get_graph_offset);
1887
1888
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "graph_offset", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), "set_graph_offset", "get_graph_offset");
1889
1890
BIND_CONSTANT(CONNECTION_OK);
1891
BIND_CONSTANT(CONNECTION_ERROR_NO_INPUT);
1892
BIND_CONSTANT(CONNECTION_ERROR_NO_INPUT_INDEX);
1893
BIND_CONSTANT(CONNECTION_ERROR_NO_OUTPUT);
1894
BIND_CONSTANT(CONNECTION_ERROR_SAME_NODE);
1895
BIND_CONSTANT(CONNECTION_ERROR_CONNECTION_EXISTS);
1896
1897
ADD_SIGNAL(MethodInfo(SNAME("node_changed"), PropertyInfo(Variant::STRING_NAME, "node_name")));
1898
}
1899
1900
void AnimationNodeBlendTree::_initialize_node_tree() {
1901
Ref<AnimationNodeOutput> output;
1902
output.instantiate();
1903
Node n;
1904
n.node = output;
1905
n.position = Vector2(300, 150);
1906
n.connections.resize(1);
1907
nodes["output"] = n;
1908
}
1909
1910
AnimationNodeBlendTree::AnimationNodeBlendTree() {
1911
_initialize_node_tree();
1912
}
1913
1914
AnimationNodeBlendTree::~AnimationNodeBlendTree() {
1915
}
1916
1917