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