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