Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
godotengine
GitHub Repository: godotengine/godot
Path: blob/master/modules/jolt_physics/shapes/jolt_shape_3d.cpp
10278 views
1
/**************************************************************************/
2
/* jolt_shape_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 "jolt_shape_3d.h"
32
33
#include "../misc/jolt_type_conversions.h"
34
#include "../objects/jolt_shaped_object_3d.h"
35
#include "jolt_custom_double_sided_shape.h"
36
#include "jolt_custom_user_data_shape.h"
37
38
#include "Jolt/Physics/Collision/Shape/MutableCompoundShape.h"
39
#include "Jolt/Physics/Collision/Shape/OffsetCenterOfMassShape.h"
40
#include "Jolt/Physics/Collision/Shape/RotatedTranslatedShape.h"
41
#include "Jolt/Physics/Collision/Shape/ScaledShape.h"
42
#include "Jolt/Physics/Collision/Shape/SphereShape.h"
43
#include "Jolt/Physics/Collision/Shape/StaticCompoundShape.h"
44
45
namespace {
46
47
constexpr float DEFAULT_SOLVER_BIAS = 0.0;
48
49
} // namespace
50
51
String JoltShape3D::_owners_to_string() const {
52
const int owner_count = ref_counts_by_owner.size();
53
54
if (owner_count == 0) {
55
return "'<unknown>' and 0 other object(s)";
56
}
57
58
const JoltShapedObject3D &random_owner = *ref_counts_by_owner.begin()->key;
59
60
return vformat("'%s' and %d other object(s)", random_owner.to_string(), owner_count - 1);
61
}
62
63
JoltShape3D::~JoltShape3D() = default;
64
65
void JoltShape3D::add_owner(JoltShapedObject3D *p_owner) {
66
ref_counts_by_owner[p_owner]++;
67
}
68
69
void JoltShape3D::remove_owner(JoltShapedObject3D *p_owner) {
70
if (--ref_counts_by_owner[p_owner] <= 0) {
71
ref_counts_by_owner.erase(p_owner);
72
}
73
}
74
75
void JoltShape3D::remove_self() {
76
// `remove_owner` will be called when we `remove_shape`, so we need to copy the map since the
77
// iterator would be invalidated from underneath us.
78
const HashMap<JoltShapedObject3D *, int> ref_counts_by_owner_copy = ref_counts_by_owner;
79
80
for (const KeyValue<JoltShapedObject3D *, int> &E : ref_counts_by_owner_copy) {
81
E.key->remove_shape(this);
82
}
83
}
84
85
float JoltShape3D::get_solver_bias() const {
86
return DEFAULT_SOLVER_BIAS;
87
}
88
89
void JoltShape3D::set_solver_bias(float p_bias) {
90
if (!Math::is_equal_approx(p_bias, DEFAULT_SOLVER_BIAS)) {
91
WARN_PRINT(vformat("Custom solver bias for shapes is not supported when using Jolt Physics. Any such value will be ignored. This shape belongs to %s.", _owners_to_string()));
92
}
93
}
94
95
JPH::ShapeRefC JoltShape3D::try_build() {
96
jolt_ref_mutex.lock();
97
98
if (jolt_ref == nullptr) {
99
jolt_ref = _build();
100
}
101
102
jolt_ref_mutex.unlock();
103
104
return jolt_ref;
105
}
106
107
void JoltShape3D::destroy() {
108
jolt_ref_mutex.lock();
109
jolt_ref = nullptr;
110
jolt_ref_mutex.unlock();
111
112
for (const KeyValue<JoltShapedObject3D *, int> &E : ref_counts_by_owner) {
113
E.key->_shapes_changed();
114
}
115
}
116
117
JPH::ShapeRefC JoltShape3D::with_scale(const JPH::Shape *p_shape, const Vector3 &p_scale) {
118
ERR_FAIL_NULL_V(p_shape, nullptr);
119
120
const JPH::ScaledShapeSettings shape_settings(p_shape, to_jolt(p_scale));
121
const JPH::ShapeSettings::ShapeResult shape_result = shape_settings.Create();
122
ERR_FAIL_COND_V_MSG(shape_result.HasError(), nullptr, vformat("Failed to scale shape with {scale=%v}. It returned the following error: '%s'.", p_scale, to_godot(shape_result.GetError())));
123
124
return shape_result.Get();
125
}
126
127
JPH::ShapeRefC JoltShape3D::with_basis_origin(const JPH::Shape *p_shape, const Basis &p_basis, const Vector3 &p_origin) {
128
ERR_FAIL_NULL_V(p_shape, nullptr);
129
130
const JPH::RotatedTranslatedShapeSettings shape_settings(to_jolt(p_origin), to_jolt(p_basis), p_shape);
131
132
const JPH::ShapeSettings::ShapeResult shape_result = shape_settings.Create();
133
ERR_FAIL_COND_V_MSG(shape_result.HasError(), nullptr, vformat("Failed to offset shape with {basis=%s origin=%v}. It returned the following error: '%s'.", p_basis, p_origin, to_godot(shape_result.GetError())));
134
135
return shape_result.Get();
136
}
137
138
JPH::ShapeRefC JoltShape3D::with_center_of_mass_offset(const JPH::Shape *p_shape, const Vector3 &p_offset) {
139
ERR_FAIL_NULL_V(p_shape, nullptr);
140
141
const JPH::OffsetCenterOfMassShapeSettings shape_settings(to_jolt(p_offset), p_shape);
142
const JPH::ShapeSettings::ShapeResult shape_result = shape_settings.Create();
143
ERR_FAIL_COND_V_MSG(shape_result.HasError(), nullptr, vformat("Failed to offset center of mass with {offset=%v}. It returned the following error: '%s'.", p_offset, to_godot(shape_result.GetError())));
144
145
return shape_result.Get();
146
}
147
148
JPH::ShapeRefC JoltShape3D::with_center_of_mass(const JPH::Shape *p_shape, const Vector3 &p_center_of_mass) {
149
ERR_FAIL_NULL_V(p_shape, nullptr);
150
151
const Vector3 center_of_mass_inner = to_godot(p_shape->GetCenterOfMass());
152
const Vector3 center_of_mass_offset = p_center_of_mass - center_of_mass_inner;
153
154
if (center_of_mass_offset == Vector3()) {
155
return p_shape;
156
}
157
158
return with_center_of_mass_offset(p_shape, center_of_mass_offset);
159
}
160
161
JPH::ShapeRefC JoltShape3D::with_user_data(const JPH::Shape *p_shape, uint64_t p_user_data) {
162
JoltCustomUserDataShapeSettings shape_settings(p_shape);
163
shape_settings.mUserData = (JPH::uint64)p_user_data;
164
165
const JPH::ShapeSettings::ShapeResult shape_result = shape_settings.Create();
166
ERR_FAIL_COND_V_MSG(shape_result.HasError(), nullptr, vformat("Failed to override user data. It returned the following error: '%s'.", to_godot(shape_result.GetError())));
167
168
return shape_result.Get();
169
}
170
171
JPH::ShapeRefC JoltShape3D::with_double_sided(const JPH::Shape *p_shape, bool p_back_face_collision) {
172
ERR_FAIL_NULL_V(p_shape, nullptr);
173
174
const JoltCustomDoubleSidedShapeSettings shape_settings(p_shape, p_back_face_collision);
175
const JPH::ShapeSettings::ShapeResult shape_result = shape_settings.Create();
176
ERR_FAIL_COND_V_MSG(shape_result.HasError(), nullptr, vformat("Failed to make shape double-sided. It returned the following error: '%s'.", to_godot(shape_result.GetError())));
177
178
return shape_result.Get();
179
}
180
181
JPH::ShapeRefC JoltShape3D::without_custom_shapes(const JPH::Shape *p_shape) {
182
switch (p_shape->GetSubType()) {
183
case JoltCustomShapeSubType::RAY:
184
case JoltCustomShapeSubType::MOTION: {
185
// Replace unsupported shapes with a small sphere.
186
return new JPH::SphereShape(0.1f);
187
}
188
189
case JoltCustomShapeSubType::OVERRIDE_USER_DATA:
190
case JoltCustomShapeSubType::DOUBLE_SIDED: {
191
const JPH::DecoratedShape *shape = static_cast<const JPH::DecoratedShape *>(p_shape);
192
193
// Replace unsupported decorator shapes with the inner shape.
194
return without_custom_shapes(shape->GetInnerShape());
195
}
196
197
case JPH::EShapeSubType::StaticCompound: {
198
const JPH::StaticCompoundShape *shape = static_cast<const JPH::StaticCompoundShape *>(p_shape);
199
200
JPH::StaticCompoundShapeSettings settings;
201
202
for (const JPH::CompoundShape::SubShape &sub_shape : shape->GetSubShapes()) {
203
settings.AddShape(shape->GetCenterOfMass() + sub_shape.GetPositionCOM() - sub_shape.GetRotation() * sub_shape.mShape->GetCenterOfMass(), sub_shape.GetRotation(), without_custom_shapes(sub_shape.mShape));
204
}
205
206
const JPH::ShapeSettings::ShapeResult shape_result = settings.Create();
207
ERR_FAIL_COND_V_MSG(shape_result.HasError(), nullptr, vformat("Failed to recreate static compound shape during filtering of custom shapes. It returned the following error: '%s'.", to_godot(shape_result.GetError())));
208
209
return shape_result.Get();
210
}
211
212
case JPH::EShapeSubType::MutableCompound: {
213
const JPH::MutableCompoundShape *shape = static_cast<const JPH::MutableCompoundShape *>(p_shape);
214
215
JPH::MutableCompoundShapeSettings settings;
216
217
for (const JPH::MutableCompoundShape::SubShape &sub_shape : shape->GetSubShapes()) {
218
settings.AddShape(shape->GetCenterOfMass() + sub_shape.GetPositionCOM() - sub_shape.GetRotation() * sub_shape.mShape->GetCenterOfMass(), sub_shape.GetRotation(), without_custom_shapes(sub_shape.mShape));
219
}
220
221
const JPH::ShapeSettings::ShapeResult shape_result = settings.Create();
222
ERR_FAIL_COND_V_MSG(shape_result.HasError(), nullptr, vformat("Failed to recreate mutable compound shape during filtering of custom shapes. It returned the following error: '%s'.", to_godot(shape_result.GetError())));
223
224
return shape_result.Get();
225
}
226
227
case JPH::EShapeSubType::RotatedTranslated: {
228
const JPH::RotatedTranslatedShape *shape = static_cast<const JPH::RotatedTranslatedShape *>(p_shape);
229
230
const JPH::Shape *inner_shape = shape->GetInnerShape();
231
const JPH::ShapeRefC new_inner_shape = without_custom_shapes(inner_shape);
232
233
if (inner_shape == new_inner_shape) {
234
return p_shape;
235
}
236
237
return new JPH::RotatedTranslatedShape(shape->GetPosition(), shape->GetRotation(), new_inner_shape);
238
}
239
240
case JPH::EShapeSubType::Scaled: {
241
const JPH::ScaledShape *shape = static_cast<const JPH::ScaledShape *>(p_shape);
242
243
const JPH::Shape *inner_shape = shape->GetInnerShape();
244
const JPH::ShapeRefC new_inner_shape = without_custom_shapes(inner_shape);
245
246
if (inner_shape == new_inner_shape) {
247
return p_shape;
248
}
249
250
return new JPH::ScaledShape(new_inner_shape, shape->GetScale());
251
}
252
253
case JPH::EShapeSubType::OffsetCenterOfMass: {
254
const JPH::OffsetCenterOfMassShape *shape = static_cast<const JPH::OffsetCenterOfMassShape *>(p_shape);
255
256
const JPH::Shape *inner_shape = shape->GetInnerShape();
257
const JPH::ShapeRefC new_inner_shape = without_custom_shapes(inner_shape);
258
259
if (inner_shape == new_inner_shape) {
260
return p_shape;
261
}
262
263
return new JPH::OffsetCenterOfMassShape(new_inner_shape, shape->GetOffset());
264
}
265
266
default: {
267
return p_shape;
268
}
269
}
270
}
271
272
Vector3 JoltShape3D::make_scale_valid(const JPH::Shape *p_shape, const Vector3 &p_scale) {
273
return to_godot(p_shape->MakeScaleValid(to_jolt(p_scale)));
274
}
275
276
bool JoltShape3D::is_scale_valid(const Vector3 &p_scale, const Vector3 &p_valid_scale, real_t p_tolerance) {
277
return Math::is_equal_approx(p_scale.x, p_valid_scale.x, p_tolerance) && Math::is_equal_approx(p_scale.y, p_valid_scale.y, p_tolerance) && Math::is_equal_approx(p_scale.z, p_valid_scale.z, p_tolerance);
278
}
279
280