forked from teamnwah/openmw-tes3coop
Readded collision objects and movement physics
This commit is contained in:
parent
54c1f19c18
commit
47758c11cd
38 changed files with 1238 additions and 473 deletions
|
@ -151,7 +151,7 @@ if(WIN32)
|
||||||
set(QT_USE_QTMAIN TRUE)
|
set(QT_USE_QTMAIN TRUE)
|
||||||
endif(WIN32)
|
endif(WIN32)
|
||||||
|
|
||||||
set(BOOST_COMPONENTS system filesystem program_options thread wave)
|
set(BOOST_COMPONENTS system filesystem program_options thread)
|
||||||
if(WIN32)
|
if(WIN32)
|
||||||
set(BOOST_COMPONENTS ${BOOST_COMPONENTS} locale)
|
set(BOOST_COMPONENTS ${BOOST_COMPONENTS} locale)
|
||||||
endif(WIN32)
|
endif(WIN32)
|
||||||
|
@ -202,7 +202,6 @@ target_link_libraries(openmw-cs
|
||||||
${OGRE_LIBRARIES}
|
${OGRE_LIBRARIES}
|
||||||
${OPENSCENEGRAPH_LIBRARIES}
|
${OPENSCENEGRAPH_LIBRARIES}
|
||||||
${Boost_LIBRARIES}
|
${Boost_LIBRARIES}
|
||||||
${BULLET_LIBRARIES}
|
|
||||||
${QT_LIBRARIES}
|
${QT_LIBRARIES}
|
||||||
components
|
components
|
||||||
)
|
)
|
||||||
|
|
|
@ -74,7 +74,7 @@ add_openmw_dir (mwworld
|
||||||
)
|
)
|
||||||
|
|
||||||
add_openmw_dir (mwphysics
|
add_openmw_dir (mwphysics
|
||||||
physicssystem
|
physicssystem trace collisiontype actor convert
|
||||||
)
|
)
|
||||||
|
|
||||||
add_openmw_dir (mwclass
|
add_openmw_dir (mwclass
|
||||||
|
@ -101,9 +101,9 @@ add_openmw_dir (mwbase
|
||||||
|
|
||||||
# Main executable
|
# Main executable
|
||||||
if (ANDROID)
|
if (ANDROID)
|
||||||
set(BOOST_COMPONENTS system filesystem program_options thread wave atomic)
|
set(BOOST_COMPONENTS system filesystem program_options thread atomic)
|
||||||
else ()
|
else ()
|
||||||
set(BOOST_COMPONENTS system filesystem program_options thread wave)
|
set(BOOST_COMPONENTS system filesystem program_options thread)
|
||||||
endif ()
|
endif ()
|
||||||
|
|
||||||
if(WIN32)
|
if(WIN32)
|
||||||
|
|
|
@ -302,7 +302,7 @@ namespace MWBase
|
||||||
virtual void positionToIndex (float x, float y, int &cellX, int &cellY) const = 0;
|
virtual void positionToIndex (float x, float y, int &cellX, int &cellY) const = 0;
|
||||||
///< Convert position to cell numbers
|
///< Convert position to cell numbers
|
||||||
|
|
||||||
virtual void queueMovement(const MWWorld::Ptr &ptr, const Ogre::Vector3 &velocity) = 0;
|
virtual void queueMovement(const MWWorld::Ptr &ptr, const osg::Vec3f &velocity) = 0;
|
||||||
///< Queues movement for \a ptr (in local space), to be applied in the next call to
|
///< Queues movement for \a ptr (in local space), to be applied in the next call to
|
||||||
/// doPhysics.
|
/// doPhysics.
|
||||||
|
|
||||||
|
@ -555,7 +555,7 @@ namespace MWBase
|
||||||
virtual bool isInStorm() const = 0;
|
virtual bool isInStorm() const = 0;
|
||||||
|
|
||||||
/// @see MWWorld::WeatherManager::getStormDirection
|
/// @see MWWorld::WeatherManager::getStormDirection
|
||||||
virtual Ogre::Vector3 getStormDirection() const = 0;
|
virtual osg::Vec3f getStormDirection() const = 0;
|
||||||
|
|
||||||
/// Resets all actors in the current active cells to their original location within that cell.
|
/// Resets all actors in the current active cells to their original location within that cell.
|
||||||
virtual void resetActors() = 0;
|
virtual void resetActors() = 0;
|
||||||
|
|
|
@ -35,8 +35,7 @@ namespace MWClass
|
||||||
|
|
||||||
void Apparatus::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const
|
void Apparatus::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const
|
||||||
{
|
{
|
||||||
if(!model.empty())
|
// TODO: add option somewhere to enable collision for placeable objects
|
||||||
physics.addObject(ptr, model, true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string Apparatus::getModel(const MWWorld::Ptr &ptr) const
|
std::string Apparatus::getModel(const MWWorld::Ptr &ptr) const
|
||||||
|
|
|
@ -40,8 +40,7 @@ namespace MWClass
|
||||||
|
|
||||||
void Armor::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const
|
void Armor::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const
|
||||||
{
|
{
|
||||||
if(!model.empty())
|
// TODO: add option somewhere to enable collision for placeable objects
|
||||||
physics.addObject(ptr, model, true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string Armor::getModel(const MWWorld::Ptr &ptr) const
|
std::string Armor::getModel(const MWWorld::Ptr &ptr) const
|
||||||
|
|
|
@ -37,8 +37,7 @@ namespace MWClass
|
||||||
|
|
||||||
void Book::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const
|
void Book::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const
|
||||||
{
|
{
|
||||||
if(!model.empty())
|
// TODO: add option somewhere to enable collision for placeable objects
|
||||||
physics.addObject(ptr, model, true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string Book::getModel(const MWWorld::Ptr &ptr) const
|
std::string Book::getModel(const MWWorld::Ptr &ptr) const
|
||||||
|
|
|
@ -37,8 +37,7 @@ namespace MWClass
|
||||||
|
|
||||||
void Clothing::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const
|
void Clothing::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const
|
||||||
{
|
{
|
||||||
if(!model.empty())
|
// TODO: add option somewhere to enable collision for placeable objects
|
||||||
physics.addObject(ptr, model, true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string Clothing::getModel(const MWWorld::Ptr &ptr) const
|
std::string Clothing::getModel(const MWWorld::Ptr &ptr) const
|
||||||
|
|
|
@ -41,8 +41,7 @@ namespace MWClass
|
||||||
|
|
||||||
void Ingredient::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const
|
void Ingredient::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const
|
||||||
{
|
{
|
||||||
if(!model.empty())
|
// TODO: add option somewhere to enable collision for placeable objects
|
||||||
physics.addObject(ptr, model, true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string Ingredient::getModel(const MWWorld::Ptr &ptr) const
|
std::string Ingredient::getModel(const MWWorld::Ptr &ptr) const
|
||||||
|
|
|
@ -47,8 +47,9 @@ namespace MWClass
|
||||||
ptr.get<ESM::Light>();
|
ptr.get<ESM::Light>();
|
||||||
assert (ref->mBase != NULL);
|
assert (ref->mBase != NULL);
|
||||||
|
|
||||||
if(!model.empty())
|
// TODO: add option somewhere to enable collision for placeable objects
|
||||||
physics.addObject(ptr, model, (ref->mBase->mData.mFlags & ESM::Light::Carry) != 0);
|
if ((ref->mBase->mData.mFlags & ESM::Light::Carry) == 0)
|
||||||
|
physics.addObject(ptr, model);
|
||||||
|
|
||||||
if (!ref->mBase->mSound.empty() && !(ref->mBase->mData.mFlags & ESM::Light::OffDefault))
|
if (!ref->mBase->mSound.empty() && !(ref->mBase->mData.mFlags & ESM::Light::OffDefault))
|
||||||
MWBase::Environment::get().getSoundManager()->playSound3D(ptr, ref->mBase->mSound, 1.0, 1.0,
|
MWBase::Environment::get().getSoundManager()->playSound3D(ptr, ref->mBase->mSound, 1.0, 1.0,
|
||||||
|
|
|
@ -36,8 +36,7 @@ namespace MWClass
|
||||||
|
|
||||||
void Lockpick::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const
|
void Lockpick::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const
|
||||||
{
|
{
|
||||||
if(!model.empty())
|
// TODO: add option somewhere to enable collision for placeable objects
|
||||||
physics.addObject(ptr, model, true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string Lockpick::getModel(const MWWorld::Ptr &ptr) const
|
std::string Lockpick::getModel(const MWWorld::Ptr &ptr) const
|
||||||
|
|
|
@ -53,8 +53,7 @@ namespace MWClass
|
||||||
|
|
||||||
void Miscellaneous::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const
|
void Miscellaneous::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const
|
||||||
{
|
{
|
||||||
if(!model.empty())
|
// TODO: add option somewhere to enable collision for placeable objects
|
||||||
physics.addObject(ptr, model, true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string Miscellaneous::getModel(const MWWorld::Ptr &ptr) const
|
std::string Miscellaneous::getModel(const MWWorld::Ptr &ptr) const
|
||||||
|
|
|
@ -39,8 +39,7 @@ namespace MWClass
|
||||||
|
|
||||||
void Potion::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const
|
void Potion::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const
|
||||||
{
|
{
|
||||||
if(!model.empty())
|
// TODO: add option somewhere to enable collision for placeable objects
|
||||||
physics.addObject(ptr, model, true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string Potion::getModel(const MWWorld::Ptr &ptr) const
|
std::string Potion::getModel(const MWWorld::Ptr &ptr) const
|
||||||
|
|
|
@ -36,8 +36,7 @@ namespace MWClass
|
||||||
|
|
||||||
void Probe::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const
|
void Probe::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const
|
||||||
{
|
{
|
||||||
if(!model.empty())
|
// TODO: add option somewhere to enable collision for placeable objects
|
||||||
physics.addObject(ptr, model, true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string Probe::getModel(const MWWorld::Ptr &ptr) const
|
std::string Probe::getModel(const MWWorld::Ptr &ptr) const
|
||||||
|
|
|
@ -35,8 +35,7 @@ namespace MWClass
|
||||||
|
|
||||||
void Repair::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const
|
void Repair::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const
|
||||||
{
|
{
|
||||||
if(!model.empty())
|
// TODO: add option somewhere to enable collision for placeable objects
|
||||||
physics.addObject(ptr, model, true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string Repair::getModel(const MWWorld::Ptr &ptr) const
|
std::string Repair::getModel(const MWWorld::Ptr &ptr) const
|
||||||
|
|
|
@ -39,8 +39,7 @@ namespace MWClass
|
||||||
|
|
||||||
void Weapon::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const
|
void Weapon::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const
|
||||||
{
|
{
|
||||||
if(!model.empty())
|
// TODO: add option somewhere to enable collision for placeable objects
|
||||||
physics.addObject(ptr, model, true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string Weapon::getModel(const MWWorld::Ptr &ptr) const
|
std::string Weapon::getModel(const MWWorld::Ptr &ptr) const
|
||||||
|
|
|
@ -1346,7 +1346,7 @@ void CharacterController::update(float duration)
|
||||||
{
|
{
|
||||||
MWBase::World *world = MWBase::Environment::get().getWorld();
|
MWBase::World *world = MWBase::Environment::get().getWorld();
|
||||||
const MWWorld::Class &cls = mPtr.getClass();
|
const MWWorld::Class &cls = mPtr.getClass();
|
||||||
Ogre::Vector3 movement(0.0f);
|
osg::Vec3f movement(0.f, 0.f, 0.f);
|
||||||
|
|
||||||
updateMagicEffects();
|
updateMagicEffects();
|
||||||
|
|
||||||
|
@ -1403,23 +1403,23 @@ void CharacterController::update(float duration)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ogre::Vector3 vec(cls.getMovementSettings(mPtr).mPosition);
|
osg::Vec3f vec(cls.getMovementSettings(mPtr).asVec3());
|
||||||
vec.normalise();
|
vec.normalize();
|
||||||
|
|
||||||
if(mHitState != CharState_None && mJumpState == JumpState_None)
|
if(mHitState != CharState_None && mJumpState == JumpState_None)
|
||||||
vec = Ogre::Vector3(0.0f);
|
vec = osg::Vec3f(0.f, 0.f, 0.f);
|
||||||
Ogre::Vector3 rot = cls.getRotationVector(mPtr);
|
Ogre::Vector3 rot = cls.getRotationVector(mPtr);
|
||||||
|
|
||||||
mMovementSpeed = cls.getSpeed(mPtr);
|
mMovementSpeed = cls.getSpeed(mPtr);
|
||||||
|
|
||||||
vec.x *= mMovementSpeed;
|
vec.x() *= mMovementSpeed;
|
||||||
vec.y *= mMovementSpeed;
|
vec.y() *= mMovementSpeed;
|
||||||
|
|
||||||
CharacterState movestate = CharState_None;
|
CharacterState movestate = CharState_None;
|
||||||
CharacterState idlestate = CharState_SpecialIdle;
|
CharacterState idlestate = CharState_SpecialIdle;
|
||||||
bool forcestateupdate = false;
|
bool forcestateupdate = false;
|
||||||
|
|
||||||
mHasMovedInXY = std::abs(vec[0])+std::abs(vec[1]) > 0.0f;
|
mHasMovedInXY = std::abs(vec.x())+std::abs(vec.y()) > 0.0f;
|
||||||
isrunning = isrunning && mHasMovedInXY;
|
isrunning = isrunning && mHasMovedInXY;
|
||||||
|
|
||||||
|
|
||||||
|
@ -1482,7 +1482,7 @@ void CharacterController::update(float duration)
|
||||||
cls.getCreatureStats(mPtr).setFatigue(fatigue);
|
cls.getCreatureStats(mPtr).setFatigue(fatigue);
|
||||||
|
|
||||||
if(sneak || inwater || flying)
|
if(sneak || inwater || flying)
|
||||||
vec.z = 0.0f;
|
vec.z() = 0.0f;
|
||||||
|
|
||||||
if (inwater || flying)
|
if (inwater || flying)
|
||||||
cls.getCreatureStats(mPtr).land();
|
cls.getCreatureStats(mPtr).land();
|
||||||
|
@ -1505,22 +1505,23 @@ void CharacterController::update(float duration)
|
||||||
static const float fJumpMoveMult = gmst.find("fJumpMoveMult")->getFloat();
|
static const float fJumpMoveMult = gmst.find("fJumpMoveMult")->getFloat();
|
||||||
float factor = fJumpMoveBase + fJumpMoveMult * mPtr.getClass().getSkill(mPtr, ESM::Skill::Acrobatics)/100.f;
|
float factor = fJumpMoveBase + fJumpMoveMult * mPtr.getClass().getSkill(mPtr, ESM::Skill::Acrobatics)/100.f;
|
||||||
factor = std::min(1.f, factor);
|
factor = std::min(1.f, factor);
|
||||||
vec.x *= factor;
|
vec.x() *= factor;
|
||||||
vec.y *= factor;
|
vec.y() *= factor;
|
||||||
vec.z = 0.0f;
|
vec.z() = 0.0f;
|
||||||
}
|
}
|
||||||
else if(vec.z > 0.0f && mJumpState == JumpState_None)
|
else if(vec.z() > 0.0f && mJumpState == JumpState_None)
|
||||||
{
|
{
|
||||||
// Started a jump.
|
// Started a jump.
|
||||||
float z = cls.getJump(mPtr);
|
float z = cls.getJump(mPtr);
|
||||||
if (z > 0)
|
if (z > 0)
|
||||||
{
|
{
|
||||||
if(vec.x == 0 && vec.y == 0)
|
if(vec.x() == 0 && vec.y() == 0)
|
||||||
vec = Ogre::Vector3(0.0f, 0.0f, z);
|
vec = osg::Vec3f(0.0f, 0.0f, z);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Ogre::Vector3 lat = Ogre::Vector3(vec.x, vec.y, 0.0f).normalisedCopy();
|
osg::Vec3f lat (vec.x(), vec.y(), 0.0f);
|
||||||
vec = Ogre::Vector3(lat.x, lat.y, 1.0f) * z * 0.707f;
|
lat.normalize();
|
||||||
|
vec = osg::Vec3f(lat.x(), lat.y(), 1.0f) * z * 0.707f;
|
||||||
}
|
}
|
||||||
|
|
||||||
// advance acrobatics
|
// advance acrobatics
|
||||||
|
@ -1544,7 +1545,7 @@ void CharacterController::update(float duration)
|
||||||
{
|
{
|
||||||
forcestateupdate = true;
|
forcestateupdate = true;
|
||||||
mJumpState = JumpState_Landing;
|
mJumpState = JumpState_Landing;
|
||||||
vec.z = 0.0f;
|
vec.z() = 0.0f;
|
||||||
|
|
||||||
float height = cls.getCreatureStats(mPtr).land();
|
float height = cls.getCreatureStats(mPtr).land();
|
||||||
float healthLost = getFallDamage(mPtr, height);
|
float healthLost = getFallDamage(mPtr, height);
|
||||||
|
@ -1575,28 +1576,28 @@ void CharacterController::update(float duration)
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
mJumpState = JumpState_None;
|
mJumpState = JumpState_None;
|
||||||
vec.z = 0.0f;
|
vec.z() = 0.0f;
|
||||||
|
|
||||||
inJump = false;
|
inJump = false;
|
||||||
|
|
||||||
if(std::abs(vec.x/2.0f) > std::abs(vec.y))
|
if(std::abs(vec.x()/2.0f) > std::abs(vec.y()))
|
||||||
{
|
{
|
||||||
if(vec.x > 0.0f)
|
if(vec.x() > 0.0f)
|
||||||
movestate = (inwater ? (isrunning ? CharState_SwimRunRight : CharState_SwimWalkRight)
|
movestate = (inwater ? (isrunning ? CharState_SwimRunRight : CharState_SwimWalkRight)
|
||||||
: (sneak ? CharState_SneakRight
|
: (sneak ? CharState_SneakRight
|
||||||
: (isrunning ? CharState_RunRight : CharState_WalkRight)));
|
: (isrunning ? CharState_RunRight : CharState_WalkRight)));
|
||||||
else if(vec.x < 0.0f)
|
else if(vec.x() < 0.0f)
|
||||||
movestate = (inwater ? (isrunning ? CharState_SwimRunLeft : CharState_SwimWalkLeft)
|
movestate = (inwater ? (isrunning ? CharState_SwimRunLeft : CharState_SwimWalkLeft)
|
||||||
: (sneak ? CharState_SneakLeft
|
: (sneak ? CharState_SneakLeft
|
||||||
: (isrunning ? CharState_RunLeft : CharState_WalkLeft)));
|
: (isrunning ? CharState_RunLeft : CharState_WalkLeft)));
|
||||||
}
|
}
|
||||||
else if(vec.y != 0.0f)
|
else if(vec.y() != 0.0f)
|
||||||
{
|
{
|
||||||
if(vec.y > 0.0f)
|
if(vec.y() > 0.0f)
|
||||||
movestate = (inwater ? (isrunning ? CharState_SwimRunForward : CharState_SwimWalkForward)
|
movestate = (inwater ? (isrunning ? CharState_SwimRunForward : CharState_SwimWalkForward)
|
||||||
: (sneak ? CharState_SneakForward
|
: (sneak ? CharState_SneakForward
|
||||||
: (isrunning ? CharState_RunForward : CharState_WalkForward)));
|
: (isrunning ? CharState_RunForward : CharState_WalkForward)));
|
||||||
else if(vec.y < 0.0f)
|
else if(vec.y() < 0.0f)
|
||||||
movestate = (inwater ? (isrunning ? CharState_SwimRunBack : CharState_SwimWalkBack)
|
movestate = (inwater ? (isrunning ? CharState_SwimRunBack : CharState_SwimWalkBack)
|
||||||
: (sneak ? CharState_SneakBack
|
: (sneak ? CharState_SneakBack
|
||||||
: (isrunning ? CharState_RunBack : CharState_WalkBack)));
|
: (isrunning ? CharState_RunBack : CharState_WalkBack)));
|
||||||
|
@ -1676,7 +1677,7 @@ void CharacterController::update(float duration)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
// We must always queue movement, even if there is none, to apply gravity.
|
// We must always queue movement, even if there is none, to apply gravity.
|
||||||
world->queueMovement(mPtr, Ogre::Vector3(0.0f));
|
world->queueMovement(mPtr, osg::Vec3f(0.f, 0.f, 0.f));
|
||||||
|
|
||||||
movement = vec;
|
movement = vec;
|
||||||
cls.getMovementSettings(mPtr).mPosition[0] = cls.getMovementSettings(mPtr).mPosition[1] = 0;
|
cls.getMovementSettings(mPtr).mPosition[0] = cls.getMovementSettings(mPtr).mPosition[1] = 0;
|
||||||
|
@ -1688,7 +1689,7 @@ void CharacterController::update(float duration)
|
||||||
}
|
}
|
||||||
else if(cls.getCreatureStats(mPtr).isDead())
|
else if(cls.getCreatureStats(mPtr).isDead())
|
||||||
{
|
{
|
||||||
world->queueMovement(mPtr, Ogre::Vector3(0.0f));
|
world->queueMovement(mPtr, osg::Vec3f(0.f, 0.f, 0.f));
|
||||||
}
|
}
|
||||||
|
|
||||||
osg::Vec3f moved = mAnimation->runAnimation(mSkipAnim ? 0.f : duration);
|
osg::Vec3f moved = mAnimation->runAnimation(mSkipAnim ? 0.f : duration);
|
||||||
|
@ -1702,15 +1703,15 @@ void CharacterController::update(float duration)
|
||||||
{
|
{
|
||||||
float l = moved.length();
|
float l = moved.length();
|
||||||
|
|
||||||
if((movement.x < 0.0f && movement.x < moved.x()*2.0f) ||
|
if((movement.x() < 0.0f && movement.x() < moved.x()*2.0f) ||
|
||||||
(movement.x > 0.0f && movement.x > moved.x()*2.0f))
|
(movement.x() > 0.0f && movement.x() > moved.x()*2.0f))
|
||||||
moved.x() = movement.x;
|
moved.x() = movement.x();
|
||||||
if((movement.y < 0.0f && movement.y < moved.y()*2.0f) ||
|
if((movement.y() < 0.0f && movement.y() < moved.y()*2.0f) ||
|
||||||
(movement.y > 0.0f && movement.y > moved.y()*2.0f))
|
(movement.y() > 0.0f && movement.y() > moved.y()*2.0f))
|
||||||
moved.y() = movement.y;
|
moved.y() = movement.y();
|
||||||
if((movement.z < 0.0f && movement.z < moved.z()*2.0f) ||
|
if((movement.z() < 0.0f && movement.z() < moved.z()*2.0f) ||
|
||||||
(movement.z > 0.0f && movement.z > moved.z()*2.0f))
|
(movement.z() > 0.0f && movement.z() > moved.z()*2.0f))
|
||||||
moved.z() = movement.z;
|
moved.z() = movement.z();
|
||||||
// but keep the original speed
|
// but keep the original speed
|
||||||
float newLength = moved.length();
|
float newLength = moved.length();
|
||||||
if (newLength > 0)
|
if (newLength > 0)
|
||||||
|
@ -1722,7 +1723,7 @@ void CharacterController::update(float duration)
|
||||||
|
|
||||||
// Update movement
|
// Update movement
|
||||||
if(mMovementAnimationControlled && mPtr.getClass().isActor())
|
if(mMovementAnimationControlled && mPtr.getClass().isActor())
|
||||||
world->queueMovement(mPtr, Ogre::Vector3(moved.x(), moved.y(), moved.z()));
|
world->queueMovement(mPtr, moved);
|
||||||
|
|
||||||
mSkipAnim = false;
|
mSkipAnim = false;
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
#ifndef GAME_MWMECHANICS_MOVEMENT_H
|
#ifndef GAME_MWMECHANICS_MOVEMENT_H
|
||||||
#define GAME_MWMECHANICS_MOVEMENT_H
|
#define GAME_MWMECHANICS_MOVEMENT_H
|
||||||
|
|
||||||
|
#include <osg/Vec3f>
|
||||||
|
|
||||||
namespace MWMechanics
|
namespace MWMechanics
|
||||||
{
|
{
|
||||||
/// Desired movement for an actor
|
/// Desired movement for an actor
|
||||||
|
@ -14,6 +16,11 @@ namespace MWMechanics
|
||||||
mPosition[0] = mPosition[1] = mPosition[2] = 0.0f;
|
mPosition[0] = mPosition[1] = mPosition[2] = 0.0f;
|
||||||
mRotation[0] = mRotation[1] = mRotation[2] = 0.0f;
|
mRotation[0] = mRotation[1] = mRotation[2] = 0.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
osg::Vec3f asVec3()
|
||||||
|
{
|
||||||
|
return osg::Vec3f(mPosition[0], mPosition[1], mPosition[2]);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
152
apps/openmw/mwphysics/actor.cpp
Normal file
152
apps/openmw/mwphysics/actor.cpp
Normal file
|
@ -0,0 +1,152 @@
|
||||||
|
#include "actor.hpp"
|
||||||
|
#include <osg/io_utils>
|
||||||
|
|
||||||
|
#include <osg/PositionAttitudeTransform>
|
||||||
|
|
||||||
|
#include <btBulletCollisionCommon.h>
|
||||||
|
|
||||||
|
#include "../mwworld/class.hpp"
|
||||||
|
|
||||||
|
#include <components/nifbullet/bulletnifloader.hpp>
|
||||||
|
|
||||||
|
#include "convert.hpp"
|
||||||
|
#include "collisiontype.hpp"
|
||||||
|
|
||||||
|
namespace MWPhysics
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
Actor::Actor(const MWWorld::Ptr& ptr, osg::ref_ptr<NifBullet::BulletShapeInstance> shape, btDynamicsWorld* world)
|
||||||
|
: mCanWaterWalk(false), mWalkingOnWater(false)
|
||||||
|
, mCollisionObject(0), mForce(0.f, 0.f, 0.f), mOnGround(false)
|
||||||
|
, mInternalCollisionMode(true)
|
||||||
|
, mExternalCollisionMode(true)
|
||||||
|
, mDynamicsWorld(world)
|
||||||
|
{
|
||||||
|
mPtr = ptr;
|
||||||
|
|
||||||
|
mHalfExtents = shape->mCollisionBoxHalfExtents;
|
||||||
|
mMeshTranslation = shape->mCollisionBoxTranslate;
|
||||||
|
|
||||||
|
// 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(toBullet(mHalfExtents)));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
mShape.reset(new btBoxShape(toBullet(mHalfExtents)));
|
||||||
|
|
||||||
|
mCollisionObject.reset(new btCollisionObject);
|
||||||
|
mCollisionObject->setCollisionFlags(btCollisionObject::CF_KINEMATIC_OBJECT);
|
||||||
|
mCollisionObject->setActivationState(DISABLE_DEACTIVATION);
|
||||||
|
mCollisionObject->setCollisionShape(mShape.get());
|
||||||
|
mCollisionObject->setUserPointer(static_cast<PtrHolder*>(this));
|
||||||
|
|
||||||
|
updateRotation();
|
||||||
|
updateScale();
|
||||||
|
// already called by updateScale()
|
||||||
|
//updatePosition();
|
||||||
|
|
||||||
|
updateCollisionMask();
|
||||||
|
}
|
||||||
|
|
||||||
|
Actor::~Actor()
|
||||||
|
{
|
||||||
|
if (mCollisionObject.get())
|
||||||
|
mDynamicsWorld->removeCollisionObject(mCollisionObject.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
void Actor::enableCollisionMode(bool collision)
|
||||||
|
{
|
||||||
|
mInternalCollisionMode = collision;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Actor::enableCollisionBody(bool collision)
|
||||||
|
{
|
||||||
|
if (mExternalCollisionMode != collision)
|
||||||
|
{
|
||||||
|
mExternalCollisionMode = collision;
|
||||||
|
updateCollisionMask();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Actor::updateCollisionMask()
|
||||||
|
{
|
||||||
|
mDynamicsWorld->removeCollisionObject(mCollisionObject.get());
|
||||||
|
int collisionMask = CollisionType_World | CollisionType_HeightMap;
|
||||||
|
if (mExternalCollisionMode)
|
||||||
|
collisionMask |= CollisionType_Actor | CollisionType_Projectile;
|
||||||
|
if (mCanWaterWalk)
|
||||||
|
collisionMask |= CollisionType_Water;
|
||||||
|
mDynamicsWorld->addCollisionObject(mCollisionObject.get(), CollisionType_Actor, collisionMask);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Actor::updatePosition()
|
||||||
|
{
|
||||||
|
osg::Vec3f position = mPtr.getRefData().getPosition().asVec3();
|
||||||
|
|
||||||
|
btTransform tr = mCollisionObject->getWorldTransform();
|
||||||
|
osg::Vec3f scaledTranslation = osg::componentMultiply(mMeshTranslation, mScale);
|
||||||
|
osg::Vec3f newPosition = scaledTranslation + position;
|
||||||
|
|
||||||
|
tr.setOrigin(toBullet(newPosition));
|
||||||
|
mCollisionObject->setWorldTransform(tr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Actor::updateRotation ()
|
||||||
|
{
|
||||||
|
btTransform tr = mCollisionObject->getWorldTransform();
|
||||||
|
tr.setRotation(toBullet(mPtr.getRefData().getBaseNode()->getAttitude()));
|
||||||
|
mCollisionObject->setWorldTransform(tr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Actor::updateScale()
|
||||||
|
{
|
||||||
|
float scale = mPtr.getCellRef().getScale();
|
||||||
|
osg::Vec3f scaleVec(scale,scale,scale);
|
||||||
|
|
||||||
|
if (!mPtr.getClass().isNpc())
|
||||||
|
mPtr.getClass().adjustScale(mPtr, scaleVec);
|
||||||
|
|
||||||
|
mScale = scaleVec;
|
||||||
|
mShape->setLocalScaling(toBullet(mScale));
|
||||||
|
|
||||||
|
updatePosition();
|
||||||
|
}
|
||||||
|
|
||||||
|
osg::Vec3f Actor::getHalfExtents() const
|
||||||
|
{
|
||||||
|
return osg::componentMultiply(mHalfExtents, mScale);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Actor::setInertialForce(const osg::Vec3f &force)
|
||||||
|
{
|
||||||
|
mForce = force;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Actor::setOnGround(bool grounded)
|
||||||
|
{
|
||||||
|
mOnGround = grounded;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Actor::isWalkingOnWater() const
|
||||||
|
{
|
||||||
|
return mWalkingOnWater;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Actor::setWalkingOnWater(bool walkingOnWater)
|
||||||
|
{
|
||||||
|
mWalkingOnWater = walkingOnWater;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Actor::setCanWaterWalk(bool waterWalk)
|
||||||
|
{
|
||||||
|
if (waterWalk != mCanWaterWalk)
|
||||||
|
{
|
||||||
|
mCanWaterWalk = waterWalk;
|
||||||
|
updateCollisionMask();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
125
apps/openmw/mwphysics/actor.hpp
Normal file
125
apps/openmw/mwphysics/actor.hpp
Normal file
|
@ -0,0 +1,125 @@
|
||||||
|
#ifndef OPENMW_MWPHYSICS_ACTOR_H
|
||||||
|
#define OPENMW_MWPHYSICS_ACTOR_H
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
#include "../mwworld/ptr.hpp"
|
||||||
|
|
||||||
|
#include <osg/Vec3f>
|
||||||
|
#include <osg/ref_ptr>
|
||||||
|
|
||||||
|
class btDynamicsWorld;
|
||||||
|
class btCollisionShape;
|
||||||
|
class btCollisionObject;
|
||||||
|
|
||||||
|
namespace NifBullet
|
||||||
|
{
|
||||||
|
class BulletShapeInstance;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace MWPhysics
|
||||||
|
{
|
||||||
|
|
||||||
|
class PtrHolder
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual ~PtrHolder() {}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
MWWorld::Ptr mPtr;
|
||||||
|
};
|
||||||
|
|
||||||
|
class Actor : public PtrHolder
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Actor(const MWWorld::Ptr& ptr, osg::ref_ptr<NifBullet::BulletShapeInstance> shape, btDynamicsWorld* world);
|
||||||
|
~Actor();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the collisionMode for this actor. If disabled, the actor can fly and clip geometry.
|
||||||
|
*/
|
||||||
|
void enableCollisionMode(bool collision);
|
||||||
|
|
||||||
|
bool getCollisionMode() const
|
||||||
|
{
|
||||||
|
return mInternalCollisionMode;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enables or disables the *external* collision body. If disabled, other actors will not collide with this actor.
|
||||||
|
*/
|
||||||
|
void enableCollisionBody(bool collision);
|
||||||
|
|
||||||
|
void updateScale();
|
||||||
|
void updateRotation();
|
||||||
|
void updatePosition();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the (scaled) half extents
|
||||||
|
*/
|
||||||
|
osg::Vec3f getHalfExtents() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the current amount of inertial force (incl. gravity) affecting this physic actor
|
||||||
|
*/
|
||||||
|
void setInertialForce(const osg::Vec3f &force);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the current amount of inertial force (incl. gravity) affecting this physic actor
|
||||||
|
*/
|
||||||
|
const osg::Vec3f &getInertialForce() const
|
||||||
|
{
|
||||||
|
return mForce;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setOnGround(bool grounded);
|
||||||
|
|
||||||
|
bool getOnGround() const
|
||||||
|
{
|
||||||
|
return mInternalCollisionMode && mOnGround;
|
||||||
|
}
|
||||||
|
|
||||||
|
btCollisionObject* getCollisionObject() const
|
||||||
|
{
|
||||||
|
return mCollisionObject.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 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 object to the dynamics world
|
||||||
|
void updateCollisionMask();
|
||||||
|
|
||||||
|
bool mCanWaterWalk;
|
||||||
|
bool mWalkingOnWater;
|
||||||
|
|
||||||
|
std::auto_ptr<btCollisionShape> mShape;
|
||||||
|
|
||||||
|
std::auto_ptr<btCollisionObject> mCollisionObject;
|
||||||
|
|
||||||
|
osg::Vec3f mMeshTranslation;
|
||||||
|
osg::Vec3f mHalfExtents;
|
||||||
|
|
||||||
|
osg::Vec3f mScale;
|
||||||
|
osg::Vec3f mPosition;
|
||||||
|
|
||||||
|
osg::Vec3f mForce;
|
||||||
|
bool mOnGround;
|
||||||
|
bool mInternalCollisionMode;
|
||||||
|
bool mExternalCollisionMode;
|
||||||
|
|
||||||
|
btDynamicsWorld* mDynamicsWorld;
|
||||||
|
|
||||||
|
Actor(const Actor&);
|
||||||
|
Actor& operator=(const Actor&);
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
17
apps/openmw/mwphysics/collisiontype.hpp
Normal file
17
apps/openmw/mwphysics/collisiontype.hpp
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
#ifndef OPENMW_MWPHYSICS_COLLISIONTYPE_H
|
||||||
|
#define OPENMW_MWPHYSICS_COLLISIONTYPE_H
|
||||||
|
|
||||||
|
namespace MWPhysics
|
||||||
|
{
|
||||||
|
|
||||||
|
enum CollisionType {
|
||||||
|
CollisionType_World = 1<<0,
|
||||||
|
CollisionType_Actor = 1<<1,
|
||||||
|
CollisionType_HeightMap = 1<<2,
|
||||||
|
CollisionType_Projectile = 1<<4,
|
||||||
|
CollisionType_Water = 1<<5
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
35
apps/openmw/mwphysics/convert.hpp
Normal file
35
apps/openmw/mwphysics/convert.hpp
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
#ifndef OPENMW_MWPHYSICS_CONVERT_H
|
||||||
|
#define OPENMW_MWPHYSICS_CONVERT_H
|
||||||
|
|
||||||
|
#include <LinearMath/btVector3.h>
|
||||||
|
#include <LinearMath/btQuaternion.h>
|
||||||
|
|
||||||
|
#include <osg/Vec3f>
|
||||||
|
#include <osg/Quat>
|
||||||
|
|
||||||
|
namespace MWPhysics
|
||||||
|
{
|
||||||
|
|
||||||
|
inline btVector3 toBullet(const osg::Vec3f& vec)
|
||||||
|
{
|
||||||
|
return btVector3(vec.x(), vec.y(), vec.z());
|
||||||
|
}
|
||||||
|
|
||||||
|
inline btQuaternion toBullet(const osg::Quat& quat)
|
||||||
|
{
|
||||||
|
return btQuaternion(quat.x(), quat.y(), quat.z(), quat.w());
|
||||||
|
}
|
||||||
|
|
||||||
|
inline osg::Vec3f toOsg(const btVector3& vec)
|
||||||
|
{
|
||||||
|
return osg::Vec3f(vec.x(), vec.y(), vec.z());
|
||||||
|
}
|
||||||
|
|
||||||
|
inline osg::Quat toOsg(const btQuaternion& quat)
|
||||||
|
{
|
||||||
|
return osg::Quat(quat.x(), quat.y(), quat.z(), quat.w());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -3,15 +3,17 @@
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
|
|
||||||
#include <osg/Group>
|
#include <osg/Group>
|
||||||
|
#include <osg/PositionAttitudeTransform>
|
||||||
|
|
||||||
#include <BulletCollision/CollisionShapes/btHeightfieldTerrainShape.h>
|
#include <BulletCollision/CollisionShapes/btHeightfieldTerrainShape.h>
|
||||||
|
|
||||||
|
#include <components/nifbullet/bulletshapemanager.hpp>
|
||||||
#include <components/nifbullet/bulletnifloader.hpp>
|
#include <components/nifbullet/bulletnifloader.hpp>
|
||||||
#include <components/misc/resourcehelpers.hpp>
|
#include <components/misc/resourcehelpers.hpp>
|
||||||
|
|
||||||
#include <components/esm/loadgmst.hpp>
|
#include <components/esm/loadgmst.hpp>
|
||||||
|
|
||||||
#include "../mwbase/world.hpp" // FIXME
|
#include "../mwbase/world.hpp"
|
||||||
#include "../mwbase/environment.hpp"
|
#include "../mwbase/environment.hpp"
|
||||||
|
|
||||||
#include "../mwmechanics/creaturestats.hpp"
|
#include "../mwmechanics/creaturestats.hpp"
|
||||||
|
@ -28,6 +30,11 @@
|
||||||
|
|
||||||
#include "../mwworld/class.hpp"
|
#include "../mwworld/class.hpp"
|
||||||
|
|
||||||
|
#include "collisiontype.hpp"
|
||||||
|
#include "actor.hpp"
|
||||||
|
#include "convert.hpp"
|
||||||
|
#include "trace.h"
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
|
|
||||||
|
@ -89,16 +96,17 @@ namespace MWPhysics
|
||||||
// Arbitrary number. To prevent infinite loops. They shouldn't happen but it's good to be prepared.
|
// Arbitrary number. To prevent infinite loops. They shouldn't happen but it's good to be prepared.
|
||||||
static const int sMaxIterations = 8;
|
static const int sMaxIterations = 8;
|
||||||
|
|
||||||
|
// FIXME: move to a separate file
|
||||||
class MovementSolver
|
class MovementSolver
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
static float getSlope(const Ogre::Vector3 &normal)
|
static float getSlope(const osg::Vec3f &normal)
|
||||||
{
|
{
|
||||||
return normal.angleBetween(Ogre::Vector3(0.0f,0.0f,1.0f)).valueDegrees();
|
return osg::RadiansToDegrees(std::acos(normal * osg::Vec3f(0.f, 0.f, 1.f)));
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool stepMove(btCollisionObject *colobj, Ogre::Vector3 &position,
|
static bool stepMove(btCollisionObject *colobj, osg::Vec3f &position,
|
||||||
const Ogre::Vector3 &toMove, float &remainingTime /*, OEngine::Physic::PhysicEngine *engine*/)
|
const osg::Vec3f &toMove, float &remainingTime, btDynamicsWorld* dynamicsWorld)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* Slide up an incline or set of stairs. Should be called only after a
|
* Slide up an incline or set of stairs. Should be called only after a
|
||||||
|
@ -144,11 +152,9 @@ namespace MWPhysics
|
||||||
* +--+ +--------
|
* +--+ +--------
|
||||||
* ==============================================
|
* ==============================================
|
||||||
*/
|
*/
|
||||||
return false;
|
ActorTracer tracer, stepper;
|
||||||
#if 0
|
|
||||||
OEngine::Physic::ActorTracer tracer, stepper;
|
|
||||||
|
|
||||||
stepper.doTrace(colobj, position, position+Ogre::Vector3(0.0f,0.0f,sStepSizeUp), engine);
|
stepper.doTrace(colobj, position, position+osg::Vec3f(0.0f,0.0f,sStepSizeUp), dynamicsWorld);
|
||||||
if(stepper.mFraction < std::numeric_limits<float>::epsilon())
|
if(stepper.mFraction < std::numeric_limits<float>::epsilon())
|
||||||
return false; // didn't even move the smallest representable amount
|
return false; // didn't even move the smallest representable amount
|
||||||
// (TODO: shouldn't this be larger? Why bother with such a small amount?)
|
// (TODO: shouldn't this be larger? Why bother with such a small amount?)
|
||||||
|
@ -166,7 +172,7 @@ namespace MWPhysics
|
||||||
* +--+
|
* +--+
|
||||||
* ==============================================
|
* ==============================================
|
||||||
*/
|
*/
|
||||||
tracer.doTrace(colobj, stepper.mEndPos, stepper.mEndPos + toMove, engine);
|
tracer.doTrace(colobj, stepper.mEndPos, stepper.mEndPos + toMove, dynamicsWorld);
|
||||||
if(tracer.mFraction < std::numeric_limits<float>::epsilon())
|
if(tracer.mFraction < std::numeric_limits<float>::epsilon())
|
||||||
return false; // didn't even move the smallest representable amount
|
return false; // didn't even move the smallest representable amount
|
||||||
|
|
||||||
|
@ -185,7 +191,7 @@ namespace MWPhysics
|
||||||
* +--+ +--+
|
* +--+ +--+
|
||||||
* ==============================================
|
* ==============================================
|
||||||
*/
|
*/
|
||||||
stepper.doTrace(colobj, tracer.mEndPos, tracer.mEndPos-Ogre::Vector3(0.0f,0.0f,sStepSizeDown), engine);
|
stepper.doTrace(colobj, tracer.mEndPos, tracer.mEndPos-osg::Vec3f(0.0f,0.0f,sStepSizeDown), dynamicsWorld);
|
||||||
if(stepper.mFraction < 1.0f && getSlope(stepper.mPlaneNormal) <= sMaxSlope)
|
if(stepper.mFraction < 1.0f && getSlope(stepper.mPlaneNormal) <= sMaxSlope)
|
||||||
{
|
{
|
||||||
// don't allow stepping up other actors
|
// don't allow stepping up other actors
|
||||||
|
@ -201,41 +207,39 @@ namespace MWPhysics
|
||||||
|
|
||||||
// moved between 0 and just under sStepSize distance but slope was too great,
|
// moved between 0 and just under sStepSize distance but slope was too great,
|
||||||
// or moved full sStepSize distance (FIXME: is this a bug?)
|
// or moved full sStepSize distance (FIXME: is this a bug?)
|
||||||
#endif
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
///Project a vector u on another vector v
|
///Project a vector u on another vector v
|
||||||
static inline Ogre::Vector3 project(const Ogre::Vector3 u, const Ogre::Vector3 &v)
|
static inline osg::Vec3f project(const osg::Vec3f& u, const osg::Vec3f &v)
|
||||||
{
|
{
|
||||||
return v * u.dotProduct(v);
|
return v * (u * v);
|
||||||
|
// ^ dot product
|
||||||
}
|
}
|
||||||
|
|
||||||
///Helper for computing the character sliding
|
///Helper for computing the character sliding
|
||||||
static inline Ogre::Vector3 slide(Ogre::Vector3 direction, const Ogre::Vector3 &planeNormal)
|
static inline osg::Vec3f slide(const osg::Vec3f& direction, const osg::Vec3f &planeNormal)
|
||||||
{
|
{
|
||||||
return direction - project(direction, planeNormal);
|
return direction - project(direction, planeNormal);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline osg::Vec3f reflect(const osg::Vec3& velocity, const osg::Vec3f& normal)
|
||||||
|
{
|
||||||
|
return (normal * (normal * velocity)) * 2 - velocity;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static Ogre::Vector3 traceDown(const MWWorld::Ptr &ptr, /*OEngine::Physic::PhysicEngine *engine,*/ float maxHeight)
|
static osg::Vec3f traceDown(const MWWorld::Ptr &ptr, Actor* actor, btDynamicsWorld* dynamicsWorld, float maxHeight)
|
||||||
{
|
{
|
||||||
const ESM::Position &refpos = ptr.getRefData().getPosition();
|
osg::Vec3f position(ptr.getRefData().getPosition().asVec3());
|
||||||
Ogre::Vector3 position(refpos.pos);
|
|
||||||
|
|
||||||
return position;
|
ActorTracer tracer;
|
||||||
#if 0
|
tracer.findGround(actor, position, position-osg::Vec3f(0,0,maxHeight), dynamicsWorld);
|
||||||
OEngine::Physic::PhysicActor *physicActor = engine->getCharacter(ptr.getRefData().getHandle());
|
|
||||||
if (!physicActor)
|
|
||||||
return position;
|
|
||||||
|
|
||||||
OEngine::Physic::ActorTracer tracer;
|
|
||||||
tracer.findGround(physicActor, position, position-Ogre::Vector3(0,0,maxHeight), engine);
|
|
||||||
if(tracer.mFraction >= 1.0f)
|
if(tracer.mFraction >= 1.0f)
|
||||||
{
|
{
|
||||||
physicActor->setOnGround(false);
|
actor->setOnGround(false);
|
||||||
return position;
|
return position;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -243,79 +247,73 @@ namespace MWPhysics
|
||||||
// Check if we actually found a valid spawn point (use an infinitely thin ray this time).
|
// Check if we actually found a valid spawn point (use an infinitely thin ray this time).
|
||||||
// Required for some broken door destinations in Morrowind.esm, where the spawn point
|
// Required for some broken door destinations in Morrowind.esm, where the spawn point
|
||||||
// intersects with other geometry if the actor's base is taken into account
|
// intersects with other geometry if the actor's base is taken into account
|
||||||
btVector3 from = BtOgre::Convert::toBullet(position);
|
btVector3 from = toBullet(position);
|
||||||
btVector3 to = from - btVector3(0,0,maxHeight);
|
btVector3 to = from - btVector3(0,0,maxHeight);
|
||||||
|
|
||||||
btCollisionWorld::ClosestRayResultCallback resultCallback1(from, to);
|
btCollisionWorld::ClosestRayResultCallback resultCallback1(from, to);
|
||||||
resultCallback1.m_collisionFilterGroup = 0xff;
|
resultCallback1.m_collisionFilterGroup = 0xff;
|
||||||
resultCallback1.m_collisionFilterMask = CollisionType_World|CollisionType_HeightMap;
|
resultCallback1.m_collisionFilterMask = CollisionType_World|CollisionType_HeightMap;
|
||||||
|
|
||||||
engine->mDynamicsWorld->rayTest(from, to, resultCallback1);
|
dynamicsWorld->rayTest(from, to, resultCallback1);
|
||||||
if (resultCallback1.hasHit() &&
|
if (resultCallback1.hasHit() &&
|
||||||
(BtOgre::Convert::toOgre(resultCallback1.m_hitPointWorld).distance(tracer.mEndPos) > 30
|
( (toOsg(resultCallback1.m_hitPointWorld) - tracer.mEndPos).length() > 30
|
||||||
|| getSlope(tracer.mPlaneNormal) > sMaxSlope))
|
|| getSlope(tracer.mPlaneNormal) > sMaxSlope))
|
||||||
{
|
{
|
||||||
physicActor->setOnGround(getSlope(BtOgre::Convert::toOgre(resultCallback1.m_hitNormalWorld)) <= sMaxSlope);
|
actor->setOnGround(getSlope(toOsg(resultCallback1.m_hitNormalWorld)) <= sMaxSlope);
|
||||||
return BtOgre::Convert::toOgre(resultCallback1.m_hitPointWorld) + Ogre::Vector3(0,0,1.f);
|
return toOsg(resultCallback1.m_hitPointWorld) + osg::Vec3f(0.f, 0.f, 1.f);
|
||||||
}
|
}
|
||||||
|
|
||||||
physicActor->setOnGround(getSlope(tracer.mPlaneNormal) <= sMaxSlope);
|
actor->setOnGround(getSlope(tracer.mPlaneNormal) <= sMaxSlope);
|
||||||
|
|
||||||
return tracer.mEndPos;
|
return tracer.mEndPos;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static Ogre::Vector3 move(const MWWorld::Ptr &ptr, const Ogre::Vector3 &movement, float time,
|
static osg::Vec3f move(const MWWorld::Ptr &ptr, Actor* physicActor, const osg::Vec3f &movement, float time,
|
||||||
bool isFlying, float waterlevel, float slowFall /*, OEngine::Physic::PhysicEngine *engine*/
|
bool isFlying, float waterlevel, float slowFall, btDynamicsWorld* dynamicsWorld
|
||||||
, std::map<std::string, std::string>& collisionTracker
|
, std::map<std::string, std::string>& collisionTracker
|
||||||
, std::map<std::string, std::string>& standingCollisionTracker)
|
, std::map<std::string, std::string>& standingCollisionTracker)
|
||||||
{
|
{
|
||||||
const ESM::Position &refpos = ptr.getRefData().getPosition();
|
const ESM::Position& refpos = ptr.getRefData().getPosition();
|
||||||
Ogre::Vector3 position(refpos.pos);
|
osg::Vec3f position(refpos.asVec3());
|
||||||
return position;
|
|
||||||
#if 0
|
|
||||||
// Early-out for totally static creatures
|
// Early-out for totally static creatures
|
||||||
// (Not sure if gravity should still apply?)
|
// (Not sure if gravity should still apply?)
|
||||||
if (!ptr.getClass().isMobile(ptr))
|
if (!ptr.getClass().isMobile(ptr))
|
||||||
return position;
|
return position;
|
||||||
|
|
||||||
OEngine::Physic::PhysicActor *physicActor = engine->getCharacter(ptr.getRefData().getHandle());
|
|
||||||
if (!physicActor)
|
|
||||||
return position;
|
|
||||||
|
|
||||||
// Reset per-frame data
|
// Reset per-frame data
|
||||||
physicActor->setWalkingOnWater(false);
|
physicActor->setWalkingOnWater(false);
|
||||||
// Anything to collide with?
|
// Anything to collide with?
|
||||||
if(!physicActor->getCollisionMode())
|
if(!physicActor->getCollisionMode())
|
||||||
{
|
{
|
||||||
return position + (Ogre::Quaternion(Ogre::Radian(refpos.rot[2]), Ogre::Vector3::NEGATIVE_UNIT_Z) *
|
return position + (osg::Quat(refpos.rot[0], osg::Vec3f(-1, 0, 0)) *
|
||||||
Ogre::Quaternion(Ogre::Radian(refpos.rot[0]), Ogre::Vector3::NEGATIVE_UNIT_X))
|
osg::Quat(refpos.rot[2], osg::Vec3f(0, 0, -1))
|
||||||
* movement * time;
|
) * movement * time;
|
||||||
}
|
}
|
||||||
|
|
||||||
btCollisionObject *colobj = physicActor->getCollisionBody();
|
btCollisionObject *colobj = physicActor->getCollisionObject();
|
||||||
Ogre::Vector3 halfExtents = physicActor->getHalfExtents();
|
osg::Vec3f halfExtents = physicActor->getHalfExtents();
|
||||||
position.z += halfExtents.z;
|
position.z() += halfExtents.z();
|
||||||
|
|
||||||
static const float fSwimHeightScale = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>()
|
static const float fSwimHeightScale = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>()
|
||||||
.find("fSwimHeightScale")->getFloat();
|
.find("fSwimHeightScale")->getFloat();
|
||||||
float swimlevel = waterlevel + halfExtents.z - (halfExtents.z * 2 * fSwimHeightScale);
|
float swimlevel = waterlevel + halfExtents.z() - (halfExtents.z() * 2 * fSwimHeightScale);
|
||||||
|
|
||||||
OEngine::Physic::ActorTracer tracer;
|
ActorTracer tracer;
|
||||||
Ogre::Vector3 inertia = physicActor->getInertialForce();
|
osg::Vec3f inertia = physicActor->getInertialForce();
|
||||||
Ogre::Vector3 velocity;
|
osg::Vec3f velocity;
|
||||||
|
|
||||||
if(position.z < swimlevel || isFlying)
|
if(position.z() < swimlevel || isFlying)
|
||||||
{
|
{
|
||||||
velocity = (Ogre::Quaternion(Ogre::Radian(refpos.rot[2]), Ogre::Vector3::NEGATIVE_UNIT_Z)*
|
velocity = (osg::Quat(refpos.rot[0], osg::Vec3f(-1, 0, 0)) *
|
||||||
Ogre::Quaternion(Ogre::Radian(refpos.rot[0]), Ogre::Vector3::NEGATIVE_UNIT_X)) * movement;
|
osg::Quat(refpos.rot[2], osg::Vec3f(0, 0, -1))) * movement;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
velocity = Ogre::Quaternion(Ogre::Radian(refpos.rot[2]), Ogre::Vector3::NEGATIVE_UNIT_Z) * movement;
|
velocity = (osg::Quat(refpos.rot[2], osg::Vec3f(0, 0, -1))) * movement;
|
||||||
|
|
||||||
if (velocity.z > 0.f)
|
if (velocity.z() > 0.f)
|
||||||
inertia = velocity;
|
inertia = velocity;
|
||||||
if(!physicActor->getOnGround())
|
if(!physicActor->getOnGround())
|
||||||
{
|
{
|
||||||
|
@ -327,16 +325,16 @@ namespace MWPhysics
|
||||||
// Now that we have the effective movement vector, apply wind forces to it
|
// Now that we have the effective movement vector, apply wind forces to it
|
||||||
if (MWBase::Environment::get().getWorld()->isInStorm())
|
if (MWBase::Environment::get().getWorld()->isInStorm())
|
||||||
{
|
{
|
||||||
Ogre::Vector3 stormDirection = MWBase::Environment::get().getWorld()->getStormDirection();
|
osg::Vec3f stormDirection = MWBase::Environment::get().getWorld()->getStormDirection();
|
||||||
Ogre::Degree angle = stormDirection.angleBetween(velocity);
|
float angleDegrees = osg::RadiansToDegrees(std::acos(stormDirection * velocity));
|
||||||
static const float fStromWalkMult = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>()
|
static const float fStromWalkMult = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>()
|
||||||
.find("fStromWalkMult")->getFloat();
|
.find("fStromWalkMult")->getFloat();
|
||||||
velocity *= 1.f-(fStromWalkMult * (angle.valueDegrees()/180.f));
|
velocity *= 1.f-(fStromWalkMult * (angleDegrees/180.f));
|
||||||
}
|
}
|
||||||
|
|
||||||
Ogre::Vector3 origVelocity = velocity;
|
osg::Vec3f origVelocity = velocity;
|
||||||
|
|
||||||
Ogre::Vector3 newPosition = position;
|
osg::Vec3f newPosition = position;
|
||||||
/*
|
/*
|
||||||
* A loop to find newPosition using tracer, if successful different from the starting position.
|
* A loop to find newPosition using tracer, if successful different from the starting position.
|
||||||
* nextpos is the local variable used to find potential newPosition, using velocity and remainingTime
|
* nextpos is the local variable used to find potential newPosition, using velocity and remainingTime
|
||||||
|
@ -345,27 +343,27 @@ namespace MWPhysics
|
||||||
float remainingTime = time;
|
float remainingTime = time;
|
||||||
for(int iterations = 0; iterations < sMaxIterations && remainingTime > 0.01f; ++iterations)
|
for(int iterations = 0; iterations < sMaxIterations && remainingTime > 0.01f; ++iterations)
|
||||||
{
|
{
|
||||||
Ogre::Vector3 nextpos = newPosition + velocity * remainingTime;
|
osg::Vec3f nextpos = newPosition + velocity * remainingTime;
|
||||||
|
|
||||||
// If not able to fly, don't allow to swim up into the air
|
// If not able to fly, don't allow to swim up into the air
|
||||||
if(newPosition.z < swimlevel &&
|
if(newPosition.z() < swimlevel &&
|
||||||
!isFlying && // can't fly
|
!isFlying && // can't fly
|
||||||
nextpos.z > swimlevel && // but about to go above water
|
nextpos.z() > swimlevel && // but about to go above water
|
||||||
newPosition.z <= swimlevel)
|
newPosition.z() <= swimlevel)
|
||||||
{
|
{
|
||||||
const Ogre::Vector3 down(0,0,-1);
|
const osg::Vec3f down(0,0,-1);
|
||||||
Ogre::Real movelen = velocity.normalise();
|
float movelen = velocity.normalize();
|
||||||
Ogre::Vector3 reflectdir = velocity.reflect(down);
|
osg::Vec3f reflectdir = reflect(velocity, down);
|
||||||
reflectdir.normalise();
|
reflectdir.normalize();
|
||||||
velocity = slide(reflectdir, down)*movelen;
|
velocity = slide(reflectdir, down)*movelen;
|
||||||
// NOTE: remainingTime is unchanged before the loop continues
|
// NOTE: remainingTime is unchanged before the loop continues
|
||||||
continue; // velocity updated, calculate nextpos again
|
continue; // velocity updated, calculate nextpos again
|
||||||
}
|
}
|
||||||
|
|
||||||
if(newPosition.squaredDistance(nextpos) > 0.0001)
|
if((newPosition - nextpos).length2() > 0.0001)
|
||||||
{
|
{
|
||||||
// trace to where character would go if there were no obstructions
|
// trace to where character would go if there were no obstructions
|
||||||
tracer.doTrace(colobj, newPosition, nextpos, engine);
|
tracer.doTrace(colobj, newPosition, nextpos, dynamicsWorld);
|
||||||
|
|
||||||
// check for obstructions
|
// check for obstructions
|
||||||
if(tracer.mFraction >= 1.0f)
|
if(tracer.mFraction >= 1.0f)
|
||||||
|
@ -375,11 +373,13 @@ namespace MWPhysics
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
/*
|
||||||
const btCollisionObject* standingOn = tracer.mHitObject;
|
const btCollisionObject* standingOn = tracer.mHitObject;
|
||||||
if (const OEngine::Physic::RigidBody* body = dynamic_cast<const OEngine::Physic::RigidBody*>(standingOn))
|
if (const OEngine::Physic::RigidBody* body = dynamic_cast<const OEngine::Physic::RigidBody*>(standingOn))
|
||||||
{
|
{
|
||||||
collisionTracker[ptr.getRefData().getHandle()] = body->mName;
|
collisionTracker[ptr.getRefData().getHandle()] = body->mName;
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -395,62 +395,68 @@ namespace MWPhysics
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Ogre::Vector3 oldPosition = newPosition;
|
osg::Vec3f oldPosition = newPosition;
|
||||||
// We hit something. Try to step up onto it. (NOTE: stepMove does not allow stepping over)
|
// We hit something. Try to step up onto it. (NOTE: stepMove does not allow stepping over)
|
||||||
// NOTE: stepMove modifies newPosition if successful
|
// NOTE: stepMove modifies newPosition if successful
|
||||||
bool result = stepMove(colobj, newPosition, velocity*remainingTime, remainingTime, engine);
|
bool result = stepMove(colobj, newPosition, velocity*remainingTime, remainingTime, dynamicsWorld);
|
||||||
if (!result) // to make sure the maximum stepping distance isn't framerate-dependent or movement-speed dependent
|
if (!result) // to make sure the maximum stepping distance isn't framerate-dependent or movement-speed dependent
|
||||||
result = stepMove(colobj, newPosition, velocity.normalisedCopy()*10.f, remainingTime, engine);
|
{
|
||||||
|
osg::Vec3f normalizedVelocity = velocity;
|
||||||
|
normalizedVelocity.normalize();
|
||||||
|
result = stepMove(colobj, newPosition, normalizedVelocity*10.f, remainingTime, dynamicsWorld);
|
||||||
|
}
|
||||||
if(result)
|
if(result)
|
||||||
{
|
{
|
||||||
// don't let pure water creatures move out of water after stepMove
|
// don't let pure water creatures move out of water after stepMove
|
||||||
if (ptr.getClass().isPureWaterCreature(ptr)
|
if (ptr.getClass().isPureWaterCreature(ptr)
|
||||||
&& newPosition.z + halfExtents.z > waterlevel)
|
&& newPosition.z() + halfExtents.z() > waterlevel)
|
||||||
newPosition = oldPosition;
|
newPosition = oldPosition;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Can't move this way, try to find another spot along the plane
|
// Can't move this way, try to find another spot along the plane
|
||||||
Ogre::Vector3 direction = velocity;
|
osg::Vec3f direction = velocity;
|
||||||
Ogre::Real movelen = direction.normalise();
|
float movelen = direction.normalize();
|
||||||
Ogre::Vector3 reflectdir = velocity.reflect(tracer.mPlaneNormal);
|
osg::Vec3f reflectdir = reflect(velocity, tracer.mPlaneNormal);
|
||||||
reflectdir.normalise();
|
reflectdir.normalize();
|
||||||
|
|
||||||
Ogre::Vector3 newVelocity = slide(reflectdir, tracer.mPlaneNormal)*movelen;
|
osg::Vec3f newVelocity = slide(reflectdir, tracer.mPlaneNormal)*movelen;
|
||||||
if ((newVelocity-velocity).squaredLength() < 0.01)
|
if ((newVelocity-velocity).length2() < 0.01)
|
||||||
break;
|
|
||||||
if (velocity.dotProduct(origVelocity) <= 0.f)
|
|
||||||
break;
|
break;
|
||||||
|
if ((velocity * origVelocity) <= 0.f)
|
||||||
|
break; // ^ dot product
|
||||||
|
|
||||||
velocity = newVelocity;
|
velocity = newVelocity;
|
||||||
|
|
||||||
// Do not allow sliding upward if there is gravity. Stepping will have taken
|
// Do not allow sliding upward if there is gravity. Stepping will have taken
|
||||||
// care of that.
|
// care of that.
|
||||||
if(!(newPosition.z < swimlevel || isFlying))
|
if(!(newPosition.z() < swimlevel || isFlying))
|
||||||
velocity.z = std::min(velocity.z, 0.0f);
|
velocity.z() = std::min(velocity.z(), 0.0f);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isOnGround = false;
|
bool isOnGround = false;
|
||||||
if (!(inertia.z > 0.f) && !(newPosition.z < swimlevel))
|
if (!(inertia.z() > 0.f) && !(newPosition.z() < swimlevel))
|
||||||
{
|
{
|
||||||
Ogre::Vector3 from = newPosition;
|
osg::Vec3f from = newPosition;
|
||||||
Ogre::Vector3 to = newPosition - (physicActor->getOnGround() ?
|
osg::Vec3f to = newPosition - (physicActor->getOnGround() ?
|
||||||
Ogre::Vector3(0,0,sStepSizeDown+2.f) : Ogre::Vector3(0,0,2.f));
|
osg::Vec3f(0,0,sStepSizeDown+2.f) : osg::Vec3f(0,0,2.f));
|
||||||
tracer.doTrace(colobj, from, to, engine);
|
tracer.doTrace(colobj, from, to, dynamicsWorld);
|
||||||
if(tracer.mFraction < 1.0f && getSlope(tracer.mPlaneNormal) <= sMaxSlope
|
if(tracer.mFraction < 1.0f && getSlope(tracer.mPlaneNormal) <= sMaxSlope
|
||||||
&& tracer.mHitObject->getBroadphaseHandle()->m_collisionFilterGroup != CollisionType_Actor)
|
&& tracer.mHitObject->getBroadphaseHandle()->m_collisionFilterGroup != CollisionType_Actor)
|
||||||
{
|
{
|
||||||
|
/*
|
||||||
const btCollisionObject* standingOn = tracer.mHitObject;
|
const btCollisionObject* standingOn = tracer.mHitObject;
|
||||||
|
|
||||||
if (const OEngine::Physic::RigidBody* body = dynamic_cast<const OEngine::Physic::RigidBody*>(standingOn))
|
if (const OEngine::Physic::RigidBody* body = dynamic_cast<const OEngine::Physic::RigidBody*>(standingOn))
|
||||||
{
|
{
|
||||||
standingCollisionTracker[ptr.getRefData().getHandle()] = body->mName;
|
standingCollisionTracker[ptr.getRefData().getHandle()] = body->mName;
|
||||||
}
|
}
|
||||||
if (standingOn->getBroadphaseHandle()->m_collisionFilterGroup == CollisionType_Water)
|
if (standingOn->getBroadphaseHandle()->m_collisionFilterGroup == CollisionType_Water)
|
||||||
physicActor->setWalkingOnWater(true);
|
physicActor->setWalkingOnWater(true);
|
||||||
|
*/
|
||||||
if (!isFlying)
|
if (!isFlying)
|
||||||
newPosition.z = tracer.mEndPos.z + 1.0f;
|
newPosition.z() = tracer.mEndPos.z() + 1.0f;
|
||||||
|
|
||||||
isOnGround = true;
|
isOnGround = true;
|
||||||
}
|
}
|
||||||
|
@ -461,13 +467,13 @@ namespace MWPhysics
|
||||||
// so that we do not stay suspended in air indefinitely.
|
// so that we do not stay suspended in air indefinitely.
|
||||||
if (tracer.mFraction < 1.0f && tracer.mHitObject->getBroadphaseHandle()->m_collisionFilterGroup == CollisionType_Actor)
|
if (tracer.mFraction < 1.0f && tracer.mHitObject->getBroadphaseHandle()->m_collisionFilterGroup == CollisionType_Actor)
|
||||||
{
|
{
|
||||||
if (Ogre::Vector3(velocity.x, velocity.y, 0).squaredLength() < 100.f*100.f)
|
if (osg::Vec3f(velocity.x(), velocity.y(), 0).length2() < 100.f*100.f)
|
||||||
{
|
{
|
||||||
btVector3 aabbMin, aabbMax;
|
btVector3 aabbMin, aabbMax;
|
||||||
tracer.mHitObject->getCollisionShape()->getAabb(tracer.mHitObject->getWorldTransform(), aabbMin, aabbMax);
|
tracer.mHitObject->getCollisionShape()->getAabb(tracer.mHitObject->getWorldTransform(), aabbMin, aabbMax);
|
||||||
btVector3 center = (aabbMin + aabbMax) / 2.f;
|
btVector3 center = (aabbMin + aabbMax) / 2.f;
|
||||||
inertia = Ogre::Vector3(position.x - center.x(), position.y - center.y(), 0);
|
inertia = osg::Vec3f(position.x() - center.x(), position.y() - center.y(), 0);
|
||||||
inertia.normalise();
|
inertia.normalize();
|
||||||
inertia *= 100;
|
inertia *= 100;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -476,20 +482,19 @@ namespace MWPhysics
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(isOnGround || newPosition.z < swimlevel || isFlying)
|
if(isOnGround || newPosition.z() < swimlevel || isFlying)
|
||||||
physicActor->setInertialForce(Ogre::Vector3(0.0f));
|
physicActor->setInertialForce(osg::Vec3f(0.f, 0.f, 0.f));
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
inertia.z += time * -627.2f;
|
inertia.z() += time * -627.2f;
|
||||||
if (inertia.z < 0)
|
if (inertia.z() < 0)
|
||||||
inertia.z *= slowFall;
|
inertia.z() *= slowFall;
|
||||||
physicActor->setInertialForce(inertia);
|
physicActor->setInertialForce(inertia);
|
||||||
}
|
}
|
||||||
physicActor->setOnGround(isOnGround);
|
physicActor->setOnGround(isOnGround);
|
||||||
|
|
||||||
newPosition.z -= halfExtents.z; // remove what was added at the beginning
|
newPosition.z() -= halfExtents.z(); // remove what was added at the beginning
|
||||||
return newPosition;
|
return newPosition;
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -543,11 +548,62 @@ namespace MWPhysics
|
||||||
btCollisionObject* mCollisionObject;
|
btCollisionObject* mCollisionObject;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// --------------------------------------------------------------
|
||||||
|
|
||||||
|
class Object : public PtrHolder
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Object(const MWWorld::Ptr& ptr, osg::ref_ptr<NifBullet::BulletShapeInstance> shapeInstance)
|
||||||
|
: mShapeInstance(shapeInstance)
|
||||||
|
{
|
||||||
|
mPtr = ptr;
|
||||||
|
|
||||||
|
mCollisionObject.reset(new btCollisionObject);
|
||||||
|
mCollisionObject->setCollisionShape(shapeInstance->getCollisionShape());
|
||||||
|
|
||||||
|
mCollisionObject->setUserPointer(static_cast<PtrHolder*>(this));
|
||||||
|
|
||||||
|
setScale(ptr.getCellRef().getScale());
|
||||||
|
setRotation(toBullet(ptr.getRefData().getBaseNode()->getAttitude()));
|
||||||
|
const float* pos = ptr.getRefData().getPosition().pos;
|
||||||
|
setOrigin(btVector3(pos[0], pos[1], pos[2]));
|
||||||
|
}
|
||||||
|
|
||||||
|
void updatePtr(const MWWorld::Ptr& updated)
|
||||||
|
{
|
||||||
|
mPtr = updated;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setScale(float scale)
|
||||||
|
{
|
||||||
|
mShapeInstance->getCollisionShape()->setLocalScaling(btVector3(scale,scale,scale));
|
||||||
|
}
|
||||||
|
|
||||||
|
void setRotation(const btQuaternion& quat)
|
||||||
|
{
|
||||||
|
mCollisionObject->getWorldTransform().setRotation(quat);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setOrigin(const btVector3& vec)
|
||||||
|
{
|
||||||
|
mCollisionObject->getWorldTransform().setOrigin(vec);
|
||||||
|
}
|
||||||
|
|
||||||
|
btCollisionObject* getCollisionObject()
|
||||||
|
{
|
||||||
|
return mCollisionObject.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::auto_ptr<btCollisionObject> mCollisionObject;
|
||||||
|
osg::ref_ptr<NifBullet::BulletShapeInstance> mShapeInstance;
|
||||||
|
};
|
||||||
|
|
||||||
// ---------------------------------------------------------------
|
// ---------------------------------------------------------------
|
||||||
|
|
||||||
|
PhysicsSystem::PhysicsSystem(const VFS::Manager* vfs, osg::ref_ptr<osg::Group> parentNode)
|
||||||
PhysicsSystem::PhysicsSystem(osg::ref_ptr<osg::Group> parentNode)
|
: mShapeManager(new NifBullet::BulletShapeManager(vfs))
|
||||||
: mTimeAccum(0.0f)
|
, mTimeAccum(0.0f)
|
||||||
, mWaterEnabled(false)
|
, mWaterEnabled(false)
|
||||||
, mWaterHeight(0)
|
, mWaterHeight(0)
|
||||||
, mDebugDrawEnabled(false)
|
, mDebugDrawEnabled(false)
|
||||||
|
@ -577,6 +633,17 @@ namespace MWPhysics
|
||||||
delete it->second;
|
delete it->second;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (ObjectMap::iterator it = mObjects.begin(); it != mObjects.end(); ++it)
|
||||||
|
{
|
||||||
|
mDynamicsWorld->removeCollisionObject(it->second->getCollisionObject());
|
||||||
|
delete it->second;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (ActorMap::iterator it = mActors.begin(); it != mActors.end(); ++it)
|
||||||
|
{
|
||||||
|
delete it->second;
|
||||||
|
}
|
||||||
|
|
||||||
delete mDynamicsWorld;
|
delete mDynamicsWorld;
|
||||||
delete mSolver;
|
delete mSolver;
|
||||||
delete mCollisionConfiguration;
|
delete mCollisionConfiguration;
|
||||||
|
@ -668,9 +735,13 @@ namespace MWPhysics
|
||||||
return std::vector<std::string>();//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)
|
osg::Vec3f PhysicsSystem::traceDown(const MWWorld::Ptr &ptr, float maxHeight)
|
||||||
{
|
{
|
||||||
return Ogre::Vector3();//MovementSolver::traceDown(ptr, mEngine, maxHeight);
|
ActorMap::iterator found = mActors.find(ptr);
|
||||||
|
if (found == mActors.end())
|
||||||
|
return ptr.getRefData().getPosition().asVec3();
|
||||||
|
else
|
||||||
|
return MovementSolver::traceDown(ptr, found->second, mDynamicsWorld, maxHeight);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PhysicsSystem::addHeightField (float* heights, int x, int y, float triSize, float sqrtVerts)
|
void PhysicsSystem::addHeightField (float* heights, int x, int y, float triSize, float sqrtVerts)
|
||||||
|
@ -693,45 +764,115 @@ namespace MWPhysics
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void PhysicsSystem::addObject (const MWWorld::Ptr& ptr, const std::string& mesh, bool placeable)
|
void PhysicsSystem::addObject (const MWWorld::Ptr& ptr, const std::string& mesh)
|
||||||
{
|
{
|
||||||
|
osg::ref_ptr<NifBullet::BulletShapeInstance> shapeInstance = mShapeManager->createInstance(mesh);
|
||||||
|
if (!shapeInstance->getCollisionShape())
|
||||||
|
return;
|
||||||
|
|
||||||
|
Object *obj = new Object(ptr, shapeInstance);
|
||||||
|
mObjects.insert(std::make_pair(ptr, obj));
|
||||||
|
|
||||||
|
mDynamicsWorld->addCollisionObject(obj->getCollisionObject(), CollisionType_World,
|
||||||
|
CollisionType_Actor|CollisionType_HeightMap|CollisionType_Projectile);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PhysicsSystem::remove(const MWWorld::Ptr &ptr)
|
||||||
|
{
|
||||||
|
ObjectMap::iterator found = mObjects.find(ptr);
|
||||||
|
if (found != mObjects.end())
|
||||||
|
{
|
||||||
|
mDynamicsWorld->removeCollisionObject(found->second->getCollisionObject());
|
||||||
|
delete found->second;
|
||||||
|
mObjects.erase(found);
|
||||||
|
}
|
||||||
|
|
||||||
|
ActorMap::iterator foundActor = mActors.find(ptr);
|
||||||
|
if (foundActor != mActors.end())
|
||||||
|
{
|
||||||
|
delete foundActor->second;
|
||||||
|
mActors.erase(foundActor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PhysicsSystem::updateScale(const MWWorld::Ptr &ptr)
|
||||||
|
{
|
||||||
|
ObjectMap::iterator found = mObjects.find(ptr);
|
||||||
|
float scale = ptr.getCellRef().getScale();
|
||||||
|
if (found != mObjects.end())
|
||||||
|
{
|
||||||
|
found->second->setScale(scale);
|
||||||
|
mDynamicsWorld->updateSingleAabb(found->second->getCollisionObject());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ActorMap::iterator foundActor = mActors.find(ptr);
|
||||||
|
if (foundActor != mActors.end())
|
||||||
|
{
|
||||||
|
foundActor->second->updateScale();
|
||||||
|
// no aabb update needed (DISABLE_DEACTIVATION)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PhysicsSystem::updateRotation(const MWWorld::Ptr &ptr)
|
||||||
|
{
|
||||||
|
ObjectMap::iterator found = mObjects.find(ptr);
|
||||||
|
if (found != mObjects.end())
|
||||||
|
{
|
||||||
|
found->second->setRotation(toBullet(ptr.getRefData().getBaseNode()->getAttitude()));
|
||||||
|
mDynamicsWorld->updateSingleAabb(found->second->getCollisionObject());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ActorMap::iterator foundActor = mActors.find(ptr);
|
||||||
|
if (foundActor != mActors.end())
|
||||||
|
{
|
||||||
|
foundActor->second->updateRotation();
|
||||||
|
// no aabb update needed (DISABLE_DEACTIVATION)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PhysicsSystem::updatePosition(const MWWorld::Ptr &ptr)
|
||||||
|
{
|
||||||
|
ObjectMap::iterator found = mObjects.find(ptr);
|
||||||
|
if (found != mObjects.end())
|
||||||
|
{
|
||||||
|
found->second->setOrigin(toBullet(ptr.getRefData().getPosition().asVec3()));
|
||||||
|
mDynamicsWorld->updateSingleAabb(found->second->getCollisionObject());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ActorMap::iterator foundActor = mActors.find(ptr);
|
||||||
|
if (foundActor != mActors.end())
|
||||||
|
{
|
||||||
|
foundActor->second->updatePosition();
|
||||||
|
// no aabb update needed (DISABLE_DEACTIVATION)
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void PhysicsSystem::addActor (const MWWorld::Ptr& ptr, const std::string& mesh)
|
void PhysicsSystem::addActor (const MWWorld::Ptr& ptr, const std::string& mesh)
|
||||||
{
|
{
|
||||||
|
osg::ref_ptr<NifBullet::BulletShapeInstance> shapeInstance = mShapeManager->createInstance(mesh);
|
||||||
|
|
||||||
|
Actor* actor = new Actor(ptr, shapeInstance, mDynamicsWorld);
|
||||||
|
mActors.insert(std::make_pair(ptr, actor));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PhysicsSystem::toggleCollisionMode()
|
bool PhysicsSystem::toggleCollisionMode()
|
||||||
{
|
{
|
||||||
/*
|
ActorMap::iterator found = mActors.find(MWBase::Environment::get().getWorld()->getPlayerPtr());
|
||||||
for(std::map<std::string,OEngine::Physic::PhysicActor*>::iterator it = mEngine->mActorMap.begin(); it != mEngine->mActorMap.end();++it)
|
if (found != mActors.end())
|
||||||
{
|
{
|
||||||
if (it->first=="player")
|
bool cmode = found->second->getCollisionMode();
|
||||||
{
|
cmode = !cmode;
|
||||||
OEngine::Physic::PhysicActor* act = it->second;
|
found->second->enableCollisionMode(cmode);
|
||||||
|
return cmode;
|
||||||
bool cmode = act->getCollisionMode();
|
|
||||||
if(cmode)
|
|
||||||
{
|
|
||||||
act->enableCollisionMode(false);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
act->enableCollisionMode(true);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
throw std::logic_error ("can't find player");
|
|
||||||
*/
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void PhysicsSystem::queueObjectMovement(const MWWorld::Ptr &ptr, const Ogre::Vector3 &movement)
|
void PhysicsSystem::queueObjectMovement(const MWWorld::Ptr &ptr, const osg::Vec3f &movement)
|
||||||
{
|
{
|
||||||
PtrVelocityList::iterator iter = mMovementQueue.begin();
|
PtrVelocityList::iterator iter = mMovementQueue.begin();
|
||||||
for(;iter != mMovementQueue.end();++iter)
|
for(;iter != mMovementQueue.end();++iter)
|
||||||
|
@ -764,8 +905,6 @@ namespace MWPhysics
|
||||||
mCollisions.clear();
|
mCollisions.clear();
|
||||||
mStandingCollisions.clear();
|
mStandingCollisions.clear();
|
||||||
|
|
||||||
/*
|
|
||||||
|
|
||||||
const MWBase::World *world = MWBase::Environment::get().getWorld();
|
const MWBase::World *world = MWBase::Environment::get().getWorld();
|
||||||
PtrVelocityList::iterator iter = mMovementQueue.begin();
|
PtrVelocityList::iterator iter = mMovementQueue.begin();
|
||||||
for(;iter != mMovementQueue.end();++iter)
|
for(;iter != mMovementQueue.end();++iter)
|
||||||
|
@ -786,19 +925,20 @@ namespace MWPhysics
|
||||||
Ogre::Vector3(iter->first.getRefData().getPosition().pos)))
|
Ogre::Vector3(iter->first.getRefData().getPosition().pos)))
|
||||||
waterCollision = true;
|
waterCollision = true;
|
||||||
|
|
||||||
OEngine::Physic::PhysicActor *physicActor = mEngine->getCharacter(iter->first.getRefData().getHandle());
|
ActorMap::iterator foundActor = mActors.find(iter->first);
|
||||||
if (!physicActor) // actor was already removed from the scene
|
if (foundActor == mActors.end()) // actor was already removed from the scene
|
||||||
continue;
|
continue;
|
||||||
|
Actor* physicActor = foundActor->second;
|
||||||
physicActor->setCanWaterWalk(waterCollision);
|
physicActor->setCanWaterWalk(waterCollision);
|
||||||
|
|
||||||
// Slow fall reduces fall speed by a factor of (effect magnitude / 200)
|
// Slow fall reduces fall speed by a factor of (effect magnitude / 200)
|
||||||
float slowFall = 1.f - std::max(0.f, std::min(1.f, effects.get(ESM::MagicEffect::SlowFall).getMagnitude() * 0.005f));
|
float slowFall = 1.f - std::max(0.f, std::min(1.f, effects.get(ESM::MagicEffect::SlowFall).getMagnitude() * 0.005f));
|
||||||
|
|
||||||
Ogre::Vector3 newpos = MovementSolver::move(iter->first, iter->second, mTimeAccum,
|
osg::Vec3f newpos = MovementSolver::move(iter->first, physicActor, iter->second, mTimeAccum,
|
||||||
world->isFlying(iter->first),
|
world->isFlying(iter->first),
|
||||||
waterlevel, slowFall, mEngine, mCollisions, mStandingCollisions);
|
waterlevel, slowFall, mDynamicsWorld, mCollisions, mStandingCollisions);
|
||||||
|
|
||||||
float heightDiff = newpos.z - oldHeight;
|
float heightDiff = newpos.z() - oldHeight;
|
||||||
|
|
||||||
if (heightDiff < 0)
|
if (heightDiff < 0)
|
||||||
iter->first.getClass().getCreatureStats(iter->first).addToFallHeight(-heightDiff);
|
iter->first.getClass().getCreatureStats(iter->first).addToFallHeight(-heightDiff);
|
||||||
|
@ -806,8 +946,6 @@ namespace MWPhysics
|
||||||
mMovementResults.push_back(std::make_pair(iter->first, newpos));
|
mMovementResults.push_back(std::make_pair(iter->first, newpos));
|
||||||
}
|
}
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
mTimeAccum = 0.0f;
|
mTimeAccum = 0.0f;
|
||||||
}
|
}
|
||||||
mMovementQueue.clear();
|
mMovementQueue.clear();
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
#ifndef GAME_MWWORLD_PHYSICSSYSTEM_H
|
#ifndef OPENMW_MWPHYSICS_PHYSICSSYSTEM_H
|
||||||
#define GAME_MWWORLD_PHYSICSSYSTEM_H
|
#define OPENMW_MWPHYSICS_PHYSICSSYSTEM_H
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
|
@ -21,34 +21,48 @@ namespace MWRender
|
||||||
class DebugDrawer;
|
class DebugDrawer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace NifBullet
|
||||||
|
{
|
||||||
|
class BulletShapeManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace VFS
|
||||||
|
{
|
||||||
|
class Manager;
|
||||||
|
}
|
||||||
|
|
||||||
class btSequentialImpulseConstraintSolver;
|
class btSequentialImpulseConstraintSolver;
|
||||||
class btDiscreteDynamicsWorld;
|
class btDiscreteDynamicsWorld;
|
||||||
|
|
||||||
namespace MWPhysics
|
namespace MWPhysics
|
||||||
{
|
{
|
||||||
typedef std::vector<std::pair<MWWorld::Ptr,Ogre::Vector3> > PtrVelocityList;
|
typedef std::vector<std::pair<MWWorld::Ptr,osg::Vec3f> > PtrVelocityList;
|
||||||
|
|
||||||
enum CollisionType {
|
|
||||||
CollisionType_World = 1<<0,
|
|
||||||
CollisionType_Actor = 1<<1,
|
|
||||||
CollisionType_HeightMap = 1<<2,
|
|
||||||
CollisionType_Projectile = 1<<4,
|
|
||||||
CollisionType_Water = 1<<5
|
|
||||||
};
|
|
||||||
|
|
||||||
class HeightField;
|
class HeightField;
|
||||||
|
class Object;
|
||||||
|
class Actor;
|
||||||
|
|
||||||
class PhysicsSystem
|
class PhysicsSystem
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
PhysicsSystem (osg::ref_ptr<osg::Group> parentNode);
|
PhysicsSystem (const VFS::Manager* vfs, osg::ref_ptr<osg::Group> parentNode);
|
||||||
~PhysicsSystem ();
|
~PhysicsSystem ();
|
||||||
|
|
||||||
void enableWater(float height);
|
void enableWater(float height);
|
||||||
void setWaterHeight(float height);
|
void setWaterHeight(float height);
|
||||||
void disableWater();
|
void disableWater();
|
||||||
|
|
||||||
void addObject (const MWWorld::Ptr& ptr, const std::string& mesh, bool placeable=false);
|
void addObject (const MWWorld::Ptr& ptr, const std::string& mesh);
|
||||||
|
|
||||||
|
// Object or Actor
|
||||||
|
void remove (const MWWorld::Ptr& ptr);
|
||||||
|
|
||||||
|
void updateScale (const MWWorld::Ptr& ptr);
|
||||||
|
void updateRotation (const MWWorld::Ptr& ptr);
|
||||||
|
void updatePosition (const MWWorld::Ptr& ptr);
|
||||||
|
|
||||||
|
// TODO
|
||||||
|
//void updatePtr (const MWWorld::Ptr& old, const MWWorld::Ptr& updated);
|
||||||
|
|
||||||
void addActor (const MWWorld::Ptr& ptr, const std::string& mesh);
|
void addActor (const MWWorld::Ptr& ptr, const std::string& mesh);
|
||||||
|
|
||||||
|
@ -61,7 +75,7 @@ namespace MWPhysics
|
||||||
void stepSimulation(float dt);
|
void stepSimulation(float dt);
|
||||||
|
|
||||||
std::vector<std::string> getCollisions(const MWWorld::Ptr &ptr, int collisionGroup, int collisionMask); ///< get handles this object collides with
|
std::vector<std::string> getCollisions(const MWWorld::Ptr &ptr, int collisionGroup, int collisionMask); ///< get handles this object collides with
|
||||||
Ogre::Vector3 traceDown(const MWWorld::Ptr &ptr, float maxHeight);
|
osg::Vec3f traceDown(const MWWorld::Ptr &ptr, float maxHeight);
|
||||||
|
|
||||||
std::pair<std::string,Ogre::Vector3> getHitContact(const std::string &name,
|
std::pair<std::string,Ogre::Vector3> getHitContact(const std::string &name,
|
||||||
const Ogre::Vector3 &origin,
|
const Ogre::Vector3 &origin,
|
||||||
|
@ -76,7 +90,7 @@ namespace MWPhysics
|
||||||
|
|
||||||
/// Queues velocity movement for a Ptr. If a Ptr is already queued, its velocity will
|
/// Queues velocity movement for a Ptr. If a Ptr is already queued, its velocity will
|
||||||
/// be overwritten. Valid until the next call to applyQueuedMovement.
|
/// be overwritten. Valid until the next call to applyQueuedMovement.
|
||||||
void queueObjectMovement(const MWWorld::Ptr &ptr, const Ogre::Vector3 &velocity);
|
void queueObjectMovement(const MWWorld::Ptr &ptr, const osg::Vec3f &velocity);
|
||||||
|
|
||||||
/// Apply all queued movements, then clear the list.
|
/// Apply all queued movements, then clear the list.
|
||||||
const PtrVelocityList& applyQueuedMovement(float dt);
|
const PtrVelocityList& applyQueuedMovement(float dt);
|
||||||
|
@ -111,6 +125,14 @@ namespace MWPhysics
|
||||||
btCollisionDispatcher* mDispatcher;
|
btCollisionDispatcher* mDispatcher;
|
||||||
btDiscreteDynamicsWorld* mDynamicsWorld;
|
btDiscreteDynamicsWorld* mDynamicsWorld;
|
||||||
|
|
||||||
|
std::auto_ptr<NifBullet::BulletShapeManager> mShapeManager;
|
||||||
|
|
||||||
|
typedef std::map<MWWorld::Ptr, Object*> ObjectMap;
|
||||||
|
ObjectMap mObjects;
|
||||||
|
|
||||||
|
typedef std::map<MWWorld::Ptr, Actor*> ActorMap;
|
||||||
|
ActorMap mActors;
|
||||||
|
|
||||||
typedef std::map<std::pair<int, int>, HeightField*> HeightFieldMap;
|
typedef std::map<std::pair<int, int>, HeightField*> HeightFieldMap;
|
||||||
HeightFieldMap mHeightFields;
|
HeightFieldMap mHeightFields;
|
||||||
|
|
||||||
|
@ -121,9 +143,9 @@ namespace MWPhysics
|
||||||
// Tracks all movement collisions happening during a single frame. <actor handle, collided handle>
|
// Tracks all movement collisions happening during a single frame. <actor handle, collided handle>
|
||||||
// This will detect e.g. running against a vertical wall. It will not detect climbing up stairs,
|
// This will detect e.g. running against a vertical wall. It will not detect climbing up stairs,
|
||||||
// stepping up small objects, etc.
|
// stepping up small objects, etc.
|
||||||
std::map<std::string, std::string> mCollisions;
|
std::map<std::string, std::string> mCollisions; // FIXME: reimplement
|
||||||
|
|
||||||
std::map<std::string, std::string> mStandingCollisions;
|
std::map<std::string, std::string> mStandingCollisions; // FIXME: reimplement
|
||||||
|
|
||||||
PtrVelocityList mMovementQueue;
|
PtrVelocityList mMovementQueue;
|
||||||
PtrVelocityList mMovementResults;
|
PtrVelocityList mMovementResults;
|
||||||
|
|
128
apps/openmw/mwphysics/trace.cpp
Normal file
128
apps/openmw/mwphysics/trace.cpp
Normal file
|
@ -0,0 +1,128 @@
|
||||||
|
#include "trace.h"
|
||||||
|
|
||||||
|
#include <map>
|
||||||
|
|
||||||
|
#include <btBulletDynamicsCommon.h>
|
||||||
|
#include <btBulletCollisionCommon.h>
|
||||||
|
|
||||||
|
#include "collisiontype.hpp"
|
||||||
|
#include "actor.hpp"
|
||||||
|
#include "convert.hpp"
|
||||||
|
|
||||||
|
namespace MWPhysics
|
||||||
|
{
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
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 osg::Vec3f& start, const osg::Vec3f& end, btDynamicsWorld* world)
|
||||||
|
{
|
||||||
|
const btVector3 btstart = toBullet(start);
|
||||||
|
const btVector3 btend = toBullet(end);
|
||||||
|
|
||||||
|
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());
|
||||||
|
world->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 = osg::Vec3f(tracehitnormal.x(), tracehitnormal.y(), tracehitnormal.z());
|
||||||
|
mEndPos = (end-start)*mFraction + start;
|
||||||
|
mHitObject = newTraceCallback.m_hitCollisionObject;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mEndPos = end;
|
||||||
|
mPlaneNormal = osg::Vec3f(0.0f, 0.0f, 1.0f);
|
||||||
|
mFraction = 1.0f;
|
||||||
|
mHitObject = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ActorTracer::findGround(const Actor* actor, const osg::Vec3f& start, const osg::Vec3f& end, btDynamicsWorld* world)
|
||||||
|
{
|
||||||
|
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->getCollisionObject()->getWorldTransform();
|
||||||
|
btTransform from(trans.getBasis(), btstart);
|
||||||
|
btTransform to(trans.getBasis(), btend);
|
||||||
|
|
||||||
|
ClosestNotMeConvexResultCallback newTraceCallback(actor->getCollisionObject(), btstart-btend, btScalar(0.0));
|
||||||
|
// Inherit the actor's collision group and mask
|
||||||
|
newTraceCallback.m_collisionFilterGroup = actor->getCollisionObject()->getBroadphaseHandle()->m_collisionFilterGroup;
|
||||||
|
newTraceCallback.m_collisionFilterMask = actor->getCollisionObject()->getBroadphaseHandle()->m_collisionFilterMask;
|
||||||
|
newTraceCallback.m_collisionFilterMask &= ~CollisionType_Actor;
|
||||||
|
|
||||||
|
btVector3 halfExtents = toBullet(actor->getHalfExtents());
|
||||||
|
|
||||||
|
halfExtents[2] = 1.0f;
|
||||||
|
btCylinderShapeZ base(halfExtents);
|
||||||
|
|
||||||
|
world->convexSweepTest(&base, from, to, newTraceCallback);
|
||||||
|
if(newTraceCallback.hasHit())
|
||||||
|
{
|
||||||
|
const btVector3& tracehitnormal = newTraceCallback.m_hitNormalWorld;
|
||||||
|
mFraction = newTraceCallback.m_closestHitFraction;
|
||||||
|
mPlaneNormal = osg::Vec3f(tracehitnormal.x(), tracehitnormal.y(), tracehitnormal.z());
|
||||||
|
mEndPos = (end-start)*mFraction + start;
|
||||||
|
mEndPos[2] += 1.0f;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mEndPos = end;
|
||||||
|
mPlaneNormal = osg::Vec3f(0.0f, 0.0f, 1.0f);
|
||||||
|
mFraction = 1.0f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
27
apps/openmw/mwphysics/trace.h
Normal file
27
apps/openmw/mwphysics/trace.h
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
#ifndef OENGINE_BULLET_TRACE_H
|
||||||
|
#define OENGINE_BULLET_TRACE_H
|
||||||
|
|
||||||
|
#include <osg/Vec3f>
|
||||||
|
|
||||||
|
class btCollisionObject;
|
||||||
|
class btDynamicsWorld;
|
||||||
|
|
||||||
|
|
||||||
|
namespace MWPhysics
|
||||||
|
{
|
||||||
|
class Actor;
|
||||||
|
|
||||||
|
struct ActorTracer
|
||||||
|
{
|
||||||
|
osg::Vec3f mEndPos;
|
||||||
|
osg::Vec3f mPlaneNormal;
|
||||||
|
const btCollisionObject* mHitObject;
|
||||||
|
|
||||||
|
float mFraction;
|
||||||
|
|
||||||
|
void doTrace(btCollisionObject *actor, const osg::Vec3f& start, const osg::Vec3f& end, btDynamicsWorld* world);
|
||||||
|
void findGround(const Actor* actor, const osg::Vec3f& start, const osg::Vec3f& end, btDynamicsWorld* world);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -425,7 +425,7 @@ namespace MWScript
|
||||||
MWWorld::Ptr targetPtr;
|
MWWorld::Ptr targetPtr;
|
||||||
if (creatureStats.getAiSequence().getCombatTarget (targetPtr))
|
if (creatureStats.getAiSequence().getCombatTarget (targetPtr))
|
||||||
{
|
{
|
||||||
if (targetPtr.getRefData().getHandle() == testedTargetId)
|
if (targetPtr.getCellRef().getRefId() == testedTargetId)
|
||||||
targetsAreEqual = true;
|
targetsAreEqual = true;
|
||||||
}
|
}
|
||||||
runtime.push(int(targetsAreEqual));
|
runtime.push(int(targetsAreEqual));
|
||||||
|
|
|
@ -811,10 +811,10 @@ namespace MWScript
|
||||||
|
|
||||||
const std::string script = ptr.getClass().getScript(ptr);
|
const std::string script = ptr.getClass().getScript(ptr);
|
||||||
if(script.empty())
|
if(script.empty())
|
||||||
str<< ptr.getCellRef().getRefId()<<" ("<<ptr.getRefData().getHandle()<<") does not have a script.";
|
str<< ptr.getCellRef().getRefId()<<" does not have a script.";
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
str<< "Local variables for "<<ptr.getCellRef().getRefId()<<" ("<<ptr.getRefData().getHandle()<<")";
|
str<< "Local variables for "<<ptr.getCellRef().getRefId();
|
||||||
|
|
||||||
const Locals &locals = ptr.getRefData().getLocals();
|
const Locals &locals = ptr.getRefData().getLocals();
|
||||||
const Compiler::Locals &complocals = MWBase::Environment::get().getScriptManager()->getLocals(script);
|
const Compiler::Locals &complocals = MWBase::Environment::get().getScriptManager()->getLocals(script);
|
||||||
|
|
|
@ -6,25 +6,21 @@
|
||||||
|
|
||||||
#include "ptr.hpp"
|
#include "ptr.hpp"
|
||||||
|
|
||||||
namespace ESM
|
|
||||||
{
|
|
||||||
class CellRef;
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace MWWorld
|
namespace MWWorld
|
||||||
{
|
{
|
||||||
/// List all (Ogre-)handles, then reset RefData::mBaseNode to 0.
|
struct ListAndResetObjects
|
||||||
struct ListAndResetHandles
|
|
||||||
{
|
{
|
||||||
std::vector<Ogre::SceneNode*> mHandles;
|
std::vector<MWWorld::Ptr> mObjects;
|
||||||
|
|
||||||
bool operator() (MWWorld::Ptr ptr)
|
bool operator() (MWWorld::Ptr ptr)
|
||||||
{
|
{
|
||||||
Ogre::SceneNode* handle = ptr.getRefData().getBaseNodeOld();
|
if (ptr.getRefData().getBaseNode())
|
||||||
if (handle)
|
{
|
||||||
mHandles.push_back (handle);
|
ptr.getRefData().setBaseNode(NULL);
|
||||||
|
mObjects.push_back (ptr);
|
||||||
|
}
|
||||||
|
|
||||||
ptr.getRefData().setBaseNodeOld(0);
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -60,7 +60,7 @@ namespace
|
||||||
rot = rot * osg::Quat(y, osg::Vec3(0,-1,0)) * osg::Quat(x, osg::Vec3(-1,0,0));
|
rot = rot * osg::Quat(y, osg::Vec3(0,-1,0)) * osg::Quat(x, osg::Vec3(-1,0,0));
|
||||||
|
|
||||||
rendering.rotateObject(ptr, rot * worldRotQuat);
|
rendering.rotateObject(ptr, rot * worldRotQuat);
|
||||||
//physics.rotateObject(ptr);
|
physics.updateRotation(ptr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -190,14 +190,13 @@ namespace MWWorld
|
||||||
void Scene::unloadCell (CellStoreCollection::iterator iter)
|
void Scene::unloadCell (CellStoreCollection::iterator iter)
|
||||||
{
|
{
|
||||||
std::cout << "Unloading cell\n";
|
std::cout << "Unloading cell\n";
|
||||||
ListAndResetHandles functor;
|
ListAndResetObjects functor;
|
||||||
|
|
||||||
(*iter)->forEach<ListAndResetHandles>(functor);
|
(*iter)->forEach<ListAndResetObjects>(functor);
|
||||||
for (std::vector<Ogre::SceneNode*>::const_iterator iter2 (functor.mHandles.begin());
|
for (std::vector<MWWorld::Ptr>::const_iterator iter2 (functor.mObjects.begin());
|
||||||
iter2!=functor.mHandles.end(); ++iter2)
|
iter2!=functor.mObjects.end(); ++iter2)
|
||||||
{
|
{
|
||||||
//Ogre::SceneNode* node = *iter2;
|
mPhysics->remove(*iter2);
|
||||||
//mPhysics->removeObject (node->getName());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((*iter)->getCell()->isExterior())
|
if ((*iter)->getCell()->isExterior())
|
||||||
|
@ -258,17 +257,16 @@ namespace MWWorld
|
||||||
insertCell (*cell, true, loadingListener);
|
insertCell (*cell, true, loadingListener);
|
||||||
|
|
||||||
mRendering.addCell(cell);
|
mRendering.addCell(cell);
|
||||||
#if 0
|
|
||||||
bool waterEnabled = cell->getCell()->hasWater();
|
bool waterEnabled = cell->getCell()->hasWater();
|
||||||
mRendering.setWaterEnabled(waterEnabled);
|
//mRendering.setWaterEnabled(waterEnabled);
|
||||||
if (waterEnabled)
|
if (waterEnabled)
|
||||||
{
|
{
|
||||||
mPhysics->enableWater(cell->getWaterLevel());
|
mPhysics->enableWater(cell->getWaterLevel());
|
||||||
mRendering.setWaterHeight(cell->getWaterLevel());
|
//mRendering.setWaterHeight(cell->getWaterLevel());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
mPhysics->disableWater();
|
mPhysics->disableWater();
|
||||||
#endif
|
|
||||||
if (!cell->isExterior() && !(cell->getCell()->mData.mFlags & ESM::Cell::QuasiEx))
|
if (!cell->isExterior() && !(cell->getCell()->mData.mFlags & ESM::Cell::QuasiEx))
|
||||||
mRendering.configureAmbient(cell->getCell());
|
mRendering.configureAmbient(cell->getCell());
|
||||||
}
|
}
|
||||||
|
@ -564,8 +562,8 @@ namespace MWWorld
|
||||||
{
|
{
|
||||||
MWBase::Environment::get().getMechanicsManager()->remove (ptr);
|
MWBase::Environment::get().getMechanicsManager()->remove (ptr);
|
||||||
MWBase::Environment::get().getSoundManager()->stopSound3D (ptr);
|
MWBase::Environment::get().getSoundManager()->stopSound3D (ptr);
|
||||||
//mPhysics->removeObject (ptr.getRefData().getHandle());
|
mPhysics->remove(ptr);
|
||||||
//mRendering.removeObject (ptr);
|
//Rendering.removeObject (ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Scene::isCellActive(const CellStore &cell)
|
bool Scene::isCellActive(const CellStore &cell)
|
||||||
|
|
|
@ -415,11 +415,11 @@ void WeatherManager::update(float duration, bool paused)
|
||||||
if (mIsStorm)
|
if (mIsStorm)
|
||||||
{
|
{
|
||||||
MWWorld::Ptr player = world->getPlayerPtr();
|
MWWorld::Ptr player = world->getPlayerPtr();
|
||||||
Ogre::Vector3 playerPos (player.getRefData().getPosition().pos);
|
osg::Vec3f playerPos (player.getRefData().getPosition().asVec3());
|
||||||
Ogre::Vector3 redMountainPos (19950, 72032, 27831);
|
osg::Vec3f redMountainPos (19950, 72032, 27831);
|
||||||
|
|
||||||
mStormDirection = (playerPos - redMountainPos);
|
mStormDirection = (playerPos - redMountainPos);
|
||||||
mStormDirection.z = 0;
|
mStormDirection.z() = 0;
|
||||||
//mRendering->getSkyManager()->setStormDirection(mStormDirection);
|
//mRendering->getSkyManager()->setStormDirection(mStormDirection);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -844,7 +844,7 @@ bool WeatherManager::isInStorm() const
|
||||||
return mIsStorm;
|
return mIsStorm;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ogre::Vector3 WeatherManager::getStormDirection() const
|
osg::Vec3f WeatherManager::getStormDirection() const
|
||||||
{
|
{
|
||||||
return mStormDirection;
|
return mStormDirection;
|
||||||
}
|
}
|
||||||
|
|
|
@ -184,7 +184,7 @@ namespace MWWorld
|
||||||
/// Are we in an ash or blight storm?
|
/// Are we in an ash or blight storm?
|
||||||
bool isInStorm() const;
|
bool isInStorm() const;
|
||||||
|
|
||||||
Ogre::Vector3 getStormDirection() const;
|
osg::Vec3f getStormDirection() const;
|
||||||
|
|
||||||
void advanceTime(double hours);
|
void advanceTime(double hours);
|
||||||
|
|
||||||
|
@ -205,7 +205,7 @@ namespace MWWorld
|
||||||
float mHour;
|
float mHour;
|
||||||
float mWindSpeed;
|
float mWindSpeed;
|
||||||
bool mIsStorm;
|
bool mIsStorm;
|
||||||
Ogre::Vector3 mStormDirection;
|
osg::Vec3f mStormDirection;
|
||||||
|
|
||||||
MWBase::SoundPtr mAmbientSound;
|
MWBase::SoundPtr mAmbientSound;
|
||||||
std::string mPlayingSoundID;
|
std::string mPlayingSoundID;
|
||||||
|
|
|
@ -7,8 +7,6 @@
|
||||||
#else
|
#else
|
||||||
#include <tr1/unordered_map>
|
#include <tr1/unordered_map>
|
||||||
#endif
|
#endif
|
||||||
#include "../mwbase/scriptmanager.hpp"
|
|
||||||
#include "../mwscript/globalscripts.hpp"
|
|
||||||
#include <OgreSceneNode.h>
|
#include <OgreSceneNode.h>
|
||||||
|
|
||||||
#include <osg/Group>
|
#include <osg/Group>
|
||||||
|
@ -19,6 +17,7 @@
|
||||||
#include <components/compiler/locals.hpp>
|
#include <components/compiler/locals.hpp>
|
||||||
#include <components/esm/cellid.hpp>
|
#include <components/esm/cellid.hpp>
|
||||||
#include <components/misc/resourcehelpers.hpp>
|
#include <components/misc/resourcehelpers.hpp>
|
||||||
|
#include <components/resource/resourcesystem.hpp>
|
||||||
|
|
||||||
#include <boost/math/special_functions/sign.hpp>
|
#include <boost/math/special_functions/sign.hpp>
|
||||||
|
|
||||||
|
@ -26,6 +25,7 @@
|
||||||
#include "../mwbase/soundmanager.hpp"
|
#include "../mwbase/soundmanager.hpp"
|
||||||
#include "../mwbase/mechanicsmanager.hpp"
|
#include "../mwbase/mechanicsmanager.hpp"
|
||||||
#include "../mwbase/windowmanager.hpp"
|
#include "../mwbase/windowmanager.hpp"
|
||||||
|
#include "../mwbase/scriptmanager.hpp"
|
||||||
|
|
||||||
#include "../mwmechanics/creaturestats.hpp"
|
#include "../mwmechanics/creaturestats.hpp"
|
||||||
#include "../mwmechanics/movement.hpp"
|
#include "../mwmechanics/movement.hpp"
|
||||||
|
@ -39,9 +39,12 @@
|
||||||
#include "../mwrender/renderingmanager.hpp"
|
#include "../mwrender/renderingmanager.hpp"
|
||||||
|
|
||||||
#include "../mwscript/interpretercontext.hpp"
|
#include "../mwscript/interpretercontext.hpp"
|
||||||
|
#include "../mwscript/globalscripts.hpp"
|
||||||
|
|
||||||
#include "../mwclass/door.hpp"
|
#include "../mwclass/door.hpp"
|
||||||
|
|
||||||
|
#include "../mwphysics/physicssystem.hpp"
|
||||||
|
|
||||||
#include "player.hpp"
|
#include "player.hpp"
|
||||||
#include "manualref.hpp"
|
#include "manualref.hpp"
|
||||||
#include "cellstore.hpp"
|
#include "cellstore.hpp"
|
||||||
|
@ -51,7 +54,6 @@
|
||||||
#include "actionteleport.hpp"
|
#include "actionteleport.hpp"
|
||||||
//#include "projectilemanager.hpp"
|
//#include "projectilemanager.hpp"
|
||||||
#include "weather.hpp"
|
#include "weather.hpp"
|
||||||
#include "../mwphysics/physicssystem.hpp"
|
|
||||||
|
|
||||||
#include "contentloader.hpp"
|
#include "contentloader.hpp"
|
||||||
#include "esmloader.hpp"
|
#include "esmloader.hpp"
|
||||||
|
@ -156,7 +158,7 @@ namespace MWWorld
|
||||||
mStartCell (startCell), mStartupScript(startupScript),
|
mStartCell (startCell), mStartupScript(startupScript),
|
||||||
mScriptsEnabled(true)
|
mScriptsEnabled(true)
|
||||||
{
|
{
|
||||||
mPhysics = new MWPhysics::PhysicsSystem(rootNode);
|
mPhysics = new MWPhysics::PhysicsSystem(resourceSystem->getVFS(), rootNode);
|
||||||
//mPhysEngine = mPhysics->getEngine();
|
//mPhysEngine = mPhysics->getEngine();
|
||||||
#if 0
|
#if 0
|
||||||
mProjectileManager.reset(new ProjectileManager(renderer.getScene(), *mPhysEngine));
|
mProjectileManager.reset(new ProjectileManager(renderer.getScene(), *mPhysEngine));
|
||||||
|
@ -1216,7 +1218,7 @@ namespace MWWorld
|
||||||
if (haveToMove && ptr.getRefData().getBaseNode())
|
if (haveToMove && ptr.getRefData().getBaseNode())
|
||||||
{
|
{
|
||||||
mRendering->moveObject(ptr, osg::Vec3f(vec.x, vec.y, vec.z));
|
mRendering->moveObject(ptr, osg::Vec3f(vec.x, vec.y, vec.z));
|
||||||
//mPhysics->moveObject (ptr);
|
mPhysics->updatePosition(ptr);
|
||||||
}
|
}
|
||||||
if (isPlayer)
|
if (isPlayer)
|
||||||
{
|
{
|
||||||
|
@ -1343,9 +1345,9 @@ namespace MWWorld
|
||||||
|
|
||||||
if (force || !isFlying(ptr))
|
if (force || !isFlying(ptr))
|
||||||
{
|
{
|
||||||
//Ogre::Vector3 traced = mPhysics->traceDown(ptr, 500);
|
osg::Vec3f traced = mPhysics->traceDown(ptr, 500);
|
||||||
//if (traced.z < pos.pos[2])
|
if (traced.z() < pos.pos[2])
|
||||||
// pos.pos[2] = traced.z;
|
pos.pos[2] = traced.z();
|
||||||
}
|
}
|
||||||
|
|
||||||
moveObject(ptr, ptr.getCell(), pos.pos[0], pos.pos[1], pos.pos[2]);
|
moveObject(ptr, ptr.getCell(), pos.pos[0], pos.pos[1], pos.pos[2]);
|
||||||
|
@ -1358,8 +1360,8 @@ namespace MWWorld
|
||||||
pos.pos[2] += dist;
|
pos.pos[2] += dist;
|
||||||
actor.getRefData().setPosition(pos);
|
actor.getRefData().setPosition(pos);
|
||||||
|
|
||||||
Ogre::Vector3 traced;// = mPhysics->traceDown(actor, dist*1.1f);
|
osg::Vec3f traced = mPhysics->traceDown(actor, dist*1.1f);
|
||||||
moveObject(actor, actor.getCell(), traced.x, traced.y, traced.z);
|
moveObject(actor, actor.getCell(), traced.x(), traced.y(), traced.z());
|
||||||
}
|
}
|
||||||
|
|
||||||
void World::rotateObject (const Ptr& ptr,float x,float y,float z, bool adjust)
|
void World::rotateObject (const Ptr& ptr,float x,float y,float z, bool adjust)
|
||||||
|
@ -1397,34 +1399,32 @@ namespace MWWorld
|
||||||
cellY = static_cast<int>(std::floor(y / cellSize));
|
cellY = static_cast<int>(std::floor(y / cellSize));
|
||||||
}
|
}
|
||||||
|
|
||||||
void World::queueMovement(const Ptr &ptr, const Ogre::Vector3 &velocity)
|
void World::queueMovement(const Ptr &ptr, const osg::Vec3f &velocity)
|
||||||
{
|
{
|
||||||
//mPhysics->queueObjectMovement(ptr, velocity);
|
mPhysics->queueObjectMovement(ptr, velocity);
|
||||||
}
|
}
|
||||||
|
|
||||||
void World::doPhysics(float duration)
|
void World::doPhysics(float duration)
|
||||||
{
|
{
|
||||||
mPhysics->stepSimulation(duration);
|
mPhysics->stepSimulation(duration);
|
||||||
#if 0
|
|
||||||
processDoors(duration);
|
processDoors(duration);
|
||||||
|
|
||||||
mProjectileManager->update(duration);
|
//mProjectileManager->update(duration);
|
||||||
|
|
||||||
const PtrVelocityList &results = mPhysics->applyQueuedMovement(duration);
|
const MWPhysics::PtrVelocityList &results = mPhysics->applyQueuedMovement(duration);
|
||||||
PtrVelocityList::const_iterator player(results.end());
|
MWPhysics::PtrVelocityList::const_iterator player(results.end());
|
||||||
for(PtrVelocityList::const_iterator iter(results.begin());iter != results.end();++iter)
|
for(MWPhysics::PtrVelocityList::const_iterator iter(results.begin());iter != results.end();++iter)
|
||||||
{
|
{
|
||||||
if(iter->first == getPlayerPtr())
|
if(iter->first == getPlayerPtr())
|
||||||
{
|
{
|
||||||
/* Handle player last, in case a cell transition occurs */
|
// Handle player last, in case a cell transition occurs
|
||||||
player = iter;
|
player = iter;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
moveObjectImp(iter->first, iter->second.x, iter->second.y, iter->second.z);
|
moveObjectImp(iter->first, iter->second.x(), iter->second.y(), iter->second.z());
|
||||||
}
|
}
|
||||||
if(player != results.end())
|
if(player != results.end())
|
||||||
moveObjectImp(player->first, player->second.x, player->second.y, player->second.z);
|
moveObjectImp(player->first, player->second.x(), player->second.y(), player->second.z());
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool World::castRay (float x1, float y1, float z1, float x2, float y2, float z2)
|
bool World::castRay (float x1, float y1, float z1, float x2, float y2, float z2)
|
||||||
|
@ -2312,12 +2312,12 @@ namespace MWWorld
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ogre::Vector3 World::getStormDirection() const
|
osg::Vec3f World::getStormDirection() const
|
||||||
{
|
{
|
||||||
if (isCellExterior() || isCellQuasiExterior())
|
if (isCellExterior() || isCellQuasiExterior())
|
||||||
return mWeatherManager->getStormDirection();
|
return mWeatherManager->getStormDirection();
|
||||||
else
|
else
|
||||||
return Ogre::Vector3(0,1,0);
|
return osg::Vec3f(0,1,0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void World::getContainersOwnedBy (const MWWorld::Ptr& npc, std::vector<MWWorld::Ptr>& out)
|
void World::getContainersOwnedBy (const MWWorld::Ptr& npc, std::vector<MWWorld::Ptr>& out)
|
||||||
|
|
|
@ -380,7 +380,7 @@ namespace MWWorld
|
||||||
virtual void positionToIndex (float x, float y, int &cellX, int &cellY) const;
|
virtual void positionToIndex (float x, float y, int &cellX, int &cellY) const;
|
||||||
///< Convert position to cell numbers
|
///< Convert position to cell numbers
|
||||||
|
|
||||||
virtual void queueMovement(const Ptr &ptr, const Ogre::Vector3 &velocity);
|
virtual void queueMovement(const Ptr &ptr, const osg::Vec3f &velocity);
|
||||||
///< Queues movement for \a ptr (in local space), to be applied in the next call to
|
///< Queues movement for \a ptr (in local space), to be applied in the next call to
|
||||||
/// doPhysics.
|
/// doPhysics.
|
||||||
|
|
||||||
|
@ -650,7 +650,7 @@ namespace MWWorld
|
||||||
virtual bool isInStorm() const;
|
virtual bool isInStorm() const;
|
||||||
|
|
||||||
/// @see MWWorld::WeatherManager::getStormDirection
|
/// @see MWWorld::WeatherManager::getStormDirection
|
||||||
virtual Ogre::Vector3 getStormDirection() const;
|
virtual osg::Vec3f getStormDirection() const;
|
||||||
|
|
||||||
/// Resets all actors in the current active cells to their original location within that cell.
|
/// Resets all actors in the current active cells to their original location within that cell.
|
||||||
virtual void resetActors();
|
virtual void resetActors();
|
||||||
|
|
|
@ -52,9 +52,9 @@ add_component_dir (nifosg
|
||||||
nifloader controller particle userdata
|
nifloader controller particle userdata
|
||||||
)
|
)
|
||||||
|
|
||||||
#add_component_dir (nifbullet
|
add_component_dir (nifbullet
|
||||||
# bulletnifloader
|
bulletnifloader bulletshapemanager
|
||||||
# )
|
)
|
||||||
|
|
||||||
add_component_dir (to_utf8
|
add_component_dir (to_utf8
|
||||||
to_utf8
|
to_utf8
|
||||||
|
@ -171,6 +171,7 @@ target_link_libraries(components
|
||||||
${Boost_LIBRARIES}
|
${Boost_LIBRARIES}
|
||||||
${OGRE_LIBRARIES}
|
${OGRE_LIBRARIES}
|
||||||
${OPENSCENEGRAPH_LIBRARIES}
|
${OPENSCENEGRAPH_LIBRARIES}
|
||||||
|
${BULLET_LIBRARIES}
|
||||||
# For MyGUI platform
|
# For MyGUI platform
|
||||||
${OPENGL_gl_LIBRARY}
|
${OPENGL_gl_LIBRARY}
|
||||||
)
|
)
|
||||||
|
|
|
@ -1,31 +1,11 @@
|
||||||
/*
|
|
||||||
OpenMW - The completely unofficial reimplementation of Morrowind
|
|
||||||
Copyright (C) 2008-2010 Nicolay Korslund
|
|
||||||
Email: < korslund@gmail.com >
|
|
||||||
WWW: http://openmw.sourceforge.net/
|
|
||||||
|
|
||||||
This file (ogre_nif_loader.cpp) is part of the OpenMW package.
|
|
||||||
|
|
||||||
OpenMW is distributed as free software: you can redistribute it
|
|
||||||
and/or modify it under the terms of the GNU General Public License
|
|
||||||
version 3, as published by the Free Software Foundation.
|
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful, but
|
|
||||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
|
||||||
version 3 along with this program. If not, see
|
|
||||||
http://www.gnu.org/licenses/ .
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "bulletnifloader.hpp"
|
#include "bulletnifloader.hpp"
|
||||||
|
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
|
#include <vector>
|
||||||
|
#include <list>
|
||||||
|
#include <iostream>
|
||||||
|
#include <stdexcept>
|
||||||
|
|
||||||
#include <OgreMatrix4.h>
|
|
||||||
#include <components/misc/stringops.hpp>
|
#include <components/misc/stringops.hpp>
|
||||||
|
|
||||||
#include "../nif/niffile.hpp"
|
#include "../nif/niffile.hpp"
|
||||||
|
@ -34,12 +14,7 @@ http://www.gnu.org/licenses/ .
|
||||||
#include "../nif/property.hpp"
|
#include "../nif/property.hpp"
|
||||||
#include "../nif/controller.hpp"
|
#include "../nif/controller.hpp"
|
||||||
#include "../nif/extra.hpp"
|
#include "../nif/extra.hpp"
|
||||||
#include <libs/platform/strings.h>
|
|
||||||
|
|
||||||
#include <vector>
|
|
||||||
#include <list>
|
|
||||||
// For warning messages
|
|
||||||
#include <iostream>
|
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
|
@ -51,53 +26,40 @@ osg::Matrixf getWorldTransform(const Nif::Node *node)
|
||||||
return node->trafo.toMatrix();
|
return node->trafo.toMatrix();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
btVector3 getbtVector(const osg::Vec3f &v)
|
||||||
|
{
|
||||||
|
return btVector3(v.x(), v.y(), v.z());
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace NifBullet
|
namespace NifBullet
|
||||||
{
|
{
|
||||||
|
|
||||||
ManualBulletShapeLoader::~ManualBulletShapeLoader()
|
BulletNifLoader::BulletNifLoader()
|
||||||
|
: mCompoundShape(NULL)
|
||||||
|
, mStaticMesh(NULL)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BulletNifLoader::~BulletNifLoader()
|
||||||
btVector3 ManualBulletShapeLoader::getbtVector(Ogre::Vector3 const &v)
|
|
||||||
{
|
{
|
||||||
return btVector3(v[0], v[1], v[2]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ManualBulletShapeLoader::loadResource(Ogre::Resource *resource)
|
osg::ref_ptr<BulletShape> BulletNifLoader::load(const Nif::NIFFilePtr nif)
|
||||||
{
|
{
|
||||||
mShape = static_cast<OEngine::Physic::BulletShape *>(resource);
|
mShape = new BulletShape;
|
||||||
mResourceName = mShape->getName();
|
|
||||||
mBoundingBox = NULL;
|
|
||||||
mShape->mBoxTranslation = osg::Vec3f(0,0,0);
|
|
||||||
mShape->mBoxRotation = osg::Quat();
|
|
||||||
mCompoundShape = NULL;
|
mCompoundShape = NULL;
|
||||||
mStaticMesh = NULL;
|
mStaticMesh = NULL;
|
||||||
|
|
||||||
Nif::NIFFilePtr pnif;// (Nif::Cache::getInstance().load(mResourceName.substr(0, mResourceName.length()-7)));
|
if (nif->numRoots() < 1)
|
||||||
Nif::NIFFile & nif = *pnif.get ();
|
|
||||||
if (nif.numRoots() < 1)
|
|
||||||
{
|
{
|
||||||
warn("Found no root nodes in NIF.");
|
warn("Found no root nodes in NIF.");
|
||||||
return;
|
return mShape;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Have to load controlled nodes from the .kf
|
Nif::Record *r = nif->getRoot(0);
|
||||||
// FIXME: the .kf has to be loaded both for rendering and physics, ideally it should be opened once and then reused
|
|
||||||
mControlledNodes.clear();
|
|
||||||
std::string kfname = mResourceName.substr(0, mResourceName.length()-7);
|
|
||||||
Misc::StringUtils::toLower(kfname);
|
|
||||||
if(kfname.size() > 4 && kfname.compare(kfname.size()-4, 4, ".nif") == 0)
|
|
||||||
kfname.replace(kfname.size()-4, 4, ".kf");
|
|
||||||
if (Ogre::ResourceGroupManager::getSingleton().resourceExistsInAnyGroup(kfname))
|
|
||||||
{
|
|
||||||
Nif::NIFFilePtr kf;// (Nif::Cache::getInstance().load(kfname));
|
|
||||||
//extractControlledNodes(kf, mControlledNodes);
|
|
||||||
}
|
|
||||||
|
|
||||||
Nif::Record *r = nif.getRoot(0);
|
|
||||||
assert(r != NULL);
|
assert(r != NULL);
|
||||||
|
|
||||||
Nif::Node *node = dynamic_cast<Nif::Node*>(r);
|
Nif::Node *node = dynamic_cast<Nif::Node*>(r);
|
||||||
|
@ -105,29 +67,40 @@ void ManualBulletShapeLoader::loadResource(Ogre::Resource *resource)
|
||||||
{
|
{
|
||||||
warn("First root in file was not a node, but a " +
|
warn("First root in file was not a node, but a " +
|
||||||
r->recName + ". Skipping file.");
|
r->recName + ". Skipping file.");
|
||||||
return;
|
return mShape;
|
||||||
}
|
}
|
||||||
|
|
||||||
mShape->mAutogenerated = hasAutoGeneratedCollision(node);
|
if (findBoundingBox(node))
|
||||||
|
|
||||||
//do a first pass
|
|
||||||
handleNode(node,0,false,false);
|
|
||||||
|
|
||||||
if(mBoundingBox != NULL)
|
|
||||||
{
|
{
|
||||||
mShape->mCollisionShape = mBoundingBox;
|
std::auto_ptr<btCompoundShape> compound (new btCompoundShape);
|
||||||
delete mStaticMesh;
|
|
||||||
if (mCompoundShape)
|
btBoxShape* boxShape = new btBoxShape(getbtVector(mShape->mCollisionBoxHalfExtents));
|
||||||
{
|
btTransform transform = btTransform::getIdentity();
|
||||||
int n = mCompoundShape->getNumChildShapes();
|
transform.setOrigin(getbtVector(mShape->mCollisionBoxTranslate));
|
||||||
for(int i=0; i <n;i++)
|
compound->addChildShape(transform, boxShape);
|
||||||
delete (mCompoundShape->getChildShape(i));
|
|
||||||
delete mCompoundShape;
|
mShape->mCollisionShape = compound.release();
|
||||||
mShape->mAnimatedShapes.clear();
|
return mShape;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
/*
|
||||||
|
// Have to load controlled nodes from the .kf
|
||||||
|
mControlledNodes.clear();
|
||||||
|
std::string kfname = mResourceName.substr(0, mResourceName.length()-7);
|
||||||
|
Misc::StringUtils::toLower(kfname);
|
||||||
|
if(kfname.size() > 4 && kfname.compare(kfname.size()-4, 4, ".nif") == 0)
|
||||||
|
kfname.replace(kfname.size()-4, 4, ".kf");
|
||||||
|
if (Ogre::ResourceGroupManager::getSingleton().resourceExistsInAnyGroup(kfname))
|
||||||
|
{
|
||||||
|
Nif::NIFFilePtr kf;// (Nif::Cache::getInstance().load(kfname));
|
||||||
|
//extractControlledNodes(kf, mControlledNodes);
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
bool autogenerated = hasAutoGeneratedCollision(node);
|
||||||
|
handleNode(node, 0, autogenerated, false, autogenerated);
|
||||||
|
|
||||||
if (mCompoundShape)
|
if (mCompoundShape)
|
||||||
{
|
{
|
||||||
mShape->mCollisionShape = mCompoundShape;
|
mShape->mCollisionShape = mCompoundShape;
|
||||||
|
@ -140,10 +113,46 @@ void ManualBulletShapeLoader::loadResource(Ogre::Resource *resource)
|
||||||
}
|
}
|
||||||
else if (mStaticMesh)
|
else if (mStaticMesh)
|
||||||
mShape->mCollisionShape = new TriangleMeshShape(mStaticMesh,true);
|
mShape->mCollisionShape = new TriangleMeshShape(mStaticMesh,true);
|
||||||
|
|
||||||
|
return mShape;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ManualBulletShapeLoader::hasAutoGeneratedCollision(Nif::Node const * rootNode)
|
// Find a boundingBox in the node hierarchy.
|
||||||
|
// Return: use bounding box for collision?
|
||||||
|
bool BulletNifLoader::findBoundingBox(const Nif::Node* node, int flags)
|
||||||
|
{
|
||||||
|
flags |= node->flags;
|
||||||
|
|
||||||
|
if (node->hasBounds)
|
||||||
|
{
|
||||||
|
mShape->mCollisionBoxHalfExtents = node->boundXYZ;
|
||||||
|
mShape->mCollisionBoxTranslate = node->boundPos;
|
||||||
|
|
||||||
|
if (flags & Nif::NiNode::Flag_BBoxCollision)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const Nif::NiNode *ninode = dynamic_cast<const Nif::NiNode*>(node);
|
||||||
|
if(ninode)
|
||||||
|
{
|
||||||
|
const Nif::NodeList &list = ninode->children;
|
||||||
|
for(size_t i = 0;i < list.length();i++)
|
||||||
|
{
|
||||||
|
if(!list[i].empty())
|
||||||
|
{
|
||||||
|
bool found = findBoundingBox (list[i].getPtr());
|
||||||
|
if (found)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool BulletNifLoader::hasAutoGeneratedCollision(const Nif::Node* rootNode)
|
||||||
{
|
{
|
||||||
const Nif::NiNode *ninode = dynamic_cast<const Nif::NiNode*>(rootNode);
|
const Nif::NiNode *ninode = dynamic_cast<const Nif::NiNode*>(rootNode);
|
||||||
if(ninode)
|
if(ninode)
|
||||||
|
@ -161,8 +170,8 @@ bool ManualBulletShapeLoader::hasAutoGeneratedCollision(Nif::Node const * rootNo
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ManualBulletShapeLoader::handleNode(const Nif::Node *node, int flags,
|
void BulletNifLoader::handleNode(const Nif::Node *node, int flags,
|
||||||
bool isCollisionNode, bool isAnimated)
|
bool isCollisionNode, bool isAnimated, bool autogenerated)
|
||||||
{
|
{
|
||||||
// Accumulate the flags from all the child nodes. This works for all
|
// Accumulate the flags from all the child nodes. This works for all
|
||||||
// the flags we currently use, at least.
|
// the flags we currently use, at least.
|
||||||
|
@ -201,24 +210,21 @@ void ManualBulletShapeLoader::handleNode(const Nif::Node *node, int flags,
|
||||||
// No collision. Use an internal flag setting to mark this.
|
// No collision. Use an internal flag setting to mark this.
|
||||||
flags |= 0x800;
|
flags |= 0x800;
|
||||||
}
|
}
|
||||||
|
else if (sd->string == "MRK" && autogenerated)
|
||||||
|
{
|
||||||
|
// Marker can still have collision if the model explicitely specifies it via a RootCollisionNode.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isCollisionNode || (mShape->mAutogenerated))
|
if (isCollisionNode)
|
||||||
{
|
{
|
||||||
// NOTE: a trishape with hasBounds=true, but no BBoxCollision flag should NOT go through handleNiTriShape!
|
// NOTE: a trishape with hasBounds=true, but no BBoxCollision flag should NOT go through handleNiTriShape!
|
||||||
// It must be ignored completely.
|
// It must be ignored completely.
|
||||||
// (occurs in tr_ex_imp_wall_arch_04.nif)
|
// (occurs in tr_ex_imp_wall_arch_04.nif)
|
||||||
if(node->hasBounds)
|
if(!node->hasBounds && node->recType == Nif::RC_NiTriShape)
|
||||||
{
|
|
||||||
if (flags & Nif::NiNode::Flag_BBoxCollision)
|
|
||||||
{
|
|
||||||
mShape->mBoxTranslation = node->boundPos;
|
|
||||||
//mShape->mBoxRotation = node->boundRot;
|
|
||||||
//mBoundingBox = new btBoxShape(getbtVector(node->boundXYZ));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if(node->recType == Nif::RC_NiTriShape)
|
|
||||||
{
|
{
|
||||||
handleNiTriShape(static_cast<const Nif::NiTriShape*>(node), flags, getWorldTransform(node), isAnimated);
|
handleNiTriShape(static_cast<const Nif::NiTriShape*>(node), flags, getWorldTransform(node), isAnimated);
|
||||||
}
|
}
|
||||||
|
@ -237,7 +243,7 @@ void ManualBulletShapeLoader::handleNode(const Nif::Node *node, int flags,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ManualBulletShapeLoader::handleNiTriShape(const Nif::NiTriShape *shape, int flags, const osg::Matrixf &transform, bool isAnimated)
|
void BulletNifLoader::handleNiTriShape(const Nif::NiTriShape *shape, int flags, const osg::Matrixf &transform, bool isAnimated)
|
||||||
{
|
{
|
||||||
assert(shape != NULL);
|
assert(shape != NULL);
|
||||||
|
|
||||||
|
@ -261,6 +267,7 @@ void ManualBulletShapeLoader::handleNiTriShape(const Nif::NiTriShape *shape, int
|
||||||
if (!shape->skin.empty())
|
if (!shape->skin.empty())
|
||||||
isAnimated = false;
|
isAnimated = false;
|
||||||
|
|
||||||
|
/*
|
||||||
if (isAnimated)
|
if (isAnimated)
|
||||||
{
|
{
|
||||||
if (!mCompoundShape)
|
if (!mCompoundShape)
|
||||||
|
@ -281,7 +288,7 @@ void ManualBulletShapeLoader::handleNiTriShape(const Nif::NiTriShape *shape, int
|
||||||
osg::Vec3f b1 = vertices[triangles[i+0]];
|
osg::Vec3f b1 = vertices[triangles[i+0]];
|
||||||
osg::Vec3f b2 = vertices[triangles[i+1]];
|
osg::Vec3f b2 = vertices[triangles[i+1]];
|
||||||
osg::Vec3f b3 = vertices[triangles[i+2]];
|
osg::Vec3f b3 = vertices[triangles[i+2]];
|
||||||
childMesh->addTriangle(btVector3(b1.x(),b1.y(),b1.z()),btVector3(b2.x(),b2.y(),b2.z()),btVector3(b3.x(),b3.y(),b3.z()));
|
childMesh->addTriangle(getbtVector(b1), getbtVector(b2), getbtVector(b3));
|
||||||
}
|
}
|
||||||
|
|
||||||
TriangleMeshShape* childShape = new TriangleMeshShape(childMesh,true);
|
TriangleMeshShape* childShape = new TriangleMeshShape(childMesh,true);
|
||||||
|
@ -304,9 +311,10 @@ void ManualBulletShapeLoader::handleNiTriShape(const Nif::NiTriShape *shape, int
|
||||||
mCompoundShape->addChildShape(trans, childShape);
|
mCompoundShape->addChildShape(trans, childShape);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
*/
|
||||||
{
|
{
|
||||||
if (!mStaticMesh)
|
if (!mStaticMesh)
|
||||||
mStaticMesh = new btTriangleMesh();
|
mStaticMesh = new btTriangleMesh(false);
|
||||||
|
|
||||||
// Static shape, just transform all vertices into position
|
// Static shape, just transform all vertices into position
|
||||||
const Nif::NiTriShapeData *data = shape->data.getPtr();
|
const Nif::NiTriShapeData *data = shape->data.getPtr();
|
||||||
|
@ -315,61 +323,99 @@ void ManualBulletShapeLoader::handleNiTriShape(const Nif::NiTriShape *shape, int
|
||||||
|
|
||||||
for(size_t i = 0;i < data->triangles.size();i+=3)
|
for(size_t i = 0;i < data->triangles.size();i+=3)
|
||||||
{
|
{
|
||||||
osg::Vec3f b1 = transform*vertices[triangles[i+0]];
|
osg::Vec3f b1 = vertices[triangles[i+0]]*transform;
|
||||||
osg::Vec3f b2 = transform*vertices[triangles[i+1]];
|
osg::Vec3f b2 = vertices[triangles[i+1]]*transform;
|
||||||
osg::Vec3f b3 = transform*vertices[triangles[i+2]];
|
osg::Vec3f b3 = vertices[triangles[i+2]]*transform;
|
||||||
mStaticMesh->addTriangle(btVector3(b1.x(),b1.y(),b1.z()),btVector3(b2.x(),b2.y(),b2.z()),btVector3(b3.x(),b3.y(),b3.z()));
|
mStaticMesh->addTriangle(getbtVector(b1), getbtVector(b2), getbtVector(b3));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool findBoundingBox (const Nif::Node* node, Ogre::Vector3& halfExtents, Ogre::Vector3& translation, Ogre::Quaternion& orientation)
|
BulletShape::BulletShape()
|
||||||
|
: mCollisionShape(NULL)
|
||||||
{
|
{
|
||||||
if(node->hasBounds)
|
|
||||||
{
|
|
||||||
if (!(node->flags & Nif::NiNode::Flag_Hidden))
|
|
||||||
{
|
|
||||||
//translation = node->boundPos;
|
|
||||||
//orientation = node->boundRot;
|
|
||||||
//halfExtents = node->boundXYZ;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const Nif::NiNode *ninode = dynamic_cast<const Nif::NiNode*>(node);
|
|
||||||
if(ninode)
|
|
||||||
{
|
|
||||||
const Nif::NodeList &list = ninode->children;
|
|
||||||
for(size_t i = 0;i < list.length();i++)
|
|
||||||
{
|
|
||||||
if(!list[i].empty())
|
|
||||||
if (findBoundingBox(list[i].getPtr(), halfExtents, translation, orientation))
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool getBoundingBox(const std::string& nifFile, Ogre::Vector3& halfExtents, Ogre::Vector3& translation, Ogre::Quaternion& orientation)
|
BulletShape::~BulletShape()
|
||||||
{
|
{
|
||||||
Nif::NIFFilePtr pnif;// (Nif::Cache::getInstance().load(nifFile));
|
deleteShape(mCollisionShape);
|
||||||
Nif::NIFFile & nif = *pnif.get ();
|
}
|
||||||
|
|
||||||
if (nif.numRoots() < 1)
|
void BulletShape::deleteShape(btCollisionShape* shape)
|
||||||
|
{
|
||||||
|
if(shape!=NULL)
|
||||||
{
|
{
|
||||||
return false;
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
btCollisionShape* BulletShape::duplicateCollisionShape(btCollisionShape *shape) const
|
||||||
|
{
|
||||||
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
Nif::Record *r = nif.getRoot(0);
|
if(btBvhTriangleMeshShape* trishape = dynamic_cast<btBvhTriangleMeshShape*>(shape))
|
||||||
assert(r != NULL);
|
|
||||||
|
|
||||||
Nif::Node *node = dynamic_cast<Nif::Node*>(r);
|
|
||||||
if (node == NULL)
|
|
||||||
{
|
{
|
||||||
return false;
|
#if BT_BULLET_VERSION >= 283
|
||||||
|
btScaledBvhTriangleMeshShape* newShape = new btScaledBvhTriangleMeshShape(trishape, btVector3(1.f, 1.f, 1.f));
|
||||||
|
#else
|
||||||
|
// work around btScaledBvhTriangleMeshShape bug ( https://code.google.com/p/bullet/issues/detail?id=371 ) in older bullet versions
|
||||||
|
btTriangleMesh* oldMesh = static_cast<btTriangleMesh*>(trishape->getMeshInterface());
|
||||||
|
btTriangleMesh* newMesh = new btTriangleMesh(*oldMesh);
|
||||||
|
NifBullet::TriangleMeshShape* newShape = new NifBullet::TriangleMeshShape(newMesh, true);
|
||||||
|
#endif
|
||||||
|
return newShape;
|
||||||
}
|
}
|
||||||
|
|
||||||
return findBoundingBox(node, halfExtents, translation, orientation);
|
if (btBoxShape* boxshape = dynamic_cast<btBoxShape*>(shape))
|
||||||
|
{
|
||||||
|
return new btBoxShape(*boxshape);
|
||||||
|
}
|
||||||
|
|
||||||
|
throw std::logic_error(std::string("Unhandled Bullet shape duplication: ")+shape->getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
btCollisionShape *BulletShape::getCollisionShape()
|
||||||
|
{
|
||||||
|
return mCollisionShape;
|
||||||
|
}
|
||||||
|
|
||||||
|
osg::ref_ptr<BulletShapeInstance> BulletShape::makeInstance()
|
||||||
|
{
|
||||||
|
osg::ref_ptr<BulletShapeInstance> instance (new BulletShapeInstance(this));
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
BulletShapeInstance::BulletShapeInstance(osg::ref_ptr<BulletShape> source)
|
||||||
|
: BulletShape()
|
||||||
|
, mSource(source)
|
||||||
|
{
|
||||||
|
mCollisionBoxHalfExtents = source->mCollisionBoxHalfExtents;
|
||||||
|
mCollisionBoxTranslate = source->mCollisionBoxTranslate;
|
||||||
|
|
||||||
|
if (source->mCollisionShape)
|
||||||
|
mCollisionShape = duplicateCollisionShape(source->mCollisionShape);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace NifBullet
|
} // namespace NifBullet
|
||||||
|
|
|
@ -1,41 +1,22 @@
|
||||||
/*
|
|
||||||
OpenMW - The completely unofficial reimplementation of Morrowind
|
|
||||||
Copyright (C) 2008-2010 Nicolay Korslund
|
|
||||||
Email: < korslund@gmail.com >
|
|
||||||
WWW: http://openmw.sourceforge.net/
|
|
||||||
|
|
||||||
This file (ogre_nif_loader.h) is part of the OpenMW package.
|
|
||||||
|
|
||||||
OpenMW is distributed as free software: you can redistribute it
|
|
||||||
and/or modify it under the terms of the GNU General Public License
|
|
||||||
version 3, as published by the Free Software Foundation.
|
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful, but
|
|
||||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
|
||||||
version 3 along with this program. If not, see
|
|
||||||
http://www.gnu.org/licenses/ .
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef OPENMW_COMPONENTS_NIFBULLET_BULLETNIFLOADER_HPP
|
#ifndef OPENMW_COMPONENTS_NIFBULLET_BULLETNIFLOADER_HPP
|
||||||
#define OPENMW_COMPONENTS_NIFBULLET_BULLETNIFLOADER_HPP
|
#define OPENMW_COMPONENTS_NIFBULLET_BULLETNIFLOADER_HPP
|
||||||
|
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <set>
|
#include <set>
|
||||||
|
#include <iostream>
|
||||||
|
#include <map>
|
||||||
#include <BulletCollision/CollisionShapes/btBvhTriangleMeshShape.h>
|
#include <BulletCollision/CollisionShapes/btBvhTriangleMeshShape.h>
|
||||||
#include <BulletCollision/CollisionShapes/btConvexTriangleMeshShape.h>
|
#include <BulletCollision/CollisionShapes/btConvexTriangleMeshShape.h>
|
||||||
#include <BulletCollision/CollisionShapes/btCompoundShape.h>
|
#include <BulletCollision/CollisionShapes/btCompoundShape.h>
|
||||||
#include <btBulletDynamicsCommon.h>
|
#include <btBulletDynamicsCommon.h>
|
||||||
|
|
||||||
#include <osg/Matrixf>
|
#include <osg/Matrixf>
|
||||||
|
#include <osg/BoundingBox>
|
||||||
|
#include <osg/ref_ptr>
|
||||||
|
#include <osg/Referenced>
|
||||||
|
|
||||||
// For warning messages
|
#include <components/nif/niffile.hpp>
|
||||||
#include <iostream>
|
|
||||||
|
|
||||||
namespace Nif
|
namespace Nif
|
||||||
{
|
{
|
||||||
|
@ -47,6 +28,48 @@ namespace Nif
|
||||||
namespace NifBullet
|
namespace NifBullet
|
||||||
{
|
{
|
||||||
|
|
||||||
|
class BulletShapeInstance;
|
||||||
|
class BulletShape : public osg::Referenced
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
BulletShape();
|
||||||
|
virtual ~BulletShape();
|
||||||
|
|
||||||
|
btCollisionShape* mCollisionShape;
|
||||||
|
|
||||||
|
// Used for actors. Note, ideally actors would use a separate loader - as it is
|
||||||
|
// we have to keep a redundant copy of the actor model around in mCollisionShape, which isn't used.
|
||||||
|
// For now, use one file <-> one resource for simplicity.
|
||||||
|
osg::Vec3f mCollisionBoxHalfExtents;
|
||||||
|
osg::Vec3f mCollisionBoxTranslate;
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
|
||||||
|
osg::ref_ptr<BulletShapeInstance> makeInstance();
|
||||||
|
|
||||||
|
btCollisionShape* duplicateCollisionShape(btCollisionShape* shape) const;
|
||||||
|
|
||||||
|
btCollisionShape* getCollisionShape();
|
||||||
|
|
||||||
|
private:
|
||||||
|
void deleteShape(btCollisionShape* shape);
|
||||||
|
};
|
||||||
|
|
||||||
|
// An instance of a BulletShape that may have its own unique scaling set on the mCollisionShape.
|
||||||
|
// Vertex data is shallow-copied where possible. A ref_ptr to the original shape needs to be held to keep vertex pointers intact.
|
||||||
|
class BulletShapeInstance : public BulletShape
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
BulletShapeInstance(osg::ref_ptr<BulletShape> source);
|
||||||
|
|
||||||
|
private:
|
||||||
|
osg::ref_ptr<BulletShape> mSource;
|
||||||
|
};
|
||||||
|
|
||||||
// Subclass btBhvTriangleMeshShape to auto-delete the meshInterface
|
// Subclass btBhvTriangleMeshShape to auto-delete the meshInterface
|
||||||
struct TriangleMeshShape : public btBvhTriangleMeshShape
|
struct TriangleMeshShape : public btBvhTriangleMeshShape
|
||||||
{
|
{
|
||||||
|
@ -66,18 +89,12 @@ struct TriangleMeshShape : public btBvhTriangleMeshShape
|
||||||
/**
|
/**
|
||||||
*Load bulletShape from NIF files.
|
*Load bulletShape from NIF files.
|
||||||
*/
|
*/
|
||||||
class ManualBulletShapeLoader
|
class BulletNifLoader
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
ManualBulletShapeLoader(bool showMarkers=false)
|
BulletNifLoader();
|
||||||
: mCompoundShape(NULL)
|
|
||||||
, mStaticMesh(NULL)
|
|
||||||
, mBoundingBox(NULL)
|
|
||||||
, mShowMarkers(showMarkers)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual ~ManualBulletShapeLoader();
|
virtual ~BulletNifLoader();
|
||||||
|
|
||||||
void warn(const std::string &msg)
|
void warn(const std::string &msg)
|
||||||
{
|
{
|
||||||
|
@ -90,44 +107,26 @@ public:
|
||||||
abort();
|
abort();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
osg::ref_ptr<BulletShape> load(const Nif::NIFFilePtr file);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
btVector3 getbtVector(Ogre::Vector3 const &v);
|
bool findBoundingBox(const Nif::Node* node, int flags = 0);
|
||||||
|
|
||||||
/**
|
void handleNode(Nif::Node const *node, int flags, bool isCollisionNode, bool isAnimated=false, bool autogenerated=false);
|
||||||
*Parse a node.
|
|
||||||
*/
|
|
||||||
void handleNode(Nif::Node const *node, int flags, bool isCollisionNode, bool isAnimated=false);
|
|
||||||
|
|
||||||
/**
|
|
||||||
*Helper function
|
|
||||||
*/
|
|
||||||
bool hasAutoGeneratedCollision(const Nif::Node *rootNode);
|
bool hasAutoGeneratedCollision(const Nif::Node *rootNode);
|
||||||
|
|
||||||
/**
|
|
||||||
*convert a NiTriShape to a bullet trishape.
|
|
||||||
*/
|
|
||||||
void handleNiTriShape(const Nif::NiTriShape *shape, int flags, const osg::Matrixf& transform, bool isAnimated);
|
void handleNiTriShape(const Nif::NiTriShape *shape, int flags, const osg::Matrixf& transform, bool isAnimated);
|
||||||
|
|
||||||
std::string mResourceName;
|
|
||||||
|
|
||||||
//OEngine::Physic::BulletShape* mShape;//current shape
|
|
||||||
|
|
||||||
btCompoundShape* mCompoundShape;
|
btCompoundShape* mCompoundShape;
|
||||||
|
|
||||||
btTriangleMesh* mStaticMesh;
|
btTriangleMesh* mStaticMesh;
|
||||||
|
|
||||||
btBoxShape *mBoundingBox;
|
|
||||||
|
|
||||||
std::set<std::string> mControlledNodes;
|
std::set<std::string> mControlledNodes;
|
||||||
|
|
||||||
bool mShowMarkers;
|
osg::ref_ptr<BulletShape> mShape;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
bool getBoundingBox(const std::string& nifFile, Ogre::Vector3& halfExtents, Ogre::Vector3& translation, Ogre::Quaternion& orientation);
|
|
||||||
|
|
||||||
bool findBoundingBox(const Nif::Node* node, Ogre::Vector3& halfExtents, Ogre::Vector3& translation, Ogre::Quaternion& orientation);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
47
components/nifbullet/bulletshapemanager.cpp
Normal file
47
components/nifbullet/bulletshapemanager.cpp
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
#include "bulletshapemanager.hpp"
|
||||||
|
|
||||||
|
#include <components/vfs/manager.hpp>
|
||||||
|
|
||||||
|
#include <components/nifbullet/bulletnifloader.hpp>
|
||||||
|
|
||||||
|
namespace NifBullet
|
||||||
|
{
|
||||||
|
|
||||||
|
BulletShapeManager::BulletShapeManager(const VFS::Manager* vfs)
|
||||||
|
: mVFS(vfs)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
BulletShapeManager::~BulletShapeManager()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
osg::ref_ptr<BulletShapeInstance> BulletShapeManager::createInstance(const std::string &name)
|
||||||
|
{
|
||||||
|
std::string normalized = name;
|
||||||
|
mVFS->normalizeFilename(normalized);
|
||||||
|
|
||||||
|
osg::ref_ptr<BulletShape> shape;
|
||||||
|
Index::iterator it = mIndex.find(normalized);
|
||||||
|
if (it == mIndex.end())
|
||||||
|
{
|
||||||
|
Files::IStreamPtr file = mVFS->get(normalized);
|
||||||
|
|
||||||
|
// TODO: add support for non-NIF formats
|
||||||
|
|
||||||
|
BulletNifLoader loader;
|
||||||
|
// might be worth sharing NIFFiles with SceneManager in some way
|
||||||
|
shape = loader.load(Nif::NIFFilePtr(new Nif::NIFFile(file, normalized)));
|
||||||
|
|
||||||
|
mIndex[normalized] = shape;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
shape = it->second;
|
||||||
|
|
||||||
|
osg::ref_ptr<BulletShapeInstance> instance = shape->makeInstance();
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
37
components/nifbullet/bulletshapemanager.hpp
Normal file
37
components/nifbullet/bulletshapemanager.hpp
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
#ifndef OPENMW_COMPONENTS_BULLETSHAPEMANAGER_H
|
||||||
|
#define OPENMW_COMPONENTS_BULLETSHAPEMANAGER_H
|
||||||
|
|
||||||
|
#include <map>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include <osg/ref_ptr>
|
||||||
|
|
||||||
|
namespace VFS
|
||||||
|
{
|
||||||
|
class Manager;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace NifBullet
|
||||||
|
{
|
||||||
|
|
||||||
|
class BulletShape;
|
||||||
|
class BulletShapeInstance;
|
||||||
|
|
||||||
|
class BulletShapeManager
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
BulletShapeManager(const VFS::Manager* vfs);
|
||||||
|
~BulletShapeManager();
|
||||||
|
|
||||||
|
osg::ref_ptr<BulletShapeInstance> createInstance(const std::string& name);
|
||||||
|
|
||||||
|
private:
|
||||||
|
const VFS::Manager* mVFS;
|
||||||
|
|
||||||
|
typedef std::map<std::string, osg::ref_ptr<BulletShape> > Index;
|
||||||
|
Index mIndex;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
Loading…
Reference in a new issue