Leviathan  0.8.0.0
Leviathan game engine
Leviathan::PhysicalWorld Class Reference

#include <PhysicalWorld.h>

Public Member Functions

DLLEXPORT PhysicalWorld (GameWorld *owner, PhysicsMaterialManager *physicscallbacks)
 
DLLEXPORT ~PhysicalWorld ()
 
DLLEXPORT void SimulateWorld (float secondspassed, int maxsubsteps=4)
 Advances the simulation the specified amount of time. More...
 
DLLEXPORT PhysicsShape::pointer CreateCompound ()
 
DLLEXPORT PhysicsShape::pointer CreateSphere (float radius)
 
DLLEXPORT PhysicsShape::pointer CreateBox (float xdimension, float ydimension, float zdimension)
 The dimensions are halfwidths of the box along each axis. More...
 
DLLEXPORT PhysicsBody::pointer CreateBodyFromCollision (const PhysicsShape::pointer &shape, float mass, PhysicsPositionProvider *positionsynchronization, int physicsmaterialid=-1)
 Constraints body to a 2d plane of movement specified by its normal. More...
 
DLLEXPORT bool ChangeBodyShape (const PhysicsBody::pointer &body, const PhysicsShape::pointer &shape)
 Applies a changed shape to a body. More...
 
DLLEXPORT bool DestroyBody (PhysicsBody *body)
 Destroys a physics body. More...
 
const PhysMaterialDataPairGetMaterialPair (int id1, int id2) const
 Finds the information for contact between objects with two materials. More...
 
DLLEXPORT GameWorldGetGameWorld ()
 
PhysicsShapeCreateSphereWrapper (float radius)
 
PhysicsShapeCreateCompoundWrapper ()
 

Protected Member Functions

void OnManifoldWithContact (btPersistentManifold *contactManifold, const btManifoldPoint &contactPoint, const btCollisionObject *objA, const btCollisionObject *objB)
 Calls appropriate material callbacks. This is called once per contact manifold that has penetrating points. More...
 

Static Protected Member Functions

static void OnPhysicsSubStep (btDynamicsWorld *world, btScalar timeStep)
 

Protected Attributes

float PassedTimeTotal = 0
 Total amount of seconds required to be simulated. More...
 
GameWorldOwningWorld
 
PhysicsMaterialManagerPhysicsMaterials
 
bool PhysicsUpdateInProgress = false
 This is a small sanity check for preventing destroying physics bodies during a tick. More...
 
std::unique_ptr< btDefaultCollisionConfiguration > CollisionConfiguration
 
std::unique_ptr< btCollisionDispatcher > Dispatcher
 
std::unique_ptr< btBroadphaseInterface > OverlappingPairCache
 
std::unique_ptr< btSequentialImpulseConstraintSolver > Solver
 
std::unique_ptr< btDiscreteDynamicsWorld > DynamicsWorld
 
std::unique_ptr< LeviathanPhysicsOverlapFilterOverlapFilter
 
std::vector< PhysicsBody::pointer > PhysicsBodies
 We need to keep the physic bodies alive (guaranteed) until they are destroyed. More...
 

Detailed Description

Definition at line 54 of file PhysicalWorld.h.

Constructor & Destructor Documentation

◆ PhysicalWorld()

DLLEXPORT PhysicalWorld::PhysicalWorld ( GameWorld owner,
PhysicsMaterialManager physicscallbacks 
)

Definition at line 74 of file PhysicalWorld.cpp.

75  :
76  OwningWorld(owner),
77  PhysicsMaterials(physicscallbacks),
78  OverlapFilter(std::make_unique<LeviathanPhysicsOverlapFilter>(this))
79 {
80  // Setup physics world //
81  CollisionConfiguration = std::make_unique<btDefaultCollisionConfiguration>();
82 
83  // Non-parallel dispatcher
84  Dispatcher = std::make_unique<btCollisionDispatcher>(CollisionConfiguration.get());
85 
86  // According to docs this is a good general broadphase
87  OverlappingPairCache = std::make_unique<btDbvtBroadphase>();
88 
89  // Non-parallel solver
90  Solver = std::make_unique<btSequentialImpulseConstraintSolver>();
91 
92  DynamicsWorld = std::make_unique<btDiscreteDynamicsWorld>(Dispatcher.get(),
94 
95  // Register required callbacks
96  DynamicsWorld->setInternalTickCallback(&PhysicalWorld::OnPhysicsSubStep);
97  // Not sure which one of these is better to use for AABB overlap
98  DynamicsWorld->getPairCache()->setOverlapFilterCallback(OverlapFilter.get());
99  // Dispatcher->setNearCallback(&PhysicalWorld::PhysicsNearCallback);
100 
101  // Set gravity. Having this set on worlds that want multiple different gravities might be
102  // an issue
103  DynamicsWorld->setGravity(btVector3(0, PHYSICS_BASE_GRAVITY, 0));
104 
105  // Set us as the user data (this is done last so that nothing overwrites this) //
106  DynamicsWorld->setWorldUserInfo(this);
107 
108  LEVIATHAN_ASSERT(DynamicsWorld->getWorldUserInfo() != nullptr, "userinfo set failed");
109 }
constexpr auto PHYSICS_BASE_GRAVITY
Definition: PhysicalWorld.h:38
std::unique_ptr< btDefaultCollisionConfiguration > CollisionConfiguration
std::unique_ptr< btBroadphaseInterface > OverlappingPairCache
std::unique_ptr< btCollisionDispatcher > Dispatcher
static void OnPhysicsSubStep(btDynamicsWorld *world, btScalar timeStep)
PhysicsMaterialManager * PhysicsMaterials
#define LEVIATHAN_ASSERT(x, msg)
Definition: Define.h:98
std::unique_ptr< LeviathanPhysicsOverlapFilter > OverlapFilter
std::unique_ptr< btDiscreteDynamicsWorld > DynamicsWorld
std::unique_ptr< btSequentialImpulseConstraintSolver > Solver

◆ ~PhysicalWorld()

DLLEXPORT PhysicalWorld::~PhysicalWorld ( )

Definition at line 111 of file PhysicalWorld.cpp.

112 {
113  // It is an error to not release a body
114  if(!PhysicsBodies.empty()) {
115  LOG_ERROR("PhysicalWorld: not all bodies have been destroyed, alive count: " +
116  std::to_string(PhysicsBodies.size()));
117  }
118 
119  // All bodies need to be destroyed here
120  while(!PhysicsBodies.empty()) {
121  DestroyBody(PhysicsBodies.back().get());
122  }
123 
124  // We can rely on the default delete order and everything is fine
125 }
std::vector< PhysicsBody::pointer > PhysicsBodies
We need to keep the physic bodies alive (guaranteed) until they are destroyed.
#define LOG_ERROR(x)
Definition: Define.h:90
DLLEXPORT bool DestroyBody(PhysicsBody *body)
Destroys a physics body.

Member Function Documentation

◆ ChangeBodyShape()

DLLEXPORT bool PhysicalWorld::ChangeBodyShape ( const PhysicsBody::pointer &  body,
const PhysicsShape::pointer &  shape 
)

Applies a changed shape to a body.

Todo:
Find out if it is required to remove and add the body back to the world (and if that can be done in a physics callback)

Definition at line 359 of file PhysicalWorld.cpp.

361 {
362  if(!body || !shape || !body->GetBody())
363  return false;
364 
365  // Debug safety code
366  bool found = false;
367  for(auto iter = PhysicsBodies.begin(); iter != PhysicsBodies.end(); ++iter) {
368  if(iter->get() == body.get()) {
369 
370  found = true;
371  break;
372  }
373  }
374 
375  if(!found) {
376  LOG_ERROR("PhysicalWorld: ChangeBodyShape: passed body not part of this world");
377  DEBUG_BREAK;
378  return false;
379  }
380 
381  // This might be fine as it will be added back in
382  if(body->GetBody()->getNumConstraintRefs() > 0) {
383  // "undestroyed constraints on entity";
384  }
385 
387  // This might be okay...
388  // DEBUG_BREAK;
389  }
390 
391  DynamicsWorld->removeRigidBody(body->GetBody());
392 
393  body->ApplyShapeChange(shape);
394 
395  DynamicsWorld->addRigidBody(body->GetBody());
396 
397  return true;
398 }
std::vector< PhysicsBody::pointer > PhysicsBodies
We need to keep the physic bodies alive (guaranteed) until they are destroyed.
bool PhysicsUpdateInProgress
This is a small sanity check for preventing destroying physics bodies during a tick.
#define LOG_ERROR(x)
Definition: Define.h:90
std::unique_ptr< btDiscreteDynamicsWorld > DynamicsWorld

◆ CreateBodyFromCollision()

DLLEXPORT PhysicsBody::pointer PhysicalWorld::CreateBodyFromCollision ( const PhysicsShape::pointer &  shape,
float  mass,
PhysicsPositionProvider positionsynchronization,
int  physicsmaterialid = -1 
)

Constraints body to a 2d plane of movement specified by its normal.

Note
DestroyBody must be called to remove the created body from this world
Parameters
massIf 0 then this is a static body

Definition at line 284 of file PhysicalWorld.cpp.

287 {
288  if(!shape)
289  return nullptr;
290 
291  btTransform transform;
292  transform.setIdentity();
293 
294  if(positionsynchronization) {
295  const Float3* position;
296  const Float4* orientation;
297  positionsynchronization->GetPositionDataForPhysics(position, orientation);
298 
299  transform.setRotation(*orientation);
300  transform.setOrigin(*position);
301  }
302 
303  // rigidbody is dynamic if and only if mass is non zero, otherwise static
304  const bool isDynamic = mass > 0;
305 
306  btVector3 localInertia(0, 0, 0);
307  if(isDynamic)
308  shape->GetShape()->calculateLocalInertia(mass, localInertia);
309 
310  // To not have to lookup all positions all the time we use the position synchronization
311  // object
312  std::unique_ptr<PhysicsDataBridge> positionBridge;
313 
314  if(positionsynchronization)
315  positionBridge = std::make_unique<PhysicsDataBridge>(positionsynchronization);
316 
317  btRigidBody::btRigidBodyConstructionInfo info(
318  mass, positionBridge.get(), shape->GetShape(), localInertia);
319 
320  auto body = PhysicsBody::MakeShared<PhysicsBody>(std::make_unique<btRigidBody>(info), mass,
321  shape, std::move(positionBridge), physicsmaterialid);
322 
323  if(!body->GetBody()) {
324  LOG_ERROR("PhysicalWorld: CreateBodyFromCollision: failed to create bullet body");
325  return nullptr;
326  }
327 
328  // Apply material
329  if(physicsmaterialid != -1 && PhysicsMaterials) {
330  auto material = PhysicsMaterials->GetMaterial(physicsmaterialid);
331 
332  if(!material) {
333  LOG_ERROR(
334  "PhysicalWorld: CreateBodyFromCollision: can't find physics material id: " +
335  std::to_string(physicsmaterialid));
336  body->SetPhysicalMaterialID(-1);
337  } else {
338 
339  body->ApplyMaterial(*material);
340  }
341  }
342 
343  // Dirty hack to make bodies not sleep. This makes apply force work (another approach would
344  // be to wake any body that has force applied to it)
345  body->GetBody()->setActivationState(DISABLE_DEACTIVATION);
346 
348  // This might be okay...
349  // DEBUG_BREAK;
350  }
351 
352  DynamicsWorld->addRigidBody(body->GetBody());
353 
354  // Make sure it is alive as long as it is in the world
355  PhysicsBodies.push_back(body);
356  return body;
357 }
std::vector< PhysicsBody::pointer > PhysicsBodies
We need to keep the physic bodies alive (guaranteed) until they are destroyed.
bool PhysicsUpdateInProgress
This is a small sanity check for preventing destroying physics bodies during a tick.
#define LOG_ERROR(x)
Definition: Define.h:90
PhysicsMaterialManager * PhysicsMaterials
DLLEXPORT PhysicalMaterial * GetMaterial(const std::string &name)
Accesses material based on name.
std::unique_ptr< btDiscreteDynamicsWorld > DynamicsWorld
virtual void GetPositionDataForPhysics(const Float3 *&position, const Float4 *&orientation) const =0

◆ CreateBox()

DLLEXPORT PhysicsShape::pointer PhysicalWorld::CreateBox ( float  xdimension,
float  ydimension,
float  zdimension 
)

The dimensions are halfwidths of the box along each axis.

Definition at line 277 of file PhysicalWorld.cpp.

279 {
280  return PhysicsShape::MakeShared<PhysicsShape>(
281  std::make_unique<btBoxShape>(btVector3(xdimension, ydimension, zdimension)));
282 }

◆ CreateCompound()

DLLEXPORT PhysicsShape::pointer PhysicalWorld::CreateCompound ( )

Definition at line 259 of file PhysicalWorld.cpp.

260 {
261  return PhysicsShape::MakeShared<PhysicsShape>(std::make_unique<btCompoundShape>());
262 }

◆ CreateCompoundWrapper()

PhysicsShape* Leviathan::PhysicalWorld::CreateCompoundWrapper ( )
inline

Definition at line 123 of file PhysicalWorld.h.

124  {
125  auto obj = CreateCompound();
126 
127  if(obj)
128  obj->AddRef();
129 
130  return obj.get();
131  }
DLLEXPORT PhysicsShape::pointer CreateCompound()

◆ CreateSphere()

DLLEXPORT PhysicsShape::pointer PhysicalWorld::CreateSphere ( float  radius)

Definition at line 264 of file PhysicalWorld.cpp.

265 {
266 #ifdef CHECK_FOR_NANS
267  if(std::isnan(radius)) {
268 
269  DEBUG_BREAK;
270  throw std::runtime_error("CreateSphere has NaNs in it!");
271  }
272 #endif // CHECK_FOR_NANS
273 
274  return PhysicsShape::MakeShared<PhysicsShape>(std::make_unique<btSphereShape>(radius));
275 }
#define isnan(x)
Definition: jsoncpp.cpp:4243

◆ CreateSphereWrapper()

PhysicsShape* Leviathan::PhysicalWorld::CreateSphereWrapper ( float  radius)
inline

Definition at line 113 of file PhysicalWorld.h.

114  {
115  auto obj = CreateSphere(radius);
116 
117  if(obj)
118  obj->AddRef();
119 
120  return obj.get();
121  }
DLLEXPORT PhysicsShape::pointer CreateSphere(float radius)

◆ DestroyBody()

DLLEXPORT bool PhysicalWorld::DestroyBody ( PhysicsBody body)

Destroys a physics body.

May not be called while a physics update is in progress

Definition at line 400 of file PhysicalWorld.cpp.

401 {
403  DEBUG_BREAK;
404  LOG_FATAL("PhysicalWorld: DestroyBody: called while physics update is in progress");
405  return false;
406  }
407 
408  // Remove from alive bodies. This also checks that the body is in this world
409  for(auto iter = PhysicsBodies.begin(); iter != PhysicsBodies.end(); ++iter) {
410 
411  if(iter->get() == body) {
412 
413  if(body->GetBody()->getNumConstraintRefs() > 0) {
414 
415  LOG_ERROR("PhysicalWorld: DestroyBody: body has undestroyed constraints, "
416  "can't safely destroy");
417  return false;
418  }
419 
420  DynamicsWorld->removeRigidBody(body->GetBody());
421 
422  body->DetachResources();
423  PhysicsBodies.erase(iter);
424  return true;
425  }
426  }
427 
428  LOG_ERROR("PhysicalWorld: DestroyBody: called with body that wasn't in this world");
429  return false;
430 }
DLLEXPORT btRigidBody * GetBody()
Definition: PhysicsBody.h:163
std::vector< PhysicsBody::pointer > PhysicsBodies
We need to keep the physic bodies alive (guaranteed) until they are destroyed.
bool PhysicsUpdateInProgress
This is a small sanity check for preventing destroying physics bodies during a tick.
#define LOG_ERROR(x)
Definition: Define.h:90
#define LOG_FATAL(x)
Definition: Define.h:92
DLLEXPORT void DetachResources()
This releases all resources held by this. This is called by the PhysicalWorld when this is destroyed ...
Definition: PhysicsBody.cpp:35
std::unique_ptr< btDiscreteDynamicsWorld > DynamicsWorld

◆ GetGameWorld()

DLLEXPORT GameWorld* Leviathan::PhysicalWorld::GetGameWorld ( )
inline

Definition at line 105 of file PhysicalWorld.h.

106  {
107  return OwningWorld;
108  }

◆ GetMaterialPair()

const PhysMaterialDataPair * PhysicalWorld::GetMaterialPair ( int  id1,
int  id2 
) const

Finds the information for contact between objects with two materials.

Definition at line 211 of file PhysicalWorld.cpp.

212 {
213  const auto material1 = PhysicsMaterials->GetMaterial(id1);
214 
215  const PhysMaterialDataPair* pair = nullptr;
216 
217  // The logs in this method will absolutely trash performance if they get hit as there will
218  // be tons of calls with the same parameters
219 
220  if(material1) {
221  pair = material1->GetPairWith(id2);
222  } else {
223  LOG_ERROR("PhysicsBody has invalid material ID: " + std::to_string(id1));
224  }
225 
226  if(!pair) {
227 
228  const auto material2 = PhysicsMaterials->GetMaterial(id2);
229 
230  if(material2) {
231  pair = material2->GetPairWith(id1);
232  } else {
233  LOG_ERROR("PhysicsBody has invalid material ID: " + std::to_string(id2));
234  }
235  }
236 
237  return pair;
238 }
#define LOG_ERROR(x)
Definition: Define.h:90
Defines properties between two materials.
PhysicsMaterialManager * PhysicsMaterials
DLLEXPORT PhysicalMaterial * GetMaterial(const std::string &name)
Accesses material based on name.

◆ OnManifoldWithContact()

void PhysicalWorld::OnManifoldWithContact ( btPersistentManifold *  contactManifold,
const btManifoldPoint &  contactPoint,
const btCollisionObject *  objA,
const btCollisionObject *  objB 
)
protected

Calls appropriate material callbacks. This is called once per contact manifold that has penetrating points.

Definition at line 180 of file PhysicalWorld.cpp.

183 {
184  // Actual points touching
185  // const btVector3& contactPointA = contactPoint.getPositionWorldOnA();
186  // const btVector3& contactPointB = contactPoint.getPositionWorldOnB();
187  // const btVector3& normalOnB = contactPoint.m_normalWorldOnB;
188 
189  // Find matching materials
190  PhysicsBody* body1 = static_cast<PhysicsBody*>(objA->getUserPointer());
191  PhysicsBody* body2 = static_cast<PhysicsBody*>(objB->getUserPointer());
192 
193  if(body1 && body2) {
194 
195  const auto materialID1 = body1->GetPhysicalMaterialID();
196  const auto materialID2 = body2->GetPhysicalMaterialID();
197 
198  // Find contact callbacks
199  if(materialID1 >= 0 && materialID2 >= 0) {
200 
201  auto pair = GetMaterialPair(materialID1, materialID2);
202 
203  if(pair && pair->ContactCallback) {
204 
205  pair->ContactCallback(*this, *body1, *body2);
206  }
207  }
208  }
209 }
This is an instance of a collision body.
Definition: PhysicsBody.h:74
const PhysMaterialDataPair * GetMaterialPair(int id1, int id2) const
Finds the information for contact between objects with two materials.
auto GetPhysicalMaterialID() const
Definition: PhysicsBody.h:173

◆ OnPhysicsSubStep()

void PhysicalWorld::OnPhysicsSubStep ( btDynamicsWorld *  world,
btScalar  timeStep 
)
staticprotected

Definition at line 136 of file PhysicalWorld.cpp.

137 {
138  auto leviathanWorld = static_cast<PhysicalWorld*>(world->getWorldUserInfo());
139 
140  // Skip if no physics materials
141  if(!leviathanWorld->PhysicsMaterials)
142  return;
143 
144  btDispatcher* dispatcher = world->getDispatcher();
145 
146  // Check all active contacts as to whether something should be done
147  const int numManifolds = dispatcher->getNumManifolds();
148  for(int i = 0; i < numManifolds; i++) {
149 
150  btPersistentManifold* contactManifold = dispatcher->getManifoldByIndexInternal(i);
151 
152  const btCollisionObject* objA = contactManifold->getBody0();
153  const btCollisionObject* objB = contactManifold->getBody1();
154 
155  // TODO: remove this check once it is confirmed that both objects must always exist
156  if(objA && objB) {
157 
158  const int numContacts = contactManifold->getNumContacts();
159 
160  bool handled = false;
161 
162  for(int j = 0; j < numContacts; j++) {
163 
164  const btManifoldPoint& contactPoint = contactManifold->getContactPoint(j);
165 
166  if(contactPoint.getDistance() < 0.f) {
167 
168  if(handled)
169  continue;
170 
171  handled = true;
172  leviathanWorld->OnManifoldWithContact(
173  contactManifold, contactPoint, objA, objB);
174  }
175  }
176  }
177  }
178 }

◆ SimulateWorld()

DLLEXPORT void PhysicalWorld::SimulateWorld ( float  secondspassed,
int  maxsubsteps = 4 
)

Advances the simulation the specified amount of time.

Definition at line 127 of file PhysicalWorld.cpp.

128 {
130 
131  DynamicsWorld->stepSimulation(secondspassed, maxsubsteps);
132 
133  PhysicsUpdateInProgress = false;
134 }
bool PhysicsUpdateInProgress
This is a small sanity check for preventing destroying physics bodies during a tick.
std::unique_ptr< btDiscreteDynamicsWorld > DynamicsWorld

Member Data Documentation

◆ CollisionConfiguration

std::unique_ptr<btDefaultCollisionConfiguration> Leviathan::PhysicalWorld::CollisionConfiguration
protected

Definition at line 153 of file PhysicalWorld.h.

◆ Dispatcher

std::unique_ptr<btCollisionDispatcher> Leviathan::PhysicalWorld::Dispatcher
protected

Definition at line 155 of file PhysicalWorld.h.

◆ DynamicsWorld

std::unique_ptr<btDiscreteDynamicsWorld> Leviathan::PhysicalWorld::DynamicsWorld
protected

Definition at line 161 of file PhysicalWorld.h.

◆ OverlapFilter

std::unique_ptr<LeviathanPhysicsOverlapFilter> Leviathan::PhysicalWorld::OverlapFilter
protected

Definition at line 163 of file PhysicalWorld.h.

◆ OverlappingPairCache

std::unique_ptr<btBroadphaseInterface> Leviathan::PhysicalWorld::OverlappingPairCache
protected

Definition at line 157 of file PhysicalWorld.h.

◆ OwningWorld

GameWorld* Leviathan::PhysicalWorld::OwningWorld
protected

Definition at line 146 of file PhysicalWorld.h.

◆ PassedTimeTotal

float Leviathan::PhysicalWorld::PassedTimeTotal = 0
protected

Total amount of seconds required to be simulated.

Definition at line 144 of file PhysicalWorld.h.

◆ PhysicsBodies

std::vector<PhysicsBody::pointer> Leviathan::PhysicalWorld::PhysicsBodies
protected

We need to keep the physic bodies alive (guaranteed) until they are destroyed.

Definition at line 166 of file PhysicalWorld.h.

◆ PhysicsMaterials

PhysicsMaterialManager* Leviathan::PhysicalWorld::PhysicsMaterials
protected

Definition at line 147 of file PhysicalWorld.h.

◆ PhysicsUpdateInProgress

bool Leviathan::PhysicalWorld::PhysicsUpdateInProgress = false
protected

This is a small sanity check for preventing destroying physics bodies during a tick.

Definition at line 150 of file PhysicalWorld.h.

◆ Solver

std::unique_ptr<btSequentialImpulseConstraintSolver> Leviathan::PhysicalWorld::Solver
protected

Definition at line 159 of file PhysicalWorld.h.


The documentation for this class was generated from the following files: