Files
bullet3/Demos/ParticlesOpenCL/ParticlesDemo.cpp
erwin.coumans fbc17731ec Several changes to sync Bullet trunk with PlayStation 3 spubullet version
Still needs some cross-platform fixes
2010-07-08 17:02:38 +00:00

652 lines
18 KiB
C++

/*
Bullet Continuous Collision Detection and Physics Library, http://bulletphysics.org
Copyright (C) 2006 - 2009 Sony Computer Entertainment Inc.
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.
*/
#define START_POS_X btScalar(0.f)
#define START_POS_Y btScalar(0.f)
#define START_POS_Z btScalar(0.f)
//#define START_POS_Y btScalar(40.f)
//#define START_POS_Z btScalar(40.f)
//#define START_POS_Y btScalar(0.4f)
//#define START_POS_Z btScalar(0.4f)
#define ARRAY_SIZE_X 32
#define ARRAY_SIZE_Y 32
//#define ARRAY_SIZE_Y 16
#define ARRAY_SIZE_Z 16
//16
//#define ARRAY_SIZE_Z 1
//#define DIST btScalar(2.f)
#define DIST (DEF_PARTICLE_RADIUS * 2.f)
#define STRESS_X 20
//#define STRESS_Y 200
#define STRESS_Y 640
///The 3 following lines include the CPU implementation of the kernels, keep them in this order.
#include "BulletMultiThreaded/btGpuDefines.h"
#include "BulletMultiThreaded/btGpuUtilsSharedDefs.h"
#include "BulletMultiThreaded/btGpuUtilsSharedCode.h"
#ifndef __APPLE__
#include <GL/glew.h>
#endif
#include "GL_DialogDynamicsWorld.h"
#include "GL_DialogWindow.h"
#include "BulletCollision/CollisionDispatch/btEmptyCollisionAlgorithm.h"
#include "BulletCollision/CollisionDispatch/btSimulationIslandManager.h"
#include "GLDebugFont.h"
#include "GlutStuff.h"
///btBulletDynamicsCommon.h is the main Bullet include file, contains most common include files.
#include "btBulletDynamicsCommon.h"
#include <stdio.h> //printf debugging
#include "shaders.h"
#include "ParticlesDemo.h"
btScalar gTimeStep = 0.5f;//btScalar(1./60.);
#define SCALING btScalar(1.f)
void ParticlesDemo::clientMoveAndDisplay()
{
updateCamera();
glDisable(GL_LIGHTING);
glColor3f(1.f, 1.f, 1.f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glDisable(GL_TEXTURE_2D); // we always draw wireframe in this demo
//simple dynamics world doesn't handle fixed-time-stepping
float ms = getDeltaTimeMicroseconds();
renderme();
if (m_dialogDynamicsWorld)
m_dialogDynamicsWorld->draw(gTimeStep);
///step the simulation
if (m_dynamicsWorld)
{
m_dynamicsWorld->stepSimulation(gTimeStep,0);//ms / 1000000.f);
//optional but useful: debug drawing
m_dynamicsWorld->debugDrawWorld();
}
ms = getDeltaTimeMicroseconds();
glFlush();
glutSwapBuffers();
}
void ParticlesDemo::displayCallback(void) {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
renderme();
//optional but useful: debug drawing to detect problems
if (m_dynamicsWorld)
m_dynamicsWorld->debugDrawWorld();
//if (m_dialogDynamicsWorld)
// m_dialogDynamicsWorld->draw(gTimeStep);
glFlush();
glutSwapBuffers();
}
class btNullBroadphase : public btBroadphaseInterface
{
public:
btNullBroadphase()
{
}
virtual ~btNullBroadphase()
{
}
virtual btBroadphaseProxy* createProxy( const btVector3& aabbMin, const btVector3& aabbMax,int shapeType,void* userPtr, short int collisionFilterGroup,short int collisionFilterMask, btDispatcher* dispatcher,void* multiSapProxy)
{
return NULL;
}
virtual void destroyProxy(btBroadphaseProxy* proxy,btDispatcher* dispatcher)
{
}
virtual void setAabb(btBroadphaseProxy* proxy,const btVector3& aabbMin,const btVector3& aabbMax, btDispatcher* dispatcher)
{
}
virtual void getAabb(btBroadphaseProxy* proxy,btVector3& aabbMin, btVector3& aabbMax ) const
{
}
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))
{
}
virtual void calculateOverlappingPairs(btDispatcher* dispatcher)
{
}
virtual btOverlappingPairCache* getOverlappingPairCache()
{
return NULL;
}
virtual const btOverlappingPairCache* getOverlappingPairCache() const
{
return NULL;
}
virtual void getBroadphaseAabb(btVector3& aabbMin,btVector3& aabbMax) const
{
}
virtual void resetPool(btDispatcher* dispatcher)
{
}
virtual void printStats()
{
}
virtual void aabbTest(const btVector3& aabbMin, const btVector3& aabbMax, btBroadphaseAabbCallback& callback)
{
}
};
void ParticlesDemo::initPhysics()
{
setTexturing(false);
setShadows(false);
// setCameraDistance(80.f);
setCameraDistance(3.0f);
// m_cameraTargetPosition.setValue(50, 10, 0);
m_cameraTargetPosition.setValue(0, 0, 0);
// m_azi = btScalar(0.f);
// m_ele = btScalar(0.f);
m_azi = btScalar(45.f);
m_ele = btScalar(30.f);
setFrustumZPlanes(0.1f, 10.f);
///collision configuration contains default setup for memory, collision setup
btDefaultCollisionConstructionInfo dci;
dci.m_defaultMaxPersistentManifoldPoolSize=50000;
dci.m_defaultMaxCollisionAlgorithmPoolSize=50000;
m_collisionConfiguration = new btDefaultCollisionConfiguration(dci);
///use the default collision dispatcher. For parallel processing you can use a diffent dispatcher (see Extras/BulletMultiThreaded)
m_dispatcher = new btCollisionDispatcher(m_collisionConfiguration);
m_pairCache = new (btAlignedAlloc(sizeof(btHashedOverlappingPairCache),16))btHashedOverlappingPairCache();
// m_broadphase = new btDbvtBroadphase(m_pairCache);
m_broadphase = new btNullBroadphase();
///the default constraint solver
m_solver = new btSequentialImpulseConstraintSolver();
m_pWorld = new btParticlesDynamicsWorld(m_dispatcher,m_broadphase,m_solver,m_collisionConfiguration, 65536);
m_dialogDynamicsWorld = new GL_DialogDynamicsWorld();
GL_DialogWindow* settings = m_dialogDynamicsWorld->createDialog(50,0,280,280,"CPU fallback");
m_pWorld->m_useCpuControls[0] = 0;
GL_ToggleControl* ctrl = 0;
m_pWorld->m_useCpuControls[SIMSTAGE_INTEGRATE_MOTION] = m_dialogDynamicsWorld->createToggle(settings,"Integrate Motion");
m_pWorld->m_useCpuControls[SIMSTAGE_COMPUTE_CELL_ID] = m_dialogDynamicsWorld->createToggle(settings,"Compute Cell ID");
m_pWorld->m_useCpuControls[SIMSTAGE_SORT_CELL_ID] = m_dialogDynamicsWorld->createToggle(settings,"Sort Cell ID");
m_pWorld->m_useCpuControls[SIMSTAGE_FIND_CELL_START] = m_dialogDynamicsWorld->createToggle(settings,"Find Cell Start");
m_pWorld->m_useCpuControls[SIMSTAGE_COLLIDE_PARTICLES] = m_dialogDynamicsWorld->createToggle(settings,"Collide Particles");
for(int i = 1; i < SIMSTAGE_TOTAL; i++)
{
m_pWorld->m_useCpuControls[i]->m_active = false;
}
#if defined(CL_PLATFORM_MINI_CL)
// these kernels use barrier()
m_pWorld->m_useCpuControls[SIMSTAGE_SORT_CELL_ID]->m_active = true;
m_pWorld->m_useCpuControls[SIMSTAGE_FIND_CELL_START]->m_active = true;
#endif
#if defined(CL_PLATFORM_AMD)
// these kernels use barrier()
m_pWorld->m_useCpuControls[SIMSTAGE_SORT_CELL_ID]->m_active = true;
m_pWorld->m_useCpuControls[SIMSTAGE_FIND_CELL_START]->m_active = true;
#endif
m_dynamicsWorld = m_pWorld;
m_pWorld->getSimulationIslandManager()->setSplitIslands(true);
m_pWorld->setGravity(btVector3(0,-10.,0));
m_pWorld->getSolverInfo().m_numIterations = 4;
{
// btCollisionShape* colShape = new btSphereShape(btScalar(1.0f));
/*
btCollisionShape* colShape = new btSphereShape(DEF_PARTICLE_RADIUS);
m_collisionShapes.push_back(colShape);
btTransform startTransform;
startTransform.setIdentity();
btScalar mass(1.f);
btVector3 localInertia(0,0,0);
colShape->calculateLocalInertia(mass,localInertia);
float start_x = START_POS_X - ARRAY_SIZE_X * DIST * btScalar(0.5f);
float start_y = START_POS_Y - ARRAY_SIZE_Y * DIST * btScalar(0.5f);
float start_z = START_POS_Z - ARRAY_SIZE_Z * DIST * btScalar(0.5f);
startTransform.setOrigin(btVector3(start_x, start_y, start_z));
btRigidBody::btRigidBodyConstructionInfo rbInfo(mass,0,colShape,localInertia);
rbInfo.m_startWorldTransform = startTransform;
btRigidBody* body = new btRigidBody(rbInfo);
m_pWorld->addRigidBody(body);
*/
init_scene_directly();
}
clientResetScene();
m_pWorld->initDeviceData();
}
inline float frand(void){
return (float)rand() / (float)RAND_MAX;
}
void ParticlesDemo::init_scene_directly()
{
srand(1969);
float start_x = -1+DEF_PARTICLE_RADIUS;//START_POS_X - ARRAY_SIZE_X * DIST * btScalar(0.5f);
float start_y = -1+DEF_PARTICLE_RADIUS;//START_POS_Y - ARRAY_SIZE_Y * DIST * btScalar(0.5f);
float start_z = -1+DEF_PARTICLE_RADIUS;//START_POS_Z - ARRAY_SIZE_Z * DIST * btScalar(0.5f);
int numParticles = ARRAY_SIZE_X * ARRAY_SIZE_Y * ARRAY_SIZE_Z;
m_pWorld->m_hPos.resize(numParticles);
m_pWorld->m_hVel.resize(numParticles);
btScalar spacing = 2 * DEF_PARTICLE_RADIUS;
for(int z=0; z<ARRAY_SIZE_Z; z++)
{
for(int y=0; y<ARRAY_SIZE_Y; y++)
{
for(int x=0; x<ARRAY_SIZE_X; x++)
{
int i = (z * ARRAY_SIZE_Y * ARRAY_SIZE_X) + (y * ARRAY_SIZE_X) + x;
if (i < numParticles)
{
btVector3 jitter = 0.01f * 0.03f * btVector3(frand(), frand(), frand());
m_pWorld->m_hVel[i]= btVector3(0,0,0);
m_pWorld->m_hPos[i].setX((spacing * x) + DEF_PARTICLE_RADIUS -WORLD_SIZE+jitter.getX());
m_pWorld->m_hPos[i].setY((spacing * y) + DEF_PARTICLE_RADIUS -WORLD_SIZE+jitter.getY());
m_pWorld->m_hPos[i].setZ((spacing * z) + DEF_PARTICLE_RADIUS -WORLD_SIZE+jitter.getZ());
}
}
}
}
m_pWorld->m_numParticles = numParticles;
}
void ParticlesDemo::clientResetScene()
{
static bool bFirstCall = true;
DemoApplication::clientResetScene();
init_scene_directly();
if(bFirstCall)
{
bFirstCall = false;
}
else
{
m_pWorld->grabSimulationData();
}
}
void ParticlesDemo::exitPhysics()
{
delete m_dialogDynamicsWorld;
m_dialogDynamicsWorld = 0;
//cleanup in the reverse order of creation/initialization
int i;
//remove the rigidbodies from the dynamics world and delete them
for (i=m_pWorld->getNumCollisionObjects()-1; i>=0 ;i--)
{
btCollisionObject* obj = m_pWorld->getCollisionObjectArray()[i];
btRigidBody* body = btRigidBody::upcast(obj);
if (body && body->getMotionState())
{
delete body->getMotionState();
}
m_pWorld->removeCollisionObject( obj );
delete obj;
}
//delete collision shapes
for (int j=0;j<m_collisionShapes.size();j++)
{
btCollisionShape* shape = m_collisionShapes[j];
delete shape;
}
delete m_pWorld;
delete m_solver;
delete m_broadphase;
delete m_dispatcher;
delete m_collisionConfiguration;
}
void ParticlesDemo::keyboardCallback(unsigned char key, int x, int y)
{
(void)x;
(void)y;
switch (key)
{
case 'G' :
{
m_drawGridMode++;
m_drawGridMode %= 3;
}
break;
case 'q' :
exitPhysics();
exit(0);
break;
default :
{
DemoApplication::keyboardCallback(key, x, y);
}
break;
}
if(key == ' ')
{
}
}
void ParticlesDemo::renderme()
{
glColor3f(1.0, 1.0, 1.0);
glutWireCube(2*WORLD_SIZE);
glPointSize(5.0f);
glEnable(GL_POINT_SPRITE_ARB);
glTexEnvi(GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, GL_TRUE);
#ifndef __APPLE__
// glEnable(GL_VERTEX_PROGRAM_POINT_SIZE_NV);
glEnable(GL_VERTEX_PROGRAM_POINT_SIZE);
#endif //__APPLE__
glDepthMask(GL_TRUE);
glEnable(GL_DEPTH_TEST);
glUseProgram(m_shaderProgram);
btScalar dist = (m_glutScreenWidth > m_glutScreenHeight) ? m_glutScreenHeight : m_glutScreenWidth;
glUniform1f( glGetUniformLocation(m_shaderProgram, "pointScale"), dist );
// glUniform1f( glGetUniformLocation(m_shaderProgram, "pointRadius"), 0.5f );
int numParticles = m_pWorld->getNumParticles();
int col_vbo = m_pWorld->m_colVbo;
int curr_vbo = m_pWorld->m_vbo;
float sphere_rad = m_pWorld->m_particleRad;
glUniform1f( glGetUniformLocation(m_shaderProgram, "pointRadius"), sphere_rad );
glColor3f(1, 1, 1);
// render from the vbo
glBindBuffer(GL_ARRAY_BUFFER, curr_vbo);
glVertexPointer(4, GL_FLOAT, 0, 0);
glEnableClientState(GL_VERTEX_ARRAY);
if(col_vbo)
{
glBindBufferARB(GL_ARRAY_BUFFER_ARB, col_vbo);
glColorPointer(4, GL_FLOAT, 0, 0);
glEnableClientState(GL_COLOR_ARRAY);
}
glDrawArrays(GL_POINTS, 0, numParticles);
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_COLOR_ARRAY);
glUseProgram(0);
glDisable(GL_POINT_SPRITE_ARB);
glBindBufferARB(GL_ARRAY_BUFFER,0);
if(m_drawGridMode)
{
btVector3& wmin = m_pWorld->m_worldMin;
btVector3& wmax = m_pWorld->m_worldMax;
glBegin(GL_LINE_LOOP);
glVertex3f(wmin[0], wmin[1], wmin[2]);
glVertex3f(wmin[0], wmax[1], wmin[2]);
glVertex3f(wmax[0], wmax[1], wmin[2]);
glVertex3f(wmax[0], wmin[1], wmin[2]);
glVertex3f(wmax[0], wmin[1], wmax[2]);
glVertex3f(wmax[0], wmax[1], wmax[2]);
glVertex3f(wmin[0], wmax[1], wmax[2]);
glVertex3f(wmin[0], wmin[1], wmax[2]);
glEnd();
glBegin(GL_LINES);
glVertex3f(wmin[0], wmin[1], wmin[2]);
glVertex3f(wmax[0], wmin[1], wmin[2]);
glVertex3f(wmin[0], wmin[1], wmax[2]);
glVertex3f(wmax[0], wmin[1], wmax[2]);
glVertex3f(wmin[0], wmax[1], wmin[2]);
glVertex3f(wmin[0], wmax[1], wmax[2]);
glVertex3f(wmax[0], wmax[1], wmin[2]);
glVertex3f(wmax[0], wmax[1], wmax[2]);
glEnd();
if(m_drawGridMode == 2)
{
int szx = m_pWorld->m_simParams.m_gridSize[0];
int szy = m_pWorld->m_simParams.m_gridSize[1];
glBegin(GL_LINES);
for(int i = 1; i < (szx-1); i++)
{
float wgt = (float)i / (float)(szx-1);
btVector3 vtx = wmax * wgt + wmin * (1.0f - wgt);
glVertex3f(vtx[0], wmin[1], wmin[2]);
glVertex3f(vtx[0], wmax[1], wmin[2]);
}
for(int i = 1; i < (szy-1); i++)
{
float wgt = (float)i / (float)(szy-1);
btVector3 vtx = wmax * wgt + wmin * (1.0f - wgt);
glVertex3f(wmin[0], vtx[1], wmin[2]);
glVertex3f(wmax[0], vtx[1], wmin[2]);
}
glEnd();
}
}
if ((m_debugMode & btIDebugDraw::DBG_NoHelpText)==0)
{
setOrthographicProjection();
int xOffset = 10.f;
int yStart = 20.f;
int yIncr = 20.f;
showProfileInfo(xOffset, yStart, yIncr);
outputDebugInfo(xOffset, yStart, yIncr);
resetPerspectiveProjection();
}
}
void ParticlesDemo::outputDebugInfo(int & xOffset,int & yStart, int yIncr)
{
char buf[124];
glDisable(GL_LIGHTING);
glColor3f(0, 0, 0);
sprintf(buf,"mouse move+buttons to interact");
GLDebugDrawString(xOffset,yStart,buf);
yStart += yIncr;
sprintf(buf,"space to reset");
GLDebugDrawString(xOffset,yStart,buf);
yStart += yIncr;
sprintf(buf,"cursor keys and z,x to navigate");
GLDebugDrawString(xOffset,yStart,buf);
yStart += yIncr;
sprintf(buf,"i to toggle simulation, s single step");
GLDebugDrawString(xOffset,yStart,buf);
yStart += yIncr;
sprintf(buf,"q to quit");
GLDebugDrawString(xOffset,yStart,buf);
yStart += yIncr;
sprintf(buf,"h to toggle help text");
GLDebugDrawString(xOffset,yStart,buf);
yStart += yIncr;
sprintf(buf,"p to toggle profiling (+results to file)");
GLDebugDrawString(xOffset,yStart,buf);
yStart += yIncr;
sprintf(buf,"j to toggle between demos (integration/OECake2D/OECake3D)");
GLDebugDrawString(xOffset,yStart,buf);
yStart += yIncr;
{
sprintf(buf,"G to draw broadphase grid");
GLDebugDrawString(xOffset,yStart,buf);
yStart += yIncr;
sprintf(buf,"D and U to toggle between GPU and CPU");
GLDebugDrawString(xOffset,yStart,buf);
yStart += yIncr;
}
}
GLuint _compileProgram(const char *vsource, const char *fsource)
{
GLuint vertexShader = glCreateShader(GL_VERTEX_SHADER);
GLuint fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(vertexShader, 1, &vsource, 0);
glShaderSource(fragmentShader, 1, &fsource, 0);
glCompileShader(vertexShader);
glCompileShader(fragmentShader);
GLuint program = glCreateProgram();
glAttachShader(program, vertexShader);
glAttachShader(program, fragmentShader);
glLinkProgram(program);
// check if program linked
GLint success = 0;
glGetProgramiv(program, GL_LINK_STATUS, &success);
if (!success) {
char temp[256];
glGetProgramInfoLog(program, 256, 0, temp);
printf("Failed to link program:\n%s\n", temp);
glDeleteProgram(program);
program = 0;
}
return program;
}
void ParticlesDemo::myinit()
{
DemoApplication::myinit();
#ifndef __APPLE__
glewInit();
if (!glewIsSupported("GL_VERSION_2_0 GL_VERSION_1_5 GL_ARB_multitexture GL_ARB_vertex_buffer_object")) {
fprintf(stderr, "Required OpenGL extensions missing.");
exit(-1);
}
#endif //__APPLE__
m_shaderProgram = _compileProgram(vertexShader, spherePixelShader);
m_pWorld->initCLKernels(m_argc, m_argv);
}
void ParticlesDemo::mouseFunc(int button, int state, int x, int y)
{
if (!m_dialogDynamicsWorld->mouseFunc(button,state,x,y))
{
DemoApplication::mouseFunc(button,state,x,y);
}
}
void ParticlesDemo::mouseMotionFunc(int x,int y)
{
m_dialogDynamicsWorld->mouseMotionFunc(x,y);
DemoApplication::mouseMotionFunc(x,y);
}
void ParticlesDemo::reshape(int w, int h)
{
if (m_dialogDynamicsWorld)
m_dialogDynamicsWorld->setScreenSize(w,h);
GlutDemoApplication::reshape(w,h);
}