2 Bullet Continuous Collision Detection and Physics Library, http://bulletphysics.org
\r
3 Copyright (C) 2006 - 2009 Sony Computer Entertainment Inc.
\r
5 This software is provided 'as-is', without any express or implied warranty.
\r
6 In no event will the authors be held liable for any damages arising from the use of this software.
\r
7 Permission is granted to anyone to use this software for any purpose,
\r
8 including commercial applications, and to alter it and redistribute it freely,
\r
9 subject to the following restrictions:
\r
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.
\r
12 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
\r
13 3. This notice may not be removed or altered from any source distribution.
\r
16 #define START_POS_X btScalar(0.f)
\r
17 #define START_POS_Y btScalar(0.f)
\r
18 #define START_POS_Z btScalar(0.f)
\r
19 //#define START_POS_Y btScalar(40.f)
\r
20 //#define START_POS_Z btScalar(40.f)
\r
21 //#define START_POS_Y btScalar(0.4f)
\r
22 //#define START_POS_Z btScalar(0.4f)
\r
23 #define ARRAY_SIZE_X 32
\r
24 #define ARRAY_SIZE_Y 32
\r
25 //#define ARRAY_SIZE_Y 16
\r
26 #define ARRAY_SIZE_Z 32
\r
28 //#define ARRAY_SIZE_Z 1
\r
29 //#define DIST btScalar(2.f)
\r
30 #define DIST (DEF_PARTICLE_RADIUS * 2.f)
\r
33 //#define STRESS_Y 200
\r
34 #define STRESS_Y 640
\r
40 ///The 3 following lines include the CPU implementation of the kernels, keep them in this order.
\r
41 #include "BulletMultiThreaded/btGpuDefines.h"
\r
42 #include "BulletMultiThreaded/btGpuUtilsSharedDefs.h"
\r
43 #include "BulletMultiThreaded/btGpuUtilsSharedCode.h"
\r
45 #include <GL/glew.h>
\r
49 #include "GL_DialogDynamicsWorld.h"
\r
50 #include "GL_DialogWindow.h"
\r
54 #include "BulletCollision/CollisionDispatch/btEmptyCollisionAlgorithm.h"
\r
55 #include "BulletCollision/CollisionDispatch/btSimulationIslandManager.h"
\r
56 #include "GLDebugFont.h"
\r
57 #include "GlutStuff.h"
\r
58 ///btBulletDynamicsCommon.h is the main Bullet include file, contains most common include files.
\r
59 #include "btBulletDynamicsCommon.h"
\r
60 #include <stdio.h> //printf debugging
\r
61 #include "shaders.h"
\r
63 #include "ParticlesDemo.h"
\r
69 btScalar gTimeStep = 0.5f;//btScalar(1./60.);
\r
71 #define SCALING btScalar(1.f)
\r
73 void ParticlesDemo::clientMoveAndDisplay()
\r
78 glDisable(GL_LIGHTING);
\r
79 glColor3f(1.f, 1.f, 1.f);
\r
81 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
\r
83 glDisable(GL_TEXTURE_2D); // we always draw wireframe in this demo
\r
85 //simple dynamics world doesn't handle fixed-time-stepping
\r
86 float ms = getDeltaTimeMicroseconds();
\r
90 if (m_dialogDynamicsWorld)
\r
91 m_dialogDynamicsWorld->draw(gTimeStep);
\r
93 ///step the simulation
\r
94 if (m_dynamicsWorld)
\r
96 m_dynamicsWorld->stepSimulation(gTimeStep,0);//ms / 1000000.f);
\r
97 //optional but useful: debug drawing
\r
98 m_dynamicsWorld->debugDrawWorld();
\r
103 ms = getDeltaTimeMicroseconds();
\r
113 void ParticlesDemo::displayCallback(void) {
\r
116 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
\r
120 //optional but useful: debug drawing to detect problems
\r
121 if (m_dynamicsWorld)
\r
122 m_dynamicsWorld->debugDrawWorld();
\r
124 //if (m_dialogDynamicsWorld)
\r
125 // m_dialogDynamicsWorld->draw(gTimeStep);
\r
131 class btNullBroadphase : public btBroadphaseInterface
\r
137 virtual ~btNullBroadphase()
\r
140 virtual btBroadphaseProxy* createProxy( const btVector3& aabbMin, const btVector3& aabbMax,int shapeType,void* userPtr, short int collisionFilterGroup,short int collisionFilterMask, btDispatcher* dispatcher,void* multiSapProxy)
\r
144 virtual void destroyProxy(btBroadphaseProxy* proxy,btDispatcher* dispatcher)
\r
147 virtual void setAabb(btBroadphaseProxy* proxy,const btVector3& aabbMin,const btVector3& aabbMax, btDispatcher* dispatcher)
\r
150 virtual void getAabb(btBroadphaseProxy* proxy,btVector3& aabbMin, btVector3& aabbMax ) const
\r
153 virtual void rayTest(const btVector3& rayFrom,const btVector3& rayTo, btBroadphaseRayCallback& rayCallback, const btVector3& aabbMin=btVector3(0,0,0), const btVector3& aabbMax = btVector3(0,0,0))
\r
156 virtual void calculateOverlappingPairs(btDispatcher* dispatcher)
\r
159 virtual btOverlappingPairCache* getOverlappingPairCache()
\r
163 virtual const btOverlappingPairCache* getOverlappingPairCache() const
\r
167 virtual void getBroadphaseAabb(btVector3& aabbMin,btVector3& aabbMax) const
\r
170 virtual void resetPool(btDispatcher* dispatcher)
\r
173 virtual void printStats()
\r
176 virtual void aabbTest(const btVector3& aabbMin, const btVector3& aabbMax, btBroadphaseAabbCallback& callback)
\r
183 void ParticlesDemo::initPhysics()
\r
186 setTexturing(false);
\r
189 // setCameraDistance(80.f);
\r
190 setCameraDistance(3.0f);
\r
191 // m_cameraTargetPosition.setValue(50, 10, 0);
\r
192 m_cameraTargetPosition.setValue(0, 0, 0);
\r
193 // m_azi = btScalar(0.f);
\r
194 // m_ele = btScalar(0.f);
\r
195 m_azi = btScalar(45.f);
\r
196 m_ele = btScalar(30.f);
\r
197 setFrustumZPlanes(0.1f, 10.f);
\r
199 ///collision configuration contains default setup for memory, collision setup
\r
201 btDefaultCollisionConstructionInfo dci;
\r
202 dci.m_defaultMaxPersistentManifoldPoolSize=50000;
\r
203 dci.m_defaultMaxCollisionAlgorithmPoolSize=50000;
\r
205 m_collisionConfiguration = new btDefaultCollisionConfiguration(dci);
\r
207 ///use the default collision dispatcher. For parallel processing you can use a diffent dispatcher (see Extras/BulletMultiThreaded)
\r
208 m_dispatcher = new btCollisionDispatcher(m_collisionConfiguration);
\r
210 m_pairCache = new (btAlignedAlloc(sizeof(btHashedOverlappingPairCache),16))btHashedOverlappingPairCache();
\r
213 // m_broadphase = new btDbvtBroadphase(m_pairCache);
\r
214 m_broadphase = new btNullBroadphase();
\r
216 ///the default constraint solver
\r
217 m_solver = new btSequentialImpulseConstraintSolver();
\r
219 m_pWorld = new btParticlesDynamicsWorld(m_dispatcher,m_broadphase,m_solver,m_collisionConfiguration, 65536);
\r
221 m_dialogDynamicsWorld = new GL_DialogDynamicsWorld();
\r
222 GL_DialogWindow* settings = m_dialogDynamicsWorld->createDialog(50,0,280,280,"CPU fallback");
\r
224 m_pWorld->m_useCpuControls[0] = 0;
\r
225 GL_ToggleControl* ctrl = 0;
\r
226 m_pWorld->m_useCpuControls[SIMSTAGE_INTEGRATE_MOTION] = m_dialogDynamicsWorld->createToggle(settings,"Integrate Motion");
\r
227 m_pWorld->m_useCpuControls[SIMSTAGE_COMPUTE_CELL_ID] = m_dialogDynamicsWorld->createToggle(settings,"Compute Cell ID");
\r
228 m_pWorld->m_useCpuControls[SIMSTAGE_SORT_CELL_ID] = m_dialogDynamicsWorld->createToggle(settings,"Sort Cell ID");
\r
229 m_pWorld->m_useCpuControls[SIMSTAGE_FIND_CELL_START] = m_dialogDynamicsWorld->createToggle(settings,"Find Cell Start");
\r
230 m_pWorld->m_useCpuControls[SIMSTAGE_COLLIDE_PARTICLES] = m_dialogDynamicsWorld->createToggle(settings,"Collide Particles");
\r
233 for(int i = 1; i < SIMSTAGE_TOTAL; i++)
\r
235 m_pWorld->m_useCpuControls[i]->m_active = false;
\r
237 #if defined(CL_PLATFORM_MINI_CL)
\r
238 // these kernels use barrier()
\r
239 m_pWorld->m_useCpuControls[SIMSTAGE_SORT_CELL_ID]->m_active = true;
\r
240 m_pWorld->m_useCpuControls[SIMSTAGE_FIND_CELL_START]->m_active = true;
\r
243 #if defined(CL_PLATFORM_AMD)
\r
244 // these kernels use barrier()
\r
245 m_pWorld->m_useCpuControls[SIMSTAGE_SORT_CELL_ID]->m_active = true;
\r
246 m_pWorld->m_useCpuControls[SIMSTAGE_FIND_CELL_START]->m_active = true;
\r
250 m_dynamicsWorld = m_pWorld;
\r
252 m_pWorld->getSimulationIslandManager()->setSplitIslands(true);
\r
253 m_pWorld->setGravity(btVector3(0,-10.,0));
\r
254 m_pWorld->getSolverInfo().m_numIterations = 4;
\r
257 // btCollisionShape* colShape = new btSphereShape(btScalar(1.0f));
\r
259 btCollisionShape* colShape = new btSphereShape(DEF_PARTICLE_RADIUS);
\r
260 m_collisionShapes.push_back(colShape);
\r
261 btTransform startTransform;
\r
262 startTransform.setIdentity();
\r
263 btScalar mass(1.f);
\r
264 btVector3 localInertia(0,0,0);
\r
265 colShape->calculateLocalInertia(mass,localInertia);
\r
266 float start_x = START_POS_X - ARRAY_SIZE_X * DIST * btScalar(0.5f);
\r
267 float start_y = START_POS_Y - ARRAY_SIZE_Y * DIST * btScalar(0.5f);
\r
268 float start_z = START_POS_Z - ARRAY_SIZE_Z * DIST * btScalar(0.5f);
\r
269 startTransform.setOrigin(btVector3(start_x, start_y, start_z));
\r
270 btRigidBody::btRigidBodyConstructionInfo rbInfo(mass,0,colShape,localInertia);
\r
271 rbInfo.m_startWorldTransform = startTransform;
\r
272 btRigidBody* body = new btRigidBody(rbInfo);
\r
273 m_pWorld->addRigidBody(body);
\r
276 init_scene_directly();
\r
278 clientResetScene();
\r
279 m_pWorld->initDeviceData();
\r
282 inline float frand(void){
\r
283 return (float)rand() / (float)RAND_MAX;
\r
286 void ParticlesDemo::init_scene_directly()
\r
291 float start_x = -1+DEF_PARTICLE_RADIUS;//START_POS_X - ARRAY_SIZE_X * DIST * btScalar(0.5f);
\r
292 float start_y = -1+DEF_PARTICLE_RADIUS;//START_POS_Y - ARRAY_SIZE_Y * DIST * btScalar(0.5f);
\r
293 float start_z = -1+DEF_PARTICLE_RADIUS;//START_POS_Z - ARRAY_SIZE_Z * DIST * btScalar(0.5f);
\r
294 int numParticles = ARRAY_SIZE_X * ARRAY_SIZE_Y * ARRAY_SIZE_Z;
\r
295 m_pWorld->m_hPos.resize(numParticles);
\r
296 m_pWorld->m_hVel.resize(numParticles);
\r
298 btScalar spacing = 2 * DEF_PARTICLE_RADIUS;
\r
300 for(int z=0; z<ARRAY_SIZE_Z; z++)
\r
302 for(int y=0; y<ARRAY_SIZE_Y; y++)
\r
304 for(int x=0; x<ARRAY_SIZE_X; x++)
\r
306 int i = (z * ARRAY_SIZE_Y * ARRAY_SIZE_X) + (y * ARRAY_SIZE_X) + x;
\r
307 if (i < numParticles)
\r
309 btVector3 jitter = 0.01f * 0.03f * btVector3(frand(), frand(), frand());
\r
310 m_pWorld->m_hVel[i]= btVector3(0,0,0);
\r
311 m_pWorld->m_hPos[i].setX((spacing * x) + 2*DEF_PARTICLE_RADIUS -WORLD_SIZE+jitter.getX());
\r
312 m_pWorld->m_hPos[i].setY((spacing * y) + 2*DEF_PARTICLE_RADIUS -WORLD_SIZE+jitter.getY());
\r
313 m_pWorld->m_hPos[i].setZ((spacing * z) + 2*DEF_PARTICLE_RADIUS -WORLD_SIZE+jitter.getZ());
\r
319 m_pWorld->m_numParticles = numParticles;
\r
324 void ParticlesDemo::clientResetScene()
\r
326 static bool bFirstCall = true;
\r
327 DemoApplication::clientResetScene();
\r
328 init_scene_directly();
\r
331 bFirstCall = false;
\r
336 m_pWorld->grabSimulationData();
\r
341 void ParticlesDemo::exitPhysics()
\r
343 delete m_dialogDynamicsWorld;
\r
344 m_dialogDynamicsWorld = 0;
\r
346 //cleanup in the reverse order of creation/initialization
\r
349 //remove the rigidbodies from the dynamics world and delete them
\r
350 for (i=m_pWorld->getNumCollisionObjects()-1; i>=0 ;i--)
\r
352 btCollisionObject* obj = m_pWorld->getCollisionObjectArray()[i];
\r
353 btRigidBody* body = btRigidBody::upcast(obj);
\r
354 if (body && body->getMotionState())
\r
356 delete body->getMotionState();
\r
358 m_pWorld->removeCollisionObject( obj );
\r
361 //delete collision shapes
\r
362 for (int j=0;j<m_collisionShapes.size();j++)
\r
364 btCollisionShape* shape = m_collisionShapes[j];
\r
372 delete m_broadphase;
\r
374 delete m_dispatcher;
\r
376 delete m_collisionConfiguration;
\r
380 void ParticlesDemo::keyboardCallback(unsigned char key, int x, int y)
\r
389 m_drawGridMode %= 3;
\r
398 DemoApplication::keyboardCallback(key, x, y);
\r
410 void ParticlesDemo::renderme()
\r
413 glColor3f(1.0, 1.0, 1.0);
\r
414 glutWireCube(2*WORLD_SIZE);
\r
417 glEnable(GL_POINT_SPRITE_ARB);
\r
419 glTexEnvi(GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, GL_TRUE);
\r
421 // glEnable(GL_VERTEX_PROGRAM_POINT_SIZE_NV);
\r
422 glEnable(GL_VERTEX_PROGRAM_POINT_SIZE);
\r
425 glDepthMask(GL_TRUE);
\r
426 glEnable(GL_DEPTH_TEST);
\r
428 glUseProgram(m_shaderProgram);
\r
430 btScalar dist = (m_glutScreenWidth > m_glutScreenHeight) ? m_glutScreenHeight : m_glutScreenWidth;
\r
431 glUniform1f( glGetUniformLocation(m_shaderProgram, "pointScale"), dist );
\r
432 // glUniform1f( glGetUniformLocation(m_shaderProgram, "pointRadius"), 0.5f );
\r
433 int numParticles = m_pWorld->getNumParticles();
\r
434 int col_vbo = m_pWorld->m_colVbo;
\r
435 int curr_vbo = m_pWorld->m_vbo;
\r
436 float sphere_rad = m_pWorld->m_particleRad;
\r
438 glUniform1f( glGetUniformLocation(m_shaderProgram, "pointRadius"), sphere_rad );
\r
439 glColor3f(1, 1, 1);
\r
441 // render from the vbo
\r
442 glBindBuffer(GL_ARRAY_BUFFER, curr_vbo);
\r
443 glVertexPointer(4, GL_FLOAT, 0, 0);
\r
444 glEnableClientState(GL_VERTEX_ARRAY);
\r
447 glBindBufferARB(GL_ARRAY_BUFFER_ARB, col_vbo);
\r
448 glColorPointer(4, GL_FLOAT, 0, 0);
\r
449 glEnableClientState(GL_COLOR_ARRAY);
\r
451 glDrawArrays(GL_POINTS, 0, numParticles);
\r
452 glDisableClientState(GL_VERTEX_ARRAY);
\r
453 glDisableClientState(GL_COLOR_ARRAY);
\r
455 glDisable(GL_POINT_SPRITE_ARB);
\r
456 glBindBufferARB(GL_ARRAY_BUFFER,0);
\r
459 btVector3& wmin = m_pWorld->m_worldMin;
\r
460 btVector3& wmax = m_pWorld->m_worldMax;
\r
461 glBegin(GL_LINE_LOOP);
\r
462 glVertex3f(wmin[0], wmin[1], wmin[2]);
\r
463 glVertex3f(wmin[0], wmax[1], wmin[2]);
\r
464 glVertex3f(wmax[0], wmax[1], wmin[2]);
\r
465 glVertex3f(wmax[0], wmin[1], wmin[2]);
\r
466 glVertex3f(wmax[0], wmin[1], wmax[2]);
\r
467 glVertex3f(wmax[0], wmax[1], wmax[2]);
\r
468 glVertex3f(wmin[0], wmax[1], wmax[2]);
\r
469 glVertex3f(wmin[0], wmin[1], wmax[2]);
\r
472 glVertex3f(wmin[0], wmin[1], wmin[2]);
\r
473 glVertex3f(wmax[0], wmin[1], wmin[2]);
\r
474 glVertex3f(wmin[0], wmin[1], wmax[2]);
\r
475 glVertex3f(wmax[0], wmin[1], wmax[2]);
\r
476 glVertex3f(wmin[0], wmax[1], wmin[2]);
\r
477 glVertex3f(wmin[0], wmax[1], wmax[2]);
\r
478 glVertex3f(wmax[0], wmax[1], wmin[2]);
\r
479 glVertex3f(wmax[0], wmax[1], wmax[2]);
\r
481 if(m_drawGridMode == 2)
\r
483 int szx = m_pWorld->m_simParams.m_gridSize[0];
\r
484 int szy = m_pWorld->m_simParams.m_gridSize[1];
\r
486 for(int i = 1; i < (szx-1); i++)
\r
488 float wgt = (float)i / (float)(szx-1);
\r
489 btVector3 vtx = wmax * wgt + wmin * (1.0f - wgt);
\r
490 glVertex3f(vtx[0], wmin[1], wmin[2]);
\r
491 glVertex3f(vtx[0], wmax[1], wmin[2]);
\r
493 for(int i = 1; i < (szy-1); i++)
\r
495 float wgt = (float)i / (float)(szy-1);
\r
496 btVector3 vtx = wmax * wgt + wmin * (1.0f - wgt);
\r
497 glVertex3f(wmin[0], vtx[1], wmin[2]);
\r
498 glVertex3f(wmax[0], vtx[1], wmin[2]);
\r
504 if ((m_debugMode & btIDebugDraw::DBG_NoHelpText)==0)
\r
506 setOrthographicProjection();
\r
507 int xOffset = 10.f;
\r
510 showProfileInfo(xOffset, yStart, yIncr);
\r
511 outputDebugInfo(xOffset, yStart, yIncr);
\r
512 resetPerspectiveProjection();
\r
518 void ParticlesDemo::outputDebugInfo(int & xOffset,int & yStart, int yIncr)
\r
521 glDisable(GL_LIGHTING);
\r
522 glColor3f(0, 0, 0);
\r
524 sprintf(buf,"mouse move+buttons to interact");
\r
525 GLDebugDrawString(xOffset,yStart,buf);
\r
529 sprintf(buf,"space to reset");
\r
530 GLDebugDrawString(xOffset,yStart,buf);
\r
534 sprintf(buf,"cursor keys and z,x to navigate");
\r
535 GLDebugDrawString(xOffset,yStart,buf);
\r
539 sprintf(buf,"i to toggle simulation, s single step");
\r
540 GLDebugDrawString(xOffset,yStart,buf);
\r
544 sprintf(buf,"q to quit");
\r
545 GLDebugDrawString(xOffset,yStart,buf);
\r
549 sprintf(buf,"h to toggle help text");
\r
550 GLDebugDrawString(xOffset,yStart,buf);
\r
554 sprintf(buf,"p to toggle profiling (+results to file)");
\r
555 GLDebugDrawString(xOffset,yStart,buf);
\r
558 sprintf(buf,"j to toggle between demos (integration/OECake2D/OECake3D)");
\r
559 GLDebugDrawString(xOffset,yStart,buf);
\r
563 sprintf(buf,"G to draw broadphase grid");
\r
564 GLDebugDrawString(xOffset,yStart,buf);
\r
566 sprintf(buf,"D and U to toggle between GPU and CPU");
\r
567 GLDebugDrawString(xOffset,yStart,buf);
\r
575 GLuint _compileProgram(const char *vsource, const char *fsource)
\r
577 GLuint vertexShader = glCreateShader(GL_VERTEX_SHADER);
\r
578 GLuint fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
\r
580 glShaderSource(vertexShader, 1, &vsource, 0);
\r
581 glShaderSource(fragmentShader, 1, &fsource, 0);
\r
583 glCompileShader(vertexShader);
\r
584 glCompileShader(fragmentShader);
\r
586 GLuint program = glCreateProgram();
\r
588 glAttachShader(program, vertexShader);
\r
589 glAttachShader(program, fragmentShader);
\r
591 glLinkProgram(program);
\r
593 // check if program linked
\r
595 glGetProgramiv(program, GL_LINK_STATUS, &success);
\r
599 glGetProgramInfoLog(program, 256, 0, temp);
\r
600 printf("Failed to link program:\n%s\n", temp);
\r
601 glDeleteProgram(program);
\r
608 void ParticlesDemo::myinit()
\r
610 DemoApplication::myinit();
\r
613 if (!glewIsSupported("GL_VERSION_2_0 GL_VERSION_1_5 GL_ARB_multitexture GL_ARB_vertex_buffer_object")) {
\r
614 fprintf(stderr, "Required OpenGL extensions missing.");
\r
619 m_shaderProgram = _compileProgram(vertexShader, spherePixelShader);
\r
620 m_pWorld->initCLKernels(m_argc, m_argv);
\r
628 void ParticlesDemo::mouseFunc(int button, int state, int x, int y)
\r
631 if (!m_dialogDynamicsWorld->mouseFunc(button,state,x,y))
\r
633 DemoApplication::mouseFunc(button,state,x,y);
\r
637 void ParticlesDemo::mouseMotionFunc(int x,int y)
\r
639 m_dialogDynamicsWorld->mouseMotionFunc(x,y);
\r
640 DemoApplication::mouseMotionFunc(x,y);
\r
645 void ParticlesDemo::reshape(int w, int h)
\r
647 if (m_dialogDynamicsWorld)
\r
648 m_dialogDynamicsWorld->setScreenSize(w,h);
\r
649 GlutDemoApplication::reshape(w,h);
\r