Files
scummvm-cursorfix/engines/hpl1/engine/libraries/newton/physics/dgCollisionCompound.cpp
2026-02-02 04:50:13 +01:00

2319 lines
70 KiB
C++

/* Copyright (c) <2003-2011> <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 "dgCollisionCompound.h"
#include "dgCollisionBVH.h"
#include "dgCollisionConvex.h"
#include "dgCollisionConvexModifier.h"
#include "dgCollisionEllipse.h"
#include "dgCollisionHeightField.h"
#include "dgWorld.h"
#include "hpl1/engine/libraries/newton/core/dg.h"
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
dgCollisionCompound::OOBBTestData::OOBBTestData(const dgMatrix &matrix) : m_matrix(matrix) {
for (dgInt32 i = 0; i < 3; i++) {
m_absMatrix[i][3] = dgFloat32(0.0f);
dgVector dir(dgFloat32(0.0f), dgFloat32(0.0f), dgFloat32(0.0f),
dgFloat32(0.0f));
dir[i] = dgFloat32(1.0f);
for (dgInt32 j = 0; j < 3; j++) {
m_absMatrix[i][j] = dgAbsf(m_matrix[i][j]);
dgVector axis(dir * m_matrix[j]);
m_crossAxis[i][j] = axis;
m_crossAxisAbs[i][j] = dgVector(dgAbsf(axis.m_x), dgAbsf(axis.m_y),
dgAbsf(axis.m_z), dgFloat32(0.0f));
m_crossAxisDotAbs[i][j] = dgVector(dgAbsf(axis % matrix[0]),
dgAbsf(axis % matrix[1]), dgAbsf(axis % matrix[2]), dgFloat32(0.0f));
}
}
m_absMatrix[3][3] = dgFloat32(1.0f);
}
dgCollisionCompound::OOBBTestData::OOBBTestData(const dgMatrix &matrix,
const dgVector &p0, const dgVector &p1) : m_matrix(matrix), m_localP0(p0), m_localP1(p1) {
m_size = (m_localP1 - m_localP0).Scale(dgFloat32(0.5f));
m_origin = (m_localP1 + m_localP0).Scale(dgFloat32(0.5f));
for (dgInt32 i = 0; i < 3; i++) {
m_absMatrix[i][3] = dgFloat32(0.0f);
dgVector dir(dgFloat32(0.0f), dgFloat32(0.0f), dgFloat32(0.0f),
dgFloat32(0.0f));
dir[i] = dgFloat32(1.0f);
for (dgInt32 j = 0; j < 3; j++) {
m_absMatrix[i][j] = dgAbsf(m_matrix[i][j]);
m_crossAxis[i][j] = dir * m_matrix[j];
}
}
m_absMatrix[3][3] = dgFloat32(1.0f);
dgVector size(m_absMatrix.RotateVector(m_size));
dgVector origin(m_matrix.TransformVector(m_origin));
m_aabbP0 = origin - size;
m_aabbP1 = origin + size;
for (dgInt32 i = 0; i < 3; i++) {
for (dgInt32 j = 0; j < 3; j++) {
dgFloat32 d;
dgFloat32 c;
dgVector &axis = m_crossAxis[i][j];
d = m_size.m_x * dgAbsf(axis % m_matrix[0]) + m_size.m_y * dgAbsf(axis % m_matrix[1]) + m_size.m_z * dgAbsf(axis % m_matrix[2]) + dgFloat32(1.0e-3f);
c = origin % axis;
m_extends[i][j] = dgVector(c - d, c + d, dgFloat32(0.0f),
dgFloat32(0.0f));
NEWTON_ASSERT(m_extends[i][j].m_x <= m_extends[i][j].m_y);
m_crossAxisAbs[i][j] = dgVector(dgAbsf(axis.m_x), dgAbsf(axis.m_y),
dgAbsf(axis.m_z), dgFloat32(0.0f));
}
}
}
dgCollisionCompound::dgNodeBase::dgNodeBase() {
m_id = -1;
m_shape = NULL;
m_left = NULL;
m_right = NULL;
}
dgCollisionCompound::dgNodeBase::dgNodeBase(dgCollisionConvex *const shape,
dgInt32 id) {
m_id = id;
m_left = NULL;
m_right = NULL;
m_parent = NULL;
m_shape = shape;
m_shape->AddRef();
m_type = m_leaf;
m_shape->CalcAABB(shape->GetOffsetMatrix(), m_p0, m_p1);
m_p0.m_w = 0.0f;
m_p1.m_w = 0.0f;
m_size = (m_p1 - m_p0).Scale(dgFloat32(0.5f));
m_origin = (m_p1 + m_p0).Scale(dgFloat32(0.5f));
dgVector size1(m_size.m_y, m_size.m_z, m_size.m_x, dgFloat32(0.0f));
m_area = m_size % size1;
}
dgCollisionCompound::dgNodeBase::dgNodeBase(dgNodeBase *const left,
dgNodeBase *const right, dgInt32 id) {
m_id = id;
m_left = left;
m_right = right;
m_parent = NULL;
m_type = m_node;
m_shape = NULL;
m_p0.m_x = GetMin(left->m_p0.m_x, right->m_p0.m_x);
m_p0.m_y = GetMin(left->m_p0.m_y, right->m_p0.m_y);
m_p0.m_z = GetMin(left->m_p0.m_z, right->m_p0.m_z);
m_p1.m_x = GetMax(left->m_p1.m_x, right->m_p1.m_x);
m_p1.m_y = GetMax(left->m_p1.m_y, right->m_p1.m_y);
m_p1.m_z = GetMax(left->m_p1.m_z, right->m_p1.m_z);
m_p0.m_w = 0.0f;
m_p1.m_w = 0.0f;
m_size = (m_p1 - m_p0).Scale(dgFloat32(0.5f));
m_origin = (m_p1 + m_p0).Scale(dgFloat32(0.5f));
dgVector size1(m_size.m_y, m_size.m_z, m_size.m_x, dgFloat32(0.0f));
m_area = m_size % size1;
}
dgCollisionCompound::dgNodeBase::~dgNodeBase() {
if (m_shape) {
m_shape->Release();
}
if (m_left) {
delete m_left;
}
if (m_right) {
delete m_right;
}
}
void dgCollisionCompound::dgNodeBase::reset() {
m_id = 0; // FIXME: Maybe should reset to -1
m_left = NULL;
m_right = NULL;
m_parent = NULL;
m_type = 0;
m_shape = NULL;
m_p0 = dgVector(0.0f, 0.0f, 0.0f, 0.0f);
m_p1 = dgVector(0.0f, 0.0f, 0.0f, 0.0f);
m_size = dgVector(0.0f, 0.0f, 0.0f, 0.0f);
m_origin = dgVector(0.0f, 0.0f, 0.0f, 0.0f);
m_area = 0.0f;
}
bool dgCollisionCompound::dgNodeBase::BoxTest(const OOBBTestData &data,
const dgNodeBase *const otherNode) const {
dgVector otherOrigin(data.m_matrix.TransformVector(otherNode->m_origin));
dgVector otherSize(data.m_absMatrix.RotateVector(otherNode->m_size));
dgVector otherP0(otherOrigin - otherSize);
dgVector otherP1(otherOrigin + otherSize);
if (dgOverlapTest(m_p0, m_p1, otherP0, otherP1)) {
dgVector origin(data.m_matrix.UntransformVector(m_origin));
dgVector size(data.m_absMatrix.UnrotateVector(m_size));
dgVector p0(origin - size);
dgVector p1(origin + size);
if (dgOverlapTest(p0, p1, otherNode->m_p0, otherNode->m_p1)) {
for (dgInt32 i = 0; i < 3; i++) {
for (dgInt32 j = 0; j < 3; j++) {
dgFloat32 x0;
dgFloat32 x1;
dgFloat32 z0;
dgFloat32 z1;
dgFloat32 d;
dgFloat32 c;
const dgVector &axis = data.m_crossAxis[i][j];
const dgVector &axisAbs = data.m_crossAxisAbs[i][j];
d = m_size.m_x * axisAbs.m_x + m_size.m_y * axisAbs.m_y + m_size.m_z * axisAbs.m_z + dgFloat32(1.0e-3f);
c = m_origin % axis;
x0 = c - d;
x1 = c + d;
NEWTON_ASSERT(x0 <= x1);
const dgVector &axisDotAbs = data.m_crossAxisDotAbs[i][j];
d = otherNode->m_size.m_x * axisDotAbs.m_x + otherNode->m_size.m_y * axisDotAbs.m_y + otherNode->m_size.m_z * axisDotAbs.m_z + dgFloat32(1.0e-3f);
c = otherOrigin % axis;
z0 = c - d;
z1 = c + d;
NEWTON_ASSERT(z0 <= z1);
if ((x1 < z0) || (x0 > z1)) {
return false;
}
}
}
return true;
}
}
return false;
}
bool dgCollisionCompound::dgNodeBase::BoxTest(const OOBBTestData &data) const {
if (dgOverlapTest(data.m_aabbP0, data.m_aabbP1, m_p0, m_p1)) {
dgVector origin(data.m_matrix.UntransformVector(m_origin));
dgVector size(data.m_absMatrix.UnrotateVector(m_size));
dgVector p0(origin - size);
dgVector p1(origin + size);
if (dgOverlapTest(p0, p1, data.m_localP0, data.m_localP1)) {
for (dgInt32 i = 0; i < 3; i++) {
for (dgInt32 j = 0; j < 3; j++) {
dgFloat32 x0;
dgFloat32 x1;
dgFloat32 d;
dgFloat32 c;
const dgVector &axis = data.m_crossAxisAbs[i][j];
d = m_size.m_x * axis.m_x + m_size.m_y * axis.m_y + m_size.m_z * axis.m_z + dgFloat32(1.0e-3f);
c = m_origin % data.m_crossAxis[i][j];
x0 = c - d;
x1 = c + d;
NEWTON_ASSERT(x0 <= x1);
const dgVector &extend = data.m_extends[i][j];
if ((x1 < extend.m_x) || (x0 > extend.m_y)) {
return false;
}
}
}
return true;
}
}
return false;
}
dgFloat32 dgCollisionCompound::dgNodeBase::BoxClosestDistance(
const dgVector *const points, dgInt32 count) const {
dgVector box[8];
box[0] = dgVector(m_p0.m_x, m_p0.m_y, m_p0.m_z, dgFloat32(0.0f));
box[1] = dgVector(m_p0.m_x, m_p0.m_y, m_p1.m_z, dgFloat32(0.0f));
box[2] = dgVector(m_p0.m_x, m_p1.m_y, m_p0.m_z, dgFloat32(0.0f));
box[3] = dgVector(m_p0.m_x, m_p1.m_y, m_p1.m_z, dgFloat32(0.0f));
box[4] = dgVector(m_p1.m_x, m_p0.m_y, m_p0.m_z, dgFloat32(0.0f));
box[5] = dgVector(m_p1.m_x, m_p0.m_y, m_p1.m_z, dgFloat32(0.0f));
box[6] = dgVector(m_p1.m_x, m_p1.m_y, m_p0.m_z, dgFloat32(0.0f));
box[7] = dgVector(m_p1.m_x, m_p1.m_y, m_p1.m_z, dgFloat32(0.0f));
dgFloat32 dist = dgFloat32(1.0e10f);
for (dgInt32 i = 0; i < count; i++) {
for (dgInt32 j = 0; j < 8; j++) {
dgVector dp(points[i] - box[j]);
dgFloat32 dist1 = dp % dp;
if (dist1 < dist) {
dist = dist1;
}
}
}
return dist;
}
dgCollisionCompound::dgCollisionCompound(dgWorld *world) : dgCollision(world->GetAllocator(), 0, dgGetIdentityMatrix(),
m_compoundCollision) {
m_world = world;
m_root = NULL;
m_count = 0;
}
dgCollisionCompound::dgCollisionCompound(dgInt32 count,
dgCollisionConvex *const shapeArray[], dgWorld *world) : dgCollision(world->GetAllocator(), 0, dgGetIdentityMatrix(),
m_compoundCollision) {
m_world = world;
m_root = NULL;
if (count) {
m_root = BuildTree(count, shapeArray);
}
Init(count, shapeArray);
}
dgCollisionCompound::dgCollisionCompound(const dgCollisionCompound &source) : dgCollision(source.GetAllocator(), 0, dgGetIdentityMatrix(),
m_compoundCollision) {
int stack;
dgNodeBase *pool[DG_COMPOUND_STACK_DEPTH];
dgNodeBase **parent[DG_COMPOUND_STACK_DEPTH];
m_root = NULL;
m_world = source.m_world;
parent[0] = &m_root;
pool[0] = source.m_root;
stack = 1;
while (stack) {
dgNodeBase *node;
dgNodeBase **parentNode;
stack--;
node = pool[stack];
parentNode = parent[stack];
if (node->m_type == m_leaf) {
*parentNode = new (m_allocator) dgNodeBase(node->m_shape, node->m_id);
} else {
dgNodeBase *newNode;
newNode = new (m_allocator) dgNodeBase(*node);
if (!m_root) {
m_root = newNode;
}
*parentNode = newNode;
pool[stack] = node->m_left;
parent[stack] = &newNode->m_left;
stack++;
pool[stack] = node->m_right;
parent[stack] = &newNode->m_right;
stack++;
}
}
Init(source.m_count, source.m_array);
m_preCollisionFilter = source.m_preCollisionFilter;
}
dgCollisionCompound::dgCollisionCompound(dgWorld *const world,
dgDeserialize deserialization, void *const userData) : dgCollision(world, deserialization, userData) {
dgInt32 stack;
dgInt32 count;
dgInt32 data[4];
dgNodeBase *pool[DG_COMPOUND_STACK_DEPTH];
// dgNodeBase* parentPool[DG_COMPOUND_STACK_DEPTH];
deserialization(userData, data, sizeof(data));
count = data[0];
m_world = world;
dgStack<dgCollisionConvex *> array(data[0]);
for (dgInt32 i = 0; i < count; i++) {
dgCollision *collision;
collision = world->CreateFromSerialization(deserialization, userData);
array[i] = (dgCollisionConvex *)collision;
}
struct Data : public dgNodeBase {
Data() {
}
~Data() {
this->reset();
}
dgInt8 m_padding[128];
};
m_root = NULL;
Data nodeInfo;
for (dgInt32 i = 0; i < 2 * count - 1; i++) {
dgNodeBase *newNode;
deserialization(userData, &nodeInfo.m_p0, sizeof(dgNodeBase));
if (nodeInfo.m_type == m_leaf) {
dgNodeBase *cell;
cell = new (m_allocator) dgNodeBase(nodeInfo);
cell->m_shape = array[nodeInfo.m_id];
cell->m_shape->AddRef();
newNode = cell;
} else {
dgNodeBase *node;
node = new (m_allocator) dgNodeBase((dgNodeBase &)nodeInfo);
node->m_left = NULL;
node->m_right = NULL;
newNode = node;
}
if (!m_root) {
m_root = newNode;
} else {
stack = 1;
pool[0] = m_root;
while (stack) {
dgNodeBase *node;
stack--;
node = pool[stack];
// if (node->m_id == dgInt32 (newNode->m_parent)) {
if (((dgNodeBase *)dgInt64(node->m_id)) == newNode->m_parent) {
if (node->m_left == NULL) {
node->m_left = newNode;
} else {
NEWTON_ASSERT(!node->m_right);
node->m_right = newNode;
}
break;
}
if (node->m_type == m_node) {
if (node->m_left) {
pool[stack] = node->m_left;
stack++;
}
if (node->m_right) {
pool[stack] = node->m_right;
stack++;
}
}
}
}
}
Init(count, &array[0]);
for (dgInt32 i = 0; i < count; i++) {
world->ReleaseCollision(array[i]);
}
}
dgCollisionCompound::~dgCollisionCompound() {
if (m_root) {
delete m_root;
}
for (dgInt32 i = 0; i < m_count; i++) {
m_world->ReleaseCollision(m_array[i]);
}
m_allocator->Free(m_array);
}
void dgCollisionCompound::Init(dgInt32 count,
dgCollisionConvex *const shapeArray[]) {
m_count = count;
m_rtti |= dgCollisionCompound_RTTI;
m_preCollisionFilter = NULL;
m_array = (dgCollisionConvex **)m_allocator->Malloc(
m_count * dgInt32(sizeof(dgCollisionConvex *)));
for (dgInt32 i = 0; i < m_count; i++) {
m_array[i] = shapeArray[i];
m_array[i]->AddRef();
}
m_boxMinRadius = GetMin(m_root->m_size.m_x, m_root->m_size.m_y,
m_root->m_size.m_z);
m_boxMaxRadius = dgSqrt(m_root->m_size % m_root->m_size);
LinkParentNodes();
}
void dgCollisionCompound::LinkParentNodes() {
dgInt32 stack;
dgNodeBase *pool[DG_COMPOUND_STACK_DEPTH];
dgNodeBase *parentPool[DG_COMPOUND_STACK_DEPTH];
pool[0] = m_root;
parentPool[0] = NULL;
stack = 1;
while (stack) {
dgNodeBase *node;
dgNodeBase *parent;
stack--;
node = pool[stack];
parent = parentPool[stack];
node->m_parent = parent;
if (node->m_type == m_node) {
parentPool[stack] = node;
pool[stack] = node->m_right;
stack++;
parentPool[stack] = node;
pool[stack] = node->m_left;
stack++;
}
}
}
void dgCollisionCompound::SetCollisionBBox(const dgVector &p0__,
const dgVector &p1__) {
NEWTON_ASSERT(0);
}
dgInt32 dgCollisionCompound::CalculateSignature() const {
NEWTON_ASSERT(0);
return 0;
}
void dgCollisionCompound::CalcAABB(const dgMatrix &matrix, dgVector &p0,
dgVector &p1) const {
dgVector origin(matrix.TransformVector(m_root->m_origin));
dgVector size(
m_root->m_size.m_x * dgAbsf(matrix[0][0]) + m_root->m_size.m_y * dgAbsf(matrix[1][0]) + m_root->m_size.m_z * dgAbsf(matrix[2][0]) + DG_MAX_COLLISION_PADDING,
m_root->m_size.m_x * dgAbsf(matrix[0][1]) + m_root->m_size.m_y * dgAbsf(matrix[1][1]) + m_root->m_size.m_z * dgAbsf(matrix[2][1]) + DG_MAX_COLLISION_PADDING,
m_root->m_size.m_x * dgAbsf(matrix[0][2]) + m_root->m_size.m_y * dgAbsf(matrix[1][2]) + m_root->m_size.m_z * dgAbsf(matrix[2][2]) + DG_MAX_COLLISION_PADDING,
dgFloat32(0.0f));
p0 = origin - size;
p1 = origin + size;
}
void dgCollisionCompound::CalcAABBSimd(const dgMatrix &matrix, dgVector &p0,
dgVector &p1) const {
dgVector origin(matrix.TransformVector(m_root->m_origin));
dgVector size(
m_root->m_size.m_x * dgAbsf(matrix[0][0]) + m_root->m_size.m_y * dgAbsf(matrix[1][0]) + m_root->m_size.m_z * dgAbsf(matrix[2][0]) + DG_MAX_COLLISION_PADDING,
m_root->m_size.m_x * dgAbsf(matrix[0][1]) + m_root->m_size.m_y * dgAbsf(matrix[1][1]) + m_root->m_size.m_z * dgAbsf(matrix[2][1]) + DG_MAX_COLLISION_PADDING,
m_root->m_size.m_x * dgAbsf(matrix[0][2]) + m_root->m_size.m_y * dgAbsf(matrix[1][2]) + m_root->m_size.m_z * dgAbsf(matrix[2][2]) + DG_MAX_COLLISION_PADDING,
dgFloat32(0.0f));
p0 = origin - size;
p1 = origin + size;
}
// void dgCollisionCompound::dgMatrix& matrix, DebugCollisionMeshCallback callback) const
void dgCollisionCompound::DebugCollision(const dgMatrix &matrix,
OnDebugCollisionMeshCallback callback, void *const userData) const {
for (dgInt32 i = 0; i < m_count; i++) {
m_array[i]->DebugCollision(matrix, callback, userData);
}
}
dgFloat32 dgCollisionCompound::RayCast(const dgVector &localP0,
const dgVector &localP1, dgContactPoint &contactOut,
OnRayPrecastAction preFilter, const dgBody *const body,
void *const userData) const {
const dgNodeBase *stackPool[DG_COMPOUND_STACK_DEPTH];
if (!m_root) {
return dgFloat32(1.2f);
}
dgInt32 stack = 1;
stackPool[0] = m_root;
dgFloat32 maxParam = dgFloat32(1.2f);
dgFastRayTest ray(localP0, localP1);
while (stack) {
stack--;
const dgNodeBase *const me = stackPool[stack];
if (me && ray.BoxTest(me->m_p0, me->m_p1)) {
if (me->m_type == m_leaf) {
dgFloat32 param;
dgContactPoint tmpContactOut;
dgCollisionConvex *const shape = me->m_shape;
dgVector p0(shape->m_offset.UntransformVector(localP0));
dgVector p1(shape->m_offset.UntransformVector(localP1));
// param = shape->RayCast (p0, p1, tmpContactOut, NULL, NULL, NULL);
param = shape->RayCast(p0, p1, tmpContactOut, preFilter, body,
userData);
if (param < maxParam) {
maxParam = param;
contactOut.m_normal = shape->m_offset.RotateVector(
tmpContactOut.m_normal);
;
contactOut.m_userId = tmpContactOut.m_userId;
ray.Reset(maxParam);
}
} else {
NEWTON_ASSERT(me->m_type == m_node);
stackPool[stack] = me->m_left;
stack++;
NEWTON_ASSERT(stack < dgInt32(sizeof(stackPool) / sizeof(dgNodeBase *)));
stackPool[stack] = me->m_right;
stack++;
NEWTON_ASSERT(stack < dgInt32(sizeof(stackPool) / sizeof(dgNodeBase *)));
}
}
}
return maxParam;
}
dgFloat32 dgCollisionCompound::RayCastSimd(const dgVector &localP0,
const dgVector &localP1, dgContactPoint &contactOut,
OnRayPrecastAction preFilter, const dgBody *const body,
void *const userData) const {
const dgNodeBase *stackPool[DG_COMPOUND_STACK_DEPTH];
if (!m_root) {
return dgFloat32(1.2f);
}
dgInt32 stack = 1;
stackPool[0] = m_root;
dgFloat32 maxParam = dgFloat32(1.2f);
dgFastRayTest ray(localP0, localP1);
while (stack) {
stack--;
const dgNodeBase *const me = stackPool[stack];
if (me && ray.BoxTestSimd(me->m_p0, me->m_p1)) {
if (me->m_type == m_leaf) {
dgContactPoint tmpContactOut;
dgCollisionConvex *const shape = me->m_shape;
dgVector p0(shape->m_offset.UntransformVector(localP0));
dgVector p1(shape->m_offset.UntransformVector(localP1));
// param = shape->RayCastSimd (p0, p1, tmpContactOut, NULL, NULL, NULL);
dgFloat32 param = shape->RayCastSimd(p0, p1, tmpContactOut, preFilter,
body, userData);
if (param < maxParam) {
maxParam = param;
contactOut.m_normal = shape->m_offset.RotateVector(
tmpContactOut.m_normal);
contactOut.m_userId = tmpContactOut.m_userId;
ray.Reset(maxParam);
}
} else {
NEWTON_ASSERT(me->m_type == m_node);
stackPool[stack] = me->m_left;
stack++;
NEWTON_ASSERT(stack < dgInt32(sizeof(stackPool) / sizeof(dgNodeBase *)));
stackPool[stack] = me->m_right;
stack++;
NEWTON_ASSERT(stack < dgInt32(sizeof(stackPool) / sizeof(dgNodeBase *)));
}
}
}
return maxParam;
}
dgFloat32 dgCollisionCompound::GetVolume() const {
dgFloat32 volume = dgFloat32(0.0f);
for (dgInt32 i = 0; i < m_count; i++) {
volume += m_array[i]->GetVolume();
}
return volume;
}
dgFloat32 dgCollisionCompound::GetBoxMinRadius() const {
return m_boxMinRadius;
}
dgFloat32 dgCollisionCompound::GetBoxMaxRadius() const {
return m_boxMaxRadius;
}
dgVector dgCollisionCompound::CalculateVolumeIntegral(
const dgMatrix &globalMatrix, GetBuoyancyPlane bouyancyPlane,
void *const context) const {
dgInt32 i;
dgFloat32 scale;
dgVector totalVolume(dgFloat32(0.0f), dgFloat32(0.0f), dgFloat32(0.0f),
dgFloat32(0.0f));
for (i = 0; i < m_count; i++) {
dgMatrix matrix(m_array[i]->m_offset * globalMatrix);
// dgVector vol (m_array[i]->CalculateVolumeIntegral (m_collisionMatrix[i], bouyancyPlane, context));
dgVector vol(
m_array[i]->CalculateVolumeIntegral(matrix, bouyancyPlane, context));
totalVolume.m_x += vol.m_x * vol.m_w;
totalVolume.m_y += vol.m_y * vol.m_w;
totalVolume.m_z += vol.m_z * vol.m_w;
totalVolume.m_w += vol.m_w;
}
scale = dgFloat32(1.0f) / (totalVolume.m_w + dgFloat32(1.0e-6f));
totalVolume.m_x *= scale;
totalVolume.m_y *= scale;
totalVolume.m_z *= scale;
return totalVolume;
}
void dgCollisionCompound::CalculateInertia(dgVector &inertia,
dgVector &origin) const {
dgInt32 i;
dgCollisionConvex *collision;
dgFloat32 invVolume;
dgFloat32 totalVolume;
dgVector tmpOrigin;
dgVector tmpInertia;
dgVector tmpCrossInertia;
dgVector totalOrigin(dgFloat32(0.0f), dgFloat32(0.0f), dgFloat32(0.0f),
dgFloat32(0.0f));
dgVector totalInertia(dgFloat32(0.0f), dgFloat32(0.0f), dgFloat32(0.0f),
dgFloat32(0.0f));
dgVector totalCrossInertia(dgFloat32(0.0f), dgFloat32(0.0f), dgFloat32(0.0f),
dgFloat32(0.0f));
#define DG_MIN_SIDE dgFloat32(1.0e-2f)
#define DG_MIN_VOLUME (DG_MIN_SIDE * DG_MIN_SIDE * DG_MIN_SIDE)
totalVolume = dgFloat32(0.0f);
for (i = 0; i < m_count; i++) {
collision = m_array[i];
totalVolume += collision->CalculateMassProperties(tmpInertia,
tmpCrossInertia, tmpOrigin);
totalOrigin += tmpOrigin;
totalInertia += tmpInertia;
totalCrossInertia += tmpCrossInertia;
}
invVolume = dgFloat32(1.0f) / GetMax(totalVolume, DG_MIN_VOLUME);
origin = totalOrigin.Scale(invVolume);
totalInertia = totalInertia.Scale(invVolume);
totalCrossInertia = totalCrossInertia.Scale(invVolume);
inertia.m_x = totalInertia.m_x - (origin.m_y * origin.m_y + origin.m_z * origin.m_z);
inertia.m_y = totalInertia.m_y - (origin.m_z * origin.m_z + origin.m_x * origin.m_x);
inertia.m_z = totalInertia.m_z - (origin.m_x * origin.m_x + origin.m_y * origin.m_y);
// crossInertia.m_x += totalCrossInertia.m_x + origin.m_y * origin.m_z;
// crossInertia.m_y += totalCrossInertia.m_x + origin.m_z * origin.m_x;
// crossInertia.m_z += totalCrossInertia.m_x + origin.m_x * origin.m_y;
NEWTON_ASSERT(inertia[0] > 0.0f);
NEWTON_ASSERT(inertia[1] > 0.0f);
NEWTON_ASSERT(inertia[2] > 0.0f);
}
void dgCollisionCompound::AddCollision(dgCollisionConvex *part) {
NEWTON_ASSERT(0);
/*
dgInt32 i;
dgInt8 *ptr;
dgCollisionConvex** array;
dgMatrix* collisionMatrix;
AABB* aabb;
NEWTON_ASSERT (0);
if (m_count >= m_maxCount) {
m_maxCount = m_maxCount * 2;
ptr = (dgInt8*) m_allocator->Malloc (m_maxCount * (sizeof (dgMatrix) + sizeof (dgCollisionConvex*) + sizeof(AABB)));
collisionMatrix = (dgMatrix*) ptr;
aabb = (AABB*) &ptr [m_maxCount * sizeof (dgMatrix)];
array = (dgCollisionConvex**) &ptr [m_maxCount * (sizeof (dgMatrix) + sizeof(AABB))];
for (i = 0; i < m_count; i ++) {
array[i] = m_array[i];
collisionMatrix[i] = m_collisionMatrix[i];
aabb[i] = m_aabb[i];
}
m_allocator->Free (m_collisionMatrix);
m_aabb = aabb;
m_array = array;
m_collisionMatrix = collisionMatrix;
}
m_array[m_count] = part;
m_array[m_count]->AddRef();
m_count ++;
*/
}
void dgCollisionCompound::RemoveCollision(dgNodeBase *treeNode) {
m_array[treeNode->m_id]->Release();
m_count--;
m_array[treeNode->m_id] = m_array[m_count];
if (!treeNode->m_parent) {
delete (m_root);
m_root = NULL;
} else if (!treeNode->m_parent->m_parent) {
dgNodeBase *const root = m_root;
if (treeNode->m_parent->m_left == treeNode) {
m_root = treeNode->m_parent->m_right;
treeNode->m_parent->m_right = NULL;
} else {
m_root = treeNode->m_parent->m_left;
treeNode->m_parent->m_left = NULL;
}
m_root->m_parent = NULL;
delete (root);
} else {
dgNodeBase *const root = treeNode->m_parent->m_parent;
if (treeNode->m_parent == root->m_left) {
if (treeNode->m_parent->m_right == treeNode) {
root->m_left = treeNode->m_parent->m_left;
treeNode->m_parent->m_left = NULL;
} else {
root->m_left = treeNode->m_parent->m_right;
treeNode->m_parent->m_right = NULL;
}
root->m_left->m_parent = root;
} else {
if (treeNode->m_parent->m_right == treeNode) {
root->m_right = treeNode->m_parent->m_left;
treeNode->m_parent->m_left = NULL;
} else {
root->m_right = treeNode->m_parent->m_right;
treeNode->m_parent->m_right = NULL;
}
root->m_right->m_parent = root;
}
delete (treeNode->m_parent);
}
}
dgVector dgCollisionCompound::SupportVertex(const dgVector &dir) const {
dgInt32 ix;
dgInt32 iy;
dgInt32 iz;
dgInt32 stack;
dgFloat32 maxProj;
dgFloat32 aabbProjection[DG_COMPOUND_STACK_DEPTH];
const dgNodeBase *stackPool[DG_COMPOUND_STACK_DEPTH];
stack = 1;
stackPool[0] = m_root;
aabbProjection[0] = dgFloat32(1.0e10f);
maxProj = dgFloat32(-1.0e20f);
dgVector searchDir(m_offset.UnrotateVector(dir));
ix = (searchDir[0] > dgFloat32(0.0f)) ? 1 : 0;
iy = (searchDir[1] > dgFloat32(0.0f)) ? 1 : 0;
iz = (searchDir[2] > dgFloat32(0.0f)) ? 1 : 0;
dgVector supportVertex(dgFloat32(0.0f), dgFloat32(0.0f), dgFloat32(0.0f),
dgFloat32(0.0f));
while (stack) {
dgFloat32 boxSupportValue;
stack--;
boxSupportValue = aabbProjection[stack];
if (boxSupportValue > maxProj) {
const dgNodeBase *const me = stackPool[stack];
if (me->m_type == m_leaf) {
dgFloat32 dist;
dgCollision *const shape = me->m_shape;
dgVector newDir(shape->m_offset.UnrotateVector(searchDir));
dgVector vertex(
shape->m_offset.TransformVector(shape->SupportVertex(newDir)));
dist = dir % vertex;
if (dist > maxProj) {
maxProj = dist;
supportVertex = vertex;
}
} else {
dgFloat32 dist0;
dgFloat32 dist1;
const dgNodeBase *const left = me->m_left;
const dgNodeBase *const right = me->m_right;
const dgVector *const box0 = &left->m_p0;
dgVector p0(box0[ix].m_x, box0[iy].m_y, box0[iz].m_z, dgFloat32(0.0f));
const dgVector *const box1 = &right->m_p0;
dgVector p1(box1[ix].m_x, box1[iy].m_y, box1[iz].m_z, dgFloat32(0.0f));
dist0 = p0 % dir;
dist1 = p1 % dir;
if (dist0 > dist1) {
stackPool[stack] = right;
aabbProjection[stack] = dist1;
stack++;
stackPool[stack] = left;
aabbProjection[stack] = dist0;
stack++;
} else {
stackPool[stack] = left;
aabbProjection[stack] = dist0;
stack++;
stackPool[stack] = right;
aabbProjection[stack] = dist1;
stack++;
}
}
}
}
return m_offset.TransformVector(supportVertex);
}
void dgCollisionCompound::GetCollisionInfo(dgCollisionInfo *info) const {
dgCollision::GetCollisionInfo(info);
info->m_offsetMatrix = GetOffsetMatrix();
info->m_compoundCollision.m_chidrenCount = m_count;
info->m_compoundCollision.m_chidren = (dgCollision **)m_array;
info->m_collisionType = m_compoundCollision;
}
void dgCollisionCompound::Serialize(dgSerialize callback,
void *const userData) const {
dgInt32 stack;
dgInt32 data[4];
dgNodeBase *pool[DG_COMPOUND_STACK_DEPTH];
data[0] = m_count;
data[1] = 0;
data[2] = 0;
data[3] = 0;
SerializeLow(callback, userData);
callback(userData, &data, sizeof(data));
for (dgInt32 i = 0; i < m_count; i++) {
dgCollision *collision;
collision = m_array[i];
m_world->Serialize(collision, callback, userData);
}
pool[0] = m_root;
stack = 1;
while (stack) {
dgNodeBase *node;
dgNodeBase *parent;
stack--;
node = pool[stack];
parent = NULL;
if (node->m_parent) {
parent = node->m_parent;
node->m_parent = (dgNodeBase *)(dgInt64(node->m_parent->m_id));
}
callback(userData, &node->m_p0, sizeof(dgNodeBase));
node->m_parent = parent;
if (node->m_type == m_node) {
pool[stack] = node->m_right;
stack++;
pool[stack] = node->m_left;
stack++;
}
}
}
bool dgCollisionCompound::OOBBTest(const dgMatrix &matrix,
const dgCollisionConvex *const shape, void *const cacheOrder) const {
NEWTON_ASSERT(0);
return true;
}
/*
dgInt32 dgCollisionCompound::GetAxis (dgNodeBase** const proxiArray, dgInt32 boxCount) const
{
dgInt32 axis;
dgFloat32 maxVal;
dgVector median (dgFloat32 (0.0f), dgFloat32 (0.0f), dgFloat32 (0.0f), dgFloat32 (0.0f));
dgVector varian (dgFloat32 (0.0f), dgFloat32 (0.0f), dgFloat32 (0.0f), dgFloat32 (0.0f));
for (dgInt32 i = 0; i < boxCount; i ++) {
const dgNodeBase* const proxy = proxiArray[i];
const dgVector& p0 = proxy->m_p0;
const dgVector& p1 = proxy->m_p1;
median += p0;
median += p1;
varian += p0.CompProduct(p0);
varian += p1.CompProduct(p1);
}
boxCount *= 2;
varian.m_x = boxCount * varian.m_x - median.m_x * median.m_x;
varian.m_y = boxCount * varian.m_y - median.m_y * median.m_y;
varian.m_z = boxCount * varian.m_z - median.m_z * median.m_z;
axis = 0;
maxVal = varian[0];
for (dgInt32 i = 1; i < 3; i ++) {
if (varian[i] > maxVal) {
axis = i;
maxVal = varian[i];
}
}
return axis;
}
dgInt32 dgCollisionCompound::CompareBox (const dgNodeBase* const boxA, const dgNodeBase* const boxB, void* const context)
{
dgInt32 axis;
axis = *((dgInt32*) context);
if (boxA->m_p0[axis] < boxB->m_p0[axis]) {
return -1;
} else if (boxA->m_p0[axis] > boxB->m_p0[axis]) {
return 1;
}
return 0;
}
dgCollisionCompound::dgNodeBase* dgCollisionCompound::BuildBottomUpTree(dgInt32 count, dgNodeBase** const proxiArray)
{
dgInt32 id;
dgStack<dgHeapNodePair> pool (count / 4 + DG_COMPOUND_STACK_DEPTH);
dgDownHeap<dgHeapNodePair, dgFloat32> heap (&pool[0], pool.GetSizeInBytes() - 64);
id = count;
while (count > 1){
dgInt32 axis;
dgInt32 newCount;
axis = GetAxis (proxiArray, count);
dgSortIndirect (proxiArray, count, CompareBox, &axis);
heap.Flush();
for (dgInt32 i = 0; i < count - 1; i ++) {
dgInt32 bestProxi;
dgFloat32 smallestVolume;
dgFloat32 breakValue;
dgNodeBase* nodeA;
nodeA = proxiArray[i];
bestProxi = -1;
smallestVolume = dgFloat32 (1.0e20f);
breakValue = ((count - i) < 32) ? dgFloat32 (1.0e20f) : nodeA->m_p1[axis] + dgFloat32 (2.0f);
if (breakValue < proxiArray[i + 1]->m_p0[axis]) {
breakValue = proxiArray[i + 1]->m_p0[axis] + dgFloat32 (2.0f);
}
for (dgInt32 j = i + 1; (j < count) && (proxiArray[j]->m_p0[axis] < breakValue); j ++) {
dgFloat32 volume;
dgVector p0;
dgVector p1;
dgNodeBase* nodeB;
nodeB = proxiArray[j];
p0.m_x = GetMin (nodeA->m_p0.m_x, nodeB->m_p0.m_x);
p0.m_y = GetMin (nodeA->m_p0.m_y, nodeB->m_p0.m_y);
p0.m_z = GetMin (nodeA->m_p0.m_z, nodeB->m_p0.m_z);
p0.m_w = dgFloat32 (0.0f);
p1.m_x = GetMax (nodeA->m_p1.m_x, nodeB->m_p1.m_x);
p1.m_y = GetMax (nodeA->m_p1.m_y, nodeB->m_p1.m_y);
p1.m_z = GetMax (nodeA->m_p1.m_z, nodeB->m_p1.m_z);
p1.m_w = dgFloat32 (0.0f);
dgVector dist (p1 - p0);
volume = dist.m_x * dist.m_y * dist.m_z;
if (volume < smallestVolume) {
bestProxi = j;
smallestVolume = volume;
}
}
NEWTON_ASSERT (bestProxi != -1);
dgHeapNodePair pair;
pair.m_nodeA = i;
pair.m_nodeB = bestProxi;
if (heap.GetCount() < heap.GetMaxCount()) {
heap.Push(pair, smallestVolume);
} else {
if (smallestVolume < heap.Value()) {
heap.Pop();
heap.Push(pair, smallestVolume);
}
}
}
heap.Sort ();
for (dgInt32 j = heap.GetCount() - 1; j >= 0; j --) {
dgHeapNodePair pair (heap[j]);
if ((proxiArray[pair.m_nodeA]->m_p0.m_w == dgFloat32 (0.0f)) && (proxiArray[pair.m_nodeB]->m_p0.m_w == dgFloat32 (0.0f))) {
proxiArray[pair.m_nodeA]->m_p0.m_w = dgFloat32 (1.0f);
proxiArray[pair.m_nodeB]->m_p0.m_w = dgFloat32 (1.0f);
proxiArray[count] = new (m_allocator) dgNodeBase (proxiArray[pair.m_nodeA], proxiArray[pair.m_nodeB], id);
proxiArray[pair.m_nodeA]->m_parent = proxiArray[count];
proxiArray[pair.m_nodeB]->m_parent = proxiArray[count];
id ++;
count ++;
}
}
newCount = 0;
for (dgInt32 i = 0; i < count; i ++) {
if (proxiArray[i]->m_p0.m_w == dgFloat32 (0.0f)) {
proxiArray[newCount] = proxiArray[i];
newCount ++;
}
}
NEWTON_ASSERT (newCount < count);
count = newCount;
}
return proxiArray[0];
}
*/
dgCollisionCompound::dgNodeBase *dgCollisionCompound::BuildTopDownTree(
dgInt32 count, dgNodeBase **const proxiArray, dgInt32 &id) {
dgNodeBase *tree = NULL;
if (count == 1) {
tree = proxiArray[0];
} else {
dgInt32 i0 = 1;
if (count > 2) {
dgVector median(dgFloat32(0.0f), dgFloat32(0.0f), dgFloat32(0.0f),
dgFloat32(0.0f));
dgVector varian(dgFloat32(0.0f), dgFloat32(0.0f), dgFloat32(0.0f),
dgFloat32(0.0f));
for (dgInt32 i = 0; i < count; i++) {
const dgNodeBase *const proxy = proxiArray[i];
const dgVector &p0 = proxy->m_p0;
const dgVector &p1 = proxy->m_p1;
median += p0;
median += p1;
varian += p0.CompProduct(p0);
varian += p1.CompProduct(p1);
}
dgInt32 pointCount = count * 2;
varian.m_x = pointCount * varian.m_x - median.m_x * median.m_x;
varian.m_y = pointCount * varian.m_y - median.m_y * median.m_y;
varian.m_z = pointCount * varian.m_z - median.m_z * median.m_z;
dgInt32 axis = 0;
dgFloat32 maxVal = varian[0];
for (dgInt32 i = 1; i < 3; i++) {
if (varian[i] > maxVal) {
axis = i;
maxVal = varian[i];
}
}
dgVector center = median.Scale(dgFloat32(1.0f) / dgFloat32(pointCount));
dgFloat32 test = center[axis];
dgInt32 i1 = count - 1;
do {
for (; i0 <= i1; i0++) {
const dgNodeBase *const proxy = proxiArray[i0];
dgFloat32 val = (proxy->m_p0[axis] + proxy->m_p1[axis]) * dgFloat32(0.5f);
if (val > test) {
break;
}
}
for (; i1 >= i0; i1--) {
const dgNodeBase *const proxy = proxiArray[i1];
dgFloat32 val = (proxy->m_p0[axis] + proxy->m_p1[axis]) * dgFloat32(0.5f);
if (val < test) {
break;
}
}
if (i0 < i1) {
Swap(proxiArray[i0], proxiArray[i1]);
i0++;
i1--;
}
} while (i0 <= i1);
if (i0 == 0) {
i0 = 1;
}
if (i0 >= count - 1) {
i0 = count - 1;
}
}
dgNodeBase *const left = BuildTopDownTree(i0, &proxiArray[0], id);
dgNodeBase *const right = BuildTopDownTree(count - i0, &proxiArray[i0], id);
tree = new (m_allocator) dgNodeBase(left, right, id);
left->m_parent = tree;
right->m_parent = tree;
id++;
}
return tree;
}
void dgCollisionCompound::PushNodes(dgNodeBase *const root,
dgNodeBase **const proxiArray, dgInt32 &index) const {
if (root->m_left) {
PushNodes(root->m_left, proxiArray, index);
}
if (root->m_right) {
PushNodes(root->m_right, proxiArray, index);
}
if (!root->m_shape) {
proxiArray[index] = root;
index++;
}
}
dgFloat32 dgCollisionCompound::CalculateSurfaceArea(dgNodeBase *const node0,
dgNodeBase *const node1, dgVector &minBox, dgVector &maxBox) const {
minBox = dgVector(GetMin(node0->m_p0.m_x, node1->m_p0.m_x),
GetMin(node0->m_p0.m_y, node1->m_p0.m_y),
GetMin(node0->m_p0.m_z, node1->m_p0.m_z), dgFloat32(0.0f));
maxBox = dgVector(GetMax(node0->m_p1.m_x, node1->m_p1.m_x),
GetMax(node0->m_p1.m_y, node1->m_p1.m_y),
GetMax(node0->m_p1.m_z, node1->m_p1.m_z), dgFloat32(0.0f));
dgVector side0((maxBox - minBox).Scale(dgFloat32(0.5f)));
dgVector side1(side0.m_y, side0.m_z, side0.m_x, dgFloat32(0.0f));
return side0 % side1;
}
void dgCollisionCompound::ImproveNodeFitness(dgNodeBase *const node) const {
NEWTON_ASSERT(node->m_left);
NEWTON_ASSERT(node->m_right);
if (node->m_parent) {
if (node->m_parent->m_left == node) {
dgFloat32 cost0 = node->m_area;
dgVector cost1P0;
dgVector cost1P1;
dgFloat32 cost1 = CalculateSurfaceArea(node->m_right,
node->m_parent->m_right, cost1P0, cost1P1);
dgVector cost2P0;
dgVector cost2P1;
dgFloat32 cost2 = CalculateSurfaceArea(node->m_left,
node->m_parent->m_right, cost2P0, cost2P1);
if ((cost1 <= cost0) && (cost1 <= cost2)) {
dgNodeBase *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 {
NEWTON_ASSERT(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).Scale(dgFloat32(0.5f));
parent->m_origin = (parent->m_p1 + parent->m_p0).Scale(dgFloat32(0.5f));
} else if ((cost2 <= cost0) && (cost2 <= cost1)) {
dgNodeBase *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 {
NEWTON_ASSERT(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).Scale(dgFloat32(0.5f));
parent->m_origin = (parent->m_p1 + parent->m_p0).Scale(dgFloat32(0.5f));
}
} else {
dgFloat32 cost0 = node->m_area;
dgVector cost1P0;
dgVector cost1P1;
dgFloat32 cost1 = CalculateSurfaceArea(node->m_left,
node->m_parent->m_left, cost1P0, cost1P1);
dgVector cost2P0;
dgVector cost2P1;
dgFloat32 cost2 = CalculateSurfaceArea(node->m_right,
node->m_parent->m_left, cost2P0, cost2P1);
if ((cost1 <= cost0) && (cost1 <= cost2)) {
dgNodeBase *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 {
NEWTON_ASSERT(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).Scale(dgFloat32(0.5f));
parent->m_origin = (parent->m_p1 + parent->m_p0).Scale(dgFloat32(0.5f));
} else if ((cost2 <= cost0) && (cost2 <= cost1)) {
dgNodeBase *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 {
NEWTON_ASSERT(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).Scale(dgFloat32(0.5f));
parent->m_origin = (parent->m_p1 + parent->m_p0).Scale(dgFloat32(0.5f));
}
}
} else {
// in the future I can handle this but it is too much work for little payoff
}
}
dgCollisionCompound::dgNodeBase *dgCollisionCompound::BuildTree(dgInt32 count,
dgCollisionConvex *const shapeArray[]) {
#if 0
dgStack<dgNodeBase *> nodeList(count * 2);
dgNodeBase **const proxiArray = &nodeList[0];
for (dgInt32 i = 0; i < count; i ++) {
proxiArray[i] = new (m_allocator) dgNodeBase(shapeArray[i], i);
}
dgNodeBase *tree = BuildBottomUpTree(count, proxiArray);
#else
dgStack<dgNodeBase *> nodeList(count);
dgNodeBase **const proxiArray = &nodeList[0];
for (dgInt32 i = 0; i < count; i++) {
proxiArray[i] = new (m_allocator) dgNodeBase(shapeArray[i], i);
}
dgInt32 id = count;
dgNodeBase *tree = BuildTopDownTree(count, proxiArray, id);
#endif
dgInt32 index = 0;
PushNodes(tree, proxiArray, index);
dgInt32 maxPasses = 2 * exp_2(index * 2) + 1;
dgFloat64 newCost = dgFloat32(1.0e20f);
dgFloat64 prevCost = newCost;
do {
prevCost = newCost;
for (dgInt32 i = 0; i < index; i++) {
dgNodeBase *const node = proxiArray[i];
ImproveNodeFitness(node);
}
newCost = dgFloat32(0.0f);
for (dgInt32 i = 0; i < index; i++) {
dgNodeBase *const node = proxiArray[i];
newCost += node->m_area;
}
maxPasses--;
} while (maxPasses && (newCost < prevCost));
if (tree->m_parent) {
NEWTON_ASSERT(index);
for (tree = proxiArray[index - 1]; tree->m_parent; tree = tree->m_parent)
;
}
return tree;
}
dgInt32 dgCollisionCompound::CalculateContacts(
dgCollidingPairCollector::dgPair *const pair, dgCollisionParamProxy &proxy,
dgInt32 useSimd) const {
dgInt32 contactCount = 0;
if (m_root) {
NEWTON_ASSERT(IsType(dgCollision::dgCollisionCompound_RTTI));
if (pair->m_body1->m_collision->IsType(dgCollision::dgConvexCollision_RTTI)) {
contactCount = CalculateContactsToSingle(pair, proxy, useSimd);
} else if (pair->m_body1->m_collision->IsType(
dgCollision::dgCollisionCompound_RTTI)) {
contactCount = CalculateContactsToCompound(pair, proxy, useSimd);
} else if (pair->m_body1->m_collision->IsType(
dgCollision::dgCollisionBVH_RTTI)) {
contactCount = CalculateContactsToCollisionTree(pair, proxy, useSimd);
} else if (pair->m_body1->m_collision->IsType(
dgCollision::dgCollisionHeightField_RTTI)) {
contactCount = CalculateContactsToHeightField(pair, proxy, useSimd);
} else {
NEWTON_ASSERT(
pair->m_body1->m_collision->IsType(dgCollision::dgCollisionUserMesh_RTTI));
contactCount = CalculateContactsBruteForce(pair, proxy, useSimd);
}
}
return contactCount;
}
dgInt32 dgCollisionCompound::CalculateContactsToSingle(
dgCollidingPairCollector::dgPair *const pair, dgCollisionParamProxy &proxy,
dgInt32 useSimd) const {
dgVector p0;
dgVector p1;
dgContactPoint *const contacts = pair->m_contactBuffer;
const dgNodeBase *stackPool[DG_COMPOUND_STACK_DEPTH];
dgBody *const otherBody = pair->m_body1;
dgBody *const compoundBody = pair->m_body0;
NEWTON_ASSERT(pair->m_body0->m_collision == this);
NEWTON_ASSERT(
otherBody->m_collision->IsType(dgCollision::dgConvexCollision_RTTI));
// dgInt32 lru = m_world->m_broadPhaseLru;
proxy.m_referenceBody = compoundBody;
proxy.m_floatingBody = otherBody;
proxy.m_floatingCollision = otherBody->m_collision;
proxy.m_floatingMatrix = otherBody->m_collisionWorldMatrix;
dgInt32 contactCount = 0;
dgMatrix myMatrix(m_offset * compoundBody->m_matrix);
dgMatrix matrix(otherBody->m_collisionWorldMatrix * myMatrix.Inverse());
otherBody->m_collision->CalcAABB(dgGetIdentityMatrix(), p0, p1);
if (proxy.m_unconditionalCast) {
dgVector step(
(otherBody->m_veloc - compoundBody->m_veloc).Scale(proxy.m_timestep));
step = otherBody->m_collisionWorldMatrix.UnrotateVector(step);
for (dgInt32 j = 0; j < 3; j++) {
if (step[j] > dgFloat32(0.0f)) {
p1[j] += step[j];
} else {
p0[j] += step[j];
}
}
}
OOBBTestData data(matrix, p0, p1);
dgInt32 stack = 1;
stackPool[0] = m_root;
while (stack) {
stack--;
const dgNodeBase *const me = stackPool[stack];
NEWTON_ASSERT(me);
if (me->BoxTest(data)) {
if (me->m_type == m_leaf) {
dgInt32 processContacts;
processContacts = 1;
if (pair->m_material && pair->m_material->m_compoundAABBOverlap) {
processContacts = pair->m_material->m_compoundAABBOverlap(
reinterpret_cast<const NewtonMaterial *>(pair->m_material), reinterpret_cast<const NewtonBody *>(compoundBody), reinterpret_cast<const NewtonBody *>(otherBody),
proxy.m_threadIndex);
}
if (processContacts) {
proxy.m_referenceCollision = me->m_shape;
proxy.m_referenceMatrix = me->m_shape->m_offset * myMatrix;
// proxy.m_floatingCollision = otherBody->m_collision;
// proxy.m_floatingMatrix = otherBody->m_collisionWorldMatrix;
proxy.m_maxContacts = DG_MAX_CONTATCS - contactCount;
proxy.m_contacts = &contacts[contactCount];
if (useSimd) {
contactCount += m_world->CalculateConvexToConvexContactsSimd(proxy);
} else {
contactCount += m_world->CalculateConvexToConvexContacts(proxy);
}
if (contactCount > (DG_MAX_CONTATCS - 2 * (DG_CONSTRAINT_MAX_ROWS / 3))) {
contactCount = m_world->ReduceContacts(contactCount, contacts,
DG_CONSTRAINT_MAX_ROWS / 3, DG_REDUCE_CONTACT_TOLERANCE);
}
}
} else {
NEWTON_ASSERT(me->m_type == m_node);
stackPool[stack] = me->m_left;
stack++;
NEWTON_ASSERT(stack < dgInt32(sizeof(stackPool) / sizeof(dgNodeBase *)));
stackPool[stack] = me->m_right;
stack++;
NEWTON_ASSERT(stack < dgInt32(sizeof(stackPool) / sizeof(dgNodeBase *)));
}
}
}
return contactCount;
}
dgInt32 dgCollisionCompound::CalculateContactsToCompound(
dgCollidingPairCollector::dgPair *const pair, dgCollisionParamProxy &proxy,
dgInt32 useSimd) const {
dgContactPoint *const contacts = pair->m_contactBuffer;
const dgNodeBase *stackPool[4 * DG_COMPOUND_STACK_DEPTH][2];
dgInt32 contactCount = 0;
dgBody *const myBody = pair->m_body0;
dgBody *const otherBody = pair->m_body1;
NEWTON_ASSERT(pair->m_body0->m_collision == this);
dgCollisionCompound *const otherCompound =
(dgCollisionCompound *)otherBody->m_collision;
// dgInt32 lru = m_world->m_broadPhaseLru;
proxy.m_referenceBody = myBody;
proxy.m_floatingBody = otherBody;
dgMatrix myMatrix(m_offset * myBody->m_matrix);
dgMatrix otherMatrix(otherCompound->m_offset * otherBody->m_matrix);
OOBBTestData data(otherMatrix * myMatrix.Inverse());
dgInt32 stack = 1;
stackPool[0][0] = m_root;
stackPool[0][1] = otherCompound->m_root;
while (stack) {
stack--;
const dgNodeBase *const me = stackPool[stack][0];
const dgNodeBase *const other = stackPool[stack][1];
NEWTON_ASSERT(me && other);
if (me->BoxTest(data, other)) {
if ((me->m_type == m_leaf) && (other->m_type == m_leaf)) {
dgInt32 processContacts;
processContacts = 1;
if (pair->m_material && pair->m_material->m_compoundAABBOverlap) {
processContacts = pair->m_material->m_compoundAABBOverlap(reinterpret_cast<const NewtonMaterial *>(pair->m_material), reinterpret_cast<const NewtonBody *>(myBody), reinterpret_cast<const NewtonBody *>(otherBody),
proxy.m_threadIndex);
}
if (processContacts) {
proxy.m_referenceCollision = me->m_shape;
proxy.m_referenceMatrix = me->m_shape->m_offset * myMatrix;
proxy.m_floatingCollision = other->m_shape;
proxy.m_floatingMatrix = other->m_shape->m_offset * otherMatrix;
proxy.m_maxContacts = DG_MAX_CONTATCS - contactCount;
proxy.m_contacts = &contacts[contactCount];
if (useSimd) {
contactCount += m_world->CalculateConvexToConvexContactsSimd(proxy);
} else {
contactCount += m_world->CalculateConvexToConvexContacts(proxy);
}
if (contactCount > (DG_MAX_CONTATCS - 2 * (DG_CONSTRAINT_MAX_ROWS / 3))) {
contactCount = m_world->ReduceContacts(contactCount, contacts,
DG_CONSTRAINT_MAX_ROWS / 3, DG_REDUCE_CONTACT_TOLERANCE);
}
}
} else if (me->m_type == m_leaf) {
// dgNode* const otherNode = (dgNode*)other;
NEWTON_ASSERT(other->m_type == m_node);
stackPool[stack][0] = me;
stackPool[stack][1] = other->m_left;
stack++;
NEWTON_ASSERT(stack < dgInt32(sizeof(stackPool) / sizeof(dgNodeBase *)));
stackPool[stack][0] = me;
stackPool[stack][1] = other->m_right;
stack++;
NEWTON_ASSERT(stack < dgInt32(sizeof(stackPool) / sizeof(dgNodeBase *)));
} else if (other->m_type == m_leaf) {
// dgNode* const myNode = (dgNode*)me;
NEWTON_ASSERT(me->m_type == m_node);
stackPool[stack][0] = me->m_left;
stackPool[stack][1] = other;
stack++;
NEWTON_ASSERT(stack < dgInt32(sizeof(stackPool) / sizeof(dgNodeBase *)));
stackPool[stack][0] = me->m_right;
stackPool[stack][1] = other;
stack++;
NEWTON_ASSERT(stack < dgInt32(sizeof(stackPool) / sizeof(dgNodeBase *)));
} else {
NEWTON_ASSERT(me->m_type == m_node);
NEWTON_ASSERT(other->m_type == m_node);
stackPool[stack][0] = me->m_left;
stackPool[stack][1] = other->m_left;
stack++;
NEWTON_ASSERT(stack < dgInt32(sizeof(stackPool) / sizeof(dgNodeBase *)));
stackPool[stack][0] = me->m_left;
stackPool[stack][1] = other->m_right;
stack++;
NEWTON_ASSERT(stack < dgInt32(sizeof(stackPool) / sizeof(dgNodeBase *)));
stackPool[stack][0] = me->m_right;
stackPool[stack][1] = other->m_left;
stack++;
NEWTON_ASSERT(stack < dgInt32(sizeof(stackPool) / sizeof(dgNodeBase *)));
stackPool[stack][0] = me->m_right;
stackPool[stack][1] = other->m_right;
stack++;
NEWTON_ASSERT(stack < dgInt32(sizeof(stackPool) / sizeof(dgNodeBase *)));
}
}
}
return contactCount;
}
dgInt32 dgCollisionCompound::CalculateContactsToCollisionTree(
dgCollidingPairCollector::dgPair *const pair, dgCollisionParamProxy &proxy,
dgInt32 useSimd) const {
dgContactPoint *const contacts = pair->m_contactBuffer;
dgTree<const dgNodeBase *, const dgNodeBase *> filter(m_allocator);
struct NodePairs {
dgNodeBase *m_myNode;
dgInt32 m_treeNodeIsLeaf;
const void *m_treeNode;
};
NodePairs stackPool[4 * DG_COMPOUND_STACK_DEPTH];
dgInt32 contactCount = 0;
dgBody *const myBody = pair->m_body0;
dgBody *const treeBody = pair->m_body1;
NEWTON_ASSERT(pair->m_body0->m_collision == this);
dgCollisionBVH *const treeCollision = (dgCollisionBVH *)treeBody->m_collision;
// dgInt32 lru = m_world->m_broadPhaseLru;
proxy.m_referenceBody = myBody;
proxy.m_floatingBody = treeBody;
proxy.m_floatingCollision = treeCollision;
proxy.m_floatingMatrix = treeBody->m_collisionWorldMatrix;
dgMatrix myMatrix(m_offset * myBody->m_matrix);
OOBBTestData data(proxy.m_floatingMatrix * myMatrix.Inverse());
dgInt32 stack = 1;
stackPool[0].m_myNode = m_root;
stackPool[0].m_treeNode = treeCollision->GetRootNode();
stackPool[0].m_treeNodeIsLeaf = 0;
dgNodeBase nodeProxi;
nodeProxi.m_left = NULL;
nodeProxi.m_right = NULL;
while (stack) {
dgInt32 treeNodeIsLeaf;
stack--;
dgNodeBase *const me = stackPool[stack].m_myNode;
const void *const other = stackPool[stack].m_treeNode;
treeNodeIsLeaf = stackPool[stack].m_treeNodeIsLeaf;
NEWTON_ASSERT(me && other);
treeCollision->GetNodeAABB(other, nodeProxi.m_p0, nodeProxi.m_p1);
nodeProxi.m_size = (nodeProxi.m_p1 - nodeProxi.m_p0).Scale(dgFloat32(0.5f));
nodeProxi.m_origin = (nodeProxi.m_p1 + nodeProxi.m_p0).Scale(dgFloat32(0.5f));
dgVector size(nodeProxi.m_size.m_y, nodeProxi.m_size.m_z,
nodeProxi.m_size.m_x, dgFloat32(0.0f));
nodeProxi.m_area = nodeProxi.m_size % size;
NEWTON_ASSERT(nodeProxi.m_area > dgFloat32(0.0f));
if (me->BoxTest(data, &nodeProxi)) {
if ((me->m_type == m_leaf) && treeNodeIsLeaf) {
if (!filter.Find(me)) {
m_world->dgGetUserLock();
filter.Insert(me, me);
m_world->dgReleasedUserLock();
// dgShapeCell* const myCell = (dgShapeCell*)me;
// m_world->dgGetIndirectLock(&myCell->m_criticalSection);
// if (myCell->m_lru != lru) {
// myCell->m_lru = lru;
// myCell->m_collisionMatrix = myCell->m_shape->m_offset * myMatrix;
// }
// m_world->dgReleaseIndirectLock(&myCell->m_criticalSection);
proxy.m_referenceCollision = me->m_shape;
proxy.m_referenceMatrix = me->m_shape->m_offset * myMatrix;
proxy.m_maxContacts = DG_MAX_CONTATCS - contactCount;
proxy.m_contacts = &contacts[contactCount];
if (useSimd) {
contactCount += m_world->CalculateConvexToNonConvexContactsSimd(
proxy);
} else {
contactCount += m_world->CalculateConvexToNonConvexContacts(proxy);
}
if (contactCount > (DG_MAX_CONTATCS - 2 * (DG_CONSTRAINT_MAX_ROWS / 3))) {
contactCount = m_world->ReduceContacts(contactCount, contacts,
DG_CONSTRAINT_MAX_ROWS / 3, DG_REDUCE_CONTACT_TOLERANCE);
}
if (filter.GetCount() == m_count) {
break;
}
}
} else if (me->m_type == m_leaf) {
const void *const frontNode = treeCollision->GetFrontNode(other);
const void *const backNode = treeCollision->GetBackNode(other);
if (backNode && frontNode) {
stackPool[stack].m_myNode = (dgNodeBase *)me;
stackPool[stack].m_treeNode = backNode;
stackPool[stack].m_treeNodeIsLeaf = 0;
stack++;
stackPool[stack].m_myNode = (dgNodeBase *)me;
stackPool[stack].m_treeNode = frontNode;
stackPool[stack].m_treeNodeIsLeaf = 0;
stack++;
} else if (backNode && !frontNode) {
stackPool[stack].m_myNode = (dgNodeBase *)me;
stackPool[stack].m_treeNode = backNode;
stackPool[stack].m_treeNodeIsLeaf = 0;
stack++;
stackPool[stack].m_myNode = (dgNodeBase *)me;
stackPool[stack].m_treeNode = other;
stackPool[stack].m_treeNodeIsLeaf = 1;
stack++;
} else if (!backNode && frontNode) {
stackPool[stack].m_myNode = (dgNodeBase *)me;
stackPool[stack].m_treeNode = frontNode;
stackPool[stack].m_treeNodeIsLeaf = 0;
stack++;
stackPool[stack].m_myNode = (dgNodeBase *)me;
stackPool[stack].m_treeNode = other;
stackPool[stack].m_treeNodeIsLeaf = 1;
stack++;
} else {
stackPool[stack].m_myNode = (dgNodeBase *)me;
stackPool[stack].m_treeNode = other;
stackPool[stack].m_treeNodeIsLeaf = 1;
stack++;
}
} else if (treeNodeIsLeaf) {
stackPool[stack].m_myNode = me->m_left;
stackPool[stack].m_treeNode = other;
stackPool[stack].m_treeNodeIsLeaf = 1;
stack++;
NEWTON_ASSERT(stack < dgInt32(sizeof(stackPool) / (sizeof(dgNodeBase *))));
stackPool[stack].m_myNode = me->m_right;
stackPool[stack].m_treeNode = other;
stackPool[stack].m_treeNodeIsLeaf = 1;
stack++;
NEWTON_ASSERT(stack < dgInt32(sizeof(stackPool) / (sizeof(dgNodeBase *))));
} else if (nodeProxi.m_area > me->m_area) {
NEWTON_ASSERT(me->m_type == m_node);
const void *const frontNode = treeCollision->GetFrontNode(other);
const void *const backNode = treeCollision->GetBackNode(other);
if (backNode && frontNode) {
stackPool[stack].m_myNode = (dgNodeBase *)me;
stackPool[stack].m_treeNode = backNode;
stackPool[stack].m_treeNodeIsLeaf = 0;
stack++;
stackPool[stack].m_myNode = (dgNodeBase *)me;
stackPool[stack].m_treeNode = frontNode;
stackPool[stack].m_treeNodeIsLeaf = 0;
stack++;
} else if (backNode && !frontNode) {
stackPool[stack].m_myNode = (dgNodeBase *)me;
stackPool[stack].m_treeNode = backNode;
stackPool[stack].m_treeNodeIsLeaf = 0;
stack++;
stackPool[stack].m_myNode = me->m_left;
stackPool[stack].m_treeNode = other;
stackPool[stack].m_treeNodeIsLeaf = 1;
stack++;
stackPool[stack].m_myNode = me->m_right;
stackPool[stack].m_treeNode = other;
stackPool[stack].m_treeNodeIsLeaf = 1;
stack++;
} else if (!backNode && frontNode) {
stackPool[stack].m_myNode = me;
stackPool[stack].m_treeNode = frontNode;
stackPool[stack].m_treeNodeIsLeaf = 0;
stack++;
stackPool[stack].m_myNode = me->m_left;
stackPool[stack].m_treeNode = other;
stackPool[stack].m_treeNodeIsLeaf = 1;
stack++;
stackPool[stack].m_myNode = me->m_right;
stackPool[stack].m_treeNode = other;
stackPool[stack].m_treeNodeIsLeaf = 1;
stack++;
} else {
stackPool[stack].m_myNode = me->m_left;
stackPool[stack].m_treeNode = other;
stackPool[stack].m_treeNodeIsLeaf = 1;
stack++;
stackPool[stack].m_myNode = me->m_right;
stackPool[stack].m_treeNode = other;
stackPool[stack].m_treeNodeIsLeaf = 1;
stack++;
}
} else {
NEWTON_ASSERT(me->m_type == m_node);
stackPool[stack].m_myNode = me->m_left;
stackPool[stack].m_treeNode = other;
stackPool[stack].m_treeNodeIsLeaf = treeNodeIsLeaf;
stack++;
stackPool[stack].m_myNode = me->m_right;
stackPool[stack].m_treeNode = other;
stackPool[stack].m_treeNodeIsLeaf = treeNodeIsLeaf;
stack++;
}
}
}
if (filter.GetCount()) {
m_world->dgGetUserLock();
filter.RemoveAll();
m_world->dgReleasedUserLock();
}
return contactCount;
}
dgInt32 dgCollisionCompound::CalculateContactsToHeightField(
dgCollidingPairCollector::dgPair *const pair, dgCollisionParamProxy &proxy,
dgInt32 useSimd) const {
dgNodeBase nodeProxi;
dgContactPoint *const contacts = pair->m_contactBuffer;
const dgNodeBase *stackPool[DG_COMPOUND_STACK_DEPTH];
dgInt32 contactCount = 0;
dgBody *const myBody = pair->m_body0;
dgBody *const terrainBody = pair->m_body1;
NEWTON_ASSERT(pair->m_body0->m_collision == this);
dgCollisionHeightField *const terrainCollision =
(dgCollisionHeightField *)terrainBody->m_collision;
// dgInt32 lru = m_world->m_broadPhaseLru;
proxy.m_referenceBody = myBody;
proxy.m_floatingBody = terrainBody;
proxy.m_floatingCollision = terrainCollision;
proxy.m_floatingMatrix = terrainBody->m_collisionWorldMatrix;
dgMatrix myMatrix(m_offset * myBody->m_matrix);
OOBBTestData data(proxy.m_floatingMatrix * myMatrix.Inverse());
dgInt32 stack = 1;
stackPool[0] = m_root;
nodeProxi.m_left = NULL;
nodeProxi.m_right = NULL;
while (stack) {
stack--;
const dgNodeBase *const me = stackPool[stack];
dgVector origin(data.m_matrix.UntransformVector(me->m_origin));
dgVector size(data.m_absMatrix.UnrotateVector(me->m_size));
dgVector p0(origin - size);
dgVector p1(origin + size);
terrainCollision->GetLocalAABB(p0, p1, nodeProxi.m_p0, nodeProxi.m_p1);
nodeProxi.m_size = (nodeProxi.m_p1 - nodeProxi.m_p0).Scale(dgFloat32(0.5f));
nodeProxi.m_origin = (nodeProxi.m_p1 + nodeProxi.m_p0).Scale(dgFloat32(0.5f));
if (me->BoxTest(data, &nodeProxi)) {
if (me->m_type == m_leaf) {
// dgShapeCell* const myCell = (dgShapeCell*)me;
// m_world->dgGetIndirectLock(&myCell->m_criticalSection);
// if (myCell->m_lru != lru) {
// myCell->m_lru = lru;
// myCell->m_collisionMatrix = myCell->m_shape->m_offset * myMatrix;
// }
// m_world->dgReleaseIndirectLock(&myCell->m_criticalSection);
proxy.m_referenceCollision = me->m_shape;
proxy.m_referenceMatrix = me->m_shape->m_offset * myMatrix;
proxy.m_maxContacts = DG_MAX_CONTATCS - contactCount;
proxy.m_contacts = &contacts[contactCount];
if (useSimd) {
contactCount += m_world->CalculateConvexToNonConvexContactsSimd(
proxy);
} else {
contactCount += m_world->CalculateConvexToNonConvexContacts(proxy);
}
if (contactCount > (DG_MAX_CONTATCS - 2 * (DG_CONSTRAINT_MAX_ROWS / 3))) {
contactCount = m_world->ReduceContacts(contactCount, contacts,
DG_CONSTRAINT_MAX_ROWS / 3, DG_REDUCE_CONTACT_TOLERANCE);
}
} else {
NEWTON_ASSERT(me->m_type == m_node);
stackPool[stack] = me->m_left;
stack++;
stackPool[stack] = me->m_right;
stack++;
}
}
}
return contactCount;
}
dgInt32 dgCollisionCompound::CalculateContactsBruteForce(
dgCollidingPairCollector::dgPair *const pair, dgCollisionParamProxy &proxy,
dgInt32 useSimd) const {
dgContactPoint *const contacts = pair->m_contactBuffer;
const dgNodeBase *stackPool[DG_COMPOUND_STACK_DEPTH];
dgInt32 contactCount = 0;
dgBody *const myBody = pair->m_body0;
dgBody *const userBody = pair->m_body1;
NEWTON_ASSERT(pair->m_body0->m_collision == this);
dgCollisionMesh *const userCollision =
(dgCollisionMesh *)userBody->m_collision;
// dgInt32 lru = m_world->m_broadPhaseLru;
proxy.m_referenceBody = myBody;
proxy.m_floatingBody = userBody;
proxy.m_floatingCollision = userCollision;
proxy.m_floatingMatrix = userBody->m_collisionWorldMatrix;
dgMatrix myMatrix(m_offset * myBody->m_matrix);
dgInt32 stack = 1;
stackPool[0] = m_root;
dgNodeBase nodeProxi;
nodeProxi.m_left = NULL;
nodeProxi.m_right = NULL;
while (stack) {
stack--;
const dgNodeBase *const me = stackPool[stack];
if (me->m_type == m_leaf) {
// dgShapeCell* const myCell = (dgShapeCell*)me;
// m_world->dgGetIndirectLock(&myCell->m_criticalSection);
// if (myCell->m_lru != lru) {
// myCell->m_lru = lru;
// myCell->m_collisionMatrix = myCell->m_shape->m_offset * myMatrix;
// }
// m_world->dgReleaseIndirectLock(&myCell->m_criticalSection);
proxy.m_referenceCollision = me->m_shape;
proxy.m_referenceMatrix = me->m_shape->m_offset * myMatrix;
proxy.m_maxContacts = DG_MAX_CONTATCS - contactCount;
proxy.m_contacts = &contacts[contactCount];
if (useSimd) {
contactCount += m_world->CalculateConvexToNonConvexContactsSimd(proxy);
} else {
contactCount += m_world->CalculateConvexToNonConvexContacts(proxy);
}
if (contactCount > (DG_MAX_CONTATCS - 2 * (DG_CONSTRAINT_MAX_ROWS / 3))) {
contactCount = m_world->ReduceContacts(contactCount, contacts,
DG_CONSTRAINT_MAX_ROWS / 3, DG_REDUCE_CONTACT_TOLERANCE);
}
} else {
NEWTON_ASSERT(me->m_type == m_node);
stackPool[stack] = me->m_left;
stack++;
stackPool[stack] = me->m_right;
stack++;
}
}
return contactCount;
}
dgInt32 dgCollisionCompound::ClosestDitance(dgBody *const compoundBody,
dgTriplex &contactA, dgBody *const bodyB, dgTriplex &contactB,
dgTriplex &normalAB) const {
if (!m_root) {
return 0;
}
#if 0
NEWTON_ASSERT(compoundBody->m_collision == this);
dgCollisionConvex *const collisionB = (dgCollisionConvex *) bodyB->m_collision;
// dgInt32 lru;
// dgInt32 stack;
// dgInt32 contactCount;
// dgBody* otherBody;
// dgBody* compoundBody;
// dgVector p0;
// dgVector p1;
// dgContactPoint* const contacts = pair->m_contactBuffer;
// const dgNodeBase* stackPool[DG_COMPOUND_STACK_DEPTH];
// otherBody = pair->m_body1;
// compoundBody = pair->m_body0;
// NEWTON_ASSERT (pair->m_body0->m_collision == this);
// NEWTON_ASSERT (otherBody->m_collision->IsType (dgCollision::dgConvexCollision_RTTI));
// lru = m_world->m_broadPhaseLru;
// proxy.m_referenceBody = compoundBody;
// proxy.m_floatingBody = otherBody;
// proxy.m_floatingCollision = otherBody->m_collision;
// proxy.m_floatingMatrix = otherBody->m_collisionWorldMatrix;
// contactCount = 0;
dgVector p0;
dgVector p1;
dgMatrix myMatrix(m_offset * compoundBody->m_matrix);
dgMatrix matrix(bodyB->m_collisionWorldMatrix * myMatrix.Inverse());
collisionB->CalcAABB(dgGetIdentityMatrix(), p0, p1);
dgFloat32 distPool[DG_COMPOUND_STACK_DEPTH];
const dgNodeBase *stackPool[DG_COMPOUND_STACK_DEPTH];
dgVector points[8];
points[0] = dgVector(p0.m_x, p0.m_y, p0.m_z, dgFloat32(0.0f));
points[1] = dgVector(p0.m_x, p0.m_y, p1.m_z, dgFloat32(0.0f));
points[2] = dgVector(p0.m_x, p1.m_y, p0.m_z, dgFloat32(0.0f));
points[3] = dgVector(p0.m_x, p1.m_y, p1.m_z, dgFloat32(0.0f));
points[4] = dgVector(p1.m_x, p0.m_y, p0.m_z, dgFloat32(0.0f));
points[5] = dgVector(p1.m_x, p0.m_y, p1.m_z, dgFloat32(0.0f));
points[6] = dgVector(p1.m_x, p1.m_y, p0.m_z, dgFloat32(0.0f));
points[7] = dgVector(p1.m_x, p1.m_y, p1.m_z, dgFloat32(0.0f));
matrix.TransformTriplex(points, sizeof(dgVector), points, sizeof(dgVector), 8);
dgInt32 stack = 1;
stackPool[0] = m_root;
distPool[0] = m_root->BoxClosestDistance(points, 8);
dgFloat32 baseDist = dgFloat32(1.0e10f);
while (stack) {
stack --;
dgFloat32 dist = distPool[stack];
const dgNodeBase *const me = stackPool[stack];
NEWTON_ASSERT(me);
// if (me->BoxTest (data)) {
if (dist < baseDist) {
if (me->m_type == m_leaf) {
NEWTON_ASSERT(0);
/*
dgInt32 processContacts;
processContacts = 1;
if (pair->m_material && pair->m_material->m_compoundAABBOverlap) {
processContacts = pair->m_material->m_compoundAABBOverlap (*pair->m_material, *compoundBody, *otherBody, proxy.m_threadIndex);
}
if (processContacts) {
proxy.m_referenceCollision = me->m_shape;
proxy.m_referenceMatrix = me->m_shape->m_offset * myMatrix;
// proxy.m_floatingCollision = otherBody->m_collision;
// proxy.m_floatingMatrix = otherBody->m_collisionWorldMatrix;
proxy.m_maxContacts = DG_MAX_CONTATCS - contactCount;
proxy.m_contacts = &contacts[contactCount];
if (useSimd) {
contactCount += m_world->CalculateConvexToConvexContactsSimd (proxy);
} else {
contactCount += m_world->CalculateConvexToConvexContacts (proxy);
}
if (contactCount > (DG_MAX_CONTATCS - 2 * (DG_CONSTRAINT_MAX_ROWS / 3))) {
contactCount = m_world->ReduceContacts (contactCount, contacts, DG_CONSTRAINT_MAX_ROWS / 3, DG_REDUCE_CONTACT_TOLERANCE);
}
}
*/
} else {
const dgNodeBase *const left = me->m_left;
dgFloat32 leftDist = dgFloat32(0.0f);
if (left->m_type != m_leaf) {
leftDist = left->BoxClosestDistance(points, 8);
}
const dgNodeBase *const right = me->m_right;
dgFloat32 rightDist = dgFloat32(0.0f);
if (right->m_type != m_leaf) {
rightDist = right->BoxClosestDistance(points, 8);
}
NEWTON_ASSERT(me->m_type == m_node);
if (leftDist > rightDist) {
distPool[stack] = leftDist;
stackPool[stack] = me->m_left;
stack++;
NEWTON_ASSERT(stack < dgInt32(sizeof(stackPool) / sizeof(dgNodeBase *)));
distPool[stack] = rightDist;
stackPool[stack] = me->m_right;
stack++;
NEWTON_ASSERT(stack < dgInt32(sizeof(stackPool) / sizeof(dgNodeBase *)));
} else {
distPool[stack] = rightDist;
stackPool[stack] = me->m_right;
stack++;
NEWTON_ASSERT(stack < dgInt32(sizeof(stackPool) / sizeof(dgNodeBase *)));
distPool[stack] = leftDist;
stackPool[stack] = me->m_left;
stack++;
NEWTON_ASSERT(stack < dgInt32(sizeof(stackPool) / sizeof(dgNodeBase *)));
}
}
}
}
return 0;
#endif
// this is temporary until I implement the code above using the spacial organization
dgInt32 retFlag = 1;
dgContactPoint contact0;
dgContactPoint contact1;
contact0.m_point = dgVector(dgFloat32(0.0f), dgFloat32(0.0f), dgFloat32(0.0f), dgFloat32(0.0f));
contact1.m_point = dgVector(dgFloat32(0.0f), dgFloat32(0.0f), dgFloat32(0.0f), dgFloat32(0.0f));
contact0.m_normal = dgVector(dgFloat32(0.0f), dgFloat32(1.0f), dgFloat32(0.0f), dgFloat32(0.0f));
contact1.m_normal = dgVector(dgFloat32(0.0f), dgFloat32(1.0f), dgFloat32(0.0f), dgFloat32(0.0f));
if (bodyB->m_collision->IsType(dgCollision::dgConvexCollision_RTTI)) {
dgCollisionParamProxy proxy(0);
dgContactPoint contacts[16];
proxy.m_referenceBody = compoundBody;
proxy.m_floatingBody = bodyB;
proxy.m_floatingCollision = bodyB->m_collision;
proxy.m_floatingMatrix = bodyB->m_collisionWorldMatrix;
proxy.m_timestep = dgFloat32(0.0f);
proxy.m_penetrationPadding = dgFloat32(0.0f);
proxy.m_unconditionalCast = 1;
proxy.m_continueCollision = 0;
proxy.m_maxContacts = 16;
proxy.m_contacts = &contacts[0];
dgMatrix myMatrix(m_offset * compoundBody->m_matrix);
dgFloat32 minDist2 = dgFloat32(1.0e10f);
for (dgInt32 i = 0; (i < m_count) && retFlag; i++) {
retFlag = 0;
proxy.m_referenceCollision = m_array[i];
proxy.m_referenceMatrix = m_array[i]->m_offset * myMatrix;
dgInt32 flag = m_world->ClosestPoint(proxy);
if (flag) {
retFlag = 1;
dgVector err(contacts[0].m_point - contacts[1].m_point);
dgFloat32 dist2 = err % err;
if (dist2 < minDist2) {
minDist2 = dist2;
contact0 = contacts[0];
contact1 = contacts[1];
}
}
}
} else {
dgCollisionParamProxy proxy(0);
dgContactPoint contacts[16];
NEWTON_ASSERT(
bodyB->m_collision->IsType(dgCollision::dgCollisionCompound_RTTI));
dgCollisionCompound *const compoundCollision1 =
(dgCollisionCompound *)bodyB->m_collision;
dgInt32 count1 = compoundCollision1->m_count;
dgCollisionConvex **collisionArray1 = compoundCollision1->m_array;
proxy.m_referenceBody = compoundBody;
proxy.m_floatingBody = bodyB;
proxy.m_timestep = dgFloat32(0.0f);
proxy.m_penetrationPadding = dgFloat32(0.0f);
proxy.m_unconditionalCast = 1;
proxy.m_continueCollision = 0;
proxy.m_maxContacts = 16;
proxy.m_contacts = &contacts[0];
dgMatrix myMatrix(m_offset * compoundBody->m_matrix);
dgMatrix otherMatrix(compoundCollision1->m_offset * bodyB->m_matrix);
dgFloat32 minDist2 = dgFloat32(1.0e10f);
for (dgInt32 i = 0; (i < m_count) && retFlag; i++) {
proxy.m_referenceCollision = m_array[i];
proxy.m_referenceMatrix = m_array[i]->m_offset * myMatrix;
for (dgInt32 j = 0; (j < count1) && retFlag; j++) {
retFlag = 0;
proxy.m_floatingCollision = collisionArray1[j];
proxy.m_floatingMatrix = collisionArray1[j]->m_offset * otherMatrix;
dgInt32 flag = m_world->ClosestPoint(proxy);
if (flag) {
retFlag = 1;
dgVector err(contacts[0].m_point - contacts[1].m_point);
dgFloat32 dist2 = err % err;
if (dist2 < minDist2) {
minDist2 = dist2;
contact0 = contacts[0];
contact1 = contacts[1];
}
}
}
}
}
if (retFlag) {
contactA.m_x = contact0.m_point.m_x;
contactA.m_y = contact0.m_point.m_y;
contactA.m_z = contact0.m_point.m_z;
contactB.m_x = contact1.m_point.m_x;
contactB.m_y = contact1.m_point.m_y;
contactB.m_z = contact1.m_point.m_z;
normalAB.m_x = contact0.m_normal.m_x;
normalAB.m_y = contact0.m_normal.m_y;
normalAB.m_z = contact0.m_normal.m_z;
}
return retFlag;
}