#ifndef __PHYSICS_H_ #define __PHYSICS_H_ #include #include #include #include #include #include #include #include #include #include void physics(); namespace JPH { class CharacterBase; class ContactManifold; class ContactSettings; class SubShapeIDPair; } // Layer that objects can be in, determines which other objects it can collide with // Typically you at least want to have 1 layer for moving bodies and 1 layer for static bodies, but you can have more // layers if you want. E.g. you could have a layer for high detail collision (which is not used by the physics simulation // but only if you do collision testing). namespace Layers { static constexpr JPH::ObjectLayer NON_MOVING = 0; static constexpr JPH::ObjectLayer MOVING = 1; static constexpr JPH::ObjectLayer SENSORS = 2; static constexpr JPH::ObjectLayer NUM_LAYERS = 3; }; // Each broadphase layer results in a separate bounding volume tree in the broad phase. You at least want to have // a layer for non-moving and moving objects to avoid having to update a tree full of static objects every frame. // You can have a 1-on-1 mapping between object layers and broadphase layers (like in this case) but if you have // many object layers you'll be creating many broad phase trees, which is not efficient. If you want to fine tune // your broadphase layers define JPH_TRACK_BROADPHASE_STATS and look at the stats reported on the TTY. namespace BroadPhaseLayers { static constexpr JPH::BroadPhaseLayer NON_MOVING(0); static constexpr JPH::BroadPhaseLayer MOVING(1); static constexpr uint NUM_LAYERS(2); }; namespace JoltPhysics { template Ogre::Vector3 convert(const T &vec) { return {vec[0], vec[1], vec[2]}; } template T convert(const Ogre::Vector3 &vec) { return { vec.x, vec.y, vec.z }; } Ogre::Quaternion convert(const JPH::QuatArg &rot); JPH::Quat convert(const Ogre::Quaternion &rot); struct ShapeData; struct CompoundShapeBuilder { JPH::StaticCompoundShapeSettings shapeSettings; void addShape(JPH::ShapeRefC shape, const Ogre::Vector3 &position, const Ogre::Quaternion &rotation); JPH::ShapeRefC build(); }; class ContactListener : public JPH::ContactListener { public: struct ContactReport { bool entered; JPH::BodyID id1, id2; JPH::ContactManifold manifold; JPH::ContactSettings settings; }; private: std::list reports; std::function dispatch; std::map > listeners; public: ContactListener(); JPH::ValidateResult OnContactValidate( const JPH::Body &inBody1, const JPH::Body &inBody2, JPH::RVec3Arg inBaseOffset, const JPH::CollideShapeResult &inCollisionResult) override; void OnContactAdded(const JPH::Body &inBody1, const JPH::Body &inBody2, const JPH::ContactManifold &inManifold, JPH::ContactSettings &ioSettings) override; void OnContactPersisted(const JPH::Body &inBody1, const JPH::Body &inBody2, const JPH::ContactManifold &inManifold, JPH::ContactSettings &ioSettings) override; void OnContactRemoved(const JPH::SubShapeIDPair &inSubShapePair) override; void setDispatch(const std::function dispatcher) { dispatch = dispatcher; } void addListener( const JPH::BodyID &id, const std::function listener) { listeners[id] = listener; } void removeListener(const JPH::BodyID &id) { listeners.erase(id); } void update(); }; } class JoltPhysicsWrapper : public Ogre::Singleton { public: JoltPhysics::ContactListener contacts; JoltPhysicsWrapper(Ogre::SceneManager *scnMgr, Ogre::SceneNode *cameraNode); ~JoltPhysicsWrapper(); void update(float dt); void addBody(const JPH::BodyID &body, JPH::EActivation activation); bool isAdded(const JPH::BodyID &body); JPH::ShapeRefC createBoxShape(const Ogre::Vector3 &extents); JPH::ShapeRefC createSphereShape(float radius); JPH::ShapeRefC createCylinderShape(float halfHeight, float radius); JPH::ShapeRefC createMeshShape(Ogre::MeshPtr mesh); JPH::ShapeRefC createMeshShape(Ogre::String meshName); JPH::ShapeRefC createConvexHullShape(Ogre::MeshPtr mesh); JPH::ShapeRefC createConvexHullShape(Ogre::String meshName); JPH::ShapeRefC createHeightfieldShape(const float *samples, Ogre::Vector3 offset, Ogre::Vector3 scale, int sampleCount); JPH::ShapeRefC createMutableCompoundShape( const std::vector &shapes, const std::vector &positions, const std::vector &rotations); JPH::ShapeRefC createStaticCompoundShape( const std::vector &shapes, const std::vector &positions, const std::vector &rotations); JPH::ShapeRefC createOffsetCenterOfMassShape(const Ogre::Vector3 &offset, JPH::ShapeRefC shape); JPH::ShapeRefC createRotatedTranslatedShape(const Ogre::Vector3 &offset, const Ogre::Quaternion rotation, JPH::ShapeRefC shape); JPH::BodyID createBody(const JPH::BodyCreationSettings &settings); JPH::BodyID createBody(const JPH::Shape *shape, float mass, const Ogre::Vector3 &position, const Ogre::Quaternion &rotation, JPH::EMotionType motion, JPH::ObjectLayer layer); JPH::BodyID createBody(const JPH::Shape *shape, float mass, Ogre::SceneNode *node, JPH::EMotionType motion, JPH::ObjectLayer layer); JPH::BodyID createSensor(const JPH::Shape *shape, const Ogre::Vector3 &position, const Ogre::Quaternion &rotation, JPH::EMotionType motion, JPH::ObjectLayer layer); JPH::BodyID createSensor(const JPH::Shape *shape, Ogre::SceneNode *node, JPH::EMotionType motion, JPH::ObjectLayer layer); JPH::CharacterBase *createCharacter(Ogre::SceneNode *node, float characterHeight, float characterRadius); void addShapeToCompound(JPH::Ref compoundShape, JPH::ShapeRefC childShape, const Ogre::Vector3 &position, const Ogre::Quaternion &rotation); void removeBody(const JPH::BodyID &id); void destroyBody(const JPH::BodyID &id); void setDebugDraw(bool enable); void broadphaseQuery(float dt, const Ogre::Vector3 &position, std::set &inWater); void applyBuoyancyImpulse(JPH::BodyID id, const Ogre::Vector3 &surfacePosition, const Ogre::Vector3 &surfaceNormal, float buoyancy, float linearDrag, float angularDrag, const Ogre::Vector3 &fluidVelocity, const Ogre::Vector3 &gravity, float dt); void applyBuoyancyImpulse(JPH::BodyID id, const Ogre::Vector3 &surfacePosition, const Ogre::Vector3 &surfaceNormal, float buoyancy, float linearDrag, float angularDrag, const Ogre::Vector3 &fluidVelocity, float dt); bool isActive(JPH::BodyID id); void activate(JPH::BodyID id); Ogre::Vector3 getPosition(JPH::BodyID id); void setPosition(JPH::BodyID id, const Ogre::Vector3 &position, bool activate = true); Ogre::Quaternion getRotation(JPH::BodyID id); void setRotation(JPH::BodyID id, const Ogre::Quaternion &rotation, bool activate = true); void getPositionAndRotation(JPH::BodyID id, Ogre::Vector3 &position, Ogre::Quaternion &rotation); void setPositionAndRotation(JPH::BodyID id, const Ogre::Vector3 &position, const Ogre::Quaternion &rotation, bool activate = true); Ogre::Vector3 getLinearVelocity(JPH::BodyID id); Ogre::Vector3 getAngularVelocity(JPH::BodyID id); float getFriction(JPH::BodyID id); void setFriction(JPH::BodyID id, float friction); void addAngularImpulse(const JPH::BodyID &id, const Ogre::Vector3 &impulse); void setDispatch(std::function dispatcher); void addContactListener( const JPH::BodyID &id, const std::function listener); void removeContactListener(const JPH::BodyID &id); bool raycastQuery(Ogre::Vector3 startPoint, Ogre::Vector3 endPoint, Ogre::Vector3 &position, JPH::BodyID &id); }; #endif