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