Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/trunk/src/bullet/BulletCollision/CollisionShapes/btHeightfieldTerrainShape.cpp @ 2873

Last change on this file since 2873 was 2662, checked in by rgrieder, 16 years ago

Merged presentation branch back to trunk.

  • Property svn:eol-style set to native
File size: 10.5 KB
Line 
1/*
2Bullet Continuous Collision Detection and Physics Library
3Copyright (c) 2003-2006 Erwin Coumans  http://continuousphysics.com/Bullet/
4
5This software is provided 'as-is', without any express or implied warranty.
6In no event will the authors be held liable for any damages arising from the use of this software.
7Permission is granted to anyone to use this software for any purpose,
8including commercial applications, and to alter it and redistribute it freely,
9subject to the following restrictions:
10
111. 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.
122. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
133. This notice may not be removed or altered from any source distribution.
14*/
15
16#include "btHeightfieldTerrainShape.h"
17
18#include "LinearMath/btTransformUtil.h"
19
20
21
22btHeightfieldTerrainShape::btHeightfieldTerrainShape
23(
24int heightStickWidth, int heightStickLength, void* heightfieldData,
25btScalar heightScale, btScalar minHeight, btScalar maxHeight,int upAxis,
26PHY_ScalarType hdt, bool flipQuadEdges
27)
28{
29        initialize(heightStickWidth, heightStickLength, heightfieldData,
30                   heightScale, minHeight, maxHeight, upAxis, hdt,
31                   flipQuadEdges);
32}
33
34
35
36btHeightfieldTerrainShape::btHeightfieldTerrainShape(int heightStickWidth, int heightStickLength,void* heightfieldData,btScalar maxHeight,int upAxis,bool useFloatData,bool flipQuadEdges)
37{
38        // legacy constructor: support only float or unsigned char,
39        //      and min height is zero
40        PHY_ScalarType hdt = (useFloatData) ? PHY_FLOAT : PHY_UCHAR;
41        btScalar minHeight = 0.0;
42
43        // previously, height = uchar * maxHeight / 65535.
44        // So to preserve legacy behavior, heightScale = maxHeight / 65535
45        btScalar heightScale = maxHeight / 65535;
46
47        initialize(heightStickWidth, heightStickLength, heightfieldData,
48                   heightScale, minHeight, maxHeight, upAxis, hdt,
49                   flipQuadEdges);
50}
51
52
53
54void btHeightfieldTerrainShape::initialize
55(
56int heightStickWidth, int heightStickLength, void* heightfieldData,
57btScalar heightScale, btScalar minHeight, btScalar maxHeight, int upAxis,
58PHY_ScalarType hdt, bool flipQuadEdges
59)
60{
61        // validation
62        btAssert(heightStickWidth > 1 && "bad width");
63        btAssert(heightStickLength > 1 && "bad length");
64        btAssert(heightfieldData && "null heightfield data");
65        // btAssert(heightScale) -- do we care?  Trust caller here
66        btAssert(minHeight <= maxHeight && "bad min/max height");
67        btAssert(upAxis >= 0 && upAxis < 3 &&
68            "bad upAxis--should be in range [0,2]");
69        btAssert(hdt != PHY_UCHAR || hdt != PHY_FLOAT || hdt != PHY_SHORT &&
70            "Bad height data type enum");
71
72        // initialize member variables
73        m_shapeType = TERRAIN_SHAPE_PROXYTYPE;
74        m_heightStickWidth = heightStickWidth;
75        m_heightStickLength = heightStickLength;
76        m_minHeight = minHeight;
77        m_maxHeight = maxHeight;
78        m_width = (btScalar) (heightStickWidth - 1);
79        m_length = (btScalar) (heightStickLength - 1);
80        m_heightScale = heightScale;
81        m_heightfieldDataUnknown = heightfieldData;
82        m_heightDataType = hdt;
83        m_flipQuadEdges = flipQuadEdges;
84        m_useDiamondSubdivision = false;
85        m_upAxis = upAxis;
86        m_localScaling.setValue(btScalar(1.), btScalar(1.), btScalar(1.));
87
88        // determine min/max axis-aligned bounding box (aabb) values
89        switch (m_upAxis)
90        {
91        case 0:
92                {
93                        m_localAabbMin.setValue(m_minHeight, 0, 0);
94                        m_localAabbMax.setValue(m_maxHeight, m_width, m_length);
95                        break;
96                }
97        case 1:
98                {
99                        m_localAabbMin.setValue(0, m_minHeight, 0);
100                        m_localAabbMax.setValue(m_width, m_maxHeight, m_length);
101                        break;
102                };
103        case 2:
104                {
105                        m_localAabbMin.setValue(0, 0, m_minHeight);
106                        m_localAabbMax.setValue(m_width, m_length, m_maxHeight);
107                        break;
108                }
109        default:
110                {
111                        //need to get valid m_upAxis
112                        btAssert(0 && "Bad m_upAxis");
113                }
114        }
115
116        // remember origin (defined as exact middle of aabb)
117        m_localOrigin = btScalar(0.5) * (m_localAabbMin + m_localAabbMax);
118}
119
120
121
122btHeightfieldTerrainShape::~btHeightfieldTerrainShape()
123{
124}
125
126
127
128void btHeightfieldTerrainShape::getAabb(const btTransform& t,btVector3& aabbMin,btVector3& aabbMax) const
129{
130        btVector3 halfExtents = (m_localAabbMax-m_localAabbMin)* m_localScaling * btScalar(0.5);
131
132        btVector3 localOrigin(0, 0, 0);
133        localOrigin[m_upAxis] = (m_minHeight + m_maxHeight) * btScalar(0.5);
134        localOrigin *= m_localScaling;
135
136        btMatrix3x3 abs_b = t.getBasis().absolute(); 
137        btVector3 center = t.getOrigin();
138        btVector3 extent = btVector3(abs_b[0].dot(halfExtents),
139                   abs_b[1].dot(halfExtents),
140                  abs_b[2].dot(halfExtents));
141        extent += btVector3(getMargin(),getMargin(),getMargin());
142
143        aabbMin = center - extent;
144        aabbMax = center + extent;
145}
146
147btScalar        btHeightfieldTerrainShape::getHeightFieldValue(int x,int y) const
148{
149        btScalar val = 0.f;
150        switch (m_heightDataType)
151        {
152        case PHY_FLOAT:
153                {
154                        val = m_heightfieldDataFloat[(y*m_heightStickWidth)+x];
155                        break;
156                }
157
158        case PHY_UCHAR:
159                {
160                        unsigned char heightFieldValue = m_heightfieldDataUnsignedChar[(y*m_heightStickWidth)+x];
161                        val = heightFieldValue * m_heightScale;
162                        break;
163                }
164
165        case PHY_SHORT:
166                {
167                        short hfValue = m_heightfieldDataShort[(y * m_heightStickWidth) + x];
168                        val = hfValue * m_heightScale;
169                        break;
170                }
171
172        default:
173                {
174                        btAssert(!"Bad m_heightDataType");
175                }
176        }
177
178        return val;
179}
180
181
182
183
184
185void    btHeightfieldTerrainShape::getVertex(int x,int y,btVector3& vertex) const
186{
187
188        btAssert(x>=0);
189        btAssert(y>=0);
190        btAssert(x<m_heightStickWidth);
191        btAssert(y<m_heightStickLength);
192
193
194        btScalar        height = getHeightFieldValue(x,y);
195
196        switch (m_upAxis)
197        {
198        case 0:
199                {
200                vertex.setValue(
201                        height,
202                        (-m_width/btScalar(2.0)) + x,
203                        (-m_length/btScalar(2.0) ) + y
204                        );
205                        break;
206                }
207        case 1:
208                {
209                        vertex.setValue(
210                        (-m_width/btScalar(2.0)) + x,
211                        height,
212                        (-m_length/btScalar(2.0)) + y
213                        );
214                        break;
215                };
216        case 2:
217                {
218                        vertex.setValue(
219                        (-m_width/btScalar(2.0)) + x,
220                        (-m_length/btScalar(2.0)) + y,
221                        height
222                        );
223                        break;
224                }
225        default:
226                {
227                        //need to get valid m_upAxis
228                        btAssert(0);
229                }
230        }
231
232        vertex*=m_localScaling;
233       
234}
235
236
237
238static inline int
239getQuantized
240(
241float x
242)
243{
244        if (x < 0.0) {
245                return (int) (x - 0.5);
246        }
247        return (int) (x + 0.5);
248}
249
250
251
252/// given input vector, return quantized version
253/**
254  This routine is basically determining the gridpoint indices for a given
255  input vector, answering the question: "which gridpoint is closest to the
256  provided point?".
257
258  "with clamp" means that we restrict the point to be in the heightfield's
259  axis-aligned bounding box.
260 */
261void btHeightfieldTerrainShape::quantizeWithClamp(int* out, const btVector3& point,int /*isMax*/) const
262{
263        btVector3 clampedPoint(point);
264        clampedPoint.setMax(m_localAabbMin);
265        clampedPoint.setMin(m_localAabbMax);
266
267        out[0] = getQuantized(clampedPoint.getX());
268        out[1] = getQuantized(clampedPoint.getY());
269        out[2] = getQuantized(clampedPoint.getZ());
270               
271}
272
273
274
275/// process all triangles within the provided axis-aligned bounding box
276/**
277  basic algorithm:
278    - convert input aabb to local coordinates (scale down and shift for local origin)
279    - convert input aabb to a range of heightfield grid points (quantize)
280    - iterate over all triangles in that subset of the grid
281 */
282void    btHeightfieldTerrainShape::processAllTriangles(btTriangleCallback* callback,const btVector3& aabbMin,const btVector3& aabbMax) const
283{
284        // scale down the input aabb's so they are in local (non-scaled) coordinates
285        btVector3       localAabbMin = aabbMin*btVector3(1.f/m_localScaling[0],1.f/m_localScaling[1],1.f/m_localScaling[2]);
286        btVector3       localAabbMax = aabbMax*btVector3(1.f/m_localScaling[0],1.f/m_localScaling[1],1.f/m_localScaling[2]);
287
288        // account for local origin
289        localAabbMin += m_localOrigin;
290        localAabbMax += m_localOrigin;
291
292        //quantize the aabbMin and aabbMax, and adjust the start/end ranges
293        int     quantizedAabbMin[3];
294        int     quantizedAabbMax[3];
295        quantizeWithClamp(quantizedAabbMin, localAabbMin,0);
296        quantizeWithClamp(quantizedAabbMax, localAabbMax,1);
297       
298        // expand the min/max quantized values
299        // this is to catch the case where the input aabb falls between grid points!
300        for (int i = 0; i < 3; ++i) {
301                quantizedAabbMin[i]--;
302                quantizedAabbMax[i]++;
303        }       
304
305        int startX=0;
306        int endX=m_heightStickWidth-1;
307        int startJ=0;
308        int endJ=m_heightStickLength-1;
309
310        switch (m_upAxis)
311        {
312        case 0:
313                {
314                        if (quantizedAabbMin[1]>startX)
315                                startX = quantizedAabbMin[1];
316                        if (quantizedAabbMax[1]<endX)
317                                endX = quantizedAabbMax[1];
318                        if (quantizedAabbMin[2]>startJ)
319                                startJ = quantizedAabbMin[2];
320                        if (quantizedAabbMax[2]<endJ)
321                                endJ = quantizedAabbMax[2];
322                        break;
323                }
324        case 1:
325                {
326                        if (quantizedAabbMin[0]>startX)
327                                startX = quantizedAabbMin[0];
328                        if (quantizedAabbMax[0]<endX)
329                                endX = quantizedAabbMax[0];
330                        if (quantizedAabbMin[2]>startJ)
331                                startJ = quantizedAabbMin[2];
332                        if (quantizedAabbMax[2]<endJ)
333                                endJ = quantizedAabbMax[2];
334                        break;
335                };
336        case 2:
337                {
338                        if (quantizedAabbMin[0]>startX)
339                                startX = quantizedAabbMin[0];
340                        if (quantizedAabbMax[0]<endX)
341                                endX = quantizedAabbMax[0];
342                        if (quantizedAabbMin[1]>startJ)
343                                startJ = quantizedAabbMin[1];
344                        if (quantizedAabbMax[1]<endJ)
345                                endJ = quantizedAabbMax[1];
346                        break;
347                }
348        default:
349                {
350                        //need to get valid m_upAxis
351                        btAssert(0);
352                }
353        }
354
355       
356 
357
358        for(int j=startJ; j<endJ; j++)
359        {
360                for(int x=startX; x<endX; x++)
361                {
362                        btVector3 vertices[3];
363                        if (m_flipQuadEdges || (m_useDiamondSubdivision && !((j+x) & 1)))
364                        {
365        //first triangle
366        getVertex(x,j,vertices[0]);
367        getVertex(x+1,j,vertices[1]);
368        getVertex(x+1,j+1,vertices[2]);
369        callback->processTriangle(vertices,x,j);
370        //second triangle
371        getVertex(x,j,vertices[0]);
372        getVertex(x+1,j+1,vertices[1]);
373        getVertex(x,j+1,vertices[2]);
374        callback->processTriangle(vertices,x,j);                               
375                        } else
376                        {
377        //first triangle
378        getVertex(x,j,vertices[0]);
379        getVertex(x,j+1,vertices[1]);
380        getVertex(x+1,j,vertices[2]);
381        callback->processTriangle(vertices,x,j);
382        //second triangle
383        getVertex(x+1,j,vertices[0]);
384        getVertex(x,j+1,vertices[1]);
385        getVertex(x+1,j+1,vertices[2]);
386        callback->processTriangle(vertices,x,j);
387                        }
388                }
389        }
390
391       
392
393}
394
395void    btHeightfieldTerrainShape::calculateLocalInertia(btScalar ,btVector3& inertia) const
396{
397        //moving concave objects not supported
398       
399        inertia.setValue(btScalar(0.),btScalar(0.),btScalar(0.));
400}
401
402void    btHeightfieldTerrainShape::setLocalScaling(const btVector3& scaling)
403{
404        m_localScaling = scaling;
405}
406const btVector3& btHeightfieldTerrainShape::getLocalScaling() const
407{
408        return m_localScaling;
409}
Note: See TracBrowser for help on using the repository browser.