PhysicsScene.cpp 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216
  1. // SPDX-FileCopyrightText: 2021 Jorrit Rouwe
  2. // SPDX-License-Identifier: MIT
  3. #include <Jolt/Jolt.h>
  4. #include <Jolt/Physics/PhysicsScene.h>
  5. #include <Jolt/Physics/PhysicsSystem.h>
  6. #include <Jolt/Physics/Body/BodyLockMulti.h>
  7. #include <Jolt/ObjectStream/TypeDeclarations.h>
  8. JPH_NAMESPACE_BEGIN
  9. JPH_IMPLEMENT_SERIALIZABLE_NON_VIRTUAL(PhysicsScene)
  10. {
  11. JPH_ADD_ATTRIBUTE(PhysicsScene, mBodies)
  12. JPH_ADD_ATTRIBUTE(PhysicsScene, mConstraints)
  13. }
  14. JPH_IMPLEMENT_SERIALIZABLE_NON_VIRTUAL(PhysicsScene::ConnectedConstraint)
  15. {
  16. JPH_ADD_ATTRIBUTE(PhysicsScene::ConnectedConstraint, mSettings)
  17. JPH_ADD_ATTRIBUTE(PhysicsScene::ConnectedConstraint, mBody1)
  18. JPH_ADD_ATTRIBUTE(PhysicsScene::ConnectedConstraint, mBody2)
  19. }
  20. void PhysicsScene::AddBody(const BodyCreationSettings &inBody)
  21. {
  22. mBodies.push_back(inBody);
  23. }
  24. void PhysicsScene::AddConstraint(const TwoBodyConstraintSettings *inConstraint, uint32 inBody1, uint32 inBody2)
  25. {
  26. mConstraints.emplace_back(inConstraint, inBody1, inBody2);
  27. }
  28. bool PhysicsScene::FixInvalidScales()
  29. {
  30. const Vec3 unit_scale = Vec3::sReplicate(1.0f);
  31. bool success = true;
  32. for (BodyCreationSettings &b : mBodies)
  33. {
  34. // Test if there is an invalid scale in the shape hierarchy
  35. const Shape *shape = b.GetShape();
  36. if (!shape->IsValidScale(unit_scale))
  37. {
  38. // Fix it up
  39. Shape::ShapeResult result = shape->ScaleShape(unit_scale);
  40. if (result.IsValid())
  41. b.SetShape(result.Get());
  42. else
  43. success = false;
  44. }
  45. }
  46. return success;
  47. }
  48. bool PhysicsScene::CreateBodies(PhysicsSystem *inSystem) const
  49. {
  50. BodyInterface &bi = inSystem->GetBodyInterface();
  51. // Create bodies
  52. BodyIDVector body_ids;
  53. body_ids.reserve(mBodies.size());
  54. for (const BodyCreationSettings &b : mBodies)
  55. {
  56. const Body *body = bi.CreateBody(b);
  57. if (body == nullptr)
  58. break;
  59. body_ids.push_back(body->GetID());
  60. }
  61. // Batch add bodies
  62. BodyIDVector temp_body_ids = body_ids; // Body ID's get shuffled by AddBodiesPrepare
  63. BodyInterface::AddState add_state = bi.AddBodiesPrepare(temp_body_ids.data(), (int)temp_body_ids.size());
  64. bi.AddBodiesFinalize(temp_body_ids.data(), (int)temp_body_ids.size(), add_state, EActivation::Activate);
  65. // If not all bodies are created, creating constraints will be unreliable
  66. if (body_ids.size() != mBodies.size())
  67. return false;
  68. // Create constraints
  69. for (const ConnectedConstraint &cc : mConstraints)
  70. {
  71. BodyID body1_id = cc.mBody1 == cFixedToWorld? BodyID() : body_ids[cc.mBody1];
  72. BodyID body2_id = cc.mBody2 == cFixedToWorld? BodyID() : body_ids[cc.mBody2];
  73. Constraint *c = bi.CreateConstraint(cc.mSettings, body1_id, body2_id);
  74. inSystem->AddConstraint(c);
  75. }
  76. // Everything was created
  77. return true;
  78. }
  79. void PhysicsScene::SaveBinaryState(StreamOut &inStream, bool inSaveShapes, bool inSaveGroupFilter) const
  80. {
  81. BodyCreationSettings::ShapeToIDMap shape_to_id;
  82. BodyCreationSettings::MaterialToIDMap material_to_id;
  83. BodyCreationSettings::GroupFilterToIDMap group_filter_to_id;
  84. // Save bodies
  85. inStream.Write((uint32)mBodies.size());
  86. for (const BodyCreationSettings &b : mBodies)
  87. b.SaveWithChildren(inStream, inSaveShapes? &shape_to_id : nullptr, inSaveShapes? &material_to_id : nullptr, inSaveGroupFilter? &group_filter_to_id : nullptr);
  88. // Save constraints
  89. inStream.Write((uint32)mConstraints.size());
  90. for (const ConnectedConstraint &cc : mConstraints)
  91. {
  92. cc.mSettings->SaveBinaryState(inStream);
  93. inStream.Write(cc.mBody1);
  94. inStream.Write(cc.mBody2);
  95. }
  96. }
  97. PhysicsScene::PhysicsSceneResult PhysicsScene::sRestoreFromBinaryState(StreamIn &inStream)
  98. {
  99. PhysicsSceneResult result;
  100. // Create scene
  101. Ref<PhysicsScene> scene = new PhysicsScene();
  102. BodyCreationSettings::IDToShapeMap id_to_shape;
  103. BodyCreationSettings::IDToMaterialMap id_to_material;
  104. BodyCreationSettings::IDToGroupFilterMap id_to_group_filter;
  105. // Reserve some memory to avoid frequent reallocations
  106. id_to_shape.reserve(1024);
  107. id_to_material.reserve(128);
  108. id_to_group_filter.reserve(128);
  109. // Read bodies
  110. uint32 len = 0;
  111. inStream.Read(len);
  112. scene->mBodies.resize(len);
  113. for (BodyCreationSettings &b : scene->mBodies)
  114. {
  115. // Read creation settings
  116. BodyCreationSettings::BCSResult bcs_result = BodyCreationSettings::sRestoreWithChildren(inStream, id_to_shape, id_to_material, id_to_group_filter);
  117. if (bcs_result.HasError())
  118. {
  119. result.SetError(bcs_result.GetError());
  120. return result;
  121. }
  122. b = bcs_result.Get();
  123. }
  124. // Read constraints
  125. len = 0;
  126. inStream.Read(len);
  127. scene->mConstraints.resize(len);
  128. for (ConnectedConstraint &cc : scene->mConstraints)
  129. {
  130. ConstraintSettings::ConstraintResult c_result = ConstraintSettings::sRestoreFromBinaryState(inStream);
  131. if (c_result.HasError())
  132. {
  133. result.SetError(c_result.GetError());
  134. return result;
  135. }
  136. cc.mSettings = static_cast<const TwoBodyConstraintSettings *>(c_result.Get().GetPtr());
  137. inStream.Read(cc.mBody1);
  138. inStream.Read(cc.mBody2);
  139. }
  140. result.Set(scene);
  141. return result;
  142. }
  143. void PhysicsScene::FromPhysicsSystem(const PhysicsSystem *inSystem)
  144. {
  145. // This map will track where each body went in mBodies
  146. using BodyIDToIdxMap = UnorderedMap<BodyID, uint32>;
  147. BodyIDToIdxMap body_id_to_idx;
  148. // Map invalid ID
  149. body_id_to_idx[BodyID()] = cFixedToWorld;
  150. // Get all bodies
  151. BodyIDVector body_ids;
  152. inSystem->GetBodies(body_ids);
  153. // Loop over all bodies
  154. const BodyLockInterface &bli = inSystem->GetBodyLockInterface();
  155. for (const BodyID &id : body_ids)
  156. {
  157. BodyLockRead lock(bli, id);
  158. if (lock.Succeeded())
  159. {
  160. // Store location of body
  161. body_id_to_idx[id] = (uint32)mBodies.size();
  162. // Convert to body creation settings
  163. AddBody(lock.GetBody().GetBodyCreationSettings());
  164. }
  165. }
  166. // Loop over all constraints
  167. Constraints constraints = inSystem->GetConstraints();
  168. for (const Constraint *c : constraints)
  169. if (c->GetType() == EConstraintType::TwoBodyConstraint)
  170. {
  171. // Cast to two body constraint
  172. const TwoBodyConstraint *tbc = static_cast<const TwoBodyConstraint *>(c);
  173. // Find the body indices
  174. BodyIDToIdxMap::const_iterator b1 = body_id_to_idx.find(tbc->GetBody1()->GetID());
  175. BodyIDToIdxMap::const_iterator b2 = body_id_to_idx.find(tbc->GetBody2()->GetID());
  176. JPH_ASSERT(b1 != body_id_to_idx.end() && b2 != body_id_to_idx.end());
  177. // Create constraint settings and add the constraint
  178. Ref<ConstraintSettings> settings = c->GetConstraintSettings();
  179. AddConstraint(static_cast<const TwoBodyConstraintSettings *>(settings.GetPtr()), b1->second, b2->second);
  180. }
  181. }
  182. JPH_NAMESPACE_END