Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
godotengine
GitHub Repository: godotengine/godot
Path: blob/master/scene/animation/animation_blend_space_2d.cpp
9896 views
1
/**************************************************************************/
2
/* animation_blend_space_2d.cpp */
3
/**************************************************************************/
4
/* This file is part of: */
5
/* GODOT ENGINE */
6
/* https://godotengine.org */
7
/**************************************************************************/
8
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
9
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
10
/* */
11
/* Permission is hereby granted, free of charge, to any person obtaining */
12
/* a copy of this software and associated documentation files (the */
13
/* "Software"), to deal in the Software without restriction, including */
14
/* without limitation the rights to use, copy, modify, merge, publish, */
15
/* distribute, sublicense, and/or sell copies of the Software, and to */
16
/* permit persons to whom the Software is furnished to do so, subject to */
17
/* the following conditions: */
18
/* */
19
/* The above copyright notice and this permission notice shall be */
20
/* included in all copies or substantial portions of the Software. */
21
/* */
22
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
23
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
24
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
25
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
26
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
27
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
28
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
29
/**************************************************************************/
30
31
#include "animation_blend_space_2d.h"
32
33
#include "animation_blend_tree.h"
34
#include "core/math/geometry_2d.h"
35
36
void AnimationNodeBlendSpace2D::get_parameter_list(List<PropertyInfo> *r_list) const {
37
AnimationNode::get_parameter_list(r_list);
38
r_list->push_back(PropertyInfo(Variant::VECTOR2, blend_position));
39
r_list->push_back(PropertyInfo(Variant::INT, closest, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE));
40
}
41
42
Variant AnimationNodeBlendSpace2D::get_parameter_default_value(const StringName &p_parameter) const {
43
Variant ret = AnimationNode::get_parameter_default_value(p_parameter);
44
if (ret != Variant()) {
45
return ret;
46
}
47
48
if (p_parameter == closest) {
49
return (int)-1;
50
} else {
51
return Vector2();
52
}
53
}
54
55
void AnimationNodeBlendSpace2D::get_child_nodes(List<ChildNode> *r_child_nodes) {
56
for (int i = 0; i < blend_points_used; i++) {
57
ChildNode cn;
58
cn.name = itos(i);
59
cn.node = blend_points[i].node;
60
r_child_nodes->push_back(cn);
61
}
62
}
63
64
void AnimationNodeBlendSpace2D::add_blend_point(const Ref<AnimationRootNode> &p_node, const Vector2 &p_position, int p_at_index) {
65
ERR_FAIL_COND(blend_points_used >= MAX_BLEND_POINTS);
66
ERR_FAIL_COND(p_node.is_null());
67
ERR_FAIL_COND(p_at_index < -1 || p_at_index > blend_points_used);
68
69
if (p_at_index == -1 || p_at_index == blend_points_used) {
70
p_at_index = blend_points_used;
71
} else {
72
for (int i = blend_points_used - 1; i > p_at_index; i--) {
73
blend_points[i] = blend_points[i - 1];
74
}
75
for (int i = 0; i < triangles.size(); i++) {
76
for (int j = 0; j < 3; j++) {
77
if (triangles[i].points[j] >= p_at_index) {
78
triangles.write[i].points[j]++;
79
}
80
}
81
}
82
}
83
blend_points[p_at_index].node = p_node;
84
blend_points[p_at_index].position = p_position;
85
86
blend_points[p_at_index].node->connect("tree_changed", callable_mp(this, &AnimationNodeBlendSpace2D::_tree_changed), CONNECT_REFERENCE_COUNTED);
87
blend_points[p_at_index].node->connect("animation_node_renamed", callable_mp(this, &AnimationNodeBlendSpace2D::_animation_node_renamed), CONNECT_REFERENCE_COUNTED);
88
blend_points[p_at_index].node->connect("animation_node_removed", callable_mp(this, &AnimationNodeBlendSpace2D::_animation_node_removed), CONNECT_REFERENCE_COUNTED);
89
blend_points_used++;
90
91
_queue_auto_triangles();
92
93
emit_signal(SNAME("tree_changed"));
94
}
95
96
void AnimationNodeBlendSpace2D::set_blend_point_position(int p_point, const Vector2 &p_position) {
97
ERR_FAIL_INDEX(p_point, blend_points_used);
98
blend_points[p_point].position = p_position;
99
_queue_auto_triangles();
100
}
101
102
void AnimationNodeBlendSpace2D::set_blend_point_node(int p_point, const Ref<AnimationRootNode> &p_node) {
103
ERR_FAIL_INDEX(p_point, blend_points_used);
104
ERR_FAIL_COND(p_node.is_null());
105
106
if (blend_points[p_point].node.is_valid()) {
107
blend_points[p_point].node->disconnect("tree_changed", callable_mp(this, &AnimationNodeBlendSpace2D::_tree_changed));
108
blend_points[p_point].node->disconnect("animation_node_renamed", callable_mp(this, &AnimationNodeBlendSpace2D::_animation_node_renamed));
109
blend_points[p_point].node->disconnect("animation_node_removed", callable_mp(this, &AnimationNodeBlendSpace2D::_animation_node_removed));
110
}
111
blend_points[p_point].node = p_node;
112
blend_points[p_point].node->connect("tree_changed", callable_mp(this, &AnimationNodeBlendSpace2D::_tree_changed), CONNECT_REFERENCE_COUNTED);
113
blend_points[p_point].node->connect("animation_node_renamed", callable_mp(this, &AnimationNodeBlendSpace2D::_animation_node_renamed), CONNECT_REFERENCE_COUNTED);
114
blend_points[p_point].node->connect("animation_node_removed", callable_mp(this, &AnimationNodeBlendSpace2D::_animation_node_removed), CONNECT_REFERENCE_COUNTED);
115
116
emit_signal(SNAME("tree_changed"));
117
}
118
119
Vector2 AnimationNodeBlendSpace2D::get_blend_point_position(int p_point) const {
120
ERR_FAIL_INDEX_V(p_point, MAX_BLEND_POINTS, Vector2());
121
return blend_points[p_point].position;
122
}
123
124
Ref<AnimationRootNode> AnimationNodeBlendSpace2D::get_blend_point_node(int p_point) const {
125
ERR_FAIL_INDEX_V(p_point, MAX_BLEND_POINTS, Ref<AnimationRootNode>());
126
return blend_points[p_point].node;
127
}
128
129
void AnimationNodeBlendSpace2D::remove_blend_point(int p_point) {
130
ERR_FAIL_INDEX(p_point, blend_points_used);
131
132
ERR_FAIL_COND(blend_points[p_point].node.is_null());
133
blend_points[p_point].node->disconnect("tree_changed", callable_mp(this, &AnimationNodeBlendSpace2D::_tree_changed));
134
blend_points[p_point].node->disconnect("animation_node_renamed", callable_mp(this, &AnimationNodeBlendSpace2D::_animation_node_renamed));
135
blend_points[p_point].node->disconnect("animation_node_removed", callable_mp(this, &AnimationNodeBlendSpace2D::_animation_node_removed));
136
137
for (int i = 0; i < triangles.size(); i++) {
138
bool erase = false;
139
for (int j = 0; j < 3; j++) {
140
if (triangles[i].points[j] == p_point) {
141
erase = true;
142
break;
143
} else if (triangles[i].points[j] > p_point) {
144
triangles.write[i].points[j]--;
145
}
146
}
147
if (erase) {
148
triangles.remove_at(i);
149
150
i--;
151
}
152
}
153
154
for (int i = p_point; i < blend_points_used - 1; i++) {
155
blend_points[i] = blend_points[i + 1];
156
}
157
blend_points_used--;
158
159
emit_signal(SNAME("animation_node_removed"), get_instance_id(), itos(p_point));
160
emit_signal(SNAME("tree_changed"));
161
}
162
163
int AnimationNodeBlendSpace2D::get_blend_point_count() const {
164
return blend_points_used;
165
}
166
167
bool AnimationNodeBlendSpace2D::has_triangle(int p_x, int p_y, int p_z) const {
168
ERR_FAIL_INDEX_V(p_x, blend_points_used, false);
169
ERR_FAIL_INDEX_V(p_y, blend_points_used, false);
170
ERR_FAIL_INDEX_V(p_z, blend_points_used, false);
171
172
BlendTriangle t;
173
t.points[0] = p_x;
174
t.points[1] = p_y;
175
t.points[2] = p_z;
176
177
SortArray<int> sort;
178
sort.sort(t.points, 3);
179
180
for (int i = 0; i < triangles.size(); i++) {
181
bool all_equal = true;
182
for (int j = 0; j < 3; j++) {
183
if (triangles[i].points[j] != t.points[j]) {
184
all_equal = false;
185
break;
186
}
187
}
188
if (all_equal) {
189
return true;
190
}
191
}
192
193
return false;
194
}
195
196
void AnimationNodeBlendSpace2D::add_triangle(int p_x, int p_y, int p_z, int p_at_index) {
197
ERR_FAIL_INDEX(p_x, blend_points_used);
198
ERR_FAIL_INDEX(p_y, blend_points_used);
199
ERR_FAIL_INDEX(p_z, blend_points_used);
200
201
_update_triangles();
202
203
BlendTriangle t;
204
t.points[0] = p_x;
205
t.points[1] = p_y;
206
t.points[2] = p_z;
207
208
SortArray<int> sort;
209
sort.sort(t.points, 3);
210
211
for (int i = 0; i < triangles.size(); i++) {
212
bool all_equal = true;
213
for (int j = 0; j < 3; j++) {
214
if (triangles[i].points[j] != t.points[j]) {
215
all_equal = false;
216
break;
217
}
218
}
219
ERR_FAIL_COND(all_equal);
220
}
221
222
if (p_at_index == -1 || p_at_index == triangles.size()) {
223
triangles.push_back(t);
224
} else {
225
triangles.insert(p_at_index, t);
226
}
227
}
228
229
int AnimationNodeBlendSpace2D::get_triangle_point(int p_triangle, int p_point) {
230
_update_triangles();
231
232
ERR_FAIL_INDEX_V(p_point, 3, -1);
233
ERR_FAIL_INDEX_V(p_triangle, triangles.size(), -1);
234
return triangles[p_triangle].points[p_point];
235
}
236
237
void AnimationNodeBlendSpace2D::remove_triangle(int p_triangle) {
238
ERR_FAIL_INDEX(p_triangle, triangles.size());
239
240
triangles.remove_at(p_triangle);
241
}
242
243
int AnimationNodeBlendSpace2D::get_triangle_count() const {
244
return triangles.size();
245
}
246
247
void AnimationNodeBlendSpace2D::set_min_space(const Vector2 &p_min) {
248
min_space = p_min;
249
if (min_space.x >= max_space.x) {
250
min_space.x = max_space.x - 1;
251
}
252
if (min_space.y >= max_space.y) {
253
min_space.y = max_space.y - 1;
254
}
255
}
256
257
Vector2 AnimationNodeBlendSpace2D::get_min_space() const {
258
return min_space;
259
}
260
261
void AnimationNodeBlendSpace2D::set_max_space(const Vector2 &p_max) {
262
max_space = p_max;
263
if (max_space.x <= min_space.x) {
264
max_space.x = min_space.x + 1;
265
}
266
if (max_space.y <= min_space.y) {
267
max_space.y = min_space.y + 1;
268
}
269
}
270
271
Vector2 AnimationNodeBlendSpace2D::get_max_space() const {
272
return max_space;
273
}
274
275
void AnimationNodeBlendSpace2D::set_snap(const Vector2 &p_snap) {
276
snap = p_snap;
277
}
278
279
Vector2 AnimationNodeBlendSpace2D::get_snap() const {
280
return snap;
281
}
282
283
void AnimationNodeBlendSpace2D::set_x_label(const String &p_label) {
284
x_label = p_label;
285
}
286
287
String AnimationNodeBlendSpace2D::get_x_label() const {
288
return x_label;
289
}
290
291
void AnimationNodeBlendSpace2D::set_y_label(const String &p_label) {
292
y_label = p_label;
293
}
294
295
String AnimationNodeBlendSpace2D::get_y_label() const {
296
return y_label;
297
}
298
299
void AnimationNodeBlendSpace2D::_add_blend_point(int p_index, const Ref<AnimationRootNode> &p_node) {
300
if (p_index == blend_points_used) {
301
add_blend_point(p_node, Vector2());
302
} else {
303
set_blend_point_node(p_index, p_node);
304
}
305
}
306
307
void AnimationNodeBlendSpace2D::_set_triangles(const Vector<int> &p_triangles) {
308
if (auto_triangles) {
309
return;
310
}
311
ERR_FAIL_COND(p_triangles.size() % 3 != 0);
312
for (int i = 0; i < p_triangles.size(); i += 3) {
313
add_triangle(p_triangles[i + 0], p_triangles[i + 1], p_triangles[i + 2]);
314
}
315
}
316
317
Vector<int> AnimationNodeBlendSpace2D::_get_triangles() const {
318
Vector<int> t;
319
if (auto_triangles && triangles_dirty) {
320
return t;
321
}
322
323
t.resize(triangles.size() * 3);
324
for (int i = 0; i < triangles.size(); i++) {
325
t.write[i * 3 + 0] = triangles[i].points[0];
326
t.write[i * 3 + 1] = triangles[i].points[1];
327
t.write[i * 3 + 2] = triangles[i].points[2];
328
}
329
return t;
330
}
331
332
void AnimationNodeBlendSpace2D::_queue_auto_triangles() {
333
if (!auto_triangles || triangles_dirty) {
334
return;
335
}
336
337
triangles_dirty = true;
338
callable_mp(this, &AnimationNodeBlendSpace2D::_update_triangles).call_deferred();
339
}
340
341
void AnimationNodeBlendSpace2D::_update_triangles() {
342
if (!auto_triangles || !triangles_dirty) {
343
return;
344
}
345
346
triangles_dirty = false;
347
triangles.clear();
348
if (blend_points_used < 3) {
349
emit_signal(SNAME("triangles_updated"));
350
return;
351
}
352
353
Vector<Vector2> points;
354
points.resize(blend_points_used);
355
for (int i = 0; i < blend_points_used; i++) {
356
points.write[i] = blend_points[i].position;
357
}
358
359
Vector<Delaunay2D::Triangle> tr = Delaunay2D::triangulate(points);
360
361
for (int i = 0; i < tr.size(); i++) {
362
add_triangle(tr[i].points[0], tr[i].points[1], tr[i].points[2]);
363
}
364
emit_signal(SNAME("triangles_updated"));
365
}
366
367
Vector2 AnimationNodeBlendSpace2D::get_closest_point(const Vector2 &p_point) {
368
_update_triangles();
369
370
if (triangles.is_empty()) {
371
return Vector2();
372
}
373
374
Vector2 best_point;
375
bool first = true;
376
377
for (int i = 0; i < triangles.size(); i++) {
378
Vector2 points[3];
379
for (int j = 0; j < 3; j++) {
380
points[j] = get_blend_point_position(get_triangle_point(i, j));
381
}
382
383
if (Geometry2D::is_point_in_triangle(p_point, points[0], points[1], points[2])) {
384
return p_point;
385
}
386
387
for (int j = 0; j < 3; j++) {
388
const Vector2 segment_a = points[j];
389
const Vector2 segment_b = points[(j + 1) % 3];
390
Vector2 closest_point = Geometry2D::get_closest_point_to_segment(p_point, segment_a, segment_b);
391
if (first || closest_point.distance_to(p_point) < best_point.distance_to(p_point)) {
392
best_point = closest_point;
393
first = false;
394
}
395
}
396
}
397
398
return best_point;
399
}
400
401
void AnimationNodeBlendSpace2D::_blend_triangle(const Vector2 &p_pos, const Vector2 *p_points, float *r_weights) {
402
if (p_pos.is_equal_approx(p_points[0])) {
403
r_weights[0] = 1;
404
r_weights[1] = 0;
405
r_weights[2] = 0;
406
return;
407
}
408
if (p_pos.is_equal_approx(p_points[1])) {
409
r_weights[0] = 0;
410
r_weights[1] = 1;
411
r_weights[2] = 0;
412
return;
413
}
414
if (p_pos.is_equal_approx(p_points[2])) {
415
r_weights[0] = 0;
416
r_weights[1] = 0;
417
r_weights[2] = 1;
418
return;
419
}
420
421
Vector2 v0 = p_points[1] - p_points[0];
422
Vector2 v1 = p_points[2] - p_points[0];
423
Vector2 v2 = p_pos - p_points[0];
424
425
float d00 = v0.dot(v0);
426
float d01 = v0.dot(v1);
427
float d11 = v1.dot(v1);
428
float d20 = v2.dot(v0);
429
float d21 = v2.dot(v1);
430
float denom = (d00 * d11 - d01 * d01);
431
if (denom == 0) {
432
r_weights[0] = 1;
433
r_weights[1] = 0;
434
r_weights[2] = 0;
435
return;
436
}
437
float v = (d11 * d20 - d01 * d21) / denom;
438
float w = (d00 * d21 - d01 * d20) / denom;
439
float u = 1.0f - v - w;
440
441
r_weights[0] = u;
442
r_weights[1] = v;
443
r_weights[2] = w;
444
}
445
446
AnimationNode::NodeTimeInfo AnimationNodeBlendSpace2D::_process(const AnimationMixer::PlaybackInfo p_playback_info, bool p_test_only) {
447
_update_triangles();
448
449
if (!blend_points_used) {
450
return NodeTimeInfo();
451
}
452
453
Vector2 blend_pos = get_parameter(blend_position);
454
int cur_closest = get_parameter(closest);
455
NodeTimeInfo mind; //time of min distance point
456
457
AnimationMixer::PlaybackInfo pi = p_playback_info;
458
459
if (blend_mode == BLEND_MODE_INTERPOLATED) {
460
if (triangles.is_empty()) {
461
return NodeTimeInfo();
462
}
463
464
Vector2 best_point;
465
bool first = true;
466
int blend_triangle = -1;
467
float blend_weights[3] = { 0, 0, 0 };
468
469
for (int i = 0; i < triangles.size(); i++) {
470
Vector2 points[3];
471
for (int j = 0; j < 3; j++) {
472
points[j] = get_blend_point_position(get_triangle_point(i, j));
473
}
474
475
if (Geometry2D::is_point_in_triangle(blend_pos, points[0], points[1], points[2])) {
476
blend_triangle = i;
477
_blend_triangle(blend_pos, points, blend_weights);
478
break;
479
}
480
481
for (int j = 0; j < 3; j++) {
482
const Vector2 segment_a = points[j];
483
const Vector2 segment_b = points[(j + 1) % 3];
484
Vector2 closest2 = Geometry2D::get_closest_point_to_segment(blend_pos, segment_a, segment_b);
485
if (first || closest2.distance_to(blend_pos) < best_point.distance_to(blend_pos)) {
486
best_point = closest2;
487
blend_triangle = i;
488
first = false;
489
const real_t d = segment_a.distance_to(segment_b);
490
if (d == 0.0) {
491
blend_weights[j] = 1.0;
492
blend_weights[(j + 1) % 3] = 0.0;
493
blend_weights[(j + 2) % 3] = 0.0;
494
} else {
495
const real_t c = segment_a.distance_to(closest2) / d;
496
497
blend_weights[j] = 1.0 - c;
498
blend_weights[(j + 1) % 3] = c;
499
blend_weights[(j + 2) % 3] = 0.0;
500
}
501
}
502
}
503
}
504
505
ERR_FAIL_COND_V(blend_triangle == -1, NodeTimeInfo()); //should never reach here
506
507
int triangle_points[3];
508
for (int j = 0; j < 3; j++) {
509
triangle_points[j] = get_triangle_point(blend_triangle, j);
510
}
511
512
first = true;
513
514
double max_weight = 0.0;
515
for (int i = 0; i < blend_points_used; i++) {
516
bool found = false;
517
for (int j = 0; j < 3; j++) {
518
if (i == triangle_points[j]) {
519
//blend with the given weight
520
pi.weight = blend_weights[j];
521
NodeTimeInfo t = blend_node(blend_points[i].node, blend_points[i].name, pi, FILTER_IGNORE, true, p_test_only);
522
if (first || pi.weight > max_weight) {
523
mind = t;
524
max_weight = pi.weight;
525
first = false;
526
}
527
found = true;
528
break;
529
}
530
}
531
532
if (sync && !found) {
533
pi.weight = 0;
534
blend_node(blend_points[i].node, blend_points[i].name, pi, FILTER_IGNORE, true, p_test_only);
535
}
536
}
537
} else {
538
int new_closest = -1;
539
float new_closest_dist = 1e20;
540
541
for (int i = 0; i < blend_points_used; i++) {
542
float d = blend_points[i].position.distance_squared_to(blend_pos);
543
if (d < new_closest_dist) {
544
new_closest = i;
545
new_closest_dist = d;
546
}
547
}
548
549
if (new_closest != cur_closest && new_closest != -1) {
550
if (blend_mode == BLEND_MODE_DISCRETE_CARRY && cur_closest != -1) {
551
NodeTimeInfo from;
552
// For ping-pong loop.
553
Ref<AnimationNodeAnimation> na_c = static_cast<Ref<AnimationNodeAnimation>>(blend_points[cur_closest].node);
554
Ref<AnimationNodeAnimation> na_n = static_cast<Ref<AnimationNodeAnimation>>(blend_points[new_closest].node);
555
if (na_c.is_valid() && na_n.is_valid()) {
556
na_n->process_state = process_state;
557
na_c->process_state = process_state;
558
559
na_n->set_backward(na_c->is_backward());
560
561
na_n = nullptr;
562
na_c = nullptr;
563
}
564
// See how much animation remains.
565
pi.seeked = false;
566
pi.weight = 0;
567
from = blend_node(blend_points[cur_closest].node, blend_points[cur_closest].name, pi, FILTER_IGNORE, true, true);
568
pi.time = from.position;
569
}
570
pi.seeked = true;
571
pi.weight = 1.0;
572
mind = blend_node(blend_points[new_closest].node, blend_points[new_closest].name, pi, FILTER_IGNORE, true, p_test_only);
573
cur_closest = new_closest;
574
} else {
575
pi.weight = 1.0;
576
mind = blend_node(blend_points[cur_closest].node, blend_points[cur_closest].name, pi, FILTER_IGNORE, true, p_test_only);
577
}
578
579
if (sync) {
580
pi = p_playback_info;
581
pi.weight = 0;
582
for (int i = 0; i < blend_points_used; i++) {
583
if (i != cur_closest) {
584
blend_node(blend_points[i].node, blend_points[i].name, pi, FILTER_IGNORE, true, p_test_only);
585
}
586
}
587
}
588
}
589
590
set_parameter(closest, cur_closest);
591
return mind;
592
}
593
594
String AnimationNodeBlendSpace2D::get_caption() const {
595
return "BlendSpace2D";
596
}
597
598
void AnimationNodeBlendSpace2D::_validate_property(PropertyInfo &p_property) const {
599
if (auto_triangles && p_property.name == "triangles") {
600
p_property.usage = PROPERTY_USAGE_NONE;
601
}
602
if (p_property.name.begins_with("blend_point_")) {
603
String left = p_property.name.get_slicec('/', 0);
604
int idx = left.get_slicec('_', 2).to_int();
605
if (idx >= blend_points_used) {
606
p_property.usage = PROPERTY_USAGE_NONE;
607
}
608
}
609
}
610
611
void AnimationNodeBlendSpace2D::set_auto_triangles(bool p_enable) {
612
if (auto_triangles == p_enable) {
613
return;
614
}
615
616
auto_triangles = p_enable;
617
_queue_auto_triangles();
618
}
619
620
bool AnimationNodeBlendSpace2D::get_auto_triangles() const {
621
return auto_triangles;
622
}
623
624
Ref<AnimationNode> AnimationNodeBlendSpace2D::get_child_by_name(const StringName &p_name) const {
625
return get_blend_point_node(p_name.operator String().to_int());
626
}
627
628
void AnimationNodeBlendSpace2D::set_blend_mode(BlendMode p_blend_mode) {
629
blend_mode = p_blend_mode;
630
}
631
632
AnimationNodeBlendSpace2D::BlendMode AnimationNodeBlendSpace2D::get_blend_mode() const {
633
return blend_mode;
634
}
635
636
void AnimationNodeBlendSpace2D::set_use_sync(bool p_sync) {
637
sync = p_sync;
638
}
639
640
bool AnimationNodeBlendSpace2D::is_using_sync() const {
641
return sync;
642
}
643
644
void AnimationNodeBlendSpace2D::_tree_changed() {
645
AnimationRootNode::_tree_changed();
646
}
647
648
void AnimationNodeBlendSpace2D::_animation_node_renamed(const ObjectID &p_oid, const String &p_old_name, const String &p_new_name) {
649
AnimationRootNode::_animation_node_renamed(p_oid, p_old_name, p_new_name);
650
}
651
652
void AnimationNodeBlendSpace2D::_animation_node_removed(const ObjectID &p_oid, const StringName &p_node) {
653
AnimationRootNode::_animation_node_removed(p_oid, p_node);
654
}
655
656
void AnimationNodeBlendSpace2D::_bind_methods() {
657
ClassDB::bind_method(D_METHOD("add_blend_point", "node", "pos", "at_index"), &AnimationNodeBlendSpace2D::add_blend_point, DEFVAL(-1));
658
ClassDB::bind_method(D_METHOD("set_blend_point_position", "point", "pos"), &AnimationNodeBlendSpace2D::set_blend_point_position);
659
ClassDB::bind_method(D_METHOD("get_blend_point_position", "point"), &AnimationNodeBlendSpace2D::get_blend_point_position);
660
ClassDB::bind_method(D_METHOD("set_blend_point_node", "point", "node"), &AnimationNodeBlendSpace2D::set_blend_point_node);
661
ClassDB::bind_method(D_METHOD("get_blend_point_node", "point"), &AnimationNodeBlendSpace2D::get_blend_point_node);
662
ClassDB::bind_method(D_METHOD("remove_blend_point", "point"), &AnimationNodeBlendSpace2D::remove_blend_point);
663
ClassDB::bind_method(D_METHOD("get_blend_point_count"), &AnimationNodeBlendSpace2D::get_blend_point_count);
664
665
ClassDB::bind_method(D_METHOD("add_triangle", "x", "y", "z", "at_index"), &AnimationNodeBlendSpace2D::add_triangle, DEFVAL(-1));
666
ClassDB::bind_method(D_METHOD("get_triangle_point", "triangle", "point"), &AnimationNodeBlendSpace2D::get_triangle_point);
667
ClassDB::bind_method(D_METHOD("remove_triangle", "triangle"), &AnimationNodeBlendSpace2D::remove_triangle);
668
ClassDB::bind_method(D_METHOD("get_triangle_count"), &AnimationNodeBlendSpace2D::get_triangle_count);
669
670
ClassDB::bind_method(D_METHOD("set_min_space", "min_space"), &AnimationNodeBlendSpace2D::set_min_space);
671
ClassDB::bind_method(D_METHOD("get_min_space"), &AnimationNodeBlendSpace2D::get_min_space);
672
673
ClassDB::bind_method(D_METHOD("set_max_space", "max_space"), &AnimationNodeBlendSpace2D::set_max_space);
674
ClassDB::bind_method(D_METHOD("get_max_space"), &AnimationNodeBlendSpace2D::get_max_space);
675
676
ClassDB::bind_method(D_METHOD("set_snap", "snap"), &AnimationNodeBlendSpace2D::set_snap);
677
ClassDB::bind_method(D_METHOD("get_snap"), &AnimationNodeBlendSpace2D::get_snap);
678
679
ClassDB::bind_method(D_METHOD("set_x_label", "text"), &AnimationNodeBlendSpace2D::set_x_label);
680
ClassDB::bind_method(D_METHOD("get_x_label"), &AnimationNodeBlendSpace2D::get_x_label);
681
682
ClassDB::bind_method(D_METHOD("set_y_label", "text"), &AnimationNodeBlendSpace2D::set_y_label);
683
ClassDB::bind_method(D_METHOD("get_y_label"), &AnimationNodeBlendSpace2D::get_y_label);
684
685
ClassDB::bind_method(D_METHOD("_add_blend_point", "index", "node"), &AnimationNodeBlendSpace2D::_add_blend_point);
686
687
ClassDB::bind_method(D_METHOD("_set_triangles", "triangles"), &AnimationNodeBlendSpace2D::_set_triangles);
688
ClassDB::bind_method(D_METHOD("_get_triangles"), &AnimationNodeBlendSpace2D::_get_triangles);
689
690
ClassDB::bind_method(D_METHOD("set_auto_triangles", "enable"), &AnimationNodeBlendSpace2D::set_auto_triangles);
691
ClassDB::bind_method(D_METHOD("get_auto_triangles"), &AnimationNodeBlendSpace2D::get_auto_triangles);
692
693
ClassDB::bind_method(D_METHOD("set_blend_mode", "mode"), &AnimationNodeBlendSpace2D::set_blend_mode);
694
ClassDB::bind_method(D_METHOD("get_blend_mode"), &AnimationNodeBlendSpace2D::get_blend_mode);
695
696
ClassDB::bind_method(D_METHOD("set_use_sync", "enable"), &AnimationNodeBlendSpace2D::set_use_sync);
697
ClassDB::bind_method(D_METHOD("is_using_sync"), &AnimationNodeBlendSpace2D::is_using_sync);
698
699
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "auto_triangles", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), "set_auto_triangles", "get_auto_triangles");
700
701
for (int i = 0; i < MAX_BLEND_POINTS; i++) {
702
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "blend_point_" + itos(i) + "/node", PROPERTY_HINT_RESOURCE_TYPE, "AnimationRootNode", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL), "_add_blend_point", "get_blend_point_node", i);
703
ADD_PROPERTYI(PropertyInfo(Variant::VECTOR2, "blend_point_" + itos(i) + "/pos", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL), "set_blend_point_position", "get_blend_point_position", i);
704
}
705
706
ADD_PROPERTY(PropertyInfo(Variant::PACKED_INT32_ARRAY, "triangles", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL), "_set_triangles", "_get_triangles");
707
708
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "min_space", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), "set_min_space", "get_min_space");
709
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "max_space", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), "set_max_space", "get_max_space");
710
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "snap", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), "set_snap", "get_snap");
711
ADD_PROPERTY(PropertyInfo(Variant::STRING, "x_label", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), "set_x_label", "get_x_label");
712
ADD_PROPERTY(PropertyInfo(Variant::STRING, "y_label", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), "set_y_label", "get_y_label");
713
ADD_PROPERTY(PropertyInfo(Variant::INT, "blend_mode", PROPERTY_HINT_ENUM, "Interpolated,Discrete,Carry", PROPERTY_USAGE_NO_EDITOR), "set_blend_mode", "get_blend_mode");
714
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "sync", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), "set_use_sync", "is_using_sync");
715
716
ADD_SIGNAL(MethodInfo("triangles_updated"));
717
BIND_ENUM_CONSTANT(BLEND_MODE_INTERPOLATED);
718
BIND_ENUM_CONSTANT(BLEND_MODE_DISCRETE);
719
BIND_ENUM_CONSTANT(BLEND_MODE_DISCRETE_CARRY);
720
}
721
722
AnimationNodeBlendSpace2D::AnimationNodeBlendSpace2D() {
723
for (int i = 0; i < MAX_BLEND_POINTS; i++) {
724
blend_points[i].name = itos(i);
725
}
726
}
727
728
AnimationNodeBlendSpace2D::~AnimationNodeBlendSpace2D() {
729
}
730
731