/* 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 "hpl1/engine/libraries/newton/core/dg.h" #include "dgBodyMasterList.h" #include "dgCollision.h" #include "dgCollisionBVH.h" #include "dgCollisionBox.h" #include "dgCollisionCapsule.h" #include "dgCollisionChamferCylinder.h" #include "dgCollisionCompound.h" #include "dgCollisionCompoundBreakable.h" #include "dgCollisionCone.h" #include "dgCollisionConvexHull.h" #include "dgCollisionConvexModifier.h" #include "dgCollisionCylinder.h" #include "dgCollisionEllipse.h" #include "dgCollisionHeightField.h" #include "dgCollisionNull.h" #include "dgCollisionScene.h" #include "dgCollisionSphere.h" #include "dgCollisionUserMesh.h" #include "dgWorld.h" #include "dgWorldDynamicUpdate.h" #define DG_USE_CACHE_CONTACTS #define DG_PRUNE_PADDING_BYTES 128 //#define DG_CONTACT_CACHE_TOLERANCE dgFloat32 (1.0e-6f) //#define DG_REDUCE_CONTACT_TOLERANCE dgFloat32 (1.0e-2f) //#define DG_PRUNE_CONTACT_TOLERANCE dgFloat32 (1.0e-2f) #define DG_COMPOUND_MAX_SORT_ARRAY (1024 * 2) dgCollision *dgWorld::CreateNull() { dgUnsigned32 crc; dgCollision *collision; dgBodyCollisionList::dgTreeNode *node; crc = dgCollision::dgCollisionNull_RTTI; node = dgBodyCollisionList::Find(crc); if (!node) { collision = new (m_allocator) dgCollisionNull(m_allocator, crc); node = dgBodyCollisionList::Insert(collision, crc); } node->GetInfo()->AddRef(); return node->GetInfo(); } dgCollision *dgWorld::CreateBox(dgFloat32 dx, dgFloat32 dy, dgFloat32 dz, dgInt32 shapeID, const dgMatrix &offsetMatrix) { // dgUnsigned32 crc; // dgCollision* collision; // dgBodyCollisionList::dgTreeNode* node; dgUnsigned32 buffer[2 * sizeof(dgMatrix) / sizeof(dgInt32)]; dx = dgAbsf(dx); dy = dgAbsf(dy); dz = dgAbsf(dz); memset(buffer, 0, sizeof(buffer)); buffer[0] = m_boxCollision; buffer[1] = dgCollision::Quantize(dx * dgFloat32(0.5f)); buffer[2] = dgCollision::Quantize(dy * dgFloat32(0.5f)); buffer[3] = dgCollision::Quantize(dz * dgFloat32(0.5f)); buffer[4] = dgUnsigned32(shapeID); memcpy(&buffer[5], &offsetMatrix, sizeof(dgMatrix)); dgUnsigned32 crc = dgCollision::MakeCRC(buffer, sizeof(buffer)); dgBodyCollisionList::dgTreeNode *node = dgBodyCollisionList::Find(crc); if (!node) { dgCollision *const collision = new (m_allocator) dgCollisionBox(m_allocator, crc, dx, dy, dz, offsetMatrix); collision->SetUserDataID(dgUnsigned32(shapeID)); node = dgBodyCollisionList::Insert(collision, crc); } node->GetInfo()->AddRef(); return node->GetInfo(); } dgCollision *dgWorld::CreateSphere(dgFloat32 radii, dgInt32 shapeID, const dgMatrix &offsetMatrix) { dgUnsigned32 buffer[2 * sizeof(dgMatrix) / sizeof(dgInt32)]; radii = dgAbsf(radii); memset(buffer, 0, sizeof(buffer)); buffer[0] = m_sphereCollision; buffer[1] = dgCollision::Quantize(radii); buffer[2] = dgUnsigned32(shapeID); memcpy(&buffer[3], &offsetMatrix, sizeof(dgMatrix)); dgUnsigned32 crc = dgCollision::MakeCRC(buffer, sizeof(buffer)); dgBodyCollisionList::dgTreeNode *node = dgBodyCollisionList::Find(crc); if (!node) { dgCollision *const collision = new (m_allocator) dgCollisionSphere( m_allocator, crc, radii, offsetMatrix); collision->SetUserDataID(dgUnsigned32(shapeID)); node = dgBodyCollisionList::Insert(collision, crc); } node->GetInfo()->AddRef(); return node->GetInfo(); } dgCollision *dgWorld::CreateEllipse(dgFloat32 rx, dgFloat32 ry, dgFloat32 rz, dgInt32 shapeID, const dgMatrix &offsetMatrix) { dgUnsigned32 buffer[2 * sizeof(dgMatrix) / sizeof(dgInt32)]; rx = dgAbsf(rx); ry = dgAbsf(ry); rz = dgAbsf(rz); memset(buffer, 0, sizeof(buffer)); buffer[0] = m_ellipseCollision; buffer[1] = dgCollision::Quantize(rx); buffer[2] = dgCollision::Quantize(ry); buffer[3] = dgCollision::Quantize(rz); buffer[4] = dgUnsigned32(shapeID); memcpy(&buffer[5], &offsetMatrix, sizeof(dgMatrix)); dgUnsigned32 crc = dgCollision::MakeCRC(buffer, sizeof(buffer)); dgBodyCollisionList::dgTreeNode *node = dgBodyCollisionList::Find(crc); if (!node) { dgCollision *const collision = new (m_allocator) dgCollisionEllipse( m_allocator, crc, rx, ry, rz, offsetMatrix); collision->SetUserDataID(dgUnsigned32(shapeID)); node = dgBodyCollisionList::Insert(collision, crc); } node->GetInfo()->AddRef(); return node->GetInfo(); } dgCollision *dgWorld::CreateCapsule(dgFloat32 radius, dgFloat32 height, dgInt32 shapeID, const dgMatrix &offsetMatrix) { dgUnsigned32 crc; dgCollision *collision; dgBodyCollisionList::dgTreeNode *node; dgUnsigned32 buffer[2 * sizeof(dgMatrix) / sizeof(dgInt32)]; radius = dgAbsf(radius); height = dgAbsf(height); memset(buffer, 0, sizeof(buffer)); buffer[0] = m_capsuleCollision; buffer[1] = dgCollision::Quantize(radius); buffer[2] = dgCollision::Quantize(height * dgFloat32(0.5f)); buffer[3] = dgUnsigned32(shapeID); memcpy(&buffer[4], &offsetMatrix, sizeof(dgMatrix)); crc = dgCollision::MakeCRC(buffer, sizeof(buffer)); node = dgBodyCollisionList::Find(crc); if (!node) { collision = new (m_allocator) dgCollisionCapsule(m_allocator, crc, radius, height, offsetMatrix); collision->SetUserDataID(dgUnsigned32(shapeID)); node = dgBodyCollisionList::Insert(collision, crc); } node->GetInfo()->AddRef(); return node->GetInfo(); } dgCollision *dgWorld::CreateCone(dgFloat32 radius, dgFloat32 height, dgInt32 shapeID, const dgMatrix &offsetMatrix) { dgUnsigned32 crc; dgCollision *collision; dgBodyCollisionList::dgTreeNode *node; dgUnsigned32 buffer[2 * sizeof(dgMatrix) / sizeof(dgInt32)]; radius = dgAbsf(radius); height = dgAbsf(height); memset(buffer, 0, sizeof(buffer)); buffer[0] = m_coneCollision; buffer[1] = dgCollision::Quantize(radius); buffer[2] = dgCollision::Quantize(height * dgFloat32(0.5f)); buffer[3] = dgUnsigned32(shapeID); memcpy(&buffer[4], &offsetMatrix, sizeof(dgMatrix)); crc = dgCollision::MakeCRC(buffer, sizeof(buffer)); node = dgBodyCollisionList::Find(crc); if (!node) { collision = new (m_allocator) dgCollisionCone(m_allocator, crc, radius, height, offsetMatrix); collision->SetUserDataID(dgUnsigned32(shapeID)); node = dgBodyCollisionList::Insert(collision, crc); } node->GetInfo()->AddRef(); return node->GetInfo(); } dgCollision *dgWorld::CreateCylinder(dgFloat32 radius, dgFloat32 height, dgInt32 shapeID, const dgMatrix &offsetMatrix) { dgUnsigned32 crc; dgCollision *collision; dgBodyCollisionList::dgTreeNode *node; dgUnsigned32 buffer[2 * sizeof(dgMatrix) / sizeof(dgInt32)]; radius = dgAbsf(radius); height = dgAbsf(height); memset(buffer, 0, sizeof(buffer)); buffer[0] = m_cylinderCollision; buffer[1] = dgCollision::Quantize(radius); buffer[2] = dgCollision::Quantize(height * dgFloat32(0.5f)); buffer[3] = dgUnsigned32(shapeID); memcpy(&buffer[4], &offsetMatrix, sizeof(dgMatrix)); crc = dgCollision::MakeCRC(buffer, sizeof(buffer)); node = dgBodyCollisionList::Find(crc); if (!node) { collision = new (m_allocator) dgCollisionCylinder(m_allocator, crc, radius, height, offsetMatrix); collision->SetUserDataID(dgUnsigned32(shapeID)); node = dgBodyCollisionList::Insert(collision, crc); } node->GetInfo()->AddRef(); return node->GetInfo(); } dgCollision *dgWorld::CreateChamferCylinder(dgFloat32 radius, dgFloat32 height, dgInt32 shapeID, const dgMatrix &offsetMatrix) { dgUnsigned32 crc; dgCollision *collision; dgBodyCollisionList::dgTreeNode *node; dgUnsigned32 buffer[2 * sizeof(dgMatrix) / sizeof(dgInt32)]; radius = dgAbsf(radius); height = dgAbsf(height); memset(buffer, 0, sizeof(buffer)); buffer[0] = m_chamferCylinderCollision; buffer[1] = dgCollision::Quantize(radius); buffer[2] = dgCollision::Quantize(height * dgFloat32(0.5f)); buffer[3] = dgUnsigned32(shapeID); memcpy(&buffer[4], &offsetMatrix, sizeof(dgMatrix)); crc = dgCollision::MakeCRC(buffer, sizeof(buffer)); node = dgBodyCollisionList::Find(crc); if (!node) { collision = new (m_allocator) dgCollisionChamferCylinder(m_allocator, crc, radius, height, offsetMatrix); collision->SetUserDataID(dgUnsigned32(shapeID)); node = dgBodyCollisionList::Insert(collision, crc); } node->GetInfo()->AddRef(); return node->GetInfo(); } dgCollision *dgWorld::CreateConvexHull(dgInt32 count, const dgFloat32 *vertexArray, dgInt32 strideInBytes, dgFloat32 tolerance, dgInt32 shapeID, const dgMatrix &offsetMatrix) { dgStack buffer( 2 + 3 * count + dgInt32(sizeof(dgMatrix) / sizeof(dgInt32))); // create crc signature for cache lookup memset(&buffer[0], 0, size_t(buffer.GetSizeInBytes())); buffer[0] = m_convexHullCollision; buffer[1] = dgUnsigned32(shapeID); dgInt32 stride = dgInt32(strideInBytes / sizeof(dgFloat32)); for (dgInt32 i = 0; i < count; i++) { buffer[2 + i * 3 + 0] = dgCollision::Quantize(vertexArray[i * stride + 0]); buffer[2 + i * 3 + 1] = dgCollision::Quantize(vertexArray[i * stride + 1]); buffer[2 + i * 3 + 2] = dgCollision::Quantize(vertexArray[i * stride + 2]); } memcpy(&buffer[2 + count * 3], &offsetMatrix, sizeof(dgMatrix)); dgUnsigned32 crc = dgCollision::MakeCRC(&buffer[0], buffer.GetSizeInBytes()); // find the shape in cache dgBodyCollisionList::dgTreeNode *node = dgBodyCollisionList::Find(crc); if (!node) { // chape not found crate a new one and add to the cache dgCollisionConvexHull *const collision = new (m_allocator) dgCollisionConvexHull(m_allocator, crc, count, strideInBytes, tolerance, vertexArray, offsetMatrix); if (collision->GetVertexCount()) { collision->SetUserDataID(dgUnsigned32(shapeID)); node = dgBodyCollisionList::Insert(collision, crc); } else { /* // hack to save the data that make convex hull fail char xxx[32]; static int aaa ; snprintf (xxx, 32, "file1__%d.txt", aaa); aaa ++; FILE * file = fopen (xxx, "wb"); fprintf (file, "float data[][3] = {\n"); for (dgInt32 i = 0; i < count; i ++) { fprintf (file, "{%f, %f, %f},\n", vertexArray[i * stride + 0], vertexArray[i * stride + 1], vertexArray[i * stride + 2]); } fprintf (file, "};\n"); fclose (file); */ NEWTON_ASSERT(0); // could not make the shape destroy the shell and return NULL // note this is the only newton shape that can return NULL; collision->Release(); return NULL; } } // add reference to the shape and return the collision pointer node->GetInfo()->AddRef(); return node->GetInfo(); } dgCollision *dgWorld::CreateConvexModifier(dgCollision *convexCollision) { dgCollision *collision; collision = NULL; if (convexCollision->IsType(dgCollision::dgConvexCollision_RTTI)) { // if (!convexCollision->IsType (dgCollision::dgCollisionCompound_RTTI) && !convexCollision->IsType (m_nullType)) { if (!convexCollision->IsType(dgCollision::dgCollisionNull_RTTI)) { collision = new (m_allocator) dgCollisionConvexModifier( (dgCollisionConvex *)convexCollision, this); } } return collision; } dgCollision *dgWorld::CreateCollisionCompound(dgInt32 count, dgCollision *const array[]) { // compound collision are not cached return new (m_allocator) dgCollisionCompound(count, (dgCollisionConvex * const*)array, this); } // dgCollision* dgWorld::CreateCollisionCompoundBreakable ( // dgInt32 count, // dgMeshEffect* const solidArray[], // dgMeshEffect* const splitePlanes[], // dgMatrix* const matrixArray, // dgInt32* const idArray, // dgFloat32* const densities, // dgInt32 debriID, // dgCollisionCompoundBreakableCallback callback, // void* buildUsedData) dgCollision *dgWorld::CreateCollisionCompoundBreakable(dgInt32 count, dgMeshEffect *const solidArray[], const dgInt32 *const idArray, const dgFloat32 *const densities, const dgInt32 *const internalFaceMaterial, dgInt32 debriID, dgFloat32 gap) { // return new dgCollisionCompoundBreakable (count, solidArray, splitePlanes, matrixArray, idArray, densities, debriID, callback, buildUsedData, this); return new (m_allocator) dgCollisionCompoundBreakable(count, solidArray, idArray, densities, internalFaceMaterial, debriID, gap, this); } dgCollision *dgWorld::CreateBVH() { // collision tree are not cached return new (m_allocator) dgCollisionBVH(m_allocator); } dgCollision *dgWorld::CreateStaticUserMesh(const dgVector &boxP0, const dgVector &boxP1, const dgUserMeshCreation &data) { return new (m_allocator) dgCollisionUserMesh(m_allocator, boxP0, boxP1, data); } dgCollision *dgWorld::CreateBVHFieldCollision(dgInt32 width, dgInt32 height, dgInt32 contructionMode, const dgUnsigned16 *const elevationMap, const dgInt8 *const atributeMap, dgFloat32 horizontalScale, dgFloat32 vertcalScale) { return new (m_allocator) dgCollisionHeightField(this, width, height, contructionMode, elevationMap, atributeMap, horizontalScale, vertcalScale); } dgCollision *dgWorld::CreateScene() { return new (m_allocator) dgCollisionScene(this); } void dgWorld::Serialize(const dgCollision *shape, dgSerialize serialization, void *const userData) const { dgInt32 signature[4]; signature[0] = shape->GetCollisionPrimityType(); signature[1] = dgInt32(shape->GetSignature()); signature[2] = 0; signature[3] = 0; serialization(userData, signature, sizeof(signature)); shape->Serialize(serialization, userData); dgInt32 end = SERIALIZE_END; serialization(userData, &end, sizeof(dgInt32)); } // dgCollision* dgWorld::CreateFromSerialization (dgInt32 signature, dgCollisionID type, dgDeserialize deserialization, void* const userData) dgCollision *dgWorld::CreateFromSerialization(dgDeserialize deserialization, void *const userData) { dgInt32 signature[4]; deserialization(userData, signature, sizeof(signature)); dgBodyCollisionList::dgTreeNode *node = dgBodyCollisionList::Find( dgUnsigned32(signature[1])); dgCollision *collision = NULL; if (node) { collision = node->GetInfo(); collision->AddRef(); } else { switch (signature[0]) { case m_sceneCollision: { collision = new (m_allocator) dgCollisionScene(this, deserialization, userData); break; } case m_heightField: { collision = new (m_allocator) dgCollisionHeightField(this, deserialization, userData); break; } case m_boundingBoxHierachy: { collision = new (m_allocator) dgCollisionBVH(this, deserialization, userData); break; } // if (!stricmp (type, "box")) case m_boxCollision: { collision = new (m_allocator) dgCollisionBox(this, deserialization, userData); node = dgBodyCollisionList::Insert(collision, collision->GetSignature()); collision->AddRef(); break; } //} else if (!stricmp (type, "cone")) { case m_coneCollision: { collision = new (m_allocator) dgCollisionCone(this, deserialization, userData); node = dgBodyCollisionList::Insert(collision, collision->GetSignature()); collision->AddRef(); break; } //} else if (!stricmp (type, "sphere_1")) { case m_ellipseCollision: { collision = new (m_allocator) dgCollisionEllipse(this, deserialization, userData); node = dgBodyCollisionList::Insert(collision, collision->GetSignature()); collision->AddRef(); break; } //} else if (!stricmp (type, "sphere")) { case m_sphereCollision: { collision = new (m_allocator) dgCollisionSphere(this, deserialization, userData); node = dgBodyCollisionList::Insert(collision, collision->GetSignature()); collision->AddRef(); break; } //} else if (!stricmp (type, "cylinder")) { case m_cylinderCollision: { collision = new (m_allocator) dgCollisionCylinder(this, deserialization, userData); node = dgBodyCollisionList::Insert(collision, collision->GetSignature()); collision->AddRef(); break; } //} else if (!stricmp (type, "capsule")) { case m_capsuleCollision: { collision = new (m_allocator) dgCollisionCapsule(this, deserialization, userData); node = dgBodyCollisionList::Insert(collision, collision->GetSignature()); collision->AddRef(); break; } //} else if (!stricmp (type, "compound")) { case m_compoundCollision: { collision = new (m_allocator) dgCollisionCompound(this, deserialization, userData); break; } case m_compoundBreakable: { collision = new (m_allocator) dgCollisionCompoundBreakable(this, deserialization, userData); break; } //} else if (!stricmp (type, "convexHull")) { case m_convexHullCollision: { collision = new (m_allocator) dgCollisionConvexHull(this, deserialization, userData); node = dgBodyCollisionList::Insert(collision, collision->GetSignature()); collision->AddRef(); break; } case m_convexConvexIntance: { collision = new (m_allocator) dgCollisionCompoundBreakable::dgCollisionConvexIntance( this, deserialization, userData); break; } //} else if (!stricmp (type, "chamferCylinder")) { case m_chamferCylinderCollision: { collision = new (m_allocator) dgCollisionChamferCylinder(this, deserialization, userData); node = dgBodyCollisionList::Insert(collision, collision->GetSignature()); collision->AddRef(); break; } case m_nullCollision: { collision = new (m_allocator) dgCollisionNull(this, deserialization, userData); node = dgBodyCollisionList::Insert(collision, collision->GetSignature()); collision->AddRef(); break; } case m_convexCollisionModifier: { collision = new (m_allocator) dgCollisionConvexModifier(this, deserialization, userData); break; } default: NEWTON_ASSERT(0); } } dgInt32 endMarker; do { deserialization(userData, &endMarker, sizeof(dgInt32)); } while (endMarker != SERIALIZE_END); return collision; } dgContactMaterial *dgWorld::GetMaterial(dgUnsigned32 bodyGroupId0, dgUnsigned32 bodyGroupId1) const { if (bodyGroupId0 > bodyGroupId1) { Swap(bodyGroupId0, bodyGroupId1); } dgUnsigned32 key = (bodyGroupId1 << 16) + bodyGroupId0; dgBodyMaterialList::dgTreeNode *const node = dgBodyMaterialList::Find(key); return node ? &node->GetInfo() : NULL; } dgContactMaterial *dgWorld::GetFirstMaterial() const { dgBodyMaterialList::dgTreeNode *const node = dgBodyMaterialList::Minimum(); NEWTON_ASSERT(node); return &node->GetInfo(); } dgContactMaterial *dgWorld::GetNextMaterial(dgContactMaterial *material) const { dgBodyMaterialList::dgTreeNode *const thisNode = dgBodyMaterialList::GetNodeFromInfo(*material); NEWTON_ASSERT(thisNode); dgBodyMaterialList::dgTreeNode *const node = (dgBodyMaterialList::dgTreeNode *)thisNode->Next(); if (node) { return &node->GetInfo(); } return NULL; } dgUnsigned32 dgWorld::GetDefualtBodyGroupID() const { return m_defualtBodyGroupID; } dgUnsigned32 dgWorld::CreateBodyGroupID() { dgContactMaterial pairMaterial; pairMaterial.m_aabbOverlap = NULL; pairMaterial.m_contactPoint = NULL; pairMaterial.m_compoundAABBOverlap = NULL; dgUnsigned32 newId = m_bodyGroupID; m_bodyGroupID += 1; for (dgUnsigned32 i = 0; i < m_bodyGroupID; i++) { dgUnsigned32 key = (newId << 16) + i; dgBodyMaterialList::Insert(pairMaterial, key); } return newId; } void dgWorld::RemoveFromCache(dgCollision *const collision) { dgBodyCollisionList::dgTreeNode *const node = dgBodyCollisionList::Find( collision->m_signature); if (node) { collision->m_signature = 0xffffffff; NEWTON_ASSERT(node->GetInfo() == collision); collision->Release(); dgBodyCollisionList::Remove(node); } } void dgWorld::ReleaseCollision(dgCollision *const collision) { if (m_destroyCollision) { if (collision->GetRefCount() == 1) { m_destroyCollision(this, collision); } } dgInt32 ref = collision->Release(); if (ref == 1) { dgBodyCollisionList::dgTreeNode *const node = dgBodyCollisionList::Find( collision->m_signature); if (node) { NEWTON_ASSERT(node->GetInfo() == collision); if (m_destroyCollision) { m_destroyCollision(this, collision); } collision->Release(); dgBodyCollisionList::Remove(node); } } } // ******************************************************************************** // // separate collision system // // ******************************************************************************** dgInt32 dgWorld::ClosestPoint(const dgTriplex &point, dgCollision *const collision, const dgMatrix &matrix, dgTriplex &contact, dgTriplex &normal, dgInt32 threadIndex) const { dgTriplex contactA; dgMatrix pointMatrix(dgGetIdentityMatrix()); contact = point; pointMatrix.m_posit.m_x = point.m_x; pointMatrix.m_posit.m_y = point.m_y; pointMatrix.m_posit.m_z = point.m_z; return ClosestPoint(collision, matrix, m_pointCollision, pointMatrix, contact, contactA, normal, threadIndex); } dgInt32 dgWorld::ClosestPoint(dgCollision *const collisionA, const dgMatrix &matrixA, dgCollision *const collisionB, const dgMatrix &matrixB, dgTriplex &contactA, dgTriplex &contactB, dgTriplex &normalAB, dgInt32 threadIndex) const { dgBody collideBodyA; dgBody collideBodyB; collideBodyA.m_matrix = matrixA; collideBodyA.m_collision = collisionA; collideBodyA.m_collisionWorldMatrix = collisionA->m_offset * matrixA; collideBodyB.m_matrix = matrixB; collideBodyB.m_collision = collisionB; collideBodyB.m_collisionWorldMatrix = collisionB->m_offset * matrixB; if (collisionA->IsType(dgCollision::dgCollisionCompound_RTTI)) { return ClosestCompoundPoint(&collideBodyA, &collideBodyB, contactA, contactB, normalAB, threadIndex); } else if (collisionB->IsType(dgCollision::dgCollisionCompound_RTTI)) { dgInt32 flag; flag = ClosestCompoundPoint(&collideBodyB, &collideBodyA, contactB, contactA, normalAB, threadIndex); normalAB.m_x *= dgFloat32(-1.0f); normalAB.m_y *= dgFloat32(-1.0f); normalAB.m_z *= dgFloat32(-1.0f); return flag; } else if (collisionA->IsType(dgCollision::dgConvexCollision_RTTI) && collisionB->IsType(dgCollision::dgConvexCollision_RTTI)) { dgInt32 flag; dgCollisionParamProxy proxy(threadIndex); dgContactPoint contacts[16]; proxy.m_referenceBody = &collideBodyA; proxy.m_referenceCollision = collideBodyA.m_collision; proxy.m_referenceMatrix = collideBodyA.m_collisionWorldMatrix; proxy.m_floatingBody = &collideBodyB; proxy.m_floatingCollision = collideBodyB.m_collision; proxy.m_floatingMatrix = collideBodyB.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]; flag = ClosestPoint(proxy); if (flag) { contactA.m_x = contacts[0].m_point.m_x; contactA.m_y = contacts[0].m_point.m_y; contactA.m_z = contacts[0].m_point.m_z; contactB.m_x = contacts[1].m_point.m_x; contactB.m_y = contacts[1].m_point.m_y; contactB.m_z = contacts[1].m_point.m_z; normalAB.m_x = contacts[0].m_normal.m_x; normalAB.m_y = contacts[0].m_normal.m_y; normalAB.m_z = contacts[0].m_normal.m_z; } return flag; } return 0; } dgInt32 dgWorld::ClosestCompoundPoint(dgBody *const compoundConvexA, dgBody *const collisionB, dgTriplex &contactA, dgTriplex &contactB, dgTriplex &normalAB, dgInt32 threadIndex) const { dgCollisionCompound *const collision = (dgCollisionCompound *)compoundConvexA->m_collision; NEWTON_ASSERT(collision->IsType(dgCollision::dgCollisionCompound_RTTI)); return collision->ClosestDitance(compoundConvexA, contactA, collisionB, contactB, normalAB); /* dgInt32 retFlag; dgInt32 count; dgMatrix* collisionMatrixArray; dgCollisionConvex** collisionArray; dgCollisionCompound *compoundCollision; dgContactPoint contact0; dgContactPoint contact1; compoundCollision = (dgCollisionCompound *) compoundConvexA->m_collision; count = compoundCollision->m_count; collisionArray = compoundCollision->m_array; collisionMatrixArray = compoundCollision->m_collisionMatrix; retFlag = 0; if (collisionB->m_collision->IsType (dgCollision::dgConvexCollision_RTTI)) { dgFloat32 minDist2; dgCollisionParamProxy proxy(threadIndex); dgContactPoint contacts[16]; proxy.m_referenceBody = compoundConvexA; proxy.m_floatingBody = collisionB; proxy.m_floatingCollision = collisionB->m_collision; proxy.m_floatingMatrix = collisionB->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 saveCollMatrix (compoundConvexA->m_collisionWorldMatrix); minDist2 = dgFloat32 (1.0e10f); for (dgInt32 i = 0; i < count; i ++) { dgInt32 flag; compoundConvexA->m_collision = collisionArray[i]; compoundConvexA->m_collisionWorldMatrix = collisionArray[i]->m_offset * saveCollMatrix; proxy.m_referenceCollision = compoundConvexA->m_collision; proxy.m_referenceMatrix = compoundConvexA->m_collisionWorldMatrix; flag = ClosestPoint (proxy); if (flag) { dgFloat32 dist2; retFlag = 1; dgVector err (contacts[0].m_point - contacts[1].m_point); dist2 = err % err; if (dist2 < minDist2) { minDist2 = dist2; contact0 = contacts[0]; contact1 = contacts[1]; } } } } else { dgInt32 count1; dgFloat32 minDist2; dgCollisionParamProxy proxy(threadIndex); dgContactPoint contacts[16]; dgMatrix* collisionMatrixArray1; dgCollisionConvex** collisionArray1; dgCollisionCompound *compoundCollision1; NEWTON_ASSERT (collisionB->m_collision->IsType (dgCollision::dgCollisionCompound_RTTI)); dgMatrix saveCollMatrix (compoundConvexA->m_collisionWorldMatrix); dgMatrix saveCollMatrix1 (collisionB->m_collisionWorldMatrix); compoundCollision1 = (dgCollisionCompound *) collisionB->m_collision; count1 = compoundCollision1->m_count; collisionArray1 = compoundCollision1->m_array; collisionMatrixArray1 = compoundCollision1->m_collisionMatrix; proxy.m_referenceBody = compoundConvexA; proxy.m_floatingBody = collisionB; 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]; minDist2 = dgFloat32 (1.0e10f); for (dgInt32 i = 0; i < count; i ++) { compoundConvexA->m_collision = collisionArray[i]; compoundConvexA->m_collisionWorldMatrix = collisionArray[i]->m_offset * saveCollMatrix; proxy.m_referenceCollision = compoundConvexA->m_collision; proxy.m_referenceMatrix = compoundConvexA->m_collisionWorldMatrix; for (dgInt32 j = 0; j < count1; j ++) { dgInt32 flag; collisionB->m_collision = collisionArray1[j]; collisionB->m_collisionWorldMatrix = collisionArray1[j]->m_offset * saveCollMatrix1; proxy.m_floatingCollision = collisionB->m_collision; proxy.m_floatingMatrix = collisionB->m_collisionWorldMatrix ; flag = ClosestPoint (proxy); if (flag) { dgFloat32 dist2; retFlag = 1; dgVector err (contacts[0].m_point - contacts[1].m_point); 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; */ } // ********************************************************************************** // // dynamics collision system // // ********************************************************************************** static inline dgInt32 CompareContact(const dgContactPoint *const contactA, const dgContactPoint *const contactB, void *dommy) { if (contactA->m_point[0] < contactB->m_point[0]) { return -1; } else if (contactA->m_point[0] > contactB->m_point[0]) { return 1; } else { return 0; } } void dgWorld::SortContacts(dgContactPoint *const contact, dgInt32 count) const { dgSort(contact, count, CompareContact, NULL); } dgInt32 dgWorld::ReduceContacts(dgInt32 count, dgContactPoint *const contact, dgInt32 maxCount, dgFloat32 tol, dgInt32 arrayIsSorted) const { if ((count > maxCount) && (maxCount > 1)) { // dgInt32 index; // dgInt32 countOver; // dgFloat32 window; // dgFloat32 window2; dgUnsigned8 mask[DG_MAX_CONTATCS]; if (!arrayIsSorted) { SortContacts(contact, count); } dgInt32 index = 0; dgFloat32 window = tol; dgFloat32 window2 = window * window; dgInt32 countOver = count - maxCount; NEWTON_ASSERT(countOver >= 0); memset(mask, 0, size_t(count)); do { for (dgInt32 i = 0; (i < count) && countOver; i++) { if (!mask[i]) { dgFloat32 val = contact[i].m_point[index] + window; for (dgInt32 j = i + 1; (j < count) && countOver && (contact[j].m_point[index] < val); j++) { if (!mask[j]) { dgVector dp(contact[j].m_point - contact[i].m_point); dgFloat32 dist2 = dp % dp; if (dist2 < window2) { mask[j] = 1; countOver--; } } } } } window *= dgFloat32(2.0f); window2 = window * window; } while (countOver); dgInt32 j = 0; for (dgInt32 i = 0; i < count; i++) { if (!mask[i]) { contact[j] = contact[i]; j++; } } NEWTON_ASSERT(j == maxCount); } else { maxCount = count; } return maxCount; } dgInt32 dgWorld::PruneContacts(dgInt32 count, dgContactPoint *const contact, dgInt32 maxCount) const { // dgInt32 index; // dgInt32 packContacts; // dgFloat32 window; // dgFloat32 window2; dgUnsigned8 mask[DG_MAX_CONTATCS]; dgInt32 index = 0; dgInt32 packContacts = 0; dgFloat32 window = DG_PRUNE_CONTACT_TOLERANCE; dgFloat32 window2 = window * window; memset(mask, 0, size_t(count)); SortContacts(contact, count); for (dgInt32 i = 0; i < count; i++) { if (!mask[i]) { dgFloat32 val = contact[i].m_point[index] + window; for (dgInt32 j = i + 1; (j < count) && (contact[j].m_point[index] < val); j++) { if (!mask[j]) { dgVector dp(contact[j].m_point - contact[i].m_point); dgFloat32 dist2 = dp % dp; if (dist2 < window2) { mask[j] = 1; packContacts = 1; } } } } } if (packContacts) { dgInt32 j = 0; for (dgInt32 i = 0; i < count; i++) { if (!mask[i]) { contact[j] = contact[i]; j++; } } count = j; } if (count > maxCount) { count = ReduceContacts(count, contact, maxCount, window * dgFloat32(2.0f), 1); } return count; } void dgWorld::ProcessCachedContacts(dgContact *const contact, const dgContactMaterial *const material, dgFloat32 timestep, dgInt32 threadIndex) const { NEWTON_ASSERT(contact); NEWTON_ASSERT(contact->m_body0); NEWTON_ASSERT(contact->m_body1); NEWTON_ASSERT(contact->m_myCacheMaterial); NEWTON_ASSERT(contact->m_myCacheMaterial == material); NEWTON_ASSERT(contact->m_body0 != contact->m_body1); dgList &list = *contact; contact->m_broadphaseLru = dgInt32(m_broadPhaseLru); contact->m_myCacheMaterial = material; dgList::dgListNode *nextContactNode; for (dgList::dgListNode *contactNode = list.GetFirst(); contactNode; contactNode = nextContactNode) { nextContactNode = contactNode->GetNext(); dgContactMaterial &contactMaterial = contactNode->GetInfo(); NEWTON_ASSERT(dgCheckFloat(contactMaterial.m_point.m_x)); NEWTON_ASSERT(dgCheckFloat(contactMaterial.m_point.m_y)); NEWTON_ASSERT(dgCheckFloat(contactMaterial.m_point.m_z)); NEWTON_ASSERT(contactMaterial.m_body0); NEWTON_ASSERT(contactMaterial.m_body1); NEWTON_ASSERT(contactMaterial.m_collision0); NEWTON_ASSERT(contactMaterial.m_collision1); NEWTON_ASSERT(contactMaterial.m_body0 == contact->m_body0); NEWTON_ASSERT(contactMaterial.m_body1 == contact->m_body1); // NEWTON_ASSERT (contactMaterial.m_userId != 0xffffffff); contactMaterial.m_softness = material->m_softness; contactMaterial.m_restitution = material->m_restitution; contactMaterial.m_staticFriction0 = material->m_staticFriction0; contactMaterial.m_staticFriction1 = material->m_staticFriction1; contactMaterial.m_dynamicFriction0 = material->m_dynamicFriction0; contactMaterial.m_dynamicFriction1 = material->m_dynamicFriction1; // contactMaterial.m_collisionEnable = true; // contactMaterial.m_friction0Enable = material->m_friction0Enable; // contactMaterial.m_friction1Enable = material->m_friction1Enable; // contactMaterial.m_override0Accel = false; // contactMaterial.m_override1Accel = false; // contactMaterial.m_overrideNormalAccel = false; contactMaterial.m_flags = dgContactMaterial::m_collisionEnable__ | (material->m_flags & (dgContactMaterial::m_friction0Enable__ | dgContactMaterial::m_friction1Enable__)); contactMaterial.m_userData = material->m_userData; } if (material->m_contactPoint) { material->m_contactPoint(reinterpret_cast(contact), timestep, threadIndex); } contact->m_maxDOF = dgUnsigned32(3 * contact->GetCount()); } void dgWorld::ProcessTriggers(dgCollidingPairCollector::dgPair *const pair, dgFloat32 timestep, dgInt32 threadIndex) { dgBody *const body0 = pair->m_body0; dgBody *const body1 = pair->m_body1; dgContact *contact1 = pair->m_contact; const dgContactMaterial *const material = pair->m_material; NEWTON_ASSERT(body0 != body1); if (!contact1) { dgGetUserLock(); contact1 = new (m_allocator) dgContact(this); pair->m_contact = contact1; AttachConstraint(contact1, body0, body1); dgReleasedUserLock(); } else if (contact1->GetBody0() != body0) { NEWTON_ASSERT(0); NEWTON_ASSERT(contact1->GetBody1() == body0); NEWTON_ASSERT(contact1->GetBody0() == body1); Swap(contact1->m_body0, contact1->m_body1); Swap(contact1->m_link0, contact1->m_link1); } dgContact *const contact = contact1; contact->m_myCacheMaterial = material; contact->m_broadphaseLru = dgInt32(m_broadPhaseLru); NEWTON_ASSERT(body0); NEWTON_ASSERT(body1); NEWTON_ASSERT(contact->m_body0 == body0); NEWTON_ASSERT(contact->m_body1 == body1); if (material->m_contactPoint) { material->m_contactPoint(reinterpret_cast(contact), timestep, threadIndex); } contact->m_maxDOF = 0; } void dgWorld::ProcessContacts(dgCollidingPairCollector::dgPair *const pair, dgFloat32 timestep, dgInt32 threadIndex) { dgBody *const body0 = pair->m_body0; dgBody *const body1 = pair->m_body1; dgContact *contact1 = pair->m_contact; const dgContactMaterial *const material = pair->m_material; dgContactPoint *const contactArray = pair->m_contactBuffer; NEWTON_ASSERT(body0 != body1); if (!contact1) { dgGetUserLock(); contact1 = new (m_allocator) dgContact(this); pair->m_contact = contact1; AttachConstraint(contact1, body0, body1); dgReleasedUserLock(); } else if (contact1->GetBody0() != body0) { NEWTON_ASSERT(0); NEWTON_ASSERT(contact1->GetBody1() == body0); NEWTON_ASSERT(contact1->GetBody0() == body1); Swap(contact1->m_body0, contact1->m_body1); Swap(contact1->m_link0, contact1->m_link1); } dgContact *const contact = contact1; dgInt32 contactCount = pair->m_contactCount; contact->m_myCacheMaterial = material; dgList &list = *contact; contact->m_broadphaseLru = dgInt32(m_broadPhaseLru); NEWTON_ASSERT(body0); NEWTON_ASSERT(body1); NEWTON_ASSERT(contact->m_body0 == body0); NEWTON_ASSERT(contact->m_body1 == body1); contact->m_prevPosit0 = body0->m_matrix.m_posit; contact->m_prevPosit1 = body1->m_matrix.m_posit; contact->m_prevRotation0 = body0->m_rotation; contact->m_prevRotation1 = body1->m_rotation; dgInt32 count = 0; dgVector cachePosition[DG_MAX_CONTATCS]; dgList::dgListNode *nodes[DG_MAX_CONTATCS]; for (dgList::dgListNode *contactNode = list.GetFirst(); contactNode; contactNode = contactNode->GetNext()) { nodes[count] = contactNode; cachePosition[count] = contactNode->GetInfo().m_point; count++; } const dgVector &v0 = body0->m_veloc; const dgVector &w0 = body0->m_omega; const dgMatrix &matrix0 = body0->m_matrix; const dgVector &v1 = body1->m_veloc; const dgVector &w1 = body1->m_omega; const dgMatrix &matrix1 = body1->m_matrix; dgVector controlDir0(dgFloat32(0.0f), dgFloat32(0.0f), dgFloat32(0.0f), dgFloat32(0.0f)); dgVector controlDir1(dgFloat32(0.0f), dgFloat32(0.0f), dgFloat32(0.0f), dgFloat32(0.0f)); dgVector controlNormal(contactArray[0].m_normal); dgVector vel0(v0 + w0 * (contactArray[0].m_point - matrix0.m_posit)); dgVector vel1(v1 + w1 * (contactArray[0].m_point - matrix1.m_posit)); dgVector vRel(vel1 - vel0); dgVector tangDir(vRel - controlNormal.Scale(vRel % controlNormal)); dgFloat32 diff = tangDir % tangDir; dgInt32 staticMotion = 0; // if (diff > dgFloat32 (1.0e-2f)) { // staticMotion = 0; // } else { if (diff <= dgFloat32(1.0e-2f)) { staticMotion = 1; if (dgAbsf(controlNormal.m_z) > dgFloat32(0.577f)) { tangDir = dgVector(-controlNormal.m_y, controlNormal.m_z, dgFloat32(0.0f), dgFloat32(0.0f)); } else { tangDir = dgVector(-controlNormal.m_y, controlNormal.m_x, dgFloat32(0.0f), dgFloat32(0.0f)); } controlDir0 = controlNormal * tangDir; NEWTON_ASSERT(controlDir0 % controlDir0 > dgFloat32(1.0e-8f)); controlDir0 = controlDir0.Scale(dgRsqrt(controlDir0 % controlDir0)); controlDir1 = controlNormal * controlDir0; NEWTON_ASSERT( dgAbsf((controlDir0 * controlDir1) % controlNormal - dgFloat32(1.0f)) < dgFloat32(1.0e-3f)); } // dgTrace (("contact pair %d %d\n", body0->m_uniqueID, body1->m_uniqueID)); dgFloat32 maxImpulse = dgFloat32(-1.0f); dgFloat32 breakImpulse0 = dgFloat32(0.0f); dgFloat32 breakImpulse1 = dgFloat32(0.0f); for (dgInt32 i = 0; i < contactCount; i++) { dgList::dgListNode *contactNode; contactNode = NULL; dgFloat32 min = dgFloat32(1.0e20f); dgInt32 index = -1; for (dgInt32 j = 0; j < count; j++) { dgVector v(cachePosition[j] - contactArray[i].m_point); diff = v % v; if (diff < min) { min = diff; index = j; contactNode = nodes[j]; } } if (contactNode) { count--; NEWTON_ASSERT(index != -1); nodes[index] = nodes[count]; cachePosition[index] = cachePosition[count]; } else { dgGetUserLock(); contactNode = list.Append(); dgReleasedUserLock(); } dgContactMaterial *const contactMaterial = &contactNode->GetInfo(); NEWTON_ASSERT(dgCheckFloat(contactArray[i].m_point.m_x)); NEWTON_ASSERT(dgCheckFloat(contactArray[i].m_point.m_y)); NEWTON_ASSERT(dgCheckFloat(contactArray[i].m_point.m_z)); NEWTON_ASSERT(contactArray[i].m_body0); NEWTON_ASSERT(contactArray[i].m_body1); NEWTON_ASSERT(contactArray[i].m_collision0); NEWTON_ASSERT(contactArray[i].m_collision1); NEWTON_ASSERT(contactArray[i].m_body0 == body0); NEWTON_ASSERT(contactArray[i].m_body1 == body1); // NEWTON_ASSERT (contactArray[i].m_userId != 0xffffffff); contactMaterial->m_point = contactArray[i].m_point; contactMaterial->m_normal = contactArray[i].m_normal; contactMaterial->m_userId = contactArray[i].m_userId; contactMaterial->m_penetration = contactArray[i].m_penetration; contactMaterial->m_body0 = contactArray[i].m_body0; contactMaterial->m_body1 = contactArray[i].m_body1; contactMaterial->m_collision0 = contactArray[i].m_collision0; contactMaterial->m_collision1 = contactArray[i].m_collision1; contactMaterial->m_softness = material->m_softness; contactMaterial->m_restitution = material->m_restitution; contactMaterial->m_staticFriction0 = material->m_staticFriction0; contactMaterial->m_staticFriction1 = material->m_staticFriction1; contactMaterial->m_dynamicFriction0 = material->m_dynamicFriction0; contactMaterial->m_dynamicFriction1 = material->m_dynamicFriction1; NEWTON_ASSERT( (dgAbsf(contactMaterial->m_normal % contactMaterial->m_normal) - dgFloat32(1.0f)) < dgFloat32(1.0e-5f)); // dgTrace (("%f\n", contactMaterial.m_penetration)); // dgTrace (("p(%f %f %f) n(%f %f %f)\n", contactMaterial.m_point.m_x, contactMaterial.m_point.m_y, contactMaterial.m_point.m_z, // contactMaterial.m_normal.m_x, contactMaterial.m_normal.m_y, contactMaterial.m_normal.m_z)); // contactMaterial.m_collisionEnable = true; // contactMaterial.m_friction0Enable = material->m_friction0Enable; // contactMaterial.m_friction1Enable = material->m_friction1Enable; // contactMaterial.m_override0Accel = false; // contactMaterial.m_override1Accel = false; // contactMaterial.m_overrideNormalAccel = false; contactMaterial->m_flags = dgContactMaterial::m_collisionEnable__ | (material->m_flags & (dgContactMaterial::m_friction0Enable__ | dgContactMaterial::m_friction1Enable__)); contactMaterial->m_userData = material->m_userData; if (staticMotion) { if ((contactMaterial->m_normal % controlNormal) > dgFloat32(0.9995f)) { contactMaterial->m_dir0 = controlDir0; contactMaterial->m_dir1 = controlDir1; } else { if (dgAbsf(contactMaterial->m_normal.m_z) > dgFloat32(0.577f)) { tangDir = dgVector(-contactMaterial->m_normal.m_y, contactMaterial->m_normal.m_z, dgFloat32(0.0f), dgFloat32(0.0f)); } else { tangDir = dgVector(-contactMaterial->m_normal.m_y, contactMaterial->m_normal.m_x, dgFloat32(0.0f), dgFloat32(0.0f)); } contactMaterial->m_dir0 = contactMaterial->m_normal * tangDir; NEWTON_ASSERT( contactMaterial->m_dir0 % contactMaterial->m_dir0 > dgFloat32(1.0e-8f)); contactMaterial->m_dir0 = contactMaterial->m_dir0.Scale( dgRsqrt(contactMaterial->m_dir0 % contactMaterial->m_dir0)); contactMaterial->m_dir1 = contactMaterial->m_normal * contactMaterial->m_dir0; NEWTON_ASSERT( dgAbsf((contactMaterial->m_dir0 * contactMaterial->m_dir1) % contactMaterial->m_normal - dgFloat32(1.0f)) < dgFloat32(1.0e-3f)); } } else { dgVector velocity0(v0 + w0 * (contactMaterial->m_point - matrix0.m_posit)); dgVector velocity1(v1 + w1 * (contactMaterial->m_point - matrix1.m_posit)); dgVector vRelative(velocity1 - velocity0); dgFloat32 impulse = vRelative % contactMaterial->m_normal; if (dgAbsf(impulse) > maxImpulse) { maxImpulse = dgAbsf(impulse); breakImpulse0 = contactMaterial->m_collision0->GetBreakImpulse(); breakImpulse1 = contactMaterial->m_collision1->GetBreakImpulse(); } dgVector tangDirection(vRelative - contactMaterial->m_normal.Scale(impulse)); diff = tangDirection % tangDirection; if (diff > dgFloat32(1.0e-2f)) { contactMaterial->m_dir0 = tangDirection.Scale(dgRsqrt(diff)); } else { if (dgAbsf(contactMaterial->m_normal.m_z) > dgFloat32(0.577f)) { tangDirection = dgVector(-contactMaterial->m_normal.m_y, contactMaterial->m_normal.m_z, dgFloat32(0.0f), dgFloat32(0.0f)); } else { tangDirection = dgVector(-contactMaterial->m_normal.m_y, contactMaterial->m_normal.m_x, dgFloat32(0.0f), dgFloat32(0.0f)); } contactMaterial->m_dir0 = contactMaterial->m_normal * tangDirection; NEWTON_ASSERT( contactMaterial->m_dir0 % contactMaterial->m_dir0 > dgFloat32(1.0e-8f)); contactMaterial->m_dir0 = contactMaterial->m_dir0.Scale( dgRsqrt(contactMaterial->m_dir0 % contactMaterial->m_dir0)); } contactMaterial->m_dir1 = contactMaterial->m_normal * contactMaterial->m_dir0; NEWTON_ASSERT( dgAbsf((contactMaterial->m_dir0 * contactMaterial->m_dir1) % contactMaterial->m_normal - dgFloat32(1.0f)) < dgFloat32(1.0e-3f)); } contactMaterial->m_normal.m_w = dgFloat32(0.0f); contactMaterial->m_dir0.m_w = dgFloat32(0.0f); contactMaterial->m_dir1.m_w = dgFloat32(0.0f); } for (dgInt32 i = 0; i < count; i++) { dgGetUserLock(); list.Remove(nodes[i]); dgReleasedUserLock(); } if (material->m_contactPoint) { material->m_contactPoint(reinterpret_cast(contact), timestep, threadIndex); } if (maxImpulse > dgFloat32(1.0f)) { maxImpulse /= (body0->m_invMass.m_w + body1->m_invMass.m_w); if ((maxImpulse > breakImpulse0) || (maxImpulse > breakImpulse1)) { dgGetUserLock(); if (maxImpulse > breakImpulse0) { AddToBreakQueue(contact, body0, maxImpulse); } if (maxImpulse > breakImpulse1) { AddToBreakQueue(contact, body1, maxImpulse); } dgReleasedUserLock(); } } contact->m_maxDOF = dgUnsigned32(3 * contact->GetCount()); } dgInt32 dgWorld::ValidateContactCache(dgBody *const convexBody, dgBody *const otherBody, dgContact *const contact) const { NEWTON_ASSERT(contact && (contact->GetId() == dgContactConstraintId)); NEWTON_ASSERT( (contact->GetBody0() == otherBody) || (contact->GetBody1() == otherBody)); NEWTON_ASSERT( (contact->GetBody0() == convexBody) || (contact->GetBody1() == convexBody)); dgInt32 contactCount = 0; #ifdef DG_USE_CACHE_CONTACTS #define DG_CACHE_DIST_TOL dgFloat32(1.0e-3f) dgBody *const body0 = contact->GetBody0(); dgVector error0(contact->m_prevPosit0 - body0->m_matrix.m_posit); dgFloat32 err2 = error0 % error0; if (err2 < (DG_CACHE_DIST_TOL * DG_CACHE_DIST_TOL)) { dgBody *const body1 = contact->GetBody1(); dgVector error1(contact->m_prevPosit1 - body1->m_matrix.m_posit); err2 = error1 % error1; if (err2 < (DG_CACHE_DIST_TOL * DG_CACHE_DIST_TOL)) { dgQuaternion errorRot0(contact->m_prevRotation0 - body0->m_rotation); err2 = errorRot0.DotProduct(errorRot0); if (err2 < (DG_CACHE_DIST_TOL * DG_CACHE_DIST_TOL)) { dgQuaternion errorRot1(contact->m_prevRotation1 - body1->m_rotation); err2 = errorRot1.DotProduct(errorRot1); if (err2 < (DG_CACHE_DIST_TOL * DG_CACHE_DIST_TOL)) { dgMatrix matrix0( dgMatrix(contact->m_prevRotation0, contact->m_prevPosit0).Inverse() * body0->m_matrix); dgMatrix matrix1( dgMatrix(contact->m_prevRotation1, contact->m_prevPosit1).Inverse() * body1->m_matrix); dgList &list = *contact; for (dgList::dgListNode *ptr = list.GetFirst(); ptr; ptr = ptr->GetNext()) { dgContactMaterial &contactMaterial = ptr->GetInfo(); dgVector p0(matrix0.TransformVector(contactMaterial.m_point)); dgVector p1(matrix1.TransformVector(contactMaterial.m_point)); dgVector error(p1 - p0); err2 = error % error; if (err2 > (DG_CACHE_DIST_TOL * DG_CACHE_DIST_TOL)) { contactCount = 0; break; } contactCount++; } } } } } #endif return contactCount; } void dgWorld::CompoundContactsSimd(dgCollidingPairCollector::dgPair *const pair, dgCollisionParamProxy &proxy) const { dgInt32 contactCount; dgBody *otherBody; dgBody *compoundBody; dgContact *constraint; dgContactPoint *const contacts = pair->m_contactBuffer; constraint = pair->m_contact; compoundBody = pair->m_body0; otherBody = pair->m_body1; pair->m_contactCount = 0; proxy.m_contacts = contacts; pair->m_isTrigger = 0; proxy.m_isTriggerVolume = 0; proxy.m_inTriggerVolume = 0; if (constraint) { contactCount = ValidateContactCache(compoundBody, otherBody, constraint); if (contactCount) { pair->m_contactCount = 0; pair->m_contactBuffer = NULL; return; } } contactCount = ((dgCollisionCompound *)compoundBody->m_collision)->CalculateContacts(pair, proxy, 1); if (contactCount) { // prune close contacts pair->m_contactCount = dgInt16(PruneContacts(contactCount, contacts)); } } void dgWorld::CompoundContacts(dgCollidingPairCollector::dgPair *const pair, dgCollisionParamProxy &proxy) const { dgInt32 contactCount; dgBody *otherBody; dgBody *compoundBody; dgContact *constraint; dgContactPoint *const contacts = pair->m_contactBuffer; constraint = pair->m_contact; compoundBody = pair->m_body0; otherBody = pair->m_body1; pair->m_contactCount = 0; proxy.m_contacts = contacts; pair->m_isTrigger = 0; proxy.m_isTriggerVolume = 0; proxy.m_inTriggerVolume = 0; if (constraint) { contactCount = ValidateContactCache(compoundBody, otherBody, constraint); if (contactCount) { pair->m_contactCount = 0; pair->m_contactBuffer = NULL; return; } } contactCount = ((dgCollisionCompound *)compoundBody->m_collision)->CalculateContacts(pair, proxy, 0); if (contactCount) { // prune close contacts pair->m_contactCount = dgInt16(PruneContacts(contactCount, contacts)); } } void dgWorld::ConvexContactsSimd(dgCollidingPairCollector::dgPair *const pair, dgCollisionParamProxy &proxy) const { dgInt32 contactCount; dgBody *otherBody; dgBody *convexBody; dgContact *constraint; contactCount = 0; constraint = pair->m_contact; convexBody = pair->m_body0; otherBody = pair->m_body1; if (constraint) { contactCount = ValidateContactCache(convexBody, otherBody, constraint); if (contactCount) { pair->m_isTrigger = 0; pair->m_contactCount = 0; pair->m_contactBuffer = NULL; return; } } // proxy.m_maxContacts = DG_MAX_CONTATCS; proxy.m_contacts = pair->m_contactBuffer; if (otherBody->m_collision->IsType(dgCollision::dgConvexCollision_RTTI)) { if (convexBody->m_invMass.m_w <= dgFloat32(1.0e-6f)) { Swap(convexBody, otherBody); pair->m_body0 = convexBody; pair->m_body1 = otherBody; } NEWTON_ASSERT( convexBody->m_collision->IsType(dgCollision::dgConvexCollision_RTTI)); NEWTON_ASSERT( otherBody->m_collision->IsType(dgCollision::dgConvexCollision_RTTI)); NEWTON_ASSERT( pair->m_body0->m_collision->IsType(dgCollision::dgConvexCollision_RTTI)); NEWTON_ASSERT( pair->m_body1->m_collision->IsType(dgCollision::dgConvexCollision_RTTI)); proxy.m_referenceBody = convexBody; proxy.m_floatingBody = otherBody; proxy.m_referenceCollision = convexBody->m_collision; proxy.m_floatingCollision = otherBody->m_collision; proxy.m_referenceMatrix = convexBody->m_collisionWorldMatrix; proxy.m_floatingMatrix = otherBody->m_collisionWorldMatrix; // contactCount = CalculateConvexToConvexContacts (proxy); pair->m_contactCount = dgInt16(CalculateConvexToConvexContactsSimd(proxy)); pair->m_isTrigger = proxy.m_inTriggerVolume; } else { NEWTON_ASSERT( pair->m_body0->m_collision->IsType(dgCollision::dgConvexCollision_RTTI)); NEWTON_ASSERT( convexBody->m_collision->IsType(dgCollision::dgConvexCollision_RTTI)); proxy.m_referenceBody = convexBody; proxy.m_floatingBody = otherBody; proxy.m_referenceCollision = convexBody->m_collision; proxy.m_floatingCollision = otherBody->m_collision; proxy.m_referenceMatrix = convexBody->m_collisionWorldMatrix; proxy.m_floatingMatrix = otherBody->m_collisionWorldMatrix; // contactCount = CalculateConvexToNonConvexContacts (proxy); pair->m_contactCount = dgInt16( CalculateConvexToNonConvexContactsSimd(proxy)); pair->m_isTrigger = proxy.m_inTriggerVolume; } } void dgWorld::ConvexContacts(dgCollidingPairCollector::dgPair *const pair, dgCollisionParamProxy &proxy) const { dgInt32 contactCount = 0; dgContact *const constraint = pair->m_contact; dgBody *convexBody = pair->m_body0; dgBody *otherBody = pair->m_body1; if (constraint) { contactCount = ValidateContactCache(convexBody, otherBody, constraint); if (contactCount) { pair->m_isTrigger = 0; pair->m_contactCount = 0; pair->m_contactBuffer = NULL; return; } } // proxy.m_maxContacts = DG_MAX_CONTATCS; proxy.m_contacts = pair->m_contactBuffer; if (otherBody->m_collision->IsType(dgCollision::dgConvexCollision_RTTI)) { if (convexBody->m_invMass.m_w <= dgFloat32(1.0e-6f)) { Swap(convexBody, otherBody); pair->m_body0 = convexBody; pair->m_body1 = otherBody; } NEWTON_ASSERT( convexBody->m_collision->IsType(dgCollision::dgConvexCollision_RTTI)); NEWTON_ASSERT( otherBody->m_collision->IsType(dgCollision::dgConvexCollision_RTTI)); NEWTON_ASSERT( pair->m_body0->m_collision->IsType(dgCollision::dgConvexCollision_RTTI)); NEWTON_ASSERT( pair->m_body1->m_collision->IsType(dgCollision::dgConvexCollision_RTTI)); proxy.m_referenceBody = convexBody; proxy.m_floatingBody = otherBody; proxy.m_referenceCollision = convexBody->m_collision; proxy.m_floatingCollision = otherBody->m_collision; proxy.m_referenceMatrix = convexBody->m_collisionWorldMatrix; proxy.m_floatingMatrix = otherBody->m_collisionWorldMatrix; pair->m_contactCount = dgInt16(CalculateConvexToConvexContacts(proxy)); pair->m_isTrigger = proxy.m_inTriggerVolume; } else { NEWTON_ASSERT( pair->m_body0->m_collision->IsType(dgCollision::dgConvexCollision_RTTI)); NEWTON_ASSERT( convexBody->m_collision->IsType(dgCollision::dgConvexCollision_RTTI)); proxy.m_referenceBody = convexBody; proxy.m_floatingBody = otherBody; proxy.m_referenceCollision = convexBody->m_collision; proxy.m_floatingCollision = otherBody->m_collision; proxy.m_referenceMatrix = convexBody->m_collisionWorldMatrix; proxy.m_floatingMatrix = otherBody->m_collisionWorldMatrix; pair->m_contactCount = dgInt16(CalculateConvexToNonConvexContacts(proxy)); pair->m_isTrigger = proxy.m_inTriggerVolume; } } void dgWorld::SceneContactsSimd(const dgCollisionScene::dgProxy &sceneProxy, dgCollidingPairCollector::dgPair *const pair, dgCollisionParamProxy &proxy) const { NEWTON_ASSERT( pair->m_body1->GetCollision()->IsType(dgCollision::dgCollisionScene_RTTI)); if (sceneProxy.m_shape->IsType(dgCollision::dgConvexCollision_RTTI)) { proxy.m_floatingCollision = sceneProxy.m_shape; proxy.m_floatingMatrix = sceneProxy.m_matrix; proxy.m_maxContacts = ((DG_MAX_CONTATCS - pair->m_contactCount) > 16) ? 16 : DG_MAX_CONTATCS - pair->m_contactCount; proxy.m_contacts = &pair->m_contactBuffer[pair->m_contactCount]; pair->m_contactCount = pair->m_contactCount + dgInt16(CalculateConvexToConvexContactsSimd(proxy)); if (pair->m_contactCount > (DG_MAX_CONTATCS - 2 * (DG_CONSTRAINT_MAX_ROWS / 3))) { pair->m_contactCount = dgInt16( ReduceContacts(pair->m_contactCount, pair->m_contactBuffer, DG_CONSTRAINT_MAX_ROWS / 3, DG_REDUCE_CONTACT_TOLERANCE)); } // pair->m_isTrigger = proxy.m_inTriggerVolume; } else { proxy.m_floatingCollision = sceneProxy.m_shape; proxy.m_floatingMatrix = sceneProxy.m_matrix; proxy.m_maxContacts = ((DG_MAX_CONTATCS - pair->m_contactCount) > 32) ? 32 : DG_MAX_CONTATCS - pair->m_contactCount; proxy.m_contacts = &pair->m_contactBuffer[pair->m_contactCount]; pair->m_contactCount = pair->m_contactCount + dgInt16(CalculateConvexToNonConvexContactsSimd(proxy)); if (pair->m_contactCount > (DG_MAX_CONTATCS - 2 * (DG_CONSTRAINT_MAX_ROWS / 3))) { pair->m_contactCount = dgInt16( ReduceContacts(pair->m_contactCount, pair->m_contactBuffer, DG_CONSTRAINT_MAX_ROWS / 3, DG_REDUCE_CONTACT_TOLERANCE)); } // pair->m_isTrigger = proxy.m_inTriggerVolume; } } void dgWorld::SceneContacts(const dgCollisionScene::dgProxy &sceneProxy, dgCollidingPairCollector::dgPair *const pair, dgCollisionParamProxy &proxy) const { NEWTON_ASSERT( pair->m_body1->GetCollision()->IsType(dgCollision::dgCollisionScene_RTTI)); if (sceneProxy.m_shape->IsType(dgCollision::dgConvexCollision_RTTI)) { proxy.m_floatingCollision = sceneProxy.m_shape; proxy.m_floatingMatrix = sceneProxy.m_matrix; proxy.m_maxContacts = ((DG_MAX_CONTATCS - pair->m_contactCount) > 16) ? 16 : DG_MAX_CONTATCS - pair->m_contactCount; proxy.m_contacts = &pair->m_contactBuffer[pair->m_contactCount]; pair->m_contactCount = pair->m_contactCount + dgInt16(CalculateConvexToConvexContacts(proxy)); if (pair->m_contactCount > (DG_MAX_CONTATCS - 2 * (DG_CONSTRAINT_MAX_ROWS / 3))) { pair->m_contactCount = dgInt16( ReduceContacts(pair->m_contactCount, pair->m_contactBuffer, DG_CONSTRAINT_MAX_ROWS / 3, DG_REDUCE_CONTACT_TOLERANCE)); } // pair->m_isTrigger = proxy.m_inTriggerVolume; } else { proxy.m_floatingCollision = sceneProxy.m_shape; proxy.m_floatingMatrix = sceneProxy.m_matrix; proxy.m_maxContacts = ((DG_MAX_CONTATCS - pair->m_contactCount) > 32) ? 32 : DG_MAX_CONTATCS - pair->m_contactCount; proxy.m_contacts = &pair->m_contactBuffer[pair->m_contactCount]; pair->m_contactCount = pair->m_contactCount + dgInt16(CalculateConvexToNonConvexContacts(proxy)); if (pair->m_contactCount > (DG_MAX_CONTATCS - 2 * (DG_CONSTRAINT_MAX_ROWS / 3))) { pair->m_contactCount = dgInt16( ReduceContacts(pair->m_contactCount, pair->m_contactBuffer, DG_CONSTRAINT_MAX_ROWS / 3, DG_REDUCE_CONTACT_TOLERANCE)); } // pair->m_isTrigger = proxy.m_inTriggerVolume; } } void dgWorld::SceneContacts(dgCollidingPairCollector::dgPair *const pair, dgCollisionParamProxy &proxy) const { dgContact *const constraint = pair->m_contact; pair->m_isTrigger = 0; pair->m_contactCount = 0; proxy.m_isTriggerVolume = 0; proxy.m_inTriggerVolume = 0; // proxy.m_contacts = contacts; // NEWTON_ASSERT (pair->m_body0->m_invMass.m_w != dgFloat32 (0.0f)); // NEWTON_ASSERT (pair->m_body1->m_invMass.m_w == dgFloat32 (0.0f)); if (constraint) { dgInt32 contactCount = ValidateContactCache(pair->m_body0, pair->m_body1, constraint); if (contactCount) { pair->m_contactCount = 0; pair->m_contactBuffer = NULL; return; } } dgCollisionScene *const scene = (dgCollisionScene *)pair->m_body1->GetCollision(); NEWTON_ASSERT(scene->IsType(dgCollision::dgCollisionScene_RTTI)); if (pair->m_body0->GetCollision()->IsType( dgCollision::dgConvexCollision_RTTI)) { proxy.m_referenceBody = pair->m_body0; proxy.m_floatingBody = pair->m_body1; proxy.m_referenceCollision = pair->m_body0->m_collision; proxy.m_floatingCollision = NULL; proxy.m_referenceMatrix = pair->m_body0->m_collisionWorldMatrix; scene->CollidePair(pair, proxy); if (pair->m_contactCount) { // prune close contacts pair->m_contactCount = dgInt16( PruneContacts(pair->m_contactCount, pair->m_contactBuffer)); } } else { NEWTON_ASSERT(0); } } void dgWorld::SceneContactsSimd(dgCollidingPairCollector::dgPair *const pair, dgCollisionParamProxy &proxy) const { dgContact *const constraint = pair->m_contact; pair->m_isTrigger = 0; pair->m_contactCount = 0; proxy.m_isTriggerVolume = 0; proxy.m_inTriggerVolume = 0; // proxy.m_contacts = contacts; // NEWTON_ASSERT (pair->m_body0->m_invMass.m_w != dgFloat32 (0.0f)); // NEWTON_ASSERT (pair->m_body1->m_invMass.m_w == dgFloat32 (0.0f)); if (constraint) { dgInt32 contactCount = ValidateContactCache(pair->m_body0, pair->m_body1, constraint); if (contactCount) { pair->m_contactCount = 0; pair->m_contactBuffer = NULL; return; } } dgCollisionScene *const scene = (dgCollisionScene *)pair->m_body1->GetCollision(); NEWTON_ASSERT(scene->IsType(dgCollision::dgCollisionScene_RTTI)); if (pair->m_body0->GetCollision()->IsType( dgCollision::dgConvexCollision_RTTI)) { proxy.m_referenceBody = pair->m_body0; proxy.m_floatingBody = pair->m_body1; proxy.m_referenceCollision = pair->m_body0->m_collision; proxy.m_floatingCollision = NULL; proxy.m_referenceMatrix = pair->m_body0->m_collisionWorldMatrix; scene->CollidePairSimd(pair, proxy); if (pair->m_contactCount) { // prune close contacts pair->m_contactCount = dgInt16( PruneContacts(pair->m_contactCount, pair->m_contactBuffer)); } } else { NEWTON_ASSERT(0); } } void dgWorld::CalculateContactsSimd( dgCollidingPairCollector::dgPair *const pair, dgFloat32 timestep, dgInt32 threadIndex) { dgBody *body0; dgBody *body1; const dgContactMaterial *material; dgCollisionParamProxy proxy(threadIndex); body0 = pair->m_body0; body1 = pair->m_body1; material = pair->m_material; proxy.m_timestep = timestep; proxy.m_unconditionalCast = 0; proxy.m_maxContacts = DG_MAX_CONTATCS; proxy.m_penetrationPadding = material->m_penetrationPadding; // proxy.m_continueCollision = material->m_collisionContinueCollisionEnable & (body0->m_continueCollisionMode | body1->m_continueCollisionMode); proxy.m_continueCollision = dgInt32( ((material->m_flags & dgContactMaterial::m_collisionContinueCollisionEnable__) ? 1 : 0) & (body0->m_continueCollisionMode | body1->m_continueCollisionMode)); proxy.m_isTriggerVolume = body0->m_collision->IsTriggerVolume() || body1->m_collision->IsTriggerVolume(); if (body0->m_collision->IsType(dgCollision::dgCollisionScene_RTTI)) { Swap(pair->m_body0, pair->m_body1); SceneContactsSimd(pair, proxy); } else if (body1->m_collision->IsType(dgCollision::dgCollisionScene_RTTI)) { SceneContactsSimd(pair, proxy); } else if (body0->m_collision->IsType(dgCollision::dgCollisionCompound_RTTI)) { CompoundContactsSimd(pair, proxy); } else if (body1->m_collision->IsType(dgCollision::dgCollisionCompound_RTTI)) { Swap(pair->m_body0, pair->m_body1); CompoundContactsSimd(pair, proxy); } else if (body0->m_collision->IsType(dgCollision::dgConvexCollision_RTTI)) { ConvexContactsSimd(pair, proxy); } else if (body1->m_collision->IsType(dgCollision::dgConvexCollision_RTTI)) { Swap(pair->m_body0, pair->m_body1); ConvexContactsSimd(pair, proxy); } } void dgWorld::CalculateContacts(dgCollidingPairCollector::dgPair *const pair, dgFloat32 timestep, dgInt32 threadIndex) { dgCollisionParamProxy proxy(threadIndex); dgBody *const body0 = pair->m_body0; dgBody *const body1 = pair->m_body1; const dgContactMaterial *const material = pair->m_material; proxy.m_timestep = timestep; proxy.m_unconditionalCast = 0; proxy.m_maxContacts = DG_MAX_CONTATCS; proxy.m_penetrationPadding = material->m_penetrationPadding; proxy.m_isTriggerVolume = body0->m_collision->IsTriggerVolume() || body1->m_collision->IsTriggerVolume(); // proxy.m_continueCollision = material->m_collisionContinueCollisionEnable & (body0->m_continueCollisionMode | body1->m_continueCollisionMode); proxy.m_continueCollision = dgInt32( ((material->m_flags & dgContactMaterial::m_collisionContinueCollisionEnable__) ? 1 : 0) & (body0->m_continueCollisionMode | body1->m_continueCollisionMode)); if (body0->m_collision->IsType(dgCollision::dgCollisionScene_RTTI)) { Swap(pair->m_body0, pair->m_body1); SceneContacts(pair, proxy); } else if (body1->m_collision->IsType(dgCollision::dgCollisionScene_RTTI)) { SceneContacts(pair, proxy); } else if (body0->m_collision->IsType(dgCollision::dgCollisionCompound_RTTI)) { CompoundContacts(pair, proxy); } else if (body1->m_collision->IsType(dgCollision::dgCollisionCompound_RTTI)) { Swap(pair->m_body0, pair->m_body1); CompoundContacts(pair, proxy); } else if (body0->m_collision->IsType(dgCollision::dgConvexCollision_RTTI)) { ConvexContacts(pair, proxy); } else if (body1->m_collision->IsType(dgCollision::dgConvexCollision_RTTI)) { Swap(pair->m_body0, pair->m_body1); ConvexContacts(pair, proxy); } } // *************************************************************************** // // *************************************************************************** dgInt32 dgWorld::CollideContinueSimd(dgCollision *const collisionA, const dgMatrix &matrixA, const dgVector &velocA, const dgVector &omegaA, dgCollision *const collisionB, const dgMatrix &matrixB, const dgVector &velocB, const dgVector &omegaB, dgFloat32 &retTimeStep, dgTriplex *const points, dgTriplex *const normals, dgFloat32 *const penetration, dgInt32 maxSize, dgInt32 threadIndex) { dgBody collideBodyA; dgBody collideBodyB; dgContactPoint contacts[DG_MAX_CONTATCS]; dgInt32 count = 0; retTimeStep = dgFloat32(1.0e10f); maxSize = GetMin(dgInt32(DG_MAX_CONTATCS), maxSize); collideBodyA.m_world = this; collideBodyA.SetContinuesCollisionMode(true); collideBodyA.m_matrix = matrixA; collideBodyA.m_collision = collisionA; collideBodyA.m_masterNode = NULL; collideBodyA.m_collisionCell.m_cell = NULL; collideBodyA.m_collisionWorldMatrix = collisionA->m_offset * matrixA; collideBodyA.m_veloc = dgVector(velocA[0], velocA[1], velocA[2], dgFloat32(0.0f)); collideBodyA.m_omega = dgVector(omegaA[0], omegaA[1], omegaA[2], dgFloat32(0.0f)); collideBodyA.m_accel = dgVector(dgFloat32(0.0f), dgFloat32(0.0f), dgFloat32(0.0f), dgFloat32(0.0f)); collideBodyA.m_alpha = dgVector(dgFloat32(0.0f), dgFloat32(0.0f), dgFloat32(0.0f), dgFloat32(0.0f)); collideBodyA.m_invMass = dgVector(dgFloat32(1.0f), dgFloat32(1.0f), dgFloat32(1.0f), dgFloat32(1.0f)); collideBodyA.UpdateCollisionMatrixSimd(dgFloat32(1.0f), 0); collideBodyB.m_world = this; collideBodyB.SetContinuesCollisionMode(true); collideBodyB.m_matrix = matrixB; collideBodyB.m_collision = collisionB; collideBodyB.m_masterNode = NULL; collideBodyB.m_collisionCell.m_cell = NULL; collideBodyB.m_collisionWorldMatrix = collisionB->m_offset * matrixB; collideBodyB.m_veloc = dgVector(velocB[0], velocB[1], velocB[2], dgFloat32(0.0f)); collideBodyB.m_omega = dgVector(omegaB[0], omegaB[1], omegaB[2], dgFloat32(0.0f)); collideBodyB.m_accel = dgVector(dgFloat32(0.0f), dgFloat32(0.0f), dgFloat32(0.0f), dgFloat32(0.0f)); collideBodyB.m_alpha = dgVector(dgFloat32(0.0f), dgFloat32(0.0f), dgFloat32(0.0f), dgFloat32(0.0f)); collideBodyB.m_invMass = dgVector(dgFloat32(1.0f), dgFloat32(1.0f), dgFloat32(1.0f), dgFloat32(1.0f)); collideBodyB.UpdateCollisionMatrixSimd(dgFloat32(1.0f), 0); dgCollisionParamProxy proxy(threadIndex); proxy.m_timestep = dgFloat32(1.0f); proxy.m_unconditionalCast = 1; proxy.m_penetrationPadding = 0.0f; proxy.m_continueCollision = 1; // proxy.m_maxContacts = DG_MAX_CONTATCS; proxy.m_maxContacts = maxSize; proxy.m_isTriggerVolume = 0; dgCollidingPairCollector::dgPair pair; pair.m_body0 = &collideBodyA; pair.m_body1 = &collideBodyB; pair.m_contact = NULL; pair.m_material = NULL; pair.m_contactCount = 0; pair.m_contactBuffer = contacts; dgFloat32 swapContactScale = dgFloat32(1.0f); if (collideBodyA.m_collision->IsType(dgCollision::dgCollisionScene_RTTI)) { swapContactScale = dgFloat32(-1.0f); Swap(pair.m_body0, pair.m_body1); SceneContactsSimd(&pair, proxy); } else if (collideBodyB.m_collision->IsType(dgCollision::dgCollisionScene_RTTI)) { SceneContactsSimd(&pair, proxy); } else if (collideBodyA.m_collision->IsType( dgCollision::dgCollisionCompound_RTTI)) { CompoundContactsSimd(&pair, proxy); } else if (collideBodyB.m_collision->IsType( dgCollision::dgCollisionCompound_RTTI)) { swapContactScale = dgFloat32(-1.0f); Swap(pair.m_body0, pair.m_body1); CompoundContactsSimd(&pair, proxy); } else if (collideBodyA.m_collision->IsType( dgCollision::dgConvexCollision_RTTI)) { ConvexContactsSimd(&pair, proxy); } else if (collideBodyB.m_collision->IsType( dgCollision::dgConvexCollision_RTTI)) { swapContactScale = dgFloat32(-1.0f); Swap(pair.m_body0, pair.m_body1); ConvexContactsSimd(&pair, proxy); } count = pair.m_contactCount; if (proxy.m_timestep < dgFloat32(1.0f)) { retTimeStep = proxy.m_timestep; } if (count) { retTimeStep = proxy.m_timestep; if (count > maxSize) { count = PruneContacts(count, contacts, maxSize); } for (dgInt32 i = 0; i < count; i++) { points[i].m_x = contacts[i].m_point.m_x; points[i].m_y = contacts[i].m_point.m_y; points[i].m_z = contacts[i].m_point.m_z; normals[i].m_x = contacts[i].m_normal.m_x * swapContactScale; normals[i].m_y = contacts[i].m_normal.m_y * swapContactScale; normals[i].m_z = contacts[i].m_normal.m_z * swapContactScale; penetration[i] = contacts[i].m_penetration; } } return count; } dgInt32 dgWorld::CollideContinue(dgCollision *const collisionA, const dgMatrix &matrixA, const dgVector &velocA, const dgVector &omegaA, dgCollision *const collisionB, const dgMatrix &matrixB, const dgVector &velocB, const dgVector &omegaB, dgFloat32 &retTimeStep, dgTriplex *const points, dgTriplex *const normals, dgFloat32 *const penetration, dgInt32 maxSize, dgInt32 threadIndex) { dgBody collideBodyA; dgBody collideBodyB; dgContactPoint contacts[DG_MAX_CONTATCS]; // dgTrace (("%x -> p(%f, %f, %f) v(%f, %f, %f)\n", collisionB, matrixA.m_posit.m_x, matrixA.m_posit.m_y, matrixA.m_posit.m_z, velocA.m_x, velocA.m_y, velocA.m_z)); dgInt32 count = 0; retTimeStep = dgFloat32(1.0e10f); maxSize = GetMin(dgInt32(DG_MAX_CONTATCS), maxSize); collideBodyA.m_world = this; collideBodyA.SetContinuesCollisionMode(true); collideBodyA.m_matrix = matrixA; collideBodyA.m_collision = collisionA; collideBodyA.m_masterNode = NULL; collideBodyA.m_collisionCell.m_cell = NULL; collideBodyA.m_collisionWorldMatrix = collisionA->m_offset * matrixA; collideBodyA.m_veloc = dgVector(velocA[0], velocA[1], velocA[2], dgFloat32(0.0f)); collideBodyA.m_omega = dgVector(omegaA[0], omegaA[1], omegaA[2], dgFloat32(0.0f)); collideBodyA.m_accel = dgVector(dgFloat32(0.0f), dgFloat32(0.0f), dgFloat32(0.0f), dgFloat32(0.0f)); collideBodyA.m_alpha = dgVector(dgFloat32(0.0f), dgFloat32(0.0f), dgFloat32(0.0f), dgFloat32(0.0f)); collideBodyA.m_invMass = dgVector(dgFloat32(1.0f), dgFloat32(1.0f), dgFloat32(1.0f), dgFloat32(1.0f)); collideBodyA.UpdateCollisionMatrix(dgFloat32(1.0f), 0); collideBodyB.m_world = this; collideBodyB.SetContinuesCollisionMode(true); collideBodyB.m_matrix = matrixB; collideBodyB.m_collision = collisionB; collideBodyB.m_masterNode = NULL; collideBodyB.m_collisionCell.m_cell = NULL; collideBodyB.m_collisionWorldMatrix = collisionB->m_offset * matrixB; collideBodyB.m_veloc = dgVector(velocB[0], velocB[1], velocB[2], dgFloat32(0.0f)); collideBodyB.m_omega = dgVector(omegaB[0], omegaB[1], omegaB[2], dgFloat32(0.0f)); collideBodyB.m_accel = dgVector(dgFloat32(0.0f), dgFloat32(0.0f), dgFloat32(0.0f), dgFloat32(0.0f)); collideBodyB.m_alpha = dgVector(dgFloat32(0.0f), dgFloat32(0.0f), dgFloat32(0.0f), dgFloat32(0.0f)); collideBodyB.m_invMass = dgVector(dgFloat32(1.0f), dgFloat32(1.0f), dgFloat32(1.0f), dgFloat32(1.0f)); collideBodyB.UpdateCollisionMatrix(dgFloat32(1.0f), 0); dgCollisionParamProxy proxy(threadIndex); proxy.m_timestep = dgFloat32(1.0f); proxy.m_unconditionalCast = 1; proxy.m_penetrationPadding = 0.0f; proxy.m_continueCollision = 1; // proxy.m_maxContacts = DG_MAX_CONTATCS; proxy.m_maxContacts = maxSize; proxy.m_isTriggerVolume = 0; dgCollidingPairCollector::dgPair pair; pair.m_body0 = &collideBodyA; pair.m_body1 = &collideBodyB; pair.m_contact = NULL; pair.m_material = NULL; pair.m_contactCount = 0; pair.m_contactBuffer = contacts; dgFloat32 swapContactScale = dgFloat32(1.0f); if (collideBodyA.m_collision->IsType(dgCollision::dgCollisionScene_RTTI)) { swapContactScale = dgFloat32(-1.0f); Swap(pair.m_body0, pair.m_body1); SceneContactsSimd(&pair, proxy); } else if (collideBodyB.m_collision->IsType(dgCollision::dgCollisionScene_RTTI)) { SceneContactsSimd(&pair, proxy); } else if (collideBodyA.m_collision->IsType( dgCollision::dgCollisionCompound_RTTI)) { CompoundContacts(&pair, proxy); } else if (collideBodyB.m_collision->IsType( dgCollision::dgCollisionCompound_RTTI)) { swapContactScale = dgFloat32(-1.0f); Swap(pair.m_body0, pair.m_body1); CompoundContacts(&pair, proxy); } else if (collideBodyA.m_collision->IsType( dgCollision::dgConvexCollision_RTTI)) { ConvexContacts(&pair, proxy); } else if (collideBodyB.m_collision->IsType( dgCollision::dgConvexCollision_RTTI)) { swapContactScale = dgFloat32(-1.0f); Swap(pair.m_body0, pair.m_body1); ConvexContacts(&pair, proxy); } count = pair.m_contactCount; if (proxy.m_timestep < dgFloat32(1.0f)) { retTimeStep = proxy.m_timestep; } if (count) { if (count > maxSize) { count = PruneContacts(count, contacts, maxSize); } for (dgInt32 i = 0; i < count; i++) { points[i].m_x = contacts[i].m_point.m_x; points[i].m_y = contacts[i].m_point.m_y; points[i].m_z = contacts[i].m_point.m_z; normals[i].m_x = contacts[i].m_normal.m_x * swapContactScale; normals[i].m_y = contacts[i].m_normal.m_y * swapContactScale; normals[i].m_z = contacts[i].m_normal.m_z * swapContactScale; penetration[i] = contacts[i].m_penetration; } } return count; } dgInt32 dgWorld::Collide(dgCollision *const collisionA, const dgMatrix &matrixA, dgCollision *const collisionB, const dgMatrix &matrixB, dgTriplex *const points, dgTriplex *const normals, dgFloat32 *const penetration, dgInt32 maxSize, dgInt32 threadIndex) { dgBody collideBodyA; dgBody collideBodyB; dgContactPoint contacts[DG_MAX_CONTATCS]; dgInt32 count = 0; maxSize = GetMin(dgInt32(DG_MAX_CONTATCS), maxSize); collideBodyA.m_world = this; collideBodyA.m_masterNode = NULL; collideBodyA.m_collisionCell.m_cell = NULL; collideBodyA.SetContinuesCollisionMode(false); collideBodyA.m_matrix = matrixA; collideBodyA.m_collision = collisionA; // collideBodyA.m_collisionWorldMatrix = collisionA->m_offset * matrixA; collideBodyA.UpdateCollisionMatrix(dgFloat32(0.0f), 0); collideBodyB.m_world = this; collideBodyB.m_masterNode = NULL; collideBodyB.m_collisionCell.m_cell = NULL; collideBodyB.SetContinuesCollisionMode(false); collideBodyB.m_matrix = matrixB; collideBodyB.m_collision = collisionB; // collideBodyB.m_collisionWorldMatrix = collisionB->m_offset * matrixB; collideBodyB.UpdateCollisionMatrix(dgFloat32(0.0f), 0); // isTriggerA = collisionA->IsTriggerVolume(); // isTriggerB = collisionB->IsTriggerVolume(); dgCollisionParamProxy proxy(threadIndex); proxy.m_timestep = dgFloat32(0.0f); proxy.m_unconditionalCast = 1; proxy.m_penetrationPadding = 0.0f; proxy.m_continueCollision = 0; proxy.m_maxContacts = maxSize; proxy.m_isTriggerVolume = 0; dgCollidingPairCollector::dgPair pair; pair.m_body0 = &collideBodyA; pair.m_body1 = &collideBodyB; pair.m_contact = NULL; pair.m_material = NULL; pair.m_contactCount = 0; pair.m_contactBuffer = contacts; dgFloat32 swapContactScale = dgFloat32(1.0f); if (collideBodyA.m_collision->IsType(dgCollision::dgCollisionScene_RTTI)) { swapContactScale = dgFloat32(-1.0f); Swap(pair.m_body0, pair.m_body1); SceneContacts(&pair, proxy); } else if (collideBodyB.m_collision->IsType(dgCollision::dgCollisionScene_RTTI)) { SceneContacts(&pair, proxy); } else if (collideBodyA.m_collision->IsType( dgCollision::dgCollisionCompound_RTTI)) { CompoundContacts(&pair, proxy); } else if (collideBodyB.m_collision->IsType( dgCollision::dgCollisionCompound_RTTI)) { swapContactScale = dgFloat32(-1.0f); Swap(pair.m_body0, pair.m_body1); CompoundContacts(&pair, proxy); } else if (collideBodyA.m_collision->IsType( dgCollision::dgConvexCollision_RTTI)) { ConvexContacts(&pair, proxy); } else if (collideBodyB.m_collision->IsType( dgCollision::dgConvexCollision_RTTI)) { swapContactScale = dgFloat32(-1.0f); Swap(pair.m_body0, pair.m_body1); ConvexContacts(&pair, proxy); } count = pair.m_contactCount; if (count > maxSize) { count = ReduceContacts(count, contacts, maxSize, DG_REDUCE_CONTACT_TOLERANCE); } for (dgInt32 i = 0; i < count; i++) { points[i].m_x = contacts[i].m_point.m_x; points[i].m_y = contacts[i].m_point.m_y; points[i].m_z = contacts[i].m_point.m_z; normals[i].m_x = contacts[i].m_normal.m_x * swapContactScale; normals[i].m_y = contacts[i].m_normal.m_y * swapContactScale; normals[i].m_z = contacts[i].m_normal.m_z * swapContactScale; penetration[i] = contacts[i].m_penetration; } return count; }