Imported Upstream version 2.81
[platform/upstream/libbullet.git] / Demos / TerrainDemo / TerrainDemo.cpp
1
2 /*
3 Bullet Continuous Collision Detection and Physics Library
4 Copyright (c) 2003-2006,2008 Erwin Coumans  http://continuousphysics.com/Bullet/
5
6 This software is provided 'as-is', without any express or implied warranty.
7 In no event will the authors be held liable for any damages arising from the use of this software.
8 Permission is granted to anyone to use this software for any purpose, 
9 including commercial applications, and to alter it and redistribute it freely, 
10 subject to the following restrictions:
11
12 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.
13 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
14 3. This notice may not be removed or altered from any source distribution.
15 */
16
17 #include "TerrainDemo.h"                // always include our own header first!
18
19 #include "btBulletDynamicsCommon.h"
20 #include "BulletCollision/CollisionShapes/btHeightfieldTerrainShape.h"
21
22 #include "GLDebugDrawer.h"
23
24 #include "GL_ShapeDrawer.h"
25
26 #include "GlutStuff.h"
27 #include "GLDebugFont.h"
28
29
30
31 // constants -------------------------------------------------------------------
32 static const float s_gravity                    = 9.8;          // 9.8 m/s^2
33
34 static const int s_gridSize                     = 64 + 1;  // must be (2^N) + 1
35 static const float s_gridSpacing                = 5.0;
36
37 static const float s_gridHeightScale            = 0.2;
38
39 // the singularity at the center of the radial model means we need a lot of
40 //   finely-spaced time steps to get the physics right.
41 // These numbers are probably too aggressive for a real game!
42 static const int s_requestedHz                  = 180;
43 static const float s_engineTimeStep             = 1.0 / s_requestedHz;
44
45 // delta phase: radians per second
46 static const float s_deltaPhase                 = 0.25 * 2.0 * SIMD_PI;
47
48 // what type of terrain is generated?
49 enum eTerrainModel {
50         eRadial                 = 1,    // deterministic
51         eFractal                = 2     // random
52 };
53
54
55 typedef unsigned char byte_t;
56
57
58
59 ////////////////////////////////////////////////////////////////////////////////
60 //
61 //      static helper methods
62 //
63 //      Only used within this file (helpers and terrain generation, etc)
64 //
65 ////////////////////////////////////////////////////////////////////////////////
66
67 static const char *
68 getTerrainTypeName
69 (
70 eTerrainModel model
71 )
72 {
73         switch (model) {
74         case eRadial:
75                 return "Radial";
76
77         case eFractal:
78                 return "Fractal";
79
80         default:
81                 btAssert(!"bad terrain model type");
82         }
83
84         return NULL;
85 }
86
87
88
89 static const char *
90 getDataTypeName
91 (
92 PHY_ScalarType type
93 )
94 {
95         switch (type) {
96         case PHY_UCHAR:
97                 return "UnsignedChar";
98
99         case PHY_SHORT:
100                 return "Short";
101
102         case PHY_FLOAT:
103                 return "Float";
104
105         default:
106                 btAssert(!"bad heightfield data type");
107         }
108
109         return NULL;
110 }
111
112
113
114 static const char *
115 getUpAxisName
116 (
117 int axis
118 )
119 {
120         switch (axis) {
121         case 0:
122                 return "X";
123
124         case 1:
125                 return "Y";
126
127         case 2:
128                 return "Z";
129
130         default:
131                 btAssert(!"bad up axis");
132         }
133
134         return NULL;
135 }
136
137
138
139 static btVector3
140 getUpVector
141 (
142 int upAxis,
143 btScalar regularValue,
144 btScalar upValue
145 )
146 {
147         btAssert(upAxis >= 0 && upAxis <= 2 && "bad up axis");
148
149         btVector3 v(regularValue, regularValue, regularValue);
150         v[upAxis] = upValue;
151
152         return v;
153 }
154
155
156
157 // TODO: it would probably cleaner to have a struct per data type, so
158 //      you could lookup byte sizes, conversion functions, etc.
159 static int getByteSize
160 (
161 PHY_ScalarType type
162 )
163 {
164         int size = 0;
165
166         switch (type) {
167         case PHY_FLOAT:
168                 size = sizeof(float);
169                 break;
170
171         case PHY_UCHAR:
172                 size = sizeof(unsigned char);
173                 break;
174
175         case PHY_SHORT:
176                 size = sizeof(short);
177                 break;
178
179         default:
180                 btAssert(!"Bad heightfield data type");
181         }
182
183         return size;
184 }
185
186
187
188 static float
189 convertToFloat
190 (
191 const byte_t * p,
192 PHY_ScalarType type
193 )
194 {
195         btAssert(p);
196
197         switch (type) {
198         case PHY_FLOAT:
199                 {
200                         float * pf = (float *) p;
201                         return *pf;
202                 }
203
204         case PHY_UCHAR:
205                 {
206                         unsigned char * pu = (unsigned char *) p;
207                         return ((*pu) * s_gridHeightScale);
208                 }
209
210         case PHY_SHORT:
211                 {
212                         short * ps = (short *) p;
213                         return ((*ps) * s_gridHeightScale);
214                 }
215
216         default:
217                 btAssert(!"bad type");
218         }
219
220         return 0;
221 }
222
223
224
225 static float
226 getGridHeight
227 (
228 byte_t * grid,
229 int i,
230 int j,
231 PHY_ScalarType type
232 )
233 {
234         btAssert(grid);
235         btAssert(i >= 0 && i < s_gridSize);
236         btAssert(j >= 0 && j < s_gridSize);
237
238         int bpe = getByteSize(type);
239         btAssert(bpe > 0 && "bad bytes per element");
240
241         int idx = (j * s_gridSize) + i;
242         long offset = ((long) bpe) * idx;
243
244         byte_t * p = grid + offset;
245
246         return convertToFloat(p, type);
247 }
248
249
250
251 static void
252 convertFromFloat
253 (
254 byte_t * p,
255 float value,
256 PHY_ScalarType type
257 )
258 {
259         btAssert(p && "null");
260
261         switch (type) {
262         case PHY_FLOAT:
263                 {
264                         float * pf = (float *) p;
265                         *pf = value;
266                 }
267                 break;
268
269         case PHY_UCHAR:
270                 {
271                         unsigned char * pu = (unsigned char *) p;
272                         *pu = (unsigned char) (value / s_gridHeightScale);
273                 }
274                 break;
275
276         case PHY_SHORT:
277                 {
278                         short * ps = (short *) p;
279                         *ps = (short) (value / s_gridHeightScale);
280                 }
281                 break;
282
283         default:
284                 btAssert(!"bad type");
285         }
286 }
287
288
289
290 // creates a radially-varying heightfield
291 static void
292 setRadial
293 (
294 byte_t * grid,
295 int bytesPerElement,
296 PHY_ScalarType type,
297 float phase = 0.0
298 )
299 {
300         btAssert(grid);
301         btAssert(bytesPerElement > 0);
302
303         // min/max
304         float period = 0.5 / s_gridSpacing;
305         float floor = 0.0;
306         float min_r = 3.0 * sqrt(s_gridSpacing);
307         float magnitude = 50.0 * sqrt(s_gridSpacing);
308
309         // pick a base_phase such that phase = 0 results in max height
310         //   (this way, if you create a heightfield with phase = 0,
311         //    you can rely on the min/max heights that result)
312         float base_phase = (0.5 * SIMD_PI) - (period * min_r);
313         phase += base_phase;
314
315         // center of grid
316         float cx = 0.5 * s_gridSize * s_gridSpacing;
317         float cy = cx;          // assume square grid
318         byte_t * p = grid;
319         for (int i = 0; i < s_gridSize; ++i) {
320                 float x = i * s_gridSpacing;
321                 for (int j = 0; j < s_gridSize; ++j) {
322                         float y = j * s_gridSpacing;
323
324                         float dx = x - cx;
325                         float dy = y - cy;
326
327                         float r = sqrt((dx * dx) + (dy * dy));
328
329                         float z = period;
330                         if (r < min_r) {
331                                 r = min_r;
332                         }
333                         z = (1.0 / r) * sin(period * r + phase);
334                         if (z > period) {
335                                 z = period;
336                         } else if (z < -period) {
337                                 z = -period;
338                         }
339                         z = floor + magnitude * z;
340
341                         convertFromFloat(p, z, type);
342                         p += bytesPerElement;
343                 }
344         }
345 }
346
347
348
349 static float
350 randomHeight
351 (
352 int step
353 )
354 {
355         return (0.33 * s_gridSpacing * s_gridSize * step * (rand() - (0.5 * RAND_MAX))) / (1.0 * RAND_MAX * s_gridSize);
356 }
357
358
359
360 static void
361 dumpGrid
362 (
363 const byte_t * grid,
364 int bytesPerElement,
365 PHY_ScalarType type,
366 int max
367 )
368 {
369         //std::cerr << "Grid:\n";
370
371         char buffer[32];
372
373         for (int j = 0; j < max; ++j) {
374                 for (int i = 0; i < max; ++i) {
375                         long offset = j * s_gridSize + i;
376                         float z = convertToFloat(grid + offset * bytesPerElement, type);
377                         sprintf(buffer, "%6.2f", z);
378                         //std::cerr << "  " << buffer;
379                 }
380                 //std::cerr << "\n";
381         }
382 }
383
384
385
386 static void
387 updateHeight
388 (
389 byte_t * p,
390 float new_val,
391 PHY_ScalarType type
392 )
393 {
394         float old_val = convertToFloat(p, type);
395         if (!old_val) {
396                 convertFromFloat(p, new_val, type);
397         }
398 }
399
400
401
402 // creates a random, fractal heightfield
403 static void
404 setFractal
405 (
406 byte_t * grid,
407 int bytesPerElement,
408 PHY_ScalarType type,
409 int step
410 )
411 {
412         btAssert(grid);
413         btAssert(bytesPerElement > 0);
414         btAssert(step > 0);
415         btAssert(step < s_gridSize);
416
417         int newStep = step / 2;
418 //      std::cerr << "Computing grid with step = " << step << ": before\n";
419 //      dumpGrid(grid, bytesPerElement, type, step + 1);
420
421         // special case: starting (must set four corners)
422         if (s_gridSize - 1 == step) {
423                 // pick a non-zero (possibly negative) base elevation for testing
424                 float base = randomHeight(step / 2);
425
426                 convertFromFloat(grid, base, type);
427                 convertFromFloat(grid + step * bytesPerElement, base, type);
428                 convertFromFloat(grid + step * s_gridSize * bytesPerElement, base, type);
429                 convertFromFloat(grid + (step * s_gridSize + step) * bytesPerElement, base, type);
430         }
431
432         // determine elevation of each corner
433         float c00 = convertToFloat(grid, type);
434         float c01 = convertToFloat(grid + step * bytesPerElement, type);
435         float c10 = convertToFloat(grid + (step * s_gridSize) * bytesPerElement, type);
436         float c11 = convertToFloat(grid + (step * s_gridSize + step) * bytesPerElement, type);
437
438         // set top middle
439         updateHeight(grid + newStep * bytesPerElement, 0.5 * (c00 + c01) + randomHeight(step), type);
440
441         // set left middle
442         updateHeight(grid + (newStep * s_gridSize) * bytesPerElement, 0.5 * (c00 + c10) + randomHeight(step), type);
443
444         // set right middle
445         updateHeight(grid + (newStep * s_gridSize + step) * bytesPerElement, 0.5 * (c01 + c11) + randomHeight(step), type);
446
447         // set bottom middle
448         updateHeight(grid + (step * s_gridSize + newStep) * bytesPerElement, 0.5 * (c10 + c11) + randomHeight(step), type);
449
450         // set middle
451         updateHeight(grid + (newStep * s_gridSize + newStep) * bytesPerElement, 0.25 * (c00 + c01 + c10 + c11) + randomHeight(step), type);
452
453 //      std::cerr << "Computing grid with step = " << step << ": after\n";
454 //      dumpGrid(grid, bytesPerElement, type, step + 1);
455
456         // terminate?
457         if (newStep < 2) {
458                 return;
459         }
460
461         // recurse
462         setFractal(grid, bytesPerElement, type, newStep);
463         setFractal(grid + newStep * bytesPerElement, bytesPerElement, type, newStep);
464         setFractal(grid + (newStep * s_gridSize) * bytesPerElement, bytesPerElement, type, newStep);
465         setFractal(grid + ((newStep * s_gridSize) + newStep) * bytesPerElement, bytesPerElement, type, newStep);
466 }
467
468
469
470 static byte_t *
471 getRawHeightfieldData
472 (
473 eTerrainModel model,
474 PHY_ScalarType type,
475 btScalar& minHeight,
476 btScalar& maxHeight
477 )
478 {
479 //      std::cerr << "\nRegenerating terrain\n";
480 //      std::cerr << "  model = " << model << "\n";
481 //      std::cerr << "  type = " << type << "\n";
482
483         long nElements = ((long) s_gridSize) * s_gridSize;
484 //      std::cerr << "  nElements = " << nElements << "\n";
485
486         int bytesPerElement = getByteSize(type);
487 //      std::cerr << "  bytesPerElement = " << bytesPerElement << "\n";
488         btAssert(bytesPerElement > 0 && "bad bytes per element");
489
490         long nBytes = nElements * bytesPerElement;
491 //      std::cerr << "  nBytes = " << nBytes << "\n";
492         byte_t * raw = new byte_t[nBytes];
493         btAssert(raw && "out of memory");
494
495         // reseed randomization every 30 seconds
496 //      srand(time(NULL) / 30);
497
498         // populate based on model
499         switch (model) {
500         case eRadial:
501                 setRadial(raw, bytesPerElement, type);
502                 break;
503
504         case eFractal:
505                 for (int i = 0; i < nBytes; i++)
506                 {
507                         raw[i] = 0;
508                 }
509                 setFractal(raw, bytesPerElement, type, s_gridSize - 1);
510                 break;
511
512         default:
513                 btAssert(!"bad model type");
514         }
515
516         if (0) {
517                 // inside if(0) so it keeps compiling but isn't
518                 //      exercised and doesn't cause warnings
519 //              std::cerr << "final grid:\n";
520                 dumpGrid(raw, bytesPerElement, type, s_gridSize - 1);
521         }
522
523         // find min/max
524         for (int i = 0; i < s_gridSize; ++i) {
525                 for (int j = 0; j < s_gridSize; ++j) {
526                         float z = getGridHeight(raw, i, j, type);
527 //                      std::cerr << "i=" << i << ", j=" << j << ": z=" << z << "\n";
528
529                         // update min/max
530                         if (!i && !j) {
531                                 minHeight = z;
532                                 maxHeight = z;
533                         } else {
534                                 if (z < minHeight) {
535                                         minHeight = z;
536                                 }
537                                 if (z > maxHeight) {
538                                         maxHeight = z;
539                                 }
540                         }
541                 }
542         }
543
544         if (maxHeight < -minHeight) {
545                 maxHeight = -minHeight;
546         }
547         if (minHeight > -maxHeight) {
548                 minHeight = -maxHeight;
549         }
550
551 //      std::cerr << "  minHeight = " << minHeight << "\n";
552 //      std::cerr << "  maxHeight = " << maxHeight << "\n";
553
554         return raw;
555 }
556
557
558
559 ////////////////////////////////////////////////////////////////////////////////
560 //
561 //      TerrainDemo class
562 //
563 ////////////////////////////////////////////////////////////////////////////////
564
565 /// class that demonstrates the btHeightfieldTerrainShape object
566 class TerrainDemo : public GlutDemoApplication {
567 public:
568         // constructor, destructor ---------------------------------------------
569         TerrainDemo(void);
570         ~TerrainDemo(void);
571
572         virtual void initPhysics() {}
573
574         // public class methods ------------------------------------------------
575         void initialize(void);
576
577         // DemoApplication class interface methods -----------------------------
578         void clientMoveAndDisplay(void);
579         void keyboardCallback(unsigned char key, int x, int y);
580         void renderme(void);
581
582 private:
583         // private helper methods ----------------------------------------------
584         void resetPhysics(void);
585         void clearWorld(void);
586
587         // private data members ------------------------------------------------
588         btDefaultCollisionConfiguration *       m_collisionConfiguration;
589         btCollisionDispatcher *                 m_dispatcher;
590         btAxisSweep3 *                          m_overlappingPairCache;
591         btSequentialImpulseConstraintSolver *   m_constraintSolver;
592         btAlignedObjectArray<btCollisionShape*> m_collisionShapes;
593         int                                     m_upAxis;
594         PHY_ScalarType                          m_type;
595         eTerrainModel                           m_model;
596         byte_t *                                m_rawHeightfieldData;
597         btScalar                                m_minHeight;
598         btScalar                                m_maxHeight;
599         float                                   m_phase;        // for dynamics
600         bool                                    m_isDynamic;
601 };
602
603
604
605 TerrainDemo::TerrainDemo(void)
606 :
607 m_collisionConfiguration(NULL),
608 m_dispatcher(NULL),
609 m_overlappingPairCache(NULL),
610 m_constraintSolver(NULL),
611 m_upAxis(1),
612 m_type(PHY_FLOAT),
613 m_model(eFractal),
614 m_rawHeightfieldData(NULL),
615 m_phase(0.0),
616 m_isDynamic(true)
617 {
618 }
619
620
621
622 TerrainDemo::~TerrainDemo(void)
623 {
624         clearWorld();
625
626         //delete dynamics world
627         delete m_dynamicsWorld;
628
629         //delete solver
630         delete m_constraintSolver;
631
632         //delete broadphase
633         delete m_overlappingPairCache;
634
635         //delete dispatcher
636         delete m_dispatcher;
637
638         delete m_collisionConfiguration;
639
640 }
641
642
643
644 ////////////////////////////////////////////////////////////////////////////////
645 //
646 //      TerrainDemo -- public class methods
647 //
648 ////////////////////////////////////////////////////////////////////////////////
649
650 /// one-time class and physics initialization
651 void TerrainDemo::initialize(void)
652 {
653 //      std::cerr << "initializing...\n";
654
655         // set up basic state
656         m_upAxis = 1;           // start with Y-axis as "up"
657         m_type = PHY_FLOAT;
658         m_model = eRadial;//eFractal;
659         m_isDynamic = true;
660
661         // set up the physics world
662         m_collisionConfiguration = new btDefaultCollisionConfiguration();
663         m_dispatcher = new btCollisionDispatcher(m_collisionConfiguration);
664         btVector3 worldMin(-1000,-1000,-1000);
665         btVector3 worldMax(1000,1000,1000);
666         m_overlappingPairCache = new btAxisSweep3(worldMin,worldMax);
667         m_constraintSolver = new btSequentialImpulseConstraintSolver();
668         m_dynamicsWorld = new btDiscreteDynamicsWorld(m_dispatcher,m_overlappingPairCache,m_constraintSolver,m_collisionConfiguration);
669
670         // initialize axis- or type-dependent physics from here
671         this->resetPhysics();
672 }
673
674
675
676 ////////////////////////////////////////////////////////////////////////////////
677 //
678 //      TerrainDemo -- DemoApplication class interface methods
679 //
680 ////////////////////////////////////////////////////////////////////////////////
681
682 void TerrainDemo::clientMoveAndDisplay(void)
683 {
684         // elapsed time
685         float us = getDeltaTimeMicroseconds();
686         float seconds = 1.0e-6 * us;
687
688         // we'll carefully iterate through each time step so we can update
689         //   the dynamic model if necessary
690         long nStepsPerIteration = 1;
691         while (seconds > 1.0e-6) {
692                 float dt = nStepsPerIteration * s_engineTimeStep;
693                 if (dt > seconds) {
694                         dt = seconds;
695                 }
696                 seconds -= dt;
697         //      std::cerr << "  Stepping through " << dt << " seconds\n";
698
699                 // if dynamic and radial, go ahead and update the field
700                 if (m_rawHeightfieldData && m_isDynamic && eRadial == m_model) {
701                         m_phase += s_deltaPhase * dt;
702                         if (m_phase > 2.0 * SIMD_PI) {
703                                 m_phase -= 2.0 * SIMD_PI;
704                         }
705                         int bpe = getByteSize(m_type);
706                         btAssert(bpe > 0 && "Bad bytes per element");
707                         setRadial(m_rawHeightfieldData, bpe, m_type, m_phase);
708                 }
709
710                 if (m_dynamicsWorld) {
711                         m_dynamicsWorld->stepSimulation(dt,
712                             nStepsPerIteration + 1, s_engineTimeStep);
713                 }
714         }
715
716         // okay, render
717         glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
718         renderme();
719         glFlush();
720         glutSwapBuffers();
721 }
722
723
724 static PHY_ScalarType nextType (PHY_ScalarType type)
725 {
726         switch (type)
727         {
728         case PHY_FLOAT:
729                 return PHY_SHORT;
730         break;
731         case PHY_SHORT:
732                 return PHY_UCHAR;
733         break;
734         case PHY_UCHAR:
735                 return PHY_FLOAT;
736         break;
737         }
738         btAssert (0);
739         return PHY_FLOAT;
740 }
741
742 void TerrainDemo::keyboardCallback(unsigned char key, int x, int y) {
743
744         if (',' == key) {
745                 // increment model
746                 m_model = (eFractal == m_model) ? eRadial : eFractal;
747                 this->resetPhysics();
748         }
749         if ('/' == key) {
750                 // increment type
751                 m_type = nextType(m_type);
752                 this->resetPhysics();
753         }
754         if ('\\' == key) {
755                 // increment axis
756                 m_upAxis++;
757                 if (m_upAxis > 2) {
758                         m_upAxis = 0;
759                 }
760                 this->resetPhysics();
761         }
762         if ('[' == key) {
763                 // toggle dynamics
764                 m_isDynamic = !m_isDynamic;
765         }
766
767         // let demo base class handle!
768         DemoApplication::keyboardCallback(key, x, y);
769 }
770
771
772
773 static void doPrint(int x,int& y,int dy,const char * text)
774 {
775         GLDebugDrawString(x,y, text);
776         y += dy;
777 }
778
779
780
781 /// override the default display just so we can overlay a bit more text
782 void TerrainDemo::renderme(void)
783 {
784         // give base class a shot
785         DemoApplication::renderme();
786
787         // overlay any debug information
788         if (m_dynamicsWorld)
789                 m_dynamicsWorld->debugDrawWorld();
790
791         // switch to orthographic
792         setOrthographicProjection();
793
794         // we'll draw on the right top of the screen
795         const int lineWidth = 200;
796         const int lineHeight = 16;
797         char buffer[256];
798
799         int xStart = m_glutScreenWidth - lineWidth;
800         int yStart = lineHeight;
801
802         sprintf(buffer, "Terrain Type: %s", getTerrainTypeName(m_model));
803         doPrint(xStart, yStart, lineHeight, buffer);
804         doPrint(xStart, yStart, lineHeight, "Press ',' to cycle terrain types");
805         doPrint(xStart, yStart, lineHeight, "");
806
807         sprintf(buffer, "Data Type: %s", getDataTypeName(m_type));
808         doPrint(xStart, yStart, lineHeight, buffer);
809         doPrint(xStart, yStart, lineHeight, "Press '/' to cycle data types");
810         doPrint(xStart, yStart, lineHeight, "");
811
812         sprintf(buffer, "'up' axis: %s", getUpAxisName(m_upAxis));
813         doPrint(xStart, yStart, lineHeight, buffer);
814         doPrint(xStart, yStart, lineHeight, "Press '\\' to cycle 'up' axes");
815         doPrint(xStart, yStart, lineHeight, "");
816
817         if (eRadial == m_model) {
818                 sprintf(buffer, "Dynamic: %s", m_isDynamic ? "yes" : "no");
819                 doPrint(xStart, yStart, lineHeight, buffer);
820                 doPrint(xStart, yStart, lineHeight, "Press '[' to toggle dynamics");
821         }
822 }
823
824
825
826 ////////////////////////////////////////////////////////////////////////////////
827 //
828 //      TerrainDemo -- private helper methods
829 //
830 ////////////////////////////////////////////////////////////////////////////////
831
832 /// called whenever key terrain attribute is changed
833 void TerrainDemo::resetPhysics(void)
834 {
835         // remove old heightfield
836         clearWorld();
837
838         // reset gravity to point in appropriate direction
839         m_dynamicsWorld->setGravity(getUpVector(m_upAxis, 0.0, -s_gravity));
840
841         // get new heightfield of appropriate type
842         m_rawHeightfieldData =
843             getRawHeightfieldData(m_model, m_type, m_minHeight, m_maxHeight);
844         btAssert(m_rawHeightfieldData && "failed to create raw heightfield");
845
846         bool flipQuadEdges = false;
847         btHeightfieldTerrainShape * heightfieldShape =
848             new btHeightfieldTerrainShape(s_gridSize, s_gridSize,
849                                           m_rawHeightfieldData,
850                                           s_gridHeightScale,
851                                           m_minHeight, m_maxHeight,
852                                           m_upAxis, m_type, flipQuadEdges);
853         btAssert(heightfieldShape && "null heightfield");
854
855         // scale the shape
856         btVector3 localScaling = getUpVector(m_upAxis, s_gridSpacing, 1.0);
857         heightfieldShape->setLocalScaling(localScaling);
858
859         // stash this shape away
860         m_collisionShapes.push_back(heightfieldShape);
861
862         // set origin to middle of heightfield
863         btTransform tr;
864         tr.setIdentity();
865         tr.setOrigin(btVector3(0,-20,0));
866
867         // create ground object
868         float mass = 0.0;
869         localCreateRigidBody(mass, tr, heightfieldShape);
870 }
871
872
873 /// removes all objects and shapes from the world
874 void TerrainDemo::clearWorld(void)
875 {
876         //remove the rigidbodies from the dynamics world and delete them
877         int i;
878         for (i=m_dynamicsWorld->getNumCollisionObjects()-1; i>=0 ;i--)
879         {
880                 btCollisionObject* obj = m_dynamicsWorld->getCollisionObjectArray()[i];
881                 btRigidBody* body = btRigidBody::upcast(obj);
882                 if (body && body->getMotionState())
883                 {
884                         delete body->getMotionState();
885                 }
886                 m_dynamicsWorld->removeCollisionObject( obj );
887                 delete obj;
888         }
889
890         //delete collision shapes
891         for (int j=0;j<m_collisionShapes.size();j++)
892         {
893                 btCollisionShape* shape = m_collisionShapes[j];
894                 delete shape;
895         }
896         m_collisionShapes.clear();
897
898         // delete raw heightfield data
899         delete m_rawHeightfieldData;
900         m_rawHeightfieldData = NULL;
901 }
902
903
904
905 ////////////////////////////////////////////////////////////////////////////////
906 //
907 //      TerrainDemo -- public API (exposed in header)
908 //
909 ////////////////////////////////////////////////////////////////////////////////
910
911 /// creates an object that demonstrates terrain
912 GlutDemoApplication * btCreateTerrainDemo(void)
913 {
914         TerrainDemo * demo = new TerrainDemo;
915         btAssert(demo && "out of memory");
916
917         demo->initialize();
918
919         return demo;
920 }
921