1351 lines
50 KiB
C++
1351 lines
50 KiB
C++
/*
|
|
Bullet Continuous Collision Detection and Physics Library
|
|
Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/
|
|
|
|
This software is provided 'as-is', without any express or implied warranty.
|
|
In no event will the authors be held liable for any damages arising from the use of this software.
|
|
Permission is granted to anyone to use this software for any purpose,
|
|
including commercial applications, and to alter it and redistribute it freely,
|
|
subject to the following restrictions:
|
|
|
|
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.
|
|
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
|
|
3. This notice may not be removed or altered from any source distribution.
|
|
*/
|
|
|
|
#include "btQuantizedBvh.h"
|
|
|
|
#include "LinearMath/btAabbUtil2.h"
|
|
#include "LinearMath/btIDebugDraw.h"
|
|
#include "LinearMath/btSerializer.h"
|
|
|
|
#define RAYAABB2
|
|
|
|
btQuantizedBvh::btQuantizedBvh() : m_bulletVersion(BT_BULLET_VERSION),
|
|
m_useQuantization(false),
|
|
//m_traversalMode(TRAVERSAL_STACKLESS_CACHE_FRIENDLY)
|
|
m_traversalMode(TRAVERSAL_STACKLESS)
|
|
//m_traversalMode(TRAVERSAL_RECURSIVE)
|
|
,
|
|
m_subtreeHeaderCount(0) //PCK: add this line
|
|
{
|
|
m_bvhAabbMin.setValue(-SIMD_INFINITY, -SIMD_INFINITY, -SIMD_INFINITY);
|
|
m_bvhAabbMax.setValue(SIMD_INFINITY, SIMD_INFINITY, SIMD_INFINITY);
|
|
}
|
|
|
|
void btQuantizedBvh::buildInternal()
|
|
{
|
|
///assumes that caller filled in the m_quantizedLeafNodes
|
|
m_useQuantization = true;
|
|
int numLeafNodes = 0;
|
|
|
|
if (m_useQuantization)
|
|
{
|
|
//now we have an array of leafnodes in m_leafNodes
|
|
numLeafNodes = m_quantizedLeafNodes.size();
|
|
|
|
m_quantizedContiguousNodes.resize(2 * numLeafNodes);
|
|
}
|
|
|
|
m_curNodeIndex = 0;
|
|
|
|
buildTree(0, numLeafNodes);
|
|
|
|
///if the entire tree is small then subtree size, we need to create a header info for the tree
|
|
if (m_useQuantization && !m_SubtreeHeaders.size())
|
|
{
|
|
btBvhSubtreeInfo& subtree = m_SubtreeHeaders.expand();
|
|
subtree.setAabbFromQuantizeNode(m_quantizedContiguousNodes[0]);
|
|
subtree.m_rootNodeIndex = 0;
|
|
subtree.m_subtreeSize = m_quantizedContiguousNodes[0].isLeafNode() ? 1 : m_quantizedContiguousNodes[0].getEscapeIndex();
|
|
}
|
|
|
|
//PCK: update the copy of the size
|
|
m_subtreeHeaderCount = m_SubtreeHeaders.size();
|
|
|
|
//PCK: clear m_quantizedLeafNodes and m_leafNodes, they are temporary
|
|
m_quantizedLeafNodes.clear();
|
|
m_leafNodes.clear();
|
|
}
|
|
|
|
///just for debugging, to visualize the individual patches/subtrees
|
|
#ifdef DEBUG_PATCH_COLORS
|
|
btVector3 color[4] =
|
|
{
|
|
btVector3(1, 0, 0),
|
|
btVector3(0, 1, 0),
|
|
btVector3(0, 0, 1),
|
|
btVector3(0, 1, 1)};
|
|
#endif //DEBUG_PATCH_COLORS
|
|
|
|
void btQuantizedBvh::setQuantizationValues(const btVector3& bvhAabbMin, const btVector3& bvhAabbMax, btScalar quantizationMargin)
|
|
{
|
|
//enlarge the AABB to avoid division by zero when initializing the quantization values
|
|
btVector3 clampValue(quantizationMargin, quantizationMargin, quantizationMargin);
|
|
m_bvhAabbMin = bvhAabbMin - clampValue;
|
|
m_bvhAabbMax = bvhAabbMax + clampValue;
|
|
btVector3 aabbSize = m_bvhAabbMax - m_bvhAabbMin;
|
|
m_bvhQuantization = btVector3(btScalar(65533.0), btScalar(65533.0), btScalar(65533.0)) / aabbSize;
|
|
|
|
m_useQuantization = true;
|
|
|
|
{
|
|
unsigned short vecIn[3];
|
|
btVector3 v;
|
|
{
|
|
quantize(vecIn, m_bvhAabbMin, false);
|
|
v = unQuantize(vecIn);
|
|
m_bvhAabbMin.setMin(v - clampValue);
|
|
}
|
|
aabbSize = m_bvhAabbMax - m_bvhAabbMin;
|
|
m_bvhQuantization = btVector3(btScalar(65533.0), btScalar(65533.0), btScalar(65533.0)) / aabbSize;
|
|
{
|
|
quantize(vecIn, m_bvhAabbMax, true);
|
|
v = unQuantize(vecIn);
|
|
m_bvhAabbMax.setMax(v + clampValue);
|
|
}
|
|
aabbSize = m_bvhAabbMax - m_bvhAabbMin;
|
|
m_bvhQuantization = btVector3(btScalar(65533.0), btScalar(65533.0), btScalar(65533.0)) / aabbSize;
|
|
}
|
|
}
|
|
|
|
btQuantizedBvh::~btQuantizedBvh()
|
|
{
|
|
}
|
|
|
|
#ifdef DEBUG_TREE_BUILDING
|
|
int gStackDepth = 0;
|
|
int gMaxStackDepth = 0;
|
|
#endif //DEBUG_TREE_BUILDING
|
|
|
|
void btQuantizedBvh::buildTree(int startIndex, int endIndex)
|
|
{
|
|
#ifdef DEBUG_TREE_BUILDING
|
|
gStackDepth++;
|
|
if (gStackDepth > gMaxStackDepth)
|
|
gMaxStackDepth = gStackDepth;
|
|
#endif //DEBUG_TREE_BUILDING
|
|
|
|
int splitAxis, splitIndex, i;
|
|
int numIndices = endIndex - startIndex;
|
|
int curIndex = m_curNodeIndex;
|
|
|
|
btAssert(numIndices > 0);
|
|
|
|
if (numIndices == 1)
|
|
{
|
|
#ifdef DEBUG_TREE_BUILDING
|
|
gStackDepth--;
|
|
#endif //DEBUG_TREE_BUILDING
|
|
|
|
assignInternalNodeFromLeafNode(m_curNodeIndex, startIndex);
|
|
|
|
m_curNodeIndex++;
|
|
return;
|
|
}
|
|
//calculate Best Splitting Axis and where to split it. Sort the incoming 'leafNodes' array within range 'startIndex/endIndex'.
|
|
|
|
splitAxis = calcSplittingAxis(startIndex, endIndex);
|
|
|
|
splitIndex = sortAndCalcSplittingIndex(startIndex, endIndex, splitAxis);
|
|
|
|
int internalNodeIndex = m_curNodeIndex;
|
|
|
|
//set the min aabb to 'inf' or a max value, and set the max aabb to a -inf/minimum value.
|
|
//the aabb will be expanded during buildTree/mergeInternalNodeAabb with actual node values
|
|
setInternalNodeAabbMin(m_curNodeIndex, m_bvhAabbMax); //can't use btVector3(SIMD_INFINITY,SIMD_INFINITY,SIMD_INFINITY)) because of quantization
|
|
setInternalNodeAabbMax(m_curNodeIndex, m_bvhAabbMin); //can't use btVector3(-SIMD_INFINITY,-SIMD_INFINITY,-SIMD_INFINITY)) because of quantization
|
|
|
|
for (i = startIndex; i < endIndex; i++)
|
|
{
|
|
mergeInternalNodeAabb(m_curNodeIndex, getAabbMin(i), getAabbMax(i));
|
|
}
|
|
|
|
m_curNodeIndex++;
|
|
|
|
//internalNode->m_escapeIndex;
|
|
|
|
int leftChildNodexIndex = m_curNodeIndex;
|
|
|
|
//build left child tree
|
|
buildTree(startIndex, splitIndex);
|
|
|
|
int rightChildNodexIndex = m_curNodeIndex;
|
|
//build right child tree
|
|
buildTree(splitIndex, endIndex);
|
|
|
|
#ifdef DEBUG_TREE_BUILDING
|
|
gStackDepth--;
|
|
#endif //DEBUG_TREE_BUILDING
|
|
|
|
int escapeIndex = m_curNodeIndex - curIndex;
|
|
|
|
if (m_useQuantization)
|
|
{
|
|
//escapeIndex is the number of nodes of this subtree
|
|
const int sizeQuantizedNode = sizeof(btQuantizedBvhNode);
|
|
const int treeSizeInBytes = escapeIndex * sizeQuantizedNode;
|
|
if (treeSizeInBytes > MAX_SUBTREE_SIZE_IN_BYTES)
|
|
{
|
|
updateSubtreeHeaders(leftChildNodexIndex, rightChildNodexIndex);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
}
|
|
|
|
setInternalNodeEscapeIndex(internalNodeIndex, escapeIndex);
|
|
}
|
|
|
|
void btQuantizedBvh::updateSubtreeHeaders(int leftChildNodexIndex, int rightChildNodexIndex)
|
|
{
|
|
btAssert(m_useQuantization);
|
|
|
|
btQuantizedBvhNode& leftChildNode = m_quantizedContiguousNodes[leftChildNodexIndex];
|
|
int leftSubTreeSize = leftChildNode.isLeafNode() ? 1 : leftChildNode.getEscapeIndex();
|
|
int leftSubTreeSizeInBytes = leftSubTreeSize * static_cast<int>(sizeof(btQuantizedBvhNode));
|
|
|
|
btQuantizedBvhNode& rightChildNode = m_quantizedContiguousNodes[rightChildNodexIndex];
|
|
int rightSubTreeSize = rightChildNode.isLeafNode() ? 1 : rightChildNode.getEscapeIndex();
|
|
int rightSubTreeSizeInBytes = rightSubTreeSize * static_cast<int>(sizeof(btQuantizedBvhNode));
|
|
|
|
if (leftSubTreeSizeInBytes <= MAX_SUBTREE_SIZE_IN_BYTES)
|
|
{
|
|
btBvhSubtreeInfo& subtree = m_SubtreeHeaders.expand();
|
|
subtree.setAabbFromQuantizeNode(leftChildNode);
|
|
subtree.m_rootNodeIndex = leftChildNodexIndex;
|
|
subtree.m_subtreeSize = leftSubTreeSize;
|
|
}
|
|
|
|
if (rightSubTreeSizeInBytes <= MAX_SUBTREE_SIZE_IN_BYTES)
|
|
{
|
|
btBvhSubtreeInfo& subtree = m_SubtreeHeaders.expand();
|
|
subtree.setAabbFromQuantizeNode(rightChildNode);
|
|
subtree.m_rootNodeIndex = rightChildNodexIndex;
|
|
subtree.m_subtreeSize = rightSubTreeSize;
|
|
}
|
|
|
|
//PCK: update the copy of the size
|
|
m_subtreeHeaderCount = m_SubtreeHeaders.size();
|
|
}
|
|
|
|
int btQuantizedBvh::sortAndCalcSplittingIndex(int startIndex, int endIndex, int splitAxis)
|
|
{
|
|
int i;
|
|
int splitIndex = startIndex;
|
|
int numIndices = endIndex - startIndex;
|
|
btScalar splitValue;
|
|
|
|
btVector3 means(btScalar(0.), btScalar(0.), btScalar(0.));
|
|
for (i = startIndex; i < endIndex; i++)
|
|
{
|
|
btVector3 center = btScalar(0.5) * (getAabbMax(i) + getAabbMin(i));
|
|
means += center;
|
|
}
|
|
means *= (btScalar(1.) / (btScalar)numIndices);
|
|
|
|
splitValue = means[splitAxis];
|
|
|
|
//sort leafNodes so all values larger then splitValue comes first, and smaller values start from 'splitIndex'.
|
|
for (i = startIndex; i < endIndex; i++)
|
|
{
|
|
btVector3 center = btScalar(0.5) * (getAabbMax(i) + getAabbMin(i));
|
|
if (center[splitAxis] > splitValue)
|
|
{
|
|
//swap
|
|
swapLeafNodes(i, splitIndex);
|
|
splitIndex++;
|
|
}
|
|
}
|
|
|
|
//if the splitIndex causes unbalanced trees, fix this by using the center in between startIndex and endIndex
|
|
//otherwise the tree-building might fail due to stack-overflows in certain cases.
|
|
//unbalanced1 is unsafe: it can cause stack overflows
|
|
//bool unbalanced1 = ((splitIndex==startIndex) || (splitIndex == (endIndex-1)));
|
|
|
|
//unbalanced2 should work too: always use center (perfect balanced trees)
|
|
//bool unbalanced2 = true;
|
|
|
|
//this should be safe too:
|
|
int rangeBalancedIndices = numIndices / 3;
|
|
bool unbalanced = ((splitIndex <= (startIndex + rangeBalancedIndices)) || (splitIndex >= (endIndex - 1 - rangeBalancedIndices)));
|
|
|
|
if (unbalanced)
|
|
{
|
|
splitIndex = startIndex + (numIndices >> 1);
|
|
}
|
|
|
|
bool unbal = (splitIndex == startIndex) || (splitIndex == (endIndex));
|
|
(void)unbal;
|
|
btAssert(!unbal);
|
|
|
|
return splitIndex;
|
|
}
|
|
|
|
int btQuantizedBvh::calcSplittingAxis(int startIndex, int endIndex)
|
|
{
|
|
int i;
|
|
|
|
btVector3 means(btScalar(0.), btScalar(0.), btScalar(0.));
|
|
btVector3 variance(btScalar(0.), btScalar(0.), btScalar(0.));
|
|
int numIndices = endIndex - startIndex;
|
|
|
|
for (i = startIndex; i < endIndex; i++)
|
|
{
|
|
btVector3 center = btScalar(0.5) * (getAabbMax(i) + getAabbMin(i));
|
|
means += center;
|
|
}
|
|
means *= (btScalar(1.) / (btScalar)numIndices);
|
|
|
|
for (i = startIndex; i < endIndex; i++)
|
|
{
|
|
btVector3 center = btScalar(0.5) * (getAabbMax(i) + getAabbMin(i));
|
|
btVector3 diff2 = center - means;
|
|
diff2 = diff2 * diff2;
|
|
variance += diff2;
|
|
}
|
|
variance *= (btScalar(1.) / ((btScalar)numIndices - 1));
|
|
|
|
return variance.maxAxis();
|
|
}
|
|
|
|
void btQuantizedBvh::reportAabbOverlappingNodex(btNodeOverlapCallback* nodeCallback, const btVector3& aabbMin, const btVector3& aabbMax) const
|
|
{
|
|
//either choose recursive traversal (walkTree) or stackless (walkStacklessTree)
|
|
|
|
if (m_useQuantization)
|
|
{
|
|
///quantize query AABB
|
|
unsigned short int quantizedQueryAabbMin[3];
|
|
unsigned short int quantizedQueryAabbMax[3];
|
|
quantizeWithClamp(quantizedQueryAabbMin, aabbMin, 0);
|
|
quantizeWithClamp(quantizedQueryAabbMax, aabbMax, 1);
|
|
|
|
switch (m_traversalMode)
|
|
{
|
|
case TRAVERSAL_STACKLESS:
|
|
walkStacklessQuantizedTree(nodeCallback, quantizedQueryAabbMin, quantizedQueryAabbMax, 0, m_curNodeIndex);
|
|
break;
|
|
case TRAVERSAL_STACKLESS_CACHE_FRIENDLY:
|
|
walkStacklessQuantizedTreeCacheFriendly(nodeCallback, quantizedQueryAabbMin, quantizedQueryAabbMax);
|
|
break;
|
|
case TRAVERSAL_RECURSIVE:
|
|
{
|
|
const btQuantizedBvhNode* rootNode = &m_quantizedContiguousNodes[0];
|
|
walkRecursiveQuantizedTreeAgainstQueryAabb(rootNode, nodeCallback, quantizedQueryAabbMin, quantizedQueryAabbMax);
|
|
}
|
|
break;
|
|
default:
|
|
//unsupported
|
|
btAssert(0);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
walkStacklessTree(nodeCallback, aabbMin, aabbMax);
|
|
}
|
|
}
|
|
|
|
int maxIterations = 0;
|
|
|
|
void btQuantizedBvh::walkStacklessTree(btNodeOverlapCallback* nodeCallback, const btVector3& aabbMin, const btVector3& aabbMax) const
|
|
{
|
|
btAssert(!m_useQuantization);
|
|
|
|
const btOptimizedBvhNode* rootNode = &m_contiguousNodes[0];
|
|
int escapeIndex, curIndex = 0;
|
|
int walkIterations = 0;
|
|
bool isLeafNode;
|
|
//PCK: unsigned instead of bool
|
|
unsigned aabbOverlap;
|
|
|
|
while (curIndex < m_curNodeIndex)
|
|
{
|
|
//catch bugs in tree data
|
|
btAssert(walkIterations < m_curNodeIndex);
|
|
|
|
walkIterations++;
|
|
aabbOverlap = TestAabbAgainstAabb2(aabbMin, aabbMax, rootNode->m_aabbMinOrg, rootNode->m_aabbMaxOrg);
|
|
isLeafNode = rootNode->m_escapeIndex == -1;
|
|
|
|
//PCK: unsigned instead of bool
|
|
if (isLeafNode && (aabbOverlap != 0))
|
|
{
|
|
nodeCallback->processNode(rootNode->m_subPart, rootNode->m_triangleIndex);
|
|
}
|
|
|
|
//PCK: unsigned instead of bool
|
|
if ((aabbOverlap != 0) || isLeafNode)
|
|
{
|
|
rootNode++;
|
|
curIndex++;
|
|
}
|
|
else
|
|
{
|
|
escapeIndex = rootNode->m_escapeIndex;
|
|
rootNode += escapeIndex;
|
|
curIndex += escapeIndex;
|
|
}
|
|
}
|
|
if (maxIterations < walkIterations)
|
|
maxIterations = walkIterations;
|
|
}
|
|
|
|
/*
|
|
///this was the original recursive traversal, before we optimized towards stackless traversal
|
|
void btQuantizedBvh::walkTree(btOptimizedBvhNode* rootNode,btNodeOverlapCallback* nodeCallback,const btVector3& aabbMin,const btVector3& aabbMax) const
|
|
{
|
|
bool isLeafNode, aabbOverlap = TestAabbAgainstAabb2(aabbMin,aabbMax,rootNode->m_aabbMin,rootNode->m_aabbMax);
|
|
if (aabbOverlap)
|
|
{
|
|
isLeafNode = (!rootNode->m_leftChild && !rootNode->m_rightChild);
|
|
if (isLeafNode)
|
|
{
|
|
nodeCallback->processNode(rootNode);
|
|
} else
|
|
{
|
|
walkTree(rootNode->m_leftChild,nodeCallback,aabbMin,aabbMax);
|
|
walkTree(rootNode->m_rightChild,nodeCallback,aabbMin,aabbMax);
|
|
}
|
|
}
|
|
|
|
}
|
|
*/
|
|
|
|
void btQuantizedBvh::walkRecursiveQuantizedTreeAgainstQueryAabb(const btQuantizedBvhNode* currentNode, btNodeOverlapCallback* nodeCallback, unsigned short int* quantizedQueryAabbMin, unsigned short int* quantizedQueryAabbMax) const
|
|
{
|
|
btAssert(m_useQuantization);
|
|
|
|
bool isLeafNode;
|
|
//PCK: unsigned instead of bool
|
|
unsigned aabbOverlap;
|
|
|
|
//PCK: unsigned instead of bool
|
|
aabbOverlap = testQuantizedAabbAgainstQuantizedAabb(quantizedQueryAabbMin, quantizedQueryAabbMax, currentNode->m_quantizedAabbMin, currentNode->m_quantizedAabbMax);
|
|
isLeafNode = currentNode->isLeafNode();
|
|
|
|
//PCK: unsigned instead of bool
|
|
if (aabbOverlap != 0)
|
|
{
|
|
if (isLeafNode)
|
|
{
|
|
nodeCallback->processNode(currentNode->getPartId(), currentNode->getTriangleIndex());
|
|
}
|
|
else
|
|
{
|
|
//process left and right children
|
|
const btQuantizedBvhNode* leftChildNode = currentNode + 1;
|
|
walkRecursiveQuantizedTreeAgainstQueryAabb(leftChildNode, nodeCallback, quantizedQueryAabbMin, quantizedQueryAabbMax);
|
|
|
|
const btQuantizedBvhNode* rightChildNode = leftChildNode->isLeafNode() ? leftChildNode + 1 : leftChildNode + leftChildNode->getEscapeIndex();
|
|
walkRecursiveQuantizedTreeAgainstQueryAabb(rightChildNode, nodeCallback, quantizedQueryAabbMin, quantizedQueryAabbMax);
|
|
}
|
|
}
|
|
}
|
|
|
|
void btQuantizedBvh::walkStacklessTreeAgainstRay(btNodeOverlapCallback* nodeCallback, const btVector3& raySource, const btVector3& rayTarget, const btVector3& aabbMin, const btVector3& aabbMax, int startNodeIndex, int endNodeIndex) const
|
|
{
|
|
btAssert(!m_useQuantization);
|
|
|
|
const btOptimizedBvhNode* rootNode = &m_contiguousNodes[0];
|
|
int escapeIndex, curIndex = 0;
|
|
int walkIterations = 0;
|
|
bool isLeafNode;
|
|
//PCK: unsigned instead of bool
|
|
unsigned aabbOverlap = 0;
|
|
unsigned rayBoxOverlap = 0;
|
|
btScalar lambda_max = 1.0;
|
|
|
|
/* Quick pruning by quantized box */
|
|
btVector3 rayAabbMin = raySource;
|
|
btVector3 rayAabbMax = raySource;
|
|
rayAabbMin.setMin(rayTarget);
|
|
rayAabbMax.setMax(rayTarget);
|
|
|
|
/* Add box cast extents to bounding box */
|
|
rayAabbMin += aabbMin;
|
|
rayAabbMax += aabbMax;
|
|
|
|
#ifdef RAYAABB2
|
|
btVector3 rayDir = (rayTarget - raySource);
|
|
rayDir.normalize();
|
|
lambda_max = rayDir.dot(rayTarget - raySource);
|
|
///what about division by zero? --> just set rayDirection[i] to 1.0
|
|
btVector3 rayDirectionInverse;
|
|
rayDirectionInverse[0] = rayDir[0] == btScalar(0.0) ? btScalar(BT_LARGE_FLOAT) : btScalar(1.0) / rayDir[0];
|
|
rayDirectionInverse[1] = rayDir[1] == btScalar(0.0) ? btScalar(BT_LARGE_FLOAT) : btScalar(1.0) / rayDir[1];
|
|
rayDirectionInverse[2] = rayDir[2] == btScalar(0.0) ? btScalar(BT_LARGE_FLOAT) : btScalar(1.0) / rayDir[2];
|
|
unsigned int sign[3] = {rayDirectionInverse[0] < 0.0, rayDirectionInverse[1] < 0.0, rayDirectionInverse[2] < 0.0};
|
|
#endif
|
|
|
|
btVector3 bounds[2];
|
|
|
|
while (curIndex < m_curNodeIndex)
|
|
{
|
|
btScalar param = 1.0;
|
|
//catch bugs in tree data
|
|
btAssert(walkIterations < m_curNodeIndex);
|
|
|
|
walkIterations++;
|
|
|
|
bounds[0] = rootNode->m_aabbMinOrg;
|
|
bounds[1] = rootNode->m_aabbMaxOrg;
|
|
/* Add box cast extents */
|
|
bounds[0] -= aabbMax;
|
|
bounds[1] -= aabbMin;
|
|
|
|
aabbOverlap = TestAabbAgainstAabb2(rayAabbMin, rayAabbMax, rootNode->m_aabbMinOrg, rootNode->m_aabbMaxOrg);
|
|
//perhaps profile if it is worth doing the aabbOverlap test first
|
|
|
|
#ifdef RAYAABB2
|
|
///careful with this check: need to check division by zero (above) and fix the unQuantize method
|
|
///thanks Joerg/hiker for the reproduction case!
|
|
///http://www.bulletphysics.com/Bullet/phpBB3/viewtopic.php?f=9&t=1858
|
|
rayBoxOverlap = aabbOverlap ? btRayAabb2(raySource, rayDirectionInverse, sign, bounds, param, 0.0f, lambda_max) : false;
|
|
|
|
#else
|
|
btVector3 normal;
|
|
rayBoxOverlap = btRayAabb(raySource, rayTarget, bounds[0], bounds[1], param, normal);
|
|
#endif
|
|
|
|
isLeafNode = rootNode->m_escapeIndex == -1;
|
|
|
|
//PCK: unsigned instead of bool
|
|
if (isLeafNode && (rayBoxOverlap != 0))
|
|
{
|
|
nodeCallback->processNode(rootNode->m_subPart, rootNode->m_triangleIndex);
|
|
}
|
|
|
|
//PCK: unsigned instead of bool
|
|
if ((rayBoxOverlap != 0) || isLeafNode)
|
|
{
|
|
rootNode++;
|
|
curIndex++;
|
|
}
|
|
else
|
|
{
|
|
escapeIndex = rootNode->m_escapeIndex;
|
|
rootNode += escapeIndex;
|
|
curIndex += escapeIndex;
|
|
}
|
|
}
|
|
if (maxIterations < walkIterations)
|
|
maxIterations = walkIterations;
|
|
}
|
|
|
|
void btQuantizedBvh::walkStacklessQuantizedTreeAgainstRay(btNodeOverlapCallback* nodeCallback, const btVector3& raySource, const btVector3& rayTarget, const btVector3& aabbMin, const btVector3& aabbMax, int startNodeIndex, int endNodeIndex) const
|
|
{
|
|
btAssert(m_useQuantization);
|
|
|
|
int curIndex = startNodeIndex;
|
|
int walkIterations = 0;
|
|
int subTreeSize = endNodeIndex - startNodeIndex;
|
|
(void)subTreeSize;
|
|
|
|
const btQuantizedBvhNode* rootNode = &m_quantizedContiguousNodes[startNodeIndex];
|
|
int escapeIndex;
|
|
|
|
bool isLeafNode;
|
|
//PCK: unsigned instead of bool
|
|
unsigned boxBoxOverlap = 0;
|
|
unsigned rayBoxOverlap = 0;
|
|
|
|
btScalar lambda_max = 1.0;
|
|
|
|
#ifdef RAYAABB2
|
|
btVector3 rayDirection = (rayTarget - raySource);
|
|
rayDirection.normalize();
|
|
lambda_max = rayDirection.dot(rayTarget - raySource);
|
|
///what about division by zero? --> just set rayDirection[i] to 1.0
|
|
rayDirection[0] = rayDirection[0] == btScalar(0.0) ? btScalar(BT_LARGE_FLOAT) : btScalar(1.0) / rayDirection[0];
|
|
rayDirection[1] = rayDirection[1] == btScalar(0.0) ? btScalar(BT_LARGE_FLOAT) : btScalar(1.0) / rayDirection[1];
|
|
rayDirection[2] = rayDirection[2] == btScalar(0.0) ? btScalar(BT_LARGE_FLOAT) : btScalar(1.0) / rayDirection[2];
|
|
unsigned int sign[3] = {rayDirection[0] < 0.0, rayDirection[1] < 0.0, rayDirection[2] < 0.0};
|
|
#endif
|
|
|
|
/* Quick pruning by quantized box */
|
|
btVector3 rayAabbMin = raySource;
|
|
btVector3 rayAabbMax = raySource;
|
|
rayAabbMin.setMin(rayTarget);
|
|
rayAabbMax.setMax(rayTarget);
|
|
|
|
/* Add box cast extents to bounding box */
|
|
rayAabbMin += aabbMin;
|
|
rayAabbMax += aabbMax;
|
|
|
|
unsigned short int quantizedQueryAabbMin[3];
|
|
unsigned short int quantizedQueryAabbMax[3];
|
|
quantizeWithClamp(quantizedQueryAabbMin, rayAabbMin, 0);
|
|
quantizeWithClamp(quantizedQueryAabbMax, rayAabbMax, 1);
|
|
|
|
while (curIndex < endNodeIndex)
|
|
{
|
|
//#define VISUALLY_ANALYZE_BVH 1
|
|
#ifdef VISUALLY_ANALYZE_BVH
|
|
//some code snippet to debugDraw aabb, to visually analyze bvh structure
|
|
static int drawPatch = 0;
|
|
//need some global access to a debugDrawer
|
|
extern btIDebugDraw* debugDrawerPtr;
|
|
if (curIndex == drawPatch)
|
|
{
|
|
btVector3 aabbMin, aabbMax;
|
|
aabbMin = unQuantize(rootNode->m_quantizedAabbMin);
|
|
aabbMax = unQuantize(rootNode->m_quantizedAabbMax);
|
|
btVector3 color(1, 0, 0);
|
|
debugDrawerPtr->drawAabb(aabbMin, aabbMax, color);
|
|
}
|
|
#endif //VISUALLY_ANALYZE_BVH
|
|
|
|
//catch bugs in tree data
|
|
btAssert(walkIterations < subTreeSize);
|
|
|
|
walkIterations++;
|
|
//PCK: unsigned instead of bool
|
|
// only interested if this is closer than any previous hit
|
|
btScalar param = 1.0;
|
|
rayBoxOverlap = 0;
|
|
boxBoxOverlap = testQuantizedAabbAgainstQuantizedAabb(quantizedQueryAabbMin, quantizedQueryAabbMax, rootNode->m_quantizedAabbMin, rootNode->m_quantizedAabbMax);
|
|
isLeafNode = rootNode->isLeafNode();
|
|
if (boxBoxOverlap)
|
|
{
|
|
btVector3 bounds[2];
|
|
bounds[0] = unQuantize(rootNode->m_quantizedAabbMin);
|
|
bounds[1] = unQuantize(rootNode->m_quantizedAabbMax);
|
|
/* Add box cast extents */
|
|
bounds[0] -= aabbMax;
|
|
bounds[1] -= aabbMin;
|
|
btVector3 normal;
|
|
#if 0
|
|
bool ra2 = btRayAabb2 (raySource, rayDirection, sign, bounds, param, 0.0, lambda_max);
|
|
bool ra = btRayAabb (raySource, rayTarget, bounds[0], bounds[1], param, normal);
|
|
if (ra2 != ra)
|
|
{
|
|
printf("functions don't match\n");
|
|
}
|
|
#endif
|
|
#ifdef RAYAABB2
|
|
///careful with this check: need to check division by zero (above) and fix the unQuantize method
|
|
///thanks Joerg/hiker for the reproduction case!
|
|
///http://www.bulletphysics.com/Bullet/phpBB3/viewtopic.php?f=9&t=1858
|
|
|
|
//BT_PROFILE("btRayAabb2");
|
|
rayBoxOverlap = btRayAabb2(raySource, rayDirection, sign, bounds, param, 0.0f, lambda_max);
|
|
|
|
#else
|
|
rayBoxOverlap = true; //btRayAabb(raySource, rayTarget, bounds[0], bounds[1], param, normal);
|
|
#endif
|
|
}
|
|
|
|
if (isLeafNode && rayBoxOverlap)
|
|
{
|
|
nodeCallback->processNode(rootNode->getPartId(), rootNode->getTriangleIndex());
|
|
}
|
|
|
|
//PCK: unsigned instead of bool
|
|
if ((rayBoxOverlap != 0) || isLeafNode)
|
|
{
|
|
rootNode++;
|
|
curIndex++;
|
|
}
|
|
else
|
|
{
|
|
escapeIndex = rootNode->getEscapeIndex();
|
|
rootNode += escapeIndex;
|
|
curIndex += escapeIndex;
|
|
}
|
|
}
|
|
if (maxIterations < walkIterations)
|
|
maxIterations = walkIterations;
|
|
}
|
|
|
|
void btQuantizedBvh::walkStacklessQuantizedTree(btNodeOverlapCallback* nodeCallback, unsigned short int* quantizedQueryAabbMin, unsigned short int* quantizedQueryAabbMax, int startNodeIndex, int endNodeIndex) const
|
|
{
|
|
btAssert(m_useQuantization);
|
|
|
|
int curIndex = startNodeIndex;
|
|
int walkIterations = 0;
|
|
int subTreeSize = endNodeIndex - startNodeIndex;
|
|
(void)subTreeSize;
|
|
|
|
const btQuantizedBvhNode* rootNode = &m_quantizedContiguousNodes[startNodeIndex];
|
|
int escapeIndex;
|
|
|
|
bool isLeafNode;
|
|
//PCK: unsigned instead of bool
|
|
unsigned aabbOverlap;
|
|
|
|
while (curIndex < endNodeIndex)
|
|
{
|
|
//#define VISUALLY_ANALYZE_BVH 1
|
|
#ifdef VISUALLY_ANALYZE_BVH
|
|
//some code snippet to debugDraw aabb, to visually analyze bvh structure
|
|
static int drawPatch = 0;
|
|
//need some global access to a debugDrawer
|
|
extern btIDebugDraw* debugDrawerPtr;
|
|
if (curIndex == drawPatch)
|
|
{
|
|
btVector3 aabbMin, aabbMax;
|
|
aabbMin = unQuantize(rootNode->m_quantizedAabbMin);
|
|
aabbMax = unQuantize(rootNode->m_quantizedAabbMax);
|
|
btVector3 color(1, 0, 0);
|
|
debugDrawerPtr->drawAabb(aabbMin, aabbMax, color);
|
|
}
|
|
#endif //VISUALLY_ANALYZE_BVH
|
|
|
|
//catch bugs in tree data
|
|
btAssert(walkIterations < subTreeSize);
|
|
|
|
walkIterations++;
|
|
//PCK: unsigned instead of bool
|
|
aabbOverlap = testQuantizedAabbAgainstQuantizedAabb(quantizedQueryAabbMin, quantizedQueryAabbMax, rootNode->m_quantizedAabbMin, rootNode->m_quantizedAabbMax);
|
|
isLeafNode = rootNode->isLeafNode();
|
|
|
|
if (isLeafNode && aabbOverlap)
|
|
{
|
|
nodeCallback->processNode(rootNode->getPartId(), rootNode->getTriangleIndex());
|
|
}
|
|
|
|
//PCK: unsigned instead of bool
|
|
if ((aabbOverlap != 0) || isLeafNode)
|
|
{
|
|
rootNode++;
|
|
curIndex++;
|
|
}
|
|
else
|
|
{
|
|
escapeIndex = rootNode->getEscapeIndex();
|
|
rootNode += escapeIndex;
|
|
curIndex += escapeIndex;
|
|
}
|
|
}
|
|
if (maxIterations < walkIterations)
|
|
maxIterations = walkIterations;
|
|
}
|
|
|
|
//This traversal can be called from Playstation 3 SPU
|
|
void btQuantizedBvh::walkStacklessQuantizedTreeCacheFriendly(btNodeOverlapCallback* nodeCallback, unsigned short int* quantizedQueryAabbMin, unsigned short int* quantizedQueryAabbMax) const
|
|
{
|
|
btAssert(m_useQuantization);
|
|
|
|
int i;
|
|
|
|
for (i = 0; i < this->m_SubtreeHeaders.size(); i++)
|
|
{
|
|
const btBvhSubtreeInfo& subtree = m_SubtreeHeaders[i];
|
|
|
|
//PCK: unsigned instead of bool
|
|
unsigned overlap = testQuantizedAabbAgainstQuantizedAabb(quantizedQueryAabbMin, quantizedQueryAabbMax, subtree.m_quantizedAabbMin, subtree.m_quantizedAabbMax);
|
|
if (overlap != 0)
|
|
{
|
|
walkStacklessQuantizedTree(nodeCallback, quantizedQueryAabbMin, quantizedQueryAabbMax,
|
|
subtree.m_rootNodeIndex,
|
|
subtree.m_rootNodeIndex + subtree.m_subtreeSize);
|
|
}
|
|
}
|
|
}
|
|
|
|
void btQuantizedBvh::reportRayOverlappingNodex(btNodeOverlapCallback* nodeCallback, const btVector3& raySource, const btVector3& rayTarget) const
|
|
{
|
|
reportBoxCastOverlappingNodex(nodeCallback, raySource, rayTarget, btVector3(0, 0, 0), btVector3(0, 0, 0));
|
|
}
|
|
|
|
void btQuantizedBvh::reportBoxCastOverlappingNodex(btNodeOverlapCallback* nodeCallback, const btVector3& raySource, const btVector3& rayTarget, const btVector3& aabbMin, const btVector3& aabbMax) const
|
|
{
|
|
//always use stackless
|
|
|
|
if (m_useQuantization)
|
|
{
|
|
walkStacklessQuantizedTreeAgainstRay(nodeCallback, raySource, rayTarget, aabbMin, aabbMax, 0, m_curNodeIndex);
|
|
}
|
|
else
|
|
{
|
|
walkStacklessTreeAgainstRay(nodeCallback, raySource, rayTarget, aabbMin, aabbMax, 0, m_curNodeIndex);
|
|
}
|
|
/*
|
|
{
|
|
//recursive traversal
|
|
btVector3 qaabbMin = raySource;
|
|
btVector3 qaabbMax = raySource;
|
|
qaabbMin.setMin(rayTarget);
|
|
qaabbMax.setMax(rayTarget);
|
|
qaabbMin += aabbMin;
|
|
qaabbMax += aabbMax;
|
|
reportAabbOverlappingNodex(nodeCallback,qaabbMin,qaabbMax);
|
|
}
|
|
*/
|
|
}
|
|
|
|
void btQuantizedBvh::swapLeafNodes(int i, int splitIndex)
|
|
{
|
|
if (m_useQuantization)
|
|
{
|
|
btQuantizedBvhNode tmp = m_quantizedLeafNodes[i];
|
|
m_quantizedLeafNodes[i] = m_quantizedLeafNodes[splitIndex];
|
|
m_quantizedLeafNodes[splitIndex] = tmp;
|
|
}
|
|
else
|
|
{
|
|
btOptimizedBvhNode tmp = m_leafNodes[i];
|
|
m_leafNodes[i] = m_leafNodes[splitIndex];
|
|
m_leafNodes[splitIndex] = tmp;
|
|
}
|
|
}
|
|
|
|
void btQuantizedBvh::assignInternalNodeFromLeafNode(int internalNode, int leafNodeIndex)
|
|
{
|
|
if (m_useQuantization)
|
|
{
|
|
m_quantizedContiguousNodes[internalNode] = m_quantizedLeafNodes[leafNodeIndex];
|
|
}
|
|
else
|
|
{
|
|
m_contiguousNodes[internalNode] = m_leafNodes[leafNodeIndex];
|
|
}
|
|
}
|
|
|
|
//PCK: include
|
|
#include <new>
|
|
|
|
#if 0
|
|
//PCK: consts
|
|
static const unsigned BVH_ALIGNMENT = 16;
|
|
static const unsigned BVH_ALIGNMENT_MASK = BVH_ALIGNMENT-1;
|
|
|
|
static const unsigned BVH_ALIGNMENT_BLOCKS = 2;
|
|
#endif
|
|
|
|
unsigned int btQuantizedBvh::getAlignmentSerializationPadding()
|
|
{
|
|
// I changed this to 0 since the extra padding is not needed or used.
|
|
return 0; //BVH_ALIGNMENT_BLOCKS * BVH_ALIGNMENT;
|
|
}
|
|
|
|
unsigned btQuantizedBvh::calculateSerializeBufferSize() const
|
|
{
|
|
unsigned baseSize = sizeof(btQuantizedBvh) + getAlignmentSerializationPadding();
|
|
baseSize += sizeof(btBvhSubtreeInfo) * m_subtreeHeaderCount;
|
|
if (m_useQuantization)
|
|
{
|
|
return baseSize + m_curNodeIndex * sizeof(btQuantizedBvhNode);
|
|
}
|
|
return baseSize + m_curNodeIndex * sizeof(btOptimizedBvhNode);
|
|
}
|
|
|
|
bool btQuantizedBvh::serialize(void* o_alignedDataBuffer, unsigned /*i_dataBufferSize */, bool i_swapEndian) const
|
|
{
|
|
btAssert(m_subtreeHeaderCount == m_SubtreeHeaders.size());
|
|
m_subtreeHeaderCount = m_SubtreeHeaders.size();
|
|
|
|
/* if (i_dataBufferSize < calculateSerializeBufferSize() || o_alignedDataBuffer == NULL || (((unsigned)o_alignedDataBuffer & BVH_ALIGNMENT_MASK) != 0))
|
|
{
|
|
///check alignedment for buffer?
|
|
btAssert(0);
|
|
return false;
|
|
}
|
|
*/
|
|
|
|
btQuantizedBvh* targetBvh = (btQuantizedBvh*)o_alignedDataBuffer;
|
|
|
|
// construct the class so the virtual function table, etc will be set up
|
|
// Also, m_leafNodes and m_quantizedLeafNodes will be initialized to default values by the constructor
|
|
new (targetBvh) btQuantizedBvh;
|
|
|
|
if (i_swapEndian)
|
|
{
|
|
targetBvh->m_curNodeIndex = static_cast<int>(btSwapEndian(m_curNodeIndex));
|
|
|
|
btSwapVector3Endian(m_bvhAabbMin, targetBvh->m_bvhAabbMin);
|
|
btSwapVector3Endian(m_bvhAabbMax, targetBvh->m_bvhAabbMax);
|
|
btSwapVector3Endian(m_bvhQuantization, targetBvh->m_bvhQuantization);
|
|
|
|
targetBvh->m_traversalMode = (btTraversalMode)btSwapEndian(m_traversalMode);
|
|
targetBvh->m_subtreeHeaderCount = static_cast<int>(btSwapEndian(m_subtreeHeaderCount));
|
|
}
|
|
else
|
|
{
|
|
targetBvh->m_curNodeIndex = m_curNodeIndex;
|
|
targetBvh->m_bvhAabbMin = m_bvhAabbMin;
|
|
targetBvh->m_bvhAabbMax = m_bvhAabbMax;
|
|
targetBvh->m_bvhQuantization = m_bvhQuantization;
|
|
targetBvh->m_traversalMode = m_traversalMode;
|
|
targetBvh->m_subtreeHeaderCount = m_subtreeHeaderCount;
|
|
}
|
|
|
|
targetBvh->m_useQuantization = m_useQuantization;
|
|
|
|
unsigned char* nodeData = (unsigned char*)targetBvh;
|
|
nodeData += sizeof(btQuantizedBvh);
|
|
|
|
unsigned sizeToAdd = 0; //(BVH_ALIGNMENT-((unsigned)nodeData & BVH_ALIGNMENT_MASK))&BVH_ALIGNMENT_MASK;
|
|
nodeData += sizeToAdd;
|
|
|
|
int nodeCount = m_curNodeIndex;
|
|
|
|
if (m_useQuantization)
|
|
{
|
|
targetBvh->m_quantizedContiguousNodes.initializeFromBuffer(nodeData, nodeCount, nodeCount);
|
|
|
|
if (i_swapEndian)
|
|
{
|
|
for (int nodeIndex = 0; nodeIndex < nodeCount; nodeIndex++)
|
|
{
|
|
targetBvh->m_quantizedContiguousNodes[nodeIndex].m_quantizedAabbMin[0] = btSwapEndian(m_quantizedContiguousNodes[nodeIndex].m_quantizedAabbMin[0]);
|
|
targetBvh->m_quantizedContiguousNodes[nodeIndex].m_quantizedAabbMin[1] = btSwapEndian(m_quantizedContiguousNodes[nodeIndex].m_quantizedAabbMin[1]);
|
|
targetBvh->m_quantizedContiguousNodes[nodeIndex].m_quantizedAabbMin[2] = btSwapEndian(m_quantizedContiguousNodes[nodeIndex].m_quantizedAabbMin[2]);
|
|
|
|
targetBvh->m_quantizedContiguousNodes[nodeIndex].m_quantizedAabbMax[0] = btSwapEndian(m_quantizedContiguousNodes[nodeIndex].m_quantizedAabbMax[0]);
|
|
targetBvh->m_quantizedContiguousNodes[nodeIndex].m_quantizedAabbMax[1] = btSwapEndian(m_quantizedContiguousNodes[nodeIndex].m_quantizedAabbMax[1]);
|
|
targetBvh->m_quantizedContiguousNodes[nodeIndex].m_quantizedAabbMax[2] = btSwapEndian(m_quantizedContiguousNodes[nodeIndex].m_quantizedAabbMax[2]);
|
|
|
|
targetBvh->m_quantizedContiguousNodes[nodeIndex].m_escapeIndexOrTriangleIndex = static_cast<int>(btSwapEndian(m_quantizedContiguousNodes[nodeIndex].m_escapeIndexOrTriangleIndex));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (int nodeIndex = 0; nodeIndex < nodeCount; nodeIndex++)
|
|
{
|
|
targetBvh->m_quantizedContiguousNodes[nodeIndex].m_quantizedAabbMin[0] = m_quantizedContiguousNodes[nodeIndex].m_quantizedAabbMin[0];
|
|
targetBvh->m_quantizedContiguousNodes[nodeIndex].m_quantizedAabbMin[1] = m_quantizedContiguousNodes[nodeIndex].m_quantizedAabbMin[1];
|
|
targetBvh->m_quantizedContiguousNodes[nodeIndex].m_quantizedAabbMin[2] = m_quantizedContiguousNodes[nodeIndex].m_quantizedAabbMin[2];
|
|
|
|
targetBvh->m_quantizedContiguousNodes[nodeIndex].m_quantizedAabbMax[0] = m_quantizedContiguousNodes[nodeIndex].m_quantizedAabbMax[0];
|
|
targetBvh->m_quantizedContiguousNodes[nodeIndex].m_quantizedAabbMax[1] = m_quantizedContiguousNodes[nodeIndex].m_quantizedAabbMax[1];
|
|
targetBvh->m_quantizedContiguousNodes[nodeIndex].m_quantizedAabbMax[2] = m_quantizedContiguousNodes[nodeIndex].m_quantizedAabbMax[2];
|
|
|
|
targetBvh->m_quantizedContiguousNodes[nodeIndex].m_escapeIndexOrTriangleIndex = m_quantizedContiguousNodes[nodeIndex].m_escapeIndexOrTriangleIndex;
|
|
}
|
|
}
|
|
nodeData += sizeof(btQuantizedBvhNode) * nodeCount;
|
|
|
|
// this clears the pointer in the member variable it doesn't really do anything to the data
|
|
// it does call the destructor on the contained objects, but they are all classes with no destructor defined
|
|
// so the memory (which is not freed) is left alone
|
|
targetBvh->m_quantizedContiguousNodes.initializeFromBuffer(NULL, 0, 0);
|
|
}
|
|
else
|
|
{
|
|
targetBvh->m_contiguousNodes.initializeFromBuffer(nodeData, nodeCount, nodeCount);
|
|
|
|
if (i_swapEndian)
|
|
{
|
|
for (int nodeIndex = 0; nodeIndex < nodeCount; nodeIndex++)
|
|
{
|
|
btSwapVector3Endian(m_contiguousNodes[nodeIndex].m_aabbMinOrg, targetBvh->m_contiguousNodes[nodeIndex].m_aabbMinOrg);
|
|
btSwapVector3Endian(m_contiguousNodes[nodeIndex].m_aabbMaxOrg, targetBvh->m_contiguousNodes[nodeIndex].m_aabbMaxOrg);
|
|
|
|
targetBvh->m_contiguousNodes[nodeIndex].m_escapeIndex = static_cast<int>(btSwapEndian(m_contiguousNodes[nodeIndex].m_escapeIndex));
|
|
targetBvh->m_contiguousNodes[nodeIndex].m_subPart = static_cast<int>(btSwapEndian(m_contiguousNodes[nodeIndex].m_subPart));
|
|
targetBvh->m_contiguousNodes[nodeIndex].m_triangleIndex = static_cast<int>(btSwapEndian(m_contiguousNodes[nodeIndex].m_triangleIndex));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (int nodeIndex = 0; nodeIndex < nodeCount; nodeIndex++)
|
|
{
|
|
targetBvh->m_contiguousNodes[nodeIndex].m_aabbMinOrg = m_contiguousNodes[nodeIndex].m_aabbMinOrg;
|
|
targetBvh->m_contiguousNodes[nodeIndex].m_aabbMaxOrg = m_contiguousNodes[nodeIndex].m_aabbMaxOrg;
|
|
|
|
targetBvh->m_contiguousNodes[nodeIndex].m_escapeIndex = m_contiguousNodes[nodeIndex].m_escapeIndex;
|
|
targetBvh->m_contiguousNodes[nodeIndex].m_subPart = m_contiguousNodes[nodeIndex].m_subPart;
|
|
targetBvh->m_contiguousNodes[nodeIndex].m_triangleIndex = m_contiguousNodes[nodeIndex].m_triangleIndex;
|
|
}
|
|
}
|
|
nodeData += sizeof(btOptimizedBvhNode) * nodeCount;
|
|
|
|
// this clears the pointer in the member variable it doesn't really do anything to the data
|
|
// it does call the destructor on the contained objects, but they are all classes with no destructor defined
|
|
// so the memory (which is not freed) is left alone
|
|
targetBvh->m_contiguousNodes.initializeFromBuffer(NULL, 0, 0);
|
|
}
|
|
|
|
sizeToAdd = 0; //(BVH_ALIGNMENT-((unsigned)nodeData & BVH_ALIGNMENT_MASK))&BVH_ALIGNMENT_MASK;
|
|
nodeData += sizeToAdd;
|
|
|
|
// Now serialize the subtree headers
|
|
targetBvh->m_SubtreeHeaders.initializeFromBuffer(nodeData, m_subtreeHeaderCount, m_subtreeHeaderCount);
|
|
if (i_swapEndian)
|
|
{
|
|
for (int i = 0; i < m_subtreeHeaderCount; i++)
|
|
{
|
|
targetBvh->m_SubtreeHeaders[i].m_quantizedAabbMin[0] = btSwapEndian(m_SubtreeHeaders[i].m_quantizedAabbMin[0]);
|
|
targetBvh->m_SubtreeHeaders[i].m_quantizedAabbMin[1] = btSwapEndian(m_SubtreeHeaders[i].m_quantizedAabbMin[1]);
|
|
targetBvh->m_SubtreeHeaders[i].m_quantizedAabbMin[2] = btSwapEndian(m_SubtreeHeaders[i].m_quantizedAabbMin[2]);
|
|
|
|
targetBvh->m_SubtreeHeaders[i].m_quantizedAabbMax[0] = btSwapEndian(m_SubtreeHeaders[i].m_quantizedAabbMax[0]);
|
|
targetBvh->m_SubtreeHeaders[i].m_quantizedAabbMax[1] = btSwapEndian(m_SubtreeHeaders[i].m_quantizedAabbMax[1]);
|
|
targetBvh->m_SubtreeHeaders[i].m_quantizedAabbMax[2] = btSwapEndian(m_SubtreeHeaders[i].m_quantizedAabbMax[2]);
|
|
|
|
targetBvh->m_SubtreeHeaders[i].m_rootNodeIndex = static_cast<int>(btSwapEndian(m_SubtreeHeaders[i].m_rootNodeIndex));
|
|
targetBvh->m_SubtreeHeaders[i].m_subtreeSize = static_cast<int>(btSwapEndian(m_SubtreeHeaders[i].m_subtreeSize));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (int i = 0; i < m_subtreeHeaderCount; i++)
|
|
{
|
|
targetBvh->m_SubtreeHeaders[i].m_quantizedAabbMin[0] = (m_SubtreeHeaders[i].m_quantizedAabbMin[0]);
|
|
targetBvh->m_SubtreeHeaders[i].m_quantizedAabbMin[1] = (m_SubtreeHeaders[i].m_quantizedAabbMin[1]);
|
|
targetBvh->m_SubtreeHeaders[i].m_quantizedAabbMin[2] = (m_SubtreeHeaders[i].m_quantizedAabbMin[2]);
|
|
|
|
targetBvh->m_SubtreeHeaders[i].m_quantizedAabbMax[0] = (m_SubtreeHeaders[i].m_quantizedAabbMax[0]);
|
|
targetBvh->m_SubtreeHeaders[i].m_quantizedAabbMax[1] = (m_SubtreeHeaders[i].m_quantizedAabbMax[1]);
|
|
targetBvh->m_SubtreeHeaders[i].m_quantizedAabbMax[2] = (m_SubtreeHeaders[i].m_quantizedAabbMax[2]);
|
|
|
|
targetBvh->m_SubtreeHeaders[i].m_rootNodeIndex = (m_SubtreeHeaders[i].m_rootNodeIndex);
|
|
targetBvh->m_SubtreeHeaders[i].m_subtreeSize = (m_SubtreeHeaders[i].m_subtreeSize);
|
|
|
|
// need to clear padding in destination buffer
|
|
targetBvh->m_SubtreeHeaders[i].m_padding[0] = 0;
|
|
targetBvh->m_SubtreeHeaders[i].m_padding[1] = 0;
|
|
targetBvh->m_SubtreeHeaders[i].m_padding[2] = 0;
|
|
}
|
|
}
|
|
nodeData += sizeof(btBvhSubtreeInfo) * m_subtreeHeaderCount;
|
|
|
|
// this clears the pointer in the member variable it doesn't really do anything to the data
|
|
// it does call the destructor on the contained objects, but they are all classes with no destructor defined
|
|
// so the memory (which is not freed) is left alone
|
|
targetBvh->m_SubtreeHeaders.initializeFromBuffer(NULL, 0, 0);
|
|
|
|
// this wipes the virtual function table pointer at the start of the buffer for the class
|
|
*((void**)o_alignedDataBuffer) = NULL;
|
|
|
|
return true;
|
|
}
|
|
|
|
btQuantizedBvh* btQuantizedBvh::deSerializeInPlace(void* i_alignedDataBuffer, unsigned int i_dataBufferSize, bool i_swapEndian)
|
|
{
|
|
if (i_alignedDataBuffer == NULL) // || (((unsigned)i_alignedDataBuffer & BVH_ALIGNMENT_MASK) != 0))
|
|
{
|
|
return NULL;
|
|
}
|
|
btQuantizedBvh* bvh = (btQuantizedBvh*)i_alignedDataBuffer;
|
|
|
|
if (i_swapEndian)
|
|
{
|
|
bvh->m_curNodeIndex = static_cast<int>(btSwapEndian(bvh->m_curNodeIndex));
|
|
|
|
btUnSwapVector3Endian(bvh->m_bvhAabbMin);
|
|
btUnSwapVector3Endian(bvh->m_bvhAabbMax);
|
|
btUnSwapVector3Endian(bvh->m_bvhQuantization);
|
|
|
|
bvh->m_traversalMode = (btTraversalMode)btSwapEndian(bvh->m_traversalMode);
|
|
bvh->m_subtreeHeaderCount = static_cast<int>(btSwapEndian(bvh->m_subtreeHeaderCount));
|
|
}
|
|
|
|
unsigned int calculatedBufSize = bvh->calculateSerializeBufferSize();
|
|
btAssert(calculatedBufSize <= i_dataBufferSize);
|
|
|
|
if (calculatedBufSize > i_dataBufferSize)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
unsigned char* nodeData = (unsigned char*)bvh;
|
|
nodeData += sizeof(btQuantizedBvh);
|
|
|
|
unsigned sizeToAdd = 0; //(BVH_ALIGNMENT-((unsigned)nodeData & BVH_ALIGNMENT_MASK))&BVH_ALIGNMENT_MASK;
|
|
nodeData += sizeToAdd;
|
|
|
|
int nodeCount = bvh->m_curNodeIndex;
|
|
|
|
// Must call placement new to fill in virtual function table, etc, but we don't want to overwrite most data, so call a special version of the constructor
|
|
// Also, m_leafNodes and m_quantizedLeafNodes will be initialized to default values by the constructor
|
|
new (bvh) btQuantizedBvh(*bvh, false);
|
|
|
|
if (bvh->m_useQuantization)
|
|
{
|
|
bvh->m_quantizedContiguousNodes.initializeFromBuffer(nodeData, nodeCount, nodeCount);
|
|
|
|
if (i_swapEndian)
|
|
{
|
|
for (int nodeIndex = 0; nodeIndex < nodeCount; nodeIndex++)
|
|
{
|
|
bvh->m_quantizedContiguousNodes[nodeIndex].m_quantizedAabbMin[0] = btSwapEndian(bvh->m_quantizedContiguousNodes[nodeIndex].m_quantizedAabbMin[0]);
|
|
bvh->m_quantizedContiguousNodes[nodeIndex].m_quantizedAabbMin[1] = btSwapEndian(bvh->m_quantizedContiguousNodes[nodeIndex].m_quantizedAabbMin[1]);
|
|
bvh->m_quantizedContiguousNodes[nodeIndex].m_quantizedAabbMin[2] = btSwapEndian(bvh->m_quantizedContiguousNodes[nodeIndex].m_quantizedAabbMin[2]);
|
|
|
|
bvh->m_quantizedContiguousNodes[nodeIndex].m_quantizedAabbMax[0] = btSwapEndian(bvh->m_quantizedContiguousNodes[nodeIndex].m_quantizedAabbMax[0]);
|
|
bvh->m_quantizedContiguousNodes[nodeIndex].m_quantizedAabbMax[1] = btSwapEndian(bvh->m_quantizedContiguousNodes[nodeIndex].m_quantizedAabbMax[1]);
|
|
bvh->m_quantizedContiguousNodes[nodeIndex].m_quantizedAabbMax[2] = btSwapEndian(bvh->m_quantizedContiguousNodes[nodeIndex].m_quantizedAabbMax[2]);
|
|
|
|
bvh->m_quantizedContiguousNodes[nodeIndex].m_escapeIndexOrTriangleIndex = static_cast<int>(btSwapEndian(bvh->m_quantizedContiguousNodes[nodeIndex].m_escapeIndexOrTriangleIndex));
|
|
}
|
|
}
|
|
nodeData += sizeof(btQuantizedBvhNode) * nodeCount;
|
|
}
|
|
else
|
|
{
|
|
bvh->m_contiguousNodes.initializeFromBuffer(nodeData, nodeCount, nodeCount);
|
|
|
|
if (i_swapEndian)
|
|
{
|
|
for (int nodeIndex = 0; nodeIndex < nodeCount; nodeIndex++)
|
|
{
|
|
btUnSwapVector3Endian(bvh->m_contiguousNodes[nodeIndex].m_aabbMinOrg);
|
|
btUnSwapVector3Endian(bvh->m_contiguousNodes[nodeIndex].m_aabbMaxOrg);
|
|
|
|
bvh->m_contiguousNodes[nodeIndex].m_escapeIndex = static_cast<int>(btSwapEndian(bvh->m_contiguousNodes[nodeIndex].m_escapeIndex));
|
|
bvh->m_contiguousNodes[nodeIndex].m_subPart = static_cast<int>(btSwapEndian(bvh->m_contiguousNodes[nodeIndex].m_subPart));
|
|
bvh->m_contiguousNodes[nodeIndex].m_triangleIndex = static_cast<int>(btSwapEndian(bvh->m_contiguousNodes[nodeIndex].m_triangleIndex));
|
|
}
|
|
}
|
|
nodeData += sizeof(btOptimizedBvhNode) * nodeCount;
|
|
}
|
|
|
|
sizeToAdd = 0; //(BVH_ALIGNMENT-((unsigned)nodeData & BVH_ALIGNMENT_MASK))&BVH_ALIGNMENT_MASK;
|
|
nodeData += sizeToAdd;
|
|
|
|
// Now serialize the subtree headers
|
|
bvh->m_SubtreeHeaders.initializeFromBuffer(nodeData, bvh->m_subtreeHeaderCount, bvh->m_subtreeHeaderCount);
|
|
if (i_swapEndian)
|
|
{
|
|
for (int i = 0; i < bvh->m_subtreeHeaderCount; i++)
|
|
{
|
|
bvh->m_SubtreeHeaders[i].m_quantizedAabbMin[0] = btSwapEndian(bvh->m_SubtreeHeaders[i].m_quantizedAabbMin[0]);
|
|
bvh->m_SubtreeHeaders[i].m_quantizedAabbMin[1] = btSwapEndian(bvh->m_SubtreeHeaders[i].m_quantizedAabbMin[1]);
|
|
bvh->m_SubtreeHeaders[i].m_quantizedAabbMin[2] = btSwapEndian(bvh->m_SubtreeHeaders[i].m_quantizedAabbMin[2]);
|
|
|
|
bvh->m_SubtreeHeaders[i].m_quantizedAabbMax[0] = btSwapEndian(bvh->m_SubtreeHeaders[i].m_quantizedAabbMax[0]);
|
|
bvh->m_SubtreeHeaders[i].m_quantizedAabbMax[1] = btSwapEndian(bvh->m_SubtreeHeaders[i].m_quantizedAabbMax[1]);
|
|
bvh->m_SubtreeHeaders[i].m_quantizedAabbMax[2] = btSwapEndian(bvh->m_SubtreeHeaders[i].m_quantizedAabbMax[2]);
|
|
|
|
bvh->m_SubtreeHeaders[i].m_rootNodeIndex = static_cast<int>(btSwapEndian(bvh->m_SubtreeHeaders[i].m_rootNodeIndex));
|
|
bvh->m_SubtreeHeaders[i].m_subtreeSize = static_cast<int>(btSwapEndian(bvh->m_SubtreeHeaders[i].m_subtreeSize));
|
|
}
|
|
}
|
|
|
|
return bvh;
|
|
}
|
|
|
|
// Constructor that prevents btVector3's default constructor from being called
|
|
btQuantizedBvh::btQuantizedBvh(btQuantizedBvh& self, bool /* ownsMemory */) : m_bvhAabbMin(self.m_bvhAabbMin),
|
|
m_bvhAabbMax(self.m_bvhAabbMax),
|
|
m_bvhQuantization(self.m_bvhQuantization),
|
|
m_bulletVersion(BT_BULLET_VERSION)
|
|
{
|
|
}
|
|
|
|
void btQuantizedBvh::deSerializeFloat(struct btQuantizedBvhFloatData& quantizedBvhFloatData)
|
|
{
|
|
m_bvhAabbMax.deSerializeFloat(quantizedBvhFloatData.m_bvhAabbMax);
|
|
m_bvhAabbMin.deSerializeFloat(quantizedBvhFloatData.m_bvhAabbMin);
|
|
m_bvhQuantization.deSerializeFloat(quantizedBvhFloatData.m_bvhQuantization);
|
|
|
|
m_curNodeIndex = quantizedBvhFloatData.m_curNodeIndex;
|
|
m_useQuantization = quantizedBvhFloatData.m_useQuantization != 0;
|
|
|
|
{
|
|
int numElem = quantizedBvhFloatData.m_numContiguousLeafNodes;
|
|
m_contiguousNodes.resize(numElem);
|
|
|
|
if (numElem)
|
|
{
|
|
btOptimizedBvhNodeFloatData* memPtr = quantizedBvhFloatData.m_contiguousNodesPtr;
|
|
|
|
for (int i = 0; i < numElem; i++, memPtr++)
|
|
{
|
|
m_contiguousNodes[i].m_aabbMaxOrg.deSerializeFloat(memPtr->m_aabbMaxOrg);
|
|
m_contiguousNodes[i].m_aabbMinOrg.deSerializeFloat(memPtr->m_aabbMinOrg);
|
|
m_contiguousNodes[i].m_escapeIndex = memPtr->m_escapeIndex;
|
|
m_contiguousNodes[i].m_subPart = memPtr->m_subPart;
|
|
m_contiguousNodes[i].m_triangleIndex = memPtr->m_triangleIndex;
|
|
}
|
|
}
|
|
}
|
|
|
|
{
|
|
int numElem = quantizedBvhFloatData.m_numQuantizedContiguousNodes;
|
|
m_quantizedContiguousNodes.resize(numElem);
|
|
|
|
if (numElem)
|
|
{
|
|
btQuantizedBvhNodeData* memPtr = quantizedBvhFloatData.m_quantizedContiguousNodesPtr;
|
|
for (int i = 0; i < numElem; i++, memPtr++)
|
|
{
|
|
m_quantizedContiguousNodes[i].m_escapeIndexOrTriangleIndex = memPtr->m_escapeIndexOrTriangleIndex;
|
|
m_quantizedContiguousNodes[i].m_quantizedAabbMax[0] = memPtr->m_quantizedAabbMax[0];
|
|
m_quantizedContiguousNodes[i].m_quantizedAabbMax[1] = memPtr->m_quantizedAabbMax[1];
|
|
m_quantizedContiguousNodes[i].m_quantizedAabbMax[2] = memPtr->m_quantizedAabbMax[2];
|
|
m_quantizedContiguousNodes[i].m_quantizedAabbMin[0] = memPtr->m_quantizedAabbMin[0];
|
|
m_quantizedContiguousNodes[i].m_quantizedAabbMin[1] = memPtr->m_quantizedAabbMin[1];
|
|
m_quantizedContiguousNodes[i].m_quantizedAabbMin[2] = memPtr->m_quantizedAabbMin[2];
|
|
}
|
|
}
|
|
}
|
|
|
|
m_traversalMode = btTraversalMode(quantizedBvhFloatData.m_traversalMode);
|
|
|
|
{
|
|
int numElem = quantizedBvhFloatData.m_numSubtreeHeaders;
|
|
m_SubtreeHeaders.resize(numElem);
|
|
if (numElem)
|
|
{
|
|
btBvhSubtreeInfoData* memPtr = quantizedBvhFloatData.m_subTreeInfoPtr;
|
|
for (int i = 0; i < numElem; i++, memPtr++)
|
|
{
|
|
m_SubtreeHeaders[i].m_quantizedAabbMax[0] = memPtr->m_quantizedAabbMax[0];
|
|
m_SubtreeHeaders[i].m_quantizedAabbMax[1] = memPtr->m_quantizedAabbMax[1];
|
|
m_SubtreeHeaders[i].m_quantizedAabbMax[2] = memPtr->m_quantizedAabbMax[2];
|
|
m_SubtreeHeaders[i].m_quantizedAabbMin[0] = memPtr->m_quantizedAabbMin[0];
|
|
m_SubtreeHeaders[i].m_quantizedAabbMin[1] = memPtr->m_quantizedAabbMin[1];
|
|
m_SubtreeHeaders[i].m_quantizedAabbMin[2] = memPtr->m_quantizedAabbMin[2];
|
|
m_SubtreeHeaders[i].m_rootNodeIndex = memPtr->m_rootNodeIndex;
|
|
m_SubtreeHeaders[i].m_subtreeSize = memPtr->m_subtreeSize;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void btQuantizedBvh::deSerializeDouble(struct btQuantizedBvhDoubleData& quantizedBvhDoubleData)
|
|
{
|
|
m_bvhAabbMax.deSerializeDouble(quantizedBvhDoubleData.m_bvhAabbMax);
|
|
m_bvhAabbMin.deSerializeDouble(quantizedBvhDoubleData.m_bvhAabbMin);
|
|
m_bvhQuantization.deSerializeDouble(quantizedBvhDoubleData.m_bvhQuantization);
|
|
|
|
m_curNodeIndex = quantizedBvhDoubleData.m_curNodeIndex;
|
|
m_useQuantization = quantizedBvhDoubleData.m_useQuantization != 0;
|
|
|
|
{
|
|
int numElem = quantizedBvhDoubleData.m_numContiguousLeafNodes;
|
|
m_contiguousNodes.resize(numElem);
|
|
|
|
if (numElem)
|
|
{
|
|
btOptimizedBvhNodeDoubleData* memPtr = quantizedBvhDoubleData.m_contiguousNodesPtr;
|
|
|
|
for (int i = 0; i < numElem; i++, memPtr++)
|
|
{
|
|
m_contiguousNodes[i].m_aabbMaxOrg.deSerializeDouble(memPtr->m_aabbMaxOrg);
|
|
m_contiguousNodes[i].m_aabbMinOrg.deSerializeDouble(memPtr->m_aabbMinOrg);
|
|
m_contiguousNodes[i].m_escapeIndex = memPtr->m_escapeIndex;
|
|
m_contiguousNodes[i].m_subPart = memPtr->m_subPart;
|
|
m_contiguousNodes[i].m_triangleIndex = memPtr->m_triangleIndex;
|
|
}
|
|
}
|
|
}
|
|
|
|
{
|
|
int numElem = quantizedBvhDoubleData.m_numQuantizedContiguousNodes;
|
|
m_quantizedContiguousNodes.resize(numElem);
|
|
|
|
if (numElem)
|
|
{
|
|
btQuantizedBvhNodeData* memPtr = quantizedBvhDoubleData.m_quantizedContiguousNodesPtr;
|
|
for (int i = 0; i < numElem; i++, memPtr++)
|
|
{
|
|
m_quantizedContiguousNodes[i].m_escapeIndexOrTriangleIndex = memPtr->m_escapeIndexOrTriangleIndex;
|
|
m_quantizedContiguousNodes[i].m_quantizedAabbMax[0] = memPtr->m_quantizedAabbMax[0];
|
|
m_quantizedContiguousNodes[i].m_quantizedAabbMax[1] = memPtr->m_quantizedAabbMax[1];
|
|
m_quantizedContiguousNodes[i].m_quantizedAabbMax[2] = memPtr->m_quantizedAabbMax[2];
|
|
m_quantizedContiguousNodes[i].m_quantizedAabbMin[0] = memPtr->m_quantizedAabbMin[0];
|
|
m_quantizedContiguousNodes[i].m_quantizedAabbMin[1] = memPtr->m_quantizedAabbMin[1];
|
|
m_quantizedContiguousNodes[i].m_quantizedAabbMin[2] = memPtr->m_quantizedAabbMin[2];
|
|
}
|
|
}
|
|
}
|
|
|
|
m_traversalMode = btTraversalMode(quantizedBvhDoubleData.m_traversalMode);
|
|
|
|
{
|
|
int numElem = quantizedBvhDoubleData.m_numSubtreeHeaders;
|
|
m_SubtreeHeaders.resize(numElem);
|
|
if (numElem)
|
|
{
|
|
btBvhSubtreeInfoData* memPtr = quantizedBvhDoubleData.m_subTreeInfoPtr;
|
|
for (int i = 0; i < numElem; i++, memPtr++)
|
|
{
|
|
m_SubtreeHeaders[i].m_quantizedAabbMax[0] = memPtr->m_quantizedAabbMax[0];
|
|
m_SubtreeHeaders[i].m_quantizedAabbMax[1] = memPtr->m_quantizedAabbMax[1];
|
|
m_SubtreeHeaders[i].m_quantizedAabbMax[2] = memPtr->m_quantizedAabbMax[2];
|
|
m_SubtreeHeaders[i].m_quantizedAabbMin[0] = memPtr->m_quantizedAabbMin[0];
|
|
m_SubtreeHeaders[i].m_quantizedAabbMin[1] = memPtr->m_quantizedAabbMin[1];
|
|
m_SubtreeHeaders[i].m_quantizedAabbMin[2] = memPtr->m_quantizedAabbMin[2];
|
|
m_SubtreeHeaders[i].m_rootNodeIndex = memPtr->m_rootNodeIndex;
|
|
m_SubtreeHeaders[i].m_subtreeSize = memPtr->m_subtreeSize;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
///fills the dataBuffer and returns the struct name (and 0 on failure)
|
|
const char* btQuantizedBvh::serialize(void* dataBuffer, btSerializer* serializer) const
|
|
{
|
|
btQuantizedBvhData* quantizedData = (btQuantizedBvhData*)dataBuffer;
|
|
|
|
m_bvhAabbMax.serialize(quantizedData->m_bvhAabbMax);
|
|
m_bvhAabbMin.serialize(quantizedData->m_bvhAabbMin);
|
|
m_bvhQuantization.serialize(quantizedData->m_bvhQuantization);
|
|
|
|
quantizedData->m_curNodeIndex = m_curNodeIndex;
|
|
quantizedData->m_useQuantization = m_useQuantization;
|
|
|
|
quantizedData->m_numContiguousLeafNodes = m_contiguousNodes.size();
|
|
quantizedData->m_contiguousNodesPtr = (btOptimizedBvhNodeData*)(m_contiguousNodes.size() ? serializer->getUniquePointer((void*)&m_contiguousNodes[0]) : 0);
|
|
if (quantizedData->m_contiguousNodesPtr)
|
|
{
|
|
int sz = sizeof(btOptimizedBvhNodeData);
|
|
int numElem = m_contiguousNodes.size();
|
|
btChunk* chunk = serializer->allocate(sz, numElem);
|
|
btOptimizedBvhNodeData* memPtr = (btOptimizedBvhNodeData*)chunk->m_oldPtr;
|
|
for (int i = 0; i < numElem; i++, memPtr++)
|
|
{
|
|
m_contiguousNodes[i].m_aabbMaxOrg.serialize(memPtr->m_aabbMaxOrg);
|
|
m_contiguousNodes[i].m_aabbMinOrg.serialize(memPtr->m_aabbMinOrg);
|
|
memPtr->m_escapeIndex = m_contiguousNodes[i].m_escapeIndex;
|
|
memPtr->m_subPart = m_contiguousNodes[i].m_subPart;
|
|
memPtr->m_triangleIndex = m_contiguousNodes[i].m_triangleIndex;
|
|
// Fill padding with zeros to appease msan.
|
|
memset(memPtr->m_pad, 0, sizeof(memPtr->m_pad));
|
|
}
|
|
serializer->finalizeChunk(chunk, "btOptimizedBvhNodeData", BT_ARRAY_CODE, (void*)&m_contiguousNodes[0]);
|
|
}
|
|
|
|
quantizedData->m_numQuantizedContiguousNodes = m_quantizedContiguousNodes.size();
|
|
// printf("quantizedData->m_numQuantizedContiguousNodes=%d\n",quantizedData->m_numQuantizedContiguousNodes);
|
|
quantizedData->m_quantizedContiguousNodesPtr = (btQuantizedBvhNodeData*)(m_quantizedContiguousNodes.size() ? serializer->getUniquePointer((void*)&m_quantizedContiguousNodes[0]) : 0);
|
|
if (quantizedData->m_quantizedContiguousNodesPtr)
|
|
{
|
|
int sz = sizeof(btQuantizedBvhNodeData);
|
|
int numElem = m_quantizedContiguousNodes.size();
|
|
btChunk* chunk = serializer->allocate(sz, numElem);
|
|
btQuantizedBvhNodeData* memPtr = (btQuantizedBvhNodeData*)chunk->m_oldPtr;
|
|
for (int i = 0; i < numElem; i++, memPtr++)
|
|
{
|
|
memPtr->m_escapeIndexOrTriangleIndex = m_quantizedContiguousNodes[i].m_escapeIndexOrTriangleIndex;
|
|
memPtr->m_quantizedAabbMax[0] = m_quantizedContiguousNodes[i].m_quantizedAabbMax[0];
|
|
memPtr->m_quantizedAabbMax[1] = m_quantizedContiguousNodes[i].m_quantizedAabbMax[1];
|
|
memPtr->m_quantizedAabbMax[2] = m_quantizedContiguousNodes[i].m_quantizedAabbMax[2];
|
|
memPtr->m_quantizedAabbMin[0] = m_quantizedContiguousNodes[i].m_quantizedAabbMin[0];
|
|
memPtr->m_quantizedAabbMin[1] = m_quantizedContiguousNodes[i].m_quantizedAabbMin[1];
|
|
memPtr->m_quantizedAabbMin[2] = m_quantizedContiguousNodes[i].m_quantizedAabbMin[2];
|
|
}
|
|
serializer->finalizeChunk(chunk, "btQuantizedBvhNodeData", BT_ARRAY_CODE, (void*)&m_quantizedContiguousNodes[0]);
|
|
}
|
|
|
|
quantizedData->m_traversalMode = int(m_traversalMode);
|
|
quantizedData->m_numSubtreeHeaders = m_SubtreeHeaders.size();
|
|
|
|
quantizedData->m_subTreeInfoPtr = (btBvhSubtreeInfoData*)(m_SubtreeHeaders.size() ? serializer->getUniquePointer((void*)&m_SubtreeHeaders[0]) : 0);
|
|
if (quantizedData->m_subTreeInfoPtr)
|
|
{
|
|
int sz = sizeof(btBvhSubtreeInfoData);
|
|
int numElem = m_SubtreeHeaders.size();
|
|
btChunk* chunk = serializer->allocate(sz, numElem);
|
|
btBvhSubtreeInfoData* memPtr = (btBvhSubtreeInfoData*)chunk->m_oldPtr;
|
|
for (int i = 0; i < numElem; i++, memPtr++)
|
|
{
|
|
memPtr->m_quantizedAabbMax[0] = m_SubtreeHeaders[i].m_quantizedAabbMax[0];
|
|
memPtr->m_quantizedAabbMax[1] = m_SubtreeHeaders[i].m_quantizedAabbMax[1];
|
|
memPtr->m_quantizedAabbMax[2] = m_SubtreeHeaders[i].m_quantizedAabbMax[2];
|
|
memPtr->m_quantizedAabbMin[0] = m_SubtreeHeaders[i].m_quantizedAabbMin[0];
|
|
memPtr->m_quantizedAabbMin[1] = m_SubtreeHeaders[i].m_quantizedAabbMin[1];
|
|
memPtr->m_quantizedAabbMin[2] = m_SubtreeHeaders[i].m_quantizedAabbMin[2];
|
|
|
|
memPtr->m_rootNodeIndex = m_SubtreeHeaders[i].m_rootNodeIndex;
|
|
memPtr->m_subtreeSize = m_SubtreeHeaders[i].m_subtreeSize;
|
|
}
|
|
serializer->finalizeChunk(chunk, "btBvhSubtreeInfoData", BT_ARRAY_CODE, (void*)&m_SubtreeHeaders[0]);
|
|
}
|
|
return btQuantizedBvhDataName;
|
|
}
|