forked from mirror/openmw-tes3mp
Physics stub in preparation for rewrite
parent
48ffeab191
commit
c843cfc8e2
@ -1,3 +0,0 @@
|
|||||||
*~
|
|
||||||
*.o
|
|
||||||
*_test
|
|
@ -1,17 +0,0 @@
|
|||||||
set(OENGINE_BULLET
|
|
||||||
bullet/physic.cpp
|
|
||||||
bullet/physic.hpp
|
|
||||||
bullet/BulletShapeLoader.cpp
|
|
||||||
bullet/BulletShapeLoader.h
|
|
||||||
bullet/trace.cpp
|
|
||||||
bullet/trace.h
|
|
||||||
)
|
|
||||||
|
|
||||||
set(OENGINE_ALL ${OENGINE_BULLET})
|
|
||||||
|
|
||||||
set(OENGINE_LIBRARY "oengine")
|
|
||||||
set(OENGINE_LIBRARY ${OENGINE_LIBRARY} PARENT_SCOPE)
|
|
||||||
|
|
||||||
source_group(oengine FILES ${OENGINE_ALL})
|
|
||||||
|
|
||||||
add_library(${OENGINE_LIBRARY} STATIC ${OENGINE_ALL})
|
|
@ -1,12 +0,0 @@
|
|||||||
OpenEngine README
|
|
||||||
=================
|
|
||||||
|
|
||||||
OpenEngine is a bunch of stand-alone game engine modules collected from the OpenMW project (see http://github.com/korslund/openmw or http://openmw.com ) and from certain other projects.
|
|
||||||
|
|
||||||
It is currently a very early work in progress, and development will follow OpenMW closely for a while forward.
|
|
||||||
|
|
||||||
OpenEngine will depend heavily on Mangle ( http://github.com/korslund/mangle/ ) and will thus aim to be backend agnostic. When finished it should work with a variety for free and commercial middleware libraries as backends for graphics, sound, physics, input and so on.
|
|
||||||
|
|
||||||
All questions can be directed to Nicolay Korslund at korslund@gmail.com
|
|
||||||
|
|
||||||
- Nicolay
|
|
@ -1,66 +0,0 @@
|
|||||||
#include "BulletShapeLoader.h"
|
|
||||||
|
|
||||||
namespace OEngine {
|
|
||||||
namespace Physic
|
|
||||||
{
|
|
||||||
|
|
||||||
BulletShape::BulletShape(Ogre::ResourceManager* creator, const Ogre::String &name,
|
|
||||||
Ogre::ResourceHandle handle, const Ogre::String &group, bool isManual,
|
|
||||||
Ogre::ManualResourceLoader *loader) :
|
|
||||||
Ogre::Resource(creator, name, handle, group, isManual, loader)
|
|
||||||
{
|
|
||||||
/* If you were storing a pointer to an object, then you would set that pointer to NULL here.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* For consistency with StringInterface, but we don't add any parameters here
|
|
||||||
That's because the Resource implementation of StringInterface is to
|
|
||||||
list all the options that need to be set before loading, of which
|
|
||||||
we have none as such. Full details can be set through scripts.
|
|
||||||
*/
|
|
||||||
mCollisionShape = NULL;
|
|
||||||
mAutogenerated = true;
|
|
||||||
createParamDictionary("BulletShape");
|
|
||||||
}
|
|
||||||
|
|
||||||
BulletShape::~BulletShape()
|
|
||||||
{
|
|
||||||
deleteShape(mCollisionShape);
|
|
||||||
}
|
|
||||||
|
|
||||||
// farm out to BulletShapeLoader
|
|
||||||
void BulletShape::loadImpl()
|
|
||||||
{
|
|
||||||
mLoader->loadResource(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
void BulletShape::deleteShape(btCollisionShape* shape)
|
|
||||||
{
|
|
||||||
if(shape!=NULL)
|
|
||||||
{
|
|
||||||
if(shape->isCompound())
|
|
||||||
{
|
|
||||||
btCompoundShape* ms = static_cast<btCompoundShape*>(shape);
|
|
||||||
int a = ms->getNumChildShapes();
|
|
||||||
for(int i=0; i <a;i++)
|
|
||||||
{
|
|
||||||
deleteShape(ms->getChildShape(i));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
delete shape;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void BulletShape::unloadImpl()
|
|
||||||
{
|
|
||||||
deleteShape(mCollisionShape);
|
|
||||||
mCollisionShape = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
//TODO:change this?
|
|
||||||
size_t BulletShape::calculateSize() const
|
|
||||||
{
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,59 +0,0 @@
|
|||||||
#ifndef OPENMW_BULLET_SHAPE_LOADER_H_
|
|
||||||
#define OPENMW_BULLET_SHAPE_LOADER_H_
|
|
||||||
|
|
||||||
#include <OgreResource.h>
|
|
||||||
#include <OgreResourceManager.h>
|
|
||||||
#include <btBulletCollisionCommon.h>
|
|
||||||
#include <OgreVector3.h>
|
|
||||||
|
|
||||||
#include <osg/Vec3f>
|
|
||||||
#include <osg/Quat>
|
|
||||||
|
|
||||||
namespace OEngine {
|
|
||||||
namespace Physic
|
|
||||||
{
|
|
||||||
|
|
||||||
/**
|
|
||||||
*Define a new resource which describe a Shape usable by bullet.See BulletShapeManager for how to get/use them.
|
|
||||||
*/
|
|
||||||
class BulletShape : public Ogre::Resource
|
|
||||||
{
|
|
||||||
protected:
|
|
||||||
void loadImpl();
|
|
||||||
void unloadImpl();
|
|
||||||
size_t calculateSize() const;
|
|
||||||
|
|
||||||
void deleteShape(btCollisionShape* shape);
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
BulletShape(Ogre::ResourceManager *creator, const Ogre::String &name,
|
|
||||||
Ogre::ResourceHandle handle, const Ogre::String &group, bool isManual = false,
|
|
||||||
Ogre::ManualResourceLoader *loader = 0);
|
|
||||||
|
|
||||||
virtual ~BulletShape();
|
|
||||||
|
|
||||||
// Stores animated collision shapes. If any collision nodes in the NIF are animated, then mCollisionShape
|
|
||||||
// will be a btCompoundShape (which consists of one or more child shapes).
|
|
||||||
// In this map, for each animated collision shape,
|
|
||||||
// we store the node's record index mapped to the child index of the shape in the btCompoundShape.
|
|
||||||
std::map<int, int> mAnimatedShapes;
|
|
||||||
|
|
||||||
btCollisionShape* mCollisionShape;
|
|
||||||
|
|
||||||
// Does this .nif have an autogenerated collision mesh?
|
|
||||||
bool mAutogenerated;
|
|
||||||
|
|
||||||
osg::Vec3f mBoxTranslation;
|
|
||||||
osg::Quat mBoxRotation;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
typedef Ogre::SharedPtr<BulletShape> BulletShapePtr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
@ -1,709 +0,0 @@
|
|||||||
#include "physic.hpp"
|
|
||||||
|
|
||||||
#include <btBulletDynamicsCommon.h>
|
|
||||||
#include <btBulletCollisionCommon.h>
|
|
||||||
#include <BulletCollision/CollisionShapes/btHeightfieldTerrainShape.h>
|
|
||||||
|
|
||||||
#include <boost/lexical_cast.hpp>
|
|
||||||
#include <boost/format.hpp>
|
|
||||||
|
|
||||||
#include <OgreSceneManager.h>
|
|
||||||
|
|
||||||
#include <components/nifbullet/bulletnifloader.hpp>
|
|
||||||
#include <components/misc/stringops.hpp>
|
|
||||||
|
|
||||||
namespace
|
|
||||||
{
|
|
||||||
|
|
||||||
// Create a copy of the given collision shape (responsibility of user to delete the returned shape).
|
|
||||||
btCollisionShape *duplicateCollisionShape(btCollisionShape *shape)
|
|
||||||
{
|
|
||||||
if(shape->isCompound())
|
|
||||||
{
|
|
||||||
btCompoundShape *comp = static_cast<btCompoundShape*>(shape);
|
|
||||||
btCompoundShape *newShape = new btCompoundShape;
|
|
||||||
|
|
||||||
int numShapes = comp->getNumChildShapes();
|
|
||||||
for(int i = 0;i < numShapes;i++)
|
|
||||||
{
|
|
||||||
btCollisionShape *child = duplicateCollisionShape(comp->getChildShape(i));
|
|
||||||
btTransform trans = comp->getChildTransform(i);
|
|
||||||
newShape->addChildShape(trans, child);
|
|
||||||
}
|
|
||||||
|
|
||||||
return newShape;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(btBvhTriangleMeshShape *trishape = dynamic_cast<btBvhTriangleMeshShape*>(shape))
|
|
||||||
{
|
|
||||||
btTriangleMesh* oldMesh = static_cast<btTriangleMesh*>(trishape->getMeshInterface());
|
|
||||||
btTriangleMesh* newMesh = new btTriangleMesh(*oldMesh);
|
|
||||||
NifBullet::TriangleMeshShape *newShape = new NifBullet::TriangleMeshShape(newMesh, true);
|
|
||||||
|
|
||||||
return newShape;
|
|
||||||
}
|
|
||||||
|
|
||||||
throw std::logic_error(std::string("Unhandled Bullet shape duplication: ")+shape->getName());
|
|
||||||
}
|
|
||||||
|
|
||||||
void deleteShape(btCollisionShape* shape)
|
|
||||||
{
|
|
||||||
if(shape!=NULL)
|
|
||||||
{
|
|
||||||
if(shape->isCompound())
|
|
||||||
{
|
|
||||||
btCompoundShape* ms = static_cast<btCompoundShape*>(shape);
|
|
||||||
int a = ms->getNumChildShapes();
|
|
||||||
for(int i=0; i <a;i++)
|
|
||||||
{
|
|
||||||
deleteShape(ms->getChildShape(i));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
delete shape;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace OEngine {
|
|
||||||
namespace Physic
|
|
||||||
{
|
|
||||||
|
|
||||||
PhysicActor::PhysicActor(const std::string &name, const std::string &mesh, PhysicEngine *engine, const Ogre::Vector3 &position, const Ogre::Quaternion &rotation, float scale)
|
|
||||||
: mCanWaterWalk(false), mWalkingOnWater(false)
|
|
||||||
, mBody(0), mScale(scale), mForce(0.0f), mOnGround(false)
|
|
||||||
, mInternalCollisionMode(true)
|
|
||||||
, mExternalCollisionMode(true)
|
|
||||||
, mMesh(mesh), mName(name), mEngine(engine)
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
if (!NifBullet::getBoundingBox(mMesh, mHalfExtents, mMeshTranslation, mMeshOrientation))
|
|
||||||
{
|
|
||||||
mHalfExtents = Ogre::Vector3(0.f);
|
|
||||||
mMeshTranslation = Ogre::Vector3(0.f);
|
|
||||||
mMeshOrientation = Ogre::Quaternion::IDENTITY;
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
/*
|
|
||||||
// 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)
|
|
||||||
{
|
|
||||||
// Could also be btCapsuleShapeZ, but the movement solver seems to have issues with it (jumping on slopes doesn't work)
|
|
||||||
mShape.reset(new btCylinderShapeZ(BtOgre::Convert::toBullet(mHalfExtents)));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
mShape.reset(new btBoxShape(BtOgre::Convert::toBullet(mHalfExtents)));
|
|
||||||
*/
|
|
||||||
|
|
||||||
mShape->setLocalScaling(btVector3(scale,scale,scale));
|
|
||||||
|
|
||||||
btRigidBody::btRigidBodyConstructionInfo CI = btRigidBody::btRigidBodyConstructionInfo
|
|
||||||
(0,0, mShape.get());
|
|
||||||
mBody = new RigidBody(CI, name);
|
|
||||||
mBody->mPlaceable = false;
|
|
||||||
mBody->setCollisionFlags(btCollisionObject::CF_KINEMATIC_OBJECT);
|
|
||||||
mBody->setActivationState(DISABLE_DEACTIVATION);
|
|
||||||
|
|
||||||
setPosition(position);
|
|
||||||
setRotation(rotation);
|
|
||||||
|
|
||||||
updateCollisionMask();
|
|
||||||
}
|
|
||||||
|
|
||||||
PhysicActor::~PhysicActor()
|
|
||||||
{
|
|
||||||
if(mBody)
|
|
||||||
{
|
|
||||||
mEngine->mDynamicsWorld->removeRigidBody(mBody);
|
|
||||||
delete mBody;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void PhysicActor::enableCollisionMode(bool collision)
|
|
||||||
{
|
|
||||||
mInternalCollisionMode = collision;
|
|
||||||
}
|
|
||||||
|
|
||||||
void PhysicActor::enableCollisionBody(bool collision)
|
|
||||||
{
|
|
||||||
if (mExternalCollisionMode != collision)
|
|
||||||
{
|
|
||||||
mExternalCollisionMode = collision;
|
|
||||||
updateCollisionMask();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void PhysicActor::updateCollisionMask()
|
|
||||||
{
|
|
||||||
mEngine->mDynamicsWorld->removeRigidBody(mBody);
|
|
||||||
int collisionMask = CollisionType_World | CollisionType_HeightMap;
|
|
||||||
if (mExternalCollisionMode)
|
|
||||||
collisionMask |= CollisionType_Actor | CollisionType_Projectile;
|
|
||||||
if (mCanWaterWalk)
|
|
||||||
collisionMask |= CollisionType_Water;
|
|
||||||
mEngine->mDynamicsWorld->addRigidBody(mBody, CollisionType_Actor, collisionMask);
|
|
||||||
}
|
|
||||||
|
|
||||||
const Ogre::Vector3& PhysicActor::getPosition() const
|
|
||||||
{
|
|
||||||
return mPosition;
|
|
||||||
}
|
|
||||||
|
|
||||||
void PhysicActor::setPosition(const Ogre::Vector3 &position)
|
|
||||||
{
|
|
||||||
assert(mBody);
|
|
||||||
|
|
||||||
mPosition = position;
|
|
||||||
|
|
||||||
//btTransform tr = mBody->getWorldTransform();
|
|
||||||
//Ogre::Quaternion meshrot = mMeshOrientation;
|
|
||||||
//Ogre::Vector3 transrot = meshrot * (mMeshTranslation * mScale);
|
|
||||||
//Ogre::Vector3 newPosition = transrot + position;
|
|
||||||
|
|
||||||
//tr.setOrigin(BtOgre::Convert::toBullet(newPosition));
|
|
||||||
//mBody->setWorldTransform(tr);
|
|
||||||
}
|
|
||||||
|
|
||||||
void PhysicActor::setRotation (const Ogre::Quaternion& rotation)
|
|
||||||
{
|
|
||||||
//btTransform tr = mBody->getWorldTransform();
|
|
||||||
//tr.setRotation(BtOgre::Convert::toBullet(mMeshOrientation * rotation));
|
|
||||||
//mBody->setWorldTransform(tr);
|
|
||||||
}
|
|
||||||
|
|
||||||
void PhysicActor::setScale(float scale)
|
|
||||||
{
|
|
||||||
mScale = scale;
|
|
||||||
mShape->setLocalScaling(btVector3(scale,scale,scale));
|
|
||||||
setPosition(mPosition);
|
|
||||||
}
|
|
||||||
|
|
||||||
Ogre::Vector3 PhysicActor::getHalfExtents() const
|
|
||||||
{
|
|
||||||
return mHalfExtents * mScale;
|
|
||||||
}
|
|
||||||
|
|
||||||
void PhysicActor::setInertialForce(const Ogre::Vector3 &force)
|
|
||||||
{
|
|
||||||
mForce = force;
|
|
||||||
}
|
|
||||||
|
|
||||||
void PhysicActor::setOnGround(bool grounded)
|
|
||||||
{
|
|
||||||
mOnGround = grounded;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool PhysicActor::isWalkingOnWater() const
|
|
||||||
{
|
|
||||||
return mWalkingOnWater;
|
|
||||||
}
|
|
||||||
|
|
||||||
void PhysicActor::setWalkingOnWater(bool walkingOnWater)
|
|
||||||
{
|
|
||||||
mWalkingOnWater = walkingOnWater;
|
|
||||||
}
|
|
||||||
|
|
||||||
void PhysicActor::setCanWaterWalk(bool waterWalk)
|
|
||||||
{
|
|
||||||
if (waterWalk != mCanWaterWalk)
|
|
||||||
{
|
|
||||||
mCanWaterWalk = waterWalk;
|
|
||||||
updateCollisionMask();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
|
|
||||||
RigidBody::RigidBody(btRigidBody::btRigidBodyConstructionInfo& CI,std::string name)
|
|
||||||
: btRigidBody(CI)
|
|
||||||
, mName(name)
|
|
||||||
, mPlaceable(false)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
RigidBody::~RigidBody()
|
|
||||||
{
|
|
||||||
delete getMotionState();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
PhysicEngine::PhysicEngine()
|
|
||||||
{
|
|
||||||
// Set up the collision configuration and dispatcher
|
|
||||||
mCollisionConfiguration = new btDefaultCollisionConfiguration();
|
|
||||||
mDispatcher = new btCollisionDispatcher(mCollisionConfiguration);
|
|
||||||
|
|
||||||
// The actual physics solver
|
|
||||||
mSolver = new btSequentialImpulseConstraintSolver;
|
|
||||||
|
|
||||||
mBroadphase = new btDbvtBroadphase();
|
|
||||||
|
|
||||||
// The world.
|
|
||||||
mDynamicsWorld = new btDiscreteDynamicsWorld(mDispatcher,mBroadphase,mSolver,mCollisionConfiguration);
|
|
||||||
|
|
||||||
// Don't update AABBs of all objects every frame. Most objects in MW are static, so we don't need this.
|
|
||||||
// Should a "static" object ever be moved, we have to update its AABB manually using DynamicsWorld::updateSingleAabb.
|
|
||||||
mDynamicsWorld->setForceUpdateAllAabbs(false);
|
|
||||||
|
|
||||||
mDynamicsWorld->setGravity(btVector3(0,0,-10));
|
|
||||||
}
|
|
||||||
|
|
||||||
PhysicEngine::~PhysicEngine()
|
|
||||||
{
|
|
||||||
for (std::map<RigidBody*, AnimatedShapeInstance>::iterator it = mAnimatedShapes.begin(); it != mAnimatedShapes.end(); ++it)
|
|
||||||
deleteShape(it->second.mCompound);
|
|
||||||
|
|
||||||
HeightFieldContainer::iterator hf_it = mHeightFieldMap.begin();
|
|
||||||
for (; hf_it != mHeightFieldMap.end(); ++hf_it)
|
|
||||||
{
|
|
||||||
mDynamicsWorld->removeRigidBody(hf_it->second.mBody);
|
|
||||||
delete hf_it->second.mShape;
|
|
||||||
delete hf_it->second.mBody;
|
|
||||||
}
|
|
||||||
|
|
||||||
RigidBodyContainer::iterator rb_it = mCollisionObjectMap.begin();
|
|
||||||
for (; rb_it != mCollisionObjectMap.end(); ++rb_it)
|
|
||||||
{
|
|
||||||
if (rb_it->second != NULL)
|
|
||||||
{
|
|
||||||
mDynamicsWorld->removeRigidBody(rb_it->second);
|
|
||||||
|
|
||||||
delete rb_it->second;
|
|
||||||
rb_it->second = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
PhysicActorContainer::iterator pa_it = mActorMap.begin();
|
|
||||||
for (; pa_it != mActorMap.end(); ++pa_it)
|
|
||||||
{
|
|
||||||
if (pa_it->second != NULL)
|
|
||||||
{
|
|
||||||
delete pa_it->second;
|
|
||||||
pa_it->second = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
delete mDynamicsWorld;
|
|
||||||
delete mSolver;
|
|
||||||
delete mCollisionConfiguration;
|
|
||||||
delete mDispatcher;
|
|
||||||
delete mBroadphase;
|
|
||||||
}
|
|
||||||
|
|
||||||
void PhysicEngine::addHeightField(float* heights,
|
|
||||||
int x, int y, float yoffset,
|
|
||||||
float triSize, float sqrtVerts)
|
|
||||||
{
|
|
||||||
const std::string name = "HeightField_"
|
|
||||||
+ boost::lexical_cast<std::string>(x) + "_"
|
|
||||||
+ boost::lexical_cast<std::string>(y);
|
|
||||||
|
|
||||||
// find the minimum and maximum heights (needed for bullet)
|
|
||||||
float minh = heights[0];
|
|
||||||
float maxh = heights[0];
|
|
||||||
for (int i=0; i<sqrtVerts*sqrtVerts; ++i)
|
|
||||||
{
|
|
||||||
float h = heights[i];
|
|
||||||
|
|
||||||
if (h>maxh) maxh = h;
|
|
||||||
if (h<minh) minh = h;
|
|
||||||
}
|
|
||||||
|
|
||||||
btHeightfieldTerrainShape* hfShape = new btHeightfieldTerrainShape(
|
|
||||||
static_cast<int>(sqrtVerts), static_cast<int>(sqrtVerts), heights, 1,
|
|
||||||
minh, maxh, 2,
|
|
||||||
PHY_FLOAT,true);
|
|
||||||
|
|
||||||
hfShape->setUseDiamondSubdivision(true);
|
|
||||||
|
|
||||||
btVector3 scl(triSize, triSize, 1);
|
|
||||||
hfShape->setLocalScaling(scl);
|
|
||||||
|
|
||||||
btRigidBody::btRigidBodyConstructionInfo CI = btRigidBody::btRigidBodyConstructionInfo(0,0,hfShape);
|
|
||||||
RigidBody* body = new RigidBody(CI,name);
|
|
||||||
body->getWorldTransform().setOrigin(btVector3( (x+0.5f)*triSize*(sqrtVerts-1), (y+0.5f)*triSize*(sqrtVerts-1), (maxh+minh)/2.f));
|
|
||||||
|
|
||||||
HeightField hf;
|
|
||||||
hf.mBody = body;
|
|
||||||
hf.mShape = hfShape;
|
|
||||||
|
|
||||||
mHeightFieldMap [name] = hf;
|
|
||||||
|
|
||||||
mDynamicsWorld->addRigidBody(body,CollisionType_HeightMap,
|
|
||||||
CollisionType_Actor|CollisionType_Projectile);
|
|
||||||
}
|
|
||||||
|
|
||||||
void PhysicEngine::removeHeightField(int x, int y)
|
|
||||||
{
|
|
||||||
const std::string name = "HeightField_"
|
|
||||||
+ boost::lexical_cast<std::string>(x) + "_"
|
|
||||||
+ boost::lexical_cast<std::string>(y);
|
|
||||||
|
|
||||||
HeightFieldContainer::iterator it = mHeightFieldMap.find(name);
|
|
||||||
if (it == mHeightFieldMap.end())
|
|
||||||
return;
|
|
||||||
|
|
||||||
const HeightField& hf = it->second;
|
|
||||||
|
|
||||||
mDynamicsWorld->removeRigidBody(hf.mBody);
|
|
||||||
delete hf.mShape;
|
|
||||||
delete hf.mBody;
|
|
||||||
|
|
||||||
mHeightFieldMap.erase(it);
|
|
||||||
}
|
|
||||||
|
|
||||||
void PhysicEngine::adjustRigidBody(RigidBody* body, const Ogre::Vector3 &position, const Ogre::Quaternion &rotation,
|
|
||||||
const Ogre::Vector3 &scaledBoxTranslation, const Ogre::Quaternion &boxRotation)
|
|
||||||
{
|
|
||||||
btTransform tr;
|
|
||||||
Ogre::Quaternion boxrot = rotation * boxRotation;
|
|
||||||
Ogre::Vector3 transrot = boxrot * scaledBoxTranslation;
|
|
||||||
Ogre::Vector3 newPosition = transrot + position;
|
|
||||||
|
|
||||||
tr.setOrigin(btVector3(newPosition.x, newPosition.y, newPosition.z));
|
|
||||||
tr.setRotation(btQuaternion(boxrot.x,boxrot.y,boxrot.z,boxrot.w));
|
|
||||||
body->setWorldTransform(tr);
|
|
||||||
}
|
|
||||||
void PhysicEngine::boxAdjustExternal(const std::string &mesh, RigidBody* body,
|
|
||||||
float scale, const Ogre::Vector3 &position, const Ogre::Quaternion &rotation)
|
|
||||||
{
|
|
||||||
std::string sid = (boost::format("%07.3f") % scale).str();
|
|
||||||
std::string outputstring = mesh + sid;
|
|
||||||
|
|
||||||
//get the shape from the .nif
|
|
||||||
//mShapeLoader->load(outputstring,"General");
|
|
||||||
//BulletShapePtr shape = BulletShapeManager::getSingleton().getByName(outputstring,"General");
|
|
||||||
|
|
||||||
//adjustRigidBody(body, position, rotation, shape->mBoxTranslation * scale, shape->mBoxRotation);
|
|
||||||
}
|
|
||||||
|
|
||||||
RigidBody* PhysicEngine::createAndAdjustRigidBody(const std::string &mesh, const std::string &name,
|
|
||||||
float scale, const Ogre::Vector3 &position, const Ogre::Quaternion &rotation,
|
|
||||||
Ogre::Vector3* scaledBoxTranslation, Ogre::Quaternion* boxRotation, bool placeable)
|
|
||||||
{
|
|
||||||
std::string sid = (boost::format("%07.3f") % scale).str();
|
|
||||||
std::string outputstring = mesh + sid;
|
|
||||||
|
|
||||||
//get the shape from the .nif
|
|
||||||
//mShapeLoader->load(outputstring,"General");
|
|
||||||
BulletShapePtr shape;// = BulletShapeManager::getSingleton().getByName(outputstring,"General");
|
|
||||||
|
|
||||||
// TODO: add option somewhere to enable collision for placeable meshes
|
|
||||||
|
|
||||||
if (placeable && shape->mCollisionShape)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
if (!shape->mCollisionShape)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
btCollisionShape* collisionShape = shape->mCollisionShape;
|
|
||||||
|
|
||||||
// If this is an animated compound shape, we must duplicate it so we can animate
|
|
||||||
// multiple instances independently.
|
|
||||||
if (!shape->mAnimatedShapes.empty())
|
|
||||||
collisionShape = duplicateCollisionShape(collisionShape);
|
|
||||||
|
|
||||||
collisionShape->setLocalScaling( btVector3(scale,scale,scale));
|
|
||||||
|
|
||||||
//create the real body
|
|
||||||
btRigidBody::btRigidBodyConstructionInfo CI = btRigidBody::btRigidBodyConstructionInfo
|
|
||||||
(0,0, collisionShape);
|
|
||||||
RigidBody* body = new RigidBody(CI,name);
|
|
||||||
body->mPlaceable = placeable;
|
|
||||||
|
|
||||||
if (!shape->mAnimatedShapes.empty())
|
|
||||||
{
|
|
||||||
AnimatedShapeInstance instance;
|
|
||||||
instance.mAnimatedShapes = shape->mAnimatedShapes;
|
|
||||||
instance.mCompound = collisionShape;
|
|
||||||
mAnimatedShapes[body] = instance;
|
|
||||||
}
|
|
||||||
|
|
||||||
//if(scaledBoxTranslation != 0)
|
|
||||||
// *scaledBoxTranslation = shape->mBoxTranslation * scale;
|
|
||||||
//if(boxRotation != 0)
|
|
||||||
// *boxRotation = shape->mBoxRotation;
|
|
||||||
|
|
||||||
//adjustRigidBody(body, position, rotation, shape->mBoxTranslation * scale, shape->mBoxRotation);
|
|
||||||
|
|
||||||
assert (mCollisionObjectMap.find(name) == mCollisionObjectMap.end());
|
|
||||||
mCollisionObjectMap[name] = body;
|
|
||||||
mDynamicsWorld->addRigidBody(body,CollisionType_World,CollisionType_Actor|CollisionType_HeightMap);
|
|
||||||
|
|
||||||
return body;
|
|
||||||
}
|
|
||||||
|
|
||||||
void PhysicEngine::removeRigidBody(const std::string &name)
|
|
||||||
{
|
|
||||||
RigidBodyContainer::iterator it = mCollisionObjectMap.find(name);
|
|
||||||
if (it != mCollisionObjectMap.end() )
|
|
||||||
{
|
|
||||||
RigidBody* body = it->second;
|
|
||||||
if(body != NULL)
|
|
||||||
{
|
|
||||||
mDynamicsWorld->removeRigidBody(body);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void PhysicEngine::deleteRigidBody(const std::string &name)
|
|
||||||
{
|
|
||||||
RigidBodyContainer::iterator it = mCollisionObjectMap.find(name);
|
|
||||||
if (it != mCollisionObjectMap.end() )
|
|
||||||
{
|
|
||||||
RigidBody* body = it->second;
|
|
||||||
|
|
||||||
if(body != NULL)
|
|
||||||
{
|
|
||||||
if (mAnimatedShapes.find(body) != mAnimatedShapes.end())
|
|
||||||
deleteShape(mAnimatedShapes[body].mCompound);
|
|
||||||
mAnimatedShapes.erase(body);
|
|
||||||
|
|
||||||
delete body;
|
|
||||||
}
|
|
||||||
mCollisionObjectMap.erase(it);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
RigidBody* PhysicEngine::getRigidBody(const std::string &name)
|
|
||||||
{
|
|
||||||
RigidBodyContainer::iterator it = mCollisionObjectMap.find(name);
|
|
||||||
if (it != mCollisionObjectMap.end() )
|
|
||||||
{
|
|
||||||
RigidBody* body = mCollisionObjectMap[name];
|
|
||||||
return body;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class ContactTestResultCallback : public btCollisionWorld::ContactResultCallback
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
std::vector<std::string> mResult;
|
|
||||||
|
|
||||||
// added in bullet 2.81
|
|
||||||
// this is just a quick hack, as there does not seem to be a BULLET_VERSION macro?
|
|
||||||
#if defined(BT_COLLISION_OBJECT_WRAPPER_H)
|
|
||||||
virtual btScalar addSingleResult(btManifoldPoint& cp,
|
|
||||||
const btCollisionObjectWrapper* colObj0Wrap,int partId0,int index0,
|
|
||||||
const btCollisionObjectWrapper* colObj1Wrap,int partId1,int index1)
|
|
||||||
{
|
|
||||||
const RigidBody* body = dynamic_cast<const RigidBody*>(colObj0Wrap->m_collisionObject);
|
|
||||||
if (body)
|
|
||||||
mResult.push_back(body->mName);
|
|
||||||
|
|
||||||
return 0.f;
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
virtual btScalar addSingleResult(btManifoldPoint& cp, const btCollisionObject* col0, int partId0, int index0,
|
|
||||||
const btCollisionObject* col1, int partId1, int index1)
|
|
||||||
{
|
|
||||||
const RigidBody* body = dynamic_cast<const RigidBody*>(col0);
|
|
||||||
if (body)
|
|
||||||
mResult.push_back(body->mName);
|
|
||||||
|
|
||||||
return 0.f;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
};
|
|
||||||
|
|
||||||
class DeepestNotMeContactTestResultCallback : public btCollisionWorld::ContactResultCallback
|
|
||||||
{
|
|
||||||
const std::string &mFilter;
|
|
||||||
// Store the real origin, since the shape's origin is its center
|
|
||||||
btVector3 mOrigin;
|
|
||||||
|
|
||||||
public:
|
|
||||||
const RigidBody *mObject;
|
|
||||||
btVector3 mContactPoint;
|
|
||||||
btScalar mLeastDistSqr;
|
|
||||||
|
|
||||||
DeepestNotMeContactTestResultCallback(const std::string &filter, const btVector3 &origin)
|
|
||||||
: mFilter(filter), mOrigin(origin), mObject(0), mContactPoint(0,0,0),
|
|
||||||
mLeastDistSqr(std::numeric_limits<float>::max())
|
|
||||||
{ }
|
|
||||||
|
|
||||||
#if defined(BT_COLLISION_OBJECT_WRAPPER_H)
|
|
||||||
virtual btScalar addSingleResult(btManifoldPoint& cp,
|
|
||||||
const btCollisionObjectWrapper* col0Wrap,int partId0,int index0,
|
|
||||||
const btCollisionObjectWrapper* col1Wrap,int partId1,int index1)
|
|
||||||
{
|
|
||||||
const RigidBody* body = dynamic_cast<const RigidBody*>(col1Wrap->m_collisionObject);
|
|
||||||
if(body && body->mName != mFilter)
|
|
||||||
{
|
|
||||||
btScalar distsqr = mOrigin.distance2(cp.getPositionWorldOnA());
|
|
||||||
if(!mObject || distsqr < mLeastDistSqr)
|
|
||||||
{
|
|
||||||
mObject = body;
|
|
||||||
mLeastDistSqr = distsqr;
|
|
||||||
mContactPoint = cp.getPositionWorldOnA();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0.f;
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
virtual btScalar addSingleResult(btManifoldPoint& cp,
|
|
||||||
const btCollisionObject* col0, int partId0, int index0,
|
|
||||||
const btCollisionObject* col1, int partId1, int index1)
|
|
||||||
{
|
|
||||||
const RigidBody* body = dynamic_cast<const RigidBody*>(col1);
|
|
||||||
if(body && body->mName != mFilter)
|
|
||||||
{
|
|
||||||
btScalar distsqr = mOrigin.distance2(cp.getPositionWorldOnA());
|
|
||||||
if(!mObject || distsqr < mLeastDistSqr)
|
|
||||||
{
|
|
||||||
mObject = body;
|
|
||||||
mLeastDistSqr = distsqr;
|
|
||||||
mContactPoint = cp.getPositionWorldOnA();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0.f;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
std::vector<std::string> PhysicEngine::getCollisions(const std::string& name, int collisionGroup, int collisionMask)
|
|
||||||
{
|
|
||||||
RigidBody* body = getRigidBody(name);
|
|
||||||
ContactTestResultCallback callback;
|
|
||||||
callback.m_collisionFilterGroup = collisionGroup;
|
|
||||||
callback.m_collisionFilterMask = collisionMask;
|
|
||||||
mDynamicsWorld->contactTest(body, callback);
|
|
||||||
return callback.mResult;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
std::pair<const RigidBody*,btVector3> PhysicEngine::getFilteredContact(const std::string &filter,
|
|
||||||
const btVector3 &origin,
|
|
||||||
btCollisionObject *object)
|
|
||||||
{
|
|
||||||
DeepestNotMeContactTestResultCallback callback(filter, origin);
|
|
||||||
callback.m_collisionFilterGroup = CollisionType_Actor;
|
|
||||||
callback.m_collisionFilterMask = CollisionType_World | CollisionType_HeightMap | CollisionType_Actor;
|
|
||||||
mDynamicsWorld->contactTest(object, callback);
|
|
||||||
return std::make_pair(callback.mObject, callback.mContactPoint);
|
|
||||||
}
|
|
||||||
|
|
||||||
void PhysicEngine::stepSimulation(double deltaT)
|
|
||||||
{
|
|
||||||
// This seems to be needed for character controller objects
|
|
||||||
mDynamicsWorld->stepSimulation(static_cast<btScalar>(deltaT), 10, 1 / 60.0f);
|
|
||||||
}
|
|
||||||
|
|
||||||
void PhysicEngine::addCharacter(const std::string &name, const std::string &mesh,
|
|
||||||
const Ogre::Vector3 &position, float scale, const Ogre::Quaternion &rotation)
|
|
||||||
{
|
|
||||||
// Remove character with given name, so we don't make memory
|
|
||||||
// leak when character would be added twice
|
|
||||||
removeCharacter(name);
|
|
||||||
|
|
||||||
PhysicActor* newActor = new PhysicActor(name, mesh, this, position, rotation, scale);
|
|
||||||
|
|
||||||
mActorMap[name] = newActor;
|
|
||||||
}
|
|
||||||
|
|
||||||
void PhysicEngine::removeCharacter(const std::string &name)
|
|
||||||
{
|
|
||||||
PhysicActorContainer::iterator it = mActorMap.find(name);
|
|
||||||
if (it != mActorMap.end() )
|
|
||||||
{
|
|
||||||
PhysicActor* act = it->second;
|
|
||||||
if(act != NULL)
|
|
||||||
{
|
|
||||||
delete act;
|
|
||||||
}
|
|
||||||
mActorMap.erase(it);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
PhysicActor* PhysicEngine::getCharacter(const std::string &name)
|
|
||||||
{
|
|
||||||
PhysicActorContainer::iterator it = mActorMap.find(name);
|
|
||||||
if (it != mActorMap.end() )
|
|
||||||
{
|
|
||||||
PhysicActor* act = mActorMap[name];
|
|
||||||
return act;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
std::pair<std::string,float> PhysicEngine::rayTest(const btVector3 &from, const btVector3 &to, bool ignoreHeightMap, Ogre::Vector3* normal)
|
|
||||||
{
|
|
||||||
std::string name = "";
|
|
||||||
float d = -1;
|
|
||||||
|
|
||||||
btCollisionWorld::ClosestRayResultCallback resultCallback1(from, to);
|
|
||||||
resultCallback1.m_collisionFilterGroup = 0xff;
|
|
||||||
resultCallback1.m_collisionFilterMask = CollisionType_World;
|
|
||||||
|
|
||||||
if(!ignoreHeightMap)
|
|
||||||
resultCallback1.m_collisionFilterMask = resultCallback1.m_collisionFilterMask | CollisionType_HeightMap;
|
|
||||||
mDynamicsWorld->rayTest(from, to, resultCallback1);
|
|
||||||
if (resultCallback1.hasHit())
|
|
||||||
{
|
|
||||||
name = static_cast<const RigidBody&>(*resultCallback1.m_collisionObject).mName;
|
|
||||||
d = resultCallback1.m_closestHitFraction;
|
|
||||||
if (normal)
|
|
||||||
*normal = Ogre::Vector3(resultCallback1.m_hitNormalWorld.x(),
|
|
||||||
resultCallback1.m_hitNormalWorld.y(),
|
|
||||||
resultCallback1.m_hitNormalWorld.z());
|
|
||||||
}
|
|
||||||
|
|
||||||
return std::pair<std::string,float>(name,d);
|
|
||||||
}
|
|
||||||
|
|
||||||
// callback that ignores player in results
|
|
||||||
struct OurClosestConvexResultCallback : public btCollisionWorld::ClosestConvexResultCallback
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
OurClosestConvexResultCallback(const btVector3& convexFromWorld,const btVector3& convexToWorld)
|
|
||||||
: btCollisionWorld::ClosestConvexResultCallback(convexFromWorld, convexToWorld) {}
|
|
||||||
|
|
||||||
virtual btScalar addSingleResult(btCollisionWorld::LocalConvexResult& convexResult,bool normalInWorldSpace)
|
|
||||||
{
|
|
||||||
if (const RigidBody* body = dynamic_cast<const RigidBody*>(convexResult.m_hitCollisionObject))
|
|
||||||
if (body->mName == "player")
|
|
||||||
return 0;
|
|
||||||
return btCollisionWorld::ClosestConvexResultCallback::addSingleResult(convexResult, normalInWorldSpace);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
std::pair<bool, float> PhysicEngine::sphereCast (float radius, btVector3& from, btVector3& to)
|
|
||||||
{
|
|
||||||
OurClosestConvexResultCallback callback(from, to);
|
|
||||||
callback.m_collisionFilterGroup = 0xff;
|
|
||||||
callback.m_collisionFilterMask = OEngine::Physic::CollisionType_World|OEngine::Physic::CollisionType_HeightMap;
|
|
||||||
|
|
||||||
btSphereShape shape(radius);
|
|
||||||
const btQuaternion btrot(0.0f, 0.0f, 0.0f);
|
|
||||||
|
|
||||||
btTransform from_ (btrot, from);
|
|
||||||
btTransform to_ (btrot, to);
|
|
||||||
|
|
||||||
mDynamicsWorld->convexSweepTest(&shape, from_, to_, callback);
|
|
||||||
|
|
||||||
if (callback.hasHit())
|
|
||||||
return std::make_pair(true, callback.m_closestHitFraction);
|
|
||||||
else
|
|
||||||
return std::make_pair(false, 1.0f);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,320 +0,0 @@
|
|||||||
#ifndef OENGINE_BULLET_PHYSIC_H
|
|
||||||
#define OENGINE_BULLET_PHYSIC_H
|
|
||||||
|
|
||||||
#include <BulletDynamics/Dynamics/btRigidBody.h>
|
|
||||||
#include "BulletCollision/CollisionDispatch/btGhostObject.h"
|
|
||||||
#include <string>
|
|
||||||
#include <list>
|
|
||||||
#include <map>
|
|
||||||
#include "BulletShapeLoader.h"
|
|
||||||
#include "BulletCollision/CollisionShapes/btScaledBvhTriangleMeshShape.h"
|
|
||||||
#include <boost/shared_ptr.hpp>
|
|
||||||
|
|
||||||
class btRigidBody;
|
|
||||||
class btBroadphaseInterface;
|
|
||||||
class btDefaultCollisionConfiguration;
|
|
||||||
class btSequentialImpulseConstraintSolver;
|
|
||||||
class btCollisionDispatcher;
|
|
||||||
class btDiscreteDynamicsWorld;
|
|
||||||
class btHeightfieldTerrainShape;
|
|
||||||
|
|
||||||
namespace BtOgre
|
|
||||||
{
|
|
||||||
class DebugDrawer;
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace Ogre
|
|
||||||
{
|
|
||||||
class SceneManager;
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace MWWorld
|
|
||||||
{
|
|
||||||
class World;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
namespace OEngine {
|
|
||||||
namespace Physic
|
|
||||||
{
|
|
||||||
struct PhysicEvent;
|
|
||||||
class PhysicEngine;
|
|
||||||
class RigidBody;
|
|
||||||
|
|
||||||
enum CollisionType {
|
|
||||||
CollisionType_Nothing = 0, //<Collide with nothing
|
|
||||||
CollisionType_World = 1<<0, //<Collide with world objects
|
|
||||||
CollisionType_Actor = 1<<1, //<Collide sith actors
|
|
||||||
CollisionType_HeightMap = 1<<2, //<collide with heightmap
|
|
||||||
CollisionType_Projectile = 1<<3,
|
|
||||||
CollisionType_Water = 1<<4
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
*This class is just an extension of normal btRigidBody in order to add extra info.
|
|
||||||
*When bullet give back a btRigidBody, you can just do a static_cast to RigidBody,
|
|
||||||
*so one never should use btRigidBody directly!
|
|
||||||
*/
|
|
||||||
class RigidBody: public btRigidBody
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
RigidBody(btRigidBody::btRigidBodyConstructionInfo& CI,std::string name);
|
|
||||||
virtual ~RigidBody();
|
|
||||||
std::string mName;
|
|
||||||
|
|
||||||
// Hack: placeable objects (that can be picked up by the player) have different collision behaviour.
|
|
||||||
// This variable needs to be passed to BulletNifLoader.
|
|
||||||
bool mPlaceable;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
class PhysicActor
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
PhysicActor(const std::string &name, const std::string &mesh, PhysicEngine *engine, const Ogre::Vector3 &position, const Ogre::Quaternion &rotation, float scale);
|
|
||||||
|
|
||||||
~PhysicActor();
|
|
||||||
|
|
||||||
void setPosition(const Ogre::Vector3 &pos);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the collisionMode for this actor. If disabled, the actor can fly and clip geometry.
|
|
||||||
*/
|
|
||||||
void enableCollisionMode(bool collision);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Enables or disables the *external* collision body. If disabled, other actors will not collide with this actor.
|
|
||||||
*/
|
|
||||||
void enableCollisionBody(bool collision);
|
|
||||||
|
|
||||||
bool getCollisionMode() const
|
|
||||||
{
|
|
||||||
return mInternalCollisionMode;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the scale of the PhysicActor
|
|
||||||
*/
|
|
||||||
void setScale(float scale);
|
|
||||||
|
|
||||||
void setRotation (const Ogre::Quaternion& rotation);
|
|
||||||
|
|
||||||
const Ogre::Vector3& getPosition() const;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the (scaled) half extents
|
|
||||||
*/
|
|
||||||
Ogre::Vector3 getHalfExtents() const;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the current amount of inertial force (incl. gravity) affecting this physic actor
|
|
||||||
*/
|
|
||||||
void setInertialForce(const Ogre::Vector3 &force);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the current amount of inertial force (incl. gravity) affecting this physic actor
|
|
||||||
*/
|
|
||||||
const Ogre::Vector3 &getInertialForce() const
|
|
||||||
{
|
|
||||||
return mForce;
|
|
||||||
}
|
|
||||||
|
|
||||||
void setOnGround(bool grounded);
|
|
||||||
|
|
||||||
bool getOnGround() const
|
|
||||||
{
|
|
||||||
return mInternalCollisionMode && mOnGround;
|
|
||||||
}
|
|
||||||
|
|
||||||
btCollisionObject *getCollisionBody() const
|
|
||||||
{
|
|
||||||
return mBody;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/// 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;
|
|
||||||
|
|
||||||
private:
|
|
||||||
/// Removes then re-adds the collision body to the dynamics world
|
|
||||||
void updateCollisionMask();
|
|
||||||
|
|
||||||
bool mCanWaterWalk;
|
|
||||||
bool mWalkingOnWater;
|
|
||||||
|
|
||||||
boost::shared_ptr<btCollisionShape> mShape;
|
|
||||||
|
|
||||||
OEngine::Physic::RigidBody* mBody;
|
|
||||||
|
|
||||||
Ogre::Quaternion mMeshOrientation;
|
|
||||||
Ogre::Vector3 mMeshTranslation;
|
|
||||||
Ogre::Vector3 mHalfExtents;
|
|
||||||
|
|
||||||
float mScale;
|
|
||||||
Ogre::Vector3 mPosition;
|
|
||||||
|
|
||||||
Ogre::Vector3 mForce;
|
|
||||||
bool mOnGround;
|
|
||||||
bool mInternalCollisionMode;
|
|
||||||
bool mExternalCollisionMode;
|
|
||||||
|
|
||||||
std::string mMesh;
|
|
||||||
std::string mName;
|
|
||||||
PhysicEngine *mEngine;
|
|
||||||
|
|
||||||
PhysicActor(const PhysicActor&);
|
|
||||||
PhysicActor& operator=(const PhysicActor&);
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
struct HeightField
|
|
||||||
{
|
|
||||||
btHeightfieldTerrainShape* mShape;
|
|
||||||
RigidBody* mBody;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct AnimatedShapeInstance
|
|
||||||
{
|
|
||||||
btCollisionShape* mCompound;
|
|
||||||
|
|
||||||
// Maps node record index to child index in the compound shape
|
|
||||||
std::map<int, int> mAnimatedShapes;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The PhysicEngine class contain everything which is needed for Physic.
|
|
||||||
* It's needed that Ogre Resources are set up before the PhysicEngine is created.
|
|
||||||
* Note:deleting it WILL NOT delete the RigidBody!
|
|
||||||
* TODO:unload unused resources?
|
|
||||||
*/
|
|
||||||
class PhysicEngine
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
/**
|
|
||||||
* Note that the shapeLoader IS destroyed by the phyic Engine!!
|
|
||||||
*/
|
|
||||||
PhysicEngine();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* It DOES destroy the shape loader!
|
|
||||||
*/
|
|
||||||
~PhysicEngine();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a RigidBody. It does not add it to the simulation.
|
|
||||||
* After created, the body is set to the correct rotation, position, and scale
|
|
||||||
*/
|
|
||||||
RigidBody* createAndAdjustRigidBody(const std::string &mesh, const std::string &name,
|
|
||||||
float scale, const Ogre::Vector3 &position, const Ogre::Quaternion &rotation,
|
|
||||||
Ogre::Vector3* scaledBoxTranslation = 0, Ogre::Quaternion* boxRotation = 0, bool placeable=false);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adjusts a rigid body to the right position and rotation
|
|
||||||
*/
|
|
||||||
|
|
||||||
void adjustRigidBody(RigidBody* body, const Ogre::Vector3 &position, const Ogre::Quaternion &rotation,
|
|
||||||
const Ogre::Vector3 &scaledBoxTranslation = Ogre::Vector3::ZERO,
|
|
||||||
const Ogre::Quaternion &boxRotation = Ogre::Quaternion::IDENTITY);
|
|
||||||
/**
|
|
||||||
Mainly used to (but not limited to) adjust rigid bodies based on box shapes to the right position and rotation.
|
|
||||||
*/
|
|
||||||
void boxAdjustExternal(const std::string &mesh, RigidBody* body, float scale, const Ogre::Vector3 &position, const Ogre::Quaternion &rotation);
|
|
||||||
/**
|
|
||||||
* Add a HeightField to the simulation
|
|
||||||
*/
|
|
||||||
void addHeightField(float* heights,
|
|
||||||
int x, int y, float yoffset,
|
|
||||||
float triSize, float sqrtVerts);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove a HeightField from the simulation
|
|
||||||
*/
|
|
||||||
void removeHeightField(int x, int y);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove a RigidBody from the simulation. It does not delete it, and does not remove it from the RigidBodyMap.
|
|
||||||
*/
|
|
||||||
void removeRigidBody(const std::string &name);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Delete a RigidBody, and remove it from RigidBodyMap.
|
|
||||||
*/
|
|
||||||
void deleteRigidBody(const std::string &name);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return a pointer to a given rigid body.
|
|
||||||
*/
|
|
||||||
RigidBody* getRigidBody(const std::string &name);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create and add a character to the scene, and add it to the ActorMap.
|
|
||||||
*/
|
|
||||||
void addCharacter(const std::string &name, const std::string &mesh,
|
|
||||||
const Ogre::Vector3 &position, float scale, const Ogre::Quaternion &rotation);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove a character from the scene.
|
|
||||||
*/
|
|
||||||
void removeCharacter(const std::string &name);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return a pointer to a character
|
|
||||||
*/
|
|
||||||
PhysicActor* getCharacter(const std::string &name);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This step the simulation of a given time.
|
|
||||||
*/
|
|
||||||
void stepSimulation(double deltaT);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return the closest object hit by a ray. If there are no objects, it will return ("",-1).
|
|
||||||
* If \a normal is non-NULL, the hit normal will be written there (if there is a hit)
|
|
||||||
*/
|
|
||||||
std::pair<std::string,float> rayTest(const btVector3& from,const btVector3& to,
|
|
||||||
bool ignoreHeightMap = false, Ogre::Vector3* normal = NULL);
|
|
||||||
|
|
||||||
std::pair<bool, float> sphereCast (float radius, btVector3& from, btVector3& to);
|
|
||||||
///< @return (hit, relative distance)
|
|
||||||
|
|
||||||
std::vector<std::string> getCollisions(const std::string& name, int collisionGroup, int collisionMask);
|
|
||||||
|
|
||||||
// Get the nearest object that's inside the given object, filtering out objects of the
|
|
||||||
// provided name
|
|
||||||
std::pair<const RigidBody*,btVector3> getFilteredContact(const std::string &filter,
|
|
||||||
const btVector3 &origin,
|
|
||||||
btCollisionObject *object);
|
|
||||||
|
|
||||||
//Bullet Stuff
|
|
||||||
btBroadphaseInterface* mBroadphase;
|
|
||||||
btDefaultCollisionConfiguration* mCollisionConfiguration;
|
|
||||||
btSequentialImpulseConstraintSolver* mSolver;
|
|
||||||
btCollisionDispatcher* mDispatcher;
|
|
||||||
btDiscreteDynamicsWorld* mDynamicsWorld;
|
|
||||||
|
|
||||||
typedef std::map<std::string, HeightField> HeightFieldContainer;
|
|
||||||
HeightFieldContainer mHeightFieldMap;
|
|
||||||
|
|
||||||
typedef std::map<std::string,RigidBody*> RigidBodyContainer;
|
|
||||||
RigidBodyContainer mCollisionObjectMap;
|
|
||||||
|
|
||||||
// Compound shapes that must be animated each frame based on bone positions
|
|
||||||
// the index refers to an element in mCollisionObjectMap
|
|
||||||
std::map<RigidBody*, AnimatedShapeInstance > mAnimatedShapes;
|
|
||||||
|
|
||||||
typedef std::map<std::string, PhysicActor*> PhysicActorContainer;
|
|
||||||
PhysicActorContainer mActorMap;
|
|
||||||
|
|
||||||
private:
|
|
||||||
PhysicEngine(const PhysicEngine&);
|
|
||||||
PhysicEngine& operator=(const PhysicEngine&);
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
}}
|
|
||||||
|
|
||||||
#endif
|
|
@ -1,133 +0,0 @@
|
|||||||
|
|
||||||
#include "trace.h"
|
|
||||||
|
|
||||||
#include <map>
|
|
||||||
|
|
||||||
#include <btBulletDynamicsCommon.h>
|
|
||||||
#include <btBulletCollisionCommon.h>
|
|
||||||
|
|
||||||
#include "physic.hpp"
|
|
||||||
|
|
||||||
|
|
||||||
namespace OEngine
|
|
||||||
{
|
|
||||||
namespace Physic
|
|
||||||
{
|
|
||||||
|
|
||||||
class ClosestNotMeConvexResultCallback : public btCollisionWorld::ClosestConvexResultCallback
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
ClosestNotMeConvexResultCallback(btCollisionObject *me, const btVector3 &up, btScalar minSlopeDot)
|
|
||||||
: btCollisionWorld::ClosestConvexResultCallback(btVector3(0.0, 0.0, 0.0), btVector3(0.0, 0.0, 0.0)),
|
|
||||||
mMe(me), mUp(up), mMinSlopeDot(minSlopeDot)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual btScalar addSingleResult(btCollisionWorld::LocalConvexResult& convexResult,bool normalInWorldSpace)
|
|
||||||
{
|
|
||||||
if(convexResult.m_hitCollisionObject == mMe)
|
|
||||||
return btScalar( 1 );
|
|
||||||
|
|
||||||
btVector3 hitNormalWorld;
|
|
||||||
if(normalInWorldSpace)
|
|
||||||
hitNormalWorld = convexResult.m_hitNormalLocal;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
///need to transform normal into worldspace
|
|
||||||
hitNormalWorld = convexResult.m_hitCollisionObject->getWorldTransform().getBasis()*convexResult.m_hitNormalLocal;
|
|
||||||
}
|
|
||||||
|
|
||||||
// NOTE : m_hitNormalLocal is not always vertical on the ground with a capsule or a box...
|
|
||||||
|
|
||||||
btScalar dotUp = mUp.dot(hitNormalWorld);
|
|
||||||
if(dotUp < mMinSlopeDot)
|
|
||||||
return btScalar(1);
|
|
||||||
|
|
||||||
return ClosestConvexResultCallback::addSingleResult(convexResult, normalInWorldSpace);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
|
||||||
btCollisionObject *mMe;
|
|
||||||
const btVector3 mUp;
|
|
||||||
const btScalar mMinSlopeDot;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
void ActorTracer::doTrace(btCollisionObject *actor, const Ogre::Vector3 &start, const Ogre::Vector3 &end, const PhysicEngine *enginePass)
|
|
||||||
{
|
|
||||||
const btVector3 btstart(start.x, start.y, start.z);
|
|
||||||
const btVector3 btend(end.x, end.y, end.z);
|
|
||||||
|
|
||||||
const btTransform &trans = actor->getWorldTransform();
|
|
||||||
btTransform from(trans);
|
|
||||||
btTransform to(trans);
|
|
||||||
from.setOrigin(btstart);
|
|
||||||
to.setOrigin(btend);
|
|
||||||
|
|
||||||
ClosestNotMeConvexResultCallback newTraceCallback(actor, btstart-btend, btScalar(0.0));
|
|
||||||
// Inherit the actor's collision group and mask
|
|
||||||
newTraceCallback.m_collisionFilterGroup = actor->getBroadphaseHandle()->m_collisionFilterGroup;
|
|
||||||
newTraceCallback.m_collisionFilterMask = actor->getBroadphaseHandle()->m_collisionFilterMask;
|
|
||||||
|
|
||||||
btCollisionShape *shape = actor->getCollisionShape();
|
|
||||||
assert(shape->isConvex());
|
|
||||||
enginePass->mDynamicsWorld->convexSweepTest(static_cast<btConvexShape*>(shape),
|
|
||||||
from, to, newTraceCallback);
|
|
||||||
|
|
||||||
// Copy the hit data over to our trace results struct:
|
|
||||||
if(newTraceCallback.hasHit())
|
|
||||||
{
|
|
||||||
const btVector3& tracehitnormal = newTraceCallback.m_hitNormalWorld;
|
|
||||||
mFraction = newTraceCallback.m_closestHitFraction;
|
|
||||||
mPlaneNormal = Ogre::Vector3(tracehitnormal.x(), tracehitnormal.y(), tracehitnormal.z());
|
|
||||||
mEndPos = (end-start)*mFraction + start;
|
|
||||||
mHitObject = newTraceCallback.m_hitCollisionObject;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
mEndPos = end;
|
|
||||||
mPlaneNormal = Ogre::Vector3(0.0f, 0.0f, 1.0f);
|
|
||||||
mFraction = 1.0f;
|
|
||||||
mHitObject = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ActorTracer::findGround(const OEngine::Physic::PhysicActor* actor, const Ogre::Vector3 &start, const Ogre::Vector3 &end, const PhysicEngine *enginePass)
|
|
||||||
{
|
|
||||||
const btVector3 btstart(start.x, start.y, start.z+1.0f);
|
|
||||||
const btVector3 btend(end.x, end.y, end.z+1.0f);
|
|
||||||
|
|
||||||
const btTransform &trans = actor->getCollisionBody()->getWorldTransform();
|
|
||||||
btTransform from(trans.getBasis(), btstart);
|
|
||||||
btTransform to(trans.getBasis(), btend);
|
|
||||||
|
|
||||||
ClosestNotMeConvexResultCallback newTraceCallback(actor->getCollisionBody(), btstart-btend, btScalar(0.0));
|
|
||||||
// Inherit the actor's collision group and mask
|
|
||||||
newTraceCallback.m_collisionFilterGroup = actor->getCollisionBody()->getBroadphaseHandle()->m_collisionFilterGroup;
|
|
||||||
newTraceCallback.m_collisionFilterMask = actor->getCollisionBody()->getBroadphaseHandle()->m_collisionFilterMask;
|
|
||||||
newTraceCallback.m_collisionFilterMask &= ~CollisionType_Actor;
|
|
||||||
|
|
||||||
btVector3 halfExtents(actor->getHalfExtents().x, actor->getHalfExtents().y, actor->getHalfExtents().z);
|
|
||||||
|
|
||||||
halfExtents[2] = 1.0f;
|
|
||||||
btCylinderShapeZ base(halfExtents);
|
|
||||||
|
|
||||||
enginePass->mDynamicsWorld->convexSweepTest(&base, from, to, newTraceCallback);
|
|
||||||
if(newTraceCallback.hasHit())
|
|
||||||
{
|
|
||||||
const btVector3& tracehitnormal = newTraceCallback.m_hitNormalWorld;
|
|
||||||
mFraction = newTraceCallback.m_closestHitFraction;
|
|
||||||
mPlaneNormal = Ogre::Vector3(tracehitnormal.x(), tracehitnormal.y(), tracehitnormal.z());
|
|
||||||
mEndPos = (end-start)*mFraction + start;
|
|
||||||
mEndPos[2] += 1.0f;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
mEndPos = end;
|
|
||||||
mPlaneNormal = Ogre::Vector3(0.0f, 0.0f, 1.0f);
|
|
||||||
mFraction = 1.0f;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,33 +0,0 @@
|
|||||||
#ifndef OENGINE_BULLET_TRACE_H
|
|
||||||
#define OENGINE_BULLET_TRACE_H
|
|
||||||
|
|
||||||
#include <OgreVector3.h>
|
|
||||||
|
|
||||||
|
|
||||||
class btCollisionObject;
|
|
||||||
|
|
||||||
|
|
||||||
namespace OEngine
|
|
||||||
{
|
|
||||||
namespace Physic
|
|
||||||
{
|
|
||||||
class PhysicEngine;
|
|
||||||
class PhysicActor;
|
|
||||||
|
|
||||||
struct ActorTracer
|
|
||||||
{
|
|
||||||
Ogre::Vector3 mEndPos;
|
|
||||||
Ogre::Vector3 mPlaneNormal;
|
|
||||||
const btCollisionObject* mHitObject;
|
|
||||||
|
|
||||||
float mFraction;
|
|
||||||
|
|
||||||
void doTrace(btCollisionObject *actor, const Ogre::Vector3 &start, const Ogre::Vector3 &end,
|
|
||||||
const PhysicEngine *enginePass);
|
|
||||||
void findGround(const OEngine::Physic::PhysicActor* actor, const Ogre::Vector3 &start, const Ogre::Vector3 &end,
|
|
||||||
const PhysicEngine *enginePass);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
Loading…
Reference in New Issue