btHeightfieldTerrainShape.cpp

Go to the documentation of this file.
00001 /*
00002 Bullet Continuous Collision Detection and Physics Library
00003 Copyright (c) 2003-2009 Erwin Coumans  http://bulletphysics.org
00004 
00005 This software is provided 'as-is', without any express or implied warranty.
00006 In no event will the authors be held liable for any damages arising from the use of this software.
00007 Permission is granted to anyone to use this software for any purpose, 
00008 including commercial applications, and to alter it and redistribute it freely, 
00009 subject to the following restrictions:
00010 
00011 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.
00012 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
00013 3. This notice may not be removed or altered from any source distribution.
00014 */
00015 
00016 #include "btHeightfieldTerrainShape.h"
00017 
00018 #include "LinearMath/btTransformUtil.h"
00019 
00020 
00021 
00022 btHeightfieldTerrainShape::btHeightfieldTerrainShape
00023 (
00024 int heightStickWidth, int heightStickLength, const void* heightfieldData,
00025 btScalar heightScale, btScalar minHeight, btScalar maxHeight,int upAxis,
00026 PHY_ScalarType hdt, bool flipQuadEdges
00027 )
00028 {
00029         initialize(heightStickWidth, heightStickLength, heightfieldData,
00030                    heightScale, minHeight, maxHeight, upAxis, hdt,
00031                    flipQuadEdges);
00032 }
00033 
00034 
00035 
00036 btHeightfieldTerrainShape::btHeightfieldTerrainShape(int heightStickWidth, int heightStickLength,const void* heightfieldData,btScalar maxHeight,int upAxis,bool useFloatData,bool flipQuadEdges)
00037 {
00038         // legacy constructor: support only float or unsigned char,
00039         //      and min height is zero
00040         PHY_ScalarType hdt = (useFloatData) ? PHY_FLOAT : PHY_UCHAR;
00041         btScalar minHeight = 0.0f;
00042 
00043         // previously, height = uchar * maxHeight / 65535.
00044         // So to preserve legacy behavior, heightScale = maxHeight / 65535
00045         btScalar heightScale = maxHeight / 65535;
00046 
00047         initialize(heightStickWidth, heightStickLength, heightfieldData,
00048                    heightScale, minHeight, maxHeight, upAxis, hdt,
00049                    flipQuadEdges);
00050 }
00051 
00052 
00053 
00054 void btHeightfieldTerrainShape::initialize
00055 (
00056 int heightStickWidth, int heightStickLength, const void* heightfieldData,
00057 btScalar heightScale, btScalar minHeight, btScalar maxHeight, int upAxis,
00058 PHY_ScalarType hdt, bool flipQuadEdges
00059 )
00060 {
00061         // validation
00062         btAssert(heightStickWidth > 1 && "bad width");
00063         btAssert(heightStickLength > 1 && "bad length");
00064         btAssert(heightfieldData && "null heightfield data");
00065         // btAssert(heightScale) -- do we care?  Trust caller here
00066         btAssert(minHeight <= maxHeight && "bad min/max height");
00067         btAssert(upAxis >= 0 && upAxis < 3 &&
00068             "bad upAxis--should be in range [0,2]");
00069         btAssert(hdt != PHY_UCHAR || hdt != PHY_FLOAT || hdt != PHY_SHORT &&
00070             "Bad height data type enum");
00071 
00072         // initialize member variables
00073         m_shapeType = TERRAIN_SHAPE_PROXYTYPE;
00074         m_heightStickWidth = heightStickWidth;
00075         m_heightStickLength = heightStickLength;
00076         m_minHeight = minHeight;
00077         m_maxHeight = maxHeight;
00078         m_width = (btScalar) (heightStickWidth - 1);
00079         m_length = (btScalar) (heightStickLength - 1);
00080         m_heightScale = heightScale;
00081         m_heightfieldDataUnknown = heightfieldData;
00082         m_heightDataType = hdt;
00083         m_flipQuadEdges = flipQuadEdges;
00084         m_useDiamondSubdivision = false;
00085         m_useZigzagSubdivision = false;
00086         m_upAxis = upAxis;
00087         m_localScaling.setValue(btScalar(1.), btScalar(1.), btScalar(1.));
00088 
00089         // determine min/max axis-aligned bounding box (aabb) values
00090         switch (m_upAxis)
00091         {
00092         case 0:
00093                 {
00094                         m_localAabbMin.setValue(m_minHeight, 0, 0);
00095                         m_localAabbMax.setValue(m_maxHeight, m_width, m_length);
00096                         break;
00097                 }
00098         case 1:
00099                 {
00100                         m_localAabbMin.setValue(0, m_minHeight, 0);
00101                         m_localAabbMax.setValue(m_width, m_maxHeight, m_length);
00102                         break;
00103                 };
00104         case 2:
00105                 {
00106                         m_localAabbMin.setValue(0, 0, m_minHeight);
00107                         m_localAabbMax.setValue(m_width, m_length, m_maxHeight);
00108                         break;
00109                 }
00110         default:
00111                 {
00112                         //need to get valid m_upAxis
00113                         btAssert(0 && "Bad m_upAxis");
00114                 }
00115         }
00116 
00117         // remember origin (defined as exact middle of aabb)
00118         m_localOrigin = btScalar(0.5) * (m_localAabbMin + m_localAabbMax);
00119 }
00120 
00121 
00122 
00123 btHeightfieldTerrainShape::~btHeightfieldTerrainShape()
00124 {
00125 }
00126 
00127 
00128 
00129 void btHeightfieldTerrainShape::getAabb(const btTransform& t,btVector3& aabbMin,btVector3& aabbMax) const
00130 {
00131         btVector3 halfExtents = (m_localAabbMax-m_localAabbMin)* m_localScaling * btScalar(0.5);
00132 
00133         btVector3 localOrigin(0, 0, 0);
00134         localOrigin[m_upAxis] = (m_minHeight + m_maxHeight) * btScalar(0.5);
00135         localOrigin *= m_localScaling;
00136 
00137         btMatrix3x3 abs_b = t.getBasis().absolute();  
00138         btVector3 center = t.getOrigin();
00139     btVector3 extent = halfExtents.dot3(abs_b[0], abs_b[1], abs_b[2]);
00140         extent += btVector3(getMargin(),getMargin(),getMargin());
00141 
00142         aabbMin = center - extent;
00143         aabbMax = center + extent;
00144 }
00145 
00146 
00150 btScalar
00151 btHeightfieldTerrainShape::getRawHeightFieldValue(int x,int y) const
00152 {
00153         btScalar val = 0.f;
00154         switch (m_heightDataType)
00155         {
00156         case PHY_FLOAT:
00157                 {
00158                         val = m_heightfieldDataFloat[(y*m_heightStickWidth)+x];
00159                         break;
00160                 }
00161 
00162         case PHY_UCHAR:
00163                 {
00164                         unsigned char heightFieldValue = m_heightfieldDataUnsignedChar[(y*m_heightStickWidth)+x];
00165                         val = heightFieldValue * m_heightScale;
00166                         break;
00167                 }
00168 
00169         case PHY_SHORT:
00170                 {
00171                         short hfValue = m_heightfieldDataShort[(y * m_heightStickWidth) + x];
00172                         val = hfValue * m_heightScale;
00173                         break;
00174                 }
00175 
00176         default:
00177                 {
00178                         btAssert(!"Bad m_heightDataType");
00179                 }
00180         }
00181 
00182         return val;
00183 }
00184 
00185 
00186 
00187 
00189 void    btHeightfieldTerrainShape::getVertex(int x,int y,btVector3& vertex) const
00190 {
00191         btAssert(x>=0);
00192         btAssert(y>=0);
00193         btAssert(x<m_heightStickWidth);
00194         btAssert(y<m_heightStickLength);
00195 
00196         btScalar        height = getRawHeightFieldValue(x,y);
00197 
00198         switch (m_upAxis)
00199         {
00200         case 0:
00201                 {
00202                 vertex.setValue(
00203                         height - m_localOrigin.getX(),
00204                         (-m_width/btScalar(2.0)) + x,
00205                         (-m_length/btScalar(2.0) ) + y
00206                         );
00207                         break;
00208                 }
00209         case 1:
00210                 {
00211                         vertex.setValue(
00212                         (-m_width/btScalar(2.0)) + x,
00213                         height - m_localOrigin.getY(),
00214                         (-m_length/btScalar(2.0)) + y
00215                         );
00216                         break;
00217                 };
00218         case 2:
00219                 {
00220                         vertex.setValue(
00221                         (-m_width/btScalar(2.0)) + x,
00222                         (-m_length/btScalar(2.0)) + y,
00223                         height - m_localOrigin.getZ()
00224                         );
00225                         break;
00226                 }
00227         default:
00228                 {
00229                         //need to get valid m_upAxis
00230                         btAssert(0);
00231                 }
00232         }
00233 
00234         vertex*=m_localScaling;
00235 }
00236 
00237 
00238 
00239 static inline int
00240 getQuantized
00241 (
00242 btScalar x
00243 )
00244 {
00245         if (x < 0.0) {
00246                 return (int) (x - 0.5);
00247         }
00248         return (int) (x + 0.5);
00249 }
00250 
00251 
00252 
00254 
00262 void btHeightfieldTerrainShape::quantizeWithClamp(int* out, const btVector3& point,int /*isMax*/) const
00263 {
00264         btVector3 clampedPoint(point);
00265         clampedPoint.setMax(m_localAabbMin);
00266         clampedPoint.setMin(m_localAabbMax);
00267 
00268         out[0] = getQuantized(clampedPoint.getX());
00269         out[1] = getQuantized(clampedPoint.getY());
00270         out[2] = getQuantized(clampedPoint.getZ());
00271                 
00272 }
00273 
00274 
00275 
00277 
00283 void    btHeightfieldTerrainShape::processAllTriangles(btTriangleCallback* callback,const btVector3& aabbMin,const btVector3& aabbMax) const
00284 {
00285         // scale down the input aabb's so they are in local (non-scaled) coordinates
00286         btVector3       localAabbMin = aabbMin*btVector3(1.f/m_localScaling[0],1.f/m_localScaling[1],1.f/m_localScaling[2]);
00287         btVector3       localAabbMax = aabbMax*btVector3(1.f/m_localScaling[0],1.f/m_localScaling[1],1.f/m_localScaling[2]);
00288 
00289         // account for local origin
00290         localAabbMin += m_localOrigin;
00291         localAabbMax += m_localOrigin;
00292 
00293         //quantize the aabbMin and aabbMax, and adjust the start/end ranges
00294         int     quantizedAabbMin[3];
00295         int     quantizedAabbMax[3];
00296         quantizeWithClamp(quantizedAabbMin, localAabbMin,0);
00297         quantizeWithClamp(quantizedAabbMax, localAabbMax,1);
00298         
00299         // expand the min/max quantized values
00300         // this is to catch the case where the input aabb falls between grid points!
00301         for (int i = 0; i < 3; ++i) {
00302                 quantizedAabbMin[i]--;
00303                 quantizedAabbMax[i]++;
00304         }       
00305 
00306         int startX=0;
00307         int endX=m_heightStickWidth-1;
00308         int startJ=0;
00309         int endJ=m_heightStickLength-1;
00310 
00311         switch (m_upAxis)
00312         {
00313         case 0:
00314                 {
00315                         if (quantizedAabbMin[1]>startX)
00316                                 startX = quantizedAabbMin[1];
00317                         if (quantizedAabbMax[1]<endX)
00318                                 endX = quantizedAabbMax[1];
00319                         if (quantizedAabbMin[2]>startJ)
00320                                 startJ = quantizedAabbMin[2];
00321                         if (quantizedAabbMax[2]<endJ)
00322                                 endJ = quantizedAabbMax[2];
00323                         break;
00324                 }
00325         case 1:
00326                 {
00327                         if (quantizedAabbMin[0]>startX)
00328                                 startX = quantizedAabbMin[0];
00329                         if (quantizedAabbMax[0]<endX)
00330                                 endX = quantizedAabbMax[0];
00331                         if (quantizedAabbMin[2]>startJ)
00332                                 startJ = quantizedAabbMin[2];
00333                         if (quantizedAabbMax[2]<endJ)
00334                                 endJ = quantizedAabbMax[2];
00335                         break;
00336                 };
00337         case 2:
00338                 {
00339                         if (quantizedAabbMin[0]>startX)
00340                                 startX = quantizedAabbMin[0];
00341                         if (quantizedAabbMax[0]<endX)
00342                                 endX = quantizedAabbMax[0];
00343                         if (quantizedAabbMin[1]>startJ)
00344                                 startJ = quantizedAabbMin[1];
00345                         if (quantizedAabbMax[1]<endJ)
00346                                 endJ = quantizedAabbMax[1];
00347                         break;
00348                 }
00349         default:
00350                 {
00351                         //need to get valid m_upAxis
00352                         btAssert(0);
00353                 }
00354         }
00355 
00356         
00357   
00358 
00359         for(int j=startJ; j<endJ; j++)
00360         {
00361                 for(int x=startX; x<endX; x++)
00362                 {
00363                         btVector3 vertices[3];
00364                         if (m_flipQuadEdges || (m_useDiamondSubdivision && !((j+x) & 1))|| (m_useZigzagSubdivision  && !(j & 1)))
00365                         {
00366         //first triangle
00367         getVertex(x,j,vertices[0]);
00368         getVertex(x+1,j,vertices[1]);
00369         getVertex(x+1,j+1,vertices[2]);
00370         callback->processTriangle(vertices,x,j);
00371         //second triangle
00372         getVertex(x,j,vertices[0]);
00373         getVertex(x+1,j+1,vertices[1]);
00374         getVertex(x,j+1,vertices[2]);
00375         callback->processTriangle(vertices,x,j);                                
00376                         } else
00377                         {
00378         //first triangle
00379         getVertex(x,j,vertices[0]);
00380         getVertex(x,j+1,vertices[1]);
00381         getVertex(x+1,j,vertices[2]);
00382         callback->processTriangle(vertices,x,j);
00383         //second triangle
00384         getVertex(x+1,j,vertices[0]);
00385         getVertex(x,j+1,vertices[1]);
00386         getVertex(x+1,j+1,vertices[2]);
00387         callback->processTriangle(vertices,x,j);
00388                         }
00389                 }
00390         }
00391 
00392         
00393 
00394 }
00395 
00396 void    btHeightfieldTerrainShape::calculateLocalInertia(btScalar ,btVector3& inertia) const
00397 {
00398         //moving concave objects not supported
00399         
00400         inertia.setValue(btScalar(0.),btScalar(0.),btScalar(0.));
00401 }
00402 
00403 void    btHeightfieldTerrainShape::setLocalScaling(const btVector3& scaling)
00404 {
00405         m_localScaling = scaling;
00406 }
00407 const btVector3& btHeightfieldTerrainShape::getLocalScaling() const
00408 {
00409         return m_localScaling;
00410 }