Blender V2.61 - r43446

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 }