Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
godotengine
GitHub Repository: godotengine/godot
Path: blob/master/scene/3d/bone_twist_disperser_3d.cpp
14709 views
1
/**************************************************************************/
2
/* bone_twist_disperser_3d.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 "bone_twist_disperser_3d.h"
32
33
bool BoneTwistDisperser3D::_set(const StringName &p_path, const Variant &p_value) {
34
String path = p_path;
35
36
if (path.begins_with("settings/")) {
37
int which = path.get_slicec('/', 1).to_int();
38
String what = path.get_slicec('/', 2);
39
ERR_FAIL_INDEX_V(which, (int)settings.size(), false);
40
41
if (what == "root_bone_name") {
42
set_root_bone_name(which, p_value);
43
} else if (what == "root_bone") {
44
set_root_bone(which, p_value);
45
} else if (what == "end_bone_name") {
46
set_end_bone_name(which, p_value);
47
} else if (what == "end_bone") {
48
set_end_bone(which, p_value);
49
} else if (what == "end_bone_direction") {
50
set_end_bone_direction(which, static_cast<BoneDirection>((int)p_value));
51
} else if (what == "extend_end_bone") {
52
set_extend_end_bone(which, p_value);
53
} else if (what == "twist_from_rest") {
54
set_twist_from_rest(which, p_value);
55
} else if (what == "twist_from") {
56
set_twist_from(which, p_value);
57
} else if (what == "disperse_mode") {
58
set_disperse_mode(which, static_cast<DisperseMode>((int)p_value));
59
} else if (what == "weight_position") {
60
set_weight_position(which, p_value);
61
} else if (what == "damping_curve") {
62
set_damping_curve(which, p_value);
63
} else if (what == "joint_count") {
64
set_joint_count(which, p_value);
65
} else if (what == "joints") {
66
int idx = path.get_slicec('/', 3).to_int();
67
String prop = path.get_slicec('/', 4);
68
if (prop == "bone_name") {
69
set_joint_bone_name(which, idx, p_value);
70
} else if (prop == "bone") {
71
set_joint_bone(which, idx, p_value);
72
} else if (prop == "twist_amount") {
73
set_joint_twist_amount(which, idx, p_value);
74
} else {
75
return false;
76
}
77
} else {
78
return false;
79
}
80
}
81
return true;
82
}
83
84
bool BoneTwistDisperser3D::_get(const StringName &p_path, Variant &r_ret) const {
85
String path = p_path;
86
87
if (path.begins_with("settings/")) {
88
int which = path.get_slicec('/', 1).to_int();
89
String what = path.get_slicec('/', 2);
90
ERR_FAIL_INDEX_V(which, (int)settings.size(), false);
91
92
if (what == "root_bone_name") {
93
r_ret = get_root_bone_name(which);
94
} else if (what == "root_bone") {
95
r_ret = get_root_bone(which);
96
} else if (what == "end_bone_name") {
97
r_ret = get_end_bone_name(which);
98
} else if (what == "end_bone") {
99
r_ret = get_end_bone(which);
100
} else if (what == "end_bone_direction") {
101
r_ret = (int)get_end_bone_direction(which);
102
} else if (what == "reference_bone_name") {
103
r_ret = get_reference_bone_name(which);
104
} else if (what == "extend_end_bone") {
105
r_ret = is_end_bone_extended(which);
106
} else if (what == "twist_from_rest") {
107
r_ret = is_twist_from_rest(which);
108
} else if (what == "twist_from") {
109
r_ret = get_twist_from(which);
110
} else if (what == "disperse_mode") {
111
r_ret = (int)get_disperse_mode(which);
112
} else if (what == "weight_position") {
113
r_ret = get_weight_position(which);
114
} else if (what == "damping_curve") {
115
r_ret = get_damping_curve(which);
116
} else if (what == "joint_count") {
117
r_ret = get_joint_count(which);
118
} else if (what == "joints") {
119
int idx = path.get_slicec('/', 3).to_int();
120
String prop = path.get_slicec('/', 4);
121
if (prop == "bone_name") {
122
r_ret = get_joint_bone_name(which, idx);
123
} else if (prop == "bone") {
124
r_ret = get_joint_bone(which, idx);
125
} else if (prop == "twist_amount") {
126
r_ret = get_joint_twist_amount(which, idx);
127
} else {
128
return false;
129
}
130
} else {
131
return false;
132
}
133
}
134
return true;
135
}
136
137
void BoneTwistDisperser3D::_get_property_list(List<PropertyInfo> *p_list) const {
138
String enum_hint;
139
Skeleton3D *skeleton = get_skeleton();
140
if (skeleton) {
141
enum_hint = skeleton->get_concatenated_bone_names();
142
}
143
144
LocalVector<PropertyInfo> props;
145
146
for (uint32_t i = 0; i < settings.size(); i++) {
147
String path = "settings/" + itos(i) + "/";
148
props.push_back(PropertyInfo(Variant::STRING, path + "root_bone_name", PROPERTY_HINT_ENUM_SUGGESTION, enum_hint));
149
props.push_back(PropertyInfo(Variant::INT, path + "root_bone", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR));
150
props.push_back(PropertyInfo(Variant::STRING, path + "end_bone_name", PROPERTY_HINT_ENUM_SUGGESTION, enum_hint));
151
props.push_back(PropertyInfo(Variant::INT, path + "end_bone", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR));
152
props.push_back(PropertyInfo(Variant::BOOL, path + "extend_end_bone"));
153
props.push_back(PropertyInfo(Variant::INT, path + "end_bone_direction", PROPERTY_HINT_ENUM, SkeletonModifier3D::get_hint_bone_direction()));
154
155
props.push_back(PropertyInfo(Variant::STRING, path + "reference_bone_name", PROPERTY_HINT_ENUM_SUGGESTION, enum_hint, PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_READ_ONLY));
156
props.push_back(PropertyInfo(Variant::BOOL, path + "twist_from_rest"));
157
props.push_back(PropertyInfo(Variant::QUATERNION, path + "twist_from"));
158
props.push_back(PropertyInfo(Variant::INT, path + "disperse_mode", PROPERTY_HINT_ENUM, "Even,Weighted,Custom"));
159
props.push_back(PropertyInfo(Variant::FLOAT, path + "weight_position", PROPERTY_HINT_RANGE, "0,1,0.001"));
160
props.push_back(PropertyInfo(Variant::OBJECT, path + "damping_curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"));
161
162
props.push_back(PropertyInfo(Variant::INT, path + "joint_count", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_ARRAY, "Joints," + path + "joints/,static,const"));
163
for (uint32_t j = 0; j < settings[i]->joints.size(); j++) {
164
String joint_path = path + "joints/" + itos(j) + "/";
165
props.push_back(PropertyInfo(Variant::STRING, joint_path + "bone_name", PROPERTY_HINT_ENUM_SUGGESTION, enum_hint, PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_READ_ONLY));
166
props.push_back(PropertyInfo(Variant::INT, joint_path + "bone", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_READ_ONLY));
167
props.push_back(PropertyInfo(Variant::FLOAT, joint_path + "twist_amount", PROPERTY_HINT_RANGE, "0,1,0.001,or_greater,or_less"));
168
}
169
}
170
171
for (PropertyInfo &p : props) {
172
_validate_dynamic_prop(p);
173
p_list->push_back(p);
174
}
175
}
176
177
void BoneTwistDisperser3D::_validate_dynamic_prop(PropertyInfo &p_property) const {
178
PackedStringArray split = p_property.name.split("/");
179
if (split.size() > 2 && split[0] == "settings") {
180
int which = split[1].to_int();
181
182
// Extended end bone option.
183
bool force_hide = false;
184
if (split[2] == "extend_end_bone" && get_end_bone(which) == -1) {
185
p_property.usage = PROPERTY_USAGE_NONE;
186
force_hide = true;
187
}
188
if (force_hide || (split[2] == "end_bone_direction" && !is_end_bone_extended(which))) {
189
p_property.usage = PROPERTY_USAGE_NONE;
190
}
191
192
if (split[2] == "twist_from" && is_twist_from_rest(which)) {
193
p_property.usage = PROPERTY_USAGE_NONE;
194
}
195
196
if (split[2] == "weight_position" && get_disperse_mode(which) != DISPERSE_MODE_WEIGHTED) {
197
p_property.usage = PROPERTY_USAGE_NONE;
198
}
199
200
if (split[2] == "damping_curve" && get_disperse_mode(which) != DISPERSE_MODE_CUSTOM) {
201
p_property.usage = PROPERTY_USAGE_NONE;
202
}
203
204
if (split[2] == "joints" && split[4] == "twist_amount") {
205
bool mutable_amount = true;
206
if (get_disperse_mode(which) != DISPERSE_MODE_CUSTOM) {
207
mutable_amount = false;
208
} else if (!is_end_bone_extended(which)) {
209
int joint = split[3].to_int();
210
mutable_amount = joint < get_joint_count(which) - 1; // Hide child of reference bone.
211
}
212
if (get_damping_curve(which).is_valid()) {
213
p_property.usage |= PROPERTY_USAGE_READ_ONLY;
214
}
215
if (!mutable_amount) {
216
p_property.usage = PROPERTY_USAGE_NONE;
217
}
218
}
219
}
220
}
221
222
void BoneTwistDisperser3D::_notification(int p_what) {
223
switch (p_what) {
224
case NOTIFICATION_ENTER_TREE: {
225
_make_all_joints_dirty();
226
} break;
227
}
228
}
229
230
void BoneTwistDisperser3D::_set_active(bool p_active) {
231
if (p_active) {
232
_make_all_joints_dirty();
233
}
234
}
235
236
void BoneTwistDisperser3D::_skeleton_changed(Skeleton3D *p_old, Skeleton3D *p_new) {
237
_make_all_joints_dirty();
238
}
239
240
// Setting.
241
242
void BoneTwistDisperser3D::set_mutable_bone_axes(bool p_enabled) {
243
mutable_bone_axes = p_enabled;
244
}
245
246
bool BoneTwistDisperser3D::are_bone_axes_mutable() const {
247
return mutable_bone_axes;
248
}
249
250
void BoneTwistDisperser3D::set_root_bone_name(int p_index, const String &p_bone_name) {
251
ERR_FAIL_INDEX(p_index, (int)settings.size());
252
settings[p_index]->root_bone.name = p_bone_name;
253
Skeleton3D *sk = get_skeleton();
254
if (sk) {
255
set_root_bone(p_index, sk->find_bone(settings[p_index]->root_bone.name));
256
}
257
}
258
259
String BoneTwistDisperser3D::get_root_bone_name(int p_index) const {
260
ERR_FAIL_INDEX_V(p_index, (int)settings.size(), String());
261
return settings[p_index]->root_bone.name;
262
}
263
264
void BoneTwistDisperser3D::set_root_bone(int p_index, int p_bone) {
265
ERR_FAIL_INDEX(p_index, (int)settings.size());
266
bool changed = settings[p_index]->root_bone.bone != p_bone;
267
settings[p_index]->root_bone.bone = p_bone;
268
Skeleton3D *sk = get_skeleton();
269
if (sk) {
270
if (settings[p_index]->root_bone.bone <= -1 || settings[p_index]->root_bone.bone >= sk->get_bone_count()) {
271
WARN_PRINT("Root bone index out of range!");
272
settings[p_index]->root_bone.bone = -1;
273
} else {
274
settings[p_index]->root_bone.name = sk->get_bone_name(settings[p_index]->root_bone.bone);
275
}
276
}
277
if (changed) {
278
_make_joints_dirty(p_index);
279
}
280
}
281
282
int BoneTwistDisperser3D::get_root_bone(int p_index) const {
283
ERR_FAIL_INDEX_V(p_index, (int)settings.size(), -1);
284
return settings[p_index]->root_bone.bone;
285
}
286
287
void BoneTwistDisperser3D::set_end_bone_name(int p_index, const String &p_bone_name) {
288
ERR_FAIL_INDEX(p_index, (int)settings.size());
289
settings[p_index]->end_bone.name = p_bone_name;
290
Skeleton3D *sk = get_skeleton();
291
if (sk) {
292
set_end_bone(p_index, sk->find_bone(settings[p_index]->end_bone.name));
293
}
294
}
295
296
String BoneTwistDisperser3D::get_end_bone_name(int p_index) const {
297
ERR_FAIL_INDEX_V(p_index, (int)settings.size(), String());
298
return settings[p_index]->end_bone.name;
299
}
300
301
void BoneTwistDisperser3D::set_end_bone(int p_index, int p_bone) {
302
ERR_FAIL_INDEX(p_index, (int)settings.size());
303
bool changed = settings[p_index]->end_bone.bone != p_bone;
304
settings[p_index]->end_bone.bone = p_bone;
305
Skeleton3D *sk = get_skeleton();
306
if (sk) {
307
if (settings[p_index]->end_bone.bone <= -1 || settings[p_index]->end_bone.bone >= sk->get_bone_count()) {
308
WARN_PRINT("End bone index out of range!");
309
settings[p_index]->end_bone.bone = -1;
310
} else {
311
settings[p_index]->end_bone.name = sk->get_bone_name(settings[p_index]->end_bone.bone);
312
}
313
}
314
if (changed) {
315
_make_joints_dirty(p_index);
316
}
317
notify_property_list_changed();
318
}
319
320
int BoneTwistDisperser3D::get_end_bone(int p_index) const {
321
ERR_FAIL_INDEX_V(p_index, (int)settings.size(), -1);
322
return settings[p_index]->end_bone.bone;
323
}
324
325
void BoneTwistDisperser3D::set_extend_end_bone(int p_index, bool p_enabled) {
326
ERR_FAIL_INDEX(p_index, (int)settings.size());
327
settings[p_index]->extend_end_bone = p_enabled;
328
_update_reference_bone(p_index);
329
notify_property_list_changed();
330
}
331
332
bool BoneTwistDisperser3D::is_end_bone_extended(int p_index) const {
333
ERR_FAIL_INDEX_V(p_index, (int)settings.size(), false);
334
return settings[p_index]->extend_end_bone;
335
}
336
337
void BoneTwistDisperser3D::set_end_bone_direction(int p_index, BoneDirection p_bone_direction) {
338
ERR_FAIL_INDEX(p_index, (int)settings.size());
339
settings[p_index]->end_bone_direction = p_bone_direction;
340
}
341
342
SkeletonModifier3D::BoneDirection BoneTwistDisperser3D::get_end_bone_direction(int p_index) const {
343
ERR_FAIL_INDEX_V(p_index, (int)settings.size(), BONE_DIRECTION_FROM_PARENT);
344
return settings[p_index]->end_bone_direction;
345
}
346
347
void BoneTwistDisperser3D::set_twist_from_rest(int p_index, bool p_enabled) {
348
ERR_FAIL_INDEX(p_index, (int)settings.size());
349
settings[p_index]->twist_from_rest = p_enabled;
350
notify_property_list_changed();
351
}
352
353
bool BoneTwistDisperser3D::is_twist_from_rest(int p_index) const {
354
ERR_FAIL_INDEX_V(p_index, (int)settings.size(), true);
355
return settings[p_index]->twist_from_rest;
356
}
357
358
void BoneTwistDisperser3D::set_twist_from(int p_index, const Quaternion &p_from) {
359
ERR_FAIL_INDEX(p_index, (int)settings.size());
360
settings[p_index]->twist_from = p_from;
361
}
362
363
Quaternion BoneTwistDisperser3D::get_twist_from(int p_index) const {
364
ERR_FAIL_INDEX_V(p_index, (int)settings.size(), Quaternion());
365
return settings[p_index]->twist_from;
366
}
367
368
void BoneTwistDisperser3D::_update_reference_bone(int p_index) {
369
ERR_FAIL_INDEX(p_index, (int)settings.size());
370
LocalVector<DisperseJointSetting> &joints = settings[p_index]->joints;
371
if (joints.size() >= 2) {
372
if (settings[p_index]->extend_end_bone) {
373
settings[p_index]->reference_bone = settings[p_index]->end_bone;
374
_update_curve(p_index);
375
return;
376
} else {
377
Skeleton3D *sk = get_skeleton();
378
if (sk) {
379
int parent = sk->get_bone_parent(settings[p_index]->end_bone.bone);
380
if (parent >= 0) {
381
settings[p_index]->reference_bone.bone = parent;
382
settings[p_index]->reference_bone.name = sk->get_bone_name(parent);
383
_update_curve(p_index);
384
return;
385
}
386
}
387
}
388
}
389
settings[p_index]->reference_bone.bone = -1;
390
settings[p_index]->reference_bone.name = String();
391
}
392
393
void BoneTwistDisperser3D::_update_curve(int p_index) {
394
Ref<Curve> curve = settings[p_index]->damping_curve;
395
if (curve.is_null()) {
396
return;
397
}
398
LocalVector<DisperseJointSetting> &joints = settings[p_index]->joints;
399
float unit = (int)joints.size() > 0 ? (1.0 / float((int)joints.size() - 1)) : 0.0;
400
for (uint32_t i = 0; i < joints.size(); i++) {
401
joints[i].custom_amount = curve->sample_baked(i * unit);
402
}
403
}
404
405
String BoneTwistDisperser3D::get_reference_bone_name(int p_index) const {
406
ERR_FAIL_INDEX_V(p_index, (int)settings.size(), String());
407
return settings[p_index]->reference_bone.name;
408
}
409
410
int BoneTwistDisperser3D::get_reference_bone(int p_index) const {
411
ERR_FAIL_INDEX_V(p_index, (int)settings.size(), -1);
412
return settings[p_index]->reference_bone.bone;
413
}
414
415
void BoneTwistDisperser3D::set_disperse_mode(int p_index, DisperseMode p_disperse_mode) {
416
ERR_FAIL_INDEX(p_index, (int)settings.size());
417
settings[p_index]->disperse_mode = p_disperse_mode;
418
notify_property_list_changed();
419
}
420
421
BoneTwistDisperser3D::DisperseMode BoneTwistDisperser3D::get_disperse_mode(int p_index) const {
422
ERR_FAIL_INDEX_V(p_index, (int)settings.size(), DISPERSE_MODE_EVEN);
423
return settings[p_index]->disperse_mode;
424
}
425
426
void BoneTwistDisperser3D::set_weight_position(int p_index, float p_position) {
427
ERR_FAIL_INDEX(p_index, (int)settings.size());
428
settings[p_index]->weight_position = p_position;
429
}
430
431
float BoneTwistDisperser3D::get_weight_position(int p_index) const {
432
ERR_FAIL_INDEX_V(p_index, (int)settings.size(), 0.0);
433
return settings[p_index]->weight_position;
434
}
435
436
void BoneTwistDisperser3D::set_damping_curve(int p_index, const Ref<Curve> &p_damping_curve) {
437
ERR_FAIL_INDEX(p_index, (int)settings.size());
438
bool changed = settings[p_index]->damping_curve != p_damping_curve;
439
if (settings[p_index]->damping_curve.is_valid()) {
440
settings[p_index]->damping_curve->disconnect_changed(callable_mp(this, &BoneTwistDisperser3D::_update_curve));
441
}
442
settings[p_index]->damping_curve = p_damping_curve;
443
if (settings[p_index]->damping_curve.is_valid()) {
444
settings[p_index]->damping_curve->connect_changed(callable_mp(this, &BoneTwistDisperser3D::_update_curve).bind(p_index));
445
}
446
if (changed) {
447
_make_joints_dirty(p_index);
448
}
449
notify_property_list_changed();
450
}
451
452
Ref<Curve> BoneTwistDisperser3D::get_damping_curve(int p_index) const {
453
ERR_FAIL_INDEX_V(p_index, (int)settings.size(), Ref<Curve>());
454
return settings[p_index]->damping_curve;
455
}
456
457
// Individual joints.
458
459
void BoneTwistDisperser3D::set_joint_bone_name(int p_index, int p_joint, const String &p_bone_name) {
460
// Exists only for indicate bone name on the inspector, no needs to make dirty joint array.
461
ERR_FAIL_INDEX(p_index, (int)settings.size());
462
LocalVector<DisperseJointSetting> &joints = settings[p_index]->joints;
463
ERR_FAIL_INDEX(p_joint, (int)joints.size());
464
joints[p_joint].joint.name = p_bone_name;
465
Skeleton3D *sk = get_skeleton();
466
if (sk) {
467
set_joint_bone(p_index, p_joint, sk->find_bone(joints[p_joint].joint.name));
468
}
469
}
470
471
String BoneTwistDisperser3D::get_joint_bone_name(int p_index, int p_joint) const {
472
ERR_FAIL_INDEX_V(p_index, (int)settings.size(), String());
473
const LocalVector<DisperseJointSetting> &joints = settings[p_index]->joints;
474
ERR_FAIL_INDEX_V(p_joint, (int)joints.size(), String());
475
return joints[p_joint].joint.name;
476
}
477
478
void BoneTwistDisperser3D::set_joint_bone(int p_index, int p_joint, int p_bone) {
479
ERR_FAIL_INDEX(p_index, (int)settings.size());
480
LocalVector<DisperseJointSetting> &joints = settings[p_index]->joints;
481
ERR_FAIL_INDEX(p_joint, (int)joints.size());
482
joints[p_joint].joint.bone = p_bone;
483
Skeleton3D *sk = get_skeleton();
484
if (sk) {
485
if (joints[p_joint].joint.bone <= -1 || joints[p_joint].joint.bone >= sk->get_bone_count()) {
486
WARN_PRINT("Joint bone index out of range!");
487
joints[p_joint].joint.bone = -1;
488
} else {
489
joints[p_joint].joint.name = sk->get_bone_name(joints[p_joint].joint.bone);
490
}
491
}
492
}
493
494
int BoneTwistDisperser3D::get_joint_bone(int p_index, int p_joint) const {
495
ERR_FAIL_INDEX_V(p_index, (int)settings.size(), -1);
496
const LocalVector<DisperseJointSetting> &joints = settings[p_index]->joints;
497
ERR_FAIL_INDEX_V(p_joint, (int)joints.size(), -1);
498
return joints[p_joint].joint.bone;
499
}
500
501
void BoneTwistDisperser3D::set_joint_count(int p_index, int p_count) {
502
ERR_FAIL_INDEX(p_index, (int)settings.size());
503
ERR_FAIL_COND(p_count < 0);
504
LocalVector<DisperseJointSetting> &joints = settings[p_index]->joints;
505
joints.resize(p_count);
506
notify_property_list_changed();
507
}
508
509
int BoneTwistDisperser3D::get_joint_count(int p_index) const {
510
ERR_FAIL_INDEX_V(p_index, (int)settings.size(), 0);
511
const LocalVector<DisperseJointSetting> &joints = settings[p_index]->joints;
512
return joints.size();
513
}
514
515
void BoneTwistDisperser3D::set_joint_twist_amount(int p_index, int p_joint, float p_amount) {
516
ERR_FAIL_INDEX(p_index, (int)settings.size());
517
LocalVector<DisperseJointSetting> &joints = settings[p_index]->joints;
518
ERR_FAIL_INDEX(p_joint, (int)joints.size());
519
joints[p_joint].custom_amount = p_amount;
520
}
521
522
float BoneTwistDisperser3D::get_joint_twist_amount(int p_index, int p_joint) const {
523
ERR_FAIL_INDEX_V(p_index, (int)settings.size(), 0);
524
const LocalVector<DisperseJointSetting> &joints = settings[p_index]->joints;
525
ERR_FAIL_INDEX_V(p_joint, (int)joints.size(), 0);
526
return joints[p_joint].custom_amount;
527
}
528
529
void BoneTwistDisperser3D::_bind_methods() {
530
ClassDB::bind_method(D_METHOD("set_setting_count", "count"), &BoneTwistDisperser3D::set_setting_count);
531
ClassDB::bind_method(D_METHOD("get_setting_count"), &BoneTwistDisperser3D::get_setting_count);
532
ClassDB::bind_method(D_METHOD("clear_settings"), &BoneTwistDisperser3D::clear_settings);
533
534
ClassDB::bind_method(D_METHOD("set_mutable_bone_axes", "enabled"), &BoneTwistDisperser3D::set_mutable_bone_axes);
535
ClassDB::bind_method(D_METHOD("are_bone_axes_mutable"), &BoneTwistDisperser3D::are_bone_axes_mutable);
536
537
// Setting.
538
ClassDB::bind_method(D_METHOD("set_root_bone_name", "index", "bone_name"), &BoneTwistDisperser3D::set_root_bone_name);
539
ClassDB::bind_method(D_METHOD("get_root_bone_name", "index"), &BoneTwistDisperser3D::get_root_bone_name);
540
ClassDB::bind_method(D_METHOD("set_root_bone", "index", "bone"), &BoneTwistDisperser3D::set_root_bone);
541
ClassDB::bind_method(D_METHOD("get_root_bone", "index"), &BoneTwistDisperser3D::get_root_bone);
542
543
ClassDB::bind_method(D_METHOD("set_end_bone_name", "index", "bone_name"), &BoneTwistDisperser3D::set_end_bone_name);
544
ClassDB::bind_method(D_METHOD("get_end_bone_name", "index"), &BoneTwistDisperser3D::get_end_bone_name);
545
ClassDB::bind_method(D_METHOD("set_end_bone", "index", "bone"), &BoneTwistDisperser3D::set_end_bone);
546
ClassDB::bind_method(D_METHOD("get_end_bone", "index"), &BoneTwistDisperser3D::get_end_bone);
547
548
ClassDB::bind_method(D_METHOD("get_reference_bone_name", "index"), &BoneTwistDisperser3D::get_reference_bone_name);
549
ClassDB::bind_method(D_METHOD("get_reference_bone", "index"), &BoneTwistDisperser3D::get_reference_bone);
550
551
ClassDB::bind_method(D_METHOD("set_extend_end_bone", "index", "enabled"), &BoneTwistDisperser3D::set_extend_end_bone);
552
ClassDB::bind_method(D_METHOD("is_end_bone_extended", "index"), &BoneTwistDisperser3D::is_end_bone_extended);
553
ClassDB::bind_method(D_METHOD("set_end_bone_direction", "index", "bone_direction"), &BoneTwistDisperser3D::set_end_bone_direction);
554
ClassDB::bind_method(D_METHOD("get_end_bone_direction", "index"), &BoneTwistDisperser3D::get_end_bone_direction);
555
556
ClassDB::bind_method(D_METHOD("set_twist_from_rest", "index", "enabled"), &BoneTwistDisperser3D::set_twist_from_rest);
557
ClassDB::bind_method(D_METHOD("is_twist_from_rest", "index"), &BoneTwistDisperser3D::is_twist_from_rest);
558
ClassDB::bind_method(D_METHOD("set_twist_from", "index", "from"), &BoneTwistDisperser3D::set_twist_from);
559
ClassDB::bind_method(D_METHOD("get_twist_from", "index"), &BoneTwistDisperser3D::get_twist_from);
560
561
ClassDB::bind_method(D_METHOD("set_disperse_mode", "index", "disperse_mode"), &BoneTwistDisperser3D::set_disperse_mode);
562
ClassDB::bind_method(D_METHOD("get_disperse_mode", "index"), &BoneTwistDisperser3D::get_disperse_mode);
563
ClassDB::bind_method(D_METHOD("set_weight_position", "index", "weight_position"), &BoneTwistDisperser3D::set_weight_position);
564
ClassDB::bind_method(D_METHOD("get_weight_position", "index"), &BoneTwistDisperser3D::get_weight_position);
565
ClassDB::bind_method(D_METHOD("set_damping_curve", "index", "curve"), &BoneTwistDisperser3D::set_damping_curve);
566
ClassDB::bind_method(D_METHOD("get_damping_curve", "index"), &BoneTwistDisperser3D::get_damping_curve);
567
568
// Individual joints.
569
ClassDB::bind_method(D_METHOD("get_joint_bone_name", "index", "joint"), &BoneTwistDisperser3D::get_joint_bone_name);
570
ClassDB::bind_method(D_METHOD("get_joint_bone", "index", "joint"), &BoneTwistDisperser3D::get_joint_bone);
571
ClassDB::bind_method(D_METHOD("get_joint_twist_amount", "index", "joint"), &BoneTwistDisperser3D::get_joint_twist_amount);
572
ClassDB::bind_method(D_METHOD("set_joint_twist_amount", "index", "joint", "twist_amount"), &BoneTwistDisperser3D::set_joint_twist_amount);
573
574
ClassDB::bind_method(D_METHOD("get_joint_count", "index"), &BoneTwistDisperser3D::get_joint_count);
575
576
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "mutable_bone_axes"), "set_mutable_bone_axes", "are_bone_axes_mutable");
577
ADD_ARRAY_COUNT("Settings", "setting_count", "set_setting_count", "get_setting_count", "settings/");
578
579
BIND_ENUM_CONSTANT(DISPERSE_MODE_EVEN);
580
BIND_ENUM_CONSTANT(DISPERSE_MODE_WEIGHTED);
581
BIND_ENUM_CONSTANT(DISPERSE_MODE_CUSTOM);
582
}
583
584
void BoneTwistDisperser3D::_validate_bone_names() {
585
for (uint32_t i = 0; i < settings.size(); i++) {
586
// Prior bone name.
587
if (!settings[i]->root_bone.name.is_empty()) {
588
set_root_bone_name(i, settings[i]->root_bone.name);
589
} else if (settings[i]->root_bone.bone != -1) {
590
set_root_bone(i, settings[i]->root_bone.bone);
591
}
592
// Prior bone name.
593
if (!settings[i]->end_bone.name.is_empty()) {
594
set_end_bone_name(i, settings[i]->end_bone.name);
595
} else if (settings[i]->end_bone.bone != -1) {
596
set_end_bone(i, settings[i]->end_bone.bone);
597
}
598
}
599
}
600
601
void BoneTwistDisperser3D::_make_all_joints_dirty() {
602
for (uint32_t i = 0; i < settings.size(); i++) {
603
_make_joints_dirty(i);
604
}
605
}
606
607
void BoneTwistDisperser3D::_make_joints_dirty(int p_index) {
608
ERR_FAIL_INDEX(p_index, (int)settings.size());
609
if (settings[p_index]->joints_dirty) {
610
return;
611
}
612
settings[p_index]->joints_dirty = true;
613
callable_mp(this, &BoneTwistDisperser3D::_update_joints).call_deferred(p_index);
614
}
615
616
void BoneTwistDisperser3D::_update_joints(int p_index) {
617
Skeleton3D *sk = get_skeleton();
618
int current_bone = settings[p_index]->end_bone.bone;
619
int root_bone = settings[p_index]->root_bone.bone;
620
if (!sk || current_bone < 0 || root_bone < 0) {
621
set_joint_count(p_index, 0);
622
settings[p_index]->joints_dirty = false;
623
return;
624
}
625
626
// Validation.
627
bool valid = false;
628
while (current_bone >= 0) {
629
current_bone = sk->get_bone_parent(current_bone);
630
if (current_bone == root_bone) {
631
valid = true;
632
break;
633
}
634
}
635
636
if (!valid) {
637
set_joint_count(p_index, 0);
638
_update_reference_bone(p_index);
639
settings[p_index]->joints_dirty = false;
640
ERR_FAIL_EDMSG("End bone must be a child of the root bone.");
641
}
642
643
Vector<int> new_joints;
644
current_bone = settings[p_index]->end_bone.bone;
645
while (current_bone != root_bone) {
646
new_joints.push_back(current_bone);
647
current_bone = sk->get_bone_parent(current_bone);
648
}
649
new_joints.push_back(current_bone);
650
new_joints.reverse();
651
652
set_joint_count(p_index, new_joints.size());
653
for (uint32_t i = 0; i < new_joints.size(); i++) {
654
set_joint_bone(p_index, i, new_joints[i]);
655
}
656
657
_update_reference_bone(p_index);
658
settings[p_index]->joints_dirty = false;
659
}
660
661
int BoneTwistDisperser3D::get_setting_count() const {
662
return (int)settings.size();
663
}
664
665
void BoneTwistDisperser3D::set_setting_count(int p_count) {
666
ERR_FAIL_COND(p_count < 0);
667
int delta = p_count - settings.size();
668
if (delta < 0) {
669
for (int i = delta; i < 0; i++) {
670
memdelete(settings[settings.size() + i]);
671
settings[settings.size() + i] = nullptr;
672
}
673
}
674
settings.resize(p_count);
675
delta++;
676
if (delta > 1) {
677
for (int i = 1; i < delta; i++) {
678
settings[p_count - i] = memnew(BoneTwistDisperser3DSetting);
679
}
680
}
681
notify_property_list_changed();
682
}
683
684
void BoneTwistDisperser3D::clear_settings() {
685
set_setting_count(0);
686
}
687
688
void BoneTwistDisperser3D::_process_modification(double p_delta) {
689
Skeleton3D *skeleton = get_skeleton();
690
if (!skeleton) {
691
return;
692
}
693
for (BoneTwistDisperser3DSetting *setting : settings) {
694
if (!setting || setting->reference_bone.bone < 0) {
695
continue;
696
}
697
LocalVector<DisperseJointSetting> &joints = setting->joints;
698
// Calc amount.
699
int actual_joint_size = setting->extend_end_bone ? (int)joints.size() : (int)joints.size() - 1;
700
if (actual_joint_size <= 1) {
701
continue;
702
}
703
if (setting->disperse_mode == DISPERSE_MODE_EVEN) {
704
double div = 1.0 / actual_joint_size;
705
for (int i = 0; i < actual_joint_size; i++) {
706
joints[i].amount = ((double)i + 1.0) * div;
707
}
708
} else if (setting->disperse_mode == DISPERSE_MODE_WEIGHTED) {
709
// Assign length for each bone.
710
double total_length = 0.0;
711
double weight_sub = 1.0 - setting->weight_position;
712
if (mutable_bone_axes) {
713
for (int i = 0; i < actual_joint_size; i++) {
714
double length = 0.0;
715
if (i == 0) {
716
length = skeleton->get_bone_pose_position(joints[i + 1].joint.bone).length() * setting->weight_position;
717
} else if (i == actual_joint_size - 1) {
718
length = skeleton->get_bone_pose_position(joints[i].joint.bone).length() * weight_sub;
719
} else {
720
length = skeleton->get_bone_pose_position(joints[i].joint.bone).length() * setting->weight_position + skeleton->get_bone_pose_position(joints[i + 1].joint.bone).length() * weight_sub;
721
}
722
total_length += length;
723
joints[i].amount = total_length;
724
}
725
} else {
726
for (int i = 0; i < actual_joint_size; i++) {
727
double length = 0.0;
728
if (i == 0) {
729
length = skeleton->get_bone_rest(joints[i + 1].joint.bone).origin.length() * setting->weight_position;
730
} else if (i == actual_joint_size - 1) {
731
length = skeleton->get_bone_rest(joints[i].joint.bone).origin.length() * weight_sub;
732
} else {
733
length = skeleton->get_bone_rest(joints[i].joint.bone).origin.length() * setting->weight_position + skeleton->get_bone_rest(joints[i + 1].joint.bone).origin.length() * weight_sub;
734
}
735
total_length += length;
736
joints[i].amount = total_length;
737
}
738
}
739
if (Math::is_zero_approx(total_length)) {
740
continue;
741
}
742
// Normalize.
743
double div = 1.0 / total_length;
744
for (int i = 0; i < actual_joint_size; i++) {
745
joints[i].amount *= div;
746
}
747
} else {
748
for (int i = 0; i < actual_joint_size; i++) {
749
joints[i].amount = joints[i].custom_amount;
750
}
751
}
752
int end = actual_joint_size - 1;
753
joints[end].amount -= 1.0; // Remove twist from current pose.
754
755
// Retrieve axes.
756
if (mutable_bone_axes) {
757
for (int i = 0; i < end; i++) {
758
joints[i].axis = skeleton->get_bone_pose_position(joints[i + 1].joint.bone).normalized();
759
if (joints[i].axis.is_zero_approx() && i > 0) {
760
joints[i].axis = joints[i - 1].axis;
761
}
762
}
763
} else {
764
for (int i = 0; i < end; i++) {
765
joints[i].axis = skeleton->get_bone_rest(joints[i + 1].joint.bone).origin.normalized();
766
if (joints[i].axis.is_zero_approx() && i > 0) {
767
joints[i].axis = joints[i - 1].axis;
768
}
769
}
770
}
771
772
if (!setting->extend_end_bone) {
773
joints[end].axis = mutable_bone_axes ? skeleton->get_bone_pose_position(setting->end_bone.bone) : skeleton->get_bone_rest(setting->end_bone.bone).origin;
774
joints[end].axis.normalize();
775
} else if (setting->end_bone_direction == BONE_DIRECTION_FROM_PARENT) {
776
joints[end].axis = skeleton->get_bone_rest(setting->end_bone.bone).basis.xform_inv(mutable_bone_axes ? skeleton->get_bone_pose_position(setting->end_bone.bone) : skeleton->get_bone_rest(setting->end_bone.bone).origin);
777
joints[end].axis.normalize();
778
} else {
779
joints[end].axis = get_vector_from_bone_axis(static_cast<BoneAxis>((int)setting->end_bone_direction));
780
}
781
if (joints[end].axis.is_zero_approx() && end > 0) {
782
joints[end].axis = joints[end - 1].axis;
783
}
784
785
// Extract twist.
786
Quaternion twist_rest = setting->twist_from_rest ? skeleton->get_bone_rest(setting->reference_bone.bone).basis.get_rotation_quaternion() : setting->twist_from.normalized();
787
Quaternion ref_rot = twist_rest.inverse() * skeleton->get_bone_pose_rotation(setting->reference_bone.bone);
788
ref_rot.normalize();
789
double twist = get_roll_angle(ref_rot, joints[end].axis);
790
791
// Apply twist for each bone by their amount.
792
// Twist parent, then cancel all twists caused by this modifier in child, and re-apply accumulated twist.
793
Quaternion prev_rot;
794
if (mutable_bone_axes) {
795
for (int i = 0; i < actual_joint_size; i++) {
796
int bn = joints[i].joint.bone;
797
Quaternion cur_rot = Quaternion(joints[i].axis, twist * joints[i].amount);
798
skeleton->set_bone_pose_rotation(bn, prev_rot.inverse() * skeleton->get_bone_pose_rotation(bn) * cur_rot);
799
prev_rot = cur_rot;
800
}
801
} else {
802
for (int i = 0; i < actual_joint_size; i++) {
803
int bn = joints[i].joint.bone;
804
Quaternion cur_rot = Quaternion(joints[i].axis, twist * joints[i].amount);
805
skeleton->set_bone_pose_rotation(bn, prev_rot.inverse() * skeleton->get_bone_pose_rotation(bn) * cur_rot);
806
prev_rot = cur_rot;
807
}
808
}
809
}
810
}
811
812
BoneTwistDisperser3D::~BoneTwistDisperser3D() {
813
clear_settings();
814
}
815
816