| /* |
| Bullet Continuous Collision Detection and Physics Library |
| Copyright (c) 2003-2009 Erwin Coumans http://bulletphysics.org |
| |
| This software is provided 'as-is', without any express or implied warranty. |
| In no event will the authors be held liable for any damages arising from the use of this software. |
| Permission is granted to anyone to use this software for any purpose, |
| including commercial applications, and to alter it and redistribute it freely, |
| subject to the following restrictions: |
| |
| 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. |
| 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. |
| 3. This notice may not be removed or altered from any source distribution. |
| */ |
| |
| ///btDbvtBroadphase implementation by Nathanael Presson |
| |
| #include "BulletCollision/BroadphaseCollision/btDbvtBroadphase.h" |
| |
| // |
| // Profiling |
| // |
| |
| #if DBVT_BP_PROFILE||DBVT_BP_ENABLE_BENCHMARK |
| #include <stdio.h> |
| #endif |
| |
| #if DBVT_BP_PROFILE |
| struct ProfileScope |
| { |
| __forceinline ProfileScope(btClock& clock,unsigned long& value) : |
| m_clock(&clock),m_value(&value),m_base(clock.getTimeMicroseconds()) |
| { |
| } |
| __forceinline ~ProfileScope() |
| { |
| (*m_value)+=m_clock->getTimeMicroseconds()-m_base; |
| } |
| btClock* m_clock; |
| unsigned long* m_value; |
| unsigned long m_base; |
| }; |
| #define SPC(_value_) ProfileScope spc_scope(m_clock,_value_) |
| #else |
| #define SPC(_value_) |
| #endif |
| |
| // |
| // Helpers |
| // |
| |
| // |
| template <typename T> |
| static inline void listappend(T* item,T*& list) |
| { |
| item->links[0]=0; |
| item->links[1]=list; |
| if(list) list->links[0]=item; |
| list=item; |
| } |
| |
| // |
| template <typename T> |
| static inline void listremove(T* item,T*& list) |
| { |
| if(item->links[0]) item->links[0]->links[1]=item->links[1]; else list=item->links[1]; |
| if(item->links[1]) item->links[1]->links[0]=item->links[0]; |
| } |
| |
| // |
| template <typename T> |
| static inline int listcount(T* root) |
| { |
| int n=0; |
| while(root) { ++n;root=root->links[1]; } |
| return(n); |
| } |
| |
| // |
| template <typename T> |
| static inline void clear(T& value) |
| { |
| static const struct ZeroDummy : T {} zerodummy; |
| value=zerodummy; |
| } |
| |
| // |
| // Colliders |
| // |
| |
| /* Tree collider */ |
| struct btDbvtTreeCollider : btDbvt::ICollide |
| { |
| btDbvtBroadphase* pbp; |
| btDbvtProxy* proxy; |
| btDbvtTreeCollider(btDbvtBroadphase* p) : pbp(p) {} |
| void Process(const btDbvtNode* na,const btDbvtNode* nb) |
| { |
| if(na!=nb) |
| { |
| btDbvtProxy* pa=(btDbvtProxy*)na->data; |
| btDbvtProxy* pb=(btDbvtProxy*)nb->data; |
| #if DBVT_BP_SORTPAIRS |
| if(pa->m_uniqueId>pb->m_uniqueId) |
| btSwap(pa,pb); |
| #endif |
| pbp->m_paircache->addOverlappingPair(pa,pb); |
| ++pbp->m_newpairs; |
| } |
| } |
| void Process(const btDbvtNode* n) |
| { |
| Process(n,proxy->leaf); |
| } |
| }; |
| |
| // |
| // btDbvtBroadphase |
| // |
| |
| // |
| btDbvtBroadphase::btDbvtBroadphase(btOverlappingPairCache* paircache) |
| { |
| m_deferedcollide = false; |
| m_needcleanup = true; |
| m_releasepaircache = (paircache!=0)?false:true; |
| m_prediction = 0; |
| m_stageCurrent = 0; |
| m_fixedleft = 0; |
| m_fupdates = 1; |
| m_dupdates = 0; |
| m_cupdates = 10; |
| m_newpairs = 1; |
| m_updates_call = 0; |
| m_updates_done = 0; |
| m_updates_ratio = 0; |
| m_paircache = paircache? paircache : new(btAlignedAlloc(sizeof(btHashedOverlappingPairCache),16)) btHashedOverlappingPairCache(); |
| m_gid = 0; |
| m_pid = 0; |
| m_cid = 0; |
| for(int i=0;i<=STAGECOUNT;++i) |
| { |
| m_stageRoots[i]=0; |
| } |
| #if DBVT_BP_PROFILE |
| clear(m_profiling); |
| #endif |
| } |
| |
| // |
| btDbvtBroadphase::~btDbvtBroadphase() |
| { |
| if(m_releasepaircache) |
| { |
| m_paircache->~btOverlappingPairCache(); |
| btAlignedFree(m_paircache); |
| } |
| } |
| |
| // |
| btBroadphaseProxy* btDbvtBroadphase::createProxy( const btVector3& aabbMin, |
| const btVector3& aabbMax, |
| int /*shapeType*/, |
| void* userPtr, |
| short int collisionFilterGroup, |
| short int collisionFilterMask, |
| btDispatcher* /*dispatcher*/, |
| void* /*multiSapProxy*/) |
| { |
| btDbvtProxy* proxy=new(btAlignedAlloc(sizeof(btDbvtProxy),16)) btDbvtProxy( aabbMin,aabbMax,userPtr, |
| collisionFilterGroup, |
| collisionFilterMask); |
| |
| btDbvtAabbMm aabb = btDbvtVolume::FromMM(aabbMin,aabbMax); |
| |
| //bproxy->aabb = btDbvtVolume::FromMM(aabbMin,aabbMax); |
| proxy->stage = m_stageCurrent; |
| proxy->m_uniqueId = ++m_gid; |
| proxy->leaf = m_sets[0].insert(aabb,proxy); |
| listappend(proxy,m_stageRoots[m_stageCurrent]); |
| if(!m_deferedcollide) |
| { |
| btDbvtTreeCollider collider(this); |
| collider.proxy=proxy; |
| m_sets[0].collideTV(m_sets[0].m_root,aabb,collider); |
| m_sets[1].collideTV(m_sets[1].m_root,aabb,collider); |
| } |
| return(proxy); |
| } |
| |
| // |
| void btDbvtBroadphase::destroyProxy( btBroadphaseProxy* absproxy, |
| btDispatcher* dispatcher) |
| { |
| btDbvtProxy* proxy=(btDbvtProxy*)absproxy; |
| if(proxy->stage==STAGECOUNT) |
| m_sets[1].remove(proxy->leaf); |
| else |
| m_sets[0].remove(proxy->leaf); |
| listremove(proxy,m_stageRoots[proxy->stage]); |
| m_paircache->removeOverlappingPairsContainingProxy(proxy,dispatcher); |
| btAlignedFree(proxy); |
| m_needcleanup=true; |
| } |
| |
| void btDbvtBroadphase::getAabb(btBroadphaseProxy* absproxy,btVector3& aabbMin, btVector3& aabbMax ) const |
| { |
| btDbvtProxy* proxy=(btDbvtProxy*)absproxy; |
| aabbMin = proxy->m_aabbMin; |
| aabbMax = proxy->m_aabbMax; |
| } |
| |
| struct BroadphaseRayTester : btDbvt::ICollide |
| { |
| btBroadphaseRayCallback& m_rayCallback; |
| BroadphaseRayTester(btBroadphaseRayCallback& orgCallback) |
| :m_rayCallback(orgCallback) |
| { |
| } |
| void Process(const btDbvtNode* leaf) |
| { |
| btDbvtProxy* proxy=(btDbvtProxy*)leaf->data; |
| m_rayCallback.process(proxy); |
| } |
| }; |
| |
| void btDbvtBroadphase::rayTest(const btVector3& rayFrom,const btVector3& rayTo, btBroadphaseRayCallback& rayCallback,const btVector3& aabbMin,const btVector3& aabbMax) |
| { |
| BroadphaseRayTester callback(rayCallback); |
| |
| m_sets[0].rayTestInternal( m_sets[0].m_root, |
| rayFrom, |
| rayTo, |
| rayCallback.m_rayDirectionInverse, |
| rayCallback.m_signs, |
| rayCallback.m_lambda_max, |
| aabbMin, |
| aabbMax, |
| callback); |
| |
| m_sets[1].rayTestInternal( m_sets[1].m_root, |
| rayFrom, |
| rayTo, |
| rayCallback.m_rayDirectionInverse, |
| rayCallback.m_signs, |
| rayCallback.m_lambda_max, |
| aabbMin, |
| aabbMax, |
| callback); |
| |
| } |
| |
| |
| // |
| void btDbvtBroadphase::setAabb( btBroadphaseProxy* absproxy, |
| const btVector3& aabbMin, |
| const btVector3& aabbMax, |
| btDispatcher* /*dispatcher*/) |
| { |
| btDbvtProxy* proxy=(btDbvtProxy*)absproxy; |
| ATTRIBUTE_ALIGNED16(btDbvtVolume) aabb=btDbvtVolume::FromMM(aabbMin,aabbMax); |
| #if DBVT_BP_PREVENTFALSEUPDATE |
| if(NotEqual(aabb,proxy->leaf->volume)) |
| #endif |
| { |
| bool docollide=false; |
| if(proxy->stage==STAGECOUNT) |
| {/* fixed -> dynamic set */ |
| m_sets[1].remove(proxy->leaf); |
| proxy->leaf=m_sets[0].insert(aabb,proxy); |
| docollide=true; |
| } |
| else |
| {/* dynamic set */ |
| ++m_updates_call; |
| if(Intersect(proxy->leaf->volume,aabb)) |
| {/* Moving */ |
| |
| const btVector3 delta=aabbMin-proxy->m_aabbMin; |
| btVector3 velocity(((proxy->m_aabbMax-proxy->m_aabbMin)/2)*m_prediction); |
| if(delta[0]<0) velocity[0]=-velocity[0]; |
| if(delta[1]<0) velocity[1]=-velocity[1]; |
| if(delta[2]<0) velocity[2]=-velocity[2]; |
| if ( |
| #ifdef DBVT_BP_MARGIN |
| m_sets[0].update(proxy->leaf,aabb,velocity,DBVT_BP_MARGIN) |
| #else |
| m_sets[0].update(proxy->leaf,aabb,velocity) |
| #endif |
| ) |
| { |
| ++m_updates_done; |
| docollide=true; |
| } |
| } |
| else |
| {/* Teleporting */ |
| m_sets[0].update(proxy->leaf,aabb); |
| ++m_updates_done; |
| docollide=true; |
| } |
| } |
| listremove(proxy,m_stageRoots[proxy->stage]); |
| proxy->m_aabbMin = aabbMin; |
| proxy->m_aabbMax = aabbMax; |
| proxy->stage = m_stageCurrent; |
| listappend(proxy,m_stageRoots[m_stageCurrent]); |
| if(docollide) |
| { |
| m_needcleanup=true; |
| if(!m_deferedcollide) |
| { |
| btDbvtTreeCollider collider(this); |
| m_sets[1].collideTTpersistentStack(m_sets[1].m_root,proxy->leaf,collider); |
| m_sets[0].collideTTpersistentStack(m_sets[0].m_root,proxy->leaf,collider); |
| } |
| } |
| } |
| } |
| |
| // |
| void btDbvtBroadphase::calculateOverlappingPairs(btDispatcher* dispatcher) |
| { |
| collide(dispatcher); |
| #if DBVT_BP_PROFILE |
| if(0==(m_pid%DBVT_BP_PROFILING_RATE)) |
| { |
| printf("fixed(%u) dynamics(%u) pairs(%u)\r\n",m_sets[1].m_leaves,m_sets[0].m_leaves,m_paircache->getNumOverlappingPairs()); |
| unsigned int total=m_profiling.m_total; |
| if(total<=0) total=1; |
| printf("ddcollide: %u%% (%uus)\r\n",(50+m_profiling.m_ddcollide*100)/total,m_profiling.m_ddcollide/DBVT_BP_PROFILING_RATE); |
| printf("fdcollide: %u%% (%uus)\r\n",(50+m_profiling.m_fdcollide*100)/total,m_profiling.m_fdcollide/DBVT_BP_PROFILING_RATE); |
| printf("cleanup: %u%% (%uus)\r\n",(50+m_profiling.m_cleanup*100)/total,m_profiling.m_cleanup/DBVT_BP_PROFILING_RATE); |
| printf("total: %uus\r\n",total/DBVT_BP_PROFILING_RATE); |
| const unsigned long sum=m_profiling.m_ddcollide+ |
| m_profiling.m_fdcollide+ |
| m_profiling.m_cleanup; |
| printf("leaked: %u%% (%uus)\r\n",100-((50+sum*100)/total),(total-sum)/DBVT_BP_PROFILING_RATE); |
| printf("job counts: %u%%\r\n",(m_profiling.m_jobcount*100)/((m_sets[0].m_leaves+m_sets[1].m_leaves)*DBVT_BP_PROFILING_RATE)); |
| clear(m_profiling); |
| m_clock.reset(); |
| } |
| #endif |
| |
| performDeferredRemoval(dispatcher); |
| |
| } |
| |
| void btDbvtBroadphase::performDeferredRemoval(btDispatcher* dispatcher) |
| { |
| |
| if (m_paircache->hasDeferredRemoval()) |
| { |
| |
| btBroadphasePairArray& overlappingPairArray = m_paircache->getOverlappingPairArray(); |
| |
| //perform a sort, to find duplicates and to sort 'invalid' pairs to the end |
| overlappingPairArray.quickSort(btBroadphasePairSortPredicate()); |
| |
| int invalidPair = 0; |
| |
| |
| int i; |
| |
| btBroadphasePair previousPair; |
| previousPair.m_pProxy0 = 0; |
| previousPair.m_pProxy1 = 0; |
| previousPair.m_algorithm = 0; |
| |
| |
| for (i=0;i<overlappingPairArray.size();i++) |
| { |
| |
| btBroadphasePair& pair = overlappingPairArray[i]; |
| |
| bool isDuplicate = (pair == previousPair); |
| |
| previousPair = pair; |
| |
| bool needsRemoval = false; |
| |
| if (!isDuplicate) |
| { |
| //important to perform AABB check that is consistent with the broadphase |
| btDbvtProxy* pa=(btDbvtProxy*)pair.m_pProxy0; |
| btDbvtProxy* pb=(btDbvtProxy*)pair.m_pProxy1; |
| bool hasOverlap = Intersect(pa->leaf->volume,pb->leaf->volume); |
| |
| if (hasOverlap) |
| { |
| needsRemoval = false; |
| } else |
| { |
| needsRemoval = true; |
| } |
| } else |
| { |
| //remove duplicate |
| needsRemoval = true; |
| //should have no algorithm |
| btAssert(!pair.m_algorithm); |
| } |
| |
| if (needsRemoval) |
| { |
| m_paircache->cleanOverlappingPair(pair,dispatcher); |
| |
| pair.m_pProxy0 = 0; |
| pair.m_pProxy1 = 0; |
| invalidPair++; |
| } |
| |
| } |
| |
| //perform a sort, to sort 'invalid' pairs to the end |
| overlappingPairArray.quickSort(btBroadphasePairSortPredicate()); |
| overlappingPairArray.resize(overlappingPairArray.size() - invalidPair); |
| } |
| } |
| |
| // |
| void btDbvtBroadphase::collide(btDispatcher* dispatcher) |
| { |
| /*printf("---------------------------------------------------------\n"); |
| printf("m_sets[0].m_leaves=%d\n",m_sets[0].m_leaves); |
| printf("m_sets[1].m_leaves=%d\n",m_sets[1].m_leaves); |
| printf("numPairs = %d\n",getOverlappingPairCache()->getNumOverlappingPairs()); |
| { |
| int i; |
| for (i=0;i<getOverlappingPairCache()->getNumOverlappingPairs();i++) |
| { |
| printf("pair[%d]=(%d,%d),",i,getOverlappingPairCache()->getOverlappingPairArray()[i].m_pProxy0->getUid(), |
| getOverlappingPairCache()->getOverlappingPairArray()[i].m_pProxy1->getUid()); |
| } |
| printf("\n"); |
| } |
| */ |
| |
| |
| |
| SPC(m_profiling.m_total); |
| /* optimize */ |
| m_sets[0].optimizeIncremental(1+(m_sets[0].m_leaves*m_dupdates)/100); |
| if(m_fixedleft) |
| { |
| const int count=1+(m_sets[1].m_leaves*m_fupdates)/100; |
| m_sets[1].optimizeIncremental(1+(m_sets[1].m_leaves*m_fupdates)/100); |
| m_fixedleft=btMax<int>(0,m_fixedleft-count); |
| } |
| /* dynamic -> fixed set */ |
| m_stageCurrent=(m_stageCurrent+1)%STAGECOUNT; |
| btDbvtProxy* current=m_stageRoots[m_stageCurrent]; |
| if(current) |
| { |
| btDbvtTreeCollider collider(this); |
| do { |
| btDbvtProxy* next=current->links[1]; |
| listremove(current,m_stageRoots[current->stage]); |
| listappend(current,m_stageRoots[STAGECOUNT]); |
| #if DBVT_BP_ACCURATESLEEPING |
| m_paircache->removeOverlappingPairsContainingProxy(current,dispatcher); |
| collider.proxy=current; |
| btDbvt::collideTV(m_sets[0].m_root,current->aabb,collider); |
| btDbvt::collideTV(m_sets[1].m_root,current->aabb,collider); |
| #endif |
| m_sets[0].remove(current->leaf); |
| ATTRIBUTE_ALIGNED16(btDbvtVolume) curAabb=btDbvtVolume::FromMM(current->m_aabbMin,current->m_aabbMax); |
| current->leaf = m_sets[1].insert(curAabb,current); |
| current->stage = STAGECOUNT; |
| current = next; |
| } while(current); |
| m_fixedleft=m_sets[1].m_leaves; |
| m_needcleanup=true; |
| } |
| /* collide dynamics */ |
| { |
| btDbvtTreeCollider collider(this); |
| if(m_deferedcollide) |
| { |
| SPC(m_profiling.m_fdcollide); |
| m_sets[0].collideTTpersistentStack(m_sets[0].m_root,m_sets[1].m_root,collider); |
| } |
| if(m_deferedcollide) |
| { |
| SPC(m_profiling.m_ddcollide); |
| m_sets[0].collideTTpersistentStack(m_sets[0].m_root,m_sets[0].m_root,collider); |
| } |
| } |
| /* clean up */ |
| if(m_needcleanup) |
| { |
| SPC(m_profiling.m_cleanup); |
| btBroadphasePairArray& pairs=m_paircache->getOverlappingPairArray(); |
| if(pairs.size()>0) |
| { |
| |
| int ni=btMin(pairs.size(),btMax<int>(m_newpairs,(pairs.size()*m_cupdates)/100)); |
| for(int i=0;i<ni;++i) |
| { |
| btBroadphasePair& p=pairs[(m_cid+i)%pairs.size()]; |
| btDbvtProxy* pa=(btDbvtProxy*)p.m_pProxy0; |
| btDbvtProxy* pb=(btDbvtProxy*)p.m_pProxy1; |
| if(!Intersect(pa->leaf->volume,pb->leaf->volume)) |
| { |
| #if DBVT_BP_SORTPAIRS |
| if(pa->m_uniqueId>pb->m_uniqueId) |
| btSwap(pa,pb); |
| #endif |
| m_paircache->removeOverlappingPair(pa,pb,dispatcher); |
| --ni;--i; |
| } |
| } |
| if(pairs.size()>0) m_cid=(m_cid+ni)%pairs.size(); else m_cid=0; |
| } |
| } |
| ++m_pid; |
| m_newpairs=1; |
| m_needcleanup=false; |
| if(m_updates_call>0) |
| { m_updates_ratio=m_updates_done/(btScalar)m_updates_call; } |
| else |
| { m_updates_ratio=0; } |
| m_updates_done/=2; |
| m_updates_call/=2; |
| } |
| |
| // |
| void btDbvtBroadphase::optimize() |
| { |
| m_sets[0].optimizeTopDown(); |
| m_sets[1].optimizeTopDown(); |
| } |
| |
| // |
| btOverlappingPairCache* btDbvtBroadphase::getOverlappingPairCache() |
| { |
| return(m_paircache); |
| } |
| |
| // |
| const btOverlappingPairCache* btDbvtBroadphase::getOverlappingPairCache() const |
| { |
| return(m_paircache); |
| } |
| |
| // |
| void btDbvtBroadphase::getBroadphaseAabb(btVector3& aabbMin,btVector3& aabbMax) const |
| { |
| |
| ATTRIBUTE_ALIGNED16(btDbvtVolume) bounds; |
| |
| if(!m_sets[0].empty()) |
| if(!m_sets[1].empty()) Merge( m_sets[0].m_root->volume, |
| m_sets[1].m_root->volume,bounds); |
| else |
| bounds=m_sets[0].m_root->volume; |
| else if(!m_sets[1].empty()) bounds=m_sets[1].m_root->volume; |
| else |
| bounds=btDbvtVolume::FromCR(btVector3(0,0,0),0); |
| aabbMin=bounds.Mins(); |
| aabbMax=bounds.Maxs(); |
| } |
| |
| void btDbvtBroadphase::resetPool(btDispatcher* dispatcher) |
| { |
| |
| int totalObjects = m_sets[0].m_leaves + m_sets[1].m_leaves; |
| if (!totalObjects) |
| { |
| //reset internal dynamic tree data structures |
| m_sets[0].clear(); |
| m_sets[1].clear(); |
| |
| m_deferedcollide = false; |
| m_needcleanup = true; |
| m_stageCurrent = 0; |
| m_fixedleft = 0; |
| m_fupdates = 1; |
| m_dupdates = 0; |
| m_cupdates = 10; |
| m_newpairs = 1; |
| m_updates_call = 0; |
| m_updates_done = 0; |
| m_updates_ratio = 0; |
| |
| m_gid = 0; |
| m_pid = 0; |
| m_cid = 0; |
| for(int i=0;i<=STAGECOUNT;++i) |
| { |
| m_stageRoots[i]=0; |
| } |
| } |
| } |
| |
| // |
| void btDbvtBroadphase::printStats() |
| {} |
| |
| // |
| #if DBVT_BP_ENABLE_BENCHMARK |
| |
| struct btBroadphaseBenchmark |
| { |
| struct Experiment |
| { |
| const char* name; |
| int object_count; |
| int update_count; |
| int spawn_count; |
| int iterations; |
| btScalar speed; |
| btScalar amplitude; |
| }; |
| struct Object |
| { |
| btVector3 center; |
| btVector3 extents; |
| btBroadphaseProxy* proxy; |
| btScalar time; |
| void update(btScalar speed,btScalar amplitude,btBroadphaseInterface* pbi) |
| { |
| time += speed; |
| center[0] = btCos(time*(btScalar)2.17)*amplitude+ |
| btSin(time)*amplitude/2; |
| center[1] = btCos(time*(btScalar)1.38)*amplitude+ |
| btSin(time)*amplitude; |
| center[2] = btSin(time*(btScalar)0.777)*amplitude; |
| pbi->setAabb(proxy,center-extents,center+extents,0); |
| } |
| }; |
| static int UnsignedRand(int range=RAND_MAX-1) { return(rand()%(range+1)); } |
| static btScalar UnitRand() { return(UnsignedRand(16384)/(btScalar)16384); } |
| static void OutputTime(const char* name,btClock& c,unsigned count=0) |
| { |
| const unsigned long us=c.getTimeMicroseconds(); |
| const unsigned long ms=(us+500)/1000; |
| const btScalar sec=us/(btScalar)(1000*1000); |
| if(count>0) |
| printf("%s : %u us (%u ms), %.2f/s\r\n",name,us,ms,count/sec); |
| else |
| printf("%s : %u us (%u ms)\r\n",name,us,ms); |
| } |
| }; |
| |
| void btDbvtBroadphase::benchmark(btBroadphaseInterface* pbi) |
| { |
| static const btBroadphaseBenchmark::Experiment experiments[]= |
| { |
| {"1024o.10%",1024,10,0,8192,(btScalar)0.005,(btScalar)100}, |
| /*{"4096o.10%",4096,10,0,8192,(btScalar)0.005,(btScalar)100}, |
| {"8192o.10%",8192,10,0,8192,(btScalar)0.005,(btScalar)100},*/ |
| }; |
| static const int nexperiments=sizeof(experiments)/sizeof(experiments[0]); |
| btAlignedObjectArray<btBroadphaseBenchmark::Object*> objects; |
| btClock wallclock; |
| /* Begin */ |
| for(int iexp=0;iexp<nexperiments;++iexp) |
| { |
| const btBroadphaseBenchmark::Experiment& experiment=experiments[iexp]; |
| const int object_count=experiment.object_count; |
| const int update_count=(object_count*experiment.update_count)/100; |
| const int spawn_count=(object_count*experiment.spawn_count)/100; |
| const btScalar speed=experiment.speed; |
| const btScalar amplitude=experiment.amplitude; |
| printf("Experiment #%u '%s':\r\n",iexp,experiment.name); |
| printf("\tObjects: %u\r\n",object_count); |
| printf("\tUpdate: %u\r\n",update_count); |
| printf("\tSpawn: %u\r\n",spawn_count); |
| printf("\tSpeed: %f\r\n",speed); |
| printf("\tAmplitude: %f\r\n",amplitude); |
| srand(180673); |
| /* Create objects */ |
| wallclock.reset(); |
| objects.reserve(object_count); |
| for(int i=0;i<object_count;++i) |
| { |
| btBroadphaseBenchmark::Object* po=new btBroadphaseBenchmark::Object(); |
| po->center[0]=btBroadphaseBenchmark::UnitRand()*50; |
| po->center[1]=btBroadphaseBenchmark::UnitRand()*50; |
| po->center[2]=btBroadphaseBenchmark::UnitRand()*50; |
| po->extents[0]=btBroadphaseBenchmark::UnitRand()*2+2; |
| po->extents[1]=btBroadphaseBenchmark::UnitRand()*2+2; |
| po->extents[2]=btBroadphaseBenchmark::UnitRand()*2+2; |
| po->time=btBroadphaseBenchmark::UnitRand()*2000; |
| po->proxy=pbi->createProxy(po->center-po->extents,po->center+po->extents,0,po,1,1,0,0); |
| objects.push_back(po); |
| } |
| btBroadphaseBenchmark::OutputTime("\tInitialization",wallclock); |
| /* First update */ |
| wallclock.reset(); |
| for(int i=0;i<objects.size();++i) |
| { |
| objects[i]->update(speed,amplitude,pbi); |
| } |
| btBroadphaseBenchmark::OutputTime("\tFirst update",wallclock); |
| /* Updates */ |
| wallclock.reset(); |
| for(int i=0;i<experiment.iterations;++i) |
| { |
| for(int j=0;j<update_count;++j) |
| { |
| objects[j]->update(speed,amplitude,pbi); |
| } |
| pbi->calculateOverlappingPairs(0); |
| } |
| btBroadphaseBenchmark::OutputTime("\tUpdate",wallclock,experiment.iterations); |
| /* Clean up */ |
| wallclock.reset(); |
| for(int i=0;i<objects.size();++i) |
| { |
| pbi->destroyProxy(objects[i]->proxy,0); |
| delete objects[i]; |
| } |
| objects.resize(0); |
| btBroadphaseBenchmark::OutputTime("\tRelease",wallclock); |
| } |
| |
| } |
| #else |
| void btDbvtBroadphase::benchmark(btBroadphaseInterface*) |
| {} |
| #endif |
| |
| #if DBVT_BP_PROFILE |
| #undef SPC |
| #endif |
| |