1
0
mirror of https://gitlab.com/OpenMW/openmw.git synced 2025-03-23 01:21:39 +00:00
OpenMW/apps/openmw/mwphysics/physicssystem.hpp

343 lines
12 KiB
C++
Raw Normal View History

#ifndef OPENMW_MWPHYSICS_PHYSICSSYSTEM_H
#define OPENMW_MWPHYSICS_PHYSICSSYSTEM_H
2011-08-01 15:55:36 +02:00
2024-05-09 19:22:47 +02:00
#include <algorithm>
#include <array>
2022-09-22 21:26:05 +03:00
#include <functional>
2015-06-03 23:04:35 +02:00
#include <map>
2022-09-22 21:26:05 +03:00
#include <memory>
#include <optional>
#include <span>
#include <unordered_map>
#include <variant>
2014-10-05 22:24:11 +02:00
#include <osg/BoundingBox>
2022-09-22 21:26:05 +03:00
#include <osg/Quat>
#include <osg/Timer>
2022-09-22 21:26:05 +03:00
#include <osg/ref_ptr>
2015-05-03 00:39:01 +02:00
#include "../mwworld/ptr.hpp"
2015-06-01 01:57:15 +02:00
#include "collisiontype.hpp"
2020-08-03 22:44:16 +02:00
#include "raycasting.hpp"
2015-06-01 01:57:15 +02:00
2015-05-03 00:39:01 +02:00
namespace osg
{
class Group;
class Object;
class Stats;
2015-05-03 00:39:01 +02:00
}
2015-05-03 00:39:01 +02:00
namespace MWRender
{
class DebugDrawer;
}
namespace Resource
{
class BulletShapeManager;
class ResourceSystem;
}
class btCollisionWorld;
2015-05-27 22:32:11 +02:00
class btBroadphaseInterface;
class btDefaultCollisionConfiguration;
class btCollisionDispatcher;
class btCollisionObject;
class btCollisionShape;
class btVector3;
2015-05-10 02:08:25 +02:00
namespace MWPhysics
2011-08-01 15:55:36 +02:00
{
2015-05-10 02:08:25 +02:00
class HeightField;
class Object;
class Actor;
class PhysicsTaskScheduler;
class Projectile;
enum ScriptedCollisionType : char;
using ActorMap = std::unordered_map<const MWWorld::LiveCellRefBase*, std::shared_ptr<Actor>>;
struct ContactPoint
{
MWWorld::Ptr mObject;
osg::Vec3f mPoint;
osg::Vec3f mNormal;
};
struct LOSRequest
{
LOSRequest(const std::weak_ptr<Actor>& a1, const std::weak_ptr<Actor>& a2);
std::array<std::weak_ptr<Actor>, 2> mActors;
std::array<const Actor*, 2> mRawActors;
bool mResult;
bool mStale;
int mAge;
};
bool operator==(const LOSRequest& lhs, const LOSRequest& rhs) noexcept;
struct ActorFrameData
{
ActorFrameData(Actor& actor, bool inert, bool waterCollision, float slowFall, float waterlevel, bool isPlayer);
osg::Vec3f mPosition;
osg::Vec3f mInertia;
const btCollisionObject* mStandingOn;
bool mIsOnGround;
bool mIsOnSlope;
bool mWalkingOnWater;
const bool mInert;
btCollisionObject* mCollisionObject;
const float mSwimLevel;
const float mSlowFall;
osg::Vec2f mRotation;
osg::Vec3f mMovement;
2021-07-22 19:29:20 +02:00
osg::Vec3f mLastStuckPosition;
const float mWaterlevel;
const float mHalfExtentsZ;
float mOldHeight;
unsigned int mStuckFrames;
const bool mFlying;
const bool mWasOnGround;
const bool mIsAquatic;
const bool mWaterCollision;
const bool mSkipCollisionDetection;
const bool mIsPlayer;
};
struct ProjectileFrameData
{
explicit ProjectileFrameData(Projectile& projectile);
osg::Vec3f mPosition;
osg::Vec3f mMovement;
const btCollisionObject* mCaster;
const btCollisionObject* mCollisionObject;
Projectile* mProjectile;
};
struct WorldFrameData
{
WorldFrameData();
bool mIsInStorm;
osg::Vec3f mStormDirection;
};
2015-05-10 02:08:25 +02:00
template <class Ptr, class FrameData>
class SimulationImpl
{
2022-09-22 21:26:05 +03:00
public:
explicit SimulationImpl(const std::weak_ptr<Ptr>& ptr, FrameData&& data)
: mPtr(ptr)
, mData(data)
{
}
std::optional<std::pair<std::shared_ptr<Ptr>, std::reference_wrapper<FrameData>>> lock()
{
if (auto locked = mPtr.lock())
return { { std::move(locked), std::ref(mData) } };
return std::nullopt;
}
private:
std::weak_ptr<Ptr> mPtr;
FrameData mData;
};
using ActorSimulation = SimulationImpl<Actor, ActorFrameData>;
using ProjectileSimulation = SimulationImpl<Projectile, ProjectileFrameData>;
using Simulation = std::variant<ActorSimulation, ProjectileSimulation>;
2020-08-03 22:44:16 +02:00
class PhysicsSystem : public RayCastingInterface
2011-08-01 15:55:36 +02:00
{
2022-09-22 21:26:05 +03:00
public:
PhysicsSystem(Resource::ResourceSystem* resourceSystem, osg::ref_ptr<osg::Group> parentNode);
virtual ~PhysicsSystem();
2014-10-05 22:24:11 +02:00
2022-09-22 21:26:05 +03:00
Resource::BulletShapeManager* getShapeManager();
2015-05-12 19:02:56 +02:00
2022-09-22 21:26:05 +03:00
void enableWater(float height);
void setWaterHeight(float height);
void disableWater();
2022-09-22 21:26:05 +03:00
void addObject(const MWWorld::Ptr& ptr, const std::string& mesh, osg::Quat rotation,
int collisionType = CollisionType_World);
void addActor(const MWWorld::Ptr& ptr, const std::string& mesh);
2015-05-12 19:02:56 +02:00
2022-09-22 21:26:05 +03:00
int addProjectile(
const MWWorld::Ptr& caster, const osg::Vec3f& position, const std::string& mesh, bool computeRadius);
void setCaster(int projectileId, const MWWorld::Ptr& caster);
void removeProjectile(const int projectileId);
2022-09-22 21:26:05 +03:00
void updatePtr(const MWWorld::Ptr& old, const MWWorld::Ptr& updated);
2022-09-22 21:26:05 +03:00
Actor* getActor(const MWWorld::Ptr& ptr);
const Actor* getActor(const MWWorld::ConstPtr& ptr) const;
2022-09-22 21:26:05 +03:00
const Object* getObject(const MWWorld::ConstPtr& ptr) const;
2022-09-22 21:26:05 +03:00
Projectile* getProjectile(int projectileId) const;
2022-09-22 21:26:05 +03:00
// Object or Actor
void remove(const MWWorld::Ptr& ptr);
2022-09-22 21:26:05 +03:00
void updateScale(const MWWorld::Ptr& ptr);
void updateRotation(const MWWorld::Ptr& ptr, osg::Quat rotate);
void updatePosition(const MWWorld::Ptr& ptr);
2022-09-22 21:26:05 +03:00
void addHeightField(const float* heights, int x, int y, int size, int verts, float minH, float maxH,
const osg::Object* holdObject);
2018-03-14 01:49:08 +03:00
2022-09-22 21:26:05 +03:00
void removeHeightField(int x, int y);
const HeightField* getHeightField(int x, int y) const;
2022-09-22 21:26:05 +03:00
bool toggleCollisionMode();
2022-09-22 21:26:05 +03:00
/// Determine new position based on all queued movements, then clear the list.
void stepSimulation(
float dt, bool skipSimulation, osg::Timer_t frameStart, unsigned int frameNumber, osg::Stats& stats);
2022-09-22 21:26:05 +03:00
/// Apply new positions to actors
void moveActors();
void debugDraw();
2012-03-25 20:52:56 +02:00
2022-09-22 21:26:05 +03:00
std::vector<MWWorld::Ptr> getCollisions(const MWWorld::ConstPtr& ptr, int collisionGroup,
int collisionMask) const; ///< get handles this object collides with
std::vector<ContactPoint> getCollisionsPoints(
const MWWorld::ConstPtr& ptr, int collisionGroup, int collisionMask) const;
osg::Vec3f traceDown(const MWWorld::Ptr& ptr, const osg::Vec3f& position, float maxHeight);
2024-02-12 07:52:47 -08:00
/// @param ignore Optional, a list of Ptr to ignore in the list of results. targets are actors to filter for,
/// ignoring all other actors.
2022-09-22 21:26:05 +03:00
RayCastingResult castRay(const osg::Vec3f& from, const osg::Vec3f& to,
2024-02-12 07:52:47 -08:00
const std::vector<MWWorld::ConstPtr>& ignore = {}, const std::vector<MWWorld::Ptr>& targets = {},
int mask = CollisionType_Default, int group = 0xff) const override;
using RayCastingInterface::castRay;
2015-06-01 15:34:46 +02:00
2022-09-22 21:26:05 +03:00
RayCastingResult castSphere(const osg::Vec3f& from, const osg::Vec3f& to, float radius,
int mask = CollisionType_Default, int group = 0xff) const override;
2012-07-25 20:25:53 +04:00
2022-09-22 21:26:05 +03:00
/// Return true if actor1 can see actor2.
bool getLineOfSight(const MWWorld::ConstPtr& actor1, const MWWorld::ConstPtr& actor2) const override;
2015-06-01 02:40:42 +02:00
2022-09-22 21:26:05 +03:00
bool isOnGround(const MWWorld::Ptr& actor);
2022-09-22 21:26:05 +03:00
bool canMoveToWaterSurface(const MWWorld::ConstPtr& actor, const float waterlevel);
2015-06-01 21:41:13 +02:00
2022-09-22 21:26:05 +03:00
/// Get physical half extents (scaled) of the given actor.
osg::Vec3f getHalfExtents(const MWWorld::ConstPtr& actor) const;
2022-09-22 21:26:05 +03:00
/// Get physical half extents (not scaled) of the given actor.
osg::Vec3f getOriginalHalfExtents(const MWWorld::ConstPtr& actor) const;
2022-09-22 21:26:05 +03:00
/// @see MWPhysics::Actor::getRenderingHalfExtents
osg::Vec3f getRenderingHalfExtents(const MWWorld::ConstPtr& actor) const;
2022-09-22 21:26:05 +03:00
/// Get the position of the collision shape for the actor. Use together with getHalfExtents() to get the
/// collision bounds in world space.
/// @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.
osg::Vec3f getCollisionObjectPosition(const MWWorld::ConstPtr& actor) const;
2022-09-22 21:26:05 +03:00
/// Get bounding box in world space of the given object.
osg::BoundingBox getBoundingBox(const MWWorld::ConstPtr& object) const;
2022-09-22 21:26:05 +03:00
/// Queues velocity movement for a Ptr. If a Ptr is already queued, its velocity will
/// be overwritten. Valid until the next call to stepSimulation
void queueObjectMovement(const MWWorld::Ptr& ptr, const osg::Vec3f& velocity);
2022-09-22 21:26:05 +03:00
/// Clear the queued movements list without applying.
void clearQueuedMovement();
2022-09-22 21:26:05 +03:00
/// Return true if \a actor has been standing on \a object in this frame
/// This will trigger whenever the object is directly below the actor.
/// It doesn't matter if the actor is stationary or moving.
bool isActorStandingOn(const MWWorld::Ptr& actor, const MWWorld::ConstPtr& object) const;
2022-09-22 21:26:05 +03:00
/// Get the handle of all actors standing on \a object in this frame.
void getActorsStandingOn(const MWWorld::ConstPtr& object, std::vector<MWWorld::Ptr>& out) const;
/// Return true if an object of the given type has collided with this object
bool isObjectCollidingWith(const MWWorld::ConstPtr& object, ScriptedCollisionType type) const;
2022-09-22 21:26:05 +03:00
/// Get the handle of all actors colliding with \a object in this frame.
void getActorsCollidingWith(const MWWorld::ConstPtr& object, std::vector<MWWorld::Ptr>& out) const;
2015-05-03 00:39:01 +02:00
2022-09-22 21:26:05 +03:00
bool toggleDebugRendering();
2015-11-20 19:22:31 +01:00
2022-09-22 21:26:05 +03:00
/// Mark the given object as a 'non-solid' object. A non-solid object means that
/// \a isOnSolidGround will return false for actors standing on that object.
void markAsNonSolid(const MWWorld::ConstPtr& ptr);
2018-05-26 17:44:25 +03:00
2022-09-22 21:26:05 +03:00
bool isOnSolidGround(const MWWorld::Ptr& actor) const;
2022-09-22 21:26:05 +03:00
void updateAnimatedCollisionShape(const MWWorld::Ptr& object);
2018-05-26 17:44:25 +03:00
2022-09-22 21:26:05 +03:00
template <class Function>
void forEachAnimatedObject(Function&& function) const
{
std::for_each(mAnimatedObjects.begin(), mAnimatedObjects.end(), function);
}
2022-09-22 21:26:05 +03:00
bool isAreaOccupiedByOtherActor(const osg::Vec3f& position, const float radius,
std::span<const MWWorld::ConstPtr> ignore, std::vector<MWWorld::Ptr>* occupyingActors) const;
2022-09-22 21:26:05 +03:00
void reportStats(unsigned int frameNumber, osg::Stats& stats) const;
void reportCollision(const btVector3& position, const btVector3& normal);
2022-09-22 21:26:05 +03:00
private:
void updateWater();
2014-10-05 22:24:11 +02:00
2022-09-22 21:26:05 +03:00
void prepareSimulation(bool willSimulate, std::vector<Simulation>& simulations);
2022-09-22 21:26:05 +03:00
std::unique_ptr<btBroadphaseInterface> mBroadphase;
std::unique_ptr<btDefaultCollisionConfiguration> mCollisionConfiguration;
std::unique_ptr<btCollisionDispatcher> mDispatcher;
std::unique_ptr<btCollisionWorld> mCollisionWorld;
std::unique_ptr<PhysicsTaskScheduler> mTaskScheduler;
2015-05-10 02:08:25 +02:00
2022-09-22 21:26:05 +03:00
std::unique_ptr<Resource::BulletShapeManager> mShapeManager;
Resource::ResourceSystem* mResourceSystem;
2022-09-22 21:26:05 +03:00
using ObjectMap = std::unordered_map<const MWWorld::LiveCellRefBase*, std::shared_ptr<Object>>;
ObjectMap mObjects;
2022-09-22 21:26:05 +03:00
std::map<Object*, bool> mAnimatedObjects; // stores pointers to elements in mObjects
2022-09-22 21:26:05 +03:00
ActorMap mActors;
2022-09-22 21:26:05 +03:00
using ProjectileMap = std::map<int, std::shared_ptr<Projectile>>;
ProjectileMap mProjectiles;
2022-09-22 21:26:05 +03:00
using HeightFieldMap = std::map<std::pair<int, int>, std::unique_ptr<HeightField>>;
HeightFieldMap mHeightFields;
2015-05-10 02:08:25 +02:00
2022-09-22 21:26:05 +03:00
bool mDebugDrawEnabled;
2015-05-03 00:39:01 +02:00
2022-09-22 21:26:05 +03:00
float mTimeAccum;
2022-09-22 21:26:05 +03:00
unsigned int mProjectileId;
2022-09-22 21:26:05 +03:00
float mWaterHeight;
bool mWaterEnabled;
2014-10-05 22:24:11 +02:00
2022-09-22 21:26:05 +03:00
std::unique_ptr<btCollisionObject> mWaterCollisionObject;
std::unique_ptr<btCollisionShape> mWaterCollisionShape;
2014-10-05 22:24:11 +02:00
2022-09-22 21:26:05 +03:00
std::unique_ptr<MWRender::DebugDrawer> mDebugDrawer;
2015-05-03 00:39:01 +02:00
2022-09-22 21:26:05 +03:00
osg::ref_ptr<osg::Group> mParentNode;
2015-05-03 00:39:01 +02:00
2022-09-22 21:26:05 +03:00
float mPhysicsDt;
2022-09-22 21:26:05 +03:00
std::size_t mSimulationsCounter = 0;
std::array<std::vector<Simulation>, 2> mSimulations;
std::vector<std::pair<MWWorld::Ptr, osg::Vec3f>> mActorsPositions;
2022-09-22 21:26:05 +03:00
PhysicsSystem(const PhysicsSystem&);
PhysicsSystem& operator=(const PhysicsSystem&);
2011-08-01 15:55:36 +02:00
};
}
#endif