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 main(int argc, char** argv)
242 ::SetPriorityClass(::GetCurrentProcess(),REALTIME_PRIORITY_CLASS);
243 /*btDbvt::benchmark();
246 // Initialize AntTweakBar
247 // (note that AntTweakBar could also be intialize after GLUT, no matter)
248 if(!TwInit(TW_OPENGL, NULL))
250 // A fatal error occured
251 fprintf(stderr, "AntTweakBar initialization failed: %s\n", TwGetLastError());
255 glutInit(&argc, argv);
256 glutInitWindowSize(WINDOW_WIDTH, WINDOW_HEIGHT);
257 glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH);
258 int mainHandle = glutCreateWindow("CD Test Framework");
261 hWnd = FindWindow("GLUT", "CD Test Framework");
263 GetWindowRect(hWnd, &Rect);
265 glutCreateMenu(NULL);
266 glutSetWindow(mainHandle);
267 glutDisplayFunc(RenderCallback);
268 glutReshapeFunc(ReshapeCallback);
269 glutIdleFunc(IdleCallback);
270 glutKeyboardFunc(KeyboardCallback);
271 glutSpecialFunc(ArrowKeyCallback);
272 glutMouseFunc(MouseCallback);
273 glutMotionFunc(MotionCallback);
274 atexit(Terminate); // Called after glutMainLoop ends
276 glutPassiveMotionFunc((GLUTmousemotionfun)TwEventMouseMotionGLUT);
277 TwGLUTModifiersFunc(glutGetModifiers);
279 // Setup default render states
280 glClearColor(0.3f, 0.4f, 0.5f, 1.0);
281 glEnable(GL_DEPTH_TEST);
282 glEnable(GL_COLOR_MATERIAL);
283 glEnable(GL_CULL_FACE);
284 glDepthFunc(GL_LEQUAL);
287 glEnable(GL_LIGHTING);
288 float AmbientColor[] = { 0.0f, 0.1f, 0.2f, 0.0f }; glLightfv(GL_LIGHT0, GL_AMBIENT, AmbientColor);
289 float DiffuseColor[] = { 1.0f, 1.0f, 1.0f, 0.0f }; glLightfv(GL_LIGHT0, GL_DIFFUSE, DiffuseColor);
290 float SpecularColor[] = { 0.0f, 0.0f, 0.0f, 0.0f }; glLightfv(GL_LIGHT0, GL_SPECULAR, SpecularColor);
291 float Position[] = { -10.0f, 1000.0f, -4.0f, 1.0f }; glLightfv(GL_LIGHT0, GL_POSITION, Position);
295 gFnt.setScreenResolution(WINDOW_WIDTH, WINDOW_HEIGHT);
296 gFnt.setColor(1.0f, 1.0f, 1.0f, 1.0f);
300 // Create main tweak bar
302 gMainBar = TwNewBar("CollisionTests");
303 TwEnumVal testEV[MAX_NB_TESTS] = {
304 // {TEST_SPHERE_MESH_QUERY, "Sphere-mesh query"},
305 // {TEST_OBB_MESH_QUERY, "OBB-mesh query"},
306 // {TEST_CAPSULE_MESH_QUERY, "Capsule-mesh query"},
307 // {TEST_COMPLETE_BOX_PRUNING, "OPCODE SAP 1024"},
308 {TEST_COMPLETE_BOX_PRUNING_8192, "OPCODE BOX PRUNING 8192"},
309 // {TEST_BULLET_SAP_1024, "Bullet SAP HASHPAIR 1024"},
310 // {TEST_BULLET_SAP_8192, "Bullet SAP HASHPAIR 8192"},
311 // {TEST_BULLET_SAP_SORTEDPAIRS_8192, "Bullet SAP SORTEDPAIR 8192"},
312 // {TEST_BULLET_MULTISAP_8192, "Bullet MultiSAP 8192"},
313 // {TEST_BIPARTITE_BOX_PRUNING, "Bipartite box pruning"},
314 {TEST_DBVT_8192, "Bullet DBVT 8192"},
315 {TEST_BULLET_CUDA_8192, "Bullet CUDA 8192"},
316 {TEST_BULLET_3DGRID_8192, "Bullet 3D Grid 8192"},
317 {TEST_OPCODE_ARRAY_SAP, "OPCODE ARRAY SAP"},
319 TwType testType = TwDefineEnum("CollisionTest", testEV, MAX_NB_TESTS);
320 TwAddVarRW(gMainBar, "CollisionTests", testType, &gSelectedTest, "");
321 TwAddVarRW(gMainBar, "% of updates",TW_TYPE_INT32,&percentUpdate,"min=0 max=100");
322 TwAddVarRW(gMainBar, "Draw",TW_TYPE_BOOLCPP,&enableDraw,"");
327 // gCollisionTests[TEST_SPHERE_MESH_QUERY] = new SphereMeshQuery;
328 // gCollisionTests[TEST_OBB_MESH_QUERY] = new OBBMeshQuery;
329 // gCollisionTests[TEST_CAPSULE_MESH_QUERY] = new CapsuleMeshQuery;
330 // gCollisionTests[TEST_COMPLETE_BOX_PRUNING] = new CompleteBoxPruningTest(NUM_SAP_BOXES);
331 // gCollisionTests[TEST_COMPLETE_BOX_PRUNING_8192] = new CompleteBoxPruningTest(NUM_SAP_BOXES);
332 gCollisionTests[TEST_COMPLETE_BOX_PRUNING_8192] = new CompleteBoxPruningTest(NUM_SAP_BOXES);
333 // gCollisionTests[TEST_BULLET_SAP_1024] = new BulletSAPCompleteBoxPruningTest(NUM_SAP_BOXES,1);
334 // gCollisionTests[TEST_BULLET_SAP_8192] = new BulletSAPCompleteBoxPruningTest(NUM_SAP_BOXES,1);
335 // gCollisionTests[TEST_BULLET_SAP_SORTEDPAIRS_8192] = new BulletSAPCompleteBoxPruningTest(NUM_SAP_BOXES,3);
336 // gCollisionTests[TEST_BULLET_MULTISAP_8192] = new BulletSAPCompleteBoxPruningTest(NUM_SAP_BOXES,6);
337 // gCollisionTests[TEST_BIPARTITE_BOX_PRUNING] = new BipartiteBoxPruningTest;
338 gCollisionTests[TEST_DBVT_8192] = new BulletSAPCompleteBoxPruningTest(NUM_SAP_BOXES,7);
339 gCollisionTests[TEST_BULLET_CUDA_8192] = new BulletSAPCompleteBoxPruningTest(NUM_SAP_BOXES,8);
340 gCollisionTests[TEST_BULLET_3DGRID_8192] = new BulletSAPCompleteBoxPruningTest(NUM_SAP_BOXES,9);
341 gCollisionTests[TEST_OPCODE_ARRAY_SAP] = new OpcodeArraySAPTest(NUM_SAP_BOXES);
343 for(int i=0;i<MAX_NB_TESTS;i++)
344 gCollisionTests[i]->Init();
345 gCollisionTests[gTest]->Select();
359 #include "btBulletCollisionCommon.h"
361 class BulletMeshInterface : public btStridingMeshInterface
364 /// get read and write access to a subpart of a triangle mesh
365 /// this subpart has a continuous array of vertices and indices
366 /// in this way the mesh can be handled as chunks of memory with striding
367 /// very similar to OpenGL vertexarray support
368 /// make a call to unLockVertexBase when the read and write access is finished
369 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)
371 numverts = gTerrainData->nbVerts;
372 (*vertexbase) = (unsigned char *)gTerrainData->verts;
374 stride = sizeof(Point);
376 numfaces = gTerrainData->nbFaces;
377 (*indexbase) = (unsigned char *)gTerrainData->faces;
378 indicestype = PHY_INTEGER;
379 indexstride = 3*sizeof(udword); // ??
382 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
384 numverts = gTerrainData->nbVerts;
385 (*vertexbase) = (unsigned char *)gTerrainData->verts;
387 stride = sizeof(Point);
389 numfaces = gTerrainData->nbFaces;
390 (*indexbase) = (unsigned char *)gTerrainData->faces;
391 indicestype = PHY_INTEGER;
392 indexstride = 3*sizeof(udword); // ??
395 /// unLockVertexBase finishes the access to a subpart of the triangle mesh
396 /// make a call to unLockVertexBase when the read and write access (using getLockedVertexIndexBase) is finished
397 virtual void unLockVertexBase(int subpart)
401 virtual void unLockReadOnlyVertexBase(int subpart) const
406 /// getNumSubParts returns the number of seperate subparts
407 /// each subpart has a continuous array of vertices and indices
408 virtual int getNumSubParts() const
413 virtual void preallocateVertices(int numverts)
416 virtual void preallocateIndices(int numindices)
421 void BuildBulletTree()
423 /* BulletMeshInterface btMeshInterface;
425 btOptimizedBvh* btTree = new btOptimizedBvh;
426 btTree->build(&btMeshInterface, true);
429 struct MyNodeOverlapCallback : public btNodeOverlapCallback
431 virtual void processNode(int nodeSubPart, int nodeTriangleIndex)
436 MyNodeOverlapCallback myNodeCallback(callback,m_meshInterface);
438 m_bvh->reportAabbOverlappingNodex(&myNodeCallback,aabbMin,aabbMax);