/* Copyright (c) <2003-2011> * * 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 "dgCollisionScene.h" #include "dgBody.h" #include "dgCollisionNull.h" #include "dgContact.h" #include "dgWorld.h" #include "hpl1/engine/libraries/newton/core/dg.h" #define DG_SCENE_MAX_STACK_DEPTH 128 #define DG_SCENE_AABB_SCALE dgFloat32(4.0f) #define DG_SCENE_AABB_INV_SCALE (dgFloat32(1.0f) / DG_SCENE_AABB_SCALE) dgCollisionScene::dgNode::dgNode() : m_parent(NULL), m_left(NULL), m_right(NULL), m_fitnessNode(NULL) { } dgCollisionScene::dgNode::dgNode(dgNode *const sibling, dgNode *const myNode) : m_parent(sibling->m_parent), m_left(sibling), m_right(myNode), m_fitnessNode( NULL) { if (m_parent) { if (m_parent->m_left == sibling) { m_parent->m_left = this; } else { NEWTON_ASSERT(m_parent->m_right == sibling); m_parent->m_right = this; } } sibling->m_parent = this; myNode->m_parent = this; dgNode *const left = m_left; dgNode *const right = m_right; m_minBox = dgVector(GetMin(left->m_minBox.m_x, right->m_minBox.m_x), GetMin(left->m_minBox.m_y, right->m_minBox.m_y), GetMin(left->m_minBox.m_z, right->m_minBox.m_z), dgFloat32(0.0f)); m_maxBox = dgVector(GetMax(left->m_maxBox.m_x, right->m_maxBox.m_x), GetMax(left->m_maxBox.m_y, right->m_maxBox.m_y), GetMax(left->m_maxBox.m_z, right->m_maxBox.m_z), dgFloat32(0.0f)); dgVector side0(m_maxBox - m_minBox); dgVector side1(side0.m_y, side0.m_z, side0.m_x, dgFloat32(0.0f)); m_surfaceArea = side0 % side1; } dgCollisionScene::dgNode::~dgNode() { if (m_left) { delete (m_left); } if (m_right) { delete (m_right); } } dgCollisionScene::dgProxy::dgProxy(dgCollision *shape, const dgMatrix &matrix, dgCollisionScene *const owner) : dgNode(), m_matrix(shape->GetOffsetMatrix() * matrix), m_userData(NULL), m_shape(shape), m_owner(owner), m_myNode(NULL) { dgVector boxP0; dgVector boxP1; shape->CalcAABB(m_matrix, boxP0, boxP1); dgVector p0( boxP0.CompProduct( dgVector(DG_SCENE_AABB_SCALE, DG_SCENE_AABB_SCALE, DG_SCENE_AABB_SCALE, dgFloat32(0.0f)))); dgVector p1( boxP1.CompProduct( dgVector(DG_SCENE_AABB_SCALE, DG_SCENE_AABB_SCALE, DG_SCENE_AABB_SCALE, dgFloat32(0.0f)))); m_minBox.m_x = dgFloor(p0.m_x) * DG_SCENE_AABB_INV_SCALE; m_minBox.m_y = dgFloor(p0.m_y) * DG_SCENE_AABB_INV_SCALE; m_minBox.m_z = dgFloor(p0.m_z) * DG_SCENE_AABB_INV_SCALE; m_minBox.m_w = dgFloat32(0.0f); m_maxBox.m_x = dgFloor(p1.m_x + dgFloat32(1.0f)) * DG_SCENE_AABB_INV_SCALE; m_maxBox.m_y = dgFloor(p1.m_y + dgFloat32(1.0f)) * DG_SCENE_AABB_INV_SCALE; m_maxBox.m_z = dgFloor(p1.m_z + dgFloat32(1.0f)) * DG_SCENE_AABB_INV_SCALE; m_maxBox.m_w = dgFloat32(0.0f); dgVector side0(m_maxBox - m_minBox); dgVector side1(side0.m_y, side0.m_z, side0.m_x, dgFloat32(0.0f)); m_surfaceArea = side0 % side1; } dgCollisionScene::dgProxy::~dgProxy() { } dgCollisionScene::dgCollisionScene(dgWorld *world) : dgCollision(world->GetAllocator(), 0, dgGetIdentityMatrix(), m_sceneCollision), m_lock(0), m_list(world->GetAllocator()), m_fitnessList( world->GetAllocator()) { m_world = world; m_rootNode = NULL; m_rtti |= dgCollisionScene_RTTI; SetCollisionBBox( dgVector(dgFloat32(0.0f), dgFloat32(0.0f), dgFloat32(0.0f), dgFloat32(0.0f)), dgVector(dgFloat32(0.0f), dgFloat32(0.0f), dgFloat32(0.0f), dgFloat32(0.0f))); } dgCollisionScene::dgCollisionScene(dgWorld *const world, dgDeserialize deserialization, void *const userData) : dgCollision(world, deserialization, userData), m_lock(0), m_list(world->GetAllocator()), m_fitnessList(world->GetAllocator()) { dgInt32 data[4]; m_world = world; m_rtti |= dgCollisionScene_RTTI; deserialization(userData, &data, sizeof(data)); for (dgInt32 i = 0; i < data[0]; i++) { dgMatrix matrix; void *dataNew; deserialization(userData, &matrix, sizeof(dgMatrix)); deserialization(userData, &dataNew, sizeof(void *)); dgCollision *const collision = m_world->CreateFromSerialization( deserialization, userData); dgList::dgListNode *const proxyNode = (dgList::dgListNode *)AddProxy(collision, matrix); dgProxy *const proxy = proxyNode->GetInfo(); proxy->m_userData = dataNew; collision->Release(); } ImproveTotalFitness(); } dgCollisionScene::~dgCollisionScene(void) { for (dgList::dgListNode *node = m_list.GetFirst(); node;) { dgList::dgListNode *const proxyNode = node; node = node->GetNext(); RemoveProxy(proxyNode); } } void dgCollisionScene::Serialize(dgSerialize callback, void *const userData) const { dgInt32 data[4]; SerializeLow(callback, userData); data[0] = m_list.GetCount(); data[1] = 0; data[2] = 0; data[3] = 0; callback(userData, &data, sizeof(data)); for (dgList::dgListNode *node = m_list.GetFirst(); node; node = node->GetNext()) { dgProxy *const proxy = node->GetInfo(); callback(userData, &proxy->m_matrix, sizeof(dgMatrix)); callback(userData, &proxy->m_userData, sizeof(void *)); m_world->Serialize(proxy->m_shape, callback, userData); } } void dgCollisionScene::SetProxyMatrix(void *proxy, const dgMatrix &matrix) { dgVector boxP0; dgVector boxP1; dgProxy *const entry = ((dgList::dgListNode *)proxy)->GetInfo(); entry->m_matrix = entry->m_shape->GetOffsetMatrix() * matrix; entry->m_shape->CalcAABB(entry->m_matrix, boxP0, boxP1); dgVector p0( boxP0.CompProduct( dgVector(DG_SCENE_AABB_SCALE, DG_SCENE_AABB_SCALE, DG_SCENE_AABB_SCALE, dgFloat32(0.0f)))); dgVector p1( boxP1.CompProduct( dgVector(DG_SCENE_AABB_SCALE, DG_SCENE_AABB_SCALE, DG_SCENE_AABB_SCALE, dgFloat32(0.0f)))); p0.m_x = dgFloor(p0.m_x) * DG_SCENE_AABB_INV_SCALE; p0.m_y = dgFloor(p0.m_y) * DG_SCENE_AABB_INV_SCALE; p0.m_z = dgFloor(p0.m_z) * DG_SCENE_AABB_INV_SCALE; p1.m_x = dgFloor(p1.m_x + dgFloat32(1.0f)) * DG_SCENE_AABB_INV_SCALE; p1.m_y = dgFloor(p1.m_y + dgFloat32(1.0f)) * DG_SCENE_AABB_INV_SCALE; p1.m_z = dgFloor(p1.m_z + dgFloat32(1.0f)) * DG_SCENE_AABB_INV_SCALE; entry->m_minBox = p0; entry->m_maxBox = p1; dgVector side0(p1 - p0); dgVector side1(side0.m_y, side0.m_z, side0.m_x, dgFloat32(0.0f)); entry->m_surfaceArea = side0 % side1; for (dgNode *parent = entry->m_parent; parent; parent = parent->m_parent) { dgVector minBox; dgVector maxBox; dgFloat32 area = CalculateSurfaceArea(parent->m_left, parent->m_right, minBox, maxBox); if (!((parent->m_minBox.m_x < minBox.m_x) || (parent->m_minBox.m_y < minBox.m_y) || (parent->m_minBox.m_z < minBox.m_z) || (parent->m_maxBox.m_x > maxBox.m_x) || (parent->m_maxBox.m_y < maxBox.m_y) || (parent->m_maxBox.m_z < maxBox.m_z))) { break; } m_world->dgGetIndirectLock(&m_lock); parent->m_minBox = minBox; parent->m_maxBox = maxBox; parent->m_surfaceArea = area; m_world->dgReleaseIndirectLock(&m_lock); } } dgMatrix dgCollisionScene::GetProxyMatrix(void *const proxy) { dgProxy *const entry = ((dgList::dgListNode *)proxy)->GetInfo(); return entry->m_shape->GetOffsetMatrix().Inverse() * entry->m_matrix; } void dgCollisionScene::SetProxyUserData(void *const proxy, void *const userData) { dgProxy *const entry = ((dgList::dgListNode *)proxy)->GetInfo(); entry->m_userData = userData; } void *dgCollisionScene::GetProxyUserData(void *const proxy) const { dgProxy *const entry = ((dgList::dgListNode *)proxy)->GetInfo(); return entry->m_userData; } void dgCollisionScene::SetCollisionCallback( dgCollisionMeshCollisionCallback debugCallback) { NEWTON_ASSERT(0); /* for (dgList::dgListNode* node = m_list.GetFirst(); node; node = node->GetNext()) { const dgCollisionScene::dgProxy& entry = node->GetInfo(); if (entry.m_shape->IsType (dgCollisionMesh_RTTI)) { dgCollisionMesh* mesh; mesh = (dgCollisionMesh*)entry.m_shape; mesh->SetCollisionCallback (debugCallback); } } */ } void dgCollisionScene::CalcAABB(const dgMatrix &matrix, dgVector &p0, dgVector &p1) const { dgVector origin(matrix.TransformVector(m_boxOrigin)); dgVector size( m_boxSize.m_x * dgAbsf(matrix[0][0]) + m_boxSize.m_y * dgAbsf(matrix[1][0]) + m_boxSize.m_z * dgAbsf(matrix[2][0]) + DG_MAX_COLLISION_PADDING, m_boxSize.m_x * dgAbsf(matrix[0][1]) + m_boxSize.m_y * dgAbsf(matrix[1][1]) + m_boxSize.m_z * dgAbsf(matrix[2][1]) + DG_MAX_COLLISION_PADDING, m_boxSize.m_x * dgAbsf(matrix[0][2]) + m_boxSize.m_y * dgAbsf(matrix[1][2]) + m_boxSize.m_z * dgAbsf(matrix[2][2]) + DG_MAX_COLLISION_PADDING, dgFloat32(0.0f)); p0 = origin - size; p1 = origin + size; #ifdef DG_DEBUG_AABB dgInt32 i; dgVector q0; dgVector q1; dgMatrix trans(matrix.Transpose()); for (i = 0; i < 3; i++) { q0[i] = matrix.m_posit[i] + matrix.RotateVector(BoxSupportMapping(trans[i].Scale(-1.0f)))[i]; q1[i] = matrix.m_posit[i] + matrix.RotateVector(BoxSupportMapping(trans[i]))[i]; } dgVector err0(p0 - q0); dgVector err1(p1 - q1); dgFloat32 err; err = GetMax(size.m_x, size.m_y, size.m_z) * 0.5f; NEWTON_ASSERT((err0 % err0) < err); NEWTON_ASSERT((err1 % err1) < err); #endif } void dgCollisionScene::CalcAABBSimd(const dgMatrix &matrix, dgVector &p0, dgVector &p1) const { CalcAABB(matrix, p0, p1); } void dgCollisionScene::DebugCollision(const dgMatrix &matrix, OnDebugCollisionMeshCallback callback, void *const userData) const { for (dgList::dgListNode *node = m_list.GetFirst(); node; node = node->GetNext()) { const dgCollisionScene::dgProxy *entry = node->GetInfo(); dgMatrix proxyMatrix(entry->m_matrix * matrix); entry->m_shape->DebugCollision( entry->m_shape->GetOffsetMatrix() * proxyMatrix, callback, userData); } } dgFloat32 dgCollisionScene::GetVolume() const { NEWTON_ASSERT(0); return dgFloat32(0.0f); } dgInt32 dgCollisionScene::CalculateSignature() const { NEWTON_ASSERT(0); return 0; } dgFloat32 dgCollisionScene::GetBoxMinRadius() const { return dgFloat32(0.0f); } dgFloat32 dgCollisionScene::GetBoxMaxRadius() const { return dgFloat32(0.0f); } void dgCollisionScene::SetCollisionBBox(const dgVector &p0, const dgVector &p1) { NEWTON_ASSERT(p0.m_x <= p1.m_x); NEWTON_ASSERT(p0.m_y <= p1.m_y); NEWTON_ASSERT(p0.m_z <= p1.m_z); m_boxSize = (p1 - p0).Scale(dgFloat32(0.5f)); m_boxOrigin = (p1 + p0).Scale(dgFloat32(0.5f)); } void dgCollisionScene::CalculateInertia(dgVector &inertia, dgVector &origin) const { inertia.m_x = dgFloat32(0.0f); inertia.m_y = dgFloat32(0.0f); inertia.m_z = dgFloat32(0.0f); origin.m_x = dgFloat32(0.0f); origin.m_y = dgFloat32(0.0f); origin.m_z = dgFloat32(0.0f); } dgVector dgCollisionScene::CalculateVolumeIntegral(const dgMatrix &globalMatrix, GetBuoyancyPlane bouyancyPlane, void *const context) const { NEWTON_ASSERT(0); return dgVector(dgFloat32(0.0f), dgFloat32(0.0f), dgFloat32(0.0f), dgFloat32(0.0f)); } void dgCollisionScene::GetCollisionInfo(dgCollisionInfo *info) const { dgCollision::GetCollisionInfo(info); info->m_offsetMatrix = dgGetIdentityMatrix(); info->m_sceneCollision.m_childrenProxyCount = m_list.GetCount(); } bool dgCollisionScene::OOBBTest(const dgMatrix &matrix, const dgCollisionConvex *const shape, void *const cacheOrder) const { NEWTON_ASSERT(0); return true; } dgVector dgCollisionScene::SupportVertex(const dgVector &dir) const { NEWTON_ASSERT(0); return dgVector(0, 0, 0, 0); } dgFloat32 dgCollisionScene::RayCastSimd(const dgVector &localP0, const dgVector &localP1, dgContactPoint &contactOut, OnRayPrecastAction preFilter, const dgBody *const body, void *const userData) const { const dgNode *stackPool[DG_SCENE_MAX_STACK_DEPTH]; if (!m_rootNode) { return dgFloat32(1.2f); } dgInt32 stack = 1; stackPool[0] = m_rootNode; dgFloat32 maxParam = dgFloat32(1.2f); dgFastRayTest ray(localP0, localP1); while (stack) { stack--; const dgNode *const me = stackPool[stack]; if (ray.BoxTestSimd(me->m_minBox, me->m_maxBox)) { if (!me->m_left) { NEWTON_ASSERT(!me->m_right); dgContactPoint tmpContactOut; const dgProxy *const proxy = (const dgProxy *)me; dgVector l0(proxy->m_matrix.UntransformVector(localP0)); dgVector l1(proxy->m_matrix.UntransformVector(localP1)); dgFloat32 param = proxy->m_shape->RayCastSimd(l0, l1, tmpContactOut, preFilter, body, userData); NEWTON_ASSERT(param >= dgFloat32(0.0f)); if (param < maxParam) { contactOut.m_normal = proxy->m_matrix.RotateVectorSimd( tmpContactOut.m_normal); maxParam = param; ray.Reset(maxParam); } } else { NEWTON_ASSERT(me->m_left); NEWTON_ASSERT(stack < dgInt32(sizeof(stackPool) / sizeof(dgNode *))); stackPool[stack] = me->m_left; stack++; NEWTON_ASSERT(me->m_right); NEWTON_ASSERT(stack < dgInt32(sizeof(stackPool) / sizeof(dgNode *))); stackPool[stack] = me->m_right; stack++; } } } return maxParam; } dgFloat32 dgCollisionScene::RayCast(const dgVector &localP0, const dgVector &localP1, dgContactPoint &contactOut, OnRayPrecastAction preFilter, const dgBody *const body, void *const userData) const { const dgNode *stackPool[DG_SCENE_MAX_STACK_DEPTH]; if (!m_rootNode) { return dgFloat32(1.2f); } dgInt32 stack = 1; stackPool[0] = m_rootNode; dgFloat32 maxParam = dgFloat32(1.2f); // int xxx = 0; dgFastRayTest ray(localP0, localP1); while (stack) { stack--; const dgNode *const me = stackPool[stack]; // xxx ++; if (ray.BoxTest(me->m_minBox, me->m_maxBox)) { if (!me->m_left) { NEWTON_ASSERT(!me->m_right); dgContactPoint tmpContactOut; const dgProxy *const proxy = (const dgProxy *)me; dgVector l0(proxy->m_matrix.UntransformVector(localP0)); dgVector l1(proxy->m_matrix.UntransformVector(localP1)); dgFloat32 param = proxy->m_shape->RayCast(l0, l1, tmpContactOut, preFilter, body, userData); NEWTON_ASSERT(param >= dgFloat32(0.0f)); if (param < maxParam) { contactOut.m_normal = proxy->m_matrix.RotateVector( tmpContactOut.m_normal); maxParam = param; ray.Reset(maxParam); } } else { NEWTON_ASSERT(me->m_left); NEWTON_ASSERT(stack < dgInt32(sizeof(stackPool) / sizeof(dgNode *))); stackPool[stack] = me->m_left; stack++; NEWTON_ASSERT(me->m_right); NEWTON_ASSERT(stack < dgInt32(sizeof(stackPool) / sizeof(dgNode *))); stackPool[stack] = me->m_right; stack++; } } } return maxParam; } void dgCollisionScene::CollidePairSimd( dgCollidingPairCollector::dgPair *const pair, dgCollisionParamProxy &proxy) const { const dgNode *stackPool[DG_SCENE_MAX_STACK_DEPTH]; NEWTON_ASSERT(pair->m_body1->GetCollision() == this); NEWTON_ASSERT( pair->m_body1->GetCollision()->IsType(dgCollision::dgCollisionScene_RTTI)); dgVector p0; dgVector p1; NEWTON_ASSERT(m_world == pair->m_body1->GetWorld()); dgMatrix matrix(pair->m_body0->m_matrix * pair->m_body1->m_matrix.Inverse()); pair->m_body0->GetCollision()->CalcAABBSimd(matrix, p0, p1); dgInt32 stack = 1; stackPool[0] = m_rootNode; while (stack) { stack--; const dgNode *const me = stackPool[stack]; if (dgOverlapTestSimd(me->m_minBox, me->m_maxBox, p0, p1)) { if (!me->m_left) { NEWTON_ASSERT(!me->m_right); const dgProxy *const sceneProxy = (const dgProxy *)me; m_world->SceneContactsSimd(*sceneProxy, pair, proxy); } else { NEWTON_ASSERT(me->m_left); NEWTON_ASSERT(stack < dgInt32(sizeof(stackPool) / sizeof(dgNode *))); stackPool[stack] = me->m_left; stack++; NEWTON_ASSERT(me->m_right); NEWTON_ASSERT(stack < dgInt32(sizeof(stackPool) / sizeof(dgNode *))); stackPool[stack] = me->m_right; stack++; } } } } void dgCollisionScene::CollidePair(dgCollidingPairCollector::dgPair *const pair, dgCollisionParamProxy &proxy) const { const dgNode *stackPool[DG_SCENE_MAX_STACK_DEPTH]; NEWTON_ASSERT(pair->m_body1->GetCollision() == this); NEWTON_ASSERT( pair->m_body1->GetCollision()->IsType(dgCollision::dgCollisionScene_RTTI)); dgVector p0; dgVector p1; NEWTON_ASSERT(m_world == pair->m_body1->GetWorld()); dgMatrix matrix(pair->m_body0->m_matrix * pair->m_body1->m_matrix.Inverse()); pair->m_body0->GetCollision()->CalcAABB(matrix, p0, p1); dgInt32 stack = 1; stackPool[0] = m_rootNode; while (stack) { stack--; const dgNode *const me = stackPool[stack]; if (dgOverlapTest(me->m_minBox, me->m_maxBox, p0, p1)) { if (!me->m_left) { NEWTON_ASSERT(!me->m_right); const dgProxy *const sceneProxy = (const dgProxy *)me; m_world->SceneContacts(*sceneProxy, pair, proxy); } else { NEWTON_ASSERT(me->m_left); NEWTON_ASSERT(stack < dgInt32(sizeof(stackPool) / sizeof(dgNode *))); stackPool[stack] = me->m_left; stack++; NEWTON_ASSERT(me->m_right); NEWTON_ASSERT(stack < dgInt32(sizeof(stackPool) / sizeof(dgNode *))); stackPool[stack] = me->m_right; stack++; } } } } void dgCollisionScene::ImproveNodeFitness(dgNode *const node) { 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_surfaceArea; 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)) { dgNode *const parent = node->m_parent; node->m_minBox = parent->m_minBox; node->m_maxBox = parent->m_maxBox; node->m_surfaceArea = parent->m_surfaceArea; 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; } } else { m_rootNode = 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_minBox = cost1P0; parent->m_maxBox = cost1P1; parent->m_surfaceArea = cost1; } else if ((cost2 <= cost0) && (cost2 <= cost1)) { dgNode *const parent = node->m_parent; node->m_minBox = parent->m_minBox; node->m_maxBox = parent->m_maxBox; node->m_surfaceArea = parent->m_surfaceArea; 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; } } else { m_rootNode = 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_minBox = cost2P0; parent->m_maxBox = cost2P1; parent->m_surfaceArea = cost2; } } else { dgFloat32 cost0 = node->m_surfaceArea; 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)) { dgNode *const parent = node->m_parent; node->m_minBox = parent->m_minBox; node->m_maxBox = parent->m_maxBox; node->m_surfaceArea = parent->m_surfaceArea; 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; } } else { m_rootNode = 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_minBox = cost1P0; parent->m_maxBox = cost1P1; parent->m_surfaceArea = cost1; } else if ((cost2 <= cost0) && (cost2 <= cost1)) { dgNode *const parent = node->m_parent; node->m_minBox = parent->m_minBox; node->m_maxBox = parent->m_maxBox; node->m_surfaceArea = parent->m_surfaceArea; 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; } } else { m_rootNode = 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_minBox = cost2P0; parent->m_maxBox = cost2P1; parent->m_surfaceArea = cost2; } } } NEWTON_ASSERT(!m_rootNode->m_parent); } void dgCollisionScene::ImproveTotalFitness() { dgInt32 maxPasses = 2 * exp_2(m_fitnessList.GetCount()) + 1; dgFloat64 newCost = dgFloat32(1.0e20f); dgFloat64 prevCost = newCost; do { prevCost = newCost; for (dgList::dgListNode *node = m_fitnessList.GetFirst(); node; node = node->GetNext()) { ImproveNodeFitness(node->GetInfo()); } newCost = dgFloat32(0.0f); for (dgList::dgListNode *node = m_fitnessList.GetFirst(); node; node = node->GetNext()) { newCost += node->GetInfo()->m_surfaceArea; } maxPasses--; } while (maxPasses && (newCost < prevCost)); SetCollisionBBox(m_rootNode->m_minBox, m_rootNode->m_maxBox); } dgFloat32 dgCollisionScene::CalculateSurfaceArea(const dgNode *const node0, const dgNode *const node1, dgVector &minBox, dgVector &maxBox) const { minBox = dgVector(GetMin(node0->m_minBox.m_x, node1->m_minBox.m_x), GetMin(node0->m_minBox.m_y, node1->m_minBox.m_y), GetMin(node0->m_minBox.m_z, node1->m_minBox.m_z), dgFloat32(0.0f)); maxBox = dgVector(GetMax(node0->m_maxBox.m_x, node1->m_maxBox.m_x), GetMax(node0->m_maxBox.m_y, node1->m_maxBox.m_y), GetMax(node0->m_maxBox.m_z, node1->m_maxBox.m_z), dgFloat32(0.0f)); dgVector side0(maxBox - minBox); dgVector side1(side0.m_y, side0.m_z, side0.m_x, dgFloat32(0.0f)); return side0 % side1; } void *dgCollisionScene::GetFirstProxy() const { return m_list.GetFirst(); } void *dgCollisionScene::GetNextProxy(void *const proxy) const { dgList::dgListNode *const node = (dgList::dgListNode *)proxy; return node->GetNext(); } void *dgCollisionScene::AddProxy(dgCollision *const shape, const dgMatrix &matrix) { shape->AddRef(); dgProxy *const newNode = new (m_world->GetAllocator()) dgProxy(shape, matrix, this); newNode->m_myNode = m_list.Append(newNode); if (!m_rootNode) { m_rootNode = newNode; } else { dgVector p0; dgVector p1; dgNode *sibling = m_rootNode; dgFloat32 surfaceArea = CalculateSurfaceArea(newNode, sibling, p0, p1); while (sibling->m_left && sibling->m_right) { if (surfaceArea > sibling->m_surfaceArea) { break; } sibling->m_minBox = p0; sibling->m_maxBox = p1; sibling->m_surfaceArea = surfaceArea; dgVector leftP0; dgVector leftP1; dgFloat32 leftSurfaceArea = CalculateSurfaceArea(newNode, sibling->m_left, leftP0, leftP1); dgVector rightP0; dgVector rightP1; dgFloat32 rightSurfaceArea = CalculateSurfaceArea(newNode, sibling->m_right, rightP0, rightP1); if (leftSurfaceArea < rightSurfaceArea) { sibling = sibling->m_left; p0 = leftP0; p1 = leftP1; surfaceArea = leftSurfaceArea; } else { sibling = sibling->m_right; p0 = rightP0; p1 = rightP1; surfaceArea = rightSurfaceArea; } } dgNode *const parent = new (m_world->GetAllocator()) dgNode(sibling, newNode); parent->m_fitnessNode = m_fitnessList.Append(parent); if (!parent->m_parent) { m_rootNode = parent; } } return newNode->m_myNode; } void dgCollisionScene::RemoveProxy(void *const proxy) { dgList::dgListNode *const node = (dgList::dgListNode *)proxy; dgProxy *const treeNode = node->GetInfo(); m_world->ReleaseCollision(treeNode->m_shape); m_list.Remove(node); if (!treeNode->m_parent) { delete (m_rootNode); m_rootNode = NULL; } else if (!treeNode->m_parent->m_parent) { m_fitnessList.Remove(treeNode->m_parent->m_fitnessNode); dgNode *const root = m_rootNode; if (treeNode->m_parent->m_left == treeNode) { m_rootNode = treeNode->m_parent->m_right; treeNode->m_parent->m_right = NULL; } else { m_rootNode = treeNode->m_parent->m_left; treeNode->m_parent->m_left = NULL; } m_rootNode->m_parent = NULL; delete (root); } else { m_fitnessList.Remove(treeNode->m_parent->m_fitnessNode); dgNode *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); } }