You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
openmw/apps/openmw/mwphysics/actor.hpp

204 lines
6.2 KiB
C++

#ifndef OPENMW_MWPHYSICS_ACTOR_H
#define OPENMW_MWPHYSICS_ACTOR_H
#include <atomic>
#include <memory>
#include <mutex>
#include "ptrholder.hpp"
#include <LinearMath/btTransform.h>
#include <osg/Vec3f>
#include <osg/Quat>
#include <osg/ref_ptr>
class btCollisionShape;
class btCollisionObject;
class btConvexShape;
namespace Resource
{
class BulletShape;
}
namespace MWPhysics
{
class PhysicsTaskScheduler;
class Actor final : public PtrHolder
{
public:
Actor(const MWWorld::Ptr& ptr, const Resource::BulletShape* shape, PhysicsTaskScheduler* scheduler);
~Actor() override;
/**
* Sets the collisionMode for this actor. If disabled, the actor can fly and clip geometry.
*/
void enableCollisionMode(bool collision);
bool getCollisionMode() const
{
return mInternalCollisionMode.load(std::memory_order_acquire);
}
btConvexShape* getConvexShape() const { return mConvexShape; }
/**
* Enables or disables the *external* collision body. If disabled, other actors will not collide with this actor.
*/
void enableCollisionBody(bool collision);
void updateScale();
void updateRotation();
/**
* Return true if the collision shape looks the same no matter how its Z rotated.
*/
bool isRotationallyInvariant() const;
/**
* Set mWorldPosition to the position in the Ptr's RefData. This is used by the physics simulation to account for
* when an object is "instantly" moved/teleported as opposed to being moved by the physics simulation.
*/
void updateWorldPosition();
osg::Vec3f getWorldPosition() const;
/**
* Used by the physics simulation to store the simulation result. Used in conjunction with mWorldPosition
* to account for e.g. scripted movements
*/
void setSimulationPosition(const osg::Vec3f& position);
osg::Vec3f getSimulationPosition() const;
void updateCollisionObjectPosition();
/**
* Returns the half extents of the collision body (scaled according to collision scale)
*/
osg::Vec3f getHalfExtents() const;
/**
* Returns the half extents of the collision body (not scaled)
*/
osg::Vec3f getOriginalHalfExtents() const;
/// Returns the mesh translation, scaled and rotated as necessary
osg::Vec3f getScaledMeshTranslation() const;
/**
* Returns the position of the collision body
* @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;
/**
* Store the current position into mPreviousPosition, then move to this position.
* Returns true if the new position is different.
*/
bool setPosition(const osg::Vec3f& position);
void updatePosition();
void adjustPosition(const osg::Vec3f& offset);
osg::Vec3f getPosition() const;
osg::Vec3f getPreviousPosition() const;
/**
* Returns the half extents of the collision body (scaled according to rendering scale)
* @note The reason we need this extra method is because of an inconsistency in MW - NPC race scales aren't applied to the collision shape,
* most likely to make environment collision testing easier. However in some cases (swimming level) we want the actual scale.
*/
osg::Vec3f getRenderingHalfExtents() const;
/**
* Sets the current amount of inertial force (incl. gravity) affecting this physic actor
*/
void setInertialForce(const osg::Vec3f &force);
/**
* Gets the current amount of inertial force (incl. gravity) affecting this physic actor
*/
const osg::Vec3f &getInertialForce() const
{
return mForce;
}
void setOnGround(bool grounded);
bool getOnGround() const
{
return mInternalCollisionMode.load(std::memory_order_acquire) && mOnGround.load(std::memory_order_acquire);
}
void setOnSlope(bool slope);
bool getOnSlope() const
{
return mInternalCollisionMode.load(std::memory_order_acquire) && mOnSlope.load(std::memory_order_acquire);
}
btCollisionObject* getCollisionObject() const
{
return mCollisionObject.get();
}
/// Sets whether this actor should be able to collide with the water surface
void setCanWaterWalk(bool waterWalk);
/// Sets whether this actor has been walking on the water surface in the last frame
void setWalkingOnWater(bool walkingOnWater);
bool isWalkingOnWater() const;
MWWorld::Ptr getStandingOnPtr() const;
void setStandingOnPtr(const MWWorld::Ptr& ptr);
private:
MWWorld::Ptr mStandingOnPtr;
/// Removes then re-adds the collision object to the dynamics world
void updateCollisionMask();
void addCollisionMask(int collisionMask);
int getCollisionMask() const;
bool mCanWaterWalk;
std::atomic<bool> mWalkingOnWater;
bool mRotationallyInvariant;
std::unique_ptr<btCollisionShape> mShape;
btConvexShape* mConvexShape;
std::unique_ptr<btCollisionObject> mCollisionObject;
osg::Vec3f mMeshTranslation;
osg::Vec3f mHalfExtents;
osg::Quat mRotation;
osg::Vec3f mScale;
osg::Vec3f mRenderingScale;
osg::Vec3f mWorldPosition;
osg::Vec3f mSimulationPosition;
osg::Vec3f mPosition;
osg::Vec3f mPreviousPosition;
osg::Vec3f mPositionOffset;
bool mWorldPositionChanged;
bool mSkipSimulation;
btTransform mLocalTransform;
mutable std::mutex mPositionMutex;
osg::Vec3f mForce;
std::atomic<bool> mOnGround;
std::atomic<bool> mOnSlope;
std::atomic<bool> mInternalCollisionMode;
bool mExternalCollisionMode;
PhysicsTaskScheduler* mTaskScheduler;
Actor(const Actor&);
Actor& operator=(const Actor&);
};
}
#endif