2 CDTestFramework http://codercorner.com
3 Copyright (c) 2007-2008 Pierre Terdiman, pierre@codercorner.com
5 This software is provided 'as-is', without any express or implied warranty.
6 In no event will the authors be held liable for any damages arising from the use of this software.
7 Permission is granted to anyone to use this software for any purpose,
8 including commercial applications, and to alter it and redistribute it freely,
9 subject to the following restrictions:
11 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.
12 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
13 3. This notice may not be removed or altered from any source distribution.
18 #include "CollisionTest.h"
19 #include "SphereMeshQuery.h"
20 #include "OBBMeshQuery.h"
21 #include "CapsuleMeshQuery.h"
22 #include "CompleteBoxPruning.h"
23 #include "BulletSAPCompleteBoxPruningTest.h"
24 #include "BulletSAPCompleteBoxPruningTest.h"
25 #include "BipartiteBoxPruning.h"
26 #include "OpcodeArraySAPTest.h"
27 #include "RenderingHelpers.h"
30 #include "GLFontRenderer.h"
31 #include "BulletCollision/BroadphaseCollision/btDbvtBroadphase.h"
32 #include "LinearMath/btQuickprof.h"
34 #define NUM_SAP_BOXES 8192
35 //#define NUM_SAP_BOXES 16384
36 //#define NUM_SAP_BOXES 1024
38 int percentUpdate = 100;
39 //float objectSpeed = 0.005f;
40 float objectSpeed = 0.01f;
41 bool enableDraw = true;
43 //Broadphase comparison
44 //Static case (updating 10% of objects to same position ( -> no swaps)
45 //number of objects //OPCODE BoxPruning / Bullet SAP / Bullet MultiSAP
46 //1024 0.35ms, 0.03ms, 0.15ms
47 //8192 21ms, 0.2ms, 5ms
48 //16384 92ms , 0.5ms, 28ms
50 //Dynamic case, 10% objects are moving as fast as this testbed allows (0.01?)
51 //number of objects //OPCODE BoxPruning / Bullet SAP / Bullet MultiSAP
52 //1024 0.35ms, 0.2ms, 0.25ms
53 //8192 21ms , 15ms , 13ms
54 //16384 92ms, 80ms, 49ms
57 #define WINDOW_WIDTH 1024
58 #define WINDOW_HEIGHT 768
60 static int gMouseX = 0;
61 static int gMouseY = 0;
62 static int gButton = 0;
64 static TwBar* gMainBar = null;
67 // TEST_SPHERE_MESH_QUERY,
68 // TEST_OBB_MESH_QUERY,
69 // TEST_CAPSULE_MESH_QUERY,
70 // TEST_COMPLETE_BOX_PRUNING=0,
71 TEST_COMPLETE_BOX_PRUNING_8192,
72 // TEST_BULLET_SAP_1024,
73 // TEST_BULLET_SAP_8192,
74 // TEST_BULLET_SAP_SORTEDPAIRS_8192,
75 // TEST_BULLET_MULTISAP_8192,
76 // TEST_BIPARTITE_BOX_PRUNING,
78 TEST_BULLET_CUDA_8192,
79 TEST_BULLET_3DGRID_8192,
80 TEST_OPCODE_ARRAY_SAP,
84 //static int gTest = TEST_DBVT_8192;//TEST_BULLET_MULTISAP_8192;
85 //static int gSelectedTest = TEST_DBVT_8192;//TEST_BULLET_MULTISAP_8192;
86 static int gTest = TEST_BULLET_CUDA_8192;
87 static int gSelectedTest = TEST_BULLET_CUDA_8192;
88 static CollisionTest* gCollisionTests[MAX_NB_TESTS];
90 static GLFontRenderer gFnt;
94 static void KeyboardCallback(unsigned char key, int x, int y)
98 case 27: exit(0); break;
102 if(gTest!=MAX_NB_TESTS-1)
104 gCollisionTests[gTest]->Deselect();
107 gCollisionTests[gTest]->Select();
116 gCollisionTests[gTest]->Deselect();
119 gCollisionTests[gTest]->Select();
124 case 101: MoveCameraForward(); break;
125 case 103: MoveCameraBackward(); break;
126 case 100: MoveCameraRight(); break;
127 case 102: MoveCameraLeft(); break;
128 default: gCollisionTests[gTest]->KeyboardCallback(key, x, y); break;
131 TwEventKeyboardGLUT(key, x, y);
134 static void ArrowKeyCallback(int key, int x, int y)
136 KeyboardCallback(key, x, y);
138 TwEventSpecialGLUT(key, x, y);
141 static void MouseCallback(int button, int state, int x, int y)
147 if(!TwEventMouseButtonGLUT(button, state, x, y))
149 gCollisionTests[gTest]->MouseCallback(button, state, x, y);
153 static void MotionCallback(int x, int y)
155 if(!TwEventMouseMotionGLUT(x, y))
159 int dx = gMouseX - x;
160 int dy = gMouseY - y;
162 RotateCamera(dx, dy);
168 gCollisionTests[gTest]->MotionCallback(x, y);
172 static void RenderCallback()
175 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
178 glMatrixMode(GL_PROJECTION);
181 glMatrixMode(GL_MODELVIEW);
184 glEnable(GL_LIGHTING);
186 if(0 /*gRenderWireframe*/)
187 glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
189 glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
191 gCollisionTests[gTest]->PerformTest();
199 if(gSelectedTest!=gTest)
201 gCollisionTests[gTest]->Deselect();
202 gTest = gSelectedTest;
203 gCollisionTests[gTest]->Select();
207 static void ReshapeCallback(int width, int height)
209 glViewport(0, 0, width, height);
211 // Send the new window size to AntTweakBar
212 TwWindowSize(width, height);
215 static void IdleCallback()
220 static void Terminate()
224 for(int i=0;i<MAX_NB_TESTS;i++)
226 gCollisionTests[i]->Release();
227 DELETESINGLE(gCollisionTests[i]);
232 TwDeleteBar(gMainBar);
239 int myGlutModifiers()
241 return glutGetModifiers();
243 int main(int argc, char** argv)
246 ::SetPriorityClass(::GetCurrentProcess(),REALTIME_PRIORITY_CLASS);
247 /*btDbvt::benchmark();
250 // Initialize AntTweakBar
251 // (note that AntTweakBar could also be intialize after GLUT, no matter)
252 if(!TwInit(TW_OPENGL, NULL))
254 // A fatal error occured
255 fprintf(stderr, "AntTweakBar initialization failed: %s\n", TwGetLastError());
259 glutInit(&argc, argv);
260 glutInitWindowSize(WINDOW_WIDTH, WINDOW_HEIGHT);
261 glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH);
262 int mainHandle = glutCreateWindow("CD Test Framework");
265 hWnd = FindWindow("GLUT", "CD Test Framework");
267 GetWindowRect(hWnd, &Rect);
269 glutCreateMenu(NULL);
270 glutSetWindow(mainHandle);
271 glutDisplayFunc(RenderCallback);
272 glutReshapeFunc(ReshapeCallback);
273 glutIdleFunc(IdleCallback);
274 glutKeyboardFunc(KeyboardCallback);
275 glutSpecialFunc(ArrowKeyCallback);
276 glutMouseFunc(MouseCallback);
277 glutMotionFunc(MotionCallback);
278 atexit(Terminate); // Called after glutMainLoop ends
280 glutPassiveMotionFunc((GLUTmousemotionfun)TwEventMouseMotionGLUT);
281 TwGLUTModifiersFunc(myGlutModifiers);
283 // Setup default render states
284 glClearColor(0.3f, 0.4f, 0.5f, 1.0);
285 glEnable(GL_DEPTH_TEST);
286 glEnable(GL_COLOR_MATERIAL);
287 glEnable(GL_CULL_FACE);
288 glDepthFunc(GL_LEQUAL);
291 glEnable(GL_LIGHTING);
292 float AmbientColor[] = { 0.0f, 0.1f, 0.2f, 0.0f }; glLightfv(GL_LIGHT0, GL_AMBIENT, AmbientColor);
293 float DiffuseColor[] = { 1.0f, 1.0f, 1.0f, 0.0f }; glLightfv(GL_LIGHT0, GL_DIFFUSE, DiffuseColor);
294 float SpecularColor[] = { 0.0f, 0.0f, 0.0f, 0.0f }; glLightfv(GL_LIGHT0, GL_SPECULAR, SpecularColor);
295 float Position[] = { -10.0f, 1000.0f, -4.0f, 1.0f }; glLightfv(GL_LIGHT0, GL_POSITION, Position);
299 gFnt.setScreenResolution(WINDOW_WIDTH, WINDOW_HEIGHT);
300 gFnt.setColor(1.0f, 1.0f, 1.0f, 1.0f);
304 // Create main tweak bar
306 gMainBar = TwNewBar("CollisionTests");
307 TwEnumVal testEV[MAX_NB_TESTS] = {
308 // {TEST_SPHERE_MESH_QUERY, "Sphere-mesh query"},
309 // {TEST_OBB_MESH_QUERY, "OBB-mesh query"},
310 // {TEST_CAPSULE_MESH_QUERY, "Capsule-mesh query"},
311 // {TEST_COMPLETE_BOX_PRUNING, "OPCODE SAP 1024"},
312 {TEST_COMPLETE_BOX_PRUNING_8192, "OPCODE BOX PRUNING 8192"},
313 // {TEST_BULLET_SAP_1024, "Bullet SAP HASHPAIR 1024"},
314 // {TEST_BULLET_SAP_8192, "Bullet SAP HASHPAIR 8192"},
315 // {TEST_BULLET_SAP_SORTEDPAIRS_8192, "Bullet SAP SORTEDPAIR 8192"},
316 // {TEST_BULLET_MULTISAP_8192, "Bullet MultiSAP 8192"},
317 // {TEST_BIPARTITE_BOX_PRUNING, "Bipartite box pruning"},
318 {TEST_DBVT_8192, "Bullet DBVT 8192"},
319 {TEST_BULLET_CUDA_8192, "Bullet CUDA 8192"},
320 {TEST_BULLET_3DGRID_8192, "Bullet 3D Grid 8192"},
321 {TEST_OPCODE_ARRAY_SAP, "OPCODE ARRAY SAP"},
323 TwType testType = TwDefineEnum("CollisionTest", testEV, MAX_NB_TESTS);
324 TwAddVarRW(gMainBar, "CollisionTests", testType, &gSelectedTest, "");
325 TwAddVarRW(gMainBar, "% of updates",TW_TYPE_INT32,&percentUpdate,"min=0 max=100");
326 TwAddVarRW(gMainBar, "Draw",TW_TYPE_BOOLCPP,&enableDraw,"");
331 // gCollisionTests[TEST_SPHERE_MESH_QUERY] = new SphereMeshQuery;
332 // gCollisionTests[TEST_OBB_MESH_QUERY] = new OBBMeshQuery;
333 // gCollisionTests[TEST_CAPSULE_MESH_QUERY] = new CapsuleMeshQuery;
334 // gCollisionTests[TEST_COMPLETE_BOX_PRUNING] = new CompleteBoxPruningTest(NUM_SAP_BOXES);
335 // gCollisionTests[TEST_COMPLETE_BOX_PRUNING_8192] = new CompleteBoxPruningTest(NUM_SAP_BOXES);
336 gCollisionTests[TEST_COMPLETE_BOX_PRUNING_8192] = new CompleteBoxPruningTest(NUM_SAP_BOXES);
337 // gCollisionTests[TEST_BULLET_SAP_1024] = new BulletSAPCompleteBoxPruningTest(NUM_SAP_BOXES,1);
338 // gCollisionTests[TEST_BULLET_SAP_8192] = new BulletSAPCompleteBoxPruningTest(NUM_SAP_BOXES,1);
339 // gCollisionTests[TEST_BULLET_SAP_SORTEDPAIRS_8192] = new BulletSAPCompleteBoxPruningTest(NUM_SAP_BOXES,3);
340 // gCollisionTests[TEST_BULLET_MULTISAP_8192] = new BulletSAPCompleteBoxPruningTest(NUM_SAP_BOXES,6);
341 // gCollisionTests[TEST_BIPARTITE_BOX_PRUNING] = new BipartiteBoxPruningTest;
342 gCollisionTests[TEST_DBVT_8192] = new BulletSAPCompleteBoxPruningTest(NUM_SAP_BOXES,7);
343 gCollisionTests[TEST_BULLET_CUDA_8192] = new BulletSAPCompleteBoxPruningTest(NUM_SAP_BOXES,8);
344 gCollisionTests[TEST_BULLET_3DGRID_8192] = new BulletSAPCompleteBoxPruningTest(NUM_SAP_BOXES,9);
345 gCollisionTests[TEST_OPCODE_ARRAY_SAP] = new OpcodeArraySAPTest(NUM_SAP_BOXES);
347 for(int i=0;i<MAX_NB_TESTS;i++)
348 gCollisionTests[i]->Init();
349 gCollisionTests[gTest]->Select();
363 #include "btBulletCollisionCommon.h"
365 class BulletMeshInterface : public btStridingMeshInterface
368 /// get read and write access to a subpart of a triangle mesh
369 /// this subpart has a continuous array of vertices and indices
370 /// in this way the mesh can be handled as chunks of memory with striding
371 /// very similar to OpenGL vertexarray support
372 /// make a call to unLockVertexBase when the read and write access is finished
373 virtual void getLockedVertexIndexBase(unsigned char **vertexbase, int& numverts,PHY_ScalarType& type, int& stride,unsigned char **indexbase,int & indexstride,int& numfaces,PHY_ScalarType& indicestype,int subpart=0)
375 numverts = gTerrainData->nbVerts;
376 (*vertexbase) = (unsigned char *)gTerrainData->verts;
378 stride = sizeof(Point);
380 numfaces = gTerrainData->nbFaces;
381 (*indexbase) = (unsigned char *)gTerrainData->faces;
382 indicestype = PHY_INTEGER;
383 indexstride = 3*sizeof(udword); // ??
386 virtual void getLockedReadOnlyVertexIndexBase(const unsigned char **vertexbase, int& numverts,PHY_ScalarType& type, int& stride,const unsigned char **indexbase,int & indexstride,int& numfaces,PHY_ScalarType& indicestype,int subpart=0) const
388 numverts = gTerrainData->nbVerts;
389 (*vertexbase) = (unsigned char *)gTerrainData->verts;
391 stride = sizeof(Point);
393 numfaces = gTerrainData->nbFaces;
394 (*indexbase) = (unsigned char *)gTerrainData->faces;
395 indicestype = PHY_INTEGER;
396 indexstride = 3*sizeof(udword); // ??
399 /// unLockVertexBase finishes the access to a subpart of the triangle mesh
400 /// make a call to unLockVertexBase when the read and write access (using getLockedVertexIndexBase) is finished
401 virtual void unLockVertexBase(int subpart)
405 virtual void unLockReadOnlyVertexBase(int subpart) const
410 /// getNumSubParts returns the number of seperate subparts
411 /// each subpart has a continuous array of vertices and indices
412 virtual int getNumSubParts() const
417 virtual void preallocateVertices(int numverts)
420 virtual void preallocateIndices(int numindices)
425 void BuildBulletTree()
427 /* BulletMeshInterface btMeshInterface;
429 btOptimizedBvh* btTree = new btOptimizedBvh;
430 btTree->build(&btMeshInterface, true);
433 struct MyNodeOverlapCallback : public btNodeOverlapCallback
435 virtual void processNode(int nodeSubPart, int nodeTriangleIndex)
440 MyNodeOverlapCallback myNodeCallback(callback,m_meshInterface);
442 m_bvh->reportAabbOverlappingNodex(&myNodeCallback,aabbMin,aabbMax);