Blender V2.61 - r43446
|
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 }