📄 ogrecollisioncontext.cpp
字号:
///////////////////////////////////////////////////////////////////////////////
/// @file OgreCollisionContext.cpp
/// @brief <TODO: insert file description here>
///
/// @author The OgreOpcode Team
///
///////////////////////////////////////////////////////////////////////////////
///
/// This file is part of OgreOpcode.
///
/// A lot of the code is based on the Nebula Opcode Collision module, see docs/Nebula_license.txt
///
/// OgreOpcode is free software; you can redistribute it and/or
/// modify it under the terms of the GNU Lesser General Public
/// License as published by the Free Software Foundation; either
/// version 2.1 of the License, or (at your option) any later version.
///
/// OgreOpcode 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
/// Lesser General Public License for more details.
///
/// You should have received a copy of the GNU Lesser General Public
/// License along with OgreOpcode; if not, write to the Free Software
/// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
///
///////////////////////////////////////////////////////////////////////////////
#include "OgreCollisionContext.h"
#include "OgreCollisionObject.h"
#include "OgreOpcodeMath.h"
#include "OgreCollisionManager.h"
#include "BP_Scene.h"
using namespace Ogre;
using namespace OgreOpcode::Details;
namespace OgreOpcode
{
namespace Details
{
inline bool intervalOverlap(Real a0, Real a1, Real b0, Real b1)
{
// Only two ways for intervals to not overlap --
// a's max less than b's min, or a's min greater than b's max.
// Otherwise they overlap.
// return !(a1<b0 || a0>b1);
// I just applied the De Morgan's law here in order to obtain short-circuit
return (a1>=b0) && (a0<=b1);
}
} // Details
// release all owned collide objects
CollisionContext::~CollisionContext()
{
// remove collision objects
while (!owned_list.empty())
{
destroyObject(*(owned_list.begin()));
}
delete mVisualDebugger;
delete mBroadPhase;
}
// Construct a new collide object.
CollisionObject *CollisionContext::createObject(const Ogre::String& name)
{
CollisionObject *co = new CollisionObject(name);
co->setId(unique_id++);
co->setContext(this);
owned_list.push_back(co);
return co;
}
CollisionContext::CollisionContext(const Ogre::String& name) :
unique_id(0),
mName(name),
mRayCulling(true),
mIsSAPDirty(true)
{
mVisualDebugger = new Details::OgreOpcodeDebugger(mName, CollisionManager::getSingletonPtr()->getSceneManager());
mRecentContactList.clear();
mBroadPhase = new BP_Scene(&proxList, &OgreOpcode::CollisionContext::addPair, &OgreOpcode::CollisionContext::removePair);
}
// Kill an owned collide object.
void CollisionContext::destroyObject(CollisionObject *collObj)
{
if (collObj != 0)
{
if(collObj->isAttached())
{
rw_attached_list_iterator itAttached = find(attached_list.begin(), attached_list.end(), collObj);
if (itAttached != attached_list.end())
{
attached_list.erase(itAttached);
}
}
rw_owned_list_iterator itOwned = find(owned_list.begin(), owned_list.end(), collObj);
if (itOwned != owned_list.end())
{
owned_list.erase(itOwned);
}
collObj->setAttached(false);
collObj->remove_broadphase();
collObj->setContext(0);
delete collObj;
}
}
void CollisionContext::addObject(CollisionObject *collObj)
{
if(collObj == 0)
OGRE_EXCEPT(Exception::ERR_INTERNAL_ERROR, "Trying to add a null object.", "CollisionContext::addObject");
attached_list.push_back(collObj);
collObj->setAttached(true);
}
void CollisionContext::removeObject(CollisionObject *collObj)
{
if (collObj != 0)
{
collObj->setAttached(false);
collObj->remove_broadphase();
rw_attached_list_iterator itAttached = find(attached_list.begin(), attached_list.end(), collObj);
if (itAttached != attached_list.end())
{
attached_list.erase(itAttached);
}
}
}
/// Call collide on each object in the context.
/// After this, each object's collision array holds all collisions
/// this object was involved with.
int CollisionContext::collide(Real dt)
{
update(dt);
// first, clear the collision counters in all collide objects
for (attached_list_iterator i = attached_list.begin(); i != attached_list.end(); ++i)
{
(*i)->clearCollisions();
}
// then, run the broadphase
for (attached_list_iterator i = attached_list.begin(); i != attached_list.end(); ++i)
{
(*i)->do_broadphase();
}
// Loop through the Potentially Colliding Set and tell each CollisionObject to test against the other
for (ProxList::iterator prox_it = proxList.begin(); prox_it != proxList.end(); ++prox_it)
{
// If the shape is marked as being static, do not add it to the PCS.
if(!(*prox_it).obj1->getShape()->isStatic())
(*prox_it).obj1->addToCollideList((*prox_it).obj2);
if(!(*prox_it).obj2->getShape()->isStatic())
(*prox_it).obj2->addToCollideList((*prox_it).obj1);
}
// check the collision status for each object
collideReportHandler.beginFrame();
for (attached_list_iterator i = attached_list.begin(); i != attached_list.end(); ++i)
{
//if ( (*i)->needsUpdate() )
(*i)->collide();
}
collideReportHandler.endFrame();
int num_coll = collideReportHandler.getNumCollisions();
return num_coll;
}
/// Get all collisions an object is involved in.
/// Returns pointer to an internal collision array and
/// the number of collisions.
int CollisionContext::getCollisions(CollisionObject *collObj, CollisionPair **&cpPtr)
{
if (collObj->getNumCollisions() > 0)
{
return collideReportHandler.getCollisions(collObj,cpPtr);
} else
{
cpPtr = 0;
return 0;
}
}
CollisionObject* CollisionContext::getAttachedObject(Ogre::String name)
{
for (attached_list_iterator i = attached_list.begin(); i != attached_list.end(); ++i)
{
if( (*i)->getName() == name )
return (*i);
}
OGRE_EXCEPT(Exception::ERR_ITEM_NOT_FOUND, "'" + name + "' is not attached! Does it even exsist?", "CollisionContext::getAttachedObject");
}
///
const std::list<CollisionObject*>& CollisionContext::getPotentialColliders(const CollisionObject* collidee)
{
return collidee->collideList;
}
/// get reporter for for last collide() call.
const CollisionReporter& CollisionContext::getCollisionReport()
{
return collideReportHandler;
}
///
const int CollisionContext::getNumCollisions()
{
return collideReportHandler.getNumCollisions();
}
/// get reporter for for last Check...() call.
const CollisionReporter& CollisionContext::getCheckReport()
{
return checkReportHandler;
}
/// visualize all objects in the context.
void CollisionContext::visualize(bool doVisualize, bool doRadii, bool doContacts, bool doBBs, bool doShapes, bool doAABBs)
{
// if the debugger is down, just return
if(!mVisualDebugger) return;
mVisualDebugger->clearAll();
for (attached_list_iterator i = attached_list.begin(); i != attached_list.end(); ++i)
{
(*i)->getShape()->clearViz();
}
if(doVisualize)
{
if (!attached_list.empty())
{
if(doRadii)
{
mVisualDebugger->beginRadii();
for (attached_list_iterator i = attached_list.begin(); i != attached_list.end(); ++i)
{
(*i)->visualizeRadii();
}
mVisualDebugger->endRadii();
}
if(doContacts)
{
if( collideReportHandler.getNumCollisions() > 0)
{
mVisualDebugger->beginContacts();
mVisualDebugger->beginContactNormals();
for (attached_list_iterator i = attached_list.begin(); i != attached_list.end(); ++i)
{
(*i)->visualizeContacts();
}
mVisualDebugger->endContactNormals();
mVisualDebugger->endContacts();
}
static int contactCount = 0;
static bool bufferContacts = true;
if( checkReportHandler.getNumCollisions() > 0)
{
CollisionPair **pick_report;
int num_picks = checkReportHandler.getAllCollisions(pick_report);
if(num_picks > 0)
{
for(int i = 0; i < num_picks; i++)
{
for (int currColl = 0; currColl < static_cast<int>(pick_report[i]->collInfos.size()); currColl++)
{
if(bufferContacts)
contactCount++;
CollisionInfo collInfo;
collInfo.contact = pick_report[i]->collInfos[currColl].contact;
collInfo.this_normal = pick_report[i]->collInfos[currColl].this_normal * 5;
collInfo.other_normal = pick_report[i]->collInfos[currColl].other_normal * 5;
mRecentContactList.push_back(collInfo);
if(!bufferContacts)
mRecentContactList.pop_front();
}
}
}
if(contactCount > 10)
bufferContacts = false;
}
// render any collision contact points
if (mRecentContactList.size() > 0)
{
mVisualDebugger->beginContacts();
mVisualDebugger->beginContactNormals();
std::list<CollisionInfo>::iterator contactIter;
for (contactIter = mRecentContactList.begin(); contactIter != mRecentContactList.end(); ++contactIter)
{
Vector3 cnt = (*contactIter).contact;
mVisualDebugger->addContactLine(cnt.x-0.5f,cnt.y,cnt.z, cnt.x+0.5f,cnt.y,cnt.z);
mVisualDebugger->addContactLine(cnt.x,cnt.y-0.5f,cnt.z, cnt.x,cnt.y+0.5f,cnt.z);
mVisualDebugger->addContactLine(cnt.x,cnt.y,cnt.z-0.5f, cnt.x,cnt.y,cnt.z+0.5f);
Vector3 n = (*contactIter).this_normal * 5;
mVisualDebugger->addContactNormalsLine(cnt.x,cnt.y,cnt.z, cnt.x+n.x,cnt.y+n.y,cnt.z+n.z);
n = (*contactIter).other_normal * 5;
mVisualDebugger->addContactNormalsLine(cnt.x,cnt.y,cnt.z, cnt.x+n.x,cnt.y+n.y,cnt.z+n.z);
}
mVisualDebugger->endContactNormals();
mVisualDebugger->endContacts();
}
}
if(doBBs)
{
mVisualDebugger->beginBBs();
for (attached_list_iterator i = attached_list.begin(); i != attached_list.end(); ++i)
{
(*i)->visualizeBoundingBoxes();
}
mVisualDebugger->endBBs();
}
if(doShapes)
{
//mVisualDebugger->beginShapes();
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -