diff --git a/apps/openmw/mwphysics/actor.hpp b/apps/openmw/mwphysics/actor.hpp index ec1d81fd9..1f5838543 100644 --- a/apps/openmw/mwphysics/actor.hpp +++ b/apps/openmw/mwphysics/actor.hpp @@ -25,6 +25,11 @@ namespace MWPhysics public: virtual ~PtrHolder() {} + void updatePtr(const MWWorld::Ptr& updated) + { + mPtr = updated; + } + protected: MWWorld::Ptr mPtr; }; diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index 9b56a46b8..81fc1e225 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -9,10 +9,12 @@ #include #include -#include +#include #include +#include // FindRecIndexVisitor + #include "../mwbase/world.hpp" #include "../mwbase/environment.hpp" @@ -24,7 +26,6 @@ #include "../mwrender/bulletdebugdraw.hpp" -//#include "../apps/openmw/mwrender/animation.hpp" #include "../mwbase/world.hpp" #include "../mwbase/environment.hpp" @@ -35,57 +36,6 @@ #include "convert.hpp" #include "trace.h" -namespace -{ - -/* -void animateCollisionShapes (std::map& map, btDynamicsWorld* dynamicsWorld) -{ - for (std::map::iterator it = map.begin(); - it != map.end(); ++it) - { - MWWorld::Ptr ptr = MWBase::Environment::get().getWorld()->searchPtrViaHandle(it->first->mName); - if (ptr.isEmpty()) // Shouldn't happen - throw std::runtime_error("can't find Ptr"); - - MWRender::Animation* animation = MWBase::Environment::get().getWorld()->getAnimation(ptr); - if (!animation) - continue; - - OEngine::Physic::AnimatedShapeInstance& instance = it->second; - - std::map& shapes = instance.mAnimatedShapes; - for (std::map::iterator shapeIt = shapes.begin(); - shapeIt != shapes.end(); ++shapeIt) - { - - const std::string& mesh = animation->getObjectRootName(); - int boneHandle = NifOgre::NIFSkeletonLoader::lookupOgreBoneHandle(mesh, shapeIt->first); - Ogre::Node* bone = animation->getNode(boneHandle); - - if (bone == NULL) - continue; - - btCompoundShape* compound = static_cast(instance.mCompound); - - btTransform trans; - trans.setOrigin(BtOgre::Convert::toBullet(bone->_getDerivedPosition()) * compound->getLocalScaling()); - trans.setRotation(BtOgre::Convert::toBullet(bone->_getDerivedOrientation())); - - compound->getChildShape(shapeIt->second)->setLocalScaling( - compound->getLocalScaling() * - BtOgre::Convert::toBullet(bone->_getDerivedScale())); - compound->updateChildTransform(shapeIt->second, trans); - } - - // needed because we used btDynamicsWorld::setForceUpdateAllAabbs(false) - dynamicsWorld->updateSingleAabb(it->first); - } -} - */ - -} - namespace MWPhysics { @@ -569,11 +519,6 @@ namespace MWPhysics 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)); @@ -594,6 +539,47 @@ namespace MWPhysics return mCollisionObject.get(); } + void animateCollisionShapes(btDynamicsWorld* dynamicsWorld) + { + if (mShapeInstance->mAnimatedShapes.empty()) + return; + + assert (mShapeInstance->getCollisionShape()->isCompound()); + + btCompoundShape* compound = dynamic_cast(mShapeInstance->getCollisionShape()); + + for (std::map::const_iterator it = mShapeInstance->mAnimatedShapes.begin(); it != mShapeInstance->mAnimatedShapes.end(); ++it) + { + int recIndex = it->first; + int shapeIndex = it->second; + + NifOsg::FindRecIndexVisitor visitor(recIndex); + mPtr.getRefData().getBaseNode()->accept(visitor); + if (!visitor.mFound) + { + std::cerr << "animateCollisionShapes: Can't find node " << recIndex << std::endl; + return; + } + + osg::NodePath path = visitor.mFoundPath; + path.erase(path.begin()); + osg::Matrixf matrix = osg::computeLocalToWorld(path); + osg::Vec3f scale = matrix.getScale(); + matrix.orthoNormalize(matrix); + + btTransform transform; + transform.setOrigin(toBullet(matrix.getTrans()) * compound->getLocalScaling()); + for (int i=0; i<3; ++i) + for (int j=0; j<3; ++j) + transform.getBasis()[i][j] = matrix(j,i); // NB column/row major difference + + compound->getChildShape(shapeIndex)->setLocalScaling(compound->getLocalScaling() * toBullet(scale)); + compound->updateChildTransform(shapeIndex, transform); + } + + dynamicsWorld->updateSingleAabb(mCollisionObject.get()); + } + private: std::auto_ptr mCollisionObject; osg::ref_ptr mShapeInstance; @@ -601,8 +587,8 @@ namespace MWPhysics // --------------------------------------------------------------- - PhysicsSystem::PhysicsSystem(const VFS::Manager* vfs, osg::ref_ptr parentNode) - : mShapeManager(new NifBullet::BulletShapeManager(vfs)) + PhysicsSystem::PhysicsSystem(Resource::ResourceSystem* resourceSystem, osg::ref_ptr parentNode) + : mShapeManager(new NifBullet::BulletShapeManager(resourceSystem->getVFS(), resourceSystem->getSceneManager())) , mTimeAccum(0.0f) , mWaterEnabled(false) , mWaterHeight(0) @@ -795,6 +781,27 @@ namespace MWPhysics } } + void PhysicsSystem::updatePtr(const MWWorld::Ptr &old, const MWWorld::Ptr &updated) + { + ObjectMap::iterator found = mObjects.find(old); + if (found != mObjects.end()) + { + Object* obj = found->second; + obj->updatePtr(updated); + mObjects.erase(found); + mObjects.insert(std::make_pair(updated, obj)); + } + + ActorMap::iterator foundActor = mActors.find(old); + if (foundActor != mActors.end()) + { + Actor* actor = foundActor->second; + actor->updatePtr(updated); + mActors.erase(foundActor); + mActors.insert(std::make_pair(updated, actor)); + } + } + void PhysicsSystem::updateScale(const MWWorld::Ptr &ptr) { ObjectMap::iterator found = mObjects.find(ptr); @@ -955,7 +962,8 @@ namespace MWPhysics void PhysicsSystem::stepSimulation(float dt) { - //animateCollisionShapes(mEngine->mAnimatedShapes, mDynamicsWorld); + for (ObjectMap::iterator it = mObjects.begin(); it != mObjects.end(); ++it) + it->second->animateCollisionShapes(mDynamicsWorld); // We have nothing to simulate, but character controllers aren't working without this call. Might be related to updating AABBs. mDynamicsWorld->stepSimulation(static_cast(dt), 1, 1 / 60.0f); diff --git a/apps/openmw/mwphysics/physicssystem.hpp b/apps/openmw/mwphysics/physicssystem.hpp index e6bfd7cd2..54cf48ad1 100644 --- a/apps/openmw/mwphysics/physicssystem.hpp +++ b/apps/openmw/mwphysics/physicssystem.hpp @@ -26,9 +26,9 @@ namespace NifBullet class BulletShapeManager; } -namespace VFS +namespace Resource { - class Manager; + class ResourceSystem; } class btSequentialImpulseConstraintSolver; @@ -45,7 +45,7 @@ namespace MWPhysics class PhysicsSystem { public: - PhysicsSystem (const VFS::Manager* vfs, osg::ref_ptr parentNode); + PhysicsSystem (Resource::ResourceSystem* resourceSystem, osg::ref_ptr parentNode); ~PhysicsSystem (); void enableWater(float height); @@ -61,8 +61,7 @@ namespace MWPhysics void updateRotation (const MWWorld::Ptr& ptr); void updatePosition (const MWWorld::Ptr& ptr); - // TODO - //void updatePtr (const MWWorld::Ptr& old, const MWWorld::Ptr& updated); + void updatePtr (const MWWorld::Ptr& old, const MWWorld::Ptr& updated); void addActor (const MWWorld::Ptr& ptr, const std::string& mesh); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 094098a91..c1e31453f 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -17,7 +17,6 @@ #include #include #include -#include #include @@ -158,7 +157,7 @@ namespace MWWorld mStartCell (startCell), mStartupScript(startupScript), mScriptsEnabled(true) { - mPhysics = new MWPhysics::PhysicsSystem(resourceSystem->getVFS(), rootNode); + mPhysics = new MWPhysics::PhysicsSystem(resourceSystem, rootNode); //mPhysEngine = mPhysics->getEngine(); #if 0 mProjectileManager.reset(new ProjectileManager(renderer.getScene(), *mPhysEngine)); diff --git a/components/nifbullet/bulletnifloader.cpp b/components/nifbullet/bulletnifloader.cpp index 62f2d94d8..89daf898a 100644 --- a/components/nifbullet/bulletnifloader.cpp +++ b/components/nifbullet/bulletnifloader.cpp @@ -46,6 +46,11 @@ BulletNifLoader::~BulletNifLoader() { } +void BulletNifLoader::setAnimatedNodes(const std::set &animatedNodes) +{ + mAnimatedNodes = animatedNodes; +} + osg::ref_ptr BulletNifLoader::load(const Nif::NIFFilePtr nif) { mShape = new BulletShape; @@ -84,20 +89,6 @@ osg::ref_ptr BulletNifLoader::load(const Nif::NIFFilePtr nif) } 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); @@ -181,7 +172,7 @@ void BulletNifLoader::handleNode(const Nif::Node *node, int flags, && (node->controller->flags & Nif::NiNode::ControllerFlag_Active)) isAnimated = true; - if (mControlledNodes.find(node->name) != mControlledNodes.end()) + if (mAnimatedNodes.find(node->name) != mAnimatedNodes.end()) isAnimated = true; isCollisionNode = isCollisionNode || (node->recType == Nif::RC_RootCollisionNode); @@ -238,7 +229,7 @@ void BulletNifLoader::handleNode(const Nif::Node *node, int flags, for(size_t i = 0;i < list.length();i++) { if(!list[i].empty()) - handleNode(list[i].getPtr(), flags, isCollisionNode, isAnimated); + handleNode(list[i].getPtr(), flags, isCollisionNode, isAnimated, autogenerated); } } } @@ -267,7 +258,6 @@ void BulletNifLoader::handleNiTriShape(const Nif::NiTriShape *shape, int flags, if (!shape->skin.empty()) isAnimated = false; - /* if (isAnimated) { if (!mCompoundShape) @@ -311,7 +301,6 @@ void BulletNifLoader::handleNiTriShape(const Nif::NiTriShape *shape, int flags, mCompoundShape->addChildShape(trans, childShape); } else - */ { if (!mStaticMesh) mStaticMesh = new btTriangleMesh(false); @@ -414,6 +403,8 @@ BulletShapeInstance::BulletShapeInstance(osg::ref_ptr source) mCollisionBoxHalfExtents = source->mCollisionBoxHalfExtents; mCollisionBoxTranslate = source->mCollisionBoxTranslate; + mAnimatedShapes = source->mAnimatedShapes; + if (source->mCollisionShape) mCollisionShape = duplicateCollisionShape(source->mCollisionShape); } diff --git a/components/nifbullet/bulletnifloader.hpp b/components/nifbullet/bulletnifloader.hpp index d80ab77bd..ae4279f40 100644 --- a/components/nifbullet/bulletnifloader.hpp +++ b/components/nifbullet/bulletnifloader.hpp @@ -107,6 +107,8 @@ public: abort(); } + void setAnimatedNodes(const std::set& animatedNodes); + osg::ref_ptr load(const Nif::NIFFilePtr file); private: @@ -122,7 +124,7 @@ private: btTriangleMesh* mStaticMesh; - std::set mControlledNodes; + std::set mAnimatedNodes; osg::ref_ptr mShape; }; diff --git a/components/nifbullet/bulletshapemanager.cpp b/components/nifbullet/bulletshapemanager.cpp index 6acfdd408..34c64570e 100644 --- a/components/nifbullet/bulletshapemanager.cpp +++ b/components/nifbullet/bulletshapemanager.cpp @@ -4,11 +4,14 @@ #include +#include + namespace NifBullet { -BulletShapeManager::BulletShapeManager(const VFS::Manager* vfs) +BulletShapeManager::BulletShapeManager(const VFS::Manager* vfs, Resource::SceneManager* sceneManager) : mVFS(vfs) + , mSceneManager(sceneManager) { } @@ -31,7 +34,20 @@ osg::ref_ptr BulletShapeManager::createInstance(const std:: // TODO: add support for non-NIF formats + std::string kfname = normalized; + if(kfname.size() > 4 && kfname.compare(kfname.size()-4, 4, ".nif") == 0) + kfname.replace(kfname.size()-4, 4, ".kf"); + std::set animatedNodes; + if (mVFS->exists(kfname)) + { + osg::ref_ptr keyframes = mSceneManager->getKeyframes(normalized); + for (NifOsg::KeyframeHolder::KeyframeControllerMap::const_iterator it = keyframes->mKeyframeControllers.begin(); + it != keyframes->mKeyframeControllers.end(); ++it) + animatedNodes.insert(it->first); + } + BulletNifLoader loader; + loader.setAnimatedNodes(animatedNodes); // might be worth sharing NIFFiles with SceneManager in some way shape = loader.load(Nif::NIFFilePtr(new Nif::NIFFile(file, normalized))); diff --git a/components/nifbullet/bulletshapemanager.hpp b/components/nifbullet/bulletshapemanager.hpp index d9ba3ffbb..9db674d6d 100644 --- a/components/nifbullet/bulletshapemanager.hpp +++ b/components/nifbullet/bulletshapemanager.hpp @@ -11,6 +11,11 @@ namespace VFS class Manager; } +namespace Resource +{ + class SceneManager; +} + namespace NifBullet { @@ -20,13 +25,15 @@ namespace NifBullet class BulletShapeManager { public: - BulletShapeManager(const VFS::Manager* vfs); + BulletShapeManager(const VFS::Manager* vfs, Resource::SceneManager* sceneManager); ~BulletShapeManager(); osg::ref_ptr createInstance(const std::string& name); private: const VFS::Manager* mVFS; + // need to load keyframes to know what nodes are going to be animated + Resource::SceneManager* mSceneManager; typedef std::map > Index; Index mIndex; diff --git a/components/sceneutil/clone.cpp b/components/sceneutil/clone.cpp index eb7e63587..862a070d8 100644 --- a/components/sceneutil/clone.cpp +++ b/components/sceneutil/clone.cpp @@ -18,7 +18,8 @@ namespace SceneUtil { setCopyFlags(osg::CopyOp::DEEP_COPY_NODES // Controller might need different inputs per scene instance - | osg::CopyOp::DEEP_COPY_CALLBACKS); + | osg::CopyOp::DEEP_COPY_CALLBACKS + | osg::CopyOp::DEEP_COPY_USERDATA); } osg::StateSet* CopyOp::operator ()(const osg::StateSet* stateset) const