Add missing files.

loadfix
cc9cii 10 years ago
parent 0e70315f91
commit 70b5d6857a

@ -0,0 +1,441 @@
#include "physicsengine.hpp"
#include <boost/lexical_cast.hpp>
#include <boost/format.hpp>
#include <BulletDynamics/btBulletDynamicsCommon.h>
#include <BulletCollision/btBulletCollisionCommon.h>
#include <BulletCollision/CollisionShapes/btHeightfieldTerrainShape.h>
#include <OgreSceneManager.h>
#include <components/nifbullet/bulletnifloader.hpp>
#include <openengine/bullet/BulletShapeLoader.h>
// PLEASE NOTE:
//
// This file is based on libs/openengine/bullet/physic.cpp. The commit history and
// credits for the code below stem from that file.
namespace CSVWorld
{
RigidBody::RigidBody(btRigidBody::btRigidBodyConstructionInfo &CI,
const std::string &referenceId) : btRigidBody(CI) , mReferenceId(referenceId)
{
}
RigidBody::~RigidBody()
{
delete getMotionState();
}
// In OpenCS one document has one PhysicsSystem. Each PhysicsSystem contains one
// PhysicsEngine. One document can have 0..n SceneWidgets, each with its own
// Ogre::SceneManager.
//
// These relationships are managed by the PhysicsManager.
//
// - When a view is created its document is registered with the PhysicsManager in
// View's constructor. If the document is new a PhysicSystem is created and
// associated with that document. A null list of SceneWidgets are assigned to
// that document.
//
// - When all views for a given document is closed, ViewManager will notify the
// PhysicsManager to destroy the PhysicsSystem associated with the document.
//
// - Each time a WorldspaceWidget (or its subclass) is created, it gets the
// PhysicsSystem associates with the widget's document from the PhysicsManager.
// The list of widgets are then maintained, but is not necessary and may be
// removed in future code updates.
//
// Each WorldspaceWidget can have objects (References) and terrain (Land) loaded
// from its document. There may be several views of the object, however there
// is only one corresponding physics object. i.e. each Reference can have 1..n
// SceneNodes
//
// These relationships are managed by the PhysicsSystem for the document.
//
// - Each time a WorldspaceWidget (or its subclass) is created, it registers
// itself and its Ogre::SceneManager with the PhysicsSystem assigned by the
// PhysicsManager.
//
// - Each time an object is added, the object's Ogre::SceneNode name is registered
// with the PhysicsSystem. Ogre itself maintains which SceneNode belongs to
// which SceneManager.
//
// - Each time an terrain is added, its cell coordinates and the SceneManager is
// registered with the PhysicsSystem.
//
PhysicsEngine::PhysicsEngine()
{
// 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));
if(OEngine::Physic::BulletShapeManager::getSingletonPtr() == NULL)
{
new OEngine::Physic::BulletShapeManager();
}
mShapeLoader = new NifBullet::ManualBulletShapeLoader();
}
PhysicsEngine::~PhysicsEngine()
{
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;
}
}
rb_it = mRaycastingObjectMap.begin();
for (; rb_it != mRaycastingObjectMap.end(); ++rb_it)
{
if (rb_it->second != NULL)
{
mDynamicsWorld->removeRigidBody(rb_it->second);
delete rb_it->second;
rb_it->second = NULL;
}
}
delete mDynamicsWorld; // FIXME: need to reference count??
delete mSolver;
delete mCollisionConfiguration;
delete mDispatcher;
delete mBroadphase;
delete mShapeLoader;
delete OEngine::Physic::BulletShapeManager::getSingletonPtr(); // FIXME: need to reference count
}
int PhysicsEngine::toggleDebugRendering(Ogre::SceneManager *sceneMgr)
{
if(!sceneMgr)
return 0;
std::map<Ogre::SceneManager *, BtOgre::DebugDrawer *>::iterator iter =
mDebugDrawers.find(sceneMgr);
if(iter != mDebugDrawers.end()) // found scene manager
{
if((*iter).second)
{
// set a new drawer each time (maybe with a different scene manager)
mDynamicsWorld->setDebugDrawer(mDebugDrawers[sceneMgr]);
if(!mDebugDrawers[sceneMgr]->getDebugMode())
mDebugDrawers[sceneMgr]->setDebugMode(1 /*mDebugDrawFlags*/);
else
mDebugDrawers[sceneMgr]->setDebugMode(0);
mDynamicsWorld->debugDrawWorld(); // FIXME: call this now?
return mDebugDrawers[sceneMgr]->getDebugMode();
}
}
return 0;
}
void PhysicsEngine::stepDebug(Ogre::SceneManager *sceneMgr)
{
if(!sceneMgr)
return;
std::map<Ogre::SceneManager *, BtOgre::DebugDrawer *>::iterator iter =
mDebugDrawers.find(sceneMgr);
if(iter != mDebugDrawers.end()) // found scene manager
{
if((*iter).second)
(*iter).second->step();
else
return;
}
}
void PhysicsEngine::createDebugDraw(Ogre::SceneManager *sceneMgr)
{
if(mDebugDrawers.find(sceneMgr) == mDebugDrawers.end())
{
mDebugSceneNodes[sceneMgr] = sceneMgr->getRootSceneNode()->createChildSceneNode();
mDebugDrawers[sceneMgr] = new BtOgre::DebugDrawer(mDebugSceneNodes[sceneMgr], mDynamicsWorld);
mDebugDrawers[sceneMgr]->setDebugMode(0);
}
}
void PhysicsEngine::removeDebugDraw(Ogre::SceneManager *sceneMgr)
{
std::map<Ogre::SceneManager *, BtOgre::DebugDrawer *>::iterator iter =
mDebugDrawers.find(sceneMgr);
if(iter != mDebugDrawers.end())
{
delete (*iter).second;
mDebugDrawers.erase(iter);
}
std::map<Ogre::SceneManager *, Ogre::SceneNode *>::iterator it =
mDebugSceneNodes.find(sceneMgr);
if(it != mDebugSceneNodes.end())
{
std::string sceneNodeName = (*it).second->getName();
if(sceneMgr->hasSceneNode(sceneNodeName))
sceneMgr->destroySceneNode(sceneNodeName);
}
}
void PhysicsEngine::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(
sqrtVerts, 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.5)*triSize*(sqrtVerts-1),
(y+0.5)*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_Raycasting|CollisionType_Projectile);
}
void PhysicsEngine::removeHeightField(int x, int y)
{
const std::string name = "HeightField_"
+ boost::lexical_cast<std::string>(x) + "_"
+ boost::lexical_cast<std::string>(y);
HeightField hf = mHeightFieldMap [name];
mDynamicsWorld->removeRigidBody(hf.mBody);
delete hf.mShape;
delete hf.mBody;
mHeightFieldMap.erase(name);
}
void PhysicsEngine::adjustRigidBody(RigidBody* body,
const Ogre::Vector3 &position, const Ogre::Quaternion &rotation)
{
btTransform tr;
//Ogre::Quaternion boxrot = rotation * boxRotation;
Ogre::Quaternion boxrot = rotation * Ogre::Quaternion::IDENTITY;
//Ogre::Vector3 transrot = boxrot * scaledBoxTranslation;
Ogre::Vector3 transrot = boxrot * Ogre::Vector3::ZERO;
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);
}
RigidBody* PhysicsEngine::createAndAdjustRigidBody(const std::string &mesh,
const std::string &name, // referenceId, assumed unique per OpenCS document
float scale,
const Ogre::Vector3 &position,
const Ogre::Quaternion &rotation,
bool raycasting,
bool placeable) // indicates whether the object can be picked up by the player
{
std::string sid = (boost::format("%07.3f") % scale).str();
std::string outputstring = mesh + sid;
//get the shape from the .nif
mShapeLoader->load(outputstring, "General");
OEngine::Physic::BulletShapeManager::getSingletonPtr()->load(outputstring, "General");
OEngine::Physic::BulletShapePtr shape =
OEngine::Physic::BulletShapeManager::getSingleton().getByName(outputstring, "General");
if (placeable && !raycasting && shape->mCollisionShape && !shape->mHasCollisionNode)
return NULL;
if (!shape->mCollisionShape && !raycasting)
return NULL;
if (!shape->mRaycastingShape && raycasting)
return NULL;
btCollisionShape* collisionShape = raycasting ? shape->mRaycastingShape : shape->mCollisionShape;
collisionShape->setLocalScaling(btVector3(scale, scale, scale));
//create the real body
btRigidBody::btRigidBodyConstructionInfo CI =
btRigidBody::btRigidBodyConstructionInfo(0, 0, collisionShape);
RigidBody* body = new RigidBody(CI, name);
adjustRigidBody(body, position, rotation);
if (!raycasting)
{
assert (mCollisionObjectMap.find(name) == mCollisionObjectMap.end());
mCollisionObjectMap[name] = body;
mDynamicsWorld->addRigidBody(body,
CollisionType_World, CollisionType_Actor|CollisionType_HeightMap);
}
else
{
assert (mRaycastingObjectMap.find(name) == mRaycastingObjectMap.end());
mRaycastingObjectMap[name] = body;
mDynamicsWorld->addRigidBody(body,
CollisionType_Raycasting, CollisionType_Raycasting|CollisionType_Projectile);
}
return body;
}
void PhysicsEngine::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);
}
}
it = mRaycastingObjectMap.find(name);
if (it != mRaycastingObjectMap.end() )
{
RigidBody* body = it->second;
if(body != NULL)
{
mDynamicsWorld->removeRigidBody(body);
}
}
}
void PhysicsEngine::deleteRigidBody(const std::string &name)
{
RigidBodyContainer::iterator it = mCollisionObjectMap.find(name);
if (it != mCollisionObjectMap.end() )
{
RigidBody* body = it->second;
if(body != NULL)
{
delete body;
}
mCollisionObjectMap.erase(it);
}
it = mRaycastingObjectMap.find(name);
if (it != mRaycastingObjectMap.end() )
{
RigidBody* body = it->second;
if(body != NULL)
{
delete body;
}
mRaycastingObjectMap.erase(it);
}
}
RigidBody* PhysicsEngine::getRigidBody(const std::string &name, bool raycasting)
{
RigidBodyContainer* map = raycasting ? &mRaycastingObjectMap : &mCollisionObjectMap;
RigidBodyContainer::iterator it = map->find(name);
if (it != map->end() )
{
RigidBody* body = (*map)[name];
return body;
}
else
{
return NULL;
}
}
std::pair<std::string, float> PhysicsEngine::rayTest(const btVector3 &from,
const btVector3 &to, bool raycastingObjectOnly, bool ignoreHeightMap, Ogre::Vector3* normal)
{
std::string referenceId = "";
float d = -1;
btCollisionWorld::ClosestRayResultCallback resultCallback1(from, to);
resultCallback1.m_collisionFilterGroup = 0xff;
if(raycastingObjectOnly)
resultCallback1.m_collisionFilterMask = CollisionType_Raycasting|CollisionType_Actor;
else
resultCallback1.m_collisionFilterMask = CollisionType_World;
if(!ignoreHeightMap)
resultCallback1.m_collisionFilterMask = resultCallback1.m_collisionFilterMask | CollisionType_HeightMap;
mDynamicsWorld->rayTest(from, to, resultCallback1);
if (resultCallback1.hasHit())
{
referenceId = static_cast<const RigidBody&>(*resultCallback1.m_collisionObject).getReferenceId();
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>(referenceId, d);
}
}

@ -0,0 +1,253 @@
#ifndef CSV_WORLD_PHYSICSENGINE_H
#define CSV_WORLD_PHYSICSENGINE_H
//#include <vector>
#include <map>
#include <BulletDynamics/Dynamics/btRigidBody.h>
//#include "BulletCollision/CollisionDispatch/btGhostObject.h"
//#include <string>
//#include "BulletCollision/CollisionShapes/btScaledBvhTriangleMeshShape.h"
//#include <boost/shared_ptr.hpp>
#include <OgreSceneNode.h>
#include <openengine/bullet/BtOgreExtras.h> // needs Ogre::SceneNode defined
//#include <OgreVector3.h>
//#include <OgreQuaternion.h>
//class btRigidBody;
class btBroadphaseInterface;
class btDefaultCollisionConfiguration;
class btSequentialImpulseConstraintSolver;
class btCollisionDispatcher;
class btDiscreteDynamicsWorld;
class btHeightfieldTerrainShape;
//class btCollisionObject;
namespace BtOgre
{
class DebugDrawer;
}
namespace Ogre
{
class Vector3;
class SceneNode;
class SceneManager;
class Quaternion;
}
namespace OEngine
{
namespace Physic
{
class BulletShapeLoader;
}
}
namespace CSVWorld
{
// enum btIDebugDraw::DebugDrawModes
// {
// DBG_NoDebug=0,
// DBG_DrawWireframe = 1,
// DBG_DrawAabb=2,
// DBG_DrawFeaturesText=4,
// DBG_DrawContactPoints=8,
// DBG_NoDeactivation=16,
// DBG_NoHelpText = 32,
// DBG_DrawText=64,
// DBG_ProfileTimings = 128,
// DBG_EnableSatComparison = 256,
// DBG_DisableBulletLCP = 512,
// DBG_EnableCCD = 1024,
// DBG_DrawConstraints = (1 << 11),
// DBG_DrawConstraintLimits = (1 << 12),
// DBG_FastWireframe = (1<<13),
// DBG_DrawNormals = (1<<14),
// DBG_MAX_DEBUG_DRAW_MODE
// };
//
#if 0
class CSVDebugDrawer : public BtOgre::DebugDrawer
{
BtOgre::DebugDrawer *mDebugDrawer;
Ogre::SceneManager *mSceneMgr;
Ogre::SceneNode *mSceneNode;
int mDebugMode;
public:
CSVDebugDrawer(Ogre::SceneManager *sceneMgr, btDiscreteDynamicsWorld *dynamicsWorld);
~CSVDebugDrawer();
void setDebugMode(int mode);
bool toggleDebugRendering();
};
#endif
// 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
{
std::string mReferenceId;
public:
RigidBody(btRigidBody::btRigidBodyConstructionInfo &CI, const std::string &referenceId);
virtual ~RigidBody();
std::string getReferenceId() const { return mReferenceId; }
};
struct HeightField
{
btHeightfieldTerrainShape* mShape;
RigidBody* mBody;
};
/**
* The PhysicsEngine class contain everything which is needed for Physic.
* It's needed that Ogre Resources are set up before the PhysicsEngine is created.
* Note:deleting it WILL NOT delete the RigidBody!
* TODO:unload unused resources?
*/
class PhysicsEngine
{
//Bullet Stuff
btBroadphaseInterface *mBroadphase;
btDefaultCollisionConfiguration *mCollisionConfiguration;
btSequentialImpulseConstraintSolver *mSolver;
btCollisionDispatcher *mDispatcher;
btDiscreteDynamicsWorld *mDynamicsWorld;
//the NIF file loader.
OEngine::Physic::BulletShapeLoader *mShapeLoader;
typedef std::map<std::string, HeightField> HeightFieldContainer;
HeightFieldContainer mHeightFieldMap;
typedef std::map<std::string, RigidBody*> RigidBodyContainer;
RigidBodyContainer mCollisionObjectMap;
RigidBodyContainer mRaycastingObjectMap;
std::map<Ogre::SceneManager *, BtOgre::DebugDrawer *> mDebugDrawers;
std::map<Ogre::SceneManager *, Ogre::SceneNode *> mDebugSceneNodes;
#if 0
// from bullet
enum CollisionFilterGroups
{
DefaultFilter = 1,
StaticFilter = 2,
KinematicFilter = 4,
DebrisFilter = 8,
SensorTrigger = 16,
CharacterFilter = 32,
AllFilter = -1 //all bits sets: DefaultFilter | StaticFilter | KinematicFilter | DebrisFilter | SensorTrigger
};
#endif
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_Raycasting = 1<<3,
CollisionType_Projectile = 1<<4,
CollisionType_Water = 1<<5
};
public:
PhysicsEngine();
~PhysicsEngine();
// 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 &referenceId, float scale,
const Ogre::Vector3 &position, const Ogre::Quaternion &rotation,
bool raycasting = false, 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);
#if 0
// 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);
#endif
// 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 &referenceId);
// Delete a RigidBody, and remove it from RigidBodyMap.
void deleteRigidBody(const std::string &referenceId);
// Return a pointer to a given rigid body.
RigidBody* getRigidBody(const std::string &referenceId, bool raycasting=false);
void stepDebug(Ogre::SceneManager *sceneMgr);
int toggleDebugRendering(Ogre::SceneManager *sceneMgr);
void createDebugDraw(Ogre::SceneManager* sceneMgr);
void removeDebugDraw(Ogre::SceneManager *sceneMgr);
// 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 raycastingObjectOnly = true,
bool ignoreHeightMap = false, Ogre::Vector3* normal = NULL);
private:
PhysicsEngine(const PhysicsEngine&);
PhysicsEngine& operator=(const PhysicsEngine&);
// Create a debug rendering. It is called by setDebgRenderingMode if it's
// not created yet.
// Important Note: this will crash if the Render is not yet initialised!
void createDebugRendering();
// Set the debug rendering mode. 0 to turn it off.
// Important Note: this will crash if the Render is not yet initialised!
void setDebugRenderingMode(int mode);
#if 0
void getObjectAABB(const std::string &mesh,
float scale, btVector3 &min, btVector3 &max);
/**
* Return all objects hit by a ray.
*/
std::vector< std::pair<float, std::string> > rayTest2(const btVector3 &from, const btVector3 &to, int filterGroup=0xff);
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);
#endif
};
}
#endif // CSV_WORLD_PHYSICSENGINE_H
Loading…
Cancel
Save