// Copyright (C) 2009-present, Panagiotis Christopoulos Charitos and contributors. // All rights reserved. // Code licensed under the BSD License. // http://www.anki3d.org/LICENSE #pragma once #include #include #include #include #include #include namespace anki { /// @addtogroup physics /// @{ /// @memberof PhysicsWorld class RayHitResult { public: PhysicsObjectBase* m_object = nullptr; Vec3 m_normal; ///< In world space. Vec3 m_hitPosition; ///< In world space. }; /// @memberof PhysicsWorld class PhysicsDebugDrawerInterface { public: /// The implementer is responsible of batching lines together. virtual void drawLines(ConstWeakArray lines, Array color) = 0; }; /// The master container for all physics related stuff. /// The newXXX methods are thread-safe between themselves and the dereference of the pointers. Every other method is not thread-safe. class PhysicsWorld : public MakeSingleton { template friend class anki::MakeSingleton; friend class PhysicsCollisionShapePtrDeleter; friend class PhysicsBodyPtrDeleter; friend class PhysicsBody; friend class PhysicsPlayerController; friend class PhysicsPlayerControllerPtrDeleter; friend class PhysicsJointPtrDeleter; public: Error init(AllocAlignedCallback allocCb, void* allocCbData); PhysicsCollisionShapePtr newSphereCollisionShape(F32 radius); PhysicsCollisionShapePtr newBoxCollisionShape(Vec3 extend); PhysicsCollisionShapePtr newCapsuleCollisionShape(F32 height, F32 radius); ///< Capsule axis is in Y. PhysicsCollisionShapePtr newConvexHullShape(ConstWeakArray positions); PhysicsCollisionShapePtr newStaticMeshShape(ConstWeakArray positions, ConstWeakArray indices); PhysicsBodyPtr newPhysicsBody(const PhysicsBodyInitInfo& init); PhysicsJointPtr newPointJoint(PhysicsBody* body1, PhysicsBody* body2, const Vec3& pivot); /// @param pivot Gives the origin and rotation of the hinge. The hinge rotats in the X axis of the transform. PhysicsJointPtr newHingeJoint(PhysicsBody* body1, PhysicsBody* body2, const Transform& pivot); PhysicsPlayerControllerPtr newPlayerController(const PhysicsPlayerControllerInitInfo& init); void update(Second dt); /// Returns the closest hit. Bool castRayClosestHit(const Vec3& rayStart, const Vec3& rayEnd, PhysicsLayerBit layers, RayHitResult& result); /// Executes a callback for all hits found. template Bool castRayAllHits(const Vec3& rayStart, const Vec3& rayEnd, PhysicsLayerBit layers, TFunc func) { PhysicsDynamicArray results; const Bool success = castRayAllHits(rayStart, rayEnd, layers, results); if(success) { for(RayHitResult& res : results) { func(res); } } return success; } void debugDraw(PhysicsDebugDrawerInterface& interface); private: class MyBodyActivationListener; class MyContactListener; class MyDebugRenderer; template class ObjArray { public: PhysicsBlockArray> m_array; Mutex m_mtx; }; class Contact { public: PhysicsBody* m_trigger; PhysicsObjectBase* m_receiver; }; ClassWrapper m_jphPhysicsSystem; ClassWrapper m_jobSystem; ClassWrapper m_tempAllocator; ObjArray m_collisionShapes; ObjArray m_bodies; ObjArray m_joints; ObjArray m_characters; DynamicArray m_insertedContacts; DynamicArray m_deletedContacts; Mutex m_insertedContactsMtx; Mutex m_deletedContactsMtx; Bool m_optimizeBroadphase = true; static MyBodyActivationListener m_bodyActivationListener; static MyContactListener m_contactListener; PhysicsWorld(); ~PhysicsWorld(); template PhysicsCollisionShapePtr newCollisionShape(TArgs&&... args); template PhysicsJointPtr newJoint(PhysicsBody* body1, PhysicsBody* body2, TArgs&&... args); PhysicsCollisionShapePtr newScaleCollisionObject(const Vec3& scale, PhysicsCollisionShape* baseShape); RayHitResult jphToAnKi(const JPH::RRayCast& ray, const JPH::RayCastResult& hit); Bool castRayAllHitsInternal(const Vec3& rayStart, const Vec3& rayEnd, PhysicsLayerBit layers, PhysicsDynamicArray& results); }; /// @} } // end namespace anki