|
@@ -17,6 +17,47 @@ subject to the following restrictions:
|
|
|
|
|
|
#include "LinearMath/btTransformUtil.h"
|
|
|
|
|
|
+btHeightfieldTerrainShape::btHeightfieldTerrainShape(
|
|
|
+ int heightStickWidth, int heightStickLength,
|
|
|
+ const float* heightfieldData, btScalar minHeight, btScalar maxHeight,
|
|
|
+ int upAxis, bool flipQuadEdges)
|
|
|
+ : m_userValue3(0), m_triangleInfoMap(0)
|
|
|
+{
|
|
|
+ initialize(heightStickWidth, heightStickLength, heightfieldData,
|
|
|
+ /*heightScale=*/1, minHeight, maxHeight, upAxis, PHY_FLOAT,
|
|
|
+ flipQuadEdges);
|
|
|
+}
|
|
|
+
|
|
|
+btHeightfieldTerrainShape::btHeightfieldTerrainShape(
|
|
|
+ int heightStickWidth, int heightStickLength, const double* heightfieldData,
|
|
|
+ btScalar minHeight, btScalar maxHeight, int upAxis, bool flipQuadEdges)
|
|
|
+ : m_userValue3(0), m_triangleInfoMap(0)
|
|
|
+{
|
|
|
+ initialize(heightStickWidth, heightStickLength, heightfieldData,
|
|
|
+ /*heightScale=*/1, minHeight, maxHeight, upAxis, PHY_DOUBLE,
|
|
|
+ flipQuadEdges);
|
|
|
+}
|
|
|
+
|
|
|
+btHeightfieldTerrainShape::btHeightfieldTerrainShape(
|
|
|
+ int heightStickWidth, int heightStickLength, const short* heightfieldData, btScalar heightScale,
|
|
|
+ btScalar minHeight, btScalar maxHeight, int upAxis, bool flipQuadEdges)
|
|
|
+ : m_userValue3(0), m_triangleInfoMap(0)
|
|
|
+{
|
|
|
+ initialize(heightStickWidth, heightStickLength, heightfieldData,
|
|
|
+ heightScale, minHeight, maxHeight, upAxis, PHY_SHORT,
|
|
|
+ flipQuadEdges);
|
|
|
+}
|
|
|
+
|
|
|
+btHeightfieldTerrainShape::btHeightfieldTerrainShape(
|
|
|
+ int heightStickWidth, int heightStickLength, const unsigned char* heightfieldData, btScalar heightScale,
|
|
|
+ btScalar minHeight, btScalar maxHeight, int upAxis, bool flipQuadEdges)
|
|
|
+ : m_userValue3(0), m_triangleInfoMap(0)
|
|
|
+{
|
|
|
+ initialize(heightStickWidth, heightStickLength, heightfieldData,
|
|
|
+ heightScale, minHeight, maxHeight, upAxis, PHY_UCHAR,
|
|
|
+ flipQuadEdges);
|
|
|
+}
|
|
|
+
|
|
|
btHeightfieldTerrainShape::btHeightfieldTerrainShape(
|
|
|
int heightStickWidth, int heightStickLength, const void* heightfieldData,
|
|
|
btScalar heightScale, btScalar minHeight, btScalar maxHeight, int upAxis,
|
|
@@ -24,6 +65,10 @@ btHeightfieldTerrainShape::btHeightfieldTerrainShape(
|
|
|
:m_userValue3(0),
|
|
|
m_triangleInfoMap(0)
|
|
|
{
|
|
|
+ // legacy constructor: Assumes PHY_FLOAT means btScalar.
|
|
|
+#ifdef BT_USE_DOUBLE_PRECISION
|
|
|
+ if (hdt == PHY_FLOAT) hdt = PHY_DOUBLE;
|
|
|
+#endif
|
|
|
initialize(heightStickWidth, heightStickLength, heightfieldData,
|
|
|
heightScale, minHeight, maxHeight, upAxis, hdt,
|
|
|
flipQuadEdges);
|
|
@@ -33,9 +78,12 @@ btHeightfieldTerrainShape::btHeightfieldTerrainShape(int heightStickWidth, int h
|
|
|
: m_userValue3(0),
|
|
|
m_triangleInfoMap(0)
|
|
|
{
|
|
|
- // legacy constructor: support only float or unsigned char,
|
|
|
- // and min height is zero
|
|
|
+ // legacy constructor: support only btScalar or unsigned char data,
|
|
|
+ // and min height is zero.
|
|
|
PHY_ScalarType hdt = (useFloatData) ? PHY_FLOAT : PHY_UCHAR;
|
|
|
+#ifdef BT_USE_DOUBLE_PRECISION
|
|
|
+ if (hdt == PHY_FLOAT) hdt = PHY_DOUBLE;
|
|
|
+#endif
|
|
|
btScalar minHeight = 0.0f;
|
|
|
|
|
|
// previously, height = uchar * maxHeight / 65535.
|
|
@@ -59,7 +107,7 @@ void btHeightfieldTerrainShape::initialize(
|
|
|
// btAssert(heightScale) -- do we care? Trust caller here
|
|
|
btAssert(minHeight <= maxHeight); // && "bad min/max height");
|
|
|
btAssert(upAxis >= 0 && upAxis < 3); // && "bad upAxis--should be in range [0,2]");
|
|
|
- btAssert(hdt != PHY_UCHAR || hdt != PHY_FLOAT || hdt != PHY_SHORT); // && "Bad height data type enum");
|
|
|
+ btAssert(hdt != PHY_UCHAR || hdt != PHY_FLOAT || hdt != PHY_DOUBLE || hdt != PHY_SHORT); // && "Bad height data type enum");
|
|
|
|
|
|
// initialize member variables
|
|
|
m_shapeType = TERRAIN_SHAPE_PROXYTYPE;
|
|
@@ -152,6 +200,12 @@ btHeightfieldTerrainShape::getRawHeightFieldValue(int x, int y) const
|
|
|
break;
|
|
|
}
|
|
|
|
|
|
+ case PHY_DOUBLE:
|
|
|
+ {
|
|
|
+ val = m_heightfieldDataDouble[(y * m_heightStickWidth) + x];
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
case PHY_UCHAR:
|
|
|
{
|
|
|
unsigned char heightFieldValue = m_heightfieldDataUnsignedChar[(y * m_heightStickWidth) + x];
|
|
@@ -232,6 +286,30 @@ getQuantized(
|
|
|
return (int)(x + 0.5);
|
|
|
}
|
|
|
|
|
|
+// Equivalent to std::minmax({a, b, c}).
|
|
|
+// Performs at most 3 comparisons.
|
|
|
+static btHeightfieldTerrainShape::Range minmaxRange(btScalar a, btScalar b, btScalar c)
|
|
|
+{
|
|
|
+ if (a > b)
|
|
|
+ {
|
|
|
+ if (b > c)
|
|
|
+ return btHeightfieldTerrainShape::Range(c, a);
|
|
|
+ else if (a > c)
|
|
|
+ return btHeightfieldTerrainShape::Range(b, a);
|
|
|
+ else
|
|
|
+ return btHeightfieldTerrainShape::Range(b, c);
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ if (a > c)
|
|
|
+ return btHeightfieldTerrainShape::Range(c, b);
|
|
|
+ else if (b > c)
|
|
|
+ return btHeightfieldTerrainShape::Range(a, b);
|
|
|
+ else
|
|
|
+ return btHeightfieldTerrainShape::Range(a, c);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
/// given input vector, return quantized version
|
|
|
/**
|
|
|
This routine is basically determining the gridpoint indices for a given
|
|
@@ -334,7 +412,8 @@ void btHeightfieldTerrainShape::processAllTriangles(btTriangleCallback* callback
|
|
|
}
|
|
|
|
|
|
// TODO If m_vboundsGrid is available, use it to determine if we really need to process this area
|
|
|
-
|
|
|
+
|
|
|
+ const Range aabbUpRange(aabbMin[m_upAxis], aabbMax[m_upAxis]);
|
|
|
for (int j = startJ; j < endJ; j++)
|
|
|
{
|
|
|
for (int x = startX; x < endX; x++)
|
|
@@ -349,29 +428,51 @@ void btHeightfieldTerrainShape::processAllTriangles(btTriangleCallback* callback
|
|
|
|
|
|
if (m_flipQuadEdges || (m_useDiamondSubdivision && !((j + x) & 1)) || (m_useZigzagSubdivision && !(j & 1)))
|
|
|
{
|
|
|
- //first triangle
|
|
|
getVertex(x, j, vertices[indices[0]]);
|
|
|
getVertex(x, j + 1, vertices[indices[1]]);
|
|
|
getVertex(x + 1, j + 1, vertices[indices[2]]);
|
|
|
- callback->processTriangle(vertices, 2 * x, j);
|
|
|
- //second triangle
|
|
|
- // getVertex(x,j,vertices[0]);//already got this vertex before, thanks to Danny Chapman
|
|
|
- getVertex(x + 1, j + 1, vertices[indices[1]]);
|
|
|
+
|
|
|
+ // Skip triangle processing if the triangle is out-of-AABB.
|
|
|
+ Range upRange = minmaxRange(vertices[0][m_upAxis], vertices[1][m_upAxis], vertices[2][m_upAxis]);
|
|
|
+
|
|
|
+ if (upRange.overlaps(aabbUpRange))
|
|
|
+ callback->processTriangle(vertices, 2 * x, j);
|
|
|
+
|
|
|
+ // already set: getVertex(x, j, vertices[indices[0]])
|
|
|
+
|
|
|
+ // equivalent to: getVertex(x + 1, j + 1, vertices[indices[1]]);
|
|
|
+ vertices[indices[1]] = vertices[indices[2]];
|
|
|
+
|
|
|
getVertex(x + 1, j, vertices[indices[2]]);
|
|
|
- callback->processTriangle(vertices, 2 * x+1, j);
|
|
|
+ upRange.min = btMin(upRange.min, vertices[indices[2]][m_upAxis]);
|
|
|
+ upRange.max = btMax(upRange.max, vertices[indices[2]][m_upAxis]);
|
|
|
+
|
|
|
+ if (upRange.overlaps(aabbUpRange))
|
|
|
+ callback->processTriangle(vertices, 2 * x + 1, j);
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
- //first triangle
|
|
|
getVertex(x, j, vertices[indices[0]]);
|
|
|
getVertex(x, j + 1, vertices[indices[1]]);
|
|
|
getVertex(x + 1, j, vertices[indices[2]]);
|
|
|
- callback->processTriangle(vertices, 2 * x, j);
|
|
|
- //second triangle
|
|
|
- getVertex(x + 1, j, vertices[indices[0]]);
|
|
|
- //getVertex(x,j+1,vertices[1]);
|
|
|
+
|
|
|
+ // Skip triangle processing if the triangle is out-of-AABB.
|
|
|
+ Range upRange = minmaxRange(vertices[0][m_upAxis], vertices[1][m_upAxis], vertices[2][m_upAxis]);
|
|
|
+
|
|
|
+ if (upRange.overlaps(aabbUpRange))
|
|
|
+ callback->processTriangle(vertices, 2 * x, j);
|
|
|
+
|
|
|
+ // already set: getVertex(x, j + 1, vertices[indices[1]]);
|
|
|
+
|
|
|
+ // equivalent to: getVertex(x + 1, j, vertices[indices[0]]);
|
|
|
+ vertices[indices[0]] = vertices[indices[2]];
|
|
|
+
|
|
|
getVertex(x + 1, j + 1, vertices[indices[2]]);
|
|
|
- callback->processTriangle(vertices, 2 * x+1, j);
|
|
|
+ upRange.min = btMin(upRange.min, vertices[indices[2]][m_upAxis]);
|
|
|
+ upRange.max = btMax(upRange.max, vertices[indices[2]][m_upAxis]);
|
|
|
+
|
|
|
+ if (upRange.overlaps(aabbUpRange))
|
|
|
+ callback->processTriangle(vertices, 2 * x + 1, j);
|
|
|
}
|
|
|
}
|
|
|
}
|
|
@@ -846,4 +947,4 @@ void btHeightfieldTerrainShape::buildAccelerator(int chunkSize)
|
|
|
void btHeightfieldTerrainShape::clearAccelerator()
|
|
|
{
|
|
|
m_vboundsGrid.clear();
|
|
|
-}
|
|
|
+}
|