Imported Upstream version 2.81
[platform/upstream/libbullet.git] / Demos / ParticlesOpenCL / ParticlesDemo.cpp
1 /*\r
2 Bullet Continuous Collision Detection and Physics Library, http://bulletphysics.org\r
3 Copyright (C) 2006 - 2009 Sony Computer Entertainment Inc. \r
4 \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
10 \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
14 */\r
15 \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
27 //16\r
28 //#define ARRAY_SIZE_Z 1\r
29 //#define DIST btScalar(2.f)\r
30 #define DIST (DEF_PARTICLE_RADIUS * 2.f)\r
31 \r
32 #define STRESS_X  20\r
33 //#define STRESS_Y  200\r
34 #define STRESS_Y  640\r
35 \r
36 \r
37 \r
38                 \r
39 \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
44 #ifndef __APPLE__\r
45 #include <GL/glew.h>\r
46 #endif\r
47 \r
48 \r
49 #include "GL_DialogDynamicsWorld.h"\r
50 #include "GL_DialogWindow.h"\r
51 \r
52 \r
53 \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
62 \r
63 #include "ParticlesDemo.h"\r
64 \r
65 \r
66 \r
67 \r
68 \r
69 btScalar gTimeStep = 0.5f;//btScalar(1./60.);\r
70 \r
71 #define SCALING btScalar(1.f)\r
72 \r
73 void ParticlesDemo::clientMoveAndDisplay()\r
74 {\r
75 \r
76 \r
77         updateCamera();\r
78         glDisable(GL_LIGHTING);\r
79         glColor3f(1.f, 1.f, 1.f);\r
80 \r
81         glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); \r
82 \r
83         glDisable(GL_TEXTURE_2D); // we always draw wireframe in this demo\r
84 \r
85         //simple dynamics world doesn't handle fixed-time-stepping\r
86         float ms = getDeltaTimeMicroseconds();\r
87 \r
88         renderme(); \r
89 \r
90         if (m_dialogDynamicsWorld)\r
91                 m_dialogDynamicsWorld->draw(gTimeStep);\r
92 \r
93         ///step the simulation\r
94         if (m_dynamicsWorld)\r
95         {\r
96                 m_dynamicsWorld->stepSimulation(gTimeStep,0);//ms / 1000000.f);\r
97                 //optional but useful: debug drawing\r
98                 m_dynamicsWorld->debugDrawWorld();\r
99         }\r
100 \r
101         \r
102 \r
103         ms = getDeltaTimeMicroseconds();\r
104 \r
105         glFlush();\r
106 \r
107         glutSwapBuffers();\r
108 \r
109 }\r
110 \r
111 \r
112 \r
113 void ParticlesDemo::displayCallback(void) {\r
114 \r
115         \r
116         glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); \r
117 \r
118         renderme();\r
119 \r
120         //optional but useful: debug drawing to detect problems\r
121         if (m_dynamicsWorld)\r
122                 m_dynamicsWorld->debugDrawWorld();\r
123 \r
124         //if (m_dialogDynamicsWorld)\r
125         //      m_dialogDynamicsWorld->draw(gTimeStep);\r
126 \r
127         glFlush();\r
128         glutSwapBuffers();\r
129 }\r
130 \r
131 class btNullBroadphase : public btBroadphaseInterface\r
132 {\r
133 public:\r
134         btNullBroadphase()\r
135         {\r
136         }\r
137         virtual ~btNullBroadphase() \r
138         {\r
139         }\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
141         {\r
142                 return NULL;\r
143         }\r
144         virtual void    destroyProxy(btBroadphaseProxy* proxy,btDispatcher* dispatcher)\r
145         {\r
146         }\r
147         virtual void    setAabb(btBroadphaseProxy* proxy,const btVector3& aabbMin,const btVector3& aabbMax, btDispatcher* dispatcher)\r
148         {\r
149         }\r
150         virtual void    getAabb(btBroadphaseProxy* proxy,btVector3& aabbMin, btVector3& aabbMax ) const\r
151         {\r
152         }\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
154         {\r
155         }\r
156         virtual void    calculateOverlappingPairs(btDispatcher* dispatcher)\r
157         {\r
158         }\r
159         virtual btOverlappingPairCache* getOverlappingPairCache()\r
160         {\r
161                 return NULL;\r
162         }\r
163         virtual const btOverlappingPairCache*   getOverlappingPairCache() const\r
164         {\r
165                 return NULL;\r
166         }\r
167         virtual void getBroadphaseAabb(btVector3& aabbMin,btVector3& aabbMax) const\r
168         {\r
169         }\r
170         virtual void resetPool(btDispatcher* dispatcher)\r
171         {\r
172         }\r
173         virtual void    printStats()\r
174         {\r
175         }\r
176         virtual void    aabbTest(const btVector3& aabbMin, const btVector3& aabbMax, btBroadphaseAabbCallback& callback)\r
177         {\r
178         }\r
179 };\r
180 \r
181 \r
182 \r
183 void    ParticlesDemo::initPhysics()\r
184 {\r
185         \r
186         setTexturing(false);\r
187         setShadows(false);\r
188 \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
198 \r
199         ///collision configuration contains default setup for memory, collision setup\r
200 \r
201         btDefaultCollisionConstructionInfo dci;\r
202         dci.m_defaultMaxPersistentManifoldPoolSize=50000;\r
203         dci.m_defaultMaxCollisionAlgorithmPoolSize=50000;\r
204 \r
205         m_collisionConfiguration = new btDefaultCollisionConfiguration(dci);\r
206 \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
209 \r
210         m_pairCache = new (btAlignedAlloc(sizeof(btHashedOverlappingPairCache),16))btHashedOverlappingPairCache(); \r
211 \r
212 \r
213 //      m_broadphase = new btDbvtBroadphase(m_pairCache);\r
214         m_broadphase = new btNullBroadphase();\r
215 \r
216         ///the default constraint solver\r
217         m_solver = new btSequentialImpulseConstraintSolver();\r
218 \r
219         m_pWorld = new btParticlesDynamicsWorld(m_dispatcher,m_broadphase,m_solver,m_collisionConfiguration, 65536);\r
220 \r
221         m_dialogDynamicsWorld = new GL_DialogDynamicsWorld();\r
222         GL_DialogWindow* settings = m_dialogDynamicsWorld->createDialog(50,0,280,280,"CPU fallback");\r
223         \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
231         \r
232 \r
233         for(int i = 1; i < SIMSTAGE_TOTAL; i++)\r
234         {\r
235                 m_pWorld->m_useCpuControls[i]->m_active = false;\r
236         }\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
241 #endif\r
242 \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
247 #endif\r
248 \r
249 \r
250         m_dynamicsWorld = m_pWorld;\r
251 \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
255 \r
256         {\r
257 //              btCollisionShape* colShape = new btSphereShape(btScalar(1.0f));\r
258 /*      \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
274                 */\r
275 \r
276                 init_scene_directly();\r
277         }\r
278         clientResetScene();\r
279         m_pWorld->initDeviceData();\r
280 }\r
281 \r
282 inline float frand(void){\r
283     return (float)rand() / (float)RAND_MAX;\r
284 }\r
285 \r
286 void ParticlesDemo::init_scene_directly()\r
287 {\r
288 \r
289 \r
290         srand(1969);\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
297         \r
298         btScalar spacing = 2 * DEF_PARTICLE_RADIUS;\r
299 \r
300         for(int z=0; z<ARRAY_SIZE_Z; z++) \r
301     {\r
302         for(int y=0; y<ARRAY_SIZE_Y; y++) \r
303         {\r
304             for(int x=0; x<ARRAY_SIZE_X; x++) \r
305             {\r
306                 int i = (z * ARRAY_SIZE_Y * ARRAY_SIZE_X) + (y * ARRAY_SIZE_X) + x;\r
307                 if (i < numParticles) \r
308                 {\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
314                 }\r
315             }\r
316         }\r
317     }\r
318 \r
319         m_pWorld->m_numParticles = numParticles;\r
320         \r
321 }\r
322 \r
323 \r
324 void ParticlesDemo::clientResetScene()\r
325 {\r
326         static bool bFirstCall = true;\r
327         DemoApplication::clientResetScene();\r
328         init_scene_directly();\r
329         if(bFirstCall)\r
330         {\r
331                 bFirstCall = false;\r
332         }\r
333         else\r
334         {\r
335         \r
336                 m_pWorld->grabSimulationData();\r
337         }\r
338 }\r
339 \r
340 \r
341 void    ParticlesDemo::exitPhysics()\r
342 {\r
343         delete m_dialogDynamicsWorld;\r
344         m_dialogDynamicsWorld = 0;\r
345 \r
346         //cleanup in the reverse order of creation/initialization\r
347         int i;\r
348 \r
349         //remove the rigidbodies from the dynamics world and delete them\r
350         for (i=m_pWorld->getNumCollisionObjects()-1; i>=0 ;i--)\r
351         {\r
352                 btCollisionObject* obj = m_pWorld->getCollisionObjectArray()[i];\r
353                 btRigidBody* body = btRigidBody::upcast(obj);\r
354                 if (body && body->getMotionState())\r
355                 {\r
356                         delete body->getMotionState();\r
357                 }\r
358                 m_pWorld->removeCollisionObject( obj );\r
359                 delete obj;\r
360         }\r
361         //delete collision shapes\r
362         for (int j=0;j<m_collisionShapes.size();j++)\r
363         {\r
364                 btCollisionShape* shape = m_collisionShapes[j];\r
365                 delete shape;\r
366         }\r
367 \r
368         delete m_pWorld;\r
369 \r
370         delete m_solver;\r
371         \r
372         delete m_broadphase;\r
373         \r
374         delete m_dispatcher;\r
375 \r
376         delete m_collisionConfiguration;\r
377 }\r
378 \r
379 \r
380 void ParticlesDemo::keyboardCallback(unsigned char key, int x, int y)\r
381 {\r
382         (void)x;\r
383         (void)y;\r
384         switch (key) \r
385         {\r
386                 case 'G' :\r
387                         {\r
388                                 m_drawGridMode++;\r
389                                 m_drawGridMode %= 3;\r
390                         }\r
391                         break;\r
392                 case 'q' : \r
393                         exitPhysics();\r
394                         exit(0);\r
395                         break;\r
396                 default : \r
397                         {\r
398                                 DemoApplication::keyboardCallback(key, x, y);\r
399                         }\r
400                         break;\r
401         }\r
402         \r
403         if(key == ' ')\r
404         {\r
405         }\r
406 }\r
407 \r
408 \r
409 \r
410 void ParticlesDemo::renderme()\r
411 {\r
412 \r
413     glColor3f(1.0, 1.0, 1.0);\r
414         glutWireCube(2*WORLD_SIZE);\r
415 \r
416         glPointSize(5.0f);\r
417         glEnable(GL_POINT_SPRITE_ARB);\r
418 \r
419         glTexEnvi(GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, GL_TRUE);\r
420 #ifndef __APPLE__\r
421 //      glEnable(GL_VERTEX_PROGRAM_POINT_SIZE_NV);\r
422         glEnable(GL_VERTEX_PROGRAM_POINT_SIZE);\r
423 #endif //__APPLE__\r
424         \r
425         glDepthMask(GL_TRUE);\r
426         glEnable(GL_DEPTH_TEST);\r
427 \r
428         glUseProgram(m_shaderProgram);\r
429 \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
437 \r
438         glUniform1f( glGetUniformLocation(m_shaderProgram, "pointRadius"), sphere_rad );\r
439         glColor3f(1, 1, 1);\r
440 \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
445     if(col_vbo) \r
446         {\r
447                 glBindBufferARB(GL_ARRAY_BUFFER_ARB, col_vbo);\r
448                 glColorPointer(4, GL_FLOAT, 0, 0);\r
449                 glEnableClientState(GL_COLOR_ARRAY);\r
450         }\r
451         glDrawArrays(GL_POINTS, 0, numParticles);\r
452     glDisableClientState(GL_VERTEX_ARRAY);\r
453     glDisableClientState(GL_COLOR_ARRAY); \r
454         glUseProgram(0);\r
455         glDisable(GL_POINT_SPRITE_ARB);\r
456         glBindBufferARB(GL_ARRAY_BUFFER,0);\r
457         if(m_drawGridMode)\r
458         {\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
470                 glEnd();\r
471                 glBegin(GL_LINES);\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
480                 glEnd();\r
481                 if(m_drawGridMode == 2)\r
482                 {\r
483                         int szx = m_pWorld->m_simParams.m_gridSize[0];\r
484                         int szy = m_pWorld->m_simParams.m_gridSize[1];\r
485                         glBegin(GL_LINES);\r
486                         for(int i = 1; i < (szx-1); i++)\r
487                         {\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
492                         }\r
493                         for(int i = 1; i < (szy-1); i++)\r
494                         {\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
499                         }\r
500                 glEnd();\r
501                 }\r
502         }\r
503 \r
504         if ((m_debugMode & btIDebugDraw::DBG_NoHelpText)==0)\r
505         {\r
506                 setOrthographicProjection();\r
507                 int  xOffset = 10.f;\r
508                 int  yStart = 20.f;\r
509                 int  yIncr = 20.f;\r
510                 showProfileInfo(xOffset, yStart, yIncr);\r
511                 outputDebugInfo(xOffset, yStart, yIncr);\r
512                 resetPerspectiveProjection();\r
513         }\r
514 }\r
515 \r
516 \r
517 \r
518 void ParticlesDemo::outputDebugInfo(int & xOffset,int & yStart, int  yIncr)\r
519 {\r
520         char buf[124];\r
521         glDisable(GL_LIGHTING);\r
522         glColor3f(0, 0, 0);\r
523         \r
524         sprintf(buf,"mouse move+buttons to interact");\r
525         GLDebugDrawString(xOffset,yStart,buf);\r
526         yStart += yIncr;\r
527 \r
528         \r
529         sprintf(buf,"space to reset");\r
530         GLDebugDrawString(xOffset,yStart,buf);\r
531         yStart += yIncr;\r
532 \r
533         \r
534         sprintf(buf,"cursor keys and z,x to navigate");\r
535         GLDebugDrawString(xOffset,yStart,buf);\r
536         yStart += yIncr;\r
537 \r
538         \r
539         sprintf(buf,"i to toggle simulation, s single step");\r
540         GLDebugDrawString(xOffset,yStart,buf);\r
541         yStart += yIncr;\r
542 \r
543         \r
544         sprintf(buf,"q to quit");\r
545         GLDebugDrawString(xOffset,yStart,buf);\r
546         yStart += yIncr;\r
547 \r
548         \r
549         sprintf(buf,"h to toggle help text");\r
550         GLDebugDrawString(xOffset,yStart,buf);\r
551         yStart += yIncr;\r
552 \r
553         \r
554         sprintf(buf,"p to toggle profiling (+results to file)");\r
555         GLDebugDrawString(xOffset,yStart,buf);\r
556         yStart += yIncr;\r
557 \r
558         sprintf(buf,"j to toggle between demos (integration/OECake2D/OECake3D)");\r
559         GLDebugDrawString(xOffset,yStart,buf);\r
560         yStart += yIncr;\r
561 \r
562         {\r
563                 sprintf(buf,"G to draw broadphase grid");\r
564                 GLDebugDrawString(xOffset,yStart,buf);\r
565                 yStart += yIncr;\r
566                 sprintf(buf,"D and U to toggle between GPU and CPU");\r
567                 GLDebugDrawString(xOffset,yStart,buf);\r
568                 yStart += yIncr;\r
569                 \r
570         }\r
571         \r
572 }\r
573 \r
574 \r
575 GLuint _compileProgram(const char *vsource, const char *fsource)\r
576 {\r
577     GLuint vertexShader = glCreateShader(GL_VERTEX_SHADER);\r
578     GLuint fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);\r
579 \r
580     glShaderSource(vertexShader, 1, &vsource, 0);\r
581     glShaderSource(fragmentShader, 1, &fsource, 0);\r
582     \r
583     glCompileShader(vertexShader);\r
584     glCompileShader(fragmentShader);\r
585 \r
586     GLuint program = glCreateProgram();\r
587 \r
588     glAttachShader(program, vertexShader);\r
589     glAttachShader(program, fragmentShader);\r
590 \r
591     glLinkProgram(program);\r
592 \r
593     // check if program linked\r
594     GLint success = 0;\r
595     glGetProgramiv(program, GL_LINK_STATUS, &success);\r
596 \r
597     if (!success) {\r
598         char temp[256];\r
599         glGetProgramInfoLog(program, 256, 0, temp);\r
600         printf("Failed to link program:\n%s\n", temp);\r
601         glDeleteProgram(program);\r
602         program = 0;\r
603     }\r
604     return program;\r
605 }\r
606 \r
607 \r
608 void ParticlesDemo::myinit()\r
609 {\r
610         DemoApplication::myinit();\r
611 #ifndef __APPLE__\r
612     glewInit();\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
615         exit(-1);\r
616     }\r
617 #endif //__APPLE__\r
618         \r
619         m_shaderProgram = _compileProgram(vertexShader, spherePixelShader);\r
620         m_pWorld->initCLKernels(m_argc, m_argv);\r
621 }\r
622 \r
623 \r
624 \r
625 \r
626 \r
627 \r
628 void ParticlesDemo::mouseFunc(int button, int state, int x, int y)\r
629 {\r
630 \r
631         if (!m_dialogDynamicsWorld->mouseFunc(button,state,x,y))\r
632         {\r
633                 DemoApplication::mouseFunc(button,state,x,y);\r
634         }\r
635 }\r
636 \r
637 void    ParticlesDemo::mouseMotionFunc(int x,int y)\r
638 {\r
639         m_dialogDynamicsWorld->mouseMotionFunc(x,y);\r
640         DemoApplication::mouseMotionFunc(x,y);\r
641 }\r
642 \r
643 \r
644 \r
645 void ParticlesDemo::reshape(int w, int h)\r
646 {\r
647         if (m_dialogDynamicsWorld)\r
648                 m_dialogDynamicsWorld->setScreenSize(w,h);\r
649         GlutDemoApplication::reshape(w,h);\r
650 }\r
651 \r