diff --git a/apps/openmw/mwgui/tradewindow.cpp b/apps/openmw/mwgui/tradewindow.cpp index 1b82d741c..0fd24601a 100644 --- a/apps/openmw/mwgui/tradewindow.cpp +++ b/apps/openmw/mwgui/tradewindow.cpp @@ -32,7 +32,7 @@ namespace MWGui , mBalanceChangePause(0.0) { // items the NPC is wearing should not be for trade - mDisplayEquippedItems = true; + mDisplayEquippedItems = false; MyGUI::ScrollView* itemView; MyGUI::Widget* containerWidget; diff --git a/apps/openmw/mwrender/occlusionquery.cpp b/apps/openmw/mwrender/occlusionquery.cpp index 81a3f4327..eaa155b06 100644 --- a/apps/openmw/mwrender/occlusionquery.cpp +++ b/apps/openmw/mwrender/occlusionquery.cpp @@ -13,9 +13,9 @@ using namespace MWRender; using namespace Ogre; OcclusionQuery::OcclusionQuery(OEngine::Render::OgreRenderer* renderer, SceneNode* sunNode) : - mSunTotalAreaQuery(0), mSunVisibleAreaQuery(0), mSingleObjectQuery(0), mActiveQuery(0), - mDoQuery(0), mSunVisibility(0), mQuerySingleObjectStarted(false), mTestResult(false), - mQuerySingleObjectRequested(false), mWasVisible(false), mObjectWasVisible(false), + mSunTotalAreaQuery(0), mSunVisibleAreaQuery(0), mActiveQuery(0), + mDoQuery(0), mSunVisibility(0), + mWasVisible(false), mBBNode(0), mActive(false) { mRendering = renderer; @@ -26,9 +26,8 @@ OcclusionQuery::OcclusionQuery(OEngine::Render::OgreRenderer* renderer, SceneNod mSunTotalAreaQuery = renderSystem->createHardwareOcclusionQuery(); mSunVisibleAreaQuery = renderSystem->createHardwareOcclusionQuery(); - mSingleObjectQuery = renderSystem->createHardwareOcclusionQuery(); - mSupported = (mSunTotalAreaQuery != 0) && (mSunVisibleAreaQuery != 0) && (mSingleObjectQuery != 0); + mSupported = (mSunTotalAreaQuery != 0) && (mSunVisibleAreaQuery != 0); } catch (Ogre::Exception e) { @@ -56,7 +55,6 @@ OcclusionQuery::OcclusionQuery(OEngine::Render::OgreRenderer* renderer, SceneNod if (sunNode) mBBNode = mSunNode->getParentSceneNode()->createChildSceneNode(); - mObjectNode = mRendering->getScene()->getRootSceneNode()->createChildSceneNode(); mBBNodeReal = mRendering->getScene()->getRootSceneNode()->createChildSceneNode(); mBBQueryTotal = mRendering->getScene()->createBillboardSet(1); @@ -77,16 +75,6 @@ OcclusionQuery::OcclusionQuery(OEngine::Render::OgreRenderer* renderer, SceneNod mBBQueryVisible->setVisibilityFlags(RV_OcclusionQuery); mBBNodeReal->attachObject(mBBQueryVisible); - mBBQuerySingleObject = mRendering->getScene()->createBillboardSet(1); - /// \todo ideally this should occupy exactly 1 pixel on the screen - mBBQuerySingleObject->setCastShadows(false); - mBBQuerySingleObject->setDefaultDimensions(0.003, 0.003); - mBBQuerySingleObject->createBillboard(Vector3::ZERO); - mBBQuerySingleObject->setMaterialName("QueryVisiblePixels"); - mBBQuerySingleObject->setRenderQueueGroup(RQG_OcclusionQuery); - mBBQuerySingleObject->setVisibilityFlags(RV_OcclusionQuery); - mObjectNode->attachObject(mBBQuerySingleObject); - mRendering->getScene()->addRenderObjectListener(this); mRendering->getScene()->addRenderQueueListener(this); mDoQuery = true; @@ -98,9 +86,10 @@ OcclusionQuery::~OcclusionQuery() mRendering->getScene()->removeRenderQueueListener(this); RenderSystem* renderSystem = Root::getSingleton().getRenderSystem(); - if (mSunTotalAreaQuery) renderSystem->destroyHardwareOcclusionQuery(mSunTotalAreaQuery); - if (mSunVisibleAreaQuery) renderSystem->destroyHardwareOcclusionQuery(mSunVisibleAreaQuery); - if (mSingleObjectQuery) renderSystem->destroyHardwareOcclusionQuery(mSingleObjectQuery); + if (mSunTotalAreaQuery) + renderSystem->destroyHardwareOcclusionQuery(mSunTotalAreaQuery); + if (mSunVisibleAreaQuery) + renderSystem->destroyHardwareOcclusionQuery(mSunVisibleAreaQuery); } bool OcclusionQuery::supported() @@ -137,13 +126,6 @@ void OcclusionQuery::notifyRenderSingleObject(Renderable* rend, const Pass* pass mActiveQuery = mSunVisibleAreaQuery; } } - if (mDoQuery == true && rend == mBBQuerySingleObject) - { - mQuerySingleObjectStarted = true; - mQuerySingleObjectRequested = false; - mActiveQuery = mSingleObjectQuery; - mObjectWasVisible = true; - } if (mActiveQuery != NULL) mActiveQuery->beginOcclusionQuery(); @@ -173,13 +155,6 @@ void OcclusionQuery::renderQueueEnded(uint8 queueGroupId, const String& invocati mSunVisibleAreaQuery->beginOcclusionQuery(); mSunVisibleAreaQuery->endOcclusionQuery(); } - if (mObjectWasVisible == false && mDoQuery) - { - mSingleObjectQuery->beginOcclusionQuery(); - mSingleObjectQuery->endOcclusionQuery(); - mQuerySingleObjectStarted = true; - mQuerySingleObjectRequested = false; - } } } @@ -188,7 +163,6 @@ void OcclusionQuery::update(float duration) if (!mSupported) return; mWasVisible = false; - mObjectWasVisible = false; // Adjust the position of the sun billboards according to camera viewing distance // we need to do this to make sure that _everything_ can occlude the sun @@ -209,8 +183,7 @@ void OcclusionQuery::update(float duration) mDoQuery = false; if (!mSunTotalAreaQuery->isStillOutstanding() - && !mSunVisibleAreaQuery->isStillOutstanding() - && !mSingleObjectQuery->isStillOutstanding()) + && !mSunVisibleAreaQuery->isStillOutstanding()) { unsigned int totalPixels; unsigned int visiblePixels; @@ -229,88 +202,13 @@ void OcclusionQuery::update(float duration) if (mSunVisibility > 1) mSunVisibility = 1; } - unsigned int result; - - mSingleObjectQuery->pullOcclusionQuery(&result); - - mTestResult = (result != 0); - - mQuerySingleObjectStarted = false; - mQuerySingleObjectRequested = false; - mDoQuery = true; } } -void OcclusionQuery::occlusionTest(const Ogre::Vector3& position, Ogre::SceneNode* object) -{ - assert( !occlusionTestPending() - && "Occlusion test still pending"); - - mBBQuerySingleObject->setVisible(true); - - mObjectNode->setPosition(position); - // scale proportional to camera distance, in order to always give the billboard the same size in screen-space - mObjectNode->setScale( Vector3(1,1,1)*(position - mRendering->getCamera()->getRealPosition()).length() ); - - mQuerySingleObjectRequested = true; - - mDoQuery = true; -} - -bool OcclusionQuery::occlusionTestPending() -{ - return (mQuerySingleObjectRequested || mQuerySingleObjectStarted); -} - void OcclusionQuery::setSunNode(Ogre::SceneNode* node) { mSunNode = node; if (!mBBNode) mBBNode = node->getParentSceneNode()->createChildSceneNode(); } - -bool OcclusionQuery::getTestResult() -{ - assert( !occlusionTestPending() - && "Occlusion test still pending"); - - return mTestResult; -} - -bool OcclusionQuery::isPotentialOccluder(Ogre::SceneNode* node) -{ - bool result = false; - for (unsigned int i=0; i < node->numAttachedObjects(); ++i) - { - MovableObject* ob = node->getAttachedObject(i); - std::string type = ob->getMovableType(); - if (type == "Entity") - { - Entity* ent = static_cast(ob); - for (unsigned int j=0; j < ent->getNumSubEntities(); ++j) - { - // if any sub entity has a material with depth write off, - // consider the object as not an occluder - MaterialPtr mat = ent->getSubEntity(j)->getMaterial(); - - Material::TechniqueIterator techIt = mat->getTechniqueIterator(); - while (techIt.hasMoreElements()) - { - Technique* tech = techIt.getNext(); - Technique::PassIterator passIt = tech->getPassIterator(); - while (passIt.hasMoreElements()) - { - Pass* pass = passIt.getNext(); - - if (pass->getDepthWriteEnabled() == false) - return false; - else - result = true; - } - } - } - } - } - return result; -} diff --git a/apps/openmw/mwrender/occlusionquery.hpp b/apps/openmw/mwrender/occlusionquery.hpp index c7a5757d3..145d77355 100644 --- a/apps/openmw/mwrender/occlusionquery.hpp +++ b/apps/openmw/mwrender/occlusionquery.hpp @@ -40,31 +40,6 @@ namespace MWRender */ void update(float duration); - /** - * request occlusion test for a billboard at the given position, omitting an entity - * @param position of the billboard in ogre coordinates - * @param object to exclude from the occluders - */ - void occlusionTest(const Ogre::Vector3& position, Ogre::SceneNode* object); - - /** - * @return true if a request is still outstanding - */ - bool occlusionTestPending(); - - /** - * Checks if the objects held by this scenenode - * can be considered as potential occluders - * (which might not be the case when transparency is involved) - * @param Scene node - */ - bool isPotentialOccluder(Ogre::SceneNode* node); - - /** - * @return true if the object tested in the last request was occluded - */ - bool getTestResult(); - float getSunVisibility() const {return mSunVisibility;}; void setSunNode(Ogre::SceneNode* node); @@ -72,33 +47,23 @@ namespace MWRender private: Ogre::HardwareOcclusionQuery* mSunTotalAreaQuery; Ogre::HardwareOcclusionQuery* mSunVisibleAreaQuery; - Ogre::HardwareOcclusionQuery* mSingleObjectQuery; Ogre::HardwareOcclusionQuery* mActiveQuery; Ogre::BillboardSet* mBBQueryVisible; Ogre::BillboardSet* mBBQueryTotal; - Ogre::BillboardSet* mBBQuerySingleObject; Ogre::SceneNode* mSunNode; Ogre::SceneNode* mBBNode; Ogre::SceneNode* mBBNodeReal; float mSunVisibility; - Ogre::SceneNode* mObjectNode; - bool mWasVisible; - bool mObjectWasVisible; - - bool mTestResult; bool mActive; bool mSupported; bool mDoQuery; - bool mQuerySingleObjectRequested; - bool mQuerySingleObjectStarted; - OEngine::Render::OgreRenderer* mRendering; protected: diff --git a/apps/openmw/mwworld/physicssystem.cpp b/apps/openmw/mwworld/physicssystem.cpp index 895517481..7edd20293 100644 --- a/apps/openmw/mwworld/physicssystem.cpp +++ b/apps/openmw/mwworld/physicssystem.cpp @@ -370,7 +370,9 @@ namespace MWWorld Ogre::SceneNode* node = ptr.getRefData().getBaseNode(); handleToMesh[node->getName()] = mesh; OEngine::Physic::RigidBody* body = mEngine->createAndAdjustRigidBody(mesh, node->getName(), node->getScale().x, node->getPosition(), node->getOrientation()); - mEngine->addRigidBody(body); + OEngine::Physic::RigidBody* raycastingBody = mEngine->createAndAdjustRigidBody + (mesh, node->getName(), node->getScale().x, node->getPosition(), node->getOrientation(), 0, 0, true); + mEngine->addRigidBody(body, true, raycastingBody); } void PhysicsSystem::addActor (const Ptr& ptr) @@ -395,9 +397,14 @@ namespace MWWorld Ogre::SceneNode *node = ptr.getRefData().getBaseNode(); const std::string &handle = node->getName(); const Ogre::Vector3 &position = node->getPosition(); + if(OEngine::Physic::RigidBody *body = mEngine->getRigidBody(handle)) body->getWorldTransform().setOrigin(btVector3(position.x,position.y,position.z)); - else if(OEngine::Physic::PhysicActor *physact = mEngine->getCharacter(handle)) + + if(OEngine::Physic::RigidBody *body = mEngine->getRigidBody(handle, true)) + body->getWorldTransform().setOrigin(btVector3(position.x,position.y,position.z)); + + if(OEngine::Physic::PhysicActor *physact = mEngine->getCharacter(handle)) physact->setPosition(position); } @@ -418,6 +425,13 @@ namespace MWWorld else mEngine->boxAdjustExternal(handleToMesh[handle], body, node->getScale().x, node->getPosition(), rotation); } + if (OEngine::Physic::RigidBody* body = mEngine->getRigidBody(handle, true)) + { + if(dynamic_cast(body->getCollisionShape()) == NULL) + body->getWorldTransform().setRotation(btQuaternion(rotation.x, rotation.y, rotation.z, rotation.w)); + else + mEngine->boxAdjustExternal(handleToMesh[handle], body, node->getScale().x, node->getPosition(), rotation); + } } void PhysicsSystem::scaleObject (const Ptr& ptr) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 33a9b52bf..4b06d6a08 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1018,42 +1018,10 @@ namespace MWWorld mRendering->getSkyManager()->setGlare(!mPhysics->castRay(Ogre::Vector3(p[0], p[1], p[2]), sun)); } - // update faced handle (object the player is looking at) - // this uses a mixture of raycasts and occlusion queries. - else // if (mRendering->occlusionQuerySupported()) - { - MWRender::OcclusionQuery* query = mRendering->getOcclusionQuery(); - if (!query->occlusionTestPending()) - { - processFacedQueryResults (query); - beginFacedQueryProcess (query); - } - } + updateFacedHandle (); } - void World::processFacedQueryResults (MWRender::OcclusionQuery* query) - { - // get result of last query - if (mNumFacing == 0) - { - mFacedHandle = ""; - mFacedDistance = FLT_MAX; - } - else if (mNumFacing == 1) - { - bool result = query->getTestResult(); - mFacedHandle = result ? mFaced1Name : ""; - mFacedDistance = result ? mFaced1Distance : FLT_MAX; - } - else if (mNumFacing == 2) - { - bool result = query->getTestResult(); - mFacedHandle = result ? mFaced2Name : mFaced1Name; - mFacedDistance = result ? mFaced1Distance : mFaced1Distance; - } - } - - void World::beginFacedQueryProcess (MWRender::OcclusionQuery* query) + void World::updateFacedHandle () { // send new query // figure out which object we want to test against @@ -1084,93 +1052,14 @@ namespace MWWorld if (results.size() == 0) { - mNumFacing = 0; - } - else if (results.size() == 1) - { - beginSingleFacedQueryProcess (query, results); - } - else - { - beginDoubleFacedQueryProcess (query, results); - } - } - - void World::beginSingleFacedQueryProcess (MWRender::OcclusionQuery* query, std::vector < std::pair < float, std::string > > const & results) - { - mFaced1 = getPtrViaHandle(results.front().second); - mFaced1Name = results.front().second; - mFaced1Distance = results.front().first; - mNumFacing = 1; - - btVector3 p; - if (MWBase::Environment::get().getWindowManager()->isGuiMode()) - { - float x, y; - MWBase::Environment::get().getWindowManager()->getMousePosition(x, y); - p = mPhysics->getRayPoint(results.front().first, x, y); - } - else - p = mPhysics->getRayPoint(results.front().first); - Ogre::Vector3 pos(p.x(), p.y(), p.z()); - Ogre::SceneNode* node = mFaced1.getRefData().getBaseNode(); - - //std::cout << "Num facing 1 : " << mFaced1Name << std::endl; - //std::cout << "Type 1 " << mFaced1.getTypeName() << std::endl; - - query->occlusionTest(pos, node); - } - - void World::beginDoubleFacedQueryProcess (MWRender::OcclusionQuery* query, std::vector < std::pair < float, std::string > > const & results) - { - mFaced1Name = results.at (0).second; - mFaced2Name = results.at (1).second; - mFaced1Distance = results.at (0).first; - mFaced2Distance = results.at (1).first; - mFaced1 = getPtrViaHandle(results.at (0).second); - mFaced2 = getPtrViaHandle(results.at (1).second); - mNumFacing = 2; - - btVector3 p; - if (MWBase::Environment::get().getWindowManager()->isGuiMode()) - { - float x, y; - MWBase::Environment::get().getWindowManager()->getMousePosition(x, y); - p = mPhysics->getRayPoint(results.at (1).first, x, y); + mFacedHandle = ""; + mFacedDistance = FLT_MAX; } else - p = mPhysics->getRayPoint(results.at (1).first); - Ogre::Vector3 pos(p.x(), p.y(), p.z()); - Ogre::SceneNode* node1 = mFaced1.getRefData().getBaseNode(); - Ogre::SceneNode* node2 = mFaced2.getRefData().getBaseNode(); - - // no need to test if the first node is not occluder - if (!query->isPotentialOccluder(node1) && (mFaced1.getTypeName().find("Static") == std::string::npos)) { - mFacedHandle = mFaced1Name; - mFacedDistance = mFaced1Distance; - //std::cout << "node1 Not an occluder" << std::endl; - return; + mFacedHandle = results.front().second; + mFacedDistance = results.front().first; } - - // no need to test if the second object is static (thus cannot be activated) - if (mFaced2.getTypeName().find("Static") != std::string::npos) - { - mFacedHandle = mFaced1Name; - mFacedDistance = mFaced1Distance; - return; - } - - // work around door problems - if (mFaced1.getTypeName().find("Static") != std::string::npos - && mFaced2.getTypeName().find("Door") != std::string::npos) - { - mFacedHandle = mFaced2Name; - mFacedDistance = mFaced2Distance; - return; - } - - query->occlusionTest(pos, node2); } bool World::isCellExterior() const diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index fe4ceff69..e06b89f60 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -97,10 +97,7 @@ namespace MWWorld void updateWindowManager (); void performUpdateSceneQueries (); - void processFacedQueryResults (MWRender::OcclusionQuery* query); - void beginFacedQueryProcess (MWRender::OcclusionQuery* query); - void beginSingleFacedQueryProcess (MWRender::OcclusionQuery* query, std::vector < std::pair < float, std::string > > const & results); - void beginDoubleFacedQueryProcess (MWRender::OcclusionQuery* query, std::vector < std::pair < float, std::string > > const & results); + void updateFacedHandle (); float getMaxActivationDistance (); float getNpcActivationDistance (); diff --git a/components/nifbullet/bulletnifloader.cpp b/components/nifbullet/bulletnifloader.cpp index 91fd6dbcf..192eb9aaf 100644 --- a/components/nifbullet/bulletnifloader.cpp +++ b/components/nifbullet/bulletnifloader.cpp @@ -22,9 +22,11 @@ http://www.gnu.org/licenses/ . */ #include "bulletnifloader.hpp" -#include + #include +#include + #include "../nif/niffile.hpp" #include "../nif/node.hpp" #include "../nif/data.hpp" @@ -46,6 +48,20 @@ typedef unsigned char ubyte; namespace NifBullet { +struct TriangleMeshShape : public btBvhTriangleMeshShape +{ + TriangleMeshShape(btStridingMeshInterface* meshInterface, bool useQuantizedAabbCompression) + : btBvhTriangleMeshShape(meshInterface, useQuantizedAabbCompression) + { + } + + virtual ~TriangleMeshShape() + { + delete getTriangleInfoMap(); + delete m_meshInterface; + } +}; + ManualBulletShapeLoader::~ManualBulletShapeLoader() { } @@ -62,10 +78,11 @@ void ManualBulletShapeLoader::loadResource(Ogre::Resource *resource) resourceName = cShape->getName(); cShape->mCollide = false; mBoundingBox = NULL; - cShape->boxTranslation = Ogre::Vector3(0,0,0); - cShape->boxRotation = Ogre::Quaternion::IDENTITY; + cShape->mBoxTranslation = Ogre::Vector3(0,0,0); + cShape->mBoxRotation = Ogre::Quaternion::IDENTITY; + mHasShape = false; - mTriMesh = new btTriangleMesh(); + btTriangleMesh* mesh1 = new btTriangleMesh(); // Load the NIF. TODO: Wrap this in a try-catch block once we're out // of the early stages of development. Right now we WANT to catch @@ -94,35 +111,43 @@ void ManualBulletShapeLoader::loadResource(Ogre::Resource *resource) bool hasCollisionNode = hasRootCollisionNode(node); //do a first pass - handleNode(node,0,hasCollisionNode,false,false); + handleNode(mesh1, node,0,hasCollisionNode,false,false); - //if collide = false, then it does a second pass which create a shape for raycasting. - if(cShape->mCollide == false) - handleNode(node,0,hasCollisionNode,false,true); + if(mBoundingBox != NULL) + { + cShape->mCollisionShape = mBoundingBox; + delete mesh1; + } + else if (mHasShape && !cShape->mIgnore && cShape->mCollide) + { + cShape->mCollisionShape = new TriangleMeshShape(mesh1,true); + } + else + delete mesh1; - //cShape->collide = hasCollisionNode&&cShape->collide; + //second pass which create a shape for raycasting. + resourceName = cShape->getName(); + cShape->mCollide = false; + mBoundingBox = NULL; + cShape->mBoxTranslation = Ogre::Vector3(0,0,0); + cShape->mBoxRotation = Ogre::Quaternion::IDENTITY; + mHasShape = false; - struct TriangleMeshShape : public btBvhTriangleMeshShape - { - TriangleMeshShape(btStridingMeshInterface* meshInterface, bool useQuantizedAabbCompression) - : btBvhTriangleMeshShape(meshInterface, useQuantizedAabbCompression) - { - } + btTriangleMesh* mesh2 = new btTriangleMesh(); - virtual ~TriangleMeshShape() - { - delete getTriangleInfoMap(); - delete m_meshInterface; - } - }; + handleNode(mesh2, node,0,hasCollisionNode,true,true); if(mBoundingBox != NULL) - cShape->Shape = mBoundingBox; - else { - currentShape = new TriangleMeshShape(mTriMesh,true); - cShape->Shape = currentShape; + cShape->mRaycastingShape = mBoundingBox; + delete mesh2; + } + else if (mHasShape && !cShape->mIgnore) + { + cShape->mRaycastingShape = new TriangleMeshShape(mesh2,true); } + else + delete mesh2; } bool ManualBulletShapeLoader::hasRootCollisionNode(Nif::Node const * node) @@ -147,22 +172,26 @@ bool ManualBulletShapeLoader::hasRootCollisionNode(Nif::Node const * node) return false; } -void ManualBulletShapeLoader::handleNode(const Nif::Node *node, int flags, +void ManualBulletShapeLoader::handleNode(btTriangleMesh* mesh, const Nif::Node *node, int flags, bool hasCollisionNode, bool isCollisionNode, - bool raycastingOnly) + bool raycasting) { // Accumulate the flags from all the child nodes. This works for all // the flags we currently use, at least. flags |= node->flags; - isCollisionNode = isCollisionNode || (node->recType == Nif::RC_RootCollisionNode); + if (!raycasting) + isCollisionNode = isCollisionNode || (node->recType == Nif::RC_RootCollisionNode); + else + isCollisionNode = isCollisionNode && (node->recType != Nif::RC_RootCollisionNode); // Marker objects: no collision /// \todo don't do this in the editor - if (node->name.find("marker") != std::string::npos) + std::string nodename = node->name; + boost::algorithm::to_lower(nodename); + if (nodename.find("marker") != std::string::npos) { - flags |= 0x800; - cShape->mIgnore = true; + return; } // Check for extra data @@ -185,7 +214,7 @@ void ManualBulletShapeLoader::handleNode(const Nif::Node *node, int flags, // No collision. Use an internal flag setting to mark this. flags |= 0x800; } - else if (sd->string == "MRK" && !raycastingOnly) + else if (sd->string == "MRK") // Marker objects. These are only visible in the // editor. Until and unless we add an editor component to // the engine, just skip this entire node. @@ -193,20 +222,16 @@ void ManualBulletShapeLoader::handleNode(const Nif::Node *node, int flags, } } - if(!hasCollisionNode || isCollisionNode) + if(node->hasBounds) { - if(node->hasBounds) - { - cShape->boxTranslation = node->boundPos; - cShape->boxRotation = node->boundRot; - mBoundingBox = new btBoxShape(getbtVector(node->boundXYZ)); - } - - if(node->recType == Nif::RC_NiTriShape) - { - cShape->mCollide = !(flags&0x800); - handleNiTriShape(static_cast(node), flags, node->getWorldTransform(), raycastingOnly); - } + cShape->mBoxTranslation = node->boundPos; + cShape->mBoxRotation = node->boundRot; + mBoundingBox = new btBoxShape(getbtVector(node->boundXYZ)); + } + else if( (isCollisionNode || (!hasCollisionNode && !raycasting)) && node->recType == Nif::RC_NiTriShape) + { + cShape->mCollide = !(flags&0x800); + handleNiTriShape(mesh, static_cast(node), flags, node->getWorldTransform(), raycasting); } // For NiNodes, loop through children @@ -217,13 +242,13 @@ void ManualBulletShapeLoader::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, hasCollisionNode, isCollisionNode, raycastingOnly); + handleNode(mesh, list[i].getPtr(), flags, hasCollisionNode, isCollisionNode, raycasting); } } } -void ManualBulletShapeLoader::handleNiTriShape(const Nif::NiTriShape *shape, int flags, const Ogre::Matrix4 &transform, - bool raycastingOnly) +void ManualBulletShapeLoader::handleNiTriShape(btTriangleMesh* mesh, const Nif::NiTriShape *shape, int flags, const Ogre::Matrix4 &transform, + bool raycasting) { assert(shape != NULL); @@ -234,18 +259,19 @@ void ManualBulletShapeLoader::handleNiTriShape(const Nif::NiTriShape *shape, int // If the object was marked "NCO" earlier, it shouldn't collide with // anything. So don't do anything. - if (flags & 0x800 && !raycastingOnly) + if ((flags & 0x800) && !raycasting) { collide = false; bbcollide = false; return; } - if (!collide && !bbcollide && hidden && !raycastingOnly) + if (!collide && !bbcollide && hidden && !raycasting) // This mesh apparently isn't being used for anything, so don't // bother setting it up. return; + mHasShape = true; const Nif::NiTriShapeData *data = shape->data.getPtr(); const std::vector &vertices = data->vertices; @@ -255,7 +281,7 @@ void ManualBulletShapeLoader::handleNiTriShape(const Nif::NiTriShape *shape, int Ogre::Vector3 b1 = transform*vertices[triangles[i+0]]; Ogre::Vector3 b2 = transform*vertices[triangles[i+1]]; Ogre::Vector3 b3 = transform*vertices[triangles[i+2]]; - mTriMesh->addTriangle(btVector3(b1.x,b1.y,b1.z),btVector3(b2.x,b2.y,b2.z),btVector3(b3.x,b3.y,b3.z)); + mesh->addTriangle(btVector3(b1.x,b1.y,b1.z),btVector3(b2.x,b2.y,b2.z),btVector3(b3.x,b3.y,b3.z)); } } diff --git a/components/nifbullet/bulletnifloader.hpp b/components/nifbullet/bulletnifloader.hpp index 0ff4b4ccd..9cb5a3e86 100644 --- a/components/nifbullet/bulletnifloader.hpp +++ b/components/nifbullet/bulletnifloader.hpp @@ -24,13 +24,12 @@ #ifndef OPENMW_COMPONENTS_NIFBULLET_BULLETNIFLOADER_HPP #define OPENMW_COMPONENTS_NIFBULLET_BULLETNIFLOADER_HPP -#include #include #include #include #include #include -#include "openengine/bullet/BulletShapeLoader.h" +#include // For warning messages #include @@ -83,7 +82,7 @@ private: /** *Parse a node. */ - void handleNode(Nif::Node const *node, int flags, bool hasCollisionNode, bool isCollisionNode, bool raycastingOnly); + void handleNode(btTriangleMesh* mesh, Nif::Node const *node, int flags, bool hasCollisionNode, bool isCollisionNode, bool raycasting); /** *Helper function @@ -93,15 +92,15 @@ private: /** *convert a NiTriShape to a bullet trishape. */ - void handleNiTriShape(const Nif::NiTriShape *shape, int flags, const Ogre::Matrix4 &transform, bool raycastingOnly); + void handleNiTriShape(btTriangleMesh* mesh, const Nif::NiTriShape *shape, int flags, const Ogre::Matrix4 &transform, bool raycasting); std::string resourceName; std::string resourceGroup; OEngine::Physic::BulletShape* cShape;//current shape - btTriangleMesh *mTriMesh; btBoxShape *mBoundingBox; - btBvhTriangleMeshShape* currentShape;//the shape curently under construction + + bool mHasShape; }; } diff --git a/libs/openengine/bullet/BulletShapeLoader.cpp b/libs/openengine/bullet/BulletShapeLoader.cpp index 071a5ee8a..8744c4e4d 100644 --- a/libs/openengine/bullet/BulletShapeLoader.cpp +++ b/libs/openengine/bullet/BulletShapeLoader.cpp @@ -17,7 +17,8 @@ Ogre::Resource(creator, name, handle, group, isManual, loader) list all the options that need to be set before loading, of which we have none as such. Full details can be set through scripts. */ - Shape = NULL; + mCollisionShape = NULL; + mRaycastingShape = NULL; mCollide = true; mIgnore = false; createParamDictionary("BulletShape"); @@ -25,7 +26,8 @@ Ogre::Resource(creator, name, handle, group, isManual, loader) BulletShape::~BulletShape() { - deleteShape(Shape); + deleteShape(mCollisionShape); + deleteShape(mRaycastingShape); } // farm out to BulletShapeLoader @@ -34,27 +36,28 @@ void BulletShape::loadImpl() mLoader->loadResource(this); } -void BulletShape::deleteShape(btCollisionShape* mShape) +void BulletShape::deleteShape(btCollisionShape* shape) { - if(mShape!=NULL) + if(shape!=NULL) { - if(mShape->isCompound()) + if(shape->isCompound()) { - btCompoundShape* ms = static_cast(Shape); + btCompoundShape* ms = static_cast(mCollisionShape); int a = ms->getNumChildShapes(); for(int i=0; i getChildShape(i)); } } - delete mShape; + delete shape; } - mShape = NULL; + shape = NULL; } void BulletShape::unloadImpl() { - deleteShape(Shape); + deleteShape(mCollisionShape); + deleteShape(mRaycastingShape); } //TODO:change this? diff --git a/libs/openengine/bullet/BulletShapeLoader.h b/libs/openengine/bullet/BulletShapeLoader.h index d9bd5879a..fa03b0276 100644 --- a/libs/openengine/bullet/BulletShapeLoader.h +++ b/libs/openengine/bullet/BulletShapeLoader.h @@ -22,7 +22,7 @@ protected: void unloadImpl(); size_t calculateSize() const; - void deleteShape(btCollisionShape* mShape); + void deleteShape(btCollisionShape* shape); public: @@ -32,9 +32,11 @@ public: virtual ~BulletShape(); - btCollisionShape* Shape; - Ogre::Vector3 boxTranslation; - Ogre::Quaternion boxRotation; + btCollisionShape* mCollisionShape; + btCollisionShape* mRaycastingShape; + + Ogre::Vector3 mBoxTranslation; + Ogre::Quaternion mBoxRotation; //this flag indicate if the shape is used for collision or if it's for raycasting only. bool mCollide; diff --git a/libs/openengine/bullet/physic.cpp b/libs/openengine/bullet/physic.cpp index e5d7c367f..c4947af1e 100644 --- a/libs/openengine/bullet/physic.cpp +++ b/libs/openengine/bullet/physic.cpp @@ -25,11 +25,10 @@ namespace Physic if(name == "player") collisionMode = false; mBody = mEngine->createAndAdjustRigidBody(mMesh, mName, scale, position, rotation, &mBoxScaledTranslation, &mBoxRotation); + mRaycastingBody = mEngine->createAndAdjustRigidBody(mMesh, mName, scale, position, rotation, &mBoxScaledTranslation, &mBoxRotation, true); Ogre::Quaternion inverse = mBoxRotation.Inverse(); mBoxRotationInverse = btQuaternion(inverse.x, inverse.y, inverse.z,inverse.w); - mEngine->addRigidBody(mBody, false); //Add rigid body to dynamics world, but do not add to object map - //mBody->setCollisionFlags(COL_NOTHING); - //mBody->setMas + mEngine->addRigidBody(mBody, false, mRaycastingBody); //Add rigid body to dynamics world, but do not add to object map } PhysicActor::~PhysicActor() @@ -39,6 +38,11 @@ namespace Physic mEngine->dynamicsWorld->removeRigidBody(mBody); delete mBody; } + if(mRaycastingBody) + { + mEngine->dynamicsWorld->removeRigidBody(mRaycastingBody); + delete mRaycastingBody; + } } void PhysicActor::enableCollisions(bool collision) @@ -52,13 +56,18 @@ namespace Physic void PhysicActor::setPosition(const Ogre::Vector3 &pos) { if(pos != getPosition()) + { mEngine->adjustRigidBody(mBody, pos, getRotation(), mBoxScaledTranslation, mBoxRotation); + mEngine->adjustRigidBody(mRaycastingBody, pos, getRotation(), mBoxScaledTranslation, mBoxRotation); + } } void PhysicActor::setRotation(const Ogre::Quaternion &quat) { if(!quat.equals(getRotation(), Ogre::Radian(0))){ mEngine->adjustRigidBody(mBody, getPosition(), quat, mBoxScaledTranslation, mBoxRotation); + mEngine->adjustRigidBody(mRaycastingBody, getPosition(), quat, mBoxScaledTranslation, mBoxRotation); + } } @@ -135,7 +144,6 @@ namespace Physic RigidBody::RigidBody(btRigidBody::btRigidBodyConstructionInfo& CI,std::string name) : btRigidBody(CI) , mName(name) - , mIgnore(false) { } @@ -226,8 +234,19 @@ namespace Physic delete hf_it->second.mBody; } - RigidBodyContainer::iterator rb_it = ObjectMap.begin(); - for (; rb_it != ObjectMap.end(); ++rb_it) + RigidBodyContainer::iterator rb_it = mCollisionObjectMap.begin(); + for (; rb_it != mCollisionObjectMap.end(); ++rb_it) + { + if (rb_it->second != NULL) + { + dynamicsWorld->removeRigidBody(rb_it->second); + + delete rb_it->second; + rb_it->second = NULL; + } + } + rb_it = mRaycastingObjectMap.begin(); + for (; rb_it != mRaycastingObjectMap.end(); ++rb_it) { if (rb_it->second != NULL) { @@ -243,8 +262,6 @@ namespace Physic { if (pa_it->second != NULL) { - - delete pa_it->second; pa_it->second = NULL; } @@ -296,7 +313,6 @@ namespace Physic btRigidBody::btRigidBodyConstructionInfo CI = btRigidBody::btRigidBodyConstructionInfo(0,newMotionState,hfShape); RigidBody* body = new RigidBody(CI,name); - body->mCollide = true; body->getWorldTransform().setOrigin(btVector3( (x+0.5)*triSize*(sqrtVerts-1), (y+0.5)*triSize*(sqrtVerts-1), (maxh+minh)/2.f)); HeightField hf; @@ -347,12 +363,12 @@ namespace Physic BulletShapeManager::getSingletonPtr()->load(outputstring,"General"); BulletShapePtr shape = BulletShapeManager::getSingleton().getByName(outputstring,"General"); - adjustRigidBody(body, position, rotation, shape->boxTranslation * scale, shape->boxRotation); + adjustRigidBody(body, position, rotation, shape->mBoxTranslation * scale, shape->mBoxRotation); } RigidBody* PhysicEngine::createAndAdjustRigidBody(const std::string &mesh, const std::string &name, float scale, const Ogre::Vector3 &position, const Ogre::Quaternion &rotation, - Ogre::Vector3* scaledBoxTranslation, Ogre::Quaternion* boxRotation) + Ogre::Vector3* scaledBoxTranslation, Ogre::Quaternion* boxRotation, bool raycasting) { std::string sid = (boost::format("%07.3f") % scale).str(); std::string outputstring = mesh + sid; @@ -361,72 +377,77 @@ namespace Physic mShapeLoader->load(outputstring,"General"); BulletShapeManager::getSingletonPtr()->load(outputstring,"General"); BulletShapePtr shape = BulletShapeManager::getSingleton().getByName(outputstring,"General"); - shape->Shape->setLocalScaling( btVector3(scale,scale,scale)); + if (!shape->mCollisionShape && !raycasting) + return NULL; + if (!shape->mRaycastingShape && raycasting) + return NULL; + + if (!raycasting) + shape->mCollisionShape->setLocalScaling( btVector3(scale,scale,scale)); + else + shape->mRaycastingShape->setLocalScaling( btVector3(scale,scale,scale)); //create the motionState CMotionState* newMotionState = new CMotionState(this,name); //create the real body - btRigidBody::btRigidBodyConstructionInfo CI = btRigidBody::btRigidBodyConstructionInfo(0,newMotionState,shape->Shape); + btRigidBody::btRigidBodyConstructionInfo CI = btRigidBody::btRigidBodyConstructionInfo + (0,newMotionState, raycasting ? shape->mRaycastingShape : shape->mCollisionShape); RigidBody* body = new RigidBody(CI,name); - body->mCollide = shape->mCollide; - body->mIgnore = shape->mIgnore; if(scaledBoxTranslation != 0) - *scaledBoxTranslation = shape->boxTranslation * scale; + *scaledBoxTranslation = shape->mBoxTranslation * scale; if(boxRotation != 0) - *boxRotation = shape->boxRotation; + *boxRotation = shape->mBoxRotation; - adjustRigidBody(body, position, rotation, shape->boxTranslation * scale, shape->boxRotation); + adjustRigidBody(body, position, rotation, shape->mBoxTranslation * scale, shape->mBoxRotation); return body; } - void PhysicEngine::addRigidBody(RigidBody* body, bool addToMap) + void PhysicEngine::addRigidBody(RigidBody* body, bool addToMap, RigidBody* raycastingBody) { - if(body) - { - if (body->mIgnore) - return; - if(body->mCollide) - { - dynamicsWorld->addRigidBody(body,CollisionType_World,CollisionType_World|CollisionType_ActorInternal|CollisionType_ActorExternal); - } - else - { - dynamicsWorld->addRigidBody(body,CollisionType_Raycasting,CollisionType_Raycasting|CollisionType_World); - } - body->setActivationState(DISABLE_DEACTIVATION); - if(addToMap){ - RigidBody* oldBody = ObjectMap[body->mName]; - if (oldBody != NULL) - { - dynamicsWorld->removeRigidBody(oldBody); - delete oldBody; - } - - ObjectMap[body->mName] = body; - } + if(!body && !raycastingBody) + return; // nothing to do + + const std::string& name = (body ? body->mName : raycastingBody->mName); + + if (body) + dynamicsWorld->addRigidBody(body,CollisionType_World,CollisionType_World|CollisionType_ActorInternal|CollisionType_ActorExternal); + + if (raycastingBody) + dynamicsWorld->addRigidBody(raycastingBody,CollisionType_Raycasting,CollisionType_Raycasting|CollisionType_World); + + if(addToMap){ + removeRigidBody(name); + deleteRigidBody(name); + + if (body) + mCollisionObjectMap[name] = body; + if (raycastingBody) + mRaycastingObjectMap[name] = raycastingBody; } } void PhysicEngine::removeRigidBody(const std::string &name) { - RigidBodyContainer::iterator it = ObjectMap.find(name); - if (it != ObjectMap.end() ) + RigidBodyContainer::iterator it = mCollisionObjectMap.find(name); + if (it != mCollisionObjectMap.end() ) + { + RigidBody* body = it->second; + if(body != NULL) + { + dynamicsWorld->removeRigidBody(body); + } + } + it = mRaycastingObjectMap.find(name); + if (it != mRaycastingObjectMap.end() ) { RigidBody* body = it->second; if(body != NULL) { - // broadphase->getOverlappingPairCache()->removeOverlappingPairsContainingProxy(body->getBroadphaseProxy(),dispatcher); - /*PhysicActorContainer::iterator it2 = PhysicActorMap.begin(); - for(;it2!=PhysicActorMap.end();it++) - { - it2->second->internalGhostObject->getOverlappingPairCache()->removeOverlappingPairsContainingProxy(body->getBroadphaseProxy(),dispatcher); - it2->second->externalGhostObject->getOverlappingPairCache()->removeOverlappingPairsContainingProxy(body->getBroadphaseProxy(),dispatcher); - }*/ dynamicsWorld->removeRigidBody(body); } } @@ -434,35 +455,42 @@ namespace Physic void PhysicEngine::deleteRigidBody(const std::string &name) { - RigidBodyContainer::iterator it = ObjectMap.find(name); - if (it != ObjectMap.end() ) + RigidBodyContainer::iterator it = mCollisionObjectMap.find(name); + if (it != mCollisionObjectMap.end() ) { RigidBody* body = it->second; - //btScaledBvhTriangleMeshShape* scaled = dynamic_cast (body->getCollisionShape()); if(body != NULL) { delete body; } - /*if(scaled != NULL) + mCollisionObjectMap.erase(it); + } + it = mRaycastingObjectMap.find(name); + if (it != mRaycastingObjectMap.end() ) + { + RigidBody* body = it->second; + + if(body != NULL) { - delete scaled; - }*/ - ObjectMap.erase(it); + delete body; + } + mRaycastingObjectMap.erase(it); } } - RigidBody* PhysicEngine::getRigidBody(const std::string &name) + RigidBody* PhysicEngine::getRigidBody(const std::string &name, bool raycasting) { - RigidBodyContainer::iterator it = ObjectMap.find(name); - if (it != ObjectMap.end() ) + RigidBodyContainer* map = raycasting ? &mRaycastingObjectMap : &mCollisionObjectMap; + RigidBodyContainer::iterator it = map->find(name); + if (it != map->end() ) { - RigidBody* body = ObjectMap[name]; + RigidBody* body = (*map)[name]; return body; } else { - return 0; + return NULL; } } @@ -530,7 +558,7 @@ namespace Physic float d1 = 10000.; btCollisionWorld::ClosestRayResultCallback resultCallback1(from, to); - resultCallback1.m_collisionFilterMask = CollisionType_World|CollisionType_Raycasting; + resultCallback1.m_collisionFilterMask = CollisionType_Raycasting; dynamicsWorld->rayTest(from, to, resultCallback1); if (resultCallback1.hasHit()) { @@ -539,35 +567,16 @@ namespace Physic d = d1; } - btCollisionWorld::ClosestRayResultCallback resultCallback2(from, to); - resultCallback2.m_collisionFilterMask = CollisionType_ActorInternal|CollisionType_ActorExternal; - dynamicsWorld->rayTest(from, to, resultCallback2); - float d2 = 10000.; - if (resultCallback2.hasHit()) - { - d2 = resultCallback1.m_closestHitFraction; - if(d2<=d1) - { - name = static_cast(*resultCallback2.m_collisionObject).mName; - d = d2; - } - } - return std::pair(name,d); } std::vector< std::pair > PhysicEngine::rayTest2(btVector3& from, btVector3& to) { MyRayResultCallback resultCallback1; - resultCallback1.m_collisionFilterMask = CollisionType_World|CollisionType_Raycasting; + resultCallback1.m_collisionFilterMask = CollisionType_Raycasting; dynamicsWorld->rayTest(from, to, resultCallback1); std::vector< std::pair > results = resultCallback1.results; - MyRayResultCallback resultCallback2; - resultCallback2.m_collisionFilterMask = CollisionType_ActorInternal|CollisionType_ActorExternal; - dynamicsWorld->rayTest(from, to, resultCallback2); - std::vector< std::pair > actorResults = resultCallback2.results; - std::vector< std::pair > results2; for (std::vector< std::pair >::iterator it=results.begin(); @@ -576,12 +585,6 @@ namespace Physic results2.push_back( std::make_pair( (*it).first, static_cast(*(*it).second).mName ) ); } - for (std::vector< std::pair >::iterator it=actorResults.begin(); - it != actorResults.end(); ++it) - { - results2.push_back( std::make_pair( (*it).first, static_cast(*(*it).second).mName ) ); - } - std::sort(results2.begin(), results2.end(), MyRayResultCallback::cmp); return results2; @@ -600,6 +603,6 @@ namespace Physic btTransform trans; trans.setIdentity(); - shape->Shape->getAabb(trans, min, max); + shape->mCollisionShape->getAabb(trans, min, max); } }} diff --git a/libs/openengine/bullet/physic.hpp b/libs/openengine/bullet/physic.hpp index 97fbbcea4..367db261f 100644 --- a/libs/openengine/bullet/physic.hpp +++ b/libs/openengine/bullet/physic.hpp @@ -141,6 +141,7 @@ namespace Physic private: OEngine::Physic::RigidBody* mBody; + OEngine::Physic::RigidBody* mRaycastingBody; Ogre::Vector3 mBoxScaledTranslation; btQuaternion mBoxRotationInverse; Ogre::Quaternion mBoxRotation; @@ -163,10 +164,6 @@ namespace Physic RigidBody(btRigidBody::btRigidBodyConstructionInfo& CI,std::string name); virtual ~RigidBody(); std::string mName; - - //is this body used for raycasting only? - bool mCollide; - bool mIgnore; }; struct HeightField @@ -200,7 +197,7 @@ namespace Physic */ RigidBody* createAndAdjustRigidBody(const std::string &mesh, const std::string &name, float scale, const Ogre::Vector3 &position, const Ogre::Quaternion &rotation, - Ogre::Vector3* scaledBoxTranslation = 0, Ogre::Quaternion* boxRotation = 0); + Ogre::Vector3* scaledBoxTranslation = 0, Ogre::Quaternion* boxRotation = 0, bool raycasting=false); /** * Adjusts a rigid body to the right position and rotation @@ -228,7 +225,7 @@ namespace Physic /** * Add a RigidBody to the simulation */ - void addRigidBody(RigidBody* body, bool addToMap = true); + void addRigidBody(RigidBody* body, bool addToMap = true, RigidBody* raycastingBody = NULL); /** * Remove a RigidBody from the simulation. It does not delete it, and does not remove it from the RigidBodyMap. @@ -242,9 +239,8 @@ namespace Physic /** * Return a pointer to a given rigid body. - * TODO:check if exist */ - RigidBody* getRigidBody(const std::string &name); + RigidBody* getRigidBody(const std::string &name, bool raycasting=false); /** * Create and add a character to the scene, and add it to the ActorMap. @@ -322,7 +318,9 @@ namespace Physic HeightFieldContainer mHeightFieldMap; typedef std::map RigidBodyContainer; - RigidBodyContainer ObjectMap; + RigidBodyContainer mCollisionObjectMap; + + RigidBodyContainer mRaycastingObjectMap; typedef std::map PhysicActorContainer; PhysicActorContainer PhysicActorMap; diff --git a/libs/openengine/bullet/trace.cpp b/libs/openengine/bullet/trace.cpp index b6649199d..cc443f267 100644 --- a/libs/openengine/bullet/trace.cpp +++ b/libs/openengine/bullet/trace.cpp @@ -27,7 +27,7 @@ void newtrace(traceResults *results, const Ogre::Vector3& start, const Ogre::Vec const btTransform to(btrot, btend); btCollisionWorld::ClosestConvexResultCallback newTraceCallback(btstart, btend); - newTraceCallback.m_collisionFilterMask = OEngine::Physic::CollisionType_World|OEngine::Physic::CollisionType_Raycasting; + newTraceCallback.m_collisionFilterMask = OEngine::Physic::CollisionType_World; enginePass->dynamicsWorld->convexSweepTest(&newshape, from, to, newTraceCallback);