1 /*************************************************************************/
2 /*  animation_blend_tree.cpp                                             */
3 /*************************************************************************/
4 /*                       This file is part of:                           */
5 /*                           GODOT ENGINE                                */
6 /*                      https://godotengine.org                          */
7 /*************************************************************************/
8 /* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur.                 */
9 /* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md).   */
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/scene_string_names.h"
34 
set_animation(const StringName & p_name)35 void AnimationNodeAnimation::set_animation(const StringName &p_name) {
36 	animation = p_name;
37 	_change_notify("animation");
38 }
39 
get_animation() const40 StringName AnimationNodeAnimation::get_animation() const {
41 	return animation;
42 }
43 
44 Vector<String> (*AnimationNodeAnimation::get_editable_animation_list)() = NULL;
45 
get_parameter_list(List<PropertyInfo> * r_list) const46 void AnimationNodeAnimation::get_parameter_list(List<PropertyInfo> *r_list) const {
47 	r_list->push_back(PropertyInfo(Variant::REAL, time, PROPERTY_HINT_NONE, "", 0));
48 }
_validate_property(PropertyInfo & property) const49 void AnimationNodeAnimation::_validate_property(PropertyInfo &property) const {
50 
51 	if (property.name == "animation" && get_editable_animation_list) {
52 		Vector<String> names = get_editable_animation_list();
53 		String anims;
54 		for (int i = 0; i < names.size(); i++) {
55 
56 			if (i > 0) {
57 				anims += ",";
58 			}
59 			anims += String(names[i]);
60 		}
61 		if (anims != String()) {
62 			property.hint = PROPERTY_HINT_ENUM;
63 			property.hint_string = anims;
64 		}
65 	}
66 }
67 
process(float p_time,bool p_seek)68 float AnimationNodeAnimation::process(float p_time, bool p_seek) {
69 
70 	AnimationPlayer *ap = state->player;
71 	ERR_FAIL_COND_V(!ap, 0);
72 
73 	float time = get_parameter(this->time);
74 
75 	if (!ap->has_animation(animation)) {
76 
77 		AnimationNodeBlendTree *tree = Object::cast_to<AnimationNodeBlendTree>(parent);
78 		if (tree) {
79 			String name = tree->get_node_name(Ref<AnimationNodeAnimation>(this));
80 			make_invalid(vformat(RTR("On BlendTree node '%s', animation not found: '%s'"), name, animation));
81 
82 		} else {
83 			make_invalid(vformat(RTR("Animation not found: '%s'"), animation));
84 		}
85 
86 		return 0;
87 	}
88 
89 	Ref<Animation> anim = ap->get_animation(animation);
90 
91 	float step;
92 
93 	if (p_seek) {
94 		time = p_time;
95 		step = 0;
96 	} else {
97 		time = MAX(0, time + p_time);
98 		step = p_time;
99 	}
100 
101 	float anim_size = anim->get_length();
102 
103 	if (anim->has_loop()) {
104 
105 		if (anim_size) {
106 			time = Math::fposmod(time, anim_size);
107 		}
108 
109 	} else if (time > anim_size) {
110 
111 		time = anim_size;
112 	}
113 
114 	blend_animation(animation, time, step, p_seek, 1.0);
115 
116 	set_parameter(this->time, time);
117 
118 	return anim_size - time;
119 }
120 
get_caption() const121 String AnimationNodeAnimation::get_caption() const {
122 	return "Animation";
123 }
124 
_bind_methods()125 void AnimationNodeAnimation::_bind_methods() {
126 	ClassDB::bind_method(D_METHOD("set_animation", "name"), &AnimationNodeAnimation::set_animation);
127 	ClassDB::bind_method(D_METHOD("get_animation"), &AnimationNodeAnimation::get_animation);
128 
129 	ADD_PROPERTY(PropertyInfo(Variant::STRING, "animation"), "set_animation", "get_animation");
130 }
131 
AnimationNodeAnimation()132 AnimationNodeAnimation::AnimationNodeAnimation() {
133 	last_version = 0;
134 	skip = false;
135 	time = "time";
136 }
137 
138 ////////////////////////////////////////////////////////
139 
get_parameter_list(List<PropertyInfo> * r_list) const140 void AnimationNodeOneShot::get_parameter_list(List<PropertyInfo> *r_list) const {
141 	r_list->push_back(PropertyInfo(Variant::BOOL, active));
142 	r_list->push_back(PropertyInfo(Variant::BOOL, prev_active, PROPERTY_HINT_NONE, "", 0));
143 	r_list->push_back(PropertyInfo(Variant::REAL, time, PROPERTY_HINT_NONE, "", 0));
144 	r_list->push_back(PropertyInfo(Variant::REAL, remaining, PROPERTY_HINT_NONE, "", 0));
145 	r_list->push_back(PropertyInfo(Variant::REAL, time_to_restart, PROPERTY_HINT_NONE, "", 0));
146 }
147 
get_parameter_default_value(const StringName & p_parameter) const148 Variant AnimationNodeOneShot::get_parameter_default_value(const StringName &p_parameter) const {
149 	if (p_parameter == active || p_parameter == prev_active) {
150 		return false;
151 	} else if (p_parameter == time_to_restart) {
152 		return -1;
153 	} else {
154 		return 0.0;
155 	}
156 }
157 
set_fadein_time(float p_time)158 void AnimationNodeOneShot::set_fadein_time(float p_time) {
159 
160 	fade_in = p_time;
161 }
162 
set_fadeout_time(float p_time)163 void AnimationNodeOneShot::set_fadeout_time(float p_time) {
164 
165 	fade_out = p_time;
166 }
167 
get_fadein_time() const168 float AnimationNodeOneShot::get_fadein_time() const {
169 
170 	return fade_in;
171 }
get_fadeout_time() const172 float AnimationNodeOneShot::get_fadeout_time() const {
173 
174 	return fade_out;
175 }
176 
set_autorestart(bool p_active)177 void AnimationNodeOneShot::set_autorestart(bool p_active) {
178 
179 	autorestart = p_active;
180 }
set_autorestart_delay(float p_time)181 void AnimationNodeOneShot::set_autorestart_delay(float p_time) {
182 
183 	autorestart_delay = p_time;
184 }
set_autorestart_random_delay(float p_time)185 void AnimationNodeOneShot::set_autorestart_random_delay(float p_time) {
186 
187 	autorestart_random_delay = p_time;
188 }
189 
has_autorestart() const190 bool AnimationNodeOneShot::has_autorestart() const {
191 
192 	return autorestart;
193 }
get_autorestart_delay() const194 float AnimationNodeOneShot::get_autorestart_delay() const {
195 
196 	return autorestart_delay;
197 }
get_autorestart_random_delay() const198 float AnimationNodeOneShot::get_autorestart_random_delay() const {
199 
200 	return autorestart_random_delay;
201 }
202 
set_mix_mode(MixMode p_mix)203 void AnimationNodeOneShot::set_mix_mode(MixMode p_mix) {
204 
205 	mix = p_mix;
206 }
get_mix_mode() const207 AnimationNodeOneShot::MixMode AnimationNodeOneShot::get_mix_mode() const {
208 
209 	return mix;
210 }
211 
get_caption() const212 String AnimationNodeOneShot::get_caption() const {
213 	return "OneShot";
214 }
215 
has_filter() const216 bool AnimationNodeOneShot::has_filter() const {
217 	return true;
218 }
219 
process(float p_time,bool p_seek)220 float AnimationNodeOneShot::process(float p_time, bool p_seek) {
221 
222 	bool active = get_parameter(this->active);
223 	bool prev_active = get_parameter(this->prev_active);
224 	float time = get_parameter(this->time);
225 	float remaining = get_parameter(this->remaining);
226 	float time_to_restart = get_parameter(this->time_to_restart);
227 
228 	if (!active) {
229 		//make it as if this node doesn't exist, pass input 0 by.
230 		if (prev_active) {
231 			set_parameter(this->prev_active, false);
232 		}
233 		if (time_to_restart >= 0.0 && !p_seek) {
234 			time_to_restart -= p_time;
235 			if (time_to_restart < 0) {
236 				//restart
237 				set_parameter(this->active, true);
238 				active = true;
239 			}
240 			set_parameter(this->time_to_restart, time_to_restart);
241 		}
242 
243 		if (!active) {
244 			return blend_input(0, p_time, p_seek, 1.0, FILTER_IGNORE, !sync);
245 		}
246 	}
247 
248 	bool os_seek = p_seek;
249 
250 	if (p_seek)
251 		time = p_time;
252 	bool do_start = !prev_active;
253 
254 	if (do_start) {
255 		time = 0;
256 		os_seek = true;
257 		set_parameter(this->prev_active, true);
258 	}
259 
260 	float blend;
261 
262 	if (time < fade_in) {
263 
264 		if (fade_in > 0)
265 			blend = time / fade_in;
266 		else
267 			blend = 0; //wtf
268 
269 	} else if (!do_start && remaining < fade_out) {
270 
271 		if (fade_out)
272 			blend = (remaining / fade_out);
273 		else
274 			blend = 1.0;
275 	} else
276 		blend = 1.0;
277 
278 	float main_rem;
279 	if (mix == MIX_MODE_ADD) {
280 		main_rem = blend_input(0, p_time, p_seek, 1.0, FILTER_IGNORE, !sync);
281 	} else {
282 		main_rem = blend_input(0, p_time, p_seek, 1.0 - blend, FILTER_BLEND, !sync);
283 	}
284 
285 	float os_rem = blend_input(1, os_seek ? time : p_time, os_seek, blend, FILTER_PASS, false);
286 
287 	if (do_start) {
288 		remaining = os_rem;
289 	}
290 
291 	if (!p_seek) {
292 		time += p_time;
293 		remaining = os_rem;
294 		if (remaining <= 0) {
295 			set_parameter(this->active, false);
296 			set_parameter(this->prev_active, false);
297 			if (autorestart) {
298 				float restart_sec = autorestart_delay + Math::randf() * autorestart_random_delay;
299 				set_parameter(this->time_to_restart, restart_sec);
300 			}
301 		}
302 	}
303 
304 	set_parameter(this->time, time);
305 	set_parameter(this->remaining, remaining);
306 
307 	return MAX(main_rem, remaining);
308 }
set_use_sync(bool p_sync)309 void AnimationNodeOneShot::set_use_sync(bool p_sync) {
310 
311 	sync = p_sync;
312 }
313 
is_using_sync() const314 bool AnimationNodeOneShot::is_using_sync() const {
315 
316 	return sync;
317 }
318 
_bind_methods()319 void AnimationNodeOneShot::_bind_methods() {
320 
321 	ClassDB::bind_method(D_METHOD("set_fadein_time", "time"), &AnimationNodeOneShot::set_fadein_time);
322 	ClassDB::bind_method(D_METHOD("get_fadein_time"), &AnimationNodeOneShot::get_fadein_time);
323 
324 	ClassDB::bind_method(D_METHOD("set_fadeout_time", "time"), &AnimationNodeOneShot::set_fadeout_time);
325 	ClassDB::bind_method(D_METHOD("get_fadeout_time"), &AnimationNodeOneShot::get_fadeout_time);
326 
327 	ClassDB::bind_method(D_METHOD("set_autorestart", "enable"), &AnimationNodeOneShot::set_autorestart);
328 	ClassDB::bind_method(D_METHOD("has_autorestart"), &AnimationNodeOneShot::has_autorestart);
329 
330 	ClassDB::bind_method(D_METHOD("set_autorestart_delay", "enable"), &AnimationNodeOneShot::set_autorestart_delay);
331 	ClassDB::bind_method(D_METHOD("get_autorestart_delay"), &AnimationNodeOneShot::get_autorestart_delay);
332 
333 	ClassDB::bind_method(D_METHOD("set_autorestart_random_delay", "enable"), &AnimationNodeOneShot::set_autorestart_random_delay);
334 	ClassDB::bind_method(D_METHOD("get_autorestart_random_delay"), &AnimationNodeOneShot::get_autorestart_random_delay);
335 
336 	ClassDB::bind_method(D_METHOD("set_mix_mode", "mode"), &AnimationNodeOneShot::set_mix_mode);
337 	ClassDB::bind_method(D_METHOD("get_mix_mode"), &AnimationNodeOneShot::get_mix_mode);
338 
339 	ClassDB::bind_method(D_METHOD("set_use_sync", "enable"), &AnimationNodeOneShot::set_use_sync);
340 	ClassDB::bind_method(D_METHOD("is_using_sync"), &AnimationNodeOneShot::is_using_sync);
341 
342 	ADD_PROPERTY(PropertyInfo(Variant::REAL, "fadein_time", PROPERTY_HINT_RANGE, "0,60,0.01,or_greater"), "set_fadein_time", "get_fadein_time");
343 	ADD_PROPERTY(PropertyInfo(Variant::REAL, "fadeout_time", PROPERTY_HINT_RANGE, "0,60,0.01,or_greater"), "set_fadeout_time", "get_fadeout_time");
344 
345 	ADD_GROUP("autorestart_", "Auto Restart");
346 	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "autorestart"), "set_autorestart", "has_autorestart");
347 
348 	ADD_PROPERTY(PropertyInfo(Variant::REAL, "autorestart_delay", PROPERTY_HINT_RANGE, "0,60,0.01,or_greater"), "set_autorestart_delay", "get_autorestart_delay");
349 	ADD_PROPERTY(PropertyInfo(Variant::REAL, "autorestart_random_delay", PROPERTY_HINT_RANGE, "0,60,0.01,or_greater"), "set_autorestart_random_delay", "get_autorestart_random_delay");
350 
351 	ADD_GROUP("", "");
352 	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "sync"), "set_use_sync", "is_using_sync");
353 
354 	BIND_ENUM_CONSTANT(MIX_MODE_BLEND);
355 	BIND_ENUM_CONSTANT(MIX_MODE_ADD);
356 }
357 
AnimationNodeOneShot()358 AnimationNodeOneShot::AnimationNodeOneShot() {
359 
360 	add_input("in");
361 	add_input("shot");
362 
363 	fade_in = 0.1;
364 	fade_out = 0.1;
365 	autorestart = false;
366 	autorestart_delay = 1;
367 	autorestart_random_delay = 0;
368 
369 	mix = MIX_MODE_BLEND;
370 	sync = false;
371 
372 	active = "active";
373 	prev_active = "prev_active";
374 	time = "time";
375 	remaining = "remaining";
376 	time_to_restart = "time_to_restart";
377 }
378 
379 ////////////////////////////////////////////////
380 
get_parameter_list(List<PropertyInfo> * r_list) const381 void AnimationNodeAdd2::get_parameter_list(List<PropertyInfo> *r_list) const {
382 	r_list->push_back(PropertyInfo(Variant::REAL, add_amount, PROPERTY_HINT_RANGE, "0,1,0.01"));
383 }
get_parameter_default_value(const StringName & p_parameter) const384 Variant AnimationNodeAdd2::get_parameter_default_value(const StringName &p_parameter) const {
385 	return 0;
386 }
387 
get_caption() const388 String AnimationNodeAdd2::get_caption() const {
389 	return "Add2";
390 }
set_use_sync(bool p_sync)391 void AnimationNodeAdd2::set_use_sync(bool p_sync) {
392 
393 	sync = p_sync;
394 }
395 
is_using_sync() const396 bool AnimationNodeAdd2::is_using_sync() const {
397 
398 	return sync;
399 }
400 
has_filter() const401 bool AnimationNodeAdd2::has_filter() const {
402 
403 	return true;
404 }
405 
process(float p_time,bool p_seek)406 float AnimationNodeAdd2::process(float p_time, bool p_seek) {
407 
408 	float amount = get_parameter(add_amount);
409 	float rem0 = blend_input(0, p_time, p_seek, 1.0, FILTER_IGNORE, !sync);
410 	blend_input(1, p_time, p_seek, amount, FILTER_PASS, !sync);
411 
412 	return rem0;
413 }
414 
_bind_methods()415 void AnimationNodeAdd2::_bind_methods() {
416 
417 	ClassDB::bind_method(D_METHOD("set_use_sync", "enable"), &AnimationNodeAdd2::set_use_sync);
418 	ClassDB::bind_method(D_METHOD("is_using_sync"), &AnimationNodeAdd2::is_using_sync);
419 
420 	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "sync"), "set_use_sync", "is_using_sync");
421 }
422 
AnimationNodeAdd2()423 AnimationNodeAdd2::AnimationNodeAdd2() {
424 
425 	add_amount = "add_amount";
426 	add_input("in");
427 	add_input("add");
428 	sync = false;
429 }
430 
431 ////////////////////////////////////////////////
432 
get_parameter_list(List<PropertyInfo> * r_list) const433 void AnimationNodeAdd3::get_parameter_list(List<PropertyInfo> *r_list) const {
434 	r_list->push_back(PropertyInfo(Variant::REAL, add_amount, PROPERTY_HINT_RANGE, "-1,1,0.01"));
435 }
get_parameter_default_value(const StringName & p_parameter) const436 Variant AnimationNodeAdd3::get_parameter_default_value(const StringName &p_parameter) const {
437 	return 0;
438 }
439 
get_caption() const440 String AnimationNodeAdd3::get_caption() const {
441 	return "Add3";
442 }
set_use_sync(bool p_sync)443 void AnimationNodeAdd3::set_use_sync(bool p_sync) {
444 
445 	sync = p_sync;
446 }
447 
is_using_sync() const448 bool AnimationNodeAdd3::is_using_sync() const {
449 
450 	return sync;
451 }
452 
has_filter() const453 bool AnimationNodeAdd3::has_filter() const {
454 
455 	return true;
456 }
457 
process(float p_time,bool p_seek)458 float AnimationNodeAdd3::process(float p_time, bool p_seek) {
459 
460 	float amount = get_parameter(add_amount);
461 	blend_input(0, p_time, p_seek, MAX(0, -amount), FILTER_PASS, !sync);
462 	float rem0 = blend_input(1, p_time, p_seek, 1.0, FILTER_IGNORE, !sync);
463 	blend_input(2, p_time, p_seek, MAX(0, amount), FILTER_PASS, !sync);
464 
465 	return rem0;
466 }
467 
_bind_methods()468 void AnimationNodeAdd3::_bind_methods() {
469 
470 	ClassDB::bind_method(D_METHOD("set_use_sync", "enable"), &AnimationNodeAdd3::set_use_sync);
471 	ClassDB::bind_method(D_METHOD("is_using_sync"), &AnimationNodeAdd3::is_using_sync);
472 
473 	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "sync"), "set_use_sync", "is_using_sync");
474 }
475 
AnimationNodeAdd3()476 AnimationNodeAdd3::AnimationNodeAdd3() {
477 
478 	add_amount = "add_amount";
479 	add_input("-add");
480 	add_input("in");
481 	add_input("+add");
482 	sync = false;
483 }
484 /////////////////////////////////////////////
485 
get_parameter_list(List<PropertyInfo> * r_list) const486 void AnimationNodeBlend2::get_parameter_list(List<PropertyInfo> *r_list) const {
487 	r_list->push_back(PropertyInfo(Variant::REAL, blend_amount, PROPERTY_HINT_RANGE, "0,1,0.01"));
488 }
get_parameter_default_value(const StringName & p_parameter) const489 Variant AnimationNodeBlend2::get_parameter_default_value(const StringName &p_parameter) const {
490 	return 0; //for blend amount
491 }
492 
get_caption() const493 String AnimationNodeBlend2::get_caption() const {
494 	return "Blend2";
495 }
496 
process(float p_time,bool p_seek)497 float AnimationNodeBlend2::process(float p_time, bool p_seek) {
498 
499 	float amount = get_parameter(blend_amount);
500 
501 	float rem0 = blend_input(0, p_time, p_seek, 1.0 - amount, FILTER_BLEND, !sync);
502 	float rem1 = blend_input(1, p_time, p_seek, amount, FILTER_PASS, !sync);
503 
504 	return amount > 0.5 ? rem1 : rem0; //hacky but good enough
505 }
506 
set_use_sync(bool p_sync)507 void AnimationNodeBlend2::set_use_sync(bool p_sync) {
508 
509 	sync = p_sync;
510 }
511 
is_using_sync() const512 bool AnimationNodeBlend2::is_using_sync() const {
513 
514 	return sync;
515 }
516 
has_filter() const517 bool AnimationNodeBlend2::has_filter() const {
518 
519 	return true;
520 }
_bind_methods()521 void AnimationNodeBlend2::_bind_methods() {
522 
523 	ClassDB::bind_method(D_METHOD("set_use_sync", "enable"), &AnimationNodeBlend2::set_use_sync);
524 	ClassDB::bind_method(D_METHOD("is_using_sync"), &AnimationNodeBlend2::is_using_sync);
525 
526 	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "sync"), "set_use_sync", "is_using_sync");
527 }
AnimationNodeBlend2()528 AnimationNodeBlend2::AnimationNodeBlend2() {
529 	blend_amount = "blend_amount";
530 	add_input("in");
531 	add_input("blend");
532 	sync = false;
533 }
534 
535 //////////////////////////////////////
536 
get_parameter_list(List<PropertyInfo> * r_list) const537 void AnimationNodeBlend3::get_parameter_list(List<PropertyInfo> *r_list) const {
538 	r_list->push_back(PropertyInfo(Variant::REAL, blend_amount, PROPERTY_HINT_RANGE, "-1,1,0.01"));
539 }
get_parameter_default_value(const StringName & p_parameter) const540 Variant AnimationNodeBlend3::get_parameter_default_value(const StringName &p_parameter) const {
541 	return 0; //for blend amount
542 }
543 
get_caption() const544 String AnimationNodeBlend3::get_caption() const {
545 	return "Blend3";
546 }
547 
set_use_sync(bool p_sync)548 void AnimationNodeBlend3::set_use_sync(bool p_sync) {
549 
550 	sync = p_sync;
551 }
552 
is_using_sync() const553 bool AnimationNodeBlend3::is_using_sync() const {
554 
555 	return sync;
556 }
557 
process(float p_time,bool p_seek)558 float AnimationNodeBlend3::process(float p_time, bool p_seek) {
559 
560 	float amount = get_parameter(blend_amount);
561 	float rem0 = blend_input(0, p_time, p_seek, MAX(0, -amount), FILTER_IGNORE, !sync);
562 	float rem1 = blend_input(1, p_time, p_seek, 1.0 - ABS(amount), FILTER_IGNORE, !sync);
563 	float rem2 = blend_input(2, p_time, p_seek, MAX(0, amount), FILTER_IGNORE, !sync);
564 
565 	return amount > 0.5 ? rem2 : (amount < -0.5 ? rem0 : rem1); //hacky but good enough
566 }
567 
_bind_methods()568 void AnimationNodeBlend3::_bind_methods() {
569 
570 	ClassDB::bind_method(D_METHOD("set_use_sync", "enable"), &AnimationNodeBlend3::set_use_sync);
571 	ClassDB::bind_method(D_METHOD("is_using_sync"), &AnimationNodeBlend3::is_using_sync);
572 
573 	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "sync"), "set_use_sync", "is_using_sync");
574 }
AnimationNodeBlend3()575 AnimationNodeBlend3::AnimationNodeBlend3() {
576 	blend_amount = "blend_amount";
577 	add_input("-blend");
578 	add_input("in");
579 	add_input("+blend");
580 	sync = false;
581 }
582 
583 /////////////////////////////////
584 
get_parameter_list(List<PropertyInfo> * r_list) const585 void AnimationNodeTimeScale::get_parameter_list(List<PropertyInfo> *r_list) const {
586 	r_list->push_back(PropertyInfo(Variant::REAL, scale, PROPERTY_HINT_RANGE, "0,32,0.01,or_greater"));
587 }
get_parameter_default_value(const StringName & p_parameter) const588 Variant AnimationNodeTimeScale::get_parameter_default_value(const StringName &p_parameter) const {
589 	return 1.0; //initial timescale
590 }
591 
get_caption() const592 String AnimationNodeTimeScale::get_caption() const {
593 	return "TimeScale";
594 }
595 
process(float p_time,bool p_seek)596 float AnimationNodeTimeScale::process(float p_time, bool p_seek) {
597 
598 	float scale = get_parameter(this->scale);
599 	if (p_seek) {
600 		return blend_input(0, p_time, true, 1.0, FILTER_IGNORE, false);
601 	} else {
602 		return blend_input(0, p_time * scale, false, 1.0, FILTER_IGNORE, false);
603 	}
604 }
605 
_bind_methods()606 void AnimationNodeTimeScale::_bind_methods() {
607 }
AnimationNodeTimeScale()608 AnimationNodeTimeScale::AnimationNodeTimeScale() {
609 	scale = "scale";
610 	add_input("in");
611 }
612 
613 ////////////////////////////////////
614 
get_parameter_list(List<PropertyInfo> * r_list) const615 void AnimationNodeTimeSeek::get_parameter_list(List<PropertyInfo> *r_list) const {
616 	r_list->push_back(PropertyInfo(Variant::REAL, seek_pos, PROPERTY_HINT_RANGE, "-1,3600,0.01,or_greater"));
617 }
get_parameter_default_value(const StringName & p_parameter) const618 Variant AnimationNodeTimeSeek::get_parameter_default_value(const StringName &p_parameter) const {
619 	return 1.0; //initial timescale
620 }
621 
get_caption() const622 String AnimationNodeTimeSeek::get_caption() const {
623 	return "Seek";
624 }
625 
process(float p_time,bool p_seek)626 float AnimationNodeTimeSeek::process(float p_time, bool p_seek) {
627 
628 	float seek_pos = get_parameter(this->seek_pos);
629 	if (p_seek) {
630 		return blend_input(0, p_time, true, 1.0, FILTER_IGNORE, false);
631 	} else if (seek_pos >= 0) {
632 		float ret = blend_input(0, seek_pos, true, 1.0, FILTER_IGNORE, false);
633 		set_parameter(this->seek_pos, -1.0); //reset
634 		_change_notify("seek_pos");
635 		return ret;
636 	} else {
637 		return blend_input(0, p_time, false, 1.0, FILTER_IGNORE, false);
638 	}
639 }
640 
_bind_methods()641 void AnimationNodeTimeSeek::_bind_methods() {
642 }
643 
AnimationNodeTimeSeek()644 AnimationNodeTimeSeek::AnimationNodeTimeSeek() {
645 	add_input("in");
646 	seek_pos = "seek_position";
647 }
648 
649 /////////////////////////////////////////////////
650 
get_parameter_list(List<PropertyInfo> * r_list) const651 void AnimationNodeTransition::get_parameter_list(List<PropertyInfo> *r_list) const {
652 
653 	String anims;
654 	for (int i = 0; i < enabled_inputs; i++) {
655 		if (i > 0) {
656 			anims += ",";
657 		}
658 		anims += inputs[i].name;
659 	}
660 
661 	r_list->push_back(PropertyInfo(Variant::INT, current, PROPERTY_HINT_ENUM, anims));
662 	r_list->push_back(PropertyInfo(Variant::INT, prev_current, PROPERTY_HINT_NONE, "", 0));
663 	r_list->push_back(PropertyInfo(Variant::INT, prev, PROPERTY_HINT_NONE, "", 0));
664 	r_list->push_back(PropertyInfo(Variant::REAL, time, PROPERTY_HINT_NONE, "", 0));
665 	r_list->push_back(PropertyInfo(Variant::REAL, prev_xfading, PROPERTY_HINT_NONE, "", 0));
666 }
get_parameter_default_value(const StringName & p_parameter) const667 Variant AnimationNodeTransition::get_parameter_default_value(const StringName &p_parameter) const {
668 	if (p_parameter == time || p_parameter == prev_xfading) {
669 		return 0.0;
670 	} else if (p_parameter == prev || p_parameter == prev_current) {
671 		return -1;
672 	} else {
673 		return 0;
674 	}
675 }
676 
get_caption() const677 String AnimationNodeTransition::get_caption() const {
678 	return "Transition";
679 }
680 
_update_inputs()681 void AnimationNodeTransition::_update_inputs() {
682 	while (get_input_count() < enabled_inputs) {
683 		add_input(inputs[get_input_count()].name);
684 	}
685 
686 	while (get_input_count() > enabled_inputs) {
687 		remove_input(get_input_count() - 1);
688 	}
689 }
690 
set_enabled_inputs(int p_inputs)691 void AnimationNodeTransition::set_enabled_inputs(int p_inputs) {
692 	ERR_FAIL_INDEX(p_inputs, MAX_INPUTS);
693 	enabled_inputs = p_inputs;
694 	_update_inputs();
695 }
696 
get_enabled_inputs()697 int AnimationNodeTransition::get_enabled_inputs() {
698 	return enabled_inputs;
699 }
700 
set_input_as_auto_advance(int p_input,bool p_enable)701 void AnimationNodeTransition::set_input_as_auto_advance(int p_input, bool p_enable) {
702 	ERR_FAIL_INDEX(p_input, MAX_INPUTS);
703 	inputs[p_input].auto_advance = p_enable;
704 }
705 
is_input_set_as_auto_advance(int p_input) const706 bool AnimationNodeTransition::is_input_set_as_auto_advance(int p_input) const {
707 	ERR_FAIL_INDEX_V(p_input, MAX_INPUTS, false);
708 	return inputs[p_input].auto_advance;
709 }
710 
set_input_caption(int p_input,const String & p_name)711 void AnimationNodeTransition::set_input_caption(int p_input, const String &p_name) {
712 	ERR_FAIL_INDEX(p_input, MAX_INPUTS);
713 	inputs[p_input].name = p_name;
714 	set_input_name(p_input, p_name);
715 }
716 
get_input_caption(int p_input) const717 String AnimationNodeTransition::get_input_caption(int p_input) const {
718 	ERR_FAIL_INDEX_V(p_input, MAX_INPUTS, String());
719 	return inputs[p_input].name;
720 }
721 
set_cross_fade_time(float p_fade)722 void AnimationNodeTransition::set_cross_fade_time(float p_fade) {
723 	xfade = p_fade;
724 }
725 
get_cross_fade_time() const726 float AnimationNodeTransition::get_cross_fade_time() const {
727 	return xfade;
728 }
729 
process(float p_time,bool p_seek)730 float AnimationNodeTransition::process(float p_time, bool p_seek) {
731 
732 	int current = get_parameter(this->current);
733 	int prev = get_parameter(this->prev);
734 	int prev_current = get_parameter(this->prev_current);
735 
736 	float time = get_parameter(this->time);
737 	float prev_xfading = get_parameter(this->prev_xfading);
738 
739 	bool switched = current != prev_current;
740 
741 	if (switched) {
742 		set_parameter(this->prev_current, current);
743 		set_parameter(this->prev, prev_current);
744 
745 		prev = prev_current;
746 		prev_xfading = xfade;
747 		time = 0;
748 		switched = true;
749 	}
750 
751 	if (current < 0 || current >= enabled_inputs || prev >= enabled_inputs) {
752 		return 0;
753 	}
754 
755 	float rem = 0;
756 
757 	if (prev < 0) { // process current animation, check for transition
758 
759 		rem = blend_input(current, p_time, p_seek, 1.0, FILTER_IGNORE, false);
760 
761 		if (p_seek)
762 			time = p_time;
763 		else
764 			time += p_time;
765 
766 		if (inputs[current].auto_advance && rem <= xfade) {
767 
768 			set_parameter(this->current, (current + 1) % enabled_inputs);
769 		}
770 
771 	} else { // cross-fading from prev to current
772 
773 		float blend = xfade ? (prev_xfading / xfade) : 1;
774 
775 		if (!p_seek && switched) { //just switched, seek to start of current
776 
777 			rem = blend_input(current, 0, true, 1.0 - blend, FILTER_IGNORE, false);
778 		} else {
779 
780 			rem = blend_input(current, p_time, p_seek, 1.0 - blend, FILTER_IGNORE, false);
781 		}
782 
783 		if (p_seek) { // don't seek prev animation
784 			blend_input(prev, 0, false, blend, FILTER_IGNORE, false);
785 			time = p_time;
786 		} else {
787 			blend_input(prev, p_time, false, blend, FILTER_IGNORE, false);
788 			time += p_time;
789 			prev_xfading -= p_time;
790 			if (prev_xfading < 0) {
791 				set_parameter(this->prev, -1);
792 			}
793 		}
794 	}
795 
796 	set_parameter(this->time, time);
797 	set_parameter(this->prev_xfading, prev_xfading);
798 
799 	return rem;
800 }
801 
_validate_property(PropertyInfo & property) const802 void AnimationNodeTransition::_validate_property(PropertyInfo &property) const {
803 
804 	if (property.name.begins_with("input_")) {
805 		String n = property.name.get_slicec('/', 0).get_slicec('_', 1);
806 		if (n != "count") {
807 			int idx = n.to_int();
808 			if (idx >= enabled_inputs) {
809 				property.usage = 0;
810 			}
811 		}
812 	}
813 
814 	AnimationNode::_validate_property(property);
815 }
816 
_bind_methods()817 void AnimationNodeTransition::_bind_methods() {
818 
819 	ClassDB::bind_method(D_METHOD("set_enabled_inputs", "amount"), &AnimationNodeTransition::set_enabled_inputs);
820 	ClassDB::bind_method(D_METHOD("get_enabled_inputs"), &AnimationNodeTransition::get_enabled_inputs);
821 
822 	ClassDB::bind_method(D_METHOD("set_input_as_auto_advance", "input", "enable"), &AnimationNodeTransition::set_input_as_auto_advance);
823 	ClassDB::bind_method(D_METHOD("is_input_set_as_auto_advance", "input"), &AnimationNodeTransition::is_input_set_as_auto_advance);
824 
825 	ClassDB::bind_method(D_METHOD("set_input_caption", "input", "caption"), &AnimationNodeTransition::set_input_caption);
826 	ClassDB::bind_method(D_METHOD("get_input_caption", "input"), &AnimationNodeTransition::get_input_caption);
827 
828 	ClassDB::bind_method(D_METHOD("set_cross_fade_time", "time"), &AnimationNodeTransition::set_cross_fade_time);
829 	ClassDB::bind_method(D_METHOD("get_cross_fade_time"), &AnimationNodeTransition::get_cross_fade_time);
830 
831 	ADD_PROPERTY(PropertyInfo(Variant::INT, "input_count", PROPERTY_HINT_RANGE, "0,64,1", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), "set_enabled_inputs", "get_enabled_inputs");
832 	ADD_PROPERTY(PropertyInfo(Variant::REAL, "xfade_time", PROPERTY_HINT_RANGE, "0,120,0.01"), "set_cross_fade_time", "get_cross_fade_time");
833 
834 	for (int i = 0; i < MAX_INPUTS; i++) {
835 		ADD_PROPERTYI(PropertyInfo(Variant::STRING, "input_" + itos(i) + "/name", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_INTERNAL), "set_input_caption", "get_input_caption", i);
836 		ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "input_" + itos(i) + "/auto_advance", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_INTERNAL), "set_input_as_auto_advance", "is_input_set_as_auto_advance", i);
837 	}
838 }
839 
AnimationNodeTransition()840 AnimationNodeTransition::AnimationNodeTransition() {
841 
842 	prev_xfading = "prev_xfading";
843 	prev = "prev";
844 	time = "time";
845 	current = "current";
846 	prev_current = "prev_current";
847 	xfade = 0.0;
848 
849 	enabled_inputs = 0;
850 	for (int i = 0; i < MAX_INPUTS; i++) {
851 		inputs[i].auto_advance = false;
852 		inputs[i].name = "state " + itos(i);
853 	}
854 }
855 
856 /////////////////////
857 
get_caption() const858 String AnimationNodeOutput::get_caption() const {
859 	return "Output";
860 }
861 
process(float p_time,bool p_seek)862 float AnimationNodeOutput::process(float p_time, bool p_seek) {
863 	return blend_input(0, p_time, p_seek, 1.0);
864 }
865 
AnimationNodeOutput()866 AnimationNodeOutput::AnimationNodeOutput() {
867 	add_input("output");
868 }
869 
870 ///////////////////////////////////////////////////////
add_node(const StringName & p_name,Ref<AnimationNode> p_node,const Vector2 & p_position)871 void AnimationNodeBlendTree::add_node(const StringName &p_name, Ref<AnimationNode> p_node, const Vector2 &p_position) {
872 
873 	ERR_FAIL_COND(nodes.has(p_name));
874 	ERR_FAIL_COND(p_node.is_null());
875 	ERR_FAIL_COND(p_name == SceneStringNames::get_singleton()->output);
876 	ERR_FAIL_COND(String(p_name).find("/") != -1);
877 
878 	Node n;
879 	n.node = p_node;
880 	n.position = p_position;
881 	n.connections.resize(n.node->get_input_count());
882 	nodes[p_name] = n;
883 
884 	emit_changed();
885 	emit_signal("tree_changed");
886 
887 	p_node->connect("tree_changed", this, "_tree_changed", varray(), CONNECT_REFERENCE_COUNTED);
888 	p_node->connect("changed", this, "_node_changed", varray(p_name), CONNECT_REFERENCE_COUNTED);
889 }
890 
get_node(const StringName & p_name) const891 Ref<AnimationNode> AnimationNodeBlendTree::get_node(const StringName &p_name) const {
892 
893 	ERR_FAIL_COND_V(!nodes.has(p_name), Ref<AnimationNode>());
894 
895 	return nodes[p_name].node;
896 }
897 
get_node_name(const Ref<AnimationNode> & p_node) const898 StringName AnimationNodeBlendTree::get_node_name(const Ref<AnimationNode> &p_node) const {
899 	for (Map<StringName, Node>::Element *E = nodes.front(); E; E = E->next()) {
900 		if (E->get().node == p_node) {
901 			return E->key();
902 		}
903 	}
904 
905 	ERR_FAIL_V(StringName());
906 }
907 
set_node_position(const StringName & p_node,const Vector2 & p_position)908 void AnimationNodeBlendTree::set_node_position(const StringName &p_node, const Vector2 &p_position) {
909 	ERR_FAIL_COND(!nodes.has(p_node));
910 	nodes[p_node].position = p_position;
911 }
912 
get_node_position(const StringName & p_node) const913 Vector2 AnimationNodeBlendTree::get_node_position(const StringName &p_node) const {
914 	ERR_FAIL_COND_V(!nodes.has(p_node), Vector2());
915 	return nodes[p_node].position;
916 }
917 
get_child_nodes(List<ChildNode> * r_child_nodes)918 void AnimationNodeBlendTree::get_child_nodes(List<ChildNode> *r_child_nodes) {
919 	Vector<StringName> ns;
920 
921 	for (Map<StringName, Node>::Element *E = nodes.front(); E; E = E->next()) {
922 		ns.push_back(E->key());
923 	}
924 
925 	ns.sort_custom<StringName::AlphCompare>();
926 
927 	for (int i = 0; i < ns.size(); i++) {
928 		ChildNode cn;
929 		cn.name = ns[i];
930 		cn.node = nodes[cn.name].node;
931 		r_child_nodes->push_back(cn);
932 	}
933 }
934 
has_node(const StringName & p_name) const935 bool AnimationNodeBlendTree::has_node(const StringName &p_name) const {
936 	return nodes.has(p_name);
937 }
get_node_connection_array(const StringName & p_name) const938 Vector<StringName> AnimationNodeBlendTree::get_node_connection_array(const StringName &p_name) const {
939 
940 	ERR_FAIL_COND_V(!nodes.has(p_name), Vector<StringName>());
941 	return nodes[p_name].connections;
942 }
remove_node(const StringName & p_name)943 void AnimationNodeBlendTree::remove_node(const StringName &p_name) {
944 
945 	ERR_FAIL_COND(!nodes.has(p_name));
946 	ERR_FAIL_COND(p_name == SceneStringNames::get_singleton()->output); //can't delete output
947 
948 	{
949 		Ref<AnimationNode> node = nodes[p_name].node;
950 		node->disconnect("tree_changed", this, "_tree_changed");
951 		node->disconnect("changed", this, "_node_changed");
952 	}
953 
954 	nodes.erase(p_name);
955 
956 	//erase connections to name
957 	for (Map<StringName, Node>::Element *E = nodes.front(); E; E = E->next()) {
958 		for (int i = 0; i < E->get().connections.size(); i++) {
959 			if (E->get().connections[i] == p_name) {
960 				E->get().connections.write[i] = StringName();
961 			}
962 		}
963 	}
964 
965 	emit_changed();
966 	emit_signal("tree_changed");
967 }
968 
rename_node(const StringName & p_name,const StringName & p_new_name)969 void AnimationNodeBlendTree::rename_node(const StringName &p_name, const StringName &p_new_name) {
970 
971 	ERR_FAIL_COND(!nodes.has(p_name));
972 	ERR_FAIL_COND(nodes.has(p_new_name));
973 	ERR_FAIL_COND(p_name == SceneStringNames::get_singleton()->output);
974 	ERR_FAIL_COND(p_new_name == SceneStringNames::get_singleton()->output);
975 
976 	nodes[p_name].node->disconnect("changed", this, "_node_changed");
977 
978 	nodes[p_new_name] = nodes[p_name];
979 	nodes.erase(p_name);
980 
981 	//rename connections
982 	for (Map<StringName, Node>::Element *E = nodes.front(); E; E = E->next()) {
983 
984 		for (int i = 0; i < E->get().connections.size(); i++) {
985 			if (E->get().connections[i] == p_name) {
986 				E->get().connections.write[i] = p_new_name;
987 			}
988 		}
989 	}
990 	//connection must be done with new name
991 	nodes[p_new_name].node->connect("changed", this, "_node_changed", varray(p_new_name), CONNECT_REFERENCE_COUNTED);
992 
993 	emit_signal("tree_changed");
994 }
995 
connect_node(const StringName & p_input_node,int p_input_index,const StringName & p_output_node)996 void AnimationNodeBlendTree::connect_node(const StringName &p_input_node, int p_input_index, const StringName &p_output_node) {
997 
998 	ERR_FAIL_COND(!nodes.has(p_output_node));
999 	ERR_FAIL_COND(!nodes.has(p_input_node));
1000 	ERR_FAIL_COND(p_output_node == SceneStringNames::get_singleton()->output);
1001 	ERR_FAIL_COND(p_input_node == p_output_node);
1002 
1003 	Ref<AnimationNode> input = nodes[p_input_node].node;
1004 	ERR_FAIL_INDEX(p_input_index, nodes[p_input_node].connections.size());
1005 
1006 	for (Map<StringName, Node>::Element *E = nodes.front(); E; E = E->next()) {
1007 		for (int i = 0; i < E->get().connections.size(); i++) {
1008 			StringName output = E->get().connections[i];
1009 			ERR_FAIL_COND(output == p_output_node);
1010 		}
1011 	}
1012 
1013 	nodes[p_input_node].connections.write[p_input_index] = p_output_node;
1014 
1015 	emit_changed();
1016 }
1017 
disconnect_node(const StringName & p_node,int p_input_index)1018 void AnimationNodeBlendTree::disconnect_node(const StringName &p_node, int p_input_index) {
1019 
1020 	ERR_FAIL_COND(!nodes.has(p_node));
1021 
1022 	Ref<AnimationNode> input = nodes[p_node].node;
1023 	ERR_FAIL_INDEX(p_input_index, nodes[p_node].connections.size());
1024 
1025 	nodes[p_node].connections.write[p_input_index] = StringName();
1026 }
1027 
can_connect_node(const StringName & p_input_node,int p_input_index,const StringName & p_output_node) const1028 AnimationNodeBlendTree::ConnectionError AnimationNodeBlendTree::can_connect_node(const StringName &p_input_node, int p_input_index, const StringName &p_output_node) const {
1029 
1030 	if (!nodes.has(p_output_node) || p_output_node == SceneStringNames::get_singleton()->output) {
1031 		return CONNECTION_ERROR_NO_OUTPUT;
1032 	}
1033 
1034 	if (!nodes.has(p_input_node)) {
1035 		return CONNECTION_ERROR_NO_INPUT;
1036 	}
1037 
1038 	if (p_input_node == p_output_node) {
1039 		return CONNECTION_ERROR_SAME_NODE;
1040 	}
1041 
1042 	Ref<AnimationNode> input = nodes[p_input_node].node;
1043 
1044 	if (p_input_index < 0 || p_input_index >= nodes[p_input_node].connections.size()) {
1045 		return CONNECTION_ERROR_NO_INPUT_INDEX;
1046 	}
1047 
1048 	if (nodes[p_input_node].connections[p_input_index] != StringName()) {
1049 		return CONNECTION_ERROR_CONNECTION_EXISTS;
1050 	}
1051 
1052 	for (Map<StringName, Node>::Element *E = nodes.front(); E; E = E->next()) {
1053 		for (int i = 0; i < E->get().connections.size(); i++) {
1054 			StringName output = E->get().connections[i];
1055 			if (output == p_output_node) {
1056 				return CONNECTION_ERROR_CONNECTION_EXISTS;
1057 			}
1058 		}
1059 	}
1060 	return CONNECTION_OK;
1061 }
1062 
get_node_connections(List<NodeConnection> * r_connections) const1063 void AnimationNodeBlendTree::get_node_connections(List<NodeConnection> *r_connections) const {
1064 
1065 	for (Map<StringName, Node>::Element *E = nodes.front(); E; E = E->next()) {
1066 		for (int i = 0; i < E->get().connections.size(); i++) {
1067 			StringName output = E->get().connections[i];
1068 			if (output != StringName()) {
1069 				NodeConnection nc;
1070 				nc.input_node = E->key();
1071 				nc.input_index = i;
1072 				nc.output_node = output;
1073 				r_connections->push_back(nc);
1074 			}
1075 		}
1076 	}
1077 }
1078 
get_caption() const1079 String AnimationNodeBlendTree::get_caption() const {
1080 	return "BlendTree";
1081 }
1082 
process(float p_time,bool p_seek)1083 float AnimationNodeBlendTree::process(float p_time, bool p_seek) {
1084 
1085 	Ref<AnimationNodeOutput> output = nodes[SceneStringNames::get_singleton()->output].node;
1086 	return _blend_node("output", nodes[SceneStringNames::get_singleton()->output].connections, this, output, p_time, p_seek, 1.0);
1087 }
1088 
get_node_list(List<StringName> * r_list)1089 void AnimationNodeBlendTree::get_node_list(List<StringName> *r_list) {
1090 
1091 	for (Map<StringName, Node>::Element *E = nodes.front(); E; E = E->next()) {
1092 		r_list->push_back(E->key());
1093 	}
1094 }
1095 
set_graph_offset(const Vector2 & p_graph_offset)1096 void AnimationNodeBlendTree::set_graph_offset(const Vector2 &p_graph_offset) {
1097 
1098 	graph_offset = p_graph_offset;
1099 }
1100 
get_graph_offset() const1101 Vector2 AnimationNodeBlendTree::get_graph_offset() const {
1102 
1103 	return graph_offset;
1104 }
1105 
get_child_by_name(const StringName & p_name)1106 Ref<AnimationNode> AnimationNodeBlendTree::get_child_by_name(const StringName &p_name) {
1107 	return get_node(p_name);
1108 }
1109 
_set(const StringName & p_name,const Variant & p_value)1110 bool AnimationNodeBlendTree::_set(const StringName &p_name, const Variant &p_value) {
1111 
1112 	String name = p_name;
1113 	if (name.begins_with("nodes/")) {
1114 
1115 		String node_name = name.get_slicec('/', 1);
1116 		String what = name.get_slicec('/', 2);
1117 
1118 		if (what == "node") {
1119 			Ref<AnimationNode> anode = p_value;
1120 			if (anode.is_valid()) {
1121 				add_node(node_name, p_value);
1122 			}
1123 			return true;
1124 		}
1125 
1126 		if (what == "position") {
1127 
1128 			if (nodes.has(node_name)) {
1129 				nodes[node_name].position = p_value;
1130 			}
1131 			return true;
1132 		}
1133 	} else if (name == "node_connections") {
1134 
1135 		Array conns = p_value;
1136 		ERR_FAIL_COND_V(conns.size() % 3 != 0, false);
1137 
1138 		for (int i = 0; i < conns.size(); i += 3) {
1139 			connect_node(conns[i], conns[i + 1], conns[i + 2]);
1140 		}
1141 		return true;
1142 	}
1143 
1144 	return false;
1145 }
1146 
_get(const StringName & p_name,Variant & r_ret) const1147 bool AnimationNodeBlendTree::_get(const StringName &p_name, Variant &r_ret) const {
1148 
1149 	String name = p_name;
1150 	if (name.begins_with("nodes/")) {
1151 		String node_name = name.get_slicec('/', 1);
1152 		String what = name.get_slicec('/', 2);
1153 
1154 		if (what == "node") {
1155 			if (nodes.has(node_name)) {
1156 				r_ret = nodes[node_name].node;
1157 				return true;
1158 			}
1159 		}
1160 
1161 		if (what == "position") {
1162 
1163 			if (nodes.has(node_name)) {
1164 				r_ret = nodes[node_name].position;
1165 				return true;
1166 			}
1167 		}
1168 	} else if (name == "node_connections") {
1169 		List<NodeConnection> nc;
1170 		get_node_connections(&nc);
1171 		Array conns;
1172 		conns.resize(nc.size() * 3);
1173 
1174 		int idx = 0;
1175 		for (List<NodeConnection>::Element *E = nc.front(); E; E = E->next()) {
1176 			conns[idx * 3 + 0] = E->get().input_node;
1177 			conns[idx * 3 + 1] = E->get().input_index;
1178 			conns[idx * 3 + 2] = E->get().output_node;
1179 			idx++;
1180 		}
1181 
1182 		r_ret = conns;
1183 		return true;
1184 	}
1185 
1186 	return false;
1187 }
_get_property_list(List<PropertyInfo> * p_list) const1188 void AnimationNodeBlendTree::_get_property_list(List<PropertyInfo> *p_list) const {
1189 
1190 	List<StringName> names;
1191 	for (Map<StringName, Node>::Element *E = nodes.front(); E; E = E->next()) {
1192 		names.push_back(E->key());
1193 	}
1194 	names.sort_custom<StringName::AlphCompare>();
1195 
1196 	for (List<StringName>::Element *E = names.front(); E; E = E->next()) {
1197 		String name = E->get();
1198 		if (name != "output") {
1199 			p_list->push_back(PropertyInfo(Variant::OBJECT, "nodes/" + name + "/node", PROPERTY_HINT_RESOURCE_TYPE, "AnimationNode", PROPERTY_USAGE_NOEDITOR));
1200 		}
1201 		p_list->push_back(PropertyInfo(Variant::VECTOR2, "nodes/" + name + "/position", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR));
1202 	}
1203 
1204 	p_list->push_back(PropertyInfo(Variant::ARRAY, "node_connections", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR));
1205 }
1206 
_tree_changed()1207 void AnimationNodeBlendTree::_tree_changed() {
1208 	emit_signal("tree_changed");
1209 }
1210 
_node_changed(const StringName & p_node)1211 void AnimationNodeBlendTree::_node_changed(const StringName &p_node) {
1212 
1213 	ERR_FAIL_COND(!nodes.has(p_node));
1214 	nodes[p_node].connections.resize(nodes[p_node].node->get_input_count());
1215 }
1216 
_bind_methods()1217 void AnimationNodeBlendTree::_bind_methods() {
1218 
1219 	ClassDB::bind_method(D_METHOD("add_node", "name", "node", "position"), &AnimationNodeBlendTree::add_node, DEFVAL(Vector2()));
1220 	ClassDB::bind_method(D_METHOD("get_node", "name"), &AnimationNodeBlendTree::get_node);
1221 	ClassDB::bind_method(D_METHOD("remove_node", "name"), &AnimationNodeBlendTree::remove_node);
1222 	ClassDB::bind_method(D_METHOD("rename_node", "name", "new_name"), &AnimationNodeBlendTree::rename_node);
1223 	ClassDB::bind_method(D_METHOD("has_node", "name"), &AnimationNodeBlendTree::has_node);
1224 	ClassDB::bind_method(D_METHOD("connect_node", "input_node", "input_index", "output_node"), &AnimationNodeBlendTree::connect_node);
1225 	ClassDB::bind_method(D_METHOD("disconnect_node", "input_node", "input_index"), &AnimationNodeBlendTree::disconnect_node);
1226 
1227 	ClassDB::bind_method(D_METHOD("set_node_position", "name", "position"), &AnimationNodeBlendTree::set_node_position);
1228 	ClassDB::bind_method(D_METHOD("get_node_position", "name"), &AnimationNodeBlendTree::get_node_position);
1229 
1230 	ClassDB::bind_method(D_METHOD("set_graph_offset", "offset"), &AnimationNodeBlendTree::set_graph_offset);
1231 	ClassDB::bind_method(D_METHOD("get_graph_offset"), &AnimationNodeBlendTree::get_graph_offset);
1232 
1233 	ClassDB::bind_method(D_METHOD("_tree_changed"), &AnimationNodeBlendTree::_tree_changed);
1234 	ClassDB::bind_method(D_METHOD("_node_changed", "node"), &AnimationNodeBlendTree::_node_changed);
1235 
1236 	ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "graph_offset", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_graph_offset", "get_graph_offset");
1237 
1238 	BIND_CONSTANT(CONNECTION_OK);
1239 	BIND_CONSTANT(CONNECTION_ERROR_NO_INPUT);
1240 	BIND_CONSTANT(CONNECTION_ERROR_NO_INPUT_INDEX);
1241 	BIND_CONSTANT(CONNECTION_ERROR_NO_OUTPUT);
1242 	BIND_CONSTANT(CONNECTION_ERROR_SAME_NODE);
1243 	BIND_CONSTANT(CONNECTION_ERROR_CONNECTION_EXISTS);
1244 }
1245 
AnimationNodeBlendTree()1246 AnimationNodeBlendTree::AnimationNodeBlendTree() {
1247 
1248 	Ref<AnimationNodeOutput> output;
1249 	output.instance();
1250 	Node n;
1251 	n.node = output;
1252 	n.position = Vector2(300, 150);
1253 	n.connections.resize(1);
1254 	nodes["output"] = n;
1255 }
1256 
~AnimationNodeBlendTree()1257 AnimationNodeBlendTree::~AnimationNodeBlendTree() {
1258 }
1259