Physics stub in preparation for rewrite

c++11
scrawl 9 years ago
parent 48ffeab191
commit c843cfc8e2

@ -455,10 +455,6 @@ if(WIN32)
include(CPack)
endif(WIN32)
# Libs
include_directories(libs)
add_subdirectory(libs/openengine)
# Extern
add_subdirectory (extern/osg-ffmpeg-videoplayer)
add_subdirectory (extern/oics)

@ -24,8 +24,6 @@
#include <components/files/configurationmanager.hpp>
#include <components/translation/translation.hpp>
#include <components/nifbullet/bulletnifloader.hpp>
#include <components/esm/loadcell.hpp>
#include "mwinput/inputmanagerimp.hpp"

@ -2,20 +2,8 @@
#include <stdexcept>
#include <OgreRoot.h>
#include <OgreRenderWindow.h>
#include <OgreSceneManager.h>
#include <OgreViewport.h>
#include <OgreCamera.h>
#include <OgreTextureManager.h>
#include <OgreSceneNode.h>
#include <osg/Group>
#include <openengine/bullet/trace.h>
#include <openengine/bullet/physic.hpp>
//#include <openengine/bullet/BulletShapeLoader.h>
#include <components/nifbullet/bulletnifloader.hpp>
#include <components/misc/resourcehelpers.hpp>
@ -33,20 +21,18 @@
#include "../mwrender/bulletdebugdraw.hpp"
//#include "../apps/openmw/mwrender/animation.hpp"
#include "../apps/openmw/mwbase/world.hpp"
#include "../apps/openmw/mwbase/environment.hpp"
#include "../mwbase/world.hpp"
#include "../mwbase/environment.hpp"
#include "ptr.hpp"
#include "class.hpp"
using namespace Ogre;
namespace
{
/*
void animateCollisionShapes (std::map<OEngine::Physic::RigidBody*, OEngine::Physic::AnimatedShapeInstance>& map, btDynamicsWorld* dynamicsWorld)
{
/*
for (std::map<OEngine::Physic::RigidBody*, OEngine::Physic::AnimatedShapeInstance>::iterator it = map.begin();
it != map.end(); ++it)
{
@ -87,41 +73,11 @@ void animateCollisionShapes (std::map<OEngine::Physic::RigidBody*, OEngine::Phys
// needed because we used btDynamicsWorld::setForceUpdateAllAabbs(false)
dynamicsWorld->updateSingleAabb(it->first);
}
*/
}
*/
}
namespace BtOgre
{
//Converts from and to Bullet and Ogre stuff. Pretty self-explanatory.
class Convert
{
public:
Convert() {};
~Convert() {};
static btQuaternion toBullet(const Ogre::Quaternion &q)
{
return btQuaternion(q.x, q.y, q.z, q.w);
}
static btVector3 toBullet(const Ogre::Vector3 &v)
{
return btVector3(v.x, v.y, v.z);
}
static Ogre::Quaternion toOgre(const btQuaternion &q)
{
return Ogre::Quaternion(q.w(), q.x(), q.y(), q.z());
}
static Ogre::Vector3 toOgre(const btVector3 &v)
{
return Ogre::Vector3(v.x(), v.y(), v.z());
}
};
}
namespace MWWorld
{
@ -188,6 +144,8 @@ namespace MWWorld
* +--+ +--------
* ==============================================
*/
return false;
#if 0
OEngine::Physic::ActorTracer tracer, stepper;
stepper.doTrace(colobj, position, position+Ogre::Vector3(0.0f,0.0f,sStepSizeUp), engine);
@ -243,6 +201,7 @@ namespace MWWorld
// moved between 0 and just under sStepSize distance but slope was too great,
// or moved full sStepSize distance (FIXME: is this a bug?)
#endif
return false;
}
@ -266,6 +225,8 @@ namespace MWWorld
const ESM::Position &refpos = ptr.getRefData().getPosition();
Ogre::Vector3 position(refpos.pos);
return position;
#if 0
OEngine::Physic::PhysicActor *physicActor = engine->getCharacter(ptr.getRefData().getHandle());
if (!physicActor)
return position;
@ -302,6 +263,7 @@ namespace MWWorld
return tracer.mEndPos;
}
#endif
}
static Ogre::Vector3 move(const MWWorld::Ptr &ptr, const Ogre::Vector3 &movement, float time,
@ -311,7 +273,8 @@ namespace MWWorld
{
const ESM::Position &refpos = ptr.getRefData().getPosition();
Ogre::Vector3 position(refpos.pos);
return position;
#if 0
// Early-out for totally static creatures
// (Not sure if gravity should still apply?)
if (!ptr.getClass().isMobile(ptr))
@ -526,21 +489,20 @@ namespace MWWorld
newPosition.z -= halfExtents.z; // remove what was added at the beginning
return newPosition;
#endif
}
};
PhysicsSystem::PhysicsSystem(osg::ref_ptr<osg::Group> parentNode) :
mEngine(0), mTimeAccum(0.0f), mWaterEnabled(false), mWaterHeight(0), mDebugDrawEnabled(false), mParentNode(parentNode)
mTimeAccum(0.0f), mWaterEnabled(false), mWaterHeight(0), mDebugDrawEnabled(false), mParentNode(parentNode)
{
mEngine = new OEngine::Physic::PhysicEngine;
}
PhysicsSystem::~PhysicsSystem()
{
if (mWaterCollisionObject.get())
mEngine->mDynamicsWorld->removeCollisionObject(mWaterCollisionObject.get());
delete mEngine;
//if (mWaterCollisionObject.get())
// mEngine->mDynamicsWorld->removeCollisionObject(mWaterCollisionObject.get());
}
bool PhysicsSystem::toggleDebugRendering()
@ -549,25 +511,22 @@ namespace MWWorld
if (mDebugDrawEnabled && !mDebugDrawer.get())
{
mDebugDrawer.reset(new MWRender::DebugDrawer(mParentNode, mEngine->mDynamicsWorld));
mEngine->mDynamicsWorld->setDebugDrawer(mDebugDrawer.get());
mDebugDrawer->setDebugMode(mDebugDrawEnabled);
//mDebugDrawer.reset(new MWRender::DebugDrawer(mParentNode, mEngine->mDynamicsWorld));
//mEngine->mDynamicsWorld->setDebugDrawer(mDebugDrawer.get());
//mDebugDrawer->setDebugMode(mDebugDrawEnabled);
}
else if (mDebugDrawer.get())
mDebugDrawer->setDebugMode(mDebugDrawEnabled);
return mDebugDrawEnabled;
}
OEngine::Physic::PhysicEngine* PhysicsSystem::getEngine()
{
return mEngine;
}
std::pair<std::string,Ogre::Vector3> PhysicsSystem::getHitContact(const std::string &name,
const Ogre::Vector3 &origin,
const Ogre::Quaternion &orient,
float queryDistance)
{
return std::make_pair(std::string(), Ogre::Vector3());
/*
const MWWorld::Store<ESM::GameSetting> &store = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>();
btConeShape shape(Ogre::Degree(store.find("fCombatAngleXY")->getFloat()/2.0f).valueRadians(),
@ -589,22 +548,28 @@ namespace MWWorld
if(!result.first)
return std::make_pair(std::string(), Ogre::Vector3(&result.second[0]));
return std::make_pair(result.first->mName, Ogre::Vector3(&result.second[0]));
*/
}
bool PhysicsSystem::castRay(const Vector3& from, const Vector3& to, bool ignoreHeightMap)
bool PhysicsSystem::castRay(const Ogre::Vector3& from, const Ogre::Vector3& to, bool ignoreHeightMap)
{
return false;
/*
btVector3 _from, _to;
_from = btVector3(from.x, from.y, from.z);
_to = btVector3(to.x, to.y, to.z);
std::pair<std::string, float> result = mEngine->rayTest(_from, _to,ignoreHeightMap);
return !(result.first == "");
*/
}
std::pair<bool, Ogre::Vector3>
PhysicsSystem::castRay(const Ogre::Vector3 &orig, const Ogre::Vector3 &dir, float len)
{
return std::make_pair(false, Ogre::Vector3());
/*
Ogre::Ray ray = Ogre::Ray(orig, dir);
Ogre::Vector3 to = ray.getPoint(len);
@ -616,125 +581,42 @@ namespace MWWorld
return std::make_pair(false, Ogre::Vector3());
}
return std::make_pair(true, ray.getPoint(len * test.second));
*/
}
std::vector<std::string> PhysicsSystem::getCollisions(const Ptr &ptr, int collisionGroup, int collisionMask)
{
return mEngine->getCollisions(ptr.getRefData().getBaseNodeOld()->getName(), collisionGroup, collisionMask);
return std::vector<std::string>();//mEngine->getCollisions(ptr.getRefData().getBaseNodeOld()->getName(), collisionGroup, collisionMask);
}
Ogre::Vector3 PhysicsSystem::traceDown(const MWWorld::Ptr &ptr, float maxHeight)
{
return MovementSolver::traceDown(ptr, mEngine, maxHeight);
return Ogre::Vector3();//MovementSolver::traceDown(ptr, mEngine, maxHeight);
}
void PhysicsSystem::addHeightField (float* heights,
int x, int y, float yoffset,
float triSize, float sqrtVerts)
{
mEngine->addHeightField(heights, x, y, yoffset, triSize, sqrtVerts);
}
void PhysicsSystem::removeHeightField (int x, int y)
{
mEngine->removeHeightField(x, y);
}
void PhysicsSystem::addObject (const Ptr& ptr, const std::string& mesh, bool placeable)
{
/*
Ogre::SceneNode* node = ptr.getRefData().getBaseNodeOld();
handleToMesh[node->getName()] = mesh;
mEngine->createAndAdjustRigidBody(
mesh, node->getName(), ptr.getCellRef().getScale(), node->getPosition(), node->getOrientation(), 0, 0, false, placeable);
mEngine->createAndAdjustRigidBody(
mesh, node->getName(), ptr.getCellRef().getScale(), node->getPosition(), node->getOrientation(), 0, 0, true, placeable);
*/
}
void PhysicsSystem::addActor (const Ptr& ptr, const std::string& mesh)
{
/*
Ogre::SceneNode* node = ptr.getRefData().getBaseNodeOld();
//TODO:optimize this. Searching the std::map isn't very efficient i think.
mEngine->addCharacter(node->getName(), mesh, node->getPosition(), node->getScale().x, node->getOrientation());
*/
}
void PhysicsSystem::removeObject (const std::string& handle)
{
mEngine->removeCharacter(handle);
mEngine->removeRigidBody(handle);
mEngine->deleteRigidBody(handle);
}
void PhysicsSystem::moveObject (const Ptr& ptr)
{
Ogre::SceneNode *node = ptr.getRefData().getBaseNodeOld();
const std::string &handle = node->getName();
const Ogre::Vector3 &position = node->getPosition();
if(OEngine::Physic::RigidBody *body = mEngine->getRigidBody(handle))
{
body->getWorldTransform().setOrigin(btVector3(position.x,position.y,position.z));
mEngine->mDynamicsWorld->updateSingleAabb(body);
}
// Actors update their AABBs every frame (DISABLE_DEACTIVATION), so no need to do it manually
if(OEngine::Physic::PhysicActor *physact = mEngine->getCharacter(handle))
physact->setPosition(position);
}
void PhysicsSystem::rotateObject (const Ptr& ptr)
{
Ogre::SceneNode* node = ptr.getRefData().getBaseNodeOld();
const std::string &handle = node->getName();
const Ogre::Quaternion &rotation = node->getOrientation();
// TODO: map to MWWorld::Ptr for faster access
if (OEngine::Physic::PhysicActor* act = mEngine->getCharacter(handle))
{
act->setRotation(rotation);
}
if (OEngine::Physic::RigidBody* body = mEngine->getRigidBody(handle))
{
if(dynamic_cast<btBoxShape*>(body->getCollisionShape()) == NULL)
body->getWorldTransform().setRotation(btQuaternion(rotation.x, rotation.y, rotation.z, rotation.w));
else
mEngine->boxAdjustExternal(handleToMesh[handle], body, node->getScale().x, node->getPosition(), rotation);
mEngine->mDynamicsWorld->updateSingleAabb(body);
}
}
void PhysicsSystem::scaleObject (const Ptr& ptr)
void PhysicsSystem::addActor (const Ptr& ptr, const std::string& mesh)
{
Ogre::SceneNode* node = ptr.getRefData().getBaseNodeOld();
const std::string &handle = node->getName();
if(handleToMesh.find(handle) != handleToMesh.end())
{
std::string model = ptr.getClass().getModel(ptr);
//model = Misc::ResourceHelpers::correctActorModelPath(model); // FIXME: scaling shouldn't require model
bool placeable = false;
if (OEngine::Physic::RigidBody* body = mEngine->getRigidBody(handle))
placeable = body->mPlaceable;
removeObject(handle);
addObject(ptr, model, placeable);
}
if (OEngine::Physic::PhysicActor* act = mEngine->getCharacter(handle))
{
float scale = ptr.getCellRef().getScale();
osg::Vec3f scaleVec (scale,scale,scale);
if (!ptr.getClass().isNpc())
// NOTE: Ignoring Npc::adjustScale (race height) on purpose. This is a bug in MW and must be replicated for compatibility reasons
ptr.getClass().adjustScale(ptr, scaleVec);
act->setScale(scaleVec.x());
}
}
bool PhysicsSystem::toggleCollisionMode()
{
/*
for(std::map<std::string,OEngine::Physic::PhysicActor*>::iterator it = mEngine->mActorMap.begin(); it != mEngine->mActorMap.end();++it)
{
if (it->first=="player")
@ -756,6 +638,8 @@ namespace MWWorld
}
throw std::logic_error ("can't find player");
*/
return false;
}
void PhysicsSystem::queueObjectMovement(const Ptr &ptr, const Ogre::Vector3 &movement)
@ -791,6 +675,8 @@ namespace MWWorld
mCollisions.clear();
mStandingCollisions.clear();
/*
const MWBase::World *world = MWBase::Environment::get().getWorld();
PtrVelocityList::iterator iter = mMovementQueue.begin();
for(;iter != mMovementQueue.end();++iter)
@ -831,6 +717,8 @@ namespace MWWorld
mMovementResults.push_back(std::make_pair(iter->first, newpos));
}
*/
mTimeAccum = 0.0f;
}
mMovementQueue.clear();
@ -840,9 +728,9 @@ namespace MWWorld
void PhysicsSystem::stepSimulation(float dt)
{
animateCollisionShapes(mEngine->mAnimatedShapes, mEngine->mDynamicsWorld);
//animateCollisionShapes(mEngine->mAnimatedShapes, mEngine->mDynamicsWorld);
mEngine->stepSimulation(dt);
//mEngine->stepSimulation(dt);
if (mDebugDrawer.get())
mDebugDrawer->step();
@ -932,7 +820,7 @@ namespace MWWorld
{
if (mWaterCollisionObject.get())
{
mEngine->mDynamicsWorld->removeCollisionObject(mWaterCollisionObject.get());
//mEngine->mDynamicsWorld->removeCollisionObject(mWaterCollisionObject.get());
}
if (!mWaterEnabled)
@ -941,7 +829,7 @@ namespace MWWorld
mWaterCollisionObject.reset(new btCollisionObject());
mWaterCollisionShape.reset(new btStaticPlaneShape(btVector3(0,0,1), mWaterHeight));
mWaterCollisionObject->setCollisionShape(mWaterCollisionShape.get());
mEngine->mDynamicsWorld->addCollisionObject(mWaterCollisionObject.get(), OEngine::Physic::CollisionType_Water,
OEngine::Physic::CollisionType_Actor);
//mEngine->mDynamicsWorld->addCollisionObject(mWaterCollisionObject.get(), OEngine::Physic::CollisionType_Water,
// OEngine::Physic::CollisionType_Actor);
}
}

@ -55,15 +55,6 @@ namespace MWWorld
void removeHeightField (int x, int y);
// have to keep this as handle for now as unloadcell only knows scenenode names
void removeObject (const std::string& handle);
void moveObject (const MWWorld::Ptr& ptr);
void rotateObject (const MWWorld::Ptr& ptr);
void scaleObject (const MWWorld::Ptr& ptr);
bool toggleCollisionMode();
void stepSimulation(float dt);
@ -82,8 +73,6 @@ namespace MWWorld
std::pair<bool, Ogre::Vector3>
castRay(const Ogre::Vector3 &orig, const Ogre::Vector3 &dir, float len);
OEngine::Physic::PhysicEngine* getEngine();
/// Queues velocity movement for a Ptr. If a Ptr is already queued, its velocity will
/// be overwritten. Valid until the next call to applyQueuedMovement.
void queueObjectMovement(const Ptr &ptr, const Ogre::Vector3 &velocity);
@ -117,7 +106,6 @@ namespace MWWorld
bool mDebugDrawEnabled;
OEngine::Physic::PhysicEngine* mEngine;
std::map<std::string, std::string> handleToMesh;
// Tracks all movement collisions happening during a single frame. <actor handle, collided handle>

@ -13,9 +13,6 @@
#include <osg/Group>
#include <libs/openengine/bullet/trace.h>
#include <libs/openengine/bullet/physic.hpp>
#include <components/misc/rng.hpp>
#include <components/files/collections.hpp>
@ -59,8 +56,6 @@
#include "contentloader.hpp"
#include "esmloader.hpp"
using namespace Ogre;
namespace
{
@ -1402,7 +1397,7 @@ namespace MWWorld
cellY = static_cast<int>(std::floor(y / cellSize));
}
void World::queueMovement(const Ptr &ptr, const Vector3 &velocity)
void World::queueMovement(const Ptr &ptr, const Ogre::Vector3 &velocity)
{
//mPhysics->queueObjectMovement(ptr, velocity);
}
@ -1630,7 +1625,9 @@ namespace MWWorld
void World::updateSoundListener()
{
/*
Ogre::Vector3 playerPos = mPlayer->getPlayer().getRefData().getBaseNodeOld()->getPosition();
const OEngine::Physic::PhysicActor *actor = mPhysEngine->getCharacter(getPlayerPtr().getRefData().getHandle());
if(actor) playerPos.z += 1.85f * actor->getHalfExtents().z;
Ogre::Quaternion playerOrient = Ogre::Quaternion(Ogre::Radian(getPlayerPtr().getRefData().getPosition().rot[2]), Ogre::Vector3::NEGATIVE_UNIT_Z) *
@ -1638,6 +1635,7 @@ namespace MWWorld
Ogre::Quaternion(Ogre::Radian(getPlayerPtr().getRefData().getPosition().rot[1]), Ogre::Vector3::NEGATIVE_UNIT_Y);
MWBase::Environment::get().getSoundManager()->setListenerPosDir(playerPos, playerOrient.yAxis(),
playerOrient.zAxis());
*/
}
void World::updateWindowManager ()
@ -1654,7 +1652,7 @@ namespace MWWorld
Ogre::AxisAlignedBox bounds = node->_getWorldAABB();
if (bounds.isFinite())
{
Vector4 screenCoords;// = mRendering->boundingBoxToScreen(bounds);
Ogre::Vector4 screenCoords;// = mRendering->boundingBoxToScreen(bounds);
MWBase::Environment::get().getWindowManager()->setFocusObjectScreenCoords(
screenCoords[0], screenCoords[1], screenCoords[2], screenCoords[3]);
}
@ -1746,11 +1744,11 @@ namespace MWWorld
MWWorld::CellRefList<ESM::Static>& statics = cell->get<ESM::Static>();
MWWorld::LiveCellRef<ESM::Static>* ref = statics.find("northmarker");
if (!ref)
return Vector2(0, 1);
return Ogre::Vector2(0, 1);
Ogre::Quaternion orient (Ogre::Radian(-ref->mData.getPosition().rot[2]), Ogre::Vector3::UNIT_Z);
Vector3 dir = orient * Ogre::Vector3(0,1,0);
Vector2 d = Vector2(dir.x, dir.y);
Ogre::Vector3 dir = orient * Ogre::Vector3(0,1,0);
Ogre::Vector2 d = Ogre::Vector2(dir.x, dir.y);
return d;
}
@ -2002,9 +2000,9 @@ namespace MWWorld
&& isLevitationEnabled())
return true;
const OEngine::Physic::PhysicActor *actor = 0;//mPhysEngine->getCharacter(ptr.getRefData().getHandle());
if(!actor || !actor->getCollisionMode())
return true;
//const OEngine::Physic::PhysicActor *actor = 0;//mPhysEngine->getCharacter(ptr.getRefData().getHandle());
//if(!actor || !actor->getCollisionMode())
// return true;
return false;
}
@ -2042,10 +2040,10 @@ namespace MWWorld
const float *fpos = object.getRefData().getPosition().pos;
Ogre::Vector3 pos(fpos[0], fpos[1], fpos[2]);
const OEngine::Physic::PhysicActor *actor = 0;//mPhysEngine->getCharacter(object.getRefData().getHandle());
if (actor)
//const OEngine::Physic::PhysicActor *actor = 0;//mPhysEngine->getCharacter(object.getRefData().getHandle());
//if (actor)
{
pos.z += heightRatio*2*actor->getHalfExtents().z;
// pos.z += heightRatio*2*actor->getHalfExtents().z;
}
return isUnderwater(object.getCell(), pos);
@ -2071,6 +2069,8 @@ namespace MWWorld
// TODO: There might be better places to update PhysicActor::mOnGround.
bool World::isOnGround(const MWWorld::Ptr &ptr) const
{
return true;
/*
//RefData &refdata = ptr.getRefData();
OEngine::Physic::PhysicActor *physactor = 0;//mPhysEngine->getCharacter(refdata.getHandle());
@ -2096,6 +2096,7 @@ namespace MWWorld
else
return false;
}
*/
}
bool World::vanityRotateCamera(float * rot)
@ -2371,6 +2372,7 @@ namespace MWWorld
if (!targetActor.getRefData().getBaseNodeOld() || !targetActor.getRefData().getBaseNodeOld())
return false; // not in active cell
/*
OEngine::Physic::PhysicActor* actor1 = mPhysEngine->getCharacter(actor.getRefData().getHandle());
OEngine::Physic::PhysicActor* actor2 = mPhysEngine->getCharacter(targetActor.getRefData().getHandle());
@ -2387,12 +2389,15 @@ namespace MWWorld
std::pair<std::string, float> result = mPhysEngine->rayTest(from, to,false);
if(result.first == "") return true;
*/
return false;
}
float World::getDistToNearestRayHit(const Ogre::Vector3& from, const Ogre::Vector3& dir, float maxDist)
{
return 0;
/*
btVector3 btFrom(from.x, from.y, from.z);
btVector3 btTo = btVector3(dir.x, dir.y, dir.z);
btTo.normalize();
@ -2402,13 +2407,16 @@ namespace MWWorld
if(result.second == -1) return maxDist;
else return result.second*(btTo-btFrom).length();
*/
}
void World::enableActorCollision(const MWWorld::Ptr& actor, bool enable)
{
/*
OEngine::Physic::PhysicActor *physicActor = 0;//mPhysEngine->getCharacter(actor.getRefData().getHandle());
if (physicActor)
physicActor->enableCollisionBody(enable);
*/
}
bool World::findInteriorPosition(const std::string &name, ESM::Position &pos)
@ -3235,7 +3243,7 @@ namespace MWWorld
mRendering->spawnEffect(model, textureOverride, worldPos);
}
void World::explodeSpell(const Vector3 &origin, const ESM::EffectList &effects, const Ptr &caster, ESM::RangeType rangeType,
void World::explodeSpell(const Ogre::Vector3 &origin, const ESM::EffectList &effects, const Ptr &caster, ESM::RangeType rangeType,
const std::string& id, const std::string& sourceName)
{
std::map<MWWorld::Ptr, std::vector<ESM::ENAMstruct> > toApply;
@ -3350,9 +3358,12 @@ namespace MWWorld
bool World::isWalkingOnWater(const Ptr &actor)
{
return false;
/*
OEngine::Physic::PhysicActor* physicActor = mPhysEngine->getCharacter(actor.getRefData().getHandle());
if (physicActor && physicActor->isWalkingOnWater())
return true;
return false;
*/
}
}

@ -52,9 +52,9 @@ add_component_dir (nifosg
nifloader controller particle userdata
)
add_component_dir (nifbullet
bulletnifloader
)
#add_component_dir (nifbullet
# bulletnifloader
# )
add_component_dir (to_utf8
to_utf8

@ -1,5 +1,5 @@
#ifndef OPENENGINE_MYGUI_LOGLISTENER_H
#define OPENENGINE_MYGUI_LOGLISTENER_H
#ifndef OPENMW_COMPONENTS_MYGUIPLATFORM_LOGLISTENER_H
#define OPENMW_COMPONENTS_MYGUIPLATFORM_LOGLISTENER_H
#include <string>
#include <boost/filesystem/fstream.hpp>

@ -26,11 +26,11 @@
#include <cassert>
#include <string>
#include <set>
#include <BulletCollision/CollisionShapes/btBvhTriangleMeshShape.h>
#include <BulletCollision/CollisionShapes/btConvexTriangleMeshShape.h>
#include <BulletCollision/CollisionShapes/btCompoundShape.h>
#include <btBulletDynamicsCommon.h>
#include <openengine/bullet/BulletShapeLoader.h>
#include <osg/Matrixf>
@ -70,8 +70,7 @@ class ManualBulletShapeLoader
{
public:
ManualBulletShapeLoader(bool showMarkers=false)
: mShape(NULL)
, mCompoundShape(NULL)
: mCompoundShape(NULL)
, mStaticMesh(NULL)
, mBoundingBox(NULL)
, mShowMarkers(showMarkers)
@ -91,11 +90,6 @@ public:
abort();
}
/**
*This function should not be called manualy. Use load instead. (this is called by the BulletShapeManager when you use load).
*/
void loadResource(Ogre::Resource *resource);
private:
btVector3 getbtVector(Ogre::Vector3 const &v);
@ -116,7 +110,7 @@ private:
std::string mResourceName;
OEngine::Physic::BulletShape* mShape;//current shape
//OEngine::Physic::BulletShape* mShape;//current shape
btCompoundShape* mCompoundShape;

@ -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…
Cancel
Save