Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
godotengine
GitHub Repository: godotengine/godot
Path: blob/master/scene/3d/bone_constraint_3d.cpp
9903 views
1
/**************************************************************************/
2
/* bone_constraint_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_constraint_3d.h"
32
33
bool BoneConstraint3D::_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, settings.size(), false);
40
41
if (what == "amount") {
42
set_amount(which, p_value);
43
} else if (what == "apply_bone_name") {
44
set_apply_bone_name(which, p_value);
45
} else if (what == "reference_bone_name") {
46
set_reference_bone_name(which, p_value);
47
} else if (what == "apply_bone") {
48
set_apply_bone(which, p_value);
49
} else if (what == "reference_bone") {
50
set_reference_bone(which, p_value);
51
} else {
52
return false;
53
}
54
}
55
return true;
56
}
57
58
bool BoneConstraint3D::_get(const StringName &p_path, Variant &r_ret) const {
59
String path = p_path;
60
61
if (path.begins_with("settings/")) {
62
int which = path.get_slicec('/', 1).to_int();
63
String what = path.get_slicec('/', 2);
64
ERR_FAIL_INDEX_V(which, settings.size(), false);
65
66
if (what == "amount") {
67
r_ret = get_amount(which);
68
} else if (what == "apply_bone_name") {
69
r_ret = get_apply_bone_name(which);
70
} else if (what == "reference_bone_name") {
71
r_ret = get_reference_bone_name(which);
72
} else if (what == "apply_bone") {
73
r_ret = get_apply_bone(which);
74
} else if (what == "reference_bone") {
75
r_ret = get_reference_bone(which);
76
} else {
77
return false;
78
}
79
}
80
return true;
81
}
82
83
void BoneConstraint3D::get_property_list(List<PropertyInfo> *p_list) const {
84
String enum_hint;
85
Skeleton3D *skeleton = get_skeleton();
86
if (skeleton) {
87
enum_hint = skeleton->get_concatenated_bone_names();
88
}
89
90
for (int i = 0; i < settings.size(); i++) {
91
String path = "settings/" + itos(i) + "/";
92
p_list->push_back(PropertyInfo(Variant::FLOAT, path + "amount", PROPERTY_HINT_RANGE, "0,1,0.001"));
93
p_list->push_back(PropertyInfo(Variant::STRING, path + "apply_bone_name", PROPERTY_HINT_ENUM_SUGGESTION, enum_hint));
94
p_list->push_back(PropertyInfo(Variant::INT, path + "apply_bone", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR));
95
p_list->push_back(PropertyInfo(Variant::STRING, path + "reference_bone_name", PROPERTY_HINT_ENUM_SUGGESTION, enum_hint));
96
p_list->push_back(PropertyInfo(Variant::INT, path + "reference_bone", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR));
97
}
98
}
99
100
void BoneConstraint3D::set_setting_count(int p_count) {
101
ERR_FAIL_COND(p_count < 0);
102
103
int delta = p_count - settings.size();
104
if (delta < 0) {
105
for (int i = delta; i < 0; i++) {
106
memdelete(settings[settings.size() + i]);
107
}
108
}
109
settings.resize(p_count);
110
delta++;
111
112
if (delta > 1) {
113
for (int i = 1; i < delta; i++) {
114
_validate_setting(p_count - i);
115
}
116
}
117
118
notify_property_list_changed();
119
}
120
121
int BoneConstraint3D::get_setting_count() const {
122
return settings.size();
123
}
124
125
void BoneConstraint3D::_validate_setting(int p_index) {
126
settings.write[p_index] = memnew(BoneConstraint3DSetting);
127
}
128
129
void BoneConstraint3D::clear_settings() {
130
set_setting_count(0);
131
}
132
133
void BoneConstraint3D::set_amount(int p_index, float p_amount) {
134
ERR_FAIL_INDEX(p_index, settings.size());
135
settings[p_index]->amount = p_amount;
136
}
137
138
float BoneConstraint3D::get_amount(int p_index) const {
139
ERR_FAIL_INDEX_V(p_index, settings.size(), 0.0);
140
return settings[p_index]->amount;
141
}
142
143
void BoneConstraint3D::set_apply_bone_name(int p_index, const String &p_bone_name) {
144
ERR_FAIL_INDEX(p_index, settings.size());
145
settings[p_index]->apply_bone_name = p_bone_name;
146
Skeleton3D *sk = get_skeleton();
147
if (sk) {
148
set_apply_bone(p_index, sk->find_bone(settings[p_index]->apply_bone_name));
149
}
150
}
151
152
String BoneConstraint3D::get_apply_bone_name(int p_index) const {
153
ERR_FAIL_INDEX_V(p_index, settings.size(), String());
154
return settings[p_index]->apply_bone_name;
155
}
156
157
void BoneConstraint3D::set_apply_bone(int p_index, int p_bone) {
158
ERR_FAIL_INDEX(p_index, settings.size());
159
settings[p_index]->apply_bone = p_bone;
160
Skeleton3D *sk = get_skeleton();
161
if (sk) {
162
if (settings[p_index]->apply_bone <= -1 || settings[p_index]->apply_bone >= sk->get_bone_count()) {
163
WARN_PRINT("apply bone index out of range!");
164
settings[p_index]->apply_bone = -1;
165
} else {
166
settings[p_index]->apply_bone_name = sk->get_bone_name(settings[p_index]->apply_bone);
167
}
168
}
169
}
170
171
int BoneConstraint3D::get_apply_bone(int p_index) const {
172
ERR_FAIL_INDEX_V(p_index, settings.size(), -1);
173
return settings[p_index]->apply_bone;
174
}
175
176
void BoneConstraint3D::set_reference_bone_name(int p_index, const String &p_bone_name) {
177
ERR_FAIL_INDEX(p_index, settings.size());
178
settings[p_index]->reference_bone_name = p_bone_name;
179
Skeleton3D *sk = get_skeleton();
180
if (sk) {
181
set_reference_bone(p_index, sk->find_bone(settings[p_index]->reference_bone_name));
182
}
183
}
184
185
String BoneConstraint3D::get_reference_bone_name(int p_index) const {
186
ERR_FAIL_INDEX_V(p_index, settings.size(), String());
187
return settings[p_index]->reference_bone_name;
188
}
189
190
void BoneConstraint3D::set_reference_bone(int p_index, int p_bone) {
191
ERR_FAIL_INDEX(p_index, settings.size());
192
settings[p_index]->reference_bone = p_bone;
193
Skeleton3D *sk = get_skeleton();
194
if (sk) {
195
if (settings[p_index]->reference_bone <= -1 || settings[p_index]->reference_bone >= sk->get_bone_count()) {
196
WARN_PRINT("reference bone index out of range!");
197
settings[p_index]->reference_bone = -1;
198
} else {
199
settings[p_index]->reference_bone_name = sk->get_bone_name(settings[p_index]->reference_bone);
200
}
201
}
202
}
203
204
int BoneConstraint3D::get_reference_bone(int p_index) const {
205
ERR_FAIL_INDEX_V(p_index, settings.size(), -1);
206
return settings[p_index]->reference_bone;
207
}
208
209
void BoneConstraint3D::_bind_methods() {
210
ClassDB::bind_method(D_METHOD("set_amount", "index", "amount"), &BoneConstraint3D::set_amount);
211
ClassDB::bind_method(D_METHOD("get_amount", "index"), &BoneConstraint3D::get_amount);
212
ClassDB::bind_method(D_METHOD("set_apply_bone_name", "index", "bone_name"), &BoneConstraint3D::set_apply_bone_name);
213
ClassDB::bind_method(D_METHOD("get_apply_bone_name", "index"), &BoneConstraint3D::get_apply_bone_name);
214
ClassDB::bind_method(D_METHOD("set_apply_bone", "index", "bone"), &BoneConstraint3D::set_apply_bone);
215
ClassDB::bind_method(D_METHOD("get_apply_bone", "index"), &BoneConstraint3D::get_apply_bone);
216
ClassDB::bind_method(D_METHOD("set_reference_bone_name", "index", "bone_name"), &BoneConstraint3D::set_reference_bone_name);
217
ClassDB::bind_method(D_METHOD("get_reference_bone_name", "index"), &BoneConstraint3D::get_reference_bone_name);
218
ClassDB::bind_method(D_METHOD("set_reference_bone", "index", "bone"), &BoneConstraint3D::set_reference_bone);
219
ClassDB::bind_method(D_METHOD("get_reference_bone", "index"), &BoneConstraint3D::get_reference_bone);
220
221
ClassDB::bind_method(D_METHOD("set_setting_count", "count"), &BoneConstraint3D::set_setting_count);
222
ClassDB::bind_method(D_METHOD("get_setting_count"), &BoneConstraint3D::get_setting_count);
223
ClassDB::bind_method(D_METHOD("clear_setting"), &BoneConstraint3D::clear_settings);
224
}
225
226
void BoneConstraint3D::_validate_bone_names() {
227
for (int i = 0; i < settings.size(); i++) {
228
// Prior bone name.
229
if (!settings[i]->apply_bone_name.is_empty()) {
230
set_apply_bone_name(i, settings[i]->apply_bone_name);
231
} else if (settings[i]->apply_bone != -1) {
232
set_apply_bone(i, settings[i]->apply_bone);
233
}
234
// Prior bone name.
235
if (!settings[i]->reference_bone_name.is_empty()) {
236
set_reference_bone_name(i, settings[i]->reference_bone_name);
237
} else if (settings[i]->reference_bone != -1) {
238
set_reference_bone(i, settings[i]->reference_bone);
239
}
240
}
241
}
242
243
void BoneConstraint3D::_process_modification(double p_delta) {
244
Skeleton3D *skeleton = get_skeleton();
245
if (!skeleton) {
246
return;
247
}
248
249
for (int i = 0; i < settings.size(); i++) {
250
int apply_bone = settings[i]->apply_bone;
251
if (apply_bone < 0) {
252
continue;
253
}
254
255
int reference_bone = settings[i]->reference_bone;
256
if (reference_bone < 0) {
257
continue;
258
}
259
260
float amount = settings[i]->amount;
261
if (amount <= 0) {
262
continue;
263
}
264
265
_process_constraint(i, skeleton, apply_bone, reference_bone, amount);
266
}
267
}
268
269
void BoneConstraint3D::_process_constraint(int p_index, Skeleton3D *p_skeleton, int p_apply_bone, int p_reference_bone, float p_amount) {
270
//
271
}
272
273
double BoneConstraint3D::symmetrize_angle(double p_angle) {
274
double angle = Math::fposmod(p_angle, Math::TAU);
275
return angle > Math::PI ? angle - Math::TAU : angle;
276
}
277
278
double BoneConstraint3D::get_roll_angle(const Quaternion &p_rotation, const Vector3 &p_roll_axis) {
279
// Ensure roll axis is normalized.
280
Vector3 roll_axis = p_roll_axis.normalized();
281
282
// Project the quaternion rotation onto the roll axis.
283
// This gives us the component of rotation around that axis.
284
double dot = p_rotation.x * roll_axis.x +
285
p_rotation.y * roll_axis.y +
286
p_rotation.z * roll_axis.z;
287
288
// Create a quaternion representing just the roll component.
289
Quaternion roll_component;
290
roll_component.x = roll_axis.x * dot;
291
roll_component.y = roll_axis.y * dot;
292
roll_component.z = roll_axis.z * dot;
293
roll_component.w = p_rotation.w;
294
295
// Normalize this component.
296
double length = roll_component.length();
297
if (length > CMP_EPSILON) {
298
roll_component = roll_component / length;
299
} else {
300
return 0.0;
301
}
302
303
// Extract the angle.
304
double angle = 2.0 * Math::acos(CLAMP(roll_component.w, -1.0, 1.0));
305
306
// Determine the sign.
307
double direction = (roll_component.x * roll_axis.x + roll_component.y * roll_axis.y + roll_component.z * roll_axis.z > 0) ? 1.0 : -1.0;
308
309
return symmetrize_angle(angle * direction);
310
}
311
312
BoneConstraint3D::~BoneConstraint3D() {
313
clear_settings();
314
}
315
316