2015-05-12 01:02:15 +00:00
|
|
|
#include "actor.hpp"
|
|
|
|
|
2017-02-06 04:39:56 +00:00
|
|
|
#include <BulletCollision/CollisionShapes/btCapsuleShape.h>
|
2015-05-27 20:32:11 +00:00
|
|
|
#include <BulletCollision/CollisionShapes/btBoxShape.h>
|
2015-05-27 21:09:38 +00:00
|
|
|
#include <BulletCollision/CollisionDispatch/btCollisionWorld.h>
|
2015-05-12 01:02:15 +00:00
|
|
|
|
2015-11-20 20:57:04 +00:00
|
|
|
#include <components/sceneutil/positionattitudetransform.hpp>
|
2015-11-16 22:30:10 +00:00
|
|
|
#include <components/resource/bulletshape.hpp>
|
2018-10-22 11:14:25 +00:00
|
|
|
#include <components/debug/debuglog.hpp>
|
2019-02-28 20:03:42 +00:00
|
|
|
#include <components/misc/convert.hpp>
|
2015-05-12 01:02:15 +00:00
|
|
|
|
2015-05-27 20:32:11 +00:00
|
|
|
#include "../mwworld/class.hpp"
|
|
|
|
|
2015-05-12 01:02:15 +00:00
|
|
|
#include "collisiontype.hpp"
|
|
|
|
|
|
|
|
namespace MWPhysics
|
|
|
|
{
|
|
|
|
|
|
|
|
|
2020-10-14 09:32:12 +00:00
|
|
|
Actor::Actor(const MWWorld::Ptr& ptr, const Resource::BulletShape* shape, btCollisionWorld* world)
|
2015-05-12 01:02:15 +00:00
|
|
|
: mCanWaterWalk(false), mWalkingOnWater(false)
|
2020-10-14 09:32:12 +00:00
|
|
|
, mCollisionObject(nullptr), mMeshTranslation(shape->mCollisionBoxTranslate), mHalfExtents(shape->mCollisionBoxHalfExtents)
|
|
|
|
, mForce(0.f, 0.f, 0.f), mOnGround(true), mOnSlope(false)
|
2015-05-12 01:02:15 +00:00
|
|
|
, mInternalCollisionMode(true)
|
|
|
|
, mExternalCollisionMode(true)
|
2015-05-27 21:09:38 +00:00
|
|
|
, mCollisionWorld(world)
|
2015-05-12 01:02:15 +00:00
|
|
|
{
|
|
|
|
mPtr = ptr;
|
|
|
|
|
2018-10-22 11:14:25 +00:00
|
|
|
// We can not create actor without collisions - he will fall through the ground.
|
|
|
|
// In this case we should autogenerate collision box based on mesh shape
|
|
|
|
// (NPCs have bodyparts and use a different approach)
|
|
|
|
if (!ptr.getClass().isNpc() && mHalfExtents.length2() == 0.f)
|
|
|
|
{
|
2020-10-14 09:32:12 +00:00
|
|
|
if (shape->mCollisionShape)
|
2018-10-22 11:14:25 +00:00
|
|
|
{
|
|
|
|
btTransform transform;
|
|
|
|
transform.setIdentity();
|
|
|
|
btVector3 min;
|
|
|
|
btVector3 max;
|
|
|
|
|
2020-10-14 09:32:12 +00:00
|
|
|
shape->mCollisionShape->getAabb(transform, min, max);
|
2018-10-22 11:14:25 +00:00
|
|
|
mHalfExtents.x() = (max[0] - min[0])/2.f;
|
|
|
|
mHalfExtents.y() = (max[1] - min[1])/2.f;
|
|
|
|
mHalfExtents.z() = (max[2] - min[2])/2.f;
|
|
|
|
|
|
|
|
mMeshTranslation = osg::Vec3f(0.f, 0.f, mHalfExtents.z());
|
|
|
|
}
|
|
|
|
|
|
|
|
if (mHalfExtents.length2() == 0.f)
|
|
|
|
Log(Debug::Error) << "Error: Failed to calculate bounding box for actor \"" << ptr.getCellRef().getRefId() << "\".";
|
|
|
|
}
|
|
|
|
|
2015-05-12 01:02:15 +00:00
|
|
|
// Use capsule shape only if base is square (nonuniform scaling apparently doesn't work on it)
|
|
|
|
if (std::abs(mHalfExtents.x()-mHalfExtents.y())<mHalfExtents.x()*0.05 && mHalfExtents.z() >= mHalfExtents.x())
|
|
|
|
{
|
2017-02-06 04:39:56 +00:00
|
|
|
mShape.reset(new btCapsuleShapeZ(mHalfExtents.x(), 2*mHalfExtents.z() - 2*mHalfExtents.x()));
|
2017-02-23 21:34:42 +00:00
|
|
|
mRotationallyInvariant = true;
|
2015-05-12 01:02:15 +00:00
|
|
|
}
|
|
|
|
else
|
2017-02-23 21:34:42 +00:00
|
|
|
{
|
2019-02-28 20:03:42 +00:00
|
|
|
mShape.reset(new btBoxShape(Misc::Convert::toBullet(mHalfExtents)));
|
2017-02-23 21:34:42 +00:00
|
|
|
mRotationallyInvariant = false;
|
|
|
|
}
|
|
|
|
|
2017-02-10 00:58:27 +00:00
|
|
|
mConvexShape = static_cast<btConvexShape*>(mShape.get());
|
2015-05-12 01:02:15 +00:00
|
|
|
|
|
|
|
mCollisionObject.reset(new btCollisionObject);
|
|
|
|
mCollisionObject->setCollisionFlags(btCollisionObject::CF_KINEMATIC_OBJECT);
|
|
|
|
mCollisionObject->setActivationState(DISABLE_DEACTIVATION);
|
|
|
|
mCollisionObject->setCollisionShape(mShape.get());
|
|
|
|
mCollisionObject->setUserPointer(static_cast<PtrHolder*>(this));
|
|
|
|
|
|
|
|
updateRotation();
|
|
|
|
updateScale();
|
2016-02-13 01:56:41 +00:00
|
|
|
updatePosition();
|
2015-05-12 01:02:15 +00:00
|
|
|
|
2016-12-16 19:22:07 +00:00
|
|
|
addCollisionMask(getCollisionMask());
|
2020-10-14 13:47:50 +00:00
|
|
|
commitPositionChange();
|
2015-05-12 01:02:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
Actor::~Actor()
|
|
|
|
{
|
2020-10-14 09:32:12 +00:00
|
|
|
if (mCollisionObject)
|
2015-05-27 21:09:38 +00:00
|
|
|
mCollisionWorld->removeCollisionObject(mCollisionObject.get());
|
2015-05-12 01:02:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void Actor::enableCollisionMode(bool collision)
|
|
|
|
{
|
|
|
|
mInternalCollisionMode = collision;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Actor::enableCollisionBody(bool collision)
|
|
|
|
{
|
|
|
|
if (mExternalCollisionMode != collision)
|
|
|
|
{
|
|
|
|
mExternalCollisionMode = collision;
|
|
|
|
updateCollisionMask();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-12-16 19:22:07 +00:00
|
|
|
void Actor::addCollisionMask(int collisionMask)
|
|
|
|
{
|
|
|
|
mCollisionWorld->addCollisionObject(mCollisionObject.get(), CollisionType_Actor, collisionMask);
|
|
|
|
}
|
|
|
|
|
2015-05-12 01:02:15 +00:00
|
|
|
void Actor::updateCollisionMask()
|
|
|
|
{
|
2020-10-14 13:47:50 +00:00
|
|
|
mCollisionObject->getBroadphaseHandle()->m_collisionFilterMask = getCollisionMask();
|
2016-12-16 19:22:07 +00:00
|
|
|
}
|
|
|
|
|
2020-10-14 09:32:12 +00:00
|
|
|
int Actor::getCollisionMask() const
|
2016-12-16 19:22:07 +00:00
|
|
|
{
|
2015-05-12 01:02:15 +00:00
|
|
|
int collisionMask = CollisionType_World | CollisionType_HeightMap;
|
|
|
|
if (mExternalCollisionMode)
|
2015-12-18 17:32:42 +00:00
|
|
|
collisionMask |= CollisionType_Actor | CollisionType_Projectile | CollisionType_Door;
|
2015-05-12 01:02:15 +00:00
|
|
|
if (mCanWaterWalk)
|
|
|
|
collisionMask |= CollisionType_Water;
|
2016-12-16 19:22:07 +00:00
|
|
|
return collisionMask;
|
2015-05-12 01:02:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void Actor::updatePosition()
|
|
|
|
{
|
|
|
|
osg::Vec3f position = mPtr.getRefData().getPosition().asVec3();
|
|
|
|
|
2016-02-13 01:56:41 +00:00
|
|
|
mPosition = position;
|
|
|
|
mPreviousPosition = position;
|
|
|
|
|
2020-10-14 13:47:50 +00:00
|
|
|
mTransformUpdatePending = true;
|
2016-02-13 01:56:41 +00:00
|
|
|
updateCollisionObjectPosition();
|
|
|
|
}
|
|
|
|
|
|
|
|
void Actor::updateCollisionObjectPosition()
|
|
|
|
{
|
2015-05-12 14:49:21 +00:00
|
|
|
osg::Vec3f scaledTranslation = mRotation * osg::componentMultiply(mMeshTranslation, mScale);
|
2016-02-13 01:56:41 +00:00
|
|
|
osg::Vec3f newPosition = scaledTranslation + mPosition;
|
2020-10-14 13:47:50 +00:00
|
|
|
mLocalTransform.setOrigin(Misc::Convert::toBullet(newPosition));
|
|
|
|
mLocalTransform.setRotation(Misc::Convert::toBullet(mRotation));
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
void Actor::commitPositionChange()
|
|
|
|
{
|
|
|
|
if (mScaleUpdatePending)
|
|
|
|
{
|
|
|
|
mShape->setLocalScaling(Misc::Convert::toBullet(mScale));
|
|
|
|
mScaleUpdatePending = false;
|
|
|
|
}
|
|
|
|
if (mTransformUpdatePending)
|
|
|
|
{
|
|
|
|
mCollisionObject->setWorldTransform(mLocalTransform);
|
|
|
|
mTransformUpdatePending = false;
|
|
|
|
}
|
2015-05-12 01:02:15 +00:00
|
|
|
}
|
|
|
|
|
2016-02-13 01:56:41 +00:00
|
|
|
osg::Vec3f Actor::getCollisionObjectPosition() const
|
2015-11-03 17:15:47 +00:00
|
|
|
{
|
2020-10-14 13:47:50 +00:00
|
|
|
return Misc::Convert::toOsg(mLocalTransform.getOrigin());
|
2015-11-03 17:15:47 +00:00
|
|
|
}
|
|
|
|
|
2016-02-13 01:56:41 +00:00
|
|
|
void Actor::setPosition(const osg::Vec3f &position)
|
|
|
|
{
|
2020-10-14 13:47:50 +00:00
|
|
|
if (mTransformUpdatePending)
|
|
|
|
{
|
|
|
|
mCollisionObject->setWorldTransform(mLocalTransform);
|
|
|
|
mTransformUpdatePending = false;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
mPreviousPosition = mPosition;
|
2016-02-13 01:56:41 +00:00
|
|
|
|
2020-10-14 13:47:50 +00:00
|
|
|
mPosition = position;
|
|
|
|
updateCollisionObjectPosition();
|
|
|
|
mCollisionObject->setWorldTransform(mLocalTransform);
|
|
|
|
}
|
2016-02-13 01:56:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
osg::Vec3f Actor::getPosition() const
|
|
|
|
{
|
|
|
|
return mPosition;
|
|
|
|
}
|
|
|
|
|
|
|
|
osg::Vec3f Actor::getPreviousPosition() const
|
|
|
|
{
|
|
|
|
return mPreviousPosition;
|
|
|
|
}
|
|
|
|
|
2015-05-12 01:02:15 +00:00
|
|
|
void Actor::updateRotation ()
|
|
|
|
{
|
2020-10-14 13:47:50 +00:00
|
|
|
if (mRotation == mPtr.getRefData().getBaseNode()->getAttitude())
|
|
|
|
return;
|
2015-05-12 14:49:21 +00:00
|
|
|
mRotation = mPtr.getRefData().getBaseNode()->getAttitude();
|
|
|
|
|
2020-10-14 13:47:50 +00:00
|
|
|
mTransformUpdatePending = true;
|
2016-02-13 01:56:41 +00:00
|
|
|
updateCollisionObjectPosition();
|
2015-05-12 01:02:15 +00:00
|
|
|
}
|
|
|
|
|
2017-02-23 21:34:42 +00:00
|
|
|
bool Actor::isRotationallyInvariant() const
|
|
|
|
{
|
|
|
|
return mRotationallyInvariant;
|
|
|
|
}
|
|
|
|
|
2015-05-12 01:02:15 +00:00
|
|
|
void Actor::updateScale()
|
|
|
|
{
|
|
|
|
float scale = mPtr.getCellRef().getScale();
|
|
|
|
osg::Vec3f scaleVec(scale,scale,scale);
|
|
|
|
|
2015-11-01 20:45:58 +00:00
|
|
|
mPtr.getClass().adjustScale(mPtr, scaleVec, false);
|
2015-05-12 01:02:15 +00:00
|
|
|
mScale = scaleVec;
|
2020-10-14 13:47:50 +00:00
|
|
|
mScaleUpdatePending = true;
|
2015-05-12 01:02:15 +00:00
|
|
|
|
2015-11-01 20:45:58 +00:00
|
|
|
scaleVec = osg::Vec3f(scale,scale,scale);
|
|
|
|
mPtr.getClass().adjustScale(mPtr, scaleVec, true);
|
|
|
|
mRenderingScale = scaleVec;
|
|
|
|
|
2020-10-14 13:47:50 +00:00
|
|
|
mTransformUpdatePending = true;
|
2016-02-13 01:56:41 +00:00
|
|
|
updateCollisionObjectPosition();
|
2015-05-12 01:02:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
osg::Vec3f Actor::getHalfExtents() const
|
|
|
|
{
|
|
|
|
return osg::componentMultiply(mHalfExtents, mScale);
|
|
|
|
}
|
|
|
|
|
2019-03-03 11:45:36 +00:00
|
|
|
osg::Vec3f Actor::getOriginalHalfExtents() const
|
|
|
|
{
|
|
|
|
return mHalfExtents;
|
|
|
|
}
|
|
|
|
|
2015-11-01 20:45:58 +00:00
|
|
|
osg::Vec3f Actor::getRenderingHalfExtents() const
|
|
|
|
{
|
|
|
|
return osg::componentMultiply(mHalfExtents, mRenderingScale);
|
|
|
|
}
|
|
|
|
|
2015-05-12 01:02:15 +00:00
|
|
|
void Actor::setInertialForce(const osg::Vec3f &force)
|
|
|
|
{
|
|
|
|
mForce = force;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Actor::setOnGround(bool grounded)
|
|
|
|
{
|
|
|
|
mOnGround = grounded;
|
|
|
|
}
|
|
|
|
|
2017-02-06 03:46:44 +00:00
|
|
|
void Actor::setOnSlope(bool slope)
|
|
|
|
{
|
|
|
|
mOnSlope = slope;
|
|
|
|
}
|
|
|
|
|
2015-05-12 01:02:15 +00:00
|
|
|
bool Actor::isWalkingOnWater() const
|
|
|
|
{
|
|
|
|
return mWalkingOnWater;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Actor::setWalkingOnWater(bool walkingOnWater)
|
|
|
|
{
|
|
|
|
mWalkingOnWater = walkingOnWater;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Actor::setCanWaterWalk(bool waterWalk)
|
|
|
|
{
|
|
|
|
if (waterWalk != mCanWaterWalk)
|
|
|
|
{
|
|
|
|
mCanWaterWalk = waterWalk;
|
|
|
|
updateCollisionMask();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|