Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
godotengine
GitHub Repository: godotengine/godot
Path: blob/master/scene/animation/animation_tree.cpp
9903 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 = 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
property_map[new_name] = property_map[E.name];
743
property_map.erase(E.name);
744
}
745
}
746
747
// Update tree second.
748
properties_dirty = true;
749
_update_properties();
750
}
751
752
void AnimationTree::_animation_node_removed(const ObjectID &p_oid, const StringName &p_node) {
753
ERR_FAIL_COND(!property_reference_map.has(p_oid));
754
String base_path = String(property_reference_map[p_oid]) + String(p_node);
755
for (const PropertyInfo &E : properties) {
756
if (E.name.begins_with(base_path)) {
757
property_map.erase(E.name);
758
}
759
}
760
761
// Update tree second.
762
properties_dirty = true;
763
_update_properties();
764
}
765
766
void AnimationTree::_update_properties_for_node(const String &p_base_path, Ref<AnimationNode> p_node) const {
767
ERR_FAIL_COND(p_node.is_null());
768
if (!property_parent_map.has(p_base_path)) {
769
property_parent_map[p_base_path] = AHashMap<StringName, StringName>();
770
}
771
if (!property_reference_map.has(p_node->get_instance_id())) {
772
property_reference_map[p_node->get_instance_id()] = p_base_path;
773
}
774
775
if (p_node->get_input_count() && !input_activity_map.has(p_base_path)) {
776
LocalVector<Activity> activity;
777
for (int i = 0; i < p_node->get_input_count(); i++) {
778
Activity a;
779
a.activity = 0;
780
a.last_pass = 0;
781
activity.push_back(a);
782
}
783
input_activity_map[p_base_path] = activity;
784
input_activity_map_get[String(p_base_path).substr(0, String(p_base_path).length() - 1)] = input_activity_map.get_index(p_base_path);
785
}
786
787
List<PropertyInfo> plist;
788
p_node->get_parameter_list(&plist);
789
for (PropertyInfo &pinfo : plist) {
790
StringName key = pinfo.name;
791
792
if (!property_map.has(p_base_path + key)) {
793
Pair<Variant, bool> param;
794
param.first = p_node->get_parameter_default_value(key);
795
param.second = p_node->is_parameter_read_only(key);
796
property_map[p_base_path + key] = param;
797
}
798
799
property_parent_map[p_base_path][key] = p_base_path + key;
800
801
pinfo.name = p_base_path + key;
802
properties.push_back(pinfo);
803
}
804
p_node->make_cache_dirty();
805
List<AnimationNode::ChildNode> children;
806
p_node->get_child_nodes(&children);
807
808
for (const AnimationNode::ChildNode &E : children) {
809
_update_properties_for_node(p_base_path + E.name + "/", E.node);
810
}
811
}
812
813
void AnimationTree::_update_properties() const {
814
if (!properties_dirty) {
815
return;
816
}
817
818
properties.clear();
819
property_reference_map.clear();
820
property_parent_map.clear();
821
input_activity_map.clear();
822
input_activity_map_get.clear();
823
824
if (root_animation_node.is_valid()) {
825
_update_properties_for_node(Animation::PARAMETERS_BASE_PATH, root_animation_node);
826
}
827
828
properties_dirty = false;
829
830
const_cast<AnimationTree *>(this)->notify_property_list_changed();
831
}
832
833
void AnimationTree::_notification(int p_what) {
834
switch (p_what) {
835
case NOTIFICATION_ENTER_TREE: {
836
_setup_animation_player();
837
if (active) {
838
_set_process(true);
839
}
840
} break;
841
}
842
}
843
844
void AnimationTree::set_animation_player(const NodePath &p_path) {
845
animation_player = p_path;
846
if (p_path.is_empty()) {
847
set_root_node(SceneStringName(path_pp));
848
while (animation_libraries.size()) {
849
remove_animation_library(animation_libraries[0].name);
850
}
851
}
852
emit_signal(SNAME("animation_player_changed")); // Needs to unpin AnimationPlayerEditor.
853
_setup_animation_player();
854
notify_property_list_changed();
855
}
856
857
NodePath AnimationTree::get_animation_player() const {
858
return animation_player;
859
}
860
861
void AnimationTree::_setup_animation_player() {
862
if (!is_inside_tree()) {
863
return;
864
}
865
866
cache_valid = false;
867
868
if (animation_player.is_empty()) {
869
clear_caches();
870
return;
871
}
872
873
// Using AnimationPlayer here is for compatibility. Changing to AnimationMixer needs extra work like error handling.
874
AnimationPlayer *player = Object::cast_to<AnimationPlayer>(get_node_or_null(animation_player));
875
if (player) {
876
if (!player->is_connected(SNAME("caches_cleared"), callable_mp(this, &AnimationTree::_setup_animation_player))) {
877
player->connect(SNAME("caches_cleared"), callable_mp(this, &AnimationTree::_setup_animation_player), CONNECT_DEFERRED);
878
}
879
if (!player->is_connected(SNAME("animation_list_changed"), callable_mp(this, &AnimationTree::_setup_animation_player))) {
880
player->connect(SNAME("animation_list_changed"), callable_mp(this, &AnimationTree::_setup_animation_player), CONNECT_DEFERRED);
881
}
882
Node *root = player->get_node_or_null(player->get_root_node());
883
if (root) {
884
set_root_node(get_path_to(root, true));
885
}
886
while (animation_libraries.size()) {
887
remove_animation_library(animation_libraries[0].name);
888
}
889
List<StringName> list;
890
player->get_animation_library_list(&list);
891
for (const StringName &E : list) {
892
Ref<AnimationLibrary> lib = player->get_animation_library(E);
893
if (lib.is_valid()) {
894
add_animation_library(E, lib);
895
}
896
}
897
}
898
899
clear_caches();
900
}
901
902
void AnimationTree::_validate_property(PropertyInfo &p_property) const {
903
if (!animation_player.is_empty()) {
904
if (Engine::get_singleton()->is_editor_hint() && (p_property.name == "root_node" || p_property.name.begins_with("libraries"))) {
905
p_property.usage |= PROPERTY_USAGE_READ_ONLY;
906
}
907
908
if (p_property.name.begins_with("libraries")) {
909
p_property.usage &= ~PROPERTY_USAGE_STORAGE;
910
}
911
}
912
}
913
914
bool AnimationTree::_set(const StringName &p_name, const Variant &p_value) {
915
#ifndef DISABLE_DEPRECATED
916
String name = p_name;
917
if (name == "process_callback") {
918
set_callback_mode_process(static_cast<AnimationCallbackModeProcess>((int)p_value));
919
return true;
920
}
921
#endif // DISABLE_DEPRECATED
922
if (properties_dirty) {
923
_update_properties();
924
}
925
926
if (property_map.has(p_name)) {
927
if (is_inside_tree() && property_map[p_name].second) {
928
return false; // Prevent to set property by user.
929
}
930
Pair<Variant, bool> &prop = property_map[p_name];
931
Variant value = p_value;
932
if (Animation::validate_type_match(prop.first, value)) {
933
prop.first = value;
934
}
935
return true;
936
}
937
938
return false;
939
}
940
941
bool AnimationTree::_get(const StringName &p_name, Variant &r_ret) const {
942
#ifndef DISABLE_DEPRECATED
943
if (p_name == "process_callback") {
944
r_ret = get_callback_mode_process();
945
return true;
946
}
947
#endif // DISABLE_DEPRECATED
948
if (properties_dirty) {
949
_update_properties();
950
}
951
952
if (property_map.has(p_name)) {
953
r_ret = property_map[p_name].first;
954
return true;
955
}
956
957
return false;
958
}
959
960
void AnimationTree::_get_property_list(List<PropertyInfo> *p_list) const {
961
if (properties_dirty) {
962
_update_properties();
963
}
964
965
for (const PropertyInfo &E : properties) {
966
p_list->push_back(E);
967
}
968
}
969
970
real_t AnimationTree::get_connection_activity(const StringName &p_path, int p_connection) const {
971
if (!input_activity_map_get.has(p_path)) {
972
return 0;
973
}
974
975
int index = input_activity_map_get[p_path];
976
const LocalVector<Activity> &activity = input_activity_map.get_by_index(index).value;
977
978
if (p_connection < 0 || p_connection >= (int64_t)activity.size() || activity[p_connection].last_pass != process_pass) {
979
return 0;
980
}
981
982
return activity[p_connection].activity;
983
}
984
985
void AnimationTree::_bind_methods() {
986
ClassDB::bind_method(D_METHOD("set_tree_root", "animation_node"), &AnimationTree::set_root_animation_node);
987
ClassDB::bind_method(D_METHOD("get_tree_root"), &AnimationTree::get_root_animation_node);
988
989
ClassDB::bind_method(D_METHOD("set_advance_expression_base_node", "path"), &AnimationTree::set_advance_expression_base_node);
990
ClassDB::bind_method(D_METHOD("get_advance_expression_base_node"), &AnimationTree::get_advance_expression_base_node);
991
992
ClassDB::bind_method(D_METHOD("set_animation_player", "path"), &AnimationTree::set_animation_player);
993
ClassDB::bind_method(D_METHOD("get_animation_player"), &AnimationTree::get_animation_player);
994
995
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "tree_root", PROPERTY_HINT_RESOURCE_TYPE, "AnimationRootNode"), "set_tree_root", "get_tree_root");
996
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");
997
ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "anim_player", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "AnimationPlayer"), "set_animation_player", "get_animation_player");
998
999
ADD_SIGNAL(MethodInfo(SNAME("animation_player_changed")));
1000
}
1001
1002
AnimationTree::AnimationTree() {
1003
deterministic = true;
1004
callback_mode_discrete = ANIMATION_CALLBACK_MODE_DISCRETE_FORCE_CONTINUOUS;
1005
}
1006
1007
AnimationTree::~AnimationTree() {
1008
}
1009
1010