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, 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,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.0;
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, 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_upAxis = upAxis;
00086         m_localScaling.setValue(btScalar(1.), btScalar(1.), btScalar(1.));
00087 
00088         // determine min/max axis-aligned bounding box (aabb) values
00089         switch (m_upAxis)
00090         {
00091         case 0:
00092                 {
00093                         m_localAabbMin.setValue(m_minHeight, 0, 0);
00094                         m_localAabbMax.setValue(m_maxHeight, m_width, m_length);
00095                         break;
00096                 }
00097         case 1:
00098                 {
00099                         m_localAabbMin.setValue(0, m_minHeight, 0);
00100                         m_localAabbMax.setValue(m_width, m_maxHeight, m_length);
00101                         break;
00102                 };
00103         case 2:
00104                 {
00105                         m_localAabbMin.setValue(0, 0, m_minHeight);
00106                         m_localAabbMax.setValue(m_width, m_length, m_maxHeight);
00107                         break;
00108                 }
00109         default:
00110                 {
00111                         //need to get valid m_upAxis
00112                         btAssert(0 && "Bad m_upAxis");
00113                 }
00114         }
00115 
00116         // remember origin (defined as exact middle of aabb)
00117         m_localOrigin = btScalar(0.5) * (m_localAabbMin + m_localAabbMax);
00118 }
00119 
00120 
00121 
00122 btHeightfieldTerrainShape::~btHeightfieldTerrainShape()
00123 {
00124 }
00125 
00126 
00127 
00128 void btHeightfieldTerrainShape::getAabb(const btTransform& t,btVector3& aabbMin,btVector3& aabbMax) const
00129 {
00130         btVector3 halfExtents = (m_localAabbMax-m_localAabbMin)* m_localScaling * btScalar(0.5);
00131 
00132         btVector3 localOrigin(0, 0, 0);
00133         localOrigin[m_upAxis] = (m_minHeight + m_maxHeight) * btScalar(0.5);
00134         localOrigin *= m_localScaling;
00135 
00136         btMatrix3x3 abs_b = t.getBasis().absolute();  
00137         btVector3 center = t.getOrigin();
00138         btVector3 extent = btVector3(abs_b[0].dot(halfExtents),
00139                    abs_b[1].dot(halfExtents),
00140                   abs_b[2].dot(halfExtents));
00141         extent += btVector3(getMargin(),getMargin(),getMargin());
00142 
00143         aabbMin = center - extent;
00144         aabbMax = center + extent;
00145 }
00146 
00147 
00151 btScalar
00152 btHeightfieldTerrainShape::getRawHeightFieldValue(int x,int y) const
00153 {
00154         btScalar val = 0.f;
00155         switch (m_heightDataType)
00156         {
00157         case PHY_FLOAT:
00158                 {
00159                         val = m_heightfieldDataFloat[(y*m_heightStickWidth)+x];
00160                         break;
00161                 }
00162 
00163         case PHY_UCHAR:
00164                 {
00165                         unsigned char heightFieldValue = m_heightfieldDataUnsignedChar[(y*m_heightStickWidth)+x];
00166                         val = heightFieldValue * m_heightScale;
00167                         break;
00168                 }
00169 
00170         case PHY_SHORT:
00171                 {
00172                         short hfValue = m_heightfieldDataShort[(y * m_heightStickWidth) + x];
00173                         val = hfValue * m_heightScale;
00174                         break;
00175                 }
00176 
00177         default:
00178                 {
00179                         btAssert(!"Bad m_heightDataType");
00180                 }
00181         }
00182 
00183         return val;
00184 }
00185 
00186 
00187 
00188 
00190 void    btHeightfieldTerrainShape::getVertex(int x,int y,btVector3& vertex) const
00191 {
00192         btAssert(x>=0);
00193         btAssert(y>=0);
00194         btAssert(x<m_heightStickWidth);
00195         btAssert(y<m_heightStickLength);
00196 
00197         btScalar        height = getRawHeightFieldValue(x,y);
00198 
00199         switch (m_upAxis)
00200         {
00201         case 0:
00202                 {
00203                 vertex.setValue(
00204                         height - m_localOrigin.getX(),
00205                         (-m_width/btScalar(2.0)) + x,
00206                         (-m_length/btScalar(2.0) ) + y
00207                         );
00208                         break;
00209                 }
00210         case 1:
00211                 {
00212                         vertex.setValue(
00213                         (-m_width/btScalar(2.0)) + x,
00214                         height - m_localOrigin.getY(),
00215                         (-m_length/btScalar(2.0)) + y
00216                         );
00217                         break;
00218                 };
00219         case 2:
00220                 {
00221                         vertex.setValue(
00222                         (-m_width/btScalar(2.0)) + x,
00223                         (-m_length/btScalar(2.0)) + y,
00224                         height - m_localOrigin.getZ()
00225                         );
00226                         break;
00227                 }
00228         default:
00229                 {
00230                         //need to get valid m_upAxis
00231                         btAssert(0);
00232                 }
00233         }
00234 
00235         vertex*=m_localScaling;
00236 }
00237 
00238 
00239 
00240 static inline int
00241 getQuantized
00242 (
00243 btScalar x
00244 )
00245 {
00246         if (x < 0.0) {
00247                 return (int) (x - 0.5);
00248         }
00249         return (int) (x + 0.5);
00250 }
00251 
00252 
00253 
00255 
00263 void btHeightfieldTerrainShape::quantizeWithClamp(int* out, const btVector3& point,int /*isMax*/) const
00264 {
00265         btVector3 clampedPoint(point);
00266         clampedPoint.setMax(m_localAabbMin);
00267         clampedPoint.setMin(m_localAabbMax);
00268 
00269         out[0] = getQuantized(clampedPoint.getX());
00270         out[1] = getQuantized(clampedPoint.getY());
00271         out[2] = getQuantized(clampedPoint.getZ());
00272                 
00273 }
00274 
00275 
00276 
00278 
00284 void    btHeightfieldTerrainShape::processAllTriangles(btTriangleCallback* callback,const btVector3& aabbMin,const btVector3& aabbMax) const
00285 {
00286         // scale down the input aabb's so they are in local (non-scaled) coordinates
00287         btVector3       localAabbMin = aabbMin*btVector3(1.f/m_localScaling[0],1.f/m_localScaling[1],1.f/m_localScaling[2]);
00288         btVector3       localAabbMax = aabbMax*btVector3(1.f/m_localScaling[0],1.f/m_localScaling[1],1.f/m_localScaling[2]);
00289 
00290         // account for local origin
00291         localAabbMin += m_localOrigin;
00292         localAabbMax += m_localOrigin;
00293 
00294         //quantize the aabbMin and aabbMax, and adjust the start/end ranges
00295         int     quantizedAabbMin[3];
00296         int     quantizedAabbMax[3];
00297         quantizeWithClamp(quantizedAabbMin, localAabbMin,0);
00298         quantizeWithClamp(quantizedAabbMax, localAabbMax,1);
00299         
00300         // expand the min/max quantized values
00301         // this is to catch the case where the input aabb falls between grid points!
00302         for (int i = 0; i < 3; ++i) {
00303                 quantizedAabbMin[i]--;
00304                 quantizedAabbMax[i]++;
00305         }       
00306 
00307         int startX=0;
00308         int endX=m_heightStickWidth-1;
00309         int startJ=0;
00310         int endJ=m_heightStickLength-1;
00311 
00312         switch (m_upAxis)
00313         {
00314         case 0:
00315                 {
00316                         if (quantizedAabbMin[1]>startX)
00317                                 startX = quantizedAabbMin[1];
00318                         if (quantizedAabbMax[1]<endX)
00319                                 endX = quantizedAabbMax[1];
00320                         if (quantizedAabbMin[2]>startJ)
00321                                 startJ = quantizedAabbMin[2];
00322                         if (quantizedAabbMax[2]<endJ)
00323                                 endJ = quantizedAabbMax[2];
00324                         break;
00325                 }
00326         case 1:
00327                 {
00328                         if (quantizedAabbMin[0]>startX)
00329                                 startX = quantizedAabbMin[0];
00330                         if (quantizedAabbMax[0]<endX)
00331                                 endX = quantizedAabbMax[0];
00332                         if (quantizedAabbMin[2]>startJ)
00333                                 startJ = quantizedAabbMin[2];
00334                         if (quantizedAabbMax[2]<endJ)
00335                                 endJ = quantizedAabbMax[2];
00336                         break;
00337                 };
00338         case 2:
00339                 {
00340                         if (quantizedAabbMin[0]>startX)
00341                                 startX = quantizedAabbMin[0];
00342                         if (quantizedAabbMax[0]<endX)
00343                                 endX = quantizedAabbMax[0];
00344                         if (quantizedAabbMin[1]>startJ)
00345                                 startJ = quantizedAabbMin[1];
00346                         if (quantizedAabbMax[1]<endJ)
00347                                 endJ = quantizedAabbMax[1];
00348                         break;
00349                 }
00350         default:
00351                 {
00352                         //need to get valid m_upAxis
00353                         btAssert(0);
00354                 }
00355         }
00356 
00357         
00358   
00359 
00360         for(int j=startJ; j<endJ; j++)
00361         {
00362                 for(int x=startX; x<endX; x++)
00363                 {
00364                         btVector3 vertices[3];
00365                         if (m_flipQuadEdges || (m_useDiamondSubdivision && !((j+x) & 1)))
00366                         {
00367         //first triangle
00368         getVertex(x,j,vertices[0]);
00369         getVertex(x+1,j,vertices[1]);
00370         getVertex(x+1,j+1,vertices[2]);
00371         callback->processTriangle(vertices,x,j);
00372         //second triangle
00373         getVertex(x,j,vertices[0]);
00374         getVertex(x+1,j+1,vertices[1]);
00375         getVertex(x,j+1,vertices[2]);
00376         callback->processTriangle(vertices,x,j);                                
00377                         } else
00378                         {
00379         //first triangle
00380         getVertex(x,j,vertices[0]);
00381         getVertex(x,j+1,vertices[1]);
00382         getVertex(x+1,j,vertices[2]);
00383         callback->processTriangle(vertices,x,j);
00384         //second triangle
00385         getVertex(x+1,j,vertices[0]);
00386         getVertex(x,j+1,vertices[1]);
00387         getVertex(x+1,j+1,vertices[2]);
00388         callback->processTriangle(vertices,x,j);
00389                         }
00390                 }
00391         }
00392 
00393         
00394 
00395 }
00396 
00397 void    btHeightfieldTerrainShape::calculateLocalInertia(btScalar ,btVector3& inertia) const
00398 {
00399         //moving concave objects not supported
00400         
00401         inertia.setValue(btScalar(0.),btScalar(0.),btScalar(0.));
00402 }
00403 
00404 void    btHeightfieldTerrainShape::setLocalScaling(const btVector3& scaling)
00405 {
00406         m_localScaling = scaling;
00407 }
00408 const btVector3& btHeightfieldTerrainShape::getLocalScaling() const
00409 {
00410         return m_localScaling;
00411 }

Generated on Mon Feb 15 22:17:04 2010 for Bullet Collision Detection & Physics Library by  doxygen 1.6.1