1 #ifndef OPENMW_MWPHYSICS_PHYSICSSYSTEM_H 2 #define OPENMW_MWPHYSICS_PHYSICSSYSTEM_H 3 4 #include <array> 5 #include <memory> 6 #include <map> 7 #include <set> 8 #include <algorithm> 9 10 #include <osg/Quat> 11 #include <osg/BoundingBox> 12 #include <osg/ref_ptr> 13 #include <osg/Timer> 14 15 #include "../mwworld/ptr.hpp" 16 17 #include "collisiontype.hpp" 18 #include "raycasting.hpp" 19 20 namespace osg 21 { 22 class Group; 23 class Object; 24 class Stats; 25 } 26 27 namespace MWRender 28 { 29 class DebugDrawer; 30 } 31 32 namespace Resource 33 { 34 class BulletShapeManager; 35 class ResourceSystem; 36 } 37 38 namespace SceneUtil 39 { 40 class UnrefQueue; 41 } 42 43 class btCollisionWorld; 44 class btBroadphaseInterface; 45 class btDefaultCollisionConfiguration; 46 class btCollisionDispatcher; 47 class btCollisionObject; 48 class btCollisionShape; 49 class btVector3; 50 51 namespace MWPhysics 52 { 53 class HeightField; 54 class Object; 55 class Actor; 56 class PhysicsTaskScheduler; 57 class Projectile; 58 59 using ActorMap = std::map<MWWorld::ConstPtr, std::shared_ptr<Actor>>; 60 61 struct ContactPoint 62 { 63 MWWorld::Ptr mObject; 64 osg::Vec3f mPoint; 65 osg::Vec3f mNormal; 66 }; 67 68 struct LOSRequest 69 { 70 LOSRequest(const std::weak_ptr<Actor>& a1, const std::weak_ptr<Actor>& a2); 71 std::array<std::weak_ptr<Actor>, 2> mActors; 72 std::array<const Actor*, 2> mRawActors; 73 bool mResult; 74 bool mStale; 75 int mAge; 76 }; 77 bool operator==(const LOSRequest& lhs, const LOSRequest& rhs) noexcept; 78 79 struct ActorFrameData 80 { 81 ActorFrameData(const std::shared_ptr<Actor>& actor, const MWWorld::Ptr standingOn, bool moveToWaterSurface, float slowFall, float waterlevel); 82 void updatePosition(btCollisionWorld* world); 83 std::weak_ptr<Actor> mActor; 84 Actor* mActorRaw; 85 MWWorld::Ptr mStandingOn; 86 bool mFlying; 87 bool mSwimming; 88 bool mWasOnGround; 89 bool mWantJump; 90 bool mDidJump; 91 bool mFloatToSurface; 92 bool mNeedLand; 93 bool mWaterCollision; 94 bool mSkipCollisionDetection; 95 float mWaterlevel; 96 float mSlowFall; 97 float mOldHeight; 98 float mFallHeight; 99 osg::Vec3f mMovement; 100 osg::Vec3f mPosition; 101 ESM::Position mRefpos; 102 }; 103 104 struct WorldFrameData 105 { 106 WorldFrameData(); 107 bool mIsInStorm; 108 osg::Vec3f mStormDirection; 109 }; 110 111 class PhysicsSystem : public RayCastingInterface 112 { 113 public: 114 PhysicsSystem (Resource::ResourceSystem* resourceSystem, osg::ref_ptr<osg::Group> parentNode); 115 virtual ~PhysicsSystem (); 116 117 void setUnrefQueue(SceneUtil::UnrefQueue* unrefQueue); 118 119 Resource::BulletShapeManager* getShapeManager(); 120 121 void enableWater(float height); 122 void setWaterHeight(float height); 123 void disableWater(); 124 125 void addObject (const MWWorld::Ptr& ptr, const std::string& mesh, int collisionType = CollisionType_World); 126 void addActor (const MWWorld::Ptr& ptr, const std::string& mesh); 127 128 int addProjectile(const MWWorld::Ptr& caster, const osg::Vec3f& position, const std::string& mesh, bool computeRadius); 129 void setCaster(int projectileId, const MWWorld::Ptr& caster); 130 void updateProjectile(const int projectileId, const osg::Vec3f &position) const; 131 void removeProjectile(const int projectileId); 132 133 void updatePtr (const MWWorld::Ptr& old, const MWWorld::Ptr& updated); 134 135 Actor* getActor(const MWWorld::Ptr& ptr); 136 const Actor* getActor(const MWWorld::ConstPtr& ptr) const; 137 138 const Object* getObject(const MWWorld::ConstPtr& ptr) const; 139 140 Projectile* getProjectile(int projectileId) const; 141 142 // Object or Actor 143 void remove (const MWWorld::Ptr& ptr); 144 145 void updateScale (const MWWorld::Ptr& ptr); 146 void updateRotation (const MWWorld::Ptr& ptr); 147 void updatePosition (const MWWorld::Ptr& ptr); 148 149 void addHeightField (const float* heights, int x, int y, float triSize, float sqrtVerts, float minH, float maxH, const osg::Object* holdObject); 150 151 void removeHeightField (int x, int y); 152 153 const HeightField* getHeightField(int x, int y) const; 154 155 bool toggleCollisionMode(); 156 157 void stepSimulation(); 158 void debugDraw(); 159 160 std::vector<MWWorld::Ptr> getCollisions(const MWWorld::ConstPtr &ptr, int collisionGroup, int collisionMask) const; ///< get handles this object collides with 161 std::vector<ContactPoint> getCollisionsPoints(const MWWorld::ConstPtr &ptr, int collisionGroup, int collisionMask) const; 162 osg::Vec3f traceDown(const MWWorld::Ptr &ptr, const osg::Vec3f& position, float maxHeight); 163 164 std::pair<MWWorld::Ptr, osg::Vec3f> getHitContact(const MWWorld::ConstPtr& actor, 165 const osg::Vec3f &origin, 166 const osg::Quat &orientation, 167 float queryDistance, std::vector<MWWorld::Ptr>& targets); 168 169 170 /// Get distance from \a point to the collision shape of \a target. Uses a raycast to find where the 171 /// target vector hits the collision shape and then calculates distance from the intersection point. 172 /// This can be used to find out how much nearer we need to move to the target for a "getHitContact" to be successful. 173 /// \note Only Actor targets are supported at the moment. 174 float getHitDistance(const osg::Vec3f& point, const MWWorld::ConstPtr& target) const override; 175 176 /// @param me Optional, a Ptr to ignore in the list of results. targets are actors to filter for, ignoring all other actors. 177 RayCastingResult castRay(const osg::Vec3f &from, const osg::Vec3f &to, const MWWorld::ConstPtr& ignore = MWWorld::ConstPtr(), 178 std::vector<MWWorld::Ptr> targets = std::vector<MWWorld::Ptr>(), 179 int mask = CollisionType_World|CollisionType_HeightMap|CollisionType_Actor|CollisionType_Door, int group=0xff) const override; 180 181 RayCastingResult castSphere(const osg::Vec3f& from, const osg::Vec3f& to, float radius) const override; 182 183 /// Return true if actor1 can see actor2. 184 bool getLineOfSight(const MWWorld::ConstPtr& actor1, const MWWorld::ConstPtr& actor2) const override; 185 186 bool isOnGround (const MWWorld::Ptr& actor); 187 188 bool canMoveToWaterSurface (const MWWorld::ConstPtr &actor, const float waterlevel); 189 190 /// Get physical half extents (scaled) of the given actor. 191 osg::Vec3f getHalfExtents(const MWWorld::ConstPtr& actor) const; 192 193 /// Get physical half extents (not scaled) of the given actor. 194 osg::Vec3f getOriginalHalfExtents(const MWWorld::ConstPtr& actor) const; 195 196 /// @see MWPhysics::Actor::getRenderingHalfExtents 197 osg::Vec3f getRenderingHalfExtents(const MWWorld::ConstPtr& actor) const; 198 199 /// Get the position of the collision shape for the actor. Use together with getHalfExtents() to get the collision bounds in world space. 200 /// @note The collision shape's origin is in its center, so the position returned can be described as center of the actor collision box in world space. 201 osg::Vec3f getCollisionObjectPosition(const MWWorld::ConstPtr& actor) const; 202 203 /// Get bounding box in world space of the given object. 204 osg::BoundingBox getBoundingBox(const MWWorld::ConstPtr &object) const; 205 206 /// Queues velocity movement for a Ptr. If a Ptr is already queued, its velocity will 207 /// be overwritten. Valid until the next call to applyQueuedMovement. 208 void queueObjectMovement(const MWWorld::Ptr &ptr, const osg::Vec3f &velocity); 209 210 /// Apply all queued movements, then clear the list. 211 const std::vector<MWWorld::Ptr>& applyQueuedMovement(float dt, bool skipSimulation, osg::Timer_t frameStart, unsigned int frameNumber, osg::Stats& stats); 212 213 /// Clear the queued movements list without applying. 214 void clearQueuedMovement(); 215 216 /// Return true if \a actor has been standing on \a object in this frame 217 /// This will trigger whenever the object is directly below the actor. 218 /// It doesn't matter if the actor is stationary or moving. 219 bool isActorStandingOn(const MWWorld::Ptr& actor, const MWWorld::ConstPtr& object) const; 220 221 /// Get the handle of all actors standing on \a object in this frame. 222 void getActorsStandingOn(const MWWorld::ConstPtr& object, std::vector<MWWorld::Ptr>& out) const; 223 224 /// Return true if \a actor has collided with \a object in this frame. 225 /// This will detect running into objects, but will not detect climbing stairs, stepping up a small object, etc. 226 bool isActorCollidingWith(const MWWorld::Ptr& actor, const MWWorld::ConstPtr& object) const; 227 228 /// Get the handle of all actors colliding with \a object in this frame. 229 void getActorsCollidingWith(const MWWorld::ConstPtr& object, std::vector<MWWorld::Ptr>& out) const; 230 231 bool toggleDebugRendering(); 232 233 /// Mark the given object as a 'non-solid' object. A non-solid object means that 234 /// \a isOnSolidGround will return false for actors standing on that object. 235 void markAsNonSolid (const MWWorld::ConstPtr& ptr); 236 237 bool isOnSolidGround (const MWWorld::Ptr& actor) const; 238 239 void updateAnimatedCollisionShape(const MWWorld::Ptr& object); 240 241 template <class Function> forEachAnimatedObject(Function && function) const242 void forEachAnimatedObject(Function&& function) const 243 { 244 std::for_each(mAnimatedObjects.begin(), mAnimatedObjects.end(), function); 245 } 246 247 bool isAreaOccupiedByOtherActor(const osg::Vec3f& position, const float radius, const MWWorld::ConstPtr& ignore) const; 248 249 void reportStats(unsigned int frameNumber, osg::Stats& stats) const; 250 void reportCollision(const btVector3& position, const btVector3& normal); 251 252 private: 253 254 void updateWater(); 255 256 std::vector<ActorFrameData> prepareFrameData(bool willSimulate); 257 258 osg::ref_ptr<SceneUtil::UnrefQueue> mUnrefQueue; 259 260 std::unique_ptr<btBroadphaseInterface> mBroadphase; 261 std::unique_ptr<btDefaultCollisionConfiguration> mCollisionConfiguration; 262 std::unique_ptr<btCollisionDispatcher> mDispatcher; 263 std::unique_ptr<btCollisionWorld> mCollisionWorld; 264 std::unique_ptr<PhysicsTaskScheduler> mTaskScheduler; 265 266 std::unique_ptr<Resource::BulletShapeManager> mShapeManager; 267 Resource::ResourceSystem* mResourceSystem; 268 269 using ObjectMap = std::map<MWWorld::ConstPtr, std::shared_ptr<Object>>; 270 ObjectMap mObjects; 271 272 std::set<Object*> mAnimatedObjects; // stores pointers to elements in mObjects 273 274 ActorMap mActors; 275 276 using ProjectileMap = std::map<int, std::shared_ptr<Projectile>>; 277 ProjectileMap mProjectiles; 278 279 using HeightFieldMap = std::map<std::pair<int, int>, osg::ref_ptr<HeightField>>; 280 HeightFieldMap mHeightFields; 281 282 bool mDebugDrawEnabled; 283 284 float mTimeAccum; 285 286 unsigned int mProjectileId; 287 288 float mWaterHeight; 289 bool mWaterEnabled; 290 291 std::unique_ptr<btCollisionObject> mWaterCollisionObject; 292 std::unique_ptr<btCollisionShape> mWaterCollisionShape; 293 294 std::unique_ptr<MWRender::DebugDrawer> mDebugDrawer; 295 296 osg::ref_ptr<osg::Group> mParentNode; 297 298 float mPhysicsDt; 299 300 PhysicsSystem (const PhysicsSystem&); 301 PhysicsSystem& operator= (const PhysicsSystem&); 302 }; 303 } 304 305 #endif 306