Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
godotengine
GitHub Repository: godotengine/godot
Path: blob/master/scene/animation/animation_tree.cpp
20931 views
1
/**************************************************************************/
2
/* animation_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_tree.h"
32
#include "animation_tree.compat.inc"
33
34
#include "animation_blend_tree.h"
35
#include "scene/animation/animation_player.h"
36
37
void AnimationNode::get_parameter_list(List<PropertyInfo> *r_list) const {
38
Array parameters;
39
40
if (GDVIRTUAL_CALL(_get_parameter_list, parameters)) {
41
for (int i = 0; i < parameters.size(); i++) {
42
Dictionary d = parameters[i];
43
ERR_CONTINUE(d.is_empty());
44
r_list->push_back(PropertyInfo::from_dict(d));
45
}
46
}
47
48
r_list->push_back(PropertyInfo(Variant::FLOAT, current_length, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_READ_ONLY));
49
r_list->push_back(PropertyInfo(Variant::FLOAT, current_position, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_READ_ONLY));
50
r_list->push_back(PropertyInfo(Variant::FLOAT, current_delta, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_READ_ONLY));
51
}
52
53
Variant AnimationNode::get_parameter_default_value(const StringName &p_parameter) const {
54
Variant ret;
55
if (p_parameter == current_length || p_parameter == current_position || p_parameter == current_delta) {
56
return 0.0;
57
}
58
GDVIRTUAL_CALL(_get_parameter_default_value, p_parameter, ret);
59
return ret;
60
}
61
62
bool AnimationNode::is_parameter_read_only(const StringName &p_parameter) const {
63
bool ret = false;
64
if (GDVIRTUAL_CALL(_is_parameter_read_only, p_parameter, ret) && ret) {
65
return true;
66
}
67
68
if (p_parameter == current_length || p_parameter == current_position || p_parameter == current_delta) {
69
return true;
70
}
71
72
return false;
73
}
74
75
void AnimationNode::set_parameter(const StringName &p_name, const Variant &p_value) {
76
ERR_FAIL_NULL(process_state);
77
if (process_state->is_testing) {
78
return;
79
}
80
81
const AHashMap<StringName, int>::Iterator it = property_cache.find(p_name);
82
if (it) {
83
Pair<Variant, bool> &prop = process_state->tree->property_map.get_by_index(it->value).value;
84
Variant value = p_value;
85
if (Animation::validate_type_match(prop.first, value)) {
86
prop.first = value;
87
}
88
return;
89
}
90
91
ERR_FAIL_COND(!process_state->tree->property_parent_map.has(node_state.base_path));
92
ERR_FAIL_COND(!process_state->tree->property_parent_map[node_state.base_path].has(p_name));
93
StringName path = process_state->tree->property_parent_map[node_state.base_path][p_name];
94
int idx = process_state->tree->property_map.get_index(path);
95
property_cache.insert_new(p_name, idx);
96
process_state->tree->property_map.get_by_index(idx).value.first = p_value;
97
}
98
99
Variant AnimationNode::get_parameter(const StringName &p_name) const {
100
ERR_FAIL_NULL_V(process_state, Variant());
101
const AHashMap<StringName, int>::ConstIterator it = property_cache.find(p_name);
102
if (it) {
103
return process_state->tree->property_map.get_by_index(it->value).value.first;
104
}
105
ERR_FAIL_COND_V(!process_state->tree->property_parent_map.has(node_state.base_path), Variant());
106
ERR_FAIL_COND_V(!process_state->tree->property_parent_map[node_state.base_path].has(p_name), Variant());
107
108
StringName path = process_state->tree->property_parent_map[node_state.base_path][p_name];
109
int idx = process_state->tree->property_map.get_index(path);
110
property_cache.insert_new(p_name, idx);
111
return process_state->tree->property_map.get_by_index(idx).value.first;
112
}
113
114
void AnimationNode::set_node_time_info(const NodeTimeInfo &p_node_time_info) {
115
set_parameter(current_length, p_node_time_info.length);
116
set_parameter(current_position, p_node_time_info.position);
117
set_parameter(current_delta, p_node_time_info.delta);
118
}
119
120
AnimationNode::NodeTimeInfo AnimationNode::get_node_time_info() const {
121
NodeTimeInfo nti;
122
nti.length = get_parameter(current_length);
123
nti.position = get_parameter(current_position);
124
nti.delta = get_parameter(current_delta);
125
return nti;
126
}
127
128
void AnimationNode::get_child_nodes(List<ChildNode> *r_child_nodes) {
129
Dictionary cn;
130
if (GDVIRTUAL_CALL(_get_child_nodes, cn)) {
131
for (const KeyValue<Variant, Variant> &kv : cn) {
132
ChildNode child;
133
child.name = kv.key;
134
child.node = kv.value;
135
r_child_nodes->push_back(child);
136
}
137
}
138
}
139
140
void AnimationNode::blend_animation(const StringName &p_animation, AnimationMixer::PlaybackInfo p_playback_info) {
141
ERR_FAIL_NULL(process_state);
142
p_playback_info.track_weights = Vector<real_t>(node_state.track_weights);
143
process_state->tree->make_animation_instance(p_animation, p_playback_info);
144
}
145
146
AnimationNode::NodeTimeInfo AnimationNode::_pre_process(ProcessState *p_process_state, AnimationMixer::PlaybackInfo p_playback_info, bool p_test_only) {
147
process_state = p_process_state;
148
NodeTimeInfo nti = process(p_playback_info, p_test_only);
149
process_state = nullptr;
150
return nti;
151
}
152
153
void AnimationNode::make_invalid(const String &p_reason) {
154
ERR_FAIL_NULL(process_state);
155
process_state->valid = false;
156
if (!process_state->invalid_reasons.is_empty()) {
157
process_state->invalid_reasons += "\n";
158
}
159
process_state->invalid_reasons += String::utf8("• ") + p_reason;
160
}
161
162
AnimationTree *AnimationNode::get_animation_tree() const {
163
ERR_FAIL_NULL_V(process_state, nullptr);
164
return process_state->tree;
165
}
166
167
AnimationNode::NodeTimeInfo AnimationNode::blend_input(int p_input, AnimationMixer::PlaybackInfo p_playback_info, FilterAction p_filter, bool p_sync, bool p_test_only) {
168
ERR_FAIL_INDEX_V(p_input, (int64_t)inputs.size(), NodeTimeInfo());
169
170
AnimationNodeBlendTree *blend_tree = Object::cast_to<AnimationNodeBlendTree>(node_state.parent);
171
ERR_FAIL_NULL_V(blend_tree, NodeTimeInfo());
172
173
// Update connections.
174
StringName current_name = blend_tree->get_node_name(Ref<AnimationNode>(this));
175
node_state.connections = blend_tree->get_node_connection_array(current_name);
176
177
// Get node which is connected input port.
178
StringName node_name = node_state.connections[p_input];
179
if (!blend_tree->has_node(node_name)) {
180
make_invalid(vformat(RTR("Nothing connected to input '%s' of node '%s'."), get_input_name(p_input), current_name));
181
return NodeTimeInfo();
182
}
183
184
Ref<AnimationNode> node = blend_tree->get_node(node_name);
185
ERR_FAIL_COND_V(node.is_null(), NodeTimeInfo());
186
187
real_t activity = 0.0;
188
LocalVector<AnimationTree::Activity> *activity_ptr = process_state->tree->input_activity_map.getptr(node_state.base_path);
189
NodeTimeInfo nti = _blend_node(node, node_name, nullptr, p_playback_info, p_filter, p_sync, p_test_only, &activity);
190
191
if (activity_ptr && p_input < (int64_t)activity_ptr->size()) {
192
(*activity_ptr)[p_input].last_pass = process_state->last_pass;
193
(*activity_ptr)[p_input].activity = activity;
194
}
195
return nti;
196
}
197
198
AnimationNode::NodeTimeInfo AnimationNode::blend_node(Ref<AnimationNode> p_node, const StringName &p_subpath, AnimationMixer::PlaybackInfo p_playback_info, FilterAction p_filter, bool p_sync, bool p_test_only) {
199
ERR_FAIL_COND_V(p_node.is_null(), NodeTimeInfo());
200
p_node->node_state.connections.clear();
201
return _blend_node(p_node, p_subpath, this, p_playback_info, p_filter, p_sync, p_test_only, nullptr);
202
}
203
204
AnimationNode::NodeTimeInfo AnimationNode::_blend_node(Ref<AnimationNode> p_node, const StringName &p_subpath, AnimationNode *p_new_parent, AnimationMixer::PlaybackInfo p_playback_info, FilterAction p_filter, bool p_sync, bool p_test_only, real_t *r_activity) {
205
ERR_FAIL_NULL_V(process_state, NodeTimeInfo());
206
207
int blend_count = node_state.track_weights.size();
208
209
if ((int64_t)p_node->node_state.track_weights.size() != blend_count) {
210
p_node->node_state.track_weights.resize(blend_count);
211
}
212
213
real_t *blendw = p_node->node_state.track_weights.ptr();
214
const real_t *blendr = node_state.track_weights.ptr();
215
216
bool any_valid = false;
217
218
if (has_filter() && is_filter_enabled() && p_filter != FILTER_IGNORE) {
219
for (int i = 0; i < blend_count; i++) {
220
blendw[i] = 0.0; // All to zero by default.
221
}
222
223
for (const KeyValue<NodePath, bool> &E : filter) {
224
const AHashMap<NodePath, int> &map = *process_state->track_map;
225
if (!map.has(E.key)) {
226
continue;
227
}
228
int idx = map[E.key];
229
blendw[idx] = 1.0; // Filtered goes to one.
230
}
231
232
switch (p_filter) {
233
case FILTER_IGNORE:
234
break; // Will not happen anyway.
235
case FILTER_PASS: {
236
// Values filtered pass, the rest don't.
237
for (int i = 0; i < blend_count; i++) {
238
if (blendw[i] == 0) { // Not filtered, does not pass.
239
continue;
240
}
241
242
blendw[i] = blendr[i] * p_playback_info.weight;
243
if (!Math::is_zero_approx(blendw[i])) {
244
any_valid = true;
245
}
246
}
247
248
} break;
249
case FILTER_STOP: {
250
// Values filtered don't pass, the rest are blended.
251
252
for (int i = 0; i < blend_count; i++) {
253
if (blendw[i] > 0) { // Filtered, does not pass.
254
continue;
255
}
256
257
blendw[i] = blendr[i] * p_playback_info.weight;
258
if (!Math::is_zero_approx(blendw[i])) {
259
any_valid = true;
260
}
261
}
262
263
} break;
264
case FILTER_BLEND: {
265
// Filtered values are blended, the rest are passed without blending.
266
267
for (int i = 0; i < blend_count; i++) {
268
if (blendw[i] == 1.0) {
269
blendw[i] = blendr[i] * p_playback_info.weight; // Filtered, blend.
270
} else {
271
blendw[i] = blendr[i]; // Not filtered, do not blend.
272
}
273
274
if (!Math::is_zero_approx(blendw[i])) {
275
any_valid = true;
276
}
277
}
278
279
} break;
280
}
281
} else {
282
for (int i = 0; i < blend_count; i++) {
283
// Regular blend.
284
blendw[i] = blendr[i] * p_playback_info.weight;
285
if (!Math::is_zero_approx(blendw[i])) {
286
any_valid = true;
287
}
288
}
289
}
290
291
if (r_activity) {
292
*r_activity = 0;
293
for (int i = 0; i < blend_count; i++) {
294
*r_activity = MAX(*r_activity, Math::abs(blendw[i]));
295
}
296
}
297
298
String new_path;
299
AnimationNode *new_parent;
300
301
// This is the slowest part of processing, but as strings process in powers of 2, and the paths always exist, it will not result in that many allocations.
302
if (p_new_parent) {
303
new_parent = p_new_parent;
304
new_path = String(node_state.base_path) + String(p_subpath) + "/";
305
} else {
306
ERR_FAIL_NULL_V(node_state.parent, NodeTimeInfo());
307
new_parent = node_state.parent;
308
new_path = String(new_parent->node_state.base_path) + String(p_subpath) + "/";
309
}
310
311
// This process, which depends on p_sync is needed to process sync correctly in the case of
312
// that a synced AnimationNodeSync exists under the un-synced AnimationNodeSync.
313
p_node->set_node_state_base_path(new_path);
314
p_node->node_state.parent = new_parent;
315
if (!p_playback_info.seeked && !p_sync && !any_valid) {
316
p_playback_info.delta = 0.0;
317
return p_node->_pre_process(process_state, p_playback_info, p_test_only);
318
}
319
return p_node->_pre_process(process_state, p_playback_info, p_test_only);
320
}
321
322
String AnimationNode::get_caption() const {
323
String ret = "Node";
324
GDVIRTUAL_CALL(_get_caption, ret);
325
return ret;
326
}
327
328
bool AnimationNode::add_input(const String &p_name) {
329
// Root nodes can't add inputs.
330
ERR_FAIL_COND_V(Object::cast_to<AnimationRootNode>(this) != nullptr, false);
331
Input input;
332
ERR_FAIL_COND_V(p_name.contains_char('.') || p_name.contains_char('/'), false);
333
input.name = p_name;
334
inputs.push_back(input);
335
emit_changed();
336
return true;
337
}
338
339
void AnimationNode::remove_input(int p_index) {
340
ERR_FAIL_INDEX(p_index, (int64_t)inputs.size());
341
inputs.remove_at(p_index);
342
emit_changed();
343
}
344
345
bool AnimationNode::set_input_name(int p_input, const String &p_name) {
346
ERR_FAIL_INDEX_V(p_input, (int64_t)inputs.size(), false);
347
ERR_FAIL_COND_V(p_name.contains_char('.') || p_name.contains_char('/'), false);
348
inputs[p_input].name = p_name;
349
emit_changed();
350
return true;
351
}
352
353
String AnimationNode::get_input_name(int p_input) const {
354
ERR_FAIL_INDEX_V(p_input, (int64_t)inputs.size(), String());
355
return inputs[p_input].name;
356
}
357
358
int AnimationNode::get_input_count() const {
359
return inputs.size();
360
}
361
362
int AnimationNode::find_input(const String &p_name) const {
363
int idx = -1;
364
for (int i = 0; i < (int64_t)inputs.size(); i++) {
365
if (inputs[i].name == p_name) {
366
idx = i;
367
break;
368
}
369
}
370
return idx;
371
}
372
373
AnimationNode::NodeTimeInfo AnimationNode::process(const AnimationMixer::PlaybackInfo p_playback_info, bool p_test_only) {
374
process_state->is_testing = p_test_only;
375
376
AnimationMixer::PlaybackInfo pi = p_playback_info;
377
if (p_playback_info.seeked) {
378
if (p_playback_info.is_external_seeking) {
379
pi.delta = get_node_time_info().position - p_playback_info.time;
380
}
381
} else {
382
pi.time = get_node_time_info().position + p_playback_info.delta;
383
}
384
385
NodeTimeInfo nti = _process(pi, p_test_only);
386
387
if (!p_test_only) {
388
set_node_time_info(nti);
389
}
390
391
return nti;
392
}
393
394
AnimationNode::NodeTimeInfo AnimationNode::_process(const AnimationMixer::PlaybackInfo p_playback_info, bool p_test_only) {
395
double r_ret = 0.0;
396
GDVIRTUAL_CALL(_process, p_playback_info.time, p_playback_info.seeked, p_playback_info.is_external_seeking, p_test_only, r_ret);
397
NodeTimeInfo nti;
398
nti.delta = r_ret;
399
return nti;
400
}
401
402
void AnimationNode::set_filter_path(const NodePath &p_path, bool p_enable) {
403
if (p_enable) {
404
filter[p_path] = true;
405
} else {
406
filter.erase(p_path);
407
}
408
}
409
410
void AnimationNode::set_filter_enabled(bool p_enable) {
411
filter_enabled = p_enable;
412
}
413
414
bool AnimationNode::is_filter_enabled() const {
415
return filter_enabled;
416
}
417
418
void AnimationNode::set_deletable(bool p_closable) {
419
closable = p_closable;
420
}
421
422
bool AnimationNode::is_deletable() const {
423
return closable;
424
}
425
426
ObjectID AnimationNode::get_processing_animation_tree_instance_id() const {
427
ERR_FAIL_NULL_V(process_state, ObjectID());
428
return process_state->tree->get_instance_id();
429
}
430
431
bool AnimationNode::is_process_testing() const {
432
ERR_FAIL_NULL_V(process_state, false);
433
return process_state->is_testing;
434
}
435
436
bool AnimationNode::is_path_filtered(const NodePath &p_path) const {
437
return filter.has(p_path);
438
}
439
440
bool AnimationNode::has_filter() const {
441
bool ret = false;
442
GDVIRTUAL_CALL(_has_filter, ret);
443
return ret;
444
}
445
446
Array AnimationNode::_get_filters() const {
447
Array paths;
448
449
for (const KeyValue<NodePath, bool> &E : filter) {
450
paths.push_back(String(E.key)); // Use strings, so sorting is possible.
451
}
452
paths.sort(); // Done so every time the scene is saved, it does not change.
453
454
return paths;
455
}
456
457
void AnimationNode::_set_filters(const Array &p_filters) {
458
filter.clear();
459
for (int i = 0; i < p_filters.size(); i++) {
460
set_filter_path(p_filters[i], true);
461
}
462
}
463
464
void AnimationNode::_validate_property(PropertyInfo &p_property) const {
465
if (!has_filter() && (p_property.name == "filter_enabled" || p_property.name == "filters")) {
466
p_property.usage = PROPERTY_USAGE_NONE;
467
}
468
}
469
470
Ref<AnimationNode> AnimationNode::get_child_by_name(const StringName &p_name) const {
471
Ref<AnimationNode> ret;
472
GDVIRTUAL_CALL(_get_child_by_name, p_name, ret);
473
return ret;
474
}
475
476
Ref<AnimationNode> AnimationNode::find_node_by_path(const String &p_name) const {
477
Vector<String> split = p_name.split("/");
478
Ref<AnimationNode> ret = const_cast<AnimationNode *>(this);
479
for (int i = 0; i < split.size(); i++) {
480
ret = ret->get_child_by_name(split[i]);
481
if (ret.is_null()) {
482
break;
483
}
484
}
485
return ret;
486
}
487
488
void AnimationNode::blend_animation_ex(const StringName &p_animation, double p_time, double p_delta, bool p_seeked, bool p_is_external_seeking, real_t p_blend, Animation::LoopedFlag p_looped_flag) {
489
AnimationMixer::PlaybackInfo info;
490
info.time = p_time;
491
info.delta = p_delta;
492
info.seeked = p_seeked;
493
info.is_external_seeking = p_is_external_seeking;
494
info.weight = p_blend;
495
info.looped_flag = p_looped_flag;
496
blend_animation(p_animation, info);
497
}
498
499
double AnimationNode::blend_node_ex(const StringName &p_sub_path, Ref<AnimationNode> p_node, double p_time, bool p_seek, bool p_is_external_seeking, real_t p_blend, FilterAction p_filter, bool p_sync, bool p_test_only) {
500
AnimationMixer::PlaybackInfo info;
501
info.time = p_time;
502
info.seeked = p_seek;
503
info.is_external_seeking = p_is_external_seeking;
504
info.weight = p_blend;
505
NodeTimeInfo nti = blend_node(p_node, p_sub_path, info, p_filter, p_sync, p_test_only);
506
return nti.length - nti.position;
507
}
508
509
double AnimationNode::blend_input_ex(int p_input, double p_time, bool p_seek, bool p_is_external_seeking, real_t p_blend, FilterAction p_filter, bool p_sync, bool p_test_only) {
510
AnimationMixer::PlaybackInfo info;
511
info.time = p_time;
512
info.seeked = p_seek;
513
info.is_external_seeking = p_is_external_seeking;
514
info.weight = p_blend;
515
NodeTimeInfo nti = blend_input(p_input, info, p_filter, p_sync, p_test_only);
516
return nti.length - nti.position;
517
}
518
519
#ifdef TOOLS_ENABLED
520
void AnimationNode::get_argument_options(const StringName &p_function, int p_idx, List<String> *r_options) const {
521
const String pf = p_function;
522
if (p_idx == 0) {
523
if (pf == "find_input") {
524
for (const AnimationNode::Input &E : inputs) {
525
r_options->push_back(E.name.quote());
526
}
527
} else if (pf == "get_parameter" || pf == "set_parameter") {
528
bool is_setter = pf == "set_parameter";
529
List<PropertyInfo> parameters;
530
get_parameter_list(&parameters);
531
for (const PropertyInfo &E : parameters) {
532
if (is_setter && is_parameter_read_only(E.name)) {
533
continue;
534
}
535
r_options->push_back(E.name.quote());
536
}
537
} else if (pf == "set_filter_path" || pf == "is_path_filtered") {
538
for (const KeyValue<NodePath, bool> &E : filter) {
539
r_options->push_back(String(E.key).quote());
540
}
541
}
542
}
543
Resource::get_argument_options(p_function, p_idx, r_options);
544
}
545
#endif
546
547
void AnimationNode::_bind_methods() {
548
ClassDB::bind_method(D_METHOD("add_input", "name"), &AnimationNode::add_input);
549
ClassDB::bind_method(D_METHOD("remove_input", "index"), &AnimationNode::remove_input);
550
ClassDB::bind_method(D_METHOD("set_input_name", "input", "name"), &AnimationNode::set_input_name);
551
ClassDB::bind_method(D_METHOD("get_input_name", "input"), &AnimationNode::get_input_name);
552
ClassDB::bind_method(D_METHOD("get_input_count"), &AnimationNode::get_input_count);
553
ClassDB::bind_method(D_METHOD("find_input", "name"), &AnimationNode::find_input);
554
555
ClassDB::bind_method(D_METHOD("set_filter_path", "path", "enable"), &AnimationNode::set_filter_path);
556
ClassDB::bind_method(D_METHOD("is_path_filtered", "path"), &AnimationNode::is_path_filtered);
557
558
ClassDB::bind_method(D_METHOD("set_filter_enabled", "enable"), &AnimationNode::set_filter_enabled);
559
ClassDB::bind_method(D_METHOD("is_filter_enabled"), &AnimationNode::is_filter_enabled);
560
561
ClassDB::bind_method(D_METHOD("get_processing_animation_tree_instance_id"), &AnimationNode::get_processing_animation_tree_instance_id);
562
563
ClassDB::bind_method(D_METHOD("is_process_testing"), &AnimationNode::is_process_testing);
564
565
ClassDB::bind_method(D_METHOD("_set_filters", "filters"), &AnimationNode::_set_filters);
566
ClassDB::bind_method(D_METHOD("_get_filters"), &AnimationNode::_get_filters);
567
568
ClassDB::bind_method(D_METHOD("blend_animation", "animation", "time", "delta", "seeked", "is_external_seeking", "blend", "looped_flag"), &AnimationNode::blend_animation_ex, DEFVAL(Animation::LOOPED_FLAG_NONE));
569
ClassDB::bind_method(D_METHOD("blend_node", "name", "node", "time", "seek", "is_external_seeking", "blend", "filter", "sync", "test_only"), &AnimationNode::blend_node_ex, DEFVAL(FILTER_IGNORE), DEFVAL(true), DEFVAL(false));
570
ClassDB::bind_method(D_METHOD("blend_input", "input_index", "time", "seek", "is_external_seeking", "blend", "filter", "sync", "test_only"), &AnimationNode::blend_input_ex, DEFVAL(FILTER_IGNORE), DEFVAL(true), DEFVAL(false));
571
572
ClassDB::bind_method(D_METHOD("set_parameter", "name", "value"), &AnimationNode::set_parameter);
573
ClassDB::bind_method(D_METHOD("get_parameter", "name"), &AnimationNode::get_parameter);
574
575
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "filter_enabled", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), "set_filter_enabled", "is_filter_enabled");
576
ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "filters", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL), "_set_filters", "_get_filters");
577
578
GDVIRTUAL_BIND(_get_child_nodes);
579
GDVIRTUAL_BIND(_get_parameter_list);
580
GDVIRTUAL_BIND(_get_child_by_name, "name");
581
GDVIRTUAL_BIND(_get_parameter_default_value, "parameter");
582
GDVIRTUAL_BIND(_is_parameter_read_only, "parameter");
583
GDVIRTUAL_BIND(_process, "time", "seek", "is_external_seeking", "test_only");
584
GDVIRTUAL_BIND(_get_caption);
585
GDVIRTUAL_BIND(_has_filter);
586
587
ADD_SIGNAL(MethodInfo("tree_changed"));
588
ADD_SIGNAL(MethodInfo("animation_node_renamed", PropertyInfo(Variant::INT, "object_id"), PropertyInfo(Variant::STRING, "old_name"), PropertyInfo(Variant::STRING, "new_name")));
589
ADD_SIGNAL(MethodInfo("animation_node_removed", PropertyInfo(Variant::INT, "object_id"), PropertyInfo(Variant::STRING, "name")));
590
591
BIND_ENUM_CONSTANT(FILTER_IGNORE);
592
BIND_ENUM_CONSTANT(FILTER_PASS);
593
BIND_ENUM_CONSTANT(FILTER_STOP);
594
BIND_ENUM_CONSTANT(FILTER_BLEND);
595
}
596
597
AnimationNode::AnimationNode() {
598
}
599
600
////////////////////
601
602
void AnimationRootNode::_tree_changed() {
603
emit_signal(SNAME("tree_changed"));
604
}
605
606
void AnimationRootNode::_animation_node_renamed(const ObjectID &p_oid, const String &p_old_name, const String &p_new_name) {
607
emit_signal(SNAME("animation_node_renamed"), p_oid, p_old_name, p_new_name);
608
}
609
610
void AnimationRootNode::_animation_node_removed(const ObjectID &p_oid, const StringName &p_node) {
611
emit_signal(SNAME("animation_node_removed"), p_oid, p_node);
612
}
613
614
////////////////////
615
616
void AnimationTree::set_root_animation_node(const Ref<AnimationRootNode> &p_animation_node) {
617
if (root_animation_node.is_valid()) {
618
root_animation_node->disconnect(SNAME("tree_changed"), callable_mp(this, &AnimationTree::_tree_changed));
619
root_animation_node->disconnect(SNAME("animation_node_renamed"), callable_mp(this, &AnimationTree::_animation_node_renamed));
620
root_animation_node->disconnect(SNAME("animation_node_removed"), callable_mp(this, &AnimationTree::_animation_node_removed));
621
}
622
623
root_animation_node = p_animation_node;
624
625
if (root_animation_node.is_valid()) {
626
root_animation_node->connect(SNAME("tree_changed"), callable_mp(this, &AnimationTree::_tree_changed));
627
root_animation_node->connect(SNAME("animation_node_renamed"), callable_mp(this, &AnimationTree::_animation_node_renamed));
628
root_animation_node->connect(SNAME("animation_node_removed"), callable_mp(this, &AnimationTree::_animation_node_removed));
629
}
630
631
properties_dirty = true;
632
633
update_configuration_warnings();
634
}
635
636
Ref<AnimationRootNode> AnimationTree::get_root_animation_node() const {
637
return root_animation_node;
638
}
639
640
bool AnimationTree::_blend_pre_process(double p_delta, int p_track_count, const AHashMap<NodePath, int> &p_track_map) {
641
_update_properties(); // If properties need updating, update them.
642
643
if (root_animation_node.is_null()) {
644
return false;
645
}
646
647
{ // Setup.
648
process_pass++;
649
650
// Init process state.
651
process_state = AnimationNode::ProcessState();
652
process_state.tree = this;
653
process_state.valid = true;
654
process_state.invalid_reasons = "";
655
process_state.last_pass = process_pass;
656
process_state.track_map = &p_track_map;
657
658
// Init node state for root AnimationNode.
659
root_animation_node->node_state.track_weights.resize(p_track_count);
660
real_t *src_blendsw = root_animation_node->node_state.track_weights.ptr();
661
for (int i = 0; i < p_track_count; i++) {
662
src_blendsw[i] = 1.0; // By default all go to 1 for the root input.
663
}
664
root_animation_node->set_node_state_base_path(SNAME(Animation::PARAMETERS_BASE_PATH.ascii().get_data()));
665
root_animation_node->node_state.parent = nullptr;
666
}
667
668
// Process.
669
{
670
PlaybackInfo pi;
671
672
if (started) {
673
// If started, seek.
674
pi.seeked = true;
675
pi.delta = p_delta;
676
root_animation_node->_pre_process(&process_state, pi, false);
677
started = false;
678
} else {
679
pi.seeked = false;
680
pi.delta = p_delta;
681
root_animation_node->_pre_process(&process_state, pi, false);
682
}
683
}
684
685
if (!process_state.valid) {
686
return false; // State is not valid, abort process.
687
}
688
689
return true;
690
}
691
692
void AnimationTree::_set_active(bool p_active) {
693
_set_process(p_active);
694
started = p_active;
695
}
696
697
void AnimationTree::set_advance_expression_base_node(const NodePath &p_path) {
698
advance_expression_base_node = p_path;
699
}
700
701
NodePath AnimationTree::get_advance_expression_base_node() const {
702
return advance_expression_base_node;
703
}
704
705
bool AnimationTree::is_state_invalid() const {
706
return !process_state.valid;
707
}
708
709
String AnimationTree::get_invalid_state_reason() const {
710
return process_state.invalid_reasons;
711
}
712
713
uint64_t AnimationTree::get_last_process_pass() const {
714
return process_pass;
715
}
716
717
PackedStringArray AnimationTree::get_configuration_warnings() const {
718
PackedStringArray warnings = AnimationMixer::get_configuration_warnings();
719
if (root_animation_node.is_null()) {
720
warnings.push_back(RTR("No root AnimationNode for the graph is set."));
721
}
722
return warnings;
723
}
724
725
void AnimationTree::_tree_changed() {
726
if (properties_dirty) {
727
return;
728
}
729
730
callable_mp(this, &AnimationTree::_update_properties).call_deferred();
731
properties_dirty = true;
732
}
733
734
void AnimationTree::_animation_node_renamed(const ObjectID &p_oid, const String &p_old_name, const String &p_new_name) {
735
ERR_FAIL_COND(!property_reference_map.has(p_oid));
736
String base_path = property_reference_map[p_oid];
737
String old_base = base_path + p_old_name;
738
String new_base = base_path + p_new_name;
739
for (const PropertyInfo &E : properties) {
740
if (E.name.begins_with(old_base)) {
741
String new_name = E.name.replace_first(old_base, new_base);
742
const Pair<Variant, bool> temp_copy = property_map[E.name];
743
property_map[new_name] = temp_copy;
744
property_map.erase(E.name);
745
}
746
}
747
748
// Update tree second.
749
properties_dirty = true;
750
_update_properties();
751
}
752
753
void AnimationTree::_animation_node_removed(const ObjectID &p_oid, const StringName &p_node) {
754
ERR_FAIL_COND(!property_reference_map.has(p_oid));
755
String base_path = String(property_reference_map[p_oid]) + String(p_node);
756
for (const PropertyInfo &E : properties) {
757
if (E.name.begins_with(base_path)) {
758
property_map.erase(E.name);
759
}
760
}
761
762
// Update tree second.
763
properties_dirty = true;
764
_update_properties();
765
}
766
767
void AnimationTree::_update_properties_for_node(const String &p_base_path, Ref<AnimationNode> p_node) const {
768
ERR_FAIL_COND(p_node.is_null());
769
if (!property_parent_map.has(p_base_path)) {
770
property_parent_map[p_base_path] = AHashMap<StringName, StringName>();
771
}
772
if (!property_reference_map.has(p_node->get_instance_id())) {
773
property_reference_map[p_node->get_instance_id()] = p_base_path;
774
}
775
776
if (p_node->get_input_count() && !input_activity_map.has(p_base_path)) {
777
LocalVector<Activity> activity;
778
for (int i = 0; i < p_node->get_input_count(); i++) {
779
Activity a;
780
a.activity = 0;
781
a.last_pass = 0;
782
activity.push_back(a);
783
}
784
input_activity_map[p_base_path] = activity;
785
input_activity_map_get[String(p_base_path).substr(0, String(p_base_path).length() - 1)] = input_activity_map.get_index(p_base_path);
786
}
787
788
List<PropertyInfo> plist;
789
p_node->get_parameter_list(&plist);
790
for (PropertyInfo &pinfo : plist) {
791
StringName key = pinfo.name;
792
793
if (!property_map.has(p_base_path + key)) {
794
Pair<Variant, bool> param;
795
param.first = p_node->get_parameter_default_value(key);
796
param.second = p_node->is_parameter_read_only(key);
797
property_map[p_base_path + key] = param;
798
}
799
800
property_parent_map[p_base_path][key] = p_base_path + key;
801
802
pinfo.name = p_base_path + key;
803
properties.push_back(pinfo);
804
}
805
p_node->make_cache_dirty();
806
List<AnimationNode::ChildNode> children;
807
p_node->get_child_nodes(&children);
808
809
for (const AnimationNode::ChildNode &E : children) {
810
_update_properties_for_node(p_base_path + E.name + "/", E.node);
811
}
812
}
813
814
void AnimationTree::_update_properties() const {
815
if (!properties_dirty) {
816
return;
817
}
818
819
properties.clear();
820
property_reference_map.clear();
821
property_parent_map.clear();
822
input_activity_map.clear();
823
input_activity_map_get.clear();
824
825
if (root_animation_node.is_valid()) {
826
_update_properties_for_node(Animation::PARAMETERS_BASE_PATH, root_animation_node);
827
}
828
829
properties_dirty = false;
830
831
const_cast<AnimationTree *>(this)->notify_property_list_changed();
832
}
833
834
void AnimationTree::_notification(int p_what) {
835
switch (p_what) {
836
case NOTIFICATION_ENTER_TREE: {
837
_setup_animation_player();
838
if (active) {
839
_set_process(true);
840
}
841
} break;
842
}
843
}
844
845
void AnimationTree::set_animation_player(const NodePath &p_path) {
846
animation_player = p_path;
847
if (p_path.is_empty()) {
848
set_root_node(SceneStringName(path_pp));
849
while (animation_libraries.size()) {
850
remove_animation_library(animation_libraries[0].name);
851
}
852
}
853
emit_signal(SNAME("animation_player_changed")); // Needs to unpin AnimationPlayerEditor.
854
_setup_animation_player();
855
notify_property_list_changed();
856
}
857
858
NodePath AnimationTree::get_animation_player() const {
859
return animation_player;
860
}
861
862
void AnimationTree::_setup_animation_player() {
863
if (!is_inside_tree()) {
864
return;
865
}
866
867
cache_valid = false;
868
869
if (animation_player.is_empty()) {
870
clear_caches();
871
return;
872
}
873
874
// Using AnimationPlayer here is for compatibility. Changing to AnimationMixer needs extra work like error handling.
875
AnimationPlayer *player = Object::cast_to<AnimationPlayer>(get_node_or_null(animation_player));
876
if (player) {
877
if (!player->is_connected(SNAME("caches_cleared"), callable_mp(this, &AnimationTree::_setup_animation_player))) {
878
player->connect(SNAME("caches_cleared"), callable_mp(this, &AnimationTree::_setup_animation_player), CONNECT_DEFERRED);
879
}
880
if (!player->is_connected(SNAME("animation_list_changed"), callable_mp(this, &AnimationTree::_setup_animation_player))) {
881
player->connect(SNAME("animation_list_changed"), callable_mp(this, &AnimationTree::_setup_animation_player), CONNECT_DEFERRED);
882
}
883
Node *root = player->get_node_or_null(player->get_root_node());
884
if (root) {
885
set_root_node(get_path_to(root, true));
886
}
887
while (animation_libraries.size()) {
888
remove_animation_library(animation_libraries[0].name);
889
}
890
List<StringName> list;
891
player->get_animation_library_list(&list);
892
for (const StringName &E : list) {
893
Ref<AnimationLibrary> lib = player->get_animation_library(E);
894
if (lib.is_valid()) {
895
add_animation_library(E, lib);
896
}
897
}
898
}
899
900
clear_caches();
901
}
902
903
// `libraries` is a dynamic property, so we can't use `_validate_property` to change it.
904
uint32_t AnimationTree::_get_libraries_property_usage() const {
905
if (!animation_player.is_empty()) {
906
return PROPERTY_USAGE_READ_ONLY;
907
}
908
return PROPERTY_USAGE_STORAGE;
909
}
910
911
void AnimationTree::_validate_property(PropertyInfo &p_property) const {
912
if (!Engine::get_singleton()->is_editor_hint()) {
913
return;
914
}
915
916
if (!animation_player.is_empty()) {
917
if (p_property.name == "root_node") {
918
p_property.usage |= PROPERTY_USAGE_READ_ONLY;
919
}
920
}
921
}
922
923
bool AnimationTree::_set(const StringName &p_name, const Variant &p_value) {
924
#ifndef DISABLE_DEPRECATED
925
String name = p_name;
926
if (name == "process_callback") {
927
set_callback_mode_process(static_cast<AnimationCallbackModeProcess>((int)p_value));
928
return true;
929
}
930
#endif // DISABLE_DEPRECATED
931
if (properties_dirty) {
932
_update_properties();
933
}
934
935
if (property_map.has(p_name)) {
936
if (is_inside_tree() && property_map[p_name].second) {
937
return false; // Prevent to set property by user.
938
}
939
Pair<Variant, bool> &prop = property_map[p_name];
940
Variant value = p_value;
941
if (Animation::validate_type_match(prop.first, value)) {
942
prop.first = value;
943
}
944
return true;
945
}
946
947
return false;
948
}
949
950
bool AnimationTree::_get(const StringName &p_name, Variant &r_ret) const {
951
#ifndef DISABLE_DEPRECATED
952
if (p_name == "process_callback") {
953
r_ret = get_callback_mode_process();
954
return true;
955
}
956
#endif // DISABLE_DEPRECATED
957
if (properties_dirty) {
958
_update_properties();
959
}
960
961
if (property_map.has(p_name)) {
962
r_ret = property_map[p_name].first;
963
return true;
964
}
965
966
return false;
967
}
968
969
void AnimationTree::_get_property_list(List<PropertyInfo> *p_list) const {
970
if (properties_dirty) {
971
_update_properties();
972
}
973
974
for (const PropertyInfo &E : properties) {
975
p_list->push_back(E);
976
}
977
}
978
979
real_t AnimationTree::get_connection_activity(const StringName &p_path, int p_connection) const {
980
if (!input_activity_map_get.has(p_path)) {
981
return 0;
982
}
983
984
int index = input_activity_map_get[p_path];
985
const LocalVector<Activity> &activity = input_activity_map.get_by_index(index).value;
986
987
if (p_connection < 0 || p_connection >= (int64_t)activity.size() || activity[p_connection].last_pass != process_pass) {
988
return 0;
989
}
990
991
return activity[p_connection].activity;
992
}
993
994
#ifdef TOOLS_ENABLED
995
String AnimationTree::get_editor_error_message() const {
996
if (!is_active()) {
997
return TTR("The AnimationTree is inactive.\nActivate it in the inspector to enable playback; check node warnings if activation fails.");
998
} else if (!is_enabled()) {
999
return TTR("The AnimationTree node (or one of its parents) has its process mode set to Disabled.\nChange the process mode in the inspector to allow playback.");
1000
} else if (is_state_invalid()) {
1001
return get_invalid_state_reason();
1002
}
1003
1004
return "";
1005
}
1006
#endif
1007
1008
void AnimationTree::_bind_methods() {
1009
ClassDB::bind_method(D_METHOD("set_tree_root", "animation_node"), &AnimationTree::set_root_animation_node);
1010
ClassDB::bind_method(D_METHOD("get_tree_root"), &AnimationTree::get_root_animation_node);
1011
1012
ClassDB::bind_method(D_METHOD("set_advance_expression_base_node", "path"), &AnimationTree::set_advance_expression_base_node);
1013
ClassDB::bind_method(D_METHOD("get_advance_expression_base_node"), &AnimationTree::get_advance_expression_base_node);
1014
1015
ClassDB::bind_method(D_METHOD("set_animation_player", "path"), &AnimationTree::set_animation_player);
1016
ClassDB::bind_method(D_METHOD("get_animation_player"), &AnimationTree::get_animation_player);
1017
1018
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "tree_root", PROPERTY_HINT_RESOURCE_TYPE, AnimationRootNode::get_class_static()), "set_tree_root", "get_tree_root");
1019
ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "advance_expression_base_node", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Node"), "set_advance_expression_base_node", "get_advance_expression_base_node");
1020
ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "anim_player", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "AnimationPlayer"), "set_animation_player", "get_animation_player");
1021
1022
ADD_SIGNAL(MethodInfo(SNAME("animation_player_changed")));
1023
}
1024
1025
AnimationTree::AnimationTree() {
1026
deterministic = true;
1027
callback_mode_discrete = ANIMATION_CALLBACK_MODE_DISCRETE_FORCE_CONTINUOUS;
1028
}
1029
1030
AnimationTree::~AnimationTree() {
1031
}
1032
1033