NazaraEngine/thirdparty/src/newton/dgCore/dgAABBPolygonSoup.cpp

1391 lines
45 KiB
C++

/* Copyright (c) <2003-2019> <Julio Jerez, Newton Game Dynamics>
*
* 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 "dgStdafx.h"
#include "dgHeap.h"
#include "dgStack.h"
#include "dgList.h"
#include "dgMatrix.h"
#include "dgAABBPolygonSoup.h"
#include "dgPolygonSoupBuilder.h"
#define DG_STACK_DEPTH 512
DG_MSC_VECTOR_ALIGNMENT
class dgAABBPolygonSoup::dgNodeBuilder: public dgAABBPolygonSoup::dgNode
{
public:
dgNodeBuilder (const dgVector& p0, const dgVector& p1)
:dgNode()
,m_left (NULL)
,m_right (NULL)
,m_parent (NULL)
,m_indexBox0(0)
,m_indexBox1(0)
,m_enumeration(-1)
,m_faceIndex(0)
,m_indexCount(0)
,m_faceIndices(NULL)
{
SetBox (p0, p1);
}
dgNodeBuilder (const dgVector* const vertexArray, dgInt32 faceIndex, dgInt32 indexCount, const dgInt32* const indexArray)
:dgNode()
,m_left (NULL)
,m_right (NULL)
,m_parent (NULL)
,m_indexBox0(0)
,m_indexBox1(0)
,m_enumeration(-1)
,m_faceIndex(faceIndex)
,m_indexCount(indexCount)
,m_faceIndices(indexArray)
{
dgVector minP ( dgFloat32 (1.0e15f));
dgVector maxP (-dgFloat32 (1.0e15f));
for (dgInt32 i = 0; i < indexCount; i ++) {
dgInt32 index = indexArray[i];
const dgVector& p (vertexArray[index]);
minP = p.GetMin(minP);
maxP = p.GetMax(maxP);
}
minP -= dgVector (dgFloat32 (1.0e-3f));
maxP += dgVector (dgFloat32 (1.0e-3f));
minP = minP & dgVector::m_triplexMask;
maxP = maxP & dgVector::m_triplexMask;
SetBox (minP, maxP);
}
dgNodeBuilder (dgNodeBuilder* const left, dgNodeBuilder* const right)
:dgNode()
,m_left(left)
,m_right(right)
,m_parent(NULL)
,m_indexBox0(0)
,m_indexBox1(0)
,m_enumeration(-1)
,m_faceIndex(0)
,m_indexCount(0)
,m_faceIndices(NULL)
{
m_left->m_parent = this;
m_right->m_parent = this;
dgVector p0 (left->m_p0.GetMin(right->m_p0));
dgVector p1 (left->m_p1.GetMax(right->m_p1));
SetBox(p0, p1);
}
void SetBox (const dgVector& p0, const dgVector& p1)
{
m_p0 = p0;
m_p1 = p1;
m_size = m_p1 - m_p0;
m_origin = (m_p1 + m_p0) * dgVector::m_half;
m_area = m_size.DotProduct(m_size.ShiftTripleRight()).m_x;
}
DG_INLINE static dgFloat32 CalculateSurfaceArea (dgNodeBuilder* const node0, dgNodeBuilder* const node1, dgVector& minBox, dgVector& maxBox)
{
minBox = node0->m_p0.GetMin(node1->m_p0);
maxBox = node0->m_p1.GetMax(node1->m_p1);
dgVector side0 ((maxBox - minBox) * dgVector::m_half);
//dgVector side1 (side0.m_y, side0.m_z, side0.m_x, dgFloat32 (0.0f));
dgVector side1 (side0.ShiftTripleLeft());
return side0.DotProduct(side1).GetScalar();
}
dgVector m_p0;
dgVector m_p1;
dgVector m_size;
dgVector m_origin;
dgFloat32 m_area;
dgNodeBuilder* m_left;
dgNodeBuilder* m_right;
dgNodeBuilder* m_parent;
dgInt32 m_indexBox0;
dgInt32 m_indexBox1;
dgInt32 m_enumeration;
dgInt32 m_faceIndex;
dgInt32 m_indexCount;
const dgInt32* m_faceIndices;
} DG_GCC_VECTOR_ALIGNMENT;
class dgAABBPolygonSoup::dgSpliteInfo
{
public:
dgSpliteInfo (dgNodeBuilder* const boxArray, dgInt32 boxCount)
{
dgVector minP ( dgFloat32 (1.0e15f));
dgVector maxP (-dgFloat32 (1.0e15f));
if (boxCount == 2) {
m_axis = 1;
for (dgInt32 i = 0; i < boxCount; i ++) {
const dgNodeBuilder& box = boxArray[i];
const dgVector& p0 = box.m_p0;
const dgVector& p1 = box.m_p1;
minP = minP.GetMin (p0);
maxP = maxP.GetMax (p1);
}
} else {
dgVector median (dgFloat32 (0.0f));
dgVector varian (dgFloat32 (0.0f));
for (dgInt32 i = 0; i < boxCount; i ++) {
const dgNodeBuilder& box = boxArray[i];
const dgVector& p0 = box.m_p0;
const dgVector& p1 = box.m_p1;
minP = minP.GetMin (p0);
maxP = maxP.GetMax (p1);
dgVector p (dgVector::m_half * (p0 + p1));
median += p;
varian += p * p;
}
varian = varian.Scale (dgFloat32 (boxCount)) - median * median;
dgInt32 index = 0;
dgFloat32 maxVarian = dgFloat32 (-1.0e10f);
for (dgInt32 i = 0; i < 3; i ++) {
if (varian[i] > maxVarian) {
index = i;
maxVarian = varian[i];
}
}
dgVector center = median.Scale (dgFloat32 (1.0f) / dgFloat32 (boxCount));
dgFloat32 test = center[index];
dgInt32 i0 = 0;
dgInt32 i1 = boxCount - 1;
do {
for (; i0 <= i1; i0 ++) {
const dgNodeBuilder& box = boxArray[i0];
dgFloat32 val = (box.m_p0[index] + box.m_p1[index]) * dgFloat32 (0.5f);
if (val > test) {
break;
}
}
for (; i1 >= i0; i1 --) {
const dgNodeBuilder& box = boxArray[i1];
dgFloat32 val = (box.m_p0[index] + box.m_p1[index]) * dgFloat32 (0.5f);
if (val < test) {
break;
}
}
if (i0 < i1) {
dgSwap(boxArray[i0], boxArray[i1]);
i0++;
i1--;
}
} while (i0 <= i1);
if (i0 > 0){
i0 --;
}
if ((i0 + 1) >= boxCount) {
i0 = boxCount - 2;
}
m_axis = i0 + 1;
}
dgAssert (maxP.m_x - minP.m_x >= dgFloat32 (0.0f));
dgAssert (maxP.m_y - minP.m_y >= dgFloat32 (0.0f));
dgAssert (maxP.m_z - minP.m_z >= dgFloat32 (0.0f));
m_p0 = minP;
m_p1 = maxP;
}
dgInt32 m_axis;
dgVector m_p0;
dgVector m_p1;
};
dgAABBPolygonSoup::dgAABBPolygonSoup ()
:dgPolygonSoupDatabase()
,m_nodesCount(0)
,m_indexCount(0)
,m_aabb(NULL)
,m_indices(NULL)
{
}
dgAABBPolygonSoup::~dgAABBPolygonSoup ()
{
if (m_aabb) {
dgFreeStack (m_aabb);
dgFreeStack (m_indices);
}
}
void dgAABBPolygonSoup::ImproveNodeFitness (dgNodeBuilder* const node) const
{
dgAssert (node->m_left);
dgAssert (node->m_right);
if (node->m_parent) {
dgAssert(node->m_parent->m_p0.m_w == dgFloat32(0.0f));
dgAssert(node->m_parent->m_p1.m_w == dgFloat32(0.0f));
if (node->m_parent->m_left == node) {
dgFloat32 cost0 = node->m_area;
dgVector cost1P0;
dgVector cost1P1;
dgFloat32 cost1 = dgNodeBuilder::CalculateSurfaceArea (node->m_right, node->m_parent->m_right, cost1P0, cost1P1);
dgVector cost2P0;
dgVector cost2P1;
dgFloat32 cost2 = dgNodeBuilder::CalculateSurfaceArea (node->m_left, node->m_parent->m_right, cost2P0, cost2P1);
if ((cost1 <= cost0) && (cost1 <= cost2)) {
dgNodeBuilder* const parent = node->m_parent;
node->m_p0 = parent->m_p0;
node->m_p1 = parent->m_p1;
node->m_area = parent->m_area;
node->m_size = parent->m_size;
node->m_origin = parent->m_origin;
if (parent->m_parent) {
if (parent->m_parent->m_left == parent) {
parent->m_parent->m_left = node;
} else {
dgAssert (parent->m_parent->m_right == parent);
parent->m_parent->m_right = node;
}
}
node->m_parent = parent->m_parent;
parent->m_parent = node;
node->m_right->m_parent = parent;
parent->m_left = node->m_right;
node->m_right = parent;
parent->m_p0 = cost1P0;
parent->m_p1 = cost1P1;
parent->m_area = cost1;
parent->m_size = (parent->m_p1 - parent->m_p0) * dgVector::m_half;
parent->m_origin = (parent->m_p1 + parent->m_p0) * dgVector::m_half;
} else if ((cost2 <= cost0) && (cost2 <= cost1)) {
dgNodeBuilder* const parent = node->m_parent;
node->m_p0 = parent->m_p0;
node->m_p1 = parent->m_p1;
node->m_area = parent->m_area;
node->m_size = parent->m_size;
node->m_origin = parent->m_origin;
if (parent->m_parent) {
if (parent->m_parent->m_left == parent) {
parent->m_parent->m_left = node;
} else {
dgAssert (parent->m_parent->m_right == parent);
parent->m_parent->m_right = node;
}
}
node->m_parent = parent->m_parent;
parent->m_parent = node;
node->m_left->m_parent = parent;
parent->m_left = node->m_left;
node->m_left = parent;
parent->m_p0 = cost2P0;
parent->m_p1 = cost2P1;
parent->m_area = cost2;
parent->m_size = (parent->m_p1 - parent->m_p0) * dgVector::m_half;
parent->m_origin = (parent->m_p1 + parent->m_p0) * dgVector::m_half;
}
} else {
dgFloat32 cost0 = node->m_area;
dgVector cost1P0;
dgVector cost1P1;
dgFloat32 cost1 = dgNodeBuilder::CalculateSurfaceArea (node->m_left, node->m_parent->m_left, cost1P0, cost1P1);
dgVector cost2P0;
dgVector cost2P1;
dgFloat32 cost2 = dgNodeBuilder::CalculateSurfaceArea (node->m_right, node->m_parent->m_left, cost2P0, cost2P1);
if ((cost1 <= cost0) && (cost1 <= cost2)) {
dgNodeBuilder* const parent = node->m_parent;
node->m_p0 = parent->m_p0;
node->m_p1 = parent->m_p1;
node->m_area = parent->m_area;
node->m_size = parent->m_size;
node->m_origin = parent->m_origin;
if (parent->m_parent) {
if (parent->m_parent->m_left == parent) {
parent->m_parent->m_left = node;
} else {
dgAssert (parent->m_parent->m_right == parent);
parent->m_parent->m_right = node;
}
}
node->m_parent = parent->m_parent;
parent->m_parent = node;
node->m_left->m_parent = parent;
parent->m_right = node->m_left;
node->m_left = parent;
parent->m_p0 = cost1P0;
parent->m_p1 = cost1P1;
parent->m_area = cost1;
parent->m_size = (parent->m_p1 - parent->m_p0) * dgVector::m_half;
parent->m_origin = (parent->m_p1 + parent->m_p0) * dgVector::m_half;
} else if ((cost2 <= cost0) && (cost2 <= cost1)) {
dgNodeBuilder* const parent = node->m_parent;
node->m_p0 = parent->m_p0;
node->m_p1 = parent->m_p1;
node->m_area = parent->m_area;
node->m_size = parent->m_size;
node->m_origin = parent->m_origin;
if (parent->m_parent) {
if (parent->m_parent->m_left == parent) {
parent->m_parent->m_left = node;
} else {
dgAssert (parent->m_parent->m_right == parent);
parent->m_parent->m_right = node;
}
}
node->m_parent = parent->m_parent;
parent->m_parent = node;
node->m_right->m_parent = parent;
parent->m_right = node->m_right;
node->m_right = parent;
parent->m_p0 = cost2P0;
parent->m_p1 = cost2P1;
parent->m_area = cost2;
parent->m_size = (parent->m_p1 - parent->m_p0) * dgVector::m_half;
parent->m_origin = (parent->m_p1 + parent->m_p0) * dgVector::m_half;
}
}
} else {
// in the future I can handle this but it is too much work for little payoff
}
}
dgFloat32 dgAABBPolygonSoup::CalculateFaceMaxSize (const dgVector* const vertex, dgInt32 indexCount, const dgInt32* const indexArray) const
{
dgFloat32 maxSize = dgFloat32 (0.0f);
dgInt32 index = indexArray[indexCount - 1];
dgVector p0 (vertex[index]);
for (dgInt32 i = 0; i < indexCount; i ++) {
dgInt32 index1 = indexArray[i];
dgVector p1 (vertex[index1]);
dgVector dir (p1 - p0);
dgAssert (dir.m_w == dgFloat32 (0.0f));
dir = dir.Normalize();
dgFloat32 maxVal = dgFloat32 (-1.0e10f);
dgFloat32 minVal = dgFloat32 ( 1.0e10f);
for (dgInt32 j = 0; j < indexCount; j ++) {
dgInt32 index2 = indexArray[j];
dgVector q (vertex[index2]);
dgFloat32 val = dir.DotProduct(q).GetScalar();
minVal = dgMin(minVal, val);
maxVal = dgMax(maxVal, val);
}
dgFloat32 size = maxVal - minVal;
maxSize = dgMax(maxSize, size);
p0 = p1;
}
return dgFloor (maxSize + dgFloat32 (1.0f));
}
void dgAABBPolygonSoup::GetAABB (dgVector& p0, dgVector& p1) const
{
if (m_aabb) {
GetNodeAABB (m_aabb, p0, p1);
} else {
p0 = dgVector::m_zero;
p1 = dgVector::m_zero;
}
}
void dgAABBPolygonSoup::CalculateAdjacendy ()
{
dgVector p0;
dgVector p1;
GetAABB (p0, p1);
dgFastAABBInfo box (p0, p1);
ForAllSectors (box, dgVector (dgFloat32 (0.0f)), dgFloat32 (1.0f), CalculateAllFaceEdgeNormals, this);
dgStack<dgTriplex> pool ((m_indexCount / 2) - 1);
const dgTriplex* const vertexArray = (dgTriplex*)GetLocalVertexPool();
dgInt32 normalCount = 0;
for (dgInt32 i = 0; i < m_nodesCount; i ++) {
const dgNode* const node = &m_aabb[i];
if (node->m_left.IsLeaf()) {
dgInt32 vCount = dgInt32 (node->m_left.GetCount());
if (vCount) {
dgInt32 index = dgInt32 (node->m_left.GetIndex());
dgInt32* const face = &m_indices[index];
dgInt32 j0 = 2 * (vCount + 1) - 1;
dgVector normal (&vertexArray[face[vCount + 1]].m_x);
normal = normal & dgVector::m_triplexMask;
dgAssert (dgAbs (normal.DotProduct(normal).GetScalar() - dgFloat32 (1.0f)) < dgFloat32 (1.0e-6f));
dgVector q0 (&vertexArray[face[vCount - 1]].m_x);
q0 = q0 & dgVector::m_triplexMask;
for (dgInt32 j = 0; j < vCount; j ++) {
dgInt32 j1 = vCount + 2 + j;
dgVector q1 (&vertexArray[face[j]].m_x);
q1 = q1 & dgVector::m_triplexMask;
if (face[j0] == -1) {
dgVector e (q1 - q0);
dgVector n (e.CrossProduct(normal));
n = n.Scale(dgFloat32 (1.0f) / dgSqrt (n.DotProduct(n).GetScalar()));
dgAssert (dgAbs (n.DotProduct(n).GetScalar() - dgFloat32 (1.0f)) < dgFloat32 (1.0e-6f));
pool[normalCount].m_x = n.m_x;
pool[normalCount].m_y = n.m_y;
pool[normalCount].m_z = n.m_z;
face[j0] = -normalCount - 1;
normalCount ++;
}
q0 = q1;
j0 = j1;
}
}
}
if (node->m_right.IsLeaf()) {
dgInt32 vCount = dgInt32 (node->m_right.GetCount());
if (vCount) {
dgInt32 index = dgInt32 (node->m_right.GetIndex());
dgInt32* const face = &m_indices[index];
dgInt32 j0 = 2 * (vCount + 1) - 1;
dgVector normal (&vertexArray[face[vCount + 1]].m_x);
normal = normal & dgVector::m_triplexMask;
dgAssert (dgAbs (normal.DotProduct(normal).GetScalar() - dgFloat32 (1.0f)) < dgFloat32 (1.0e-6f));
dgVector q0 (&vertexArray[face[vCount - 1]].m_x);
q0 = q0 & dgVector::m_triplexMask;
for (dgInt32 j = 0; j < vCount; j ++) {
dgInt32 j1 = vCount + 2 + j;
dgVector q1 (&vertexArray[face[j]].m_x);
q1 = q1 & dgVector::m_triplexMask;
if (face[j0] == -1) {
dgVector e (q1 - q0);
dgVector n (e.CrossProduct(normal));
n = n.Scale(dgFloat32 (1.0f) / dgSqrt (n.DotProduct(n).GetScalar()));
dgAssert (dgAbs (n.DotProduct(n).GetScalar() - dgFloat32 (1.0f)) < dgFloat32 (1.0e-6f));
pool[normalCount].m_x = n.m_x;
pool[normalCount].m_y = n.m_y;
pool[normalCount].m_z = n.m_z;
face[j0] = -normalCount - 1;
normalCount ++;
}
q0 = q1;
j0 = j1;
}
}
}
}
if (normalCount) {
dgStack<dgInt32> indexArray (normalCount);
dgInt32 newNormalCount = dgVertexListToIndexList (&pool[0].m_x, sizeof (dgTriplex), sizeof (dgTriplex), 0, normalCount, &indexArray[0], dgFloat32 (1.0e-6f));
dgInt32 oldCount = GetVertexCount();
dgTriplex* const vertexArray1 = (dgTriplex*) dgMallocStack (sizeof (dgTriplex) * (oldCount + newNormalCount));
memcpy (vertexArray1, GetLocalVertexPool(), sizeof (dgTriplex) * oldCount);
memcpy (&vertexArray1[oldCount], &pool[0].m_x, sizeof (dgTriplex) * newNormalCount);
dgFreeStack(GetLocalVertexPool());
m_localVertex = &vertexArray1[0].m_x;
m_vertexCount = oldCount + newNormalCount;
for (dgInt32 i = 0; i < m_nodesCount; i ++) {
const dgNode* const node = &m_aabb[i];
if (node->m_left.IsLeaf()) {
dgInt32 vCount = dgInt32 (node->m_left.GetCount());
dgInt32 index = dgInt32 (node->m_left.GetIndex());
dgInt32* const face = &m_indices[index];
for (dgInt32 j = 0; j < vCount; j ++) {
if (face[vCount + 2 + j] < 0) {
dgInt32 k = -1 - face[vCount + 2 + j];
face[vCount + 2 + j] = indexArray[k] + oldCount;
}
#ifdef _DEBUG
dgVector normal (&vertexArray1[face[vCount + 2 + j]].m_x);
normal = normal & dgVector::m_triplexMask;
dgAssert (dgAbs (normal.DotProduct(normal).GetScalar() - dgFloat32 (1.0f)) < dgFloat32 (1.0e-6f));
#endif
}
}
if (node->m_right.IsLeaf()) {
dgInt32 vCount = dgInt32 (node->m_right.GetCount());
dgInt32 index = dgInt32 (node->m_right.GetIndex());
dgInt32* const face = &m_indices[index];
for (dgInt32 j = 0; j < vCount; j ++) {
if (face[vCount + 2 + j] < 0) {
dgInt32 k = -1 - face[vCount + 2 + j];
face[vCount + 2 + j] = indexArray[k] + oldCount;
}
#ifdef _DEBUG
dgVector normal (&vertexArray1[face[vCount + 2 + j]].m_x);
normal = normal & dgVector::m_triplexMask;
dgAssert (dgAbs (normal.DotProduct(normal).GetScalar() - dgFloat32 (1.0f)) < dgFloat32 (1.0e-6f));
#endif
}
}
}
}
}
dgIntersectStatus dgAABBPolygonSoup::CalculateAllFaceEdgeNormals (void* const context, const dgFloat32* const polygon, dgInt32 strideInBytes, const dgInt32* const indexArray, dgInt32 indexCount, dgFloat32 hitDistance)
{
dgInt32 stride = dgInt32 (strideInBytes / sizeof (dgFloat32));
AdjacentdFace adjacentFaces;
adjacentFaces.m_count = indexCount;
adjacentFaces.m_index = (dgInt32*) indexArray;
dgVector n (&polygon[indexArray[indexCount + 1] * stride]);
dgVector p (&polygon[indexArray[0] * stride]);
n = n & dgVector::m_triplexMask;
p = p & dgVector::m_triplexMask;
adjacentFaces.m_normal = dgPlane (n, - n.DotProduct(p).GetScalar());
dgAssert (indexCount < dgInt32 (sizeof (adjacentFaces.m_edgeMap) / sizeof (adjacentFaces.m_edgeMap[0])));
dgInt32 edgeIndex = indexCount - 1;
dgInt32 i0 = indexArray[indexCount - 1];
dgVector p0 ( dgFloat32 (1.0e15f), dgFloat32 (1.0e15f), dgFloat32 (1.0e15f), dgFloat32 (0.0f));
dgVector p1 (-dgFloat32 (1.0e15f), -dgFloat32 (1.0e15f), -dgFloat32 (1.0e15f), dgFloat32 (0.0f));
for (dgInt32 i = 0; i < indexCount; i ++) {
dgInt32 i1 = indexArray[i];
dgInt32 index = i1 * stride;
dgVector point (&polygon[index]);
point = point & dgVector::m_triplexMask;
p0 = p0.GetMin(point);
p1 = p1.GetMax(point);
adjacentFaces.m_edgeMap[edgeIndex] = (dgInt64 (i1) << 32) + i0;
edgeIndex = i;
i0 = i1;
}
dgFloat32 padding = dgFloat32 (1.0f/16.0f);
p0.m_x -= padding;
p0.m_y -= padding;
p0.m_z -= padding;
p1.m_x += padding;
p1.m_y += padding;
p1.m_z += padding;
dgAABBPolygonSoup* const me = (dgAABBPolygonSoup*) context;
dgFastAABBInfo box (p0, p1);
me->ForAllSectors (box, dgVector (dgFloat32 (0.0f)), dgFloat32 (1.0f), CalculateDisjointedFaceEdgeNormals, &adjacentFaces);
return t_ContinueSearh;
}
dgIntersectStatus dgAABBPolygonSoup::CalculateDisjointedFaceEdgeNormals (void* const context, const dgFloat32* const polygon, dgInt32 strideInBytes, const dgInt32* const indexArray, dgInt32 indexCount, dgFloat32 hitDistance)
{
#define DG_WELDING_TOL (1.0e-2f)
#define DG_WELDING_TOL2 (DG_WELDING_TOL * DG_WELDING_TOL)
const AdjacentdFace& adjacentFace = *((AdjacentdFace*)context);
if (adjacentFace.m_index != indexArray) {
dgInt32 adjacentCount = adjacentFace.m_count;
dgInt32 stride = dgInt32 (strideInBytes / sizeof (dgFloat32));
dgInt32 j0 = adjacentCount - 1;
dgInt32 indexJ0 = adjacentFace.m_index[adjacentCount - 1];
for (dgInt32 j = 0; j < adjacentCount; j ++) {
dgInt32 indexJ1 = adjacentFace.m_index[j];
dgBigVector q0 (dgVector(&polygon[indexJ1 * stride]) & dgVector::m_triplexMask);
dgBigVector q1 (dgVector(&polygon[indexJ0 * stride]) & dgVector::m_triplexMask);
dgBigVector q1q0 (q1 - q0);
dgFloat64 q1q0Mag2 = q1q0.DotProduct(q1q0).GetScalar();
dgInt32 indexI0 = indexArray[indexCount - 1];
for (dgInt32 i = 0; i < indexCount; i ++) {
dgInt32 indexI1 = indexArray[i];
dgBigVector p0 (dgVector(&polygon[indexI0 * stride]) & dgVector::m_triplexMask);
dgBigVector p1 (dgVector(&polygon[indexI1 * stride]) & dgVector::m_triplexMask);
dgBigVector p1p0 (p1 - p0);
dgFloat64 dot = p1p0.DotProduct(q1q0).GetScalar();
if (dot > 0.0f) {
dgFloat64 q1p0Mag2 = p1p0.DotProduct(p1p0).GetScalar();
if ((dot * dot) >= (q1p0Mag2 * q1q0Mag2 * dgFloat64(0.99995f))) {
dgFloat64 x0 = q0.DotProduct(q1q0).GetScalar();
dgFloat64 x1 = q1.DotProduct(q1q0).GetScalar();
dgFloat64 y0 = p0.DotProduct(q1q0).GetScalar();
dgFloat64 y1 = p1.DotProduct(q1q0).GetScalar();
dgAssert (x1 > x0);
dgAssert (y1 > y0);
if (!((y0 >= x1) || (y1 <= x0))) {
dgFloat64 t = q1q0.DotProduct(p0 - q0).GetScalar() / q1q0Mag2;
dgAssert (q1q0.m_w == dgFloat32 (0.0f));
dgBigVector q (q0 + q1q0.Scale(t));
dgBigVector dist (p0 - q);
dgAssert (dist.m_w == dgFloat32 (0.0f));
dgFloat64 err2 = dist.DotProduct(dist).GetScalar();
if (err2 < DG_WELDING_TOL2) {
dgFloat32 maxDist = dgFloat32 (0.0f);
for (dgInt32 k = 0; k < indexCount; k ++) {
dgVector r (&polygon[indexArray[k] * stride]);
r = r & dgVector::m_triplexMask;
dgFloat32 dist1 = adjacentFace.m_normal.Evalue(r);
if (dgAbs (dist1) > dgAbs (maxDist)) {
maxDist = dist1;
}
}
if (adjacentFace.m_index[j0 + adjacentCount + 2] == -1) {
if (maxDist < -dgFloat32 (1.0e-3f)) {
adjacentFace.m_index[j0 + adjacentCount + 2] = indexArray[indexCount + 1];
} else {
adjacentFace.m_index[j0 + adjacentCount + 2] = adjacentFace.m_index[adjacentCount + 1];
}
} else {
if (maxDist < -dgFloat32 (1.0e-3f)) {
dgBigVector n0 (adjacentFace.m_normal[0], adjacentFace.m_normal[1], adjacentFace.m_normal[2], dgFloat64(0.0f));
dgBigVector n1 (dgVector(&polygon[adjacentFace.m_index[j0 + adjacentCount + 2] * stride]) & dgVector::m_triplexMask);
dgBigVector n2 (dgVector(&polygon[indexArray[indexCount + 1] * stride]) & dgVector::m_triplexMask);
dgBigVector tilt0 (n0.CrossProduct(n1));
dgBigVector tilt1 (n0.CrossProduct(n2));
dgFloat64 dist0 (q1q0.DotProduct(tilt0).GetScalar());
dgFloat64 dist1 (q1q0.DotProduct(tilt1).GetScalar());
if (dist0 < dist1) {
adjacentFace.m_index[j0 + adjacentCount + 2] = indexArray[indexCount + 1];
}
} else {
adjacentFace.m_index[j0 + adjacentCount + 2] = adjacentFace.m_index[adjacentCount + 1];
}
}
break;
}
}
}
}
indexI0 = indexI1;
}
j0 = j;
indexJ0 = indexJ1;
}
}
return t_ContinueSearh;
}
dgAABBPolygonSoup::dgNodeBuilder* dgAABBPolygonSoup::BuildTopDown (dgNodeBuilder* const leafArray, dgInt32 firstBox, dgInt32 lastBox, dgNodeBuilder** const allocator) const
{
dgAssert (firstBox >= 0);
dgAssert (lastBox >= 0);
if (lastBox == firstBox) {
return &leafArray[firstBox];
} else {
dgSpliteInfo info (&leafArray[firstBox], lastBox - firstBox + 1);
dgNodeBuilder* const parent = new (*allocator) dgNodeBuilder (info.m_p0, info.m_p1);
*allocator = *allocator + 1;
dgAssert (parent);
parent->m_right = BuildTopDown (leafArray, firstBox + info.m_axis, lastBox, allocator);
parent->m_right->m_parent = parent;
parent->m_left = BuildTopDown (leafArray, firstBox, firstBox + info.m_axis - 1, allocator);
parent->m_left->m_parent = parent;
return parent;
}
}
void dgAABBPolygonSoup::Create (const dgPolygonSoupDatabaseBuilder& builder, bool optimizedBuild)
{
if (builder.m_faceCount == 0) {
return;
}
dgAssert (builder.m_faceCount >= 1);
m_strideInBytes = sizeof (dgTriplex);
m_nodesCount = ((builder.m_faceCount - 1) < 1) ? 1 : builder.m_faceCount - 1;
m_aabb = (dgNode*) dgMallocStack (sizeof (dgNode) * m_nodesCount);
m_indexCount = builder.m_indexCount * 2 + builder.m_faceCount;
if (builder.m_faceCount == 1) {
m_indexCount *= 2;
}
m_indices = (dgInt32*) dgMallocStack (sizeof (dgInt32) * m_indexCount);
dgStack<dgVector> tmpVertexArrayCont(builder.m_vertexCount + builder.m_normalCount + builder.m_faceCount * 2 + 4);
dgVector* const tmpVertexArray = &tmpVertexArrayCont[0];
for (dgInt32 i = 0; i < builder.m_vertexCount; i ++) {
tmpVertexArray[i] = builder.m_vertexPoints[i];
}
for (dgInt32 i = 0; i < builder.m_normalCount; i ++) {
tmpVertexArray[i + builder.m_vertexCount] = builder.m_normalPoints[i];
}
const dgInt32* const indices = &builder.m_vertexIndex[0];
dgStack<dgNodeBuilder> constructor (builder.m_faceCount * 2 + 16);
dgInt32 polygonIndex = 0;
dgInt32 allocatorIndex = 0;
if (builder.m_faceCount == 1) {
dgInt32 indexCount = builder.m_faceVertexCount[0] - 1;
new (&constructor[allocatorIndex]) dgNodeBuilder (&tmpVertexArray[0], 0, indexCount, &indices[0]);
allocatorIndex ++;
}
for (dgInt32 i = 0; i < builder.m_faceCount; i ++) {
dgInt32 indexCount = builder.m_faceVertexCount[i] - 1;
new (&constructor[allocatorIndex]) dgNodeBuilder (&tmpVertexArray[0], i, indexCount, &indices[polygonIndex]);
allocatorIndex ++;
polygonIndex += (indexCount + 1);
}
dgNodeBuilder* contructorAllocator = &constructor[allocatorIndex];
dgNodeBuilder* root = BuildTopDown (&constructor[0], 0, allocatorIndex - 1, &contructorAllocator);
dgAssert (root);
if (root->m_left) {
dgAssert (root->m_right);
dgList<dgNodeBuilder*> list (builder.m_allocator);
dgList<dgNodeBuilder*> stack (builder.m_allocator);
stack.Append(root);
while (stack.GetCount()) {
dgList<dgNodeBuilder*>::dgListNode* const stackNode = stack.GetLast();
dgNodeBuilder* const node = stackNode->GetInfo();
stack.Remove(stackNode);
if (node->m_left) {
dgAssert (node->m_right);
list.Append(node);
stack.Append(node->m_right);
stack.Append(node->m_left);
}
}
dgFloat64 newCost = dgFloat32 (1.0e20f);
dgFloat64 prevCost = newCost;
do {
prevCost = newCost;
for (dgList<dgNodeBuilder*>::dgListNode* listNode = list.GetFirst(); listNode; listNode = listNode->GetNext()) {
dgNodeBuilder* const node = listNode->GetInfo();
ImproveNodeFitness (node);
}
newCost = dgFloat32 (0.0f);
for (dgList<dgNodeBuilder*>::dgListNode* listNode = list.GetFirst(); listNode; listNode = listNode->GetNext()) {
dgNodeBuilder* const node = listNode->GetInfo();
newCost += node->m_area;
}
} while (newCost < (prevCost * dgFloat32 (0.9999f)));
root = list.GetLast()->GetInfo();
while (root->m_parent) {
root = root->m_parent;
}
}
dgList<dgNodeBuilder*> list (builder.m_allocator);
list.Append(root);
dgInt32 nodeIndex = 0;
while (list.GetCount()) {
dgNodeBuilder* const node = list.GetFirst()->GetInfo();
list.Remove(list.GetFirst());
if (node->m_left) {
node->m_enumeration = nodeIndex;
nodeIndex ++;
dgAssert (node->m_right);
list.Append(node->m_left);
list.Append(node->m_right);
}
}
dgAssert(!list.GetCount());
dgInt32 aabbBase = builder.m_vertexCount + builder.m_normalCount;
dgVector* const aabbPoints = &tmpVertexArray[aabbBase];
dgInt32 vertexIndex = 0;
dgInt32 aabbNodeIndex = 0;
list.Append(root);
dgInt32 indexMap = 0;
while (list.GetCount()) {
dgNodeBuilder* const node = list.GetFirst()->GetInfo();
list.Remove(list.GetFirst());
if (node->m_enumeration >= 0) {
dgAssert (node->m_left);
dgAssert (node->m_right);
dgNode& aabbNode = m_aabb[aabbNodeIndex];
aabbNodeIndex ++;
dgAssert (aabbNodeIndex <= m_nodesCount);
if (node->m_parent) {
if (node->m_parent->m_left == node) {
m_aabb[node->m_parent->m_enumeration].m_left = dgNode::dgLeafNodePtr (dgUnsigned32 (&m_aabb[node->m_enumeration] - m_aabb));
} else {
dgAssert (node->m_parent->m_right == node);
m_aabb[node->m_parent->m_enumeration].m_right = dgNode::dgLeafNodePtr (dgUnsigned32 (&m_aabb[node->m_enumeration] - m_aabb));
}
}
aabbPoints[vertexIndex + 0] = node->m_p0;
aabbPoints[vertexIndex + 1] = node->m_p1;
aabbNode.m_indexBox0 = aabbBase + vertexIndex;
aabbNode.m_indexBox1 = aabbBase + vertexIndex + 1;
vertexIndex += 2;
} else {
dgAssert (!node->m_left);
dgAssert (!node->m_right);
if (node->m_parent) {
if (node->m_parent->m_left == node) {
m_aabb[node->m_parent->m_enumeration].m_left = dgNode::dgLeafNodePtr (dgUnsigned32(node->m_indexCount), dgUnsigned32(indexMap));
} else {
dgAssert (node->m_parent->m_right == node);
m_aabb[node->m_parent->m_enumeration].m_right = dgNode::dgLeafNodePtr (dgUnsigned32(node->m_indexCount), dgUnsigned32(indexMap));
}
}
// index format i0, i1, i2, ... , id, normal, e0Normal, e1Normal, e2Normal, ..., faceSize
for (dgInt32 j = 0; j < node->m_indexCount; j ++) {
m_indices[indexMap + j] = node->m_faceIndices[j];
m_indices[indexMap + j + node->m_indexCount + 2] = -1;
}
// face attribute
m_indices[indexMap + node->m_indexCount] = node->m_faceIndices[node->m_indexCount];
// face normal
m_indices[indexMap + node->m_indexCount + 1] = builder.m_vertexCount + builder.m_normalIndex[node->m_faceIndex];
// face size
m_indices[indexMap + node->m_indexCount * 2 + 2] = dgInt32 (CalculateFaceMaxSize (&tmpVertexArray[0], node->m_indexCount, node->m_faceIndices));
indexMap += node->m_indexCount * 2 + 3;
}
if (node->m_left) {
dgAssert (node->m_right);
list.Append(node->m_left);
list.Append(node->m_right);
}
}
dgStack<dgInt32> indexArray (vertexIndex);
dgInt32 aabbPointCount = dgVertexListToIndexList (&aabbPoints[0].m_x, sizeof (dgVector), sizeof (dgTriplex), 0, vertexIndex, &indexArray[0], dgFloat32 (1.0e-6f));
m_vertexCount = aabbBase + aabbPointCount;
m_localVertex = (dgFloat32*) dgMallocStack (sizeof (dgTriplex) * m_vertexCount);
dgTriplex* const dstPoints = (dgTriplex*)m_localVertex;
for (dgInt32 i = 0; i < m_vertexCount; i ++) {
dstPoints[i].m_x = tmpVertexArray[i].m_x;
dstPoints[i].m_y = tmpVertexArray[i].m_y;
dstPoints[i].m_z = tmpVertexArray[i].m_z;
}
for (dgInt32 i = 0; i < m_nodesCount; i ++) {
dgNode& box = m_aabb[i];
dgInt32 j = box.m_indexBox0 - aabbBase;
box.m_indexBox0 = indexArray[j] + aabbBase;
j = box.m_indexBox1 - aabbBase;
box.m_indexBox1 = indexArray[j] + aabbBase;
}
if (builder.m_faceCount == 1) {
m_aabb[0].m_right = dgNode::dgLeafNodePtr (0, 0);
}
// CalculateAdjacendy();
}
void dgAABBPolygonSoup::Serialize (dgSerialize callback, void* const userData) const
{
callback (userData, &m_vertexCount, sizeof (dgInt32));
callback (userData, &m_indexCount, sizeof (dgInt32));
callback (userData, &m_nodesCount, sizeof (dgInt32));
callback (userData, &m_nodesCount, sizeof (dgInt32));
if (m_aabb) {
callback (userData, m_localVertex, dgInt32 (sizeof (dgTriplex) * m_vertexCount));
callback (userData, m_indices, dgInt32 (sizeof (dgInt32) * m_indexCount));
callback (userData, m_aabb, dgInt32 (sizeof (dgNode) * m_nodesCount));
}
}
void dgAABBPolygonSoup::Deserialize (dgDeserialize callback, void* const userData, dgInt32 revisionNumber)
{
m_strideInBytes = sizeof (dgTriplex);
callback (userData, &m_vertexCount, sizeof (dgInt32));
callback (userData, &m_indexCount, sizeof (dgInt32));
callback (userData, &m_nodesCount, sizeof (dgInt32));
callback (userData, &m_nodesCount, sizeof (dgInt32));
if (m_vertexCount) {
m_localVertex = (dgFloat32*) dgMallocStack (sizeof (dgTriplex) * m_vertexCount);
m_indices = (dgInt32*) dgMallocStack (sizeof (dgInt32) * m_indexCount);
m_aabb = (dgNode*) dgMallocStack (sizeof (dgNode) * m_nodesCount);
callback (userData, m_localVertex, dgInt32 (sizeof (dgTriplex) * m_vertexCount));
callback (userData, m_indices, dgInt32 (sizeof (dgInt32) * m_indexCount));
callback (userData, m_aabb, dgInt32 (sizeof (dgNode) * m_nodesCount));
} else {
m_localVertex = NULL;
m_indices = NULL;
m_aabb = NULL;
}
}
dgVector dgAABBPolygonSoup::ForAllSectorsSupportVectex (const dgVector& dir) const
{
dgVector supportVertex (dgFloat32 (0.0f));
if (m_aabb) {
dgFloat32 aabbProjection[DG_STACK_DEPTH];
const dgNode *stackPool[DG_STACK_DEPTH];
dgInt32 stack = 1;
stackPool[0] = m_aabb;
aabbProjection[0] = dgFloat32 (1.0e10f);
const dgTriplex* const boxArray = (dgTriplex*)m_localVertex;
dgFloat32 maxProj = dgFloat32 (-1.0e20f);
dgInt32 ix = (dir[0] > dgFloat32 (0.0f)) ? 1 : 0;
dgInt32 iy = (dir[1] > dgFloat32 (0.0f)) ? 1 : 0;
dgInt32 iz = (dir[2] > dgFloat32 (0.0f)) ? 1 : 0;
while (stack) {
dgFloat32 boxSupportValue;
stack--;
boxSupportValue = aabbProjection[stack];
if (boxSupportValue > maxProj) {
dgFloat32 backSupportDist = dgFloat32 (0.0f);
dgFloat32 frontSupportDist = dgFloat32 (0.0f);
const dgNode* const me = stackPool[stack];
if (me->m_left.IsLeaf()) {
backSupportDist = dgFloat32 (-1.0e20f);
dgInt32 index = dgInt32 (me->m_left.GetIndex());
dgInt32 vCount = dgInt32 (me->m_left.GetCount());
dgVector vertex (dgFloat32 (0.0f));
for (dgInt32 j = 0; j < vCount; j ++) {
dgInt32 i0 = m_indices[index + j] * dgInt32 (sizeof (dgTriplex) / sizeof (dgFloat32));
dgVector p (&boxArray[i0].m_x);
p = p & dgVector::m_triplexMask;
dgFloat32 dist = p.DotProduct(dir).GetScalar();
if (dist > backSupportDist) {
backSupportDist = dist;
vertex = p;
}
}
if (backSupportDist > maxProj) {
maxProj = backSupportDist;
supportVertex = vertex;
}
} else {
dgVector box[2];
const dgNode* const node = me->m_left.GetNode(m_aabb);
box[0].m_x = boxArray[node->m_indexBox0].m_x;
box[0].m_y = boxArray[node->m_indexBox0].m_y;
box[0].m_z = boxArray[node->m_indexBox0].m_z;
box[1].m_x = boxArray[node->m_indexBox1].m_x;
box[1].m_y = boxArray[node->m_indexBox1].m_y;
box[1].m_z = boxArray[node->m_indexBox1].m_z;
dgVector supportPoint (box[ix].m_x, box[iy].m_y, box[iz].m_z, dgFloat32 (0.0));
backSupportDist = supportPoint.DotProduct(dir).GetScalar();
}
if (me->m_right.IsLeaf()) {
frontSupportDist = dgFloat32 (-1.0e20f);
dgInt32 index = dgInt32 (me->m_right.GetIndex());
dgInt32 vCount = dgInt32 (me->m_right.GetCount());
dgVector vertex (dgFloat32 (0.0f));
for (dgInt32 j = 0; j < vCount; j ++) {
dgInt32 i0 = m_indices[index + j] * dgInt32 (sizeof (dgTriplex) / sizeof (dgFloat32));
dgVector p (&boxArray[i0].m_x);
p = p & dgVector::m_triplexMask;
dgFloat32 dist = p.DotProduct(dir).GetScalar();
if (dist > frontSupportDist) {
frontSupportDist = dist;
vertex = p;
}
}
if (frontSupportDist > maxProj) {
maxProj = frontSupportDist;
supportVertex = vertex;
}
} else {
dgVector box[2];
const dgNode* const node = me->m_right.GetNode(m_aabb);
box[0].m_x = boxArray[node->m_indexBox0].m_x;
box[0].m_y = boxArray[node->m_indexBox0].m_y;
box[0].m_z = boxArray[node->m_indexBox0].m_z;
box[1].m_x = boxArray[node->m_indexBox1].m_x;
box[1].m_y = boxArray[node->m_indexBox1].m_y;
box[1].m_z = boxArray[node->m_indexBox1].m_z;
dgVector supportPoint (box[ix].m_x, box[iy].m_y, box[iz].m_z, dgFloat32 (0.0f));
frontSupportDist = supportPoint.DotProduct(dir).GetScalar();
}
if (frontSupportDist >= backSupportDist) {
if (!me->m_left.IsLeaf()) {
aabbProjection[stack] = backSupportDist;
stackPool[stack] = me->m_left.GetNode(m_aabb);
stack++;
}
if (!me->m_right.IsLeaf()) {
aabbProjection[stack] = frontSupportDist;
stackPool[stack] = me->m_right.GetNode(m_aabb);
stack++;
}
} else {
if (!me->m_right.IsLeaf()) {
aabbProjection[stack] = frontSupportDist;
stackPool[stack] = me->m_right.GetNode(m_aabb);
stack++;
}
if (!me->m_left.IsLeaf()) {
aabbProjection[stack] = backSupportDist;
stackPool[stack] = me->m_left.GetNode(m_aabb);
stack++;
}
}
}
}
}
return supportVertex;
}
void dgAABBPolygonSoup::ForAllSectorsRayHit (const dgFastRayTest& raySrc, dgFloat32 maxParam, dgRayIntersectCallback callback, void* const context) const
{
const dgNode *stackPool[DG_STACK_DEPTH];
dgFloat32 distance[DG_STACK_DEPTH];
dgFastRayTest ray (raySrc);
dgInt32 stack = 1;
const dgTriplex* const vertexArray = (dgTriplex*) m_localVertex;
stackPool[0] = m_aabb;
distance[0] = m_aabb->RayDistance(ray, vertexArray);
while (stack) {
stack --;
dgFloat32 dist = distance[stack];
if (dist > maxParam) {
break;
} else {
const dgNode *const me = stackPool[stack];
if (me->m_left.IsLeaf()) {
dgInt32 vCount = dgInt32 (me->m_left.GetCount());
if (vCount > 0) {
dgInt32 index = dgInt32 (me->m_left.GetIndex());
dgFloat32 param = callback(context, &vertexArray[0].m_x, sizeof (dgTriplex), &m_indices[index], vCount);
dgAssert (param >= dgFloat32 (0.0f));
if (param < maxParam) {
maxParam = param;
if (maxParam == dgFloat32 (0.0f)) {
break;
}
}
}
} else {
const dgNode* const node = me->m_left.GetNode(m_aabb);
dgFloat32 dist1 = node->RayDistance(ray, vertexArray);
if (dist1 < maxParam) {
dgInt32 j = stack;
for ( ; j && (dist1 > distance[j - 1]); j --) {
stackPool[j] = stackPool[j - 1];
distance[j] = distance[j - 1];
}
dgAssert (stack < DG_STACK_DEPTH);
stackPool[j] = node;
distance[j] = dist1;
stack++;
}
}
if (me->m_right.IsLeaf()) {
dgInt32 vCount = dgInt32 (me->m_right.GetCount());
if (vCount > 0) {
dgInt32 index = dgInt32 (me->m_right.GetIndex());
dgFloat32 param = callback(context, &vertexArray[0].m_x, sizeof (dgTriplex), &m_indices[index], vCount);
dgAssert (param >= dgFloat32 (0.0f));
if (param < maxParam) {
maxParam = param;
if (maxParam == dgFloat32 (0.0f)) {
break;
}
}
}
} else {
const dgNode* const node = me->m_right.GetNode(m_aabb);
dgFloat32 dist1 = node->RayDistance(ray, vertexArray);
if (dist1 < maxParam) {
dgInt32 j = stack;
for ( ; j && (dist1 > distance[j - 1]); j --) {
stackPool[j] = stackPool[j - 1];
distance[j] = distance[j - 1];
}
dgAssert (stack < DG_STACK_DEPTH);
stackPool[j] = node;
distance[j] = dist1;
stack++;
}
}
}
}
}
void dgAABBPolygonSoup::ForAllSectors (const dgFastAABBInfo& obbAabbInfo, const dgVector& boxDistanceTravel, dgFloat32 m_maxT, dgAABBIntersectCallback callback, void* const context) const
{
dgAssert (dgAbs(dgAbs(obbAabbInfo[0][0]) - obbAabbInfo.m_absDir[0][0]) < dgFloat32 (1.0e-4f));
dgAssert (dgAbs(dgAbs(obbAabbInfo[1][1]) - obbAabbInfo.m_absDir[1][1]) < dgFloat32 (1.0e-4f));
dgAssert (dgAbs(dgAbs(obbAabbInfo[2][2]) - obbAabbInfo.m_absDir[2][2]) < dgFloat32 (1.0e-4f));
dgAssert (dgAbs(dgAbs(obbAabbInfo[0][1]) - obbAabbInfo.m_absDir[1][0]) < dgFloat32 (1.0e-4f));
dgAssert (dgAbs(dgAbs(obbAabbInfo[0][2]) - obbAabbInfo.m_absDir[2][0]) < dgFloat32 (1.0e-4f));
dgAssert (dgAbs(dgAbs(obbAabbInfo[1][2]) - obbAabbInfo.m_absDir[2][1]) < dgFloat32 (1.0e-4f));
if (m_aabb) {
dgFloat32 distance[DG_STACK_DEPTH];
const dgNode* stackPool[DG_STACK_DEPTH];
const dgInt32 stride = sizeof (dgTriplex) / sizeof (dgFloat32);
const dgTriplex* const vertexArray = (dgTriplex*) m_localVertex;
dgAssert (boxDistanceTravel.m_w == dgFloat32 (0.0f));
if (boxDistanceTravel.DotProduct(boxDistanceTravel).GetScalar() < dgFloat32 (1.0e-8f)) {
dgInt32 stack = 1;
stackPool[0] = m_aabb;
distance[0] = m_aabb->BoxPenetration(obbAabbInfo, vertexArray);
if (distance[0] <= dgFloat32(0.0f)) {
obbAabbInfo.m_separationDistance = dgMin(obbAabbInfo.m_separationDistance[0], -distance[0]);
}
while (stack) {
stack --;
dgFloat32 dist = distance[stack];
if (dist > dgFloat32 (0.0f)) {
const dgNode* const me = stackPool[stack];
if (me->m_left.IsLeaf()) {
dgInt32 index = dgInt32 (me->m_left.GetIndex());
dgInt32 vCount = dgInt32 (me->m_left.GetCount());
if (vCount > 0) {
const dgInt32* const indices = &m_indices[index];
dgInt32 normalIndex = indices[vCount + 1];
dgVector faceNormal (&vertexArray[normalIndex].m_x);
faceNormal = faceNormal & dgVector::m_triplexMask;
dgFloat32 dist1 = obbAabbInfo.PolygonBoxDistance (faceNormal, vCount, indices, stride, &vertexArray[0].m_x);
if (dist1 > dgFloat32 (0.0f)) {
obbAabbInfo.m_separationDistance = dgFloat32(0.0f);
dgAssert (vCount >= 3);
if (callback(context, &vertexArray[0].m_x, sizeof (dgTriplex), indices, vCount, dist1) == t_StopSearh) {
return;
}
} else {
obbAabbInfo.m_separationDistance = dgMin(obbAabbInfo.m_separationDistance[0], -dist1);
}
}
} else {
const dgNode* const node = me->m_left.GetNode(m_aabb);
dgFloat32 dist1 = node->BoxPenetration(obbAabbInfo, vertexArray);
if (dist1 > dgFloat32 (0.0f)) {
dgInt32 j = stack;
for ( ; j && (dist1 > distance[j - 1]); j --) {
stackPool[j] = stackPool[j - 1];
distance[j] = distance[j - 1];
}
dgAssert (stack < DG_STACK_DEPTH);
stackPool[j] = node;
distance[j] = dist1;
stack++;
} else {
obbAabbInfo.m_separationDistance = dgMin(obbAabbInfo.m_separationDistance[0], -dist1);
}
}
if (me->m_right.IsLeaf()) {
dgInt32 index = dgInt32 (me->m_right.GetIndex());
dgInt32 vCount = dgInt32 (me->m_right.GetCount());
if (vCount > 0) {
const dgInt32* const indices = &m_indices[index];
dgInt32 normalIndex = indices[vCount + 1];
dgVector faceNormal (&vertexArray[normalIndex].m_x);
faceNormal = faceNormal & dgVector::m_triplexMask;
dgFloat32 dist1 = obbAabbInfo.PolygonBoxDistance (faceNormal, vCount, indices, stride, &vertexArray[0].m_x);
if (dist1 > dgFloat32 (0.0f)) {
dgAssert (vCount >= 3);
obbAabbInfo.m_separationDistance = dgFloat32(0.0f);
if (callback(context, &vertexArray[0].m_x, sizeof (dgTriplex), indices, vCount, dist1) == t_StopSearh) {
return;
}
} else {
obbAabbInfo.m_separationDistance = dgMin(obbAabbInfo.m_separationDistance[0], -dist1);
}
}
} else {
const dgNode* const node = me->m_right.GetNode(m_aabb);
dgFloat32 dist1 = node->BoxPenetration(obbAabbInfo, vertexArray);
if (dist1 > dgFloat32 (0.0f)) {
dgInt32 j = stack;
for ( ; j && (dist1 > distance[j - 1]); j --) {
stackPool[j] = stackPool[j - 1];
distance[j] = distance[j - 1];
}
dgAssert (stack < DG_STACK_DEPTH);
stackPool[j] = node;
distance[j] = dist1;
stack++;
} else {
obbAabbInfo.m_separationDistance = dgMin(obbAabbInfo.m_separationDistance[0], -dist1);
}
}
}
}
} else {
dgFastRayTest ray (dgVector (dgFloat32 (0.0f)), boxDistanceTravel);
dgFastRayTest obbRay (dgVector (dgFloat32 (0.0f)), obbAabbInfo.UnrotateVector(boxDistanceTravel));
dgInt32 stack = 1;
stackPool[0] = m_aabb;
distance [0] = m_aabb->BoxIntersect (ray, obbRay, obbAabbInfo, vertexArray);
while (stack) {
stack --;
const dgFloat32 dist = distance[stack];
const dgNode* const me = stackPool[stack];
if (dist < dgFloat32 (1.0f)) {
if (me->m_left.IsLeaf()) {
dgInt32 index = dgInt32 (me->m_left.GetIndex());
dgInt32 vCount = dgInt32 (me->m_left.GetCount());
if (vCount > 0) {
const dgInt32* const indices = &m_indices[index];
dgInt32 normalIndex = indices[vCount + 1];
dgVector faceNormal (&vertexArray[normalIndex].m_x);
faceNormal = faceNormal & dgVector::m_triplexMask;
dgFloat32 hitDistance = obbAabbInfo.PolygonBoxRayDistance (faceNormal, vCount, indices, stride, &vertexArray[0].m_x, ray);
if (hitDistance < dgFloat32 (1.0f)) {
dgAssert (vCount >= 3);
if (callback(context, &vertexArray[0].m_x, sizeof (dgTriplex), indices, vCount, hitDistance) == t_StopSearh) {
return;
}
}
}
} else {
const dgNode* const node = me->m_left.GetNode(m_aabb);
dgFloat32 dist1 = node->BoxIntersect (ray, obbRay, obbAabbInfo, vertexArray);
if (dist1 < dgFloat32 (1.0f)) {
dgInt32 j = stack;
for ( ; j && (dist1 > distance[j - 1]); j --) {
stackPool[j] = stackPool[j - 1];
distance[j] = distance[j - 1];
}
dgAssert (stack < DG_STACK_DEPTH);
stackPool[j] = node;
distance[j] = dist1;
stack++;
}
}
if (me->m_right.IsLeaf()) {
dgInt32 index = dgInt32 (me->m_right.GetIndex());
dgInt32 vCount = dgInt32 (me->m_right.GetCount());
if (vCount > 0) {
const dgInt32* const indices = &m_indices[index];
dgInt32 normalIndex = indices[vCount + 1];
dgVector faceNormal (&vertexArray[normalIndex].m_x);
faceNormal = faceNormal & dgVector::m_triplexMask;
dgFloat32 hitDistance = obbAabbInfo.PolygonBoxRayDistance (faceNormal, vCount, indices, stride, &vertexArray[0].m_x, ray);
if (hitDistance < dgFloat32 (1.0f)) {
dgAssert (vCount >= 3);
if (callback(context, &vertexArray[0].m_x, sizeof (dgTriplex), indices, vCount, hitDistance) == t_StopSearh) {
return;
}
}
}
} else {
const dgNode* const node = me->m_right.GetNode(m_aabb);
dgFloat32 dist1 = node->BoxIntersect (ray, obbRay, obbAabbInfo, vertexArray);
if (dist1 < dgFloat32 (1.0f)) {
dgInt32 j = stack;
for ( ; j && (dist1 > distance[j - 1]); j --) {
stackPool[j] = stackPool[j - 1];
distance[j] = distance[j - 1];
}
dgAssert (stack < DG_STACK_DEPTH);
stackPool[j] = node;
distance[j] = dist1;
stack ++;
}
}
}
}
}
}
}