/* BulletSAPCompleteBoxPruningTest, Copyright (c) 2008 Erwin Coumans Part of: CDTestFramework http://codercorner.com Copyright (c) 2007-2008 Pierre Terdiman, pierre@codercorner.com 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. */ //This file was added by Erwin Coumans, to test Bullet SAP performance #include "stdafx.h" #include "BulletSAPCompleteBoxPruningTest.h" #include "RenderingHelpers.h" #include "GLFontRenderer.h" #include "btBulletCollisionCommon.h" #include "BulletCollision/BroadphaseCollision/btDbvtBroadphase.h" #include "Camera.h" #ifdef USE_CUDA_BROADPHASE #include "../CUDA/btCudaBroadphase.h" #endif #include "LinearMath/btQuickprof.h" int numParts =2; bool enableCulling = true; bool cullFarPlane = false; bool showCulling = false; bool enableOcclusion = false; bool showOcclusion = true; int visiblecount = 0; static bool sBulletProfilerToggle = false; struct OcclusionBuffer { struct WriteOCL { static inline bool Process(btScalar& q,btScalar v) { if(q buffer; int sizes[2]; btScalar scales[2]; btScalar offsets[2]; btScalar wtrs[16]; btVector3 eye; btVector3 neardist; btScalar ocarea; btScalar qrarea; GLuint texture; OcclusionBuffer() { initialized=false; neardist=btVector3(2,2,2); ocarea=(btScalar)0; qrarea=(btScalar)0; } void setup(int w,int h) { initialized=true; sizes[0]=w; sizes[1]=h; scales[0]=w/2; scales[1]=h/2; offsets[0]=scales[0]+0.5; offsets[1]=scales[1]+0.5; glGenTextures(1,&texture); clear(); } void clear() { buffer.resize(0); buffer.resize(sizes[0]*sizes[1],0); } void initialize() { if(!initialized) { setup(128,128); } GLint v[4]; GLdouble m[16],p[16]; glGetIntegerv(GL_VIEWPORT,v); glGetDoublev(GL_MODELVIEW_MATRIX,m); glGetDoublev(GL_PROJECTION_MATRIX,p); for(int i=0;i<16;++i) wtrs[i]=p[i]; clear(); } void drawBuffer( btScalar l,btScalar t, btScalar r,btScalar b) { btAlignedObjectArray data; data.resize(buffer.size()); for(int i=0;i static int clip(const btVector4* pi,btVector4* po) { btScalar s[NP]; int m=0; for(int i=0;i0)&&(t<1)) { po[n][0] = a[0]+(b[0]-a[0])*t; po[n][1] = a[1]+(b[1]-a[1])*t; po[n][2] = a[2]+(b[2]-a[2])*t; po[n][3] = a[3]+(b[3]-a[3])*t; ++n; } if(s[j]>0) po[n++]=b; } return(n); } for(int i=0;i inline bool draw( const btVector4& a, const btVector4& b, const btVector4& c, const btScalar minarea) { const btScalar a2=(b-a).cross(c-a)[2]; if(a2>0) { if(a20) { const int dx[]={ y[0]-y[1], y[1]-y[2], y[2]-y[0]}; const int dy[]={ x[1]-x[0]-dx[0]*width, x[2]-x[1]-dx[1]*width, x[0]-x[2]-dx[2]*width}; const int a=x[2]*y[0]+x[0]*y[1]-x[2]*y[1]-x[0]*y[2]+x[1]*y[2]-x[1]*y[0]; const btScalar ia=1/(btScalar)a; const btScalar dzx=ia*(y[2]*(z[1]-z[0])+y[1]*(z[0]-z[2])+y[0]*(z[2]-z[1])); const btScalar dzy=ia*(x[2]*(z[0]-z[1])+x[0]*(z[1]-z[2])+x[1]*(z[2]-z[0]))-(dzx*width); int c[]={ miy*x[1]+mix*y[0]-x[1]*y[0]-mix*y[1]+x[0]*y[1]-miy*x[0], miy*x[2]+mix*y[1]-x[2]*y[1]-mix*y[2]+x[1]*y[2]-miy*x[1], miy*x[0]+mix*y[2]-x[0]*y[2]-mix*y[0]+x[2]*y[0]-miy*x[2]}; btScalar v=ia*((z[2]*c[0])+(z[0]*c[1])+(z[1]*c[2])); btScalar* scan=&buffer[miy*sizes[1]]; for(int iy=miy;iy=0)&&(c[1]>=0)&&(c[2]>=0)) { if(POLICY::Process(scan[ix],v)) return(true); } c[0]+=dx[0];c[1]+=dx[1];c[2]+=dx[2];v+=dzx; } c[0]+=dy[0];c[1]+=dy[1];c[2]+=dy[2];v+=dzy; scan+=sizes[0]; } } } return(false); } template inline bool clipDraw( const btVector4* p, btScalar minarea) { btVector4 o[NP*2]; const int n=clip(p,o); bool earlyexit=false; project(o,n); for(int i=2;i(o[0],o[i-1],o[i],minarea); } return(earlyexit); } void appendOccluder( const btVector3& a, const btVector3& b, const btVector3& c) { const btVector4 p[]={transform(a),transform(b),transform(c)}; clipDraw<3,WriteOCL>(p,ocarea); } void appendOccluder( const btVector3& a, const btVector3& b, const btVector3& c, const btVector3& d) { const btVector4 p[]={transform(a),transform(b),transform(c),transform(d)}; clipDraw<4,WriteOCL>(p,ocarea); } void appendOccluder( const btVector3& c, const btVector3& e) { const btVector4 x[]={ transform(btVector3(c[0]-e[0],c[1]-e[1],c[2]-e[2])), transform(btVector3(c[0]+e[0],c[1]-e[1],c[2]-e[2])), transform(btVector3(c[0]+e[0],c[1]+e[1],c[2]-e[2])), transform(btVector3(c[0]-e[0],c[1]+e[1],c[2]-e[2])), transform(btVector3(c[0]-e[0],c[1]-e[1],c[2]+e[2])), transform(btVector3(c[0]+e[0],c[1]-e[1],c[2]+e[2])), transform(btVector3(c[0]+e[0],c[1]+e[1],c[2]+e[2])), transform(btVector3(c[0]-e[0],c[1]+e[1],c[2]+e[2]))}; static const int d[]={ 1,0,3,2, 4,5,6,7, 4,7,3,0, 6,5,1,2, 7,6,2,3, 5,4,0,1}; for(int i=0;i<(sizeof(d)/sizeof(d[0]));) { const btVector4 p[]={ x[d[i++]], x[d[i++]], x[d[i++]], x[d[i++]]}; clipDraw<4,WriteOCL>(p,ocarea); } } inline bool queryOccluder( const btVector3& a, const btVector3& b, const btVector3& c) { const btVector4 p[]={transform(a),transform(b),transform(c)}; return(clipDraw<3,QueryOCL>(p,qrarea)); } inline bool queryOccluder( const btVector3& a, const btVector3& b, const btVector3& c, const btVector3& d) { const btVector4 p[]={transform(a),transform(b),transform(c),transform(d)}; return(clipDraw<4,QueryOCL>(p,qrarea)); } inline bool queryOccluder( const btVector3& c, const btVector3& e) { const btVector4 x[]={ transform(btVector3(c[0]-e[0],c[1]-e[1],c[2]-e[2])), transform(btVector3(c[0]+e[0],c[1]-e[1],c[2]-e[2])), transform(btVector3(c[0]+e[0],c[1]+e[1],c[2]-e[2])), transform(btVector3(c[0]-e[0],c[1]+e[1],c[2]-e[2])), transform(btVector3(c[0]-e[0],c[1]-e[1],c[2]+e[2])), transform(btVector3(c[0]+e[0],c[1]-e[1],c[2]+e[2])), transform(btVector3(c[0]+e[0],c[1]+e[1],c[2]+e[2])), transform(btVector3(c[0]-e[0],c[1]+e[1],c[2]+e[2]))}; for(int i=0;i<8;++i) { if((x[i][2]+x[i][3])<=0) return(true); } static const int d[]={ 1,0,3,2, 4,5,6,7, 4,7,3,0, 6,5,1,2, 7,6,2,3, 5,4,0,1}; for(int i=0;i<(sizeof(d)/sizeof(d[0]));) { const btVector4 p[]={ x[d[i++]], x[d[i++]], x[d[i++]], x[d[i++]]}; if(clipDraw<4,QueryOCL>(p,qrarea)) return(true); } return(false); } }; OcclusionBuffer ocb; BulletSAPCompleteBoxPruningTest::BulletSAPCompleteBoxPruningTest(int numBoxes,int method) : mBar (null), mNbBoxes (numBoxes), mBoxes (null), mBoxPtrs (null), mBoxTime (null), mAmplitude (100.0f), m_method(method) { btVector3 aabbMin(-200,-200,-200); btVector3 aabbMax(200,200,200); int maxNumBoxes = numBoxes; m_isdbvt=false; bool disableRaycastAccelerator = true; switch (method) { case 1: m_broadphase = new btAxisSweep3(aabbMin,aabbMax,maxNumBoxes,0,disableRaycastAccelerator); methodname = "btAxisSweep3"; break; case 2: m_broadphase = new btAxisSweep3(aabbMin,aabbMax,maxNumBoxes,new btNullPairCache(),disableRaycastAccelerator); methodname = "btAxisSweep3+btNullPairCache"; break; case 3: m_broadphase = new btAxisSweep3(aabbMin,aabbMax,maxNumBoxes,new btSortedOverlappingPairCache(),disableRaycastAccelerator); methodname = "btAxisSweep3+btSortedOverlappingPairCache"; break; case 4: m_broadphase = new btSimpleBroadphase(maxNumBoxes,new btSortedOverlappingPairCache()); methodname = "btSimpleBroadphase+btSortedOverlappingPairCache"; break; case 5: m_broadphase = new btSimpleBroadphase(maxNumBoxes,new btNullPairCache()); methodname = "btSimpleBroadphase+btNullPairCache"; break; /* case 6: { methodname = "btMultiSapBroadphase"; btMultiSapBroadphase* multiSap = new btMultiSapBroadphase(maxNumBoxes); m_broadphase = multiSap; btVector3 tmpAabbMin,tmpAabbMax; float numP = (float) numParts; for (int i=0;igetOverlappingPairCache(),disableRaycastAccelerator); multiSap->getBroadphaseArray().push_back(childBp); } } } // btAxisSweep3* childBp = new btAxisSweep3(aabbMin,aabbMax,maxNumBoxes,multiSap->getOverlappingPairCache()); // multiSap->getBroadphaseArray().push_back(childBp); multiSap->buildTree(aabbMin,aabbMax); } break; */ case 7: { btDbvtBroadphase* pbp=new btDbvtBroadphase(); m_broadphase = pbp; pbp->m_deferedcollide = true; /* Faster initialization, set to false after. */ m_isdbvt = true; methodname = "dynamic AABB tree, btDbvtBroadphase"; } break; case 8: // m_broadphase = new btAxisSweep3(aabbMin,aabbMax,maxNumBoxes); // m_broadphase = new btSimpleBroadphase(maxNumBoxes,new btSortedOverlappingPairCache()); // m_broadphase = new btCudaBroadphase(aabbMin, aabbMax, 8, 8, 8, 8192, 8192, 64, 16); // m_broadphase = new btCudaBroadphase(aabbMin, aabbMax, 12, 12, 12, 8192, 8192, 64, 16); // m_broadphase = new btCudaBroadphase(aabbMin, aabbMax, 16, 16, 16, 8192, 8192, 64, 16); #ifdef USE_CUDA_BROADPHASE m_broadphase = new btCudaBroadphase(aabbMin, aabbMax, 24, 24, 24,maxNumBoxes , maxNumBoxes, 64, 16); // m_broadphase = new btCudaBroadphase(aabbMin, aabbMax, 32, 32, 32, 8192, 8192, 64, 16); methodname = "btCudaBroadphase"; break; case 9: m_broadphase = new bt3DGridBroadphase(aabbMin, aabbMax, 24, 24, 24,maxNumBoxes , maxNumBoxes, 64, 16); methodname = "bt3DGridBroadphase"; break; #endif //USE_CUDA_BROADPHASE default: { btDbvtBroadphase* pbp=new btDbvtBroadphase(); m_broadphase = pbp; pbp->m_deferedcollide = true; /* Faster initialization, set to false after. */ m_isdbvt = true; methodname = "dynamic AABB tree, btDbvtBroadphase"; //m_broadphase = new btAxisSweep3(aabbMin,aabbMax,numBoxes,new btNullPairCache()); //methodname = "btAxisSweep3+btNullPairCache"; } } } BulletSAPCompleteBoxPruningTest::~BulletSAPCompleteBoxPruningTest() { DELETEARRAY(mBoxTime); DELETEARRAY(mBoxPtrs); DELETEARRAY(mBoxes); delete m_broadphase; } void BulletSAPCompleteBoxPruningTest::Init() { btClock clock; m_firstTime = true; SRand(0); mBoxes = new AABB[mNbBoxes]; mFlags = new bool[mNbBoxes]; mBoxPtrs = new const AABB*[mNbBoxes]; mBoxTime = new float[mNbBoxes]; for(udword i=0;icreateProxy(aabbMin,aabbMax,shapeType,&mBoxes[i],1,1,0,0);//m_dispatcher); m_proxies.push_back( proxy ); mBoxTime[i] = 2000.0f*UnitRandomFloat(); } printf("Initialization of %s with %u boxes: %ums\r\n",methodname,mNbBoxes,clock.getTimeMilliseconds()); } void BulletSAPCompleteBoxPruningTest::Release() { DELETEARRAY(mBoxTime); DELETEARRAY(mBoxes); } extern int doTree; extern int percentUpdate; extern float objectSpeed; extern bool enableDraw; static void TW_CALL NormalMode(void* pdata) { btDbvtBroadphase* pb=(btDbvtBroadphase*)pdata; pb->m_deferedcollide = true; } static void TW_CALL SlowSpeedMode(void* pdata) { btDbvtBroadphase* pb=(btDbvtBroadphase*)pdata; pb->m_deferedcollide = false; } void BulletSAPCompleteBoxPruningTest::Select() { // Create a tweak bar { mBar = TwNewBar("OPC_CompleteBoxPruning"); TwAddVarRW(mBar, "Speed", TW_TYPE_FLOAT, &objectSpeed, " min=0.0 max=0.01 step=0.0001"); TwAddVarRW(mBar, "Amplitude", TW_TYPE_FLOAT, &mAmplitude, " min=10.0 max=200.0 step=0.1"); if(m_isdbvt) { btDbvtBroadphase* pbp=(btDbvtBroadphase*)m_broadphase; TwAddVarRW(mBar, "Enable culling",TW_TYPE_BOOLCPP,&enableCulling,""); TwAddVarRW(mBar, "Enable occlusion",TW_TYPE_BOOLCPP,&enableOcclusion,""); TwAddVarRW(mBar, "Show culling",TW_TYPE_BOOLCPP,&showCulling,""); TwAddVarRW(mBar, "Show occlusion",TW_TYPE_BOOLCPP,&showOcclusion,""); TwAddVarRW(mBar, "Cull far plane",TW_TYPE_BOOLCPP,&cullFarPlane,""); TwAddVarRW(mBar, "OC Min area",TW_TYPE_FLOAT,&ocb.ocarea,"min=0.0 max=1.0 step=0.001"); TwAddVarRW(mBar, "QR Min area",TW_TYPE_FLOAT,&ocb.qrarea,"min=0.0 max=1.0 step=0.001"); TwAddVarRW(mBar, "Dyn lkhd",TW_TYPE_INT32,&pbp->m_sets[0].m_lkhd,"min=-1 max=32"); TwAddVarRW(mBar, "Fix lkhd",TW_TYPE_INT32,&pbp->m_sets[1].m_lkhd,"min=-1 max=32"); TwAddVarRW(mBar, "Dyn opt/f(%)",TW_TYPE_INT32,&pbp->m_dupdates,"min=0 max=100"); TwAddVarRW(mBar, "Fix opt/f(%)",TW_TYPE_INT32,&pbp->m_fupdates,"min=0 max=100"); TwAddVarRW(mBar, "Cln opt/f(%)",TW_TYPE_INT32,&pbp->m_cupdates,"min=0 max=100"); TwAddVarRW(mBar, "Prediction",TW_TYPE_FLOAT,&pbp->m_prediction,"min=0.0 max=2.0 step=0.1"); TwAddVarRW(mBar, "Defered collide",TW_TYPE_BOOLCPP,&pbp->m_deferedcollide,""); TwAddVarRO(mBar, "Dyn leafs",TW_TYPE_INT32,&pbp->m_sets[0].m_leaves,""); TwAddVarRO(mBar, "Fix leafs",TW_TYPE_INT32,&pbp->m_sets[1].m_leaves,""); TwAddVarRO(mBar, "Updates ratio",TW_TYPE_FLOAT,&pbp->m_updates_ratio,""); TwAddVarRO(mBar, "Visible",TW_TYPE_INT32,&visiblecount,""); TwAddButton(mBar,"Normal mode",&NormalMode,m_broadphase,""); TwAddButton(mBar,"Slow speed mode",&SlowSpeedMode,m_broadphase,""); } } printf("SubMethod: %s\r\n",methodname); } void BulletSAPCompleteBoxPruningTest::Deselect() { if(mBar) { TwDeleteBar(mBar); mBar = null; } } bool BulletSAPCompleteBoxPruningTest::UpdateBoxes(int numBoxes) { static bool once=true; for(udword i=0;i<(udword)numBoxes;i++) { mBoxTime[i] += objectSpeed; Point Center,Extents; mBoxes[i].GetExtents(Extents); Center.x = cosf(mBoxTime[i]*2.17f)*mAmplitude + sinf(mBoxTime[i])*mAmplitude*0.5f; Center.y = cosf(mBoxTime[i]*1.38f)*mAmplitude + sinf(mBoxTime[i]*mAmplitude); Center.z = sinf(mBoxTime[i]*0.777f)*mAmplitude; mBoxes[i].SetCenterExtents(Center, Extents); } return true; } void BulletSAPCompleteBoxPruningTest::PerformTest() { int numUpdatedBoxes = (mNbBoxes*percentUpdate)/100; if (m_firstTime) { numUpdatedBoxes = mNbBoxes; } mProfiler.Start(); UpdateBoxes(numUpdatedBoxes); mPairs.ResetPairs(); //CompleteBoxPruning(mNbBoxes, mBoxPtrs, mPairs, Axes(AXES_XZY)); ///add batch query? for (int i=0;iGetCenter(Center); mBoxPtrs[i]->GetExtents(Extents); btVector3 aabbMin(Center.x-Extents.x,Center.y-Extents.y,Center.z-Extents.z); btVector3 aabbMax(Center.x+Extents.x,Center.y+Extents.y,Center.z+Extents.z); m_broadphase->setAabb(m_proxies[i],aabbMin,aabbMax,0);//m_dispatcher); } #ifndef BT_NO_PROFILE if(sBulletProfilerToggle) { CProfileManager::Reset(); } #endif //BT_NO_PROFILE m_broadphase->calculateOverlappingPairs(0); #ifndef BT_NO_PROFILE if(sBulletProfilerToggle) { CProfileManager::Increment_Frame_Counter(); CProfileManager::dumpAll(); } #endif //BT_NO_PROFILE mProfiler.End(); mProfiler.Accum(); if (m_firstTime) { //initialization messes up timings m_firstTime = false; if(m_isdbvt) { ((btDbvtBroadphase*)m_broadphase)->m_deferedcollide=false; } mProfiler.Reset(); } #if 0 { int missedpairs=0; for(int i=0;iaabb,pb->aabb)) { btDbvtProxy* spa=pa; btDbvtProxy* spb=pb; if(spa>spb) btSwap(spa,spb); if(!m_broadphase->getOverlappingPairCache()->findPair(spa,spb)) { ++missedpairs; printf("Cannot find %i,%i\r\n",i,j); } } } } if(missedpairs>0) printf("Missed pairs: %u\r\n",missedpairs); } #endif // printf("%d pairs colliding\r ", mPairs.GetNbPairs()); ZeroMemory(mFlags,sizeof(bool)*mNbBoxes); btOverlappingPairCache* pairCache = m_broadphase->getOverlappingPairCache(); const btBroadphasePair* pairPtr = pairCache->getOverlappingPairArrayPtr(); for(udword i=0;i<(udword)pairCache->getNumOverlappingPairs();i++) { // Flags[pairPtr[i].m_pProxy0->getUid()-1] = true; // Flags[pairPtr[i].m_pProxy1->getUid()-1] = true; int j; j=((AABB*)pairPtr[i].m_pProxy0->m_clientObject)-mBoxes; mFlags[j] = true; j=((AABB*)pairPtr[i].m_pProxy1->m_clientObject)-mBoxes; mFlags[j] = true; } if(enableDraw) { btVector3 aabbMin(-200,-200,-200); btVector3 aabbMax(200,200,200); btVector3 tmpAabbMin,tmpAabbMax; glDisable(GL_DEPTH_TEST); float numP = (float) numParts; for (int i=0;igetOverlappingPairCache()->getNumOverlappingPairs()); // m_broadphase)->printStats(); GLFontRenderer::print(10.0f, 10.0f, 0.02f, Buffer); } // static void DrawVolume(const btDbvtVolume& volume,const btVector3& color) { const btVector3 mins=volume.Mins(); const btVector3 maxs=volume.Maxs(); glColor3f(color.x(),color.y(),color.z()); glVertex3f(mins.x(),mins.y(),mins.z()); glVertex3f(maxs.x(),mins.y(),mins.z()); glVertex3f(maxs.x(),mins.y(),mins.z()); glVertex3f(maxs.x(),maxs.y(),mins.z()); glVertex3f(maxs.x(),maxs.y(),mins.z()); glVertex3f(mins.x(),maxs.y(),mins.z()); glVertex3f(mins.x(),maxs.y(),mins.z()); glVertex3f(mins.x(),mins.y(),mins.z()); glVertex3f(mins.x(),mins.y(),maxs.z()); glVertex3f(maxs.x(),mins.y(),maxs.z()); glVertex3f(maxs.x(),mins.y(),maxs.z()); glVertex3f(maxs.x(),maxs.y(),maxs.z()); glVertex3f(maxs.x(),maxs.y(),maxs.z()); glVertex3f(mins.x(),maxs.y(),maxs.z()); glVertex3f(mins.x(),maxs.y(),maxs.z()); glVertex3f(mins.x(),mins.y(),maxs.z()); glVertex3f(mins.x(),mins.y(),mins.z()); glVertex3f(mins.x(),mins.y(),maxs.z()); glVertex3f(maxs.x(),mins.y(),mins.z()); glVertex3f(maxs.x(),mins.y(),maxs.z()); glVertex3f(maxs.x(),maxs.y(),mins.z()); glVertex3f(maxs.x(),maxs.y(),maxs.z()); glVertex3f(mins.x(),maxs.y(),mins.z()); glVertex3f(mins.x(),maxs.y(),maxs.z()); } // void BulletSAPCompleteBoxPruningTest::RenderAll() { OBB CurrentBox; CurrentBox.mRot.Identity(); for(udword i=0;iqueryOccluder(node->volume.Center(),node->volume.Extents())); } void Process(const btDbvtNode* node,btScalar depth) { Process(node); } void Process(const btDbvtNode* leaf) { btBroadphaseProxy* proxy=(btBroadphaseProxy*)leaf->data; int i=((AABB*)proxy->m_clientObject)-self->mBoxes; if(self->mFlags[i]) glColor3f(1.0f, 0.0f, 0.0f); else glColor3f(0.0f, 1.0f, 0.0f); self->mBoxes[i].GetCenter(box.mCenter); self->mBoxes[i].GetExtents(box.mExtents); DrawOBB(box);drawn++; if(ocb) { ocb->appendOccluder(btVector3(box.mCenter.x,box.mCenter.y,box.mCenter.z), btVector3(box.mExtents.x,box.mExtents.y,box.mExtents.z)); } } } srenderer; srenderer.self=this; srenderer.ocb=0; if(enableOcclusion) { srenderer.ocb=&ocb; btDbvt::collideOCL(pbp->m_sets[1].m_root,planes_n,planes_o,dir,acplanes,srenderer); btDbvt::collideOCL(pbp->m_sets[0].m_root,planes_n,planes_o,dir,acplanes,srenderer); } else { btDbvt::collideKDOP(pbp->m_sets[1].m_root,planes_n,planes_o,acplanes,srenderer); btDbvt::collideKDOP(pbp->m_sets[0].m_root,planes_n,planes_o,acplanes,srenderer); } visiblecount=srenderer.drawn; if(showOcclusion&&enableOcclusion) { const btScalar ratio=((float)glutGet(GLUT_WINDOW_HEIGHT))/((float)glutGet(GLUT_WINDOW_WIDTH)); glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrtho(-1,1,-1,1,-1,1); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); const float mm[]={ 1,0,0,0, 0,1,0,0, 0,0,0,1, 0,0,0,1}; glMultMatrixf(mm); glDisable(GL_DEPTH_TEST); glDisable(GL_LIGHTING); const float size=0.6f; const float orgx=0.3f; const float orgy=0.25f; const float left=orgx; const float right=orgx+size; const float top=orgy+size; const float bottom=orgy; ocb.drawBuffer(left,bottom,right,top); } if(showCulling) { const btScalar ratio=((float)glutGet(GLUT_WINDOW_HEIGHT))/((float)glutGet(GLUT_WINDOW_WIDTH)); static const float scale=0.004; glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrtho(-1,1,-1*ratio,1*ratio,-1,1); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); const float mm[]={ 1,0,0,0, 0,0,1,0, 0,1,0,0, 0,0,0,1}; glMultMatrixf(mm); glScalef(scale,scale,scale); glDisable(GL_DEPTH_TEST); glDisable(GL_LIGHTING); glBegin(GL_LINES); glColor4f(1,1,1,1); struct DebugRenderer : btDbvt::ICollide { OcclusionBuffer* ocb; int sid; bool AllLeafs(const btDbvtNode* node) { Process(node); return(false); } bool Descent(const btDbvtNode* node) { return(ocb->queryOccluder(node->volume.Center(),node->volume.Extents())); } void Process(const btDbvtNode* node,btScalar depth) { Process(node); } void Process(const btDbvtNode* node) { if(ocb) { ocb->appendOccluder(node->volume.Center(),node->volume.Extents()); } if(sid>=0) { const float f=sid/1023.; DrawVolume(node->volume,btVector3(1,f,f)); sid=(sid+1)%1024; } else { if(node->isinternal()) DrawVolume(node->volume,btVector3(0,1,0)); else DrawVolume(node->volume,btVector3(1,0,1)); } } } drenderer; if(enableOcclusion) { drenderer.ocb=&ocb; drenderer.sid=0; ocb.clear(); btDbvt::collideOCL(pbp->m_sets[1].m_root,planes_n,planes_o,dir,acplanes,drenderer); btDbvt::collideOCL(pbp->m_sets[0].m_root,planes_n,planes_o,dir,acplanes,drenderer); } else { drenderer.ocb=0; drenderer.sid=-1; btDbvt::collideKDOP(pbp->m_sets[1].m_root,planes_n,planes_o,acplanes,drenderer); btDbvt::collideKDOP(pbp->m_sets[0].m_root,planes_n,planes_o,acplanes,drenderer); } glEnd(); glBegin(GL_LINES); glColor4f(1,1,1,1); glVertex3f(eye.x(),eye.y(),eye.z()); glVertex3f(x00.x(),x00.y(),x00.z()); glVertex3f(eye.x(),eye.y(),eye.z()); glVertex3f(x10.x(),x10.y(),x10.z()); glVertex3f(eye.x(),eye.y(),eye.z()); glVertex3f(x01.x(),x01.y(),x01.z()); glVertex3f(eye.x(),eye.y(),eye.z()); glVertex3f(x11.x(),x11.y(),x11.z()); glVertex3f(x00.x(),x00.y(),x00.z()); glVertex3f(x10.x(),x10.y(),x10.z()); glVertex3f(x10.x(),x10.y(),x10.z()); glVertex3f(x11.x(),x11.y(),x11.z()); glVertex3f(x11.x(),x11.y(),x11.z()); glVertex3f(x01.x(),x01.y(),x01.z()); glVertex3f(x01.x(),x01.y(),x01.z()); glVertex3f(x00.x(),x00.y(),x00.z()); glEnd(); } } } void BulletSAPCompleteBoxPruningTest::KeyboardCallback(unsigned char key, int x, int y) { switch (key) { case 'p': case 'P': sBulletProfilerToggle = !sBulletProfilerToggle; break; default : break; } } void BulletSAPCompleteBoxPruningTest::MouseCallback(int button, int state, int x, int y) { } void BulletSAPCompleteBoxPruningTest::MotionCallback(int x, int y) { }