Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
godotengine
GitHub Repository: godotengine/godot
Path: blob/master/thirdparty/jolt_physics/Jolt/Physics/PhysicsScene.cpp
9913 views
1
// Jolt Physics Library (https://github.com/jrouwe/JoltPhysics)
2
// SPDX-FileCopyrightText: 2021 Jorrit Rouwe
3
// SPDX-License-Identifier: MIT
4
5
#include <Jolt/Jolt.h>
6
7
#include <Jolt/Physics/PhysicsScene.h>
8
#include <Jolt/Physics/PhysicsSystem.h>
9
#include <Jolt/Physics/Body/BodyLockMulti.h>
10
#include <Jolt/ObjectStream/TypeDeclarations.h>
11
12
JPH_NAMESPACE_BEGIN
13
14
JPH_IMPLEMENT_SERIALIZABLE_NON_VIRTUAL(PhysicsScene)
15
{
16
JPH_ADD_ATTRIBUTE(PhysicsScene, mBodies)
17
JPH_ADD_ATTRIBUTE(PhysicsScene, mConstraints)
18
JPH_ADD_ATTRIBUTE(PhysicsScene, mSoftBodies)
19
}
20
21
JPH_IMPLEMENT_SERIALIZABLE_NON_VIRTUAL(PhysicsScene::ConnectedConstraint)
22
{
23
JPH_ADD_ATTRIBUTE(PhysicsScene::ConnectedConstraint, mSettings)
24
JPH_ADD_ATTRIBUTE(PhysicsScene::ConnectedConstraint, mBody1)
25
JPH_ADD_ATTRIBUTE(PhysicsScene::ConnectedConstraint, mBody2)
26
}
27
28
void PhysicsScene::AddBody(const BodyCreationSettings &inBody)
29
{
30
mBodies.push_back(inBody);
31
}
32
33
void PhysicsScene::AddConstraint(const TwoBodyConstraintSettings *inConstraint, uint32 inBody1, uint32 inBody2)
34
{
35
mConstraints.emplace_back(inConstraint, inBody1, inBody2);
36
}
37
38
void PhysicsScene::AddSoftBody(const SoftBodyCreationSettings &inSoftBody)
39
{
40
mSoftBodies.push_back(inSoftBody);
41
}
42
43
bool PhysicsScene::FixInvalidScales()
44
{
45
const Vec3 unit_scale = Vec3::sOne();
46
47
bool success = true;
48
for (BodyCreationSettings &b : mBodies)
49
{
50
// Test if there is an invalid scale in the shape hierarchy
51
const Shape *shape = b.GetShape();
52
if (!shape->IsValidScale(unit_scale))
53
{
54
// Fix it up
55
Shape::ShapeResult result = shape->ScaleShape(unit_scale);
56
if (result.IsValid())
57
b.SetShape(result.Get());
58
else
59
success = false;
60
}
61
}
62
return success;
63
}
64
65
bool PhysicsScene::CreateBodies(PhysicsSystem *inSystem) const
66
{
67
BodyInterface &bi = inSystem->GetBodyInterface();
68
69
BodyIDVector body_ids;
70
body_ids.reserve(mBodies.size() + mSoftBodies.size());
71
72
// Create bodies
73
for (const BodyCreationSettings &b : mBodies)
74
{
75
const Body *body = bi.CreateBody(b);
76
if (body == nullptr)
77
break;
78
body_ids.push_back(body->GetID());
79
}
80
81
// Create soft bodies
82
for (const SoftBodyCreationSettings &b : mSoftBodies)
83
{
84
const Body *body = bi.CreateSoftBody(b);
85
if (body == nullptr)
86
break;
87
body_ids.push_back(body->GetID());
88
}
89
90
// Batch add bodies
91
BodyIDVector temp_body_ids = body_ids; // Body ID's get shuffled by AddBodiesPrepare
92
BodyInterface::AddState add_state = bi.AddBodiesPrepare(temp_body_ids.data(), (int)temp_body_ids.size());
93
bi.AddBodiesFinalize(temp_body_ids.data(), (int)temp_body_ids.size(), add_state, EActivation::Activate);
94
95
// If not all bodies are created, creating constraints will be unreliable
96
if (body_ids.size() != mBodies.size() + mSoftBodies.size())
97
return false;
98
99
// Create constraints
100
for (const ConnectedConstraint &cc : mConstraints)
101
{
102
BodyID body1_id = cc.mBody1 == cFixedToWorld? BodyID() : body_ids[cc.mBody1];
103
BodyID body2_id = cc.mBody2 == cFixedToWorld? BodyID() : body_ids[cc.mBody2];
104
Constraint *c = bi.CreateConstraint(cc.mSettings, body1_id, body2_id);
105
inSystem->AddConstraint(c);
106
}
107
108
// Everything was created
109
return true;
110
}
111
112
void PhysicsScene::SaveBinaryState(StreamOut &inStream, bool inSaveShapes, bool inSaveGroupFilter) const
113
{
114
BodyCreationSettings::ShapeToIDMap shape_to_id;
115
BodyCreationSettings::MaterialToIDMap material_to_id;
116
BodyCreationSettings::GroupFilterToIDMap group_filter_to_id;
117
SoftBodyCreationSettings::SharedSettingsToIDMap settings_to_id;
118
119
// Save bodies
120
inStream.Write((uint32)mBodies.size());
121
for (const BodyCreationSettings &b : mBodies)
122
b.SaveWithChildren(inStream, inSaveShapes? &shape_to_id : nullptr, inSaveShapes? &material_to_id : nullptr, inSaveGroupFilter? &group_filter_to_id : nullptr);
123
124
// Save constraints
125
inStream.Write((uint32)mConstraints.size());
126
for (const ConnectedConstraint &cc : mConstraints)
127
{
128
cc.mSettings->SaveBinaryState(inStream);
129
inStream.Write(cc.mBody1);
130
inStream.Write(cc.mBody2);
131
}
132
133
// Save soft bodies
134
inStream.Write((uint32)mSoftBodies.size());
135
for (const SoftBodyCreationSettings &b : mSoftBodies)
136
b.SaveWithChildren(inStream, &settings_to_id, &material_to_id, inSaveGroupFilter? &group_filter_to_id : nullptr);
137
}
138
139
PhysicsScene::PhysicsSceneResult PhysicsScene::sRestoreFromBinaryState(StreamIn &inStream)
140
{
141
PhysicsSceneResult result;
142
143
// Create scene
144
Ref<PhysicsScene> scene = new PhysicsScene();
145
146
BodyCreationSettings::IDToShapeMap id_to_shape;
147
BodyCreationSettings::IDToMaterialMap id_to_material;
148
BodyCreationSettings::IDToGroupFilterMap id_to_group_filter;
149
SoftBodyCreationSettings::IDToSharedSettingsMap id_to_settings;
150
151
// Reserve some memory to avoid frequent reallocations
152
id_to_shape.reserve(1024);
153
id_to_material.reserve(128);
154
id_to_group_filter.reserve(128);
155
156
// Read bodies
157
uint32 len = 0;
158
inStream.Read(len);
159
scene->mBodies.resize(len);
160
for (BodyCreationSettings &b : scene->mBodies)
161
{
162
// Read creation settings
163
BodyCreationSettings::BCSResult bcs_result = BodyCreationSettings::sRestoreWithChildren(inStream, id_to_shape, id_to_material, id_to_group_filter);
164
if (bcs_result.HasError())
165
{
166
result.SetError(bcs_result.GetError());
167
return result;
168
}
169
b = bcs_result.Get();
170
}
171
172
// Read constraints
173
len = 0;
174
inStream.Read(len);
175
scene->mConstraints.resize(len);
176
for (ConnectedConstraint &cc : scene->mConstraints)
177
{
178
ConstraintSettings::ConstraintResult c_result = ConstraintSettings::sRestoreFromBinaryState(inStream);
179
if (c_result.HasError())
180
{
181
result.SetError(c_result.GetError());
182
return result;
183
}
184
cc.mSettings = StaticCast<TwoBodyConstraintSettings>(c_result.Get());
185
inStream.Read(cc.mBody1);
186
inStream.Read(cc.mBody2);
187
}
188
189
// Read soft bodies
190
len = 0;
191
inStream.Read(len);
192
scene->mSoftBodies.resize(len);
193
for (SoftBodyCreationSettings &b : scene->mSoftBodies)
194
{
195
// Read creation settings
196
SoftBodyCreationSettings::SBCSResult sbcs_result = SoftBodyCreationSettings::sRestoreWithChildren(inStream, id_to_settings, id_to_material, id_to_group_filter);
197
if (sbcs_result.HasError())
198
{
199
result.SetError(sbcs_result.GetError());
200
return result;
201
}
202
b = sbcs_result.Get();
203
}
204
205
result.Set(scene);
206
return result;
207
}
208
209
void PhysicsScene::FromPhysicsSystem(const PhysicsSystem *inSystem)
210
{
211
// This map will track where each body went in mBodies
212
using BodyIDToIdxMap = UnorderedMap<BodyID, uint32>;
213
BodyIDToIdxMap body_id_to_idx;
214
215
// Map invalid ID
216
body_id_to_idx[BodyID()] = cFixedToWorld;
217
218
// Get all bodies
219
BodyIDVector body_ids;
220
inSystem->GetBodies(body_ids);
221
222
// Loop over all bodies
223
const BodyLockInterface &bli = inSystem->GetBodyLockInterface();
224
for (const BodyID &id : body_ids)
225
{
226
BodyLockRead lock(bli, id);
227
if (lock.Succeeded())
228
{
229
// Store location of body
230
body_id_to_idx[id] = (uint32)mBodies.size();
231
232
const Body &body = lock.GetBody();
233
234
// Convert to body creation settings
235
if (body.IsRigidBody())
236
AddBody(body.GetBodyCreationSettings());
237
else
238
AddSoftBody(body.GetSoftBodyCreationSettings());
239
}
240
}
241
242
// Loop over all constraints
243
Constraints constraints = inSystem->GetConstraints();
244
for (const Constraint *c : constraints)
245
if (c->GetType() == EConstraintType::TwoBodyConstraint)
246
{
247
// Cast to two body constraint
248
const TwoBodyConstraint *tbc = static_cast<const TwoBodyConstraint *>(c);
249
250
// Find the body indices
251
BodyIDToIdxMap::const_iterator b1 = body_id_to_idx.find(tbc->GetBody1()->GetID());
252
BodyIDToIdxMap::const_iterator b2 = body_id_to_idx.find(tbc->GetBody2()->GetID());
253
JPH_ASSERT(b1 != body_id_to_idx.end() && b2 != body_id_to_idx.end());
254
255
// Create constraint settings and add the constraint
256
Ref<ConstraintSettings> settings = c->GetConstraintSettings();
257
AddConstraint(StaticCast<TwoBodyConstraintSettings>(settings), b1->second, b2->second);
258
}
259
}
260
261
JPH_NAMESPACE_END
262
263