/* 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 "dgMeshEffect.h" #include "dgBody.h" #include "dgCollisionBVH.h" #include "dgCollisionCompound.h" #include "dgCollisionConvexHull.h" #include "dgMeshEffectSolidTree.h" #include "dgWorld.h" #include "hpl1/engine/libraries/newton/core/dg.h" class dgFlatClipEdgeAttr { public: dgInt32 m_rightIndex; dgInt32 m_leftIndex; dgInt32 m_leftEdgeAttr; dgInt32 m_leftTwinAttr; dgInt32 m_rightEdgeAttr; dgInt32 m_rightTwinAttr; dgEdge *m_edge; dgEdge *m_twin; }; dgMeshEffect::dgMeshEffect(dgMemoryAllocator *const allocator, bool preAllocaBuffers) : dgPolyhedra(allocator) { Init(preAllocaBuffers); } dgMeshEffect::dgMeshEffect(dgMemoryAllocator *const allocator, const dgMatrix &planeMatrix, dgFloat32 witdth, dgFloat32 breadth, dgInt32 material, const dgMatrix &textureMatrix0, const dgMatrix &textureMatrix1) : dgPolyhedra(allocator) { dgInt32 index[4]; dgInt64 attrIndex[4]; dgBigVector face[4]; Init(true); face[0] = dgBigVector(dgFloat32(0.0f), -witdth, -breadth, dgFloat32(0.0f)); face[1] = dgBigVector(dgFloat32(0.0f), witdth, -breadth, dgFloat32(0.0f)); face[2] = dgBigVector(dgFloat32(0.0f), witdth, breadth, dgFloat32(0.0f)); face[3] = dgBigVector(dgFloat32(0.0f), -witdth, breadth, dgFloat32(0.0f)); for (dgInt32 i = 0; i < 4; i++) { dgBigVector uv0(textureMatrix0.TransformVector(face[i])); dgBigVector uv1(textureMatrix1.TransformVector(face[i])); m_points[i] = planeMatrix.TransformVector(face[i]); m_attib[i].m_vertex.m_x = m_points[i].m_x; m_attib[i].m_vertex.m_y = m_points[i].m_y; m_attib[i].m_vertex.m_z = m_points[i].m_z; m_attib[i].m_vertex.m_w = dgFloat64(0.0f); m_attib[i].m_normal_x = planeMatrix.m_front.m_x; m_attib[i].m_normal_y = planeMatrix.m_front.m_y; m_attib[i].m_normal_z = planeMatrix.m_front.m_z; m_attib[i].m_u0 = uv0.m_y; m_attib[i].m_v0 = uv0.m_z; m_attib[i].m_u1 = uv1.m_y; m_attib[i].m_v1 = uv1.m_z; m_attib[i].m_material = material; index[i] = i; attrIndex[i] = i; } m_pointCount = 4; m_atribCount = 4; BeginFace(); AddFace(4, index, attrIndex); EndFace(); } dgMeshEffect::dgMeshEffect(dgPolyhedra &mesh, const dgMeshEffect &source) : dgPolyhedra(mesh) { m_pointCount = source.m_pointCount; m_maxPointCount = source.m_maxPointCount; m_points = (dgBigVector *)GetAllocator()->MallocLow( dgInt32(m_maxPointCount * sizeof(dgBigVector))); memcpy(m_points, source.m_points, m_pointCount * sizeof(dgBigVector)); m_atribCount = source.m_atribCount; m_maxAtribCount = source.m_maxAtribCount; m_attib = (dgVertexAtribute *)GetAllocator()->MallocLow( dgInt32(m_maxAtribCount * sizeof(dgVertexAtribute))); memcpy(m_attib, source.m_attib, m_atribCount * sizeof(dgVertexAtribute)); } dgMeshEffect::dgMeshEffect(const dgMeshEffect &source) : dgPolyhedra(source) { m_pointCount = source.m_pointCount; m_maxPointCount = source.m_maxPointCount; m_points = (dgBigVector *)GetAllocator()->MallocLow( dgInt32(m_maxPointCount * sizeof(dgBigVector))); memcpy(m_points, source.m_points, m_pointCount * sizeof(dgBigVector)); m_atribCount = source.m_atribCount; m_maxAtribCount = source.m_maxAtribCount; m_attib = (dgVertexAtribute *)GetAllocator()->MallocLow( dgInt32(m_maxAtribCount * sizeof(dgVertexAtribute))); memcpy(m_attib, source.m_attib, m_atribCount * sizeof(dgVertexAtribute)); } dgMeshEffect::dgMeshEffect(dgCollision *const collision) : dgPolyhedra(collision->GetAllocator()) { class dgMeshEffectBuilder { public: dgMeshEffectBuilder() { m_brush = 0; m_faceCount = 0; m_vertexCount = 0; m_maxFaceCount = 32; m_maxVertexCount = 32; m_vertex = (dgVector *)dgMallocStack(m_maxVertexCount * sizeof(dgVector)); m_faceIndexCount = (dgInt32 *)dgMallocStack( m_maxFaceCount * sizeof(dgInt32)); } ~dgMeshEffectBuilder() { dgFreeStack(m_faceIndexCount); dgFreeStack(m_vertex); } static void GetShapeFromCollision(void *userData, dgInt32 vertexCount, const dgFloat32 *faceVertex, dgInt32 id) { dgInt32 vertexIndex; dgMeshEffectBuilder &builder = *((dgMeshEffectBuilder *)userData); if (builder.m_faceCount >= builder.m_maxFaceCount) { dgInt32 *index; builder.m_maxFaceCount *= 2; index = (dgInt32 *)dgMallocStack( builder.m_maxFaceCount * sizeof(dgInt32)); memcpy(index, builder.m_faceIndexCount, builder.m_faceCount * sizeof(dgInt32)); dgFreeStack(builder.m_faceIndexCount); builder.m_faceIndexCount = index; } builder.m_faceIndexCount[builder.m_faceCount] = vertexCount; builder.m_faceCount = builder.m_faceCount + 1; vertexIndex = builder.m_vertexCount; dgFloat32 brush = dgFloat32(builder.m_brush); for (dgInt32 i = 0; i < vertexCount; i++) { if (vertexIndex >= builder.m_maxVertexCount) { dgVector *points; builder.m_maxVertexCount *= 2; points = (dgVector *)dgMallocStack( builder.m_maxVertexCount * sizeof(dgVector)); memcpy(points, builder.m_vertex, vertexIndex * sizeof(dgVector)); dgFreeStack(builder.m_vertex); builder.m_vertex = points; } builder.m_vertex[vertexIndex].m_x = faceVertex[i * 3 + 0]; builder.m_vertex[vertexIndex].m_y = faceVertex[i * 3 + 1]; builder.m_vertex[vertexIndex].m_z = faceVertex[i * 3 + 2]; builder.m_vertex[vertexIndex].m_w = brush; vertexIndex++; } builder.m_vertexCount = vertexIndex; } dgInt32 m_brush; dgInt32 m_vertexCount; dgInt32 m_maxVertexCount; dgInt32 m_faceCount; dgInt32 m_maxFaceCount; dgVector *m_vertex; dgInt32 *m_faceIndexCount; }; dgMeshEffectBuilder builder; if (collision->IsType(dgCollision::dgCollisionCompound_RTTI)) { dgCollisionInfo collisionInfo; collision->GetCollisionInfo(&collisionInfo); dgMatrix matrix(collisionInfo.m_offsetMatrix); dgCollisionInfo::dgCoumpountCollisionData &data = collisionInfo.m_compoundCollision; for (dgInt32 i = 0; i < data.m_chidrenCount; i++) { builder.m_brush = i; dgCollision *const childShape = data.m_chidren[i]; childShape->DebugCollision( matrix, (OnDebugCollisionMeshCallback)dgMeshEffectBuilder::GetShapeFromCollision, &builder); } } else { dgMatrix matrix(dgGetIdentityMatrix()); collision->DebugCollision( matrix, (OnDebugCollisionMeshCallback)dgMeshEffectBuilder::GetShapeFromCollision, &builder); } dgStack indexList(builder.m_vertexCount); dgVertexListToIndexList(&builder.m_vertex[0].m_x, sizeof(dgVector), sizeof(dgVector), 0, builder.m_vertexCount, &indexList[0], DG_VERTEXLIST_INDEXLIST_TOL); dgStack materialIndex(builder.m_faceCount); dgStack m_normalUVIndex(builder.m_vertexCount); dgVector normalUV(dgFloat32(0.0f), dgFloat32(0.0f), dgFloat32(0.0f), dgFloat32(0.0f)); memset(&materialIndex[0], 0, size_t(materialIndex.GetSizeInBytes())); memset(&m_normalUVIndex[0], 0, size_t(m_normalUVIndex.GetSizeInBytes())); Init(true); BuildFromVertexListIndexList(builder.m_faceCount, builder.m_faceIndexCount, &materialIndex[0], &builder.m_vertex[0].m_x, sizeof(dgVector), &indexList[0], &normalUV.m_x, sizeof(dgVector), &m_normalUVIndex[0], &normalUV.m_x, sizeof(dgVector), &m_normalUVIndex[0], &normalUV.m_x, sizeof(dgVector), &m_normalUVIndex[0]); RepairTJoints(true); CalculateNormals(dgFloat32(45.0f * 3.1416f / 180.0f)); } dgMeshEffect::~dgMeshEffect(void) { GetAllocator()->FreeLow(m_points); GetAllocator()->FreeLow(m_attib); } void dgMeshEffect::Init(bool preAllocaBuffers) { m_pointCount = 0; m_atribCount = 0; m_maxPointCount = DG_MESH_EFFECT_INITIAL_VERTEX_SIZE; m_maxAtribCount = DG_MESH_EFFECT_INITIAL_VERTEX_SIZE; m_points = NULL; m_attib = NULL; if (preAllocaBuffers) { m_points = (dgBigVector *)GetAllocator()->MallocLow( dgInt32(m_maxPointCount * sizeof(dgBigVector))); m_attib = (dgVertexAtribute *)GetAllocator()->MallocLow( dgInt32(m_maxAtribCount * sizeof(dgVertexAtribute))); } } void dgMeshEffect::Triangulate() { dgPolyhedra polygon(GetAllocator()); dgInt32 mark = IncLRU(); polygon.BeginFace(); dgPolyhedra::Iterator iter(*this); for (iter.Begin(); iter; iter++) { dgEdge *const face = &(*iter); if ((face->m_mark != mark) && (face->m_incidentFace > 0)) { dgInt32 index[DG_MESH_EFFECT_POINT_SPLITED]; dgEdge *ptr = face; dgInt32 indexCount = 0; do { dgInt32 attribIndex = dgInt32(ptr->m_userData); m_attib[attribIndex].m_vertex.m_w = dgFloat64(ptr->m_incidentVertex); ptr->m_mark = mark; index[indexCount] = attribIndex; indexCount++; ptr = ptr->m_next; } while (ptr != face); polygon.AddFace(indexCount, index); } } polygon.EndFace(); dgPolyhedra leftOversOut(GetAllocator()); polygon.Triangulate(&m_attib[0].m_vertex.m_x, sizeof(dgVertexAtribute), &leftOversOut); NEWTON_ASSERT(leftOversOut.GetCount() == 0); RemoveAll(); SetLRU(0); mark = polygon.IncLRU(); BeginFace(); dgPolyhedra::Iterator iter1(polygon); for (iter1.Begin(); iter1; iter1++) { dgEdge *const face = &(*iter1); if ((face->m_mark != mark) && (face->m_incidentFace > 0)) { dgInt32 index[DG_MESH_EFFECT_POINT_SPLITED]; dgInt64 userData[DG_MESH_EFFECT_POINT_SPLITED]; dgEdge *ptr = face; dgInt32 indexCount = 0; do { ptr->m_mark = mark; index[indexCount] = dgInt32( m_attib[ptr->m_incidentVertex].m_vertex.m_w); userData[indexCount] = ptr->m_incidentVertex; indexCount++; ptr = ptr->m_next; } while (ptr != face); AddFace(indexCount, index, userData); } } EndFace(); for (iter.Begin(); iter; iter++) { dgEdge *const face = &(*iter); if (face->m_incidentFace > 0) { dgInt32 attribIndex = dgInt32(face->m_userData); m_attib[attribIndex].m_vertex.m_w = m_points[face->m_incidentVertex].m_w; } } } void dgMeshEffect::ConvertToPolygons() { dgPolyhedra polygon(GetAllocator()); dgInt32 mark = IncLRU(); polygon.BeginFace(); dgPolyhedra::Iterator iter(*this); for (iter.Begin(); iter; iter++) { dgEdge *const face = &(*iter); if ((face->m_mark != mark) && (face->m_incidentFace > 0)) { dgInt32 index[DG_MESH_EFFECT_POINT_SPLITED]; dgEdge *ptr = face; dgInt32 indexCount = 0; do { dgInt32 attribIndex = dgInt32(ptr->m_userData); m_attib[attribIndex].m_vertex.m_w = dgFloat32(ptr->m_incidentVertex); ptr->m_mark = mark; index[indexCount] = attribIndex; indexCount++; ptr = ptr->m_next; } while (ptr != face); polygon.AddFace(indexCount, index); } } polygon.EndFace(); dgPolyhedra leftOversOut(GetAllocator()); polygon.ConvexPartition(&m_attib[0].m_vertex.m_x, sizeof(dgVertexAtribute), &leftOversOut); NEWTON_ASSERT(leftOversOut.GetCount() == 0); RemoveAll(); SetLRU(0); mark = polygon.IncLRU(); BeginFace(); dgPolyhedra::Iterator iter1(polygon); for (iter1.Begin(); iter1; iter1++) { dgEdge *const face = &(*iter1); if ((face->m_mark != mark) && (face->m_incidentFace > 0)) { dgInt32 index[DG_MESH_EFFECT_POINT_SPLITED]; dgInt64 userData[DG_MESH_EFFECT_POINT_SPLITED]; dgEdge *ptr = face; dgInt32 indexCount = 0; do { ptr->m_mark = mark; index[indexCount] = dgInt32( m_attib[ptr->m_incidentVertex].m_vertex.m_w); userData[indexCount] = ptr->m_incidentVertex; indexCount++; ptr = ptr->m_next; } while (ptr != face); AddFace(indexCount, index, userData); } } EndFace(); for (iter.Begin(); iter; iter++) { dgEdge *const face = &(*iter); if (face->m_incidentFace > 0) { dgInt32 attribIndex = dgInt32(face->m_userData); m_attib[attribIndex].m_vertex.m_w = m_points[face->m_incidentVertex].m_w; } } RepairTJoints(false); } void dgMeshEffect::RemoveUnusedVertices(dgInt32 *const vertexMap) { dgPolyhedra polygon(GetAllocator()); dgStack attrbMap(m_atribCount); memset(&vertexMap[0], -1, m_pointCount * sizeof(int)); memset(&attrbMap[0], -1, m_atribCount * sizeof(int)); int attribCount = 0; int vertexCount = 0; dgStack points(m_pointCount); dgStack atributes(m_atribCount); dgInt32 mark = IncLRU(); polygon.BeginFace(); dgPolyhedra::Iterator iter(*this); for (iter.Begin(); iter; iter++) { dgEdge *const face = &(*iter); if ((face->m_mark != mark) && (face->m_incidentFace > 0)) { dgInt32 vertex[DG_MESH_EFFECT_POINT_SPLITED]; dgInt64 userData[DG_MESH_EFFECT_POINT_SPLITED]; int indexCount = 0; dgEdge *ptr = face; do { ptr->m_mark = mark; int index = ptr->m_incidentVertex; if (vertexMap[index] == -1) { vertexMap[index] = vertexCount; points[vertexCount] = m_points[index]; vertexCount++; } vertex[indexCount] = vertexMap[index]; index = int(ptr->m_userData); if (attrbMap[index] == -1) { attrbMap[index] = attribCount; atributes[attribCount] = m_attib[index]; attribCount++; } userData[indexCount] = attrbMap[index]; indexCount++; ptr = ptr->m_next; } while (ptr != face); polygon.AddFace(indexCount, vertex, userData); } } polygon.EndFace(); m_pointCount = vertexCount; memcpy(&m_points[0].m_x, &points[0].m_x, m_pointCount * sizeof(dgBigVector)); m_atribCount = attribCount; memcpy(&m_attib[0].m_vertex.m_x, &atributes[0].m_vertex.m_x, m_atribCount * sizeof(dgVertexAtribute)); RemoveAll(); SetLRU(0); BeginFace(); dgPolyhedra::Iterator iter1(polygon); for (iter1.Begin(); iter1; iter1++) { dgEdge *const face = &(*iter1); if ((face->m_mark != mark) && (face->m_incidentFace > 0)) { dgInt32 index[DG_MESH_EFFECT_POINT_SPLITED]; dgInt64 userData[DG_MESH_EFFECT_POINT_SPLITED]; dgEdge *ptr = face; dgInt32 indexCount = 0; do { ptr->m_mark = mark; index[indexCount] = ptr->m_incidentVertex; userData[indexCount] = dgInt64(ptr->m_userData); indexCount++; ptr = ptr->m_next; } while (ptr != face); AddFace(indexCount, index, userData); } } EndFace(); PackVertexArrays(); } void dgMeshEffect::ApplyTransform(const dgMatrix &matrix) { matrix.TransformTriplex(&m_points[0].m_x, sizeof(dgBigVector), &m_points[0].m_x, sizeof(dgBigVector), m_pointCount); matrix.TransformTriplex(&m_attib[0].m_vertex.m_x, sizeof(dgVertexAtribute), &m_attib[0].m_vertex.m_x, sizeof(dgVertexAtribute), m_atribCount); dgMatrix rotation(matrix.Inverse4x4().Transpose4X4()); for (dgInt32 i = 0; i < m_atribCount; i++) { dgVector n(dgFloat32(m_attib[i].m_normal_x), dgFloat32(m_attib[i].m_normal_y), dgFloat32(m_attib[i].m_normal_z), dgFloat32(0.0f)); n = rotation.RotateVector(n); n = n.Scale(dgFloat32(1.0f) / dgSqrt(n % n)); m_attib[i].m_normal_x = n.m_x; m_attib[i].m_normal_y = n.m_y; m_attib[i].m_normal_z = n.m_z; } } dgMatrix dgMeshEffect::CalculateOOBB(dgBigVector &size) const { dgSphere sphere(CalculateSphere(&m_points[0].m_x, sizeof(dgBigVector), NULL)); size = sphere.m_size; dgMatrix permuation(dgGetIdentityMatrix()); permuation[0][0] = dgFloat32(0.0f); permuation[0][1] = dgFloat32(1.0f); permuation[1][1] = dgFloat32(0.0f); permuation[1][2] = dgFloat32(1.0f); permuation[2][2] = dgFloat32(0.0f); permuation[2][0] = dgFloat32(1.0f); while ((size.m_x < size.m_y) || (size.m_x < size.m_z)) { sphere = permuation * sphere; size = permuation.UnrotateVector(size); } return sphere; } void dgMeshEffect::CalculateAABB(dgBigVector &minBox, dgBigVector &maxBox) const { dgBigVector minP(dgFloat64(1.0e15f), dgFloat64(1.0e15f), dgFloat64(1.0e15f), dgFloat64(0.0f)); dgBigVector maxP(-dgFloat64(1.0e15f), -dgFloat64(1.0e15f), -dgFloat64(1.0e15f), dgFloat64(0.0f)); dgPolyhedra::Iterator iter(*this); const dgBigVector *const points = &m_points[0]; for (iter.Begin(); iter; iter++) { dgEdge *const edge = &(*iter); const dgBigVector &p(points[edge->m_incidentVertex]); minP.m_x = GetMin(p.m_x, minP.m_x); minP.m_y = GetMin(p.m_y, minP.m_y); minP.m_z = GetMin(p.m_z, minP.m_z); maxP.m_x = GetMax(p.m_x, maxP.m_x); maxP.m_y = GetMax(p.m_y, maxP.m_y); maxP.m_z = GetMax(p.m_z, maxP.m_z); } minBox = minP; maxBox = maxP; } dgInt32 dgMeshEffect::EnumerateAttributeArray(dgVertexAtribute *const attib) { dgInt32 index = 0; dgPolyhedra::Iterator iter(*this); for (iter.Begin(); iter; iter++) { dgEdge *const edge = &(*iter); NEWTON_ASSERT(index < GetCount()); if (edge->m_incidentFace > 0) { attib[index] = m_attib[dgInt32(edge->m_userData)]; edge->m_userData = dgUnsigned64(index); index++; } } return index; } void dgMeshEffect::ApplyAttributeArray(dgVertexAtribute *const attib, dgInt32 maxCount) { dgStack indexMap(GetCount()); m_atribCount = dgVertexListToIndexList(&attib[0].m_vertex.m_x, sizeof(dgVertexAtribute), sizeof(dgVertexAtribute) / sizeof(dgFloat64), maxCount, &indexMap[0], DG_VERTEXLIST_INDEXLIST_TOL); m_maxAtribCount = m_atribCount; GetAllocator()->FreeLow(m_attib); m_attib = (dgVertexAtribute *)GetAllocator()->MallocLow( dgInt32(m_atribCount * sizeof(dgVertexAtribute))); memcpy(m_attib, attib, m_atribCount * sizeof(dgVertexAtribute)); dgPolyhedra::Iterator iter(*this); for (iter.Begin(); iter; iter++) { dgEdge *const edge = &(*iter); if (edge->m_incidentFace > 0) { dgInt32 index = indexMap[dgInt32(edge->m_userData)]; NEWTON_ASSERT(index >= 0); NEWTON_ASSERT(index < m_atribCount); edge->m_userData = dgUnsigned64(index); } } } dgBigVector dgMeshEffect::GetOrigin() const { dgBigVector origin(dgFloat64(0.0f), dgFloat64(0.0f), dgFloat64(0.0f), dgFloat64(0.0f)); for (dgInt32 i = 0; i < m_pointCount; i++) { origin += m_points[i]; } return origin.Scale(dgFloat64(1.0f) / m_pointCount); } void dgMeshEffect::FixCylindricalMapping(dgVertexAtribute *attribArray) const { dgPolyhedra::Iterator iter(*this); for (iter.Begin(); iter; iter++) { dgEdge *const edge = &(*iter); dgVertexAtribute &attrib0 = attribArray[dgInt32(edge->m_userData)]; dgVertexAtribute &attrib1 = attribArray[dgInt32(edge->m_next->m_userData)]; dgFloat64 error = fabs(attrib0.m_u0 - attrib1.m_u0); if (error > dgFloat32(0.6f)) { if (attrib0.m_u0 < attrib1.m_u0) { attrib0.m_u0 += dgFloat32(1.0f); attrib0.m_u1 = attrib0.m_u0; } else { attrib1.m_u0 += dgFloat32(1.0f); attrib1.m_u1 = attrib1.m_u0; } } } for (iter.Begin(); iter; iter++) { dgEdge *const edge = &(*iter); dgVertexAtribute &attrib0 = attribArray[dgInt32(edge->m_userData)]; dgVertexAtribute &attrib1 = attribArray[dgInt32(edge->m_next->m_userData)]; dgFloat64 error = fabs(attrib0.m_u0 - attrib1.m_u0); if (error > dgFloat32(0.6f)) { if (attrib0.m_u0 < attrib1.m_u0) { attrib0.m_u0 += dgFloat32(1.0f); attrib0.m_u1 = attrib0.m_u0; } else { attrib1.m_u0 += dgFloat32(1.0f); attrib1.m_u1 = attrib1.m_u0; } } } } void dgMeshEffect::SphericalMapping(dgInt32 material) { dgBigVector origin(GetOrigin()); dgStack sphere(m_pointCount); for (dgInt32 i = 0; i < m_pointCount; i++) { dgBigVector point(m_points[i] - origin); point = point.Scale(1.0f / dgSqrt(point % point)); dgFloat64 u = dgAsin(point.m_y); dgFloat64 v = dgAtan2(point.m_x, point.m_z); u = (dgFloat64(3.1416f / 2.0f) - u) / dgFloat64(3.1416f); v = (dgFloat64(3.1416f) - v) / dgFloat64(2.0f * 3.1416f); sphere[i].m_x = v; sphere[i].m_y = u; } dgStack attribArray(GetCount()); dgInt32 count = EnumerateAttributeArray(&attribArray[0]); dgPolyhedra::Iterator iter(*this); for (iter.Begin(); iter; iter++) { dgEdge *edge; edge = &(*iter); dgVertexAtribute &attrib = attribArray[dgInt32(edge->m_userData)]; attrib.m_u0 = sphere[edge->m_incidentVertex].m_x; attrib.m_v0 = sphere[edge->m_incidentVertex].m_y; attrib.m_u1 = sphere[edge->m_incidentVertex].m_x; attrib.m_v1 = sphere[edge->m_incidentVertex].m_y; attrib.m_material = material; } FixCylindricalMapping(&attribArray[0]); ApplyAttributeArray(&attribArray[0], count); } void dgMeshEffect::CylindricalMapping(dgInt32 cylinderMaterial, dgInt32 capMaterial) { /* dgVector origin (GetOrigin()); dgStackcylinder (m_pointCount); dgFloat32 xMax; dgFloat32 xMin; xMin= dgFloat32 (1.0e10f); xMax= dgFloat32 (-1.0e10f); for (dgInt32 i = 0; i < m_pointCount; i ++) { cylinder[i] = m_points[i] - origin; xMin = GetMin (xMin, cylinder[i].m_x); xMax = GetMax (xMax, cylinder[i].m_x); } dgFloat32 xscale = dgFloat32 (1.0f)/ (xMax - xMin); for (dgInt32 i = 0; i < m_pointCount; i ++) { dgFloat32 u; dgFloat32 v; dgFloat32 y; dgFloat32 z; y = cylinder[i].m_y; z = cylinder[i].m_z; u = dgAtan2 (z, y); if (u < dgFloat32 (0.0f)) { u += dgFloat32 (3.141592f * 2.0f); } v = (cylinder[i].m_x - xMin) * xscale; cylinder[i].m_x = dgFloat32 (1.0f) - u * dgFloat32 (1.0f / (2.0f * 3.141592f)); cylinder[i].m_y = v; } dgStackattribArray (GetCount()); EnumerateAttributeArray (&attribArray[0]); dgPolyhedra::Iterator iter (*this); for(iter.Begin(); iter; iter ++){ dgEdge* edge; edge = &(*iter); dgVertexAtribute& attrib = attribArray[dgInt32 (edge->m_userData)]; attrib.m_u0 = cylinder[edge->m_incidentVertex].m_x; attrib.m_v0 = cylinder[edge->m_incidentVertex].m_y; attrib.m_u1 = cylinder[edge->m_incidentVertex].m_x; attrib.m_v1 = cylinder[edge->m_incidentVertex].m_y; attrib.m_material = cylinderMaterial; } FixCylindricalMapping (&attribArray[0]); dgInt32 mark; mark = IncLRU(); for(iter.Begin(); iter; iter ++){ dgEdge* edge; edge = &(*iter); if (edge->m_mark < mark){ const dgVector& p0 = m_points[edge->m_incidentVertex]; const dgVector& p1 = m_points[edge->m_next->m_incidentVertex]; const dgVector& p2 = m_points[edge->m_prev->m_incidentVertex]; edge->m_mark = mark; edge->m_next->m_mark = mark; edge->m_prev->m_mark = mark; dgVector e0 (p1 - p0); dgVector e1 (p2 - p0); dgVector n (e0 * e1); if ((n.m_x * n.m_x) > (dgFloat32 (0.99f) * (n % n))) { dgEdge* ptr; ptr = edge; do { dgVertexAtribute& attrib = attribArray[dgInt32 (ptr->m_userData)]; dgVector p (m_points[ptr->m_incidentVertex] - origin); p.m_x = dgFloat32 (0.0f); p = p.Scale (dgFloat32 (dgRsqrt(p % p))); attrib.m_u0 = dgFloat32 (0.5f) + p.m_y * dgFloat32 (0.5f); attrib.m_v0 = dgFloat32 (0.5f) + p.m_z * dgFloat32 (0.5f); attrib.m_u1 = dgFloat32 (0.5f) + p.m_y * dgFloat32 (0.5f); attrib.m_v1 = dgFloat32 (0.5f) + p.m_z * dgFloat32 (0.5f); attrib.m_material = capMaterial; ptr = ptr->m_next; }while (ptr != edge); } } } ApplyAttributeArray (&attribArray[0]); */ dgBigVector origin(GetOrigin()); dgStack cylinder(m_pointCount); dgBigVector pMin(dgFloat64(1.0e10f), dgFloat64(1.0e10f), dgFloat64(1.0e10f), dgFloat64(0.0f)); dgBigVector pMax(dgFloat64(-1.0e10f), dgFloat64(-1.0e10f), dgFloat64(-1.0e10f), dgFloat64(0.0f)); for (dgInt32 i = 0; i < m_pointCount; i++) { dgBigVector tmp(m_points[i] - origin); pMin.m_x = GetMin(pMin.m_x, tmp.m_x); pMax.m_x = GetMax(pMax.m_x, tmp.m_x); pMin.m_y = GetMin(pMin.m_y, tmp.m_y); pMax.m_y = GetMax(pMax.m_y, tmp.m_y); pMin.m_z = GetMin(pMin.m_z, tmp.m_z); pMax.m_z = GetMax(pMax.m_z, tmp.m_z); } dgBigVector scale(dgFloat64(1.0f) / (pMax.m_x - pMin.m_x), dgFloat64(1.0f) / (pMax.m_x - pMin.m_x), dgFloat64(1.0f) / (pMax.m_x - pMin.m_x), dgFloat64(0.0f)); for (dgInt32 i = 0; i < m_pointCount; i++) { dgBigVector point(m_points[i] - origin); dgFloat64 u = (point.m_x - pMin.m_x) * scale.m_x; point = point.Scale(1.0f / dgSqrt(point % point)); dgFloat64 v = dgAtan2(point.m_y, point.m_z); // u = (dgFloat64 (3.1416f/2.0f) - u) / dgFloat64 (3.1416f); v = (dgFloat64(3.1416f) - v) / dgFloat64(2.0f * 3.1416f); cylinder[i].m_x = v; cylinder[i].m_y = u; } dgStack attribArray(GetCount()); dgInt32 count = EnumerateAttributeArray(&attribArray[0]); dgPolyhedra::Iterator iter(*this); for (iter.Begin(); iter; iter++) { dgEdge *const edge = &(*iter); dgVertexAtribute &attrib = attribArray[dgInt32(edge->m_userData)]; attrib.m_u0 = cylinder[edge->m_incidentVertex].m_x; attrib.m_v0 = cylinder[edge->m_incidentVertex].m_y; attrib.m_u1 = cylinder[edge->m_incidentVertex].m_x; attrib.m_v1 = cylinder[edge->m_incidentVertex].m_y; attrib.m_material = cylinderMaterial; } FixCylindricalMapping(&attribArray[0]); // apply cap mapping dgInt32 mark = IncLRU(); for (iter.Begin(); iter; iter++) { dgEdge *const edge = &(*iter); if (edge->m_mark < mark) { const dgVector &p0 = m_points[edge->m_incidentVertex]; const dgVector &p1 = m_points[edge->m_next->m_incidentVertex]; const dgVector &p2 = m_points[edge->m_prev->m_incidentVertex]; edge->m_mark = mark; edge->m_next->m_mark = mark; edge->m_prev->m_mark = mark; dgVector e0(p1 - p0); dgVector e1(p2 - p0); dgVector n(e0 * e1); if ((n.m_x * n.m_x) > (dgFloat32(0.99f) * (n % n))) { dgEdge *ptr = edge; do { dgVertexAtribute &attrib = attribArray[dgInt32(ptr->m_userData)]; dgVector p(m_points[ptr->m_incidentVertex] - origin); dgFloat64 u = (p.m_y - pMin.m_y) * scale.m_y; dgFloat64 v = (p.m_z - pMin.m_z) * scale.m_z; attrib.m_u0 = u; attrib.m_v0 = v; attrib.m_u1 = u; attrib.m_v1 = v; attrib.m_material = capMaterial; ptr = ptr->m_next; } while (ptr != edge); } } } ApplyAttributeArray(&attribArray[0], count); } void dgMeshEffect::BoxMapping(dgInt32 front, dgInt32 side, dgInt32 top) { dgBigVector minVal; dgBigVector maxVal; dgInt32 materialArray[3]; GetMinMax(minVal, maxVal, &m_points[0][0], m_pointCount, sizeof(dgBigVector)); dgBigVector dist(maxVal - minVal); dgBigVector scale(dgFloat64(1.0f) / dist[0], dgFloat64(1.0f) / dist[1], dgFloat64(1.0f) / dist[2], dgFloat64(0.0f)); dgStack attribArray(GetCount()); dgInt32 count = EnumerateAttributeArray(&attribArray[0]); materialArray[0] = front; materialArray[1] = side; materialArray[2] = top; dgInt32 mark = IncLRU(); dgPolyhedra::Iterator iter(*this); for (iter.Begin(); iter; iter++) { dgEdge *const edge = &(*iter); if (edge->m_mark < mark) { const dgBigVector &p0 = m_points[edge->m_incidentVertex]; const dgBigVector &p1 = m_points[edge->m_next->m_incidentVertex]; const dgBigVector &p2 = m_points[edge->m_prev->m_incidentVertex]; edge->m_mark = mark; edge->m_next->m_mark = mark; edge->m_prev->m_mark = mark; dgBigVector e0(p1 - p0); dgBigVector e1(p2 - p0); dgBigVector n(e0 * e1); dgInt32 index = 0; dgFloat64 maxProjection = dgFloat32(0.0f); for (dgInt32 i = 0; i < 3; i++) { dgFloat64 proj = fabs(n[i]); if (proj > maxProjection) { index = i; maxProjection = proj; } } dgInt32 u = (index + 1) % 3; dgInt32 v = (u + 1) % 3; if (index == 1) { Swap(u, v); } dgEdge *ptr = edge; do { dgVertexAtribute &attrib = attribArray[dgInt32(ptr->m_userData)]; dgBigVector p( scale.CompProduct(m_points[ptr->m_incidentVertex] - minVal)); attrib.m_u0 = p[u]; attrib.m_v0 = p[v]; attrib.m_u1 = dgFloat64(0.0f); attrib.m_v1 = dgFloat64(0.0f); attrib.m_material = materialArray[index]; ptr = ptr->m_next; } while (ptr != edge); } } ApplyAttributeArray(&attribArray[0], count); } void dgMeshEffect::UniformBoxMapping(dgInt32 material, const dgMatrix &textureMatrix) { dgStack attribArray(GetCount()); dgInt32 count = EnumerateAttributeArray(&attribArray[0]); dgInt32 mark = IncLRU(); for (dgInt32 i = 0; i < 3; i++) { dgMatrix rotationMatrix(dgGetIdentityMatrix()); if (i == 1) { rotationMatrix = dgYawMatrix(dgFloat32(90.0f * 3.1416f / 180.0f)); } else if (i == 2) { rotationMatrix = dgPitchMatrix(dgFloat32(90.0f * 3.1416f / 180.0f)); } dgPolyhedra::Iterator iter(*this); for (iter.Begin(); iter; iter++) { dgEdge *const edge = &(*iter); if (edge->m_mark < mark) { dgBigVector n(FaceNormal(edge, &m_points[0].m_x, sizeof(dgBigVector))); dgVector normal( rotationMatrix.RotateVector( dgVector(n.Scale(dgFloat64(1.0f) / sqrt(n % n))))); normal.m_x = dgAbsf(normal.m_x); normal.m_y = dgAbsf(normal.m_y); normal.m_z = dgAbsf(normal.m_z); if ((normal.m_z >= (normal.m_x - dgFloat32(1.0e-4f))) && (normal.m_z >= (normal.m_y - dgFloat32(1.0e-4f)))) { dgEdge *ptr = edge; do { ptr->m_mark = mark; dgVertexAtribute &attrib = attribArray[dgInt32(ptr->m_userData)]; dgVector p( textureMatrix.TransformVector( rotationMatrix.RotateVector( m_points[ptr->m_incidentVertex]))); attrib.m_u0 = p.m_x; attrib.m_v0 = p.m_y; attrib.m_u1 = dgFloat32(0.0f); attrib.m_v1 = dgFloat32(0.0f); attrib.m_material = material; ptr = ptr->m_next; } while (ptr != edge); } } } } ApplyAttributeArray(&attribArray[0], count); } void dgMeshEffect::CalculateNormals(dgFloat64 angleInRadians) { dgStack faceNormal(GetCount()); dgStack attribArray(GetCount()); dgInt32 count = EnumerateAttributeArray(&attribArray[0]); dgInt32 faceIndex = 1; dgInt32 mark = IncLRU(); dgPolyhedra::Iterator iter(*this); for (iter.Begin(); iter; iter++) { dgEdge *const edge = &(*iter); if ((edge->m_mark < mark) && (edge->m_incidentFace > 0)) { dgEdge *ptr = edge; do { ptr->m_incidentFace = faceIndex; ptr->m_mark = mark; ptr = ptr->m_next; } while (ptr != edge); dgBigVector normal( FaceNormal(edge, &m_points[0].m_x, sizeof(m_points[0]))); normal = normal.Scale( dgFloat32(1.0f) / (sqrt(normal % normal) + dgFloat32(1.0e-16f))); faceNormal[faceIndex] = normal; faceIndex++; } } dgFloat32 smoothValue = dgCos(angleInRadians); // smoothValue = -1; for (iter.Begin(); iter; iter++) { dgEdge *const edge = &(*iter); if (edge->m_incidentFace > 0) { dgBigVector normal0(faceNormal[edge->m_incidentFace]); dgEdge *startEdge = edge; for (dgEdge *ptr = edge->m_prev->m_twin; (ptr != edge) && (ptr->m_incidentFace > 0); ptr = ptr->m_prev->m_twin) { const dgBigVector &normal1(faceNormal[ptr->m_incidentFace]); dgFloat64 dot = normal0 % normal1; if (dot < smoothValue) { break; } startEdge = ptr; normal0 = normal1; } dgBigVector normal(faceNormal[startEdge->m_incidentFace]); normal0 = normal; for (dgEdge *ptr = startEdge->m_twin->m_next; (ptr != startEdge) && (ptr->m_incidentFace > 0); ptr = ptr->m_twin->m_next) { const dgBigVector &normal1(faceNormal[ptr->m_incidentFace]); dgFloat64 dot = normal0 % normal1; if (dot < smoothValue) { break; } normal += normal1; normal0 = normal1; } normal = normal.Scale( dgFloat32(1.0f) / (sqrt(normal % normal) + dgFloat32(1.0e-16f))); dgInt32 edgeIndex = dgInt32(edge->m_userData); dgVertexAtribute &attrib = attribArray[edgeIndex]; attrib.m_normal_x = normal.m_x; attrib.m_normal_y = normal.m_y; attrib.m_normal_z = normal.m_z; } } ApplyAttributeArray(&attribArray[0], count); } void dgMeshEffect::BeginPolygon() { m_pointCount = 0; m_atribCount = 0; RemoveAll(); BeginFace(); } void dgMeshEffect::AddAtribute(const dgVertexAtribute &attib) { if (m_atribCount >= m_maxAtribCount) { m_maxAtribCount *= 2; dgVertexAtribute *const attibArray = (dgVertexAtribute *)GetAllocator()->MallocLow( dgInt32(m_maxAtribCount * sizeof(dgVertexAtribute))); memcpy(attibArray, m_attib, m_atribCount * sizeof(dgVertexAtribute)); GetAllocator()->FreeLow(m_attib); m_attib = attibArray; } m_attib[m_atribCount] = attib; m_attib[m_atribCount].m_vertex.m_x = QuantizeCordinade( m_attib[m_atribCount].m_vertex.m_x); m_attib[m_atribCount].m_vertex.m_y = QuantizeCordinade( m_attib[m_atribCount].m_vertex.m_y); m_attib[m_atribCount].m_vertex.m_z = QuantizeCordinade( m_attib[m_atribCount].m_vertex.m_z); m_atribCount++; } void dgMeshEffect::AddVertex(const dgBigVector &vertex) { if (m_pointCount >= m_maxPointCount) { m_maxPointCount *= 2; dgBigVector *const points = (dgBigVector *)GetAllocator()->MallocLow( dgInt32(m_maxPointCount * sizeof(dgBigVector))); memcpy(points, m_points, m_pointCount * sizeof(dgBigVector)); GetAllocator()->FreeLow(m_points); m_points = points; } m_points[m_pointCount].m_x = QuantizeCordinade(vertex[0]); m_points[m_pointCount].m_y = QuantizeCordinade(vertex[1]); m_points[m_pointCount].m_z = QuantizeCordinade(vertex[2]); m_points[m_pointCount].m_w = vertex.m_w; m_pointCount++; } void dgMeshEffect::AddPoint(const dgFloat64 *vertex, dgInt32 material) { dgVertexAtribute attib; AddVertex(dgBigVector(vertex[0], vertex[1], vertex[2], vertex[3])); attib.m_vertex.m_x = m_points[m_pointCount - 1].m_x; attib.m_vertex.m_y = m_points[m_pointCount - 1].m_y; attib.m_vertex.m_z = m_points[m_pointCount - 1].m_z; attib.m_vertex.m_w = m_points[m_pointCount - 1].m_w; attib.m_normal_x = vertex[4]; attib.m_normal_y = vertex[5]; attib.m_normal_z = vertex[6]; attib.m_u0 = vertex[7]; attib.m_v0 = vertex[8]; attib.m_u1 = vertex[9]; attib.m_v1 = vertex[10]; attib.m_material = material; AddAtribute(attib); } void dgMeshEffect::PackVertexArrays() { if (m_maxPointCount > m_pointCount) { dgBigVector *const points = (dgBigVector *)GetAllocator()->MallocLow( dgInt32(m_pointCount * sizeof(dgBigVector))); memcpy(points, m_points, m_pointCount * sizeof(dgBigVector)); GetAllocator()->FreeLow(m_points); m_points = points; m_maxPointCount = m_pointCount; } if (m_maxAtribCount > m_atribCount) { dgVertexAtribute *const attibArray = (dgVertexAtribute *)GetAllocator()->MallocLow( dgInt32(m_atribCount * sizeof(dgVertexAtribute))); memcpy(attibArray, m_attib, m_atribCount * sizeof(dgVertexAtribute)); GetAllocator()->FreeLow(m_attib); m_attib = attibArray; m_maxAtribCount = m_atribCount; } } #ifdef __USE_DOUBLE_PRECISION__ void dgMeshEffect::AddPolygon(dgInt32 count, const dgFloat32 *const vertexList, dgInt32 strideIndBytes, dgInt32 material) #else void dgMeshEffect::AddPolygon(dgInt32 count, const dgFloat64 *const vertexList, dgInt32 strideIndBytes, dgInt32 material) #endif { dgInt32 stride = dgInt32(strideIndBytes / sizeof(dgFloat64)); if (count > 3) { dgPolyhedra polygon(GetAllocator()); dgInt32 indexList[256]; NEWTON_ASSERT(count < dgInt32(sizeof(indexList) / sizeof(indexList[0]))); for (dgInt32 i = 0; i < count; i++) { indexList[i] = i; } polygon.BeginFace(); polygon.AddFace(count, indexList, NULL); polygon.EndFace(); polygon.Triangulate(vertexList, strideIndBytes, NULL); dgInt32 mark = polygon.IncLRU(); dgPolyhedra::Iterator iter(polygon); for (iter.Begin(); iter; iter++) { dgEdge *const edge = &iter.GetNode()->GetInfo(); if ((edge->m_incidentFace > 0) && (edge->m_mark < mark)) { dgInt32 i0 = edge->m_incidentVertex; dgInt32 i1 = edge->m_next->m_incidentVertex; dgInt32 i2 = edge->m_next->m_next->m_incidentVertex; edge->m_mark = mark; edge->m_next->m_mark = mark; edge->m_next->m_next->m_mark = mark; // #ifdef _DEBUG // dgBigVector p0_ (&vertexList[i0 * stride]); // dgBigVector p1_ (&vertexList[i1 * stride]); // dgBigVector p2_ (&vertexList[i2 * stride]); // dgBigVector e1_ (p1_ - p0_); // dgBigVector e2_ (p2_ - p0_); // dgBigVector n_ (e1_ * e2_); // dgFloat64 mag2_ = n_ % n_; // NEWTON_ASSERT (mag2_ > dgFloat32 (DG_MESH_EFFECT_PRECISION_SCALE_INV * DG_MESH_EFFECT_PRECISION_SCALE_INV)); // #endif AddPoint(vertexList + i0 * stride, material); AddPoint(vertexList + i1 * stride, material); AddPoint(vertexList + i2 * stride, material); #if 0 && defined(_DEBUG) // NEWTON_ASSERT is disabled so this whole calculation is useless const dgBigVector &p0 = m_points[m_pointCount - 3]; const dgBigVector &p1 = m_points[m_pointCount - 2]; const dgBigVector &p2 = m_points[m_pointCount - 1]; dgBigVector e1(p1 - p0); dgBigVector e2(p2 - p0); dgBigVector n(e1 * e2); dgFloat64 mag3 = n % n; NEWTON_ASSERT(mag3 > dgFloat64(DG_MESH_EFFECT_PRECISION_SCALE_INV * DG_MESH_EFFECT_PRECISION_SCALE_INV)); #endif } } } else { AddPoint(vertexList, material); AddPoint(vertexList + stride, material); AddPoint(vertexList + stride + stride, material); const dgBigVector &p0 = m_points[m_pointCount - 3]; const dgBigVector &p1 = m_points[m_pointCount - 2]; const dgBigVector &p2 = m_points[m_pointCount - 1]; dgBigVector e1(p1 - p0); dgBigVector e2(p2 - p0); dgBigVector n(e1 * e2); dgFloat64 mag3 = n % n; if (mag3 < dgFloat64(DG_MESH_EFFECT_PRECISION_SCALE_INV * DG_MESH_EFFECT_PRECISION_SCALE_INV)) { m_pointCount -= 3; m_atribCount -= 3; } } } #ifndef __USE_DOUBLE_PRECISION__ void dgMeshEffect::AddPolygon(dgInt32 count, const dgFloat32 *const vertexList, dgInt32 strideIndBytes, dgInt32 material) { dgVertexAtribute points[256]; NEWTON_ASSERT(count < dgInt32(sizeof(points) / sizeof(points[0]))); dgInt32 stride = strideIndBytes / sizeof(dgFloat32); for (dgInt32 i = 0; i < count; i++) { points[i].m_vertex.m_x = vertexList[i * stride + 0]; points[i].m_vertex.m_y = vertexList[i * stride + 1]; points[i].m_vertex.m_z = vertexList[i * stride + 2]; points[i].m_vertex.m_w = vertexList[i * stride + 3]; points[i].m_normal_x = vertexList[i * stride + 4]; points[i].m_normal_y = vertexList[i * stride + 5]; points[i].m_normal_z = vertexList[i * stride + 6]; points[i].m_u0 = vertexList[i * stride + 7]; points[i].m_v0 = vertexList[i * stride + 8]; points[i].m_u1 = vertexList[i * stride + 9]; points[i].m_u1 = vertexList[i * stride + 10]; } AddPolygon(count, &points[0].m_vertex.m_x, sizeof(dgVertexAtribute), material); } #endif void dgMeshEffect::EndPolygon(dgFloat64 tol) { dgStack indexMap(m_pointCount); dgStack attrIndexMap(m_atribCount); #if 0 && defined(_DEBUG) // NEWTON_ASSERT is disabled so this whole calculation is useless for (dgInt32 i = 0; i < m_pointCount; i += 3) { dgBigVector p0(m_points[i + 0]); dgBigVector p1(m_points[i + 1]); dgBigVector p2(m_points[i + 2]); dgBigVector e1(p1 - p0); dgBigVector e2(p2 - p0); dgBigVector n(e1 * e2); dgFloat64 mag2 = n % n; // NEWTON_ASSERT (mag2 > DG_MESH_EFFECT_TRIANGLE_MIN_AREA); NEWTON_ASSERT(mag2 > dgFloat32(0.0f)); } #endif dgInt32 triangCount = m_pointCount / 3; m_pointCount = dgVertexListToIndexList(&m_points[0].m_x, sizeof(dgBigVector), sizeof(dgBigVector) / sizeof(dgFloat64), m_pointCount, &indexMap[0], tol); m_atribCount = dgVertexListToIndexList(&m_attib[0].m_vertex.m_x, sizeof(dgVertexAtribute), sizeof(dgVertexAtribute) / sizeof(dgFloat64), m_atribCount, &attrIndexMap[0], tol); for (dgInt32 i = 0; i < triangCount; i++) { dgInt32 index[3]; dgInt64 userdata[3]; index[0] = indexMap[i * 3 + 0]; index[1] = indexMap[i * 3 + 1]; index[2] = indexMap[i * 3 + 2]; dgBigVector e1(m_points[index[1]] - m_points[index[0]]); dgBigVector e2(m_points[index[2]] - m_points[index[0]]); dgBigVector n(e1 * e2); dgFloat64 mag2 = n % n; if (mag2 > dgFloat64(1.0e-12f)) { userdata[0] = attrIndexMap[i * 3 + 0]; userdata[1] = attrIndexMap[i * 3 + 1]; userdata[2] = attrIndexMap[i * 3 + 2]; dgEdge *const edge = AddFace(3, index, userdata); if (!edge) { NEWTON_ASSERT((m_pointCount + 3) <= m_maxPointCount); m_points[m_pointCount + 0] = m_points[index[0]]; m_points[m_pointCount + 1] = m_points[index[1]]; m_points[m_pointCount + 2] = m_points[index[2]]; index[0] = m_pointCount + 0; index[1] = m_pointCount + 1; index[2] = m_pointCount + 2; m_pointCount += 3; #if 0 && defined(_DEBUG) // NEWTON_ASSERT is disabled so this whole calculation is useless dgEdge *test = AddFace(3, index, userdata); NEWTON_ASSERT(test); #else AddFace(3, index, userdata); #endif } } } EndFace(); RepairTJoints(true); #if 0 && defined(_DEBUG) // NEWTON_ASSERT is disabled so this whole calculation is useless dgPolyhedra::Iterator iter(*this); for (iter.Begin(); iter; iter++) { dgEdge *const face = &(*iter); if (face->m_incidentFace > 0) { dgBigVector p0(m_points[face->m_incidentVertex]); dgBigVector p1(m_points[face->m_next->m_incidentVertex]); dgBigVector p2(m_points[face->m_next->m_next->m_incidentVertex]); dgBigVector e1(p1 - p0); dgBigVector e2(p2 - p0); dgBigVector n(e1 * e2); // NEWTON_ASSERT (mag2 > DG_MESH_EFFECT_TRIANGLE_MIN_AREA); dgFloat64 mag2 = n % n; NEWTON_ASSERT(mag2 > dgFloat32(0.0f)); } } #endif } void dgMeshEffect::BuildFromVertexListIndexList( dgInt32 faceCount, const dgInt32 *const faceIndexCount, const dgInt32 *const faceMaterialIndex, const dgFloat32 *const vertex, dgInt32 vertexStrideInBytes, const dgInt32 *const vertexIndex, const dgFloat32 *const normal, dgInt32 normalStrideInBytes, const dgInt32 *const normalIndex, const dgFloat32 *const uv0, dgInt32 uv0StrideInBytes, const dgInt32 *const uv0Index, const dgFloat32 *const uv1, dgInt32 uv1StrideInBytes, const dgInt32 *const uv1Index) { BeginPolygon(); // calculate vertex Count dgInt32 vertexCount = 0; dgInt32 maxIndexCount = 0; for (dgInt32 j = 0; j < faceCount; j++) { dgInt32 count = faceIndexCount[j]; for (dgInt32 i = 0; i < count; i++) { vertexCount = GetMax(vertexCount, vertexIndex[maxIndexCount + i] + 1); } maxIndexCount += count; } dgInt32 layerCountBase = 0; dgInt32 vertexStride = dgInt32(vertexStrideInBytes / sizeof(dgFloat32)); for (int i = 0; i < vertexCount; i++) { int index = i * vertexStride; AddVertex(dgBigVector(vertex[index + 0], vertex[index + 1], vertex[index + 2], vertex[index + 3])); layerCountBase += (vertex[index + 3]) > dgFloat32(layerCountBase); } dgInt32 acc = 0; dgInt32 normalStride = dgInt32(normalStrideInBytes / sizeof(dgFloat32)); dgInt32 uv0Stride = dgInt32(uv0StrideInBytes / sizeof(dgFloat32)); dgInt32 uv1Stride = dgInt32(uv1StrideInBytes / sizeof(dgFloat32)); for (dgInt32 j = 0; j < faceCount; j++) { dgInt32 indexCount = faceIndexCount[j]; dgInt32 materialIndex = faceMaterialIndex[j]; for (dgInt32 i = 0; i < indexCount; i++) { dgVertexAtribute point; dgInt32 index = vertexIndex[acc + i]; point.m_vertex = m_points[index]; index = normalIndex[(acc + i)] * normalStride; point.m_normal_x = normal[index + 0]; point.m_normal_y = normal[index + 1]; point.m_normal_z = normal[index + 2]; index = uv0Index[(acc + i)] * uv0Stride; point.m_u0 = uv0[index + 0]; point.m_v0 = uv0[index + 1]; index = uv1Index[(acc + i)] * uv1Stride; point.m_u1 = uv1[index + 0]; point.m_v1 = uv1[index + 1]; point.m_material = materialIndex; AddAtribute(point); } acc += indexCount; } dgStack attrIndexMap(m_atribCount); m_atribCount = dgVertexListToIndexList(&m_attib[0].m_vertex.m_x, sizeof(dgVertexAtribute), sizeof(dgVertexAtribute) / sizeof(dgFloat64), m_atribCount, &attrIndexMap[0], DG_VERTEXLIST_INDEXLIST_TOL); dgInt32 totalIndexCount = 0; dgTree aliasVertexMap(GetAllocator()); for (dgInt32 j = 0; j < faceCount; j++) { dgInt32 index[256]; dgInt64 userdata[256]; dgInt32 count = faceIndexCount[j]; NEWTON_ASSERT(count < dgInt32(sizeof(index) / sizeof(index[0]))); for (dgInt32 i = 0; i < count; i++) { index[i] = vertexIndex[totalIndexCount + i]; // dgTrace (("%d ", index[i])); userdata[i] = attrIndexMap[totalIndexCount + i]; } // dgTrace (("\n")); dgEdge *const edge = AddFace(count, index, userdata); if (!edge) { dgInt32 newFaceIndex[256]; memcpy(newFaceIndex, index, count * sizeof(newFaceIndex[0])); for (bool faceAdded = false; !faceAdded;) { faceAdded = true; dgInt32 i0 = index[count - 1]; for (dgInt32 k = 0; k < count; k++) { dgInt32 i1 = index[k]; dgEdge *const duplicate = FindEdge(i0, i1); if (duplicate) { dgTree::dgTreeNode *aliasNode = aliasVertexMap.Find(i0); if (!aliasNode) { dgInt32 nodeIndex = i0 * vertexStride; aliasNode = aliasVertexMap.Insert(m_pointCount, i0); AddVertex(dgBigVector(vertex[nodeIndex + 0], vertex[nodeIndex + 1], vertex[nodeIndex + 2], vertex[nodeIndex + 3] + 1.0f)); } i0 = aliasNode->GetInfo(); newFaceIndex[k ? (k - 1) : (count - 1)] = i0; aliasNode = aliasVertexMap.Find(i1); if (!aliasNode) { dgInt32 nodeIndex = i1 * vertexStride; aliasNode = aliasVertexMap.Insert(m_pointCount, i1); AddVertex(dgBigVector(vertex[nodeIndex + 0], vertex[nodeIndex + 1], vertex[nodeIndex + 2], vertex[nodeIndex + 3] + 1.0f)); } i1 = aliasNode->GetInfo(); newFaceIndex[k] = i1; } i0 = i1; } dgEdge *const edgeF = AddFace(count, newFaceIndex, userdata); if (!edgeF) { faceAdded = false; memcpy(index, newFaceIndex, count * sizeof(newFaceIndex[0])); } } } totalIndexCount += count; } EndFace(); dgTree::Iterator iter(aliasVertexMap); for (iter.Begin(); iter; iter++) { dgInt32 aliasVertex = iter.GetNode()->GetInfo(); dgPolyhedra::dgPairKey key(aliasVertex, 0); dgTreeNode *const aliasNode = FindGreaterEqual(key.GetVal()); if (aliasNode && (aliasNode->GetInfo().m_incidentVertex == aliasVertex)) { dgInt32 parentVertex = iter.GetNode()->GetKey(); dgPolyhedra::dgPairKey keyV(parentVertex, 0); dgTreeNode *const parentNode = FindGreaterEqual(keyV.GetVal()); NEWTON_ASSERT(parentNode); dgEdge *const alliasEdge = &aliasNode->GetInfo(); dgEdge *const parentEdge = &parentNode->GetInfo(); dgTrace(("\n")); dgEdge *ptr = alliasEdge; do { dgTrace(("%d %d\n", ptr->m_incidentVertex, ptr->m_twin->m_incidentVertex)); ptr = ptr->m_twin->m_next; } while (ptr != alliasEdge); dgTrace(("\n")); ptr = parentEdge; do { dgTrace(("%d %d\n", ptr->m_incidentVertex, ptr->m_twin->m_incidentVertex)); ptr = ptr->m_twin->m_next; } while (ptr != parentEdge); dgTrace(("\n")); } } /* while (conlictFaceList.GetCount()) { dgInt32 confliEdgeCount = 0; //dgEdge* conflictEdgeList[64]; //dgInt32 inverted[64]; dgFloat32 angle[64]; dgConflictEdge conflictEdge (conlictFaceList.GetFirst()->GetInfo()); conlictFaceList.Remove(conlictFaceList.GetFirst()); dgInt32 i0 = conflictEdge.m_edge->m_incidentVertex; dgInt32 i1 = conflictEdge.m_edge->m_next->m_incidentVertex; dgVector p0 (m_points[i0]); dgVector p1 (m_points[i1]); dgVector dir (p1 - p0); dir = dir.Scale (dgFloat32 (1.0f)/dgSqrt (dir % dir)); dgMatrix matrix (dir); matrix = matrix.Inverse(); //conflictEdgeList[confliEdgeCount] = conflictEdge.m_edge; dgVector n (cleanFacesFilter.FaceNormal(conflictEdge.m_edge, &m_points[0].m_x, sizeof (dgBigVector))); n = matrix.RotateVector(n); NEWTON_ASSERT (dgAbsf (n.m_x) < dgFloat32 (1.0e-5f)); angle[confliEdgeCount] = dgAtan2 (n.m_y, n.m_z); if (angle[confliEdgeCount] < dgFloat32 (0.0f)) { angle[confliEdgeCount] += dgFloat32 (2.0f * 3.141593f); } confliEdgeCount ++; if (conflictEdge.m_edge->m_twin) { //confliEdgeList[confliEdgeCount] = conflictEdge.m_edge->m_twin; dgVector n (cleanFacesFilter.FaceNormal(conflictEdge.m_edge->m_twin, &m_points[0].m_x, sizeof (dgBigVector))); n = matrix.RotateVector(n); NEWTON_ASSERT (dgAbsf (n.m_x) < dgFloat32 (1.0e-5f)); angle[confliEdgeCount] = dgAtan2 (n.m_y, n.m_z); if (angle[confliEdgeCount] < dgFloat32 (0.0f)) { angle[confliEdgeCount] += dgFloat32 (2.0f * 3.141593f); } confliEdgeCount ++; } else { dgEdge* const twin = cleanFacesFilter.FindEdge(i1, i0); if (twin) { dgVector n (cleanFacesFilter.FaceNormal(twin, &m_points[0].m_x, sizeof (dgBigVector))); n = matrix.RotateVector(n); NEWTON_ASSERT (dgAbsf (n.m_x) < dgFloat32 (1.0e-5f)); angle[confliEdgeCount] = dgAtan2 (n.m_y, n.m_z); if (angle[confliEdgeCount] < dgFloat32 (0.0f)) { angle[confliEdgeCount] += dgFloat32 (2.0f * 3.141593f); } confliEdgeCount ++; } } //confliEdgeList[confliEdgeCount] = conflictEdge.m_edge; confliEdgeCount ++; for (dgList::dgListNode* node = conlictFaceList.GetFirst(); node; ) { dgList::dgListNode* const ptr = node; dgConflictEdge newConflictEdge (ptr->GetInfo()); node = node->GetNext(); if ((newConflictEdge.m_edge->m_incidentVertex == i0) && (newConflictEdge.m_edge->m_next->m_incidentVertex == i1)) { conlictFaceList.Remove(ptr); confliEdgeCount ++; } else if ((newConflictEdge.m_edge->m_incidentVertex == i1) && (newConflictEdge.m_edge->m_next->m_incidentVertex == i0)) { conlictFaceList.Remove(ptr); confliEdgeCount ++; } } } */ /* bool hasFaces = true; dgStack faceMark(faceCount); memset(&faceMark[0], 1, size_t(faceMark.GetSizeInBytes())); dgInt32 layerCount = 0; while (hasFaces) { acc = 0; hasFaces = false; dgInt32 vertexBank = layerCount * vertexCount; for (dgInt32 j = 0; j < faceCount; j++) { dgInt32 index[256]; dgInt64 userdata[256]; int indexCount = faceIndexCount[j]; NEWTON_ASSERT(indexCount < dgInt32 (sizeof (index) / sizeof (index[0]))); if (faceMark[j]) { for (int i = 0; i < indexCount; i++) { index[i] = vertexIndex[acc + i] + vertexBank; userdata[i] = attrIndexMap[acc + i]; } dgEdge* const edge = AddFace(indexCount, index, userdata); if (edge) { faceMark[j] = 0; } else { // check if the face is not degenerated bool degeneratedFace = false; for (int i = 0; i < indexCount - 1; i++) { for (int k = i + 1; k < indexCount; k++) { if (index[i] == index[k]) { degeneratedFace = true; } } } if (degeneratedFace) { faceMark[j] = 0; } else { hasFaces = true; } } } acc += indexCount; } if (hasFaces) { layerCount++; for (int i = 0; i < vertexCount; i++) { int index = i * vertexStride; AddVertex(dgBigVector(vertex[index + 0], vertex[index + 1], vertex[index + 2], dgFloat64(layerCount + layerCountBase))); } } } EndFace(); */ PackVertexArrays(); // RepairTJoints(true); } dgInt32 dgMeshEffect::GetTotalFaceCount() const { return GetFaceCount(); } dgInt32 dgMeshEffect::GetTotalIndexCount() const { Iterator iter(*this); dgInt32 count = 0; dgInt32 mark = IncLRU(); for (iter.Begin(); iter; iter++) { dgEdge *const edge = &(*iter); if (edge->m_mark == mark) { continue; } if (edge->m_incidentFace < 0) { continue; } dgEdge *ptr = edge; do { count++; ptr->m_mark = mark; ptr = ptr->m_next; } while (ptr != edge); } return count; } void dgMeshEffect::GetFaces(dgInt32 *const facesIndex, dgInt32 *const materials, void **const faceNodeList) const { Iterator iter(*this); dgInt32 faces = 0; dgInt32 indexCount = 0; dgInt32 mark = IncLRU(); for (iter.Begin(); iter; iter++) { dgEdge *const edge = &(*iter); if (edge->m_mark == mark) { continue; } if (edge->m_incidentFace < 0) { continue; } dgInt32 faceCount = 0; dgEdge *ptr = edge; do { // indexList[indexCount] = dgInt32 (ptr->m_userData); faceNodeList[indexCount] = GetNodeFromInfo(*ptr); indexCount++; faceCount++; ptr->m_mark = mark; ptr = ptr->m_next; } while (ptr != edge); facesIndex[faces] = faceCount; materials[faces] = dgFastInt(m_attib[dgInt32(edge->m_userData)].m_material); faces++; } } void *dgMeshEffect::GetFirstVertex() const { NEWTON_ASSERT(0); return 0; /* Iterator iter (*this); iter.Begin(); dgTreeNode* const node = NULL; if (iter) { dgInt32 mark = IncLRU(); node = iter.GetNode(); dgEdge* const edge = &node->GetInfo(); dgEdge* ptr = edge; do { ptr->m_mark = mark; ptr = ptr->m_twin->m_next; } while (ptr != edge); } return node; */ } void *dgMeshEffect::GetNextVertex(void *vertex) const { dgTreeNode *const node = (dgTreeNode *)vertex; dgInt32 mark = node->GetInfo().m_mark; Iterator iter(*this); iter.Set(node); for (iter++; iter; iter++) { dgTreeNode *const nodeI = iter.GetNode(); if (nodeI->GetInfo().m_mark != mark) { dgEdge *const edge = &nodeI->GetInfo(); dgEdge *ptr = edge; do { ptr->m_mark = mark; ptr = ptr->m_twin->m_next; } while (ptr != edge); return nodeI; } } return NULL; } dgInt32 dgMeshEffect::GetVertexIndex(void *vertex) const { dgTreeNode *const nodeT = (dgTreeNode *)vertex; dgEdge *const edge = &nodeT->GetInfo(); return edge->m_incidentVertex; } void *dgMeshEffect::GetFirstPoint() const { Iterator iter(*this); for (iter.Begin(); iter; iter++) { dgTreeNode *const nodeI = iter.GetNode(); dgEdge *const edge = &nodeI->GetInfo(); if (edge->m_incidentFace > 0) { return nodeI; } } return NULL; } void *dgMeshEffect::GetNextPoint(void *const point) const { Iterator iter(*this); iter.Set((dgTreeNode *)point); for (iter++; iter; iter++) { dgTreeNode *const node = iter.GetNode(); dgEdge *const edge = &node->GetInfo(); if (edge->m_incidentFace > 0) { return node; } } return NULL; } dgInt32 dgMeshEffect::GetPointIndex(const void *point) const { const dgTreeNode *const node = (const dgTreeNode *)point; const dgEdge *const edge = &node->GetInfo(); return int(edge->m_userData); } dgInt32 dgMeshEffect::GetVertexIndexFromPoint(void *point) const { return GetVertexIndex(point); } dgEdge *dgMeshEffect::ConectVertex(dgEdge *const e0, dgEdge *const e1) { dgEdge *const edge = AddHalfEdge(e1->m_incidentVertex, e0->m_incidentVertex); dgEdge *const twin = AddHalfEdge(e0->m_incidentVertex, e1->m_incidentVertex); NEWTON_ASSERT((edge && twin) || !(edge || twin)); if (edge) { edge->m_twin = twin; twin->m_twin = edge; edge->m_incidentFace = e0->m_incidentFace; twin->m_incidentFace = e1->m_incidentFace; edge->m_userData = e1->m_userData; twin->m_userData = e0->m_userData; edge->m_next = e0; edge->m_prev = e1->m_prev; twin->m_next = e1; twin->m_prev = e0->m_prev; e0->m_prev->m_next = twin; e0->m_prev = edge; e1->m_prev->m_next = edge; e1->m_prev = twin; } return edge; } // dgInt32 dgMeshEffect::GetVertexAttributeIndex (const void* vertex) const //{ // dgTreeNode* const node = (dgTreeNode*) vertex; // dgEdge* const edge = &node->GetInfo(); // return int (edge->m_userData); // } void *dgMeshEffect::GetFirstEdge() const { Iterator iter(*this); iter.Begin(); dgTreeNode *node = NULL; if (iter) { dgInt32 mark = IncLRU(); node = iter.GetNode(); dgEdge *const edge = &node->GetInfo(); edge->m_mark = mark; edge->m_twin->m_mark = mark; } return node; } void *dgMeshEffect::GetNextEdge(void *edge) const { dgTreeNode *const node = (dgTreeNode *)edge; dgInt32 mark = node->GetInfo().m_mark; Iterator iter(*this); iter.Set(node); for (iter++; iter; iter++) { dgTreeNode *const nodeI = iter.GetNode(); if (nodeI->GetInfo().m_mark != mark) { nodeI->GetInfo().m_mark = mark; nodeI->GetInfo().m_twin->m_mark = mark; return nodeI; } } return NULL; } void dgMeshEffect::GetEdgeIndex(const void *edge, dgInt32 &v0, dgInt32 &v1) const { const dgTreeNode *const node = (const dgTreeNode *)edge; v0 = node->GetInfo().m_incidentVertex; v1 = node->GetInfo().m_twin->m_incidentVertex; } // void dgMeshEffect::GetEdgeAttributeIndex (const void* edge, dgInt32& v0, dgInt32& v1) const //{ // dgTreeNode* const node = (dgTreeNode*) edge; // v0 = int (node->GetInfo().m_userData); // v1 = int (node->GetInfo().m_twin->m_userData); // } void *dgMeshEffect::GetFirstFace() const { Iterator iter(*this); iter.Begin(); dgTreeNode *node = NULL; if (iter) { dgInt32 mark = IncLRU(); node = iter.GetNode(); dgEdge *const edge = &node->GetInfo(); dgEdge *ptr = edge; do { ptr->m_mark = mark; ptr = ptr->m_next; } while (ptr != edge); } return node; } void *dgMeshEffect::GetNextFace(void *const face) const { dgTreeNode *const node = (dgTreeNode *)face; dgInt32 mark = node->GetInfo().m_mark; Iterator iter(*this); iter.Set(node); for (iter++; iter; iter++) { dgTreeNode *const nodeI = iter.GetNode(); if (nodeI->GetInfo().m_mark != mark) { dgEdge *const edge = &nodeI->GetInfo(); dgEdge *ptr = edge; do { ptr->m_mark = mark; ptr = ptr->m_next; } while (ptr != edge); return nodeI; } } return NULL; } dgInt32 dgMeshEffect::IsFaceOpen(const void *const face) const { const dgTreeNode *const node = (const dgTreeNode *)face; const dgEdge *const edge = &node->GetInfo(); return (edge->m_incidentFace > 0) ? 0 : 1; } dgInt32 dgMeshEffect::GetFaceMaterial(const void *const face) const { const dgTreeNode *const node = (const dgTreeNode *)face; const dgEdge *const edge = &node->GetInfo(); return dgInt32(m_attib[edge->m_userData].m_material); } dgInt32 dgMeshEffect::GetFaceIndexCount(const void *const face) const { int count = 0; const dgTreeNode *const node = (const dgTreeNode *)face; const dgEdge *const edge = &node->GetInfo(); const dgEdge *ptr = edge; do { count++; ptr = ptr->m_next; } while (ptr != edge); return count; } void dgMeshEffect::GetFaceIndex(const void *const face, int *const indices) const { int count = 0; const dgTreeNode *const node = (const dgTreeNode *)face; const dgEdge *const edge = &node->GetInfo(); const dgEdge *ptr = edge; do { indices[count] = ptr->m_incidentVertex; count++; ptr = ptr->m_next; } while (ptr != edge); } void dgMeshEffect::GetFaceAttributeIndex(const void *const face, int *const indices) const { int count = 0; const dgTreeNode *const node = (const dgTreeNode *)face; const dgEdge *const edge = &node->GetInfo(); const dgEdge *ptr = edge; do { indices[count] = int(ptr->m_userData); count++; ptr = ptr->m_next; } while (ptr != edge); } /* dgInt32 GetTotalFaceCount() const; { dgInt32 mark; dgInt32 count; dgInt32 materialCount; dgInt32 materials[256]; dgInt32 streamIndexMap[256]; dgIndexArray* array; count = 0; materialCount = 0; array = (dgIndexArray*) GetAllocator()->MallocLow (4 * sizeof (dgInt32) * GetCount() + sizeof (dgIndexArray) + 2048); array->m_indexList = (dgInt32*)&array[1]; mark = IncLRU(); dgPolyhedra::Iterator iter (*this); memset(streamIndexMap, 0, sizeof (streamIndexMap)); for(iter.Begin(); iter; iter ++){ dgEdge* edge; edge = &(*iter); if ((edge->m_incidentFace >= 0) && (edge->m_mark != mark)) { dgEdge* ptr; dgInt32 hashValue; dgInt32 index0; dgInt32 index1; ptr = edge; ptr->m_mark = mark; index0 = dgInt32 (ptr->m_userData); ptr = ptr->m_next; ptr->m_mark = mark; index1 = dgInt32 (ptr->m_userData); ptr = ptr->m_next; do { ptr->m_mark = mark; array->m_indexList[count * 4 + 0] = index0; array->m_indexList[count * 4 + 1] = index1; array->m_indexList[count * 4 + 2] = dgInt32 (ptr->m_userData); array->m_indexList[count * 4 + 3] = m_attib[dgInt32 (edge->m_userData)].m_material; index1 = dgInt32 (ptr->m_userData); hashValue = array->m_indexList[count * 4 + 3] & 0xff; streamIndexMap[hashValue] ++; materials[hashValue] = array->m_indexList[count * 4 + 3]; count ++; ptr = ptr->m_next; } while (ptr != edge); } } */ void dgMeshEffect::GetVertexStreams(dgInt32 vetexStrideInByte, dgFloat32 *const vertex, dgInt32 normalStrideInByte, dgFloat32 *const normal, dgInt32 uvStrideInByte0, dgFloat32 *const uv0, dgInt32 uvStrideInByte1, dgFloat32 *const uv1) const { uvStrideInByte0 /= sizeof(dgFloat32); uvStrideInByte1 /= sizeof(dgFloat32); vetexStrideInByte /= sizeof(dgFloat32); normalStrideInByte /= sizeof(dgFloat32); for (dgInt32 i = 0; i < m_atribCount; i++) { dgInt32 j = i * vetexStrideInByte; vertex[j + 0] = dgFloat32(m_attib[i].m_vertex.m_x); vertex[j + 1] = dgFloat32(m_attib[i].m_vertex.m_y); vertex[j + 2] = dgFloat32(m_attib[i].m_vertex.m_z); j = i * normalStrideInByte; normal[j + 0] = dgFloat32(m_attib[i].m_normal_x); normal[j + 1] = dgFloat32(m_attib[i].m_normal_y); normal[j + 2] = dgFloat32(m_attib[i].m_normal_z); j = i * uvStrideInByte1; uv1[j + 0] = dgFloat32(m_attib[i].m_u1); uv1[j + 1] = dgFloat32(m_attib[i].m_v1); j = i * uvStrideInByte0; uv0[j + 0] = dgFloat32(m_attib[i].m_u0); uv0[j + 1] = dgFloat32(m_attib[i].m_v0); } } void dgMeshEffect::GetIndirectVertexStreams(dgInt32 vetexStrideInByte, dgFloat64 *const vertex, dgInt32 *const vertexIndices, dgInt32 *const vertexCount, dgInt32 normalStrideInByte, dgFloat64 *const normal, dgInt32 *const normalIndices, dgInt32 *const normalCount, dgInt32 uvStrideInByte0, dgFloat64 *const uv0, dgInt32 *const uvIndices0, dgInt32 *const uvCount0, dgInt32 uvStrideInByte1, dgFloat64 *const uv1, dgInt32 *const uvIndices1, dgInt32 *const uvCount1) { /* GetVertexStreams (vetexStrideInByte, vertex, normalStrideInByte, normal, uvStrideInByte0, uv0, uvStrideInByte1, uv1); *vertexCount = dgVertexListToIndexList(vertex, vetexStrideInByte, vetexStrideInByte, 0, m_atribCount, vertexIndices, dgFloat32 (0.0f)); *normalCount = dgVertexListToIndexList(normal, normalStrideInByte, normalStrideInByte, 0, m_atribCount, normalIndices, dgFloat32 (0.0f)); dgTriplex* const tmpUV = (dgTriplex*) GetAllocator()->MallocLow (dgInt32 (sizeof (dgTriplex) * m_atribCount)); dgInt32 stride = dgInt32 (uvStrideInByte1 /sizeof (dgFloat32)); for (dgInt32 i = 0; i < m_atribCount; i ++){ tmpUV[i].m_x = uv1[i * stride + 0]; tmpUV[i].m_y = uv1[i * stride + 1]; tmpUV[i].m_z = dgFloat32 (0.0f); } dgInt32 count = dgVertexListToIndexList(&tmpUV[0].m_x, sizeof (dgTriplex), sizeof (dgTriplex), 0, m_atribCount, uvIndices1, dgFloat32 (0.0f)); for (dgInt32 i = 0; i < count; i ++){ uv1[i * stride + 0] = tmpUV[i].m_x; uv1[i * stride + 1] = tmpUV[i].m_y; } *uvCount1 = count; stride = dgInt32 (uvStrideInByte0 /sizeof (dgFloat32)); for (dgInt32 i = 0; i < m_atribCount; i ++){ tmpUV[i].m_x = uv0[i * stride + 0]; tmpUV[i].m_y = uv0[i * stride + 1]; tmpUV[i].m_z = dgFloat32 (0.0f); } count = dgVertexListToIndexList(&tmpUV[0].m_x, sizeof (dgTriplex), sizeof (dgTriplex), 0, m_atribCount, uvIndices0, dgFloat32 (0.0f)); for (dgInt32 i = 0; i < count; i ++){ uv0[i * stride + 0] = tmpUV[i].m_x; uv0[i * stride + 1] = tmpUV[i].m_y; } *uvCount0 = count; GetAllocator()->FreeLow (tmpUV); */ } dgMeshEffect::dgIndexArray *dgMeshEffect::MaterialGeometryBegin() const { dgInt32 materials[256]; dgInt32 streamIndexMap[256]; dgInt32 count = 0; dgInt32 materialCount = 0; dgIndexArray *const array = (dgIndexArray *)GetAllocator()->MallocLow( dgInt32(4 * sizeof(dgInt32) * GetCount() + sizeof(dgIndexArray) + 2048)); array->m_indexList = (dgInt32 *)&array[1]; dgInt32 mark = IncLRU(); dgPolyhedra::Iterator iter(*this); memset(streamIndexMap, 0, sizeof(streamIndexMap)); for (iter.Begin(); iter; iter++) { dgEdge *const edge = &(*iter); if ((edge->m_incidentFace >= 0) && (edge->m_mark != mark)) { dgEdge *ptr = edge; ptr->m_mark = mark; dgInt32 index0 = dgInt32(ptr->m_userData); ptr = ptr->m_next; ptr->m_mark = mark; dgInt32 index1 = dgInt32(ptr->m_userData); ptr = ptr->m_next; do { ptr->m_mark = mark; array->m_indexList[count * 4 + 0] = index0; array->m_indexList[count * 4 + 1] = index1; array->m_indexList[count * 4 + 2] = dgInt32(ptr->m_userData); array->m_indexList[count * 4 + 3] = dgInt32( m_attib[dgInt32(edge->m_userData)].m_material); index1 = dgInt32(ptr->m_userData); dgInt32 hashValue = array->m_indexList[count * 4 + 3] & 0xff; streamIndexMap[hashValue]++; materials[hashValue] = array->m_indexList[count * 4 + 3]; count++; ptr = ptr->m_next; } while (ptr != edge); } } array->m_indexCount = count; array->m_materialCount = materialCount; count = 0; for (dgInt32 i = 0; i < 256; i++) { if (streamIndexMap[i]) { array->m_materials[count] = materials[i]; array->m_materialsIndexCount[count] = streamIndexMap[i] * 3; count++; } } array->m_materialCount = count; return array; } void dgMeshEffect::MaterialGeomteryEnd(dgIndexArray *handle) const { GetAllocator()->FreeLow(handle); } dgInt32 dgMeshEffect::GetFirstMaterial(dgIndexArray *handle)const { return GetNextMaterial(handle, -1); } dgInt32 dgMeshEffect::GetNextMaterial(dgIndexArray *const handle, dgInt32 materialId) const { materialId++; if (materialId >= handle->m_materialCount) { materialId = -1; } return materialId; } void dgMeshEffect::GetMaterialGetIndexStream(dgIndexArray *const handle, dgInt32 materialHandle, dgInt32 *const indexArray) const { dgInt32 index; dgInt32 textureID; index = 0; textureID = handle->m_materials[materialHandle]; for (dgInt32 j = 0; j < handle->m_indexCount; j++) { if (handle->m_indexList[j * 4 + 3] == textureID) { indexArray[index + 0] = handle->m_indexList[j * 4 + 0]; indexArray[index + 1] = handle->m_indexList[j * 4 + 1]; indexArray[index + 2] = handle->m_indexList[j * 4 + 2]; index += 3; } } } void dgMeshEffect::GetMaterialGetIndexStreamShort(dgIndexArray *const handle, dgInt32 materialHandle, dgInt16 *const indexArray) const { dgInt32 index; dgInt32 textureID; index = 0; textureID = handle->m_materials[materialHandle]; for (dgInt32 j = 0; j < handle->m_indexCount; j++) { if (handle->m_indexList[j * 4 + 3] == textureID) { indexArray[index + 0] = (dgInt16)handle->m_indexList[j * 4 + 0]; indexArray[index + 1] = (dgInt16)handle->m_indexList[j * 4 + 1]; indexArray[index + 2] = (dgInt16)handle->m_indexList[j * 4 + 2]; index += 3; } } } dgCollision *dgMeshEffect::CreateCollisionTree(dgInt32 shapeID) const { // dgCollision* const collision = world->CreateBVH (); // collision->SetUserDataID(dgUnsigned32 (shapeID)); dgCollisionBVH *const collision = new (GetAllocator()) dgCollisionBVH(GetAllocator()); collision->SetUserDataID(dgUnsigned32(shapeID)); collision->BeginBuild(); dgInt32 mark = IncLRU(); dgPolyhedra::Iterator iter(*this); for (iter.Begin(); iter; iter++) { dgEdge *const face = &(*iter); if ((face->m_mark != mark) && (face->m_incidentFace > 0)) { dgInt32 count = 0; dgVector polygon[256]; dgEdge *ptr = face; do { polygon[count] = dgVector(m_points[ptr->m_incidentVertex]); polygon[count].m_w = dgFloat32(0.0f); count++; ptr->m_mark = mark; ptr = ptr->m_next; } while (ptr != face); collision->AddFace(count, &polygon[0].m_x, sizeof(dgVector), dgInt32(m_attib[face->m_userData].m_material)); } } collision->EndBuild(0); return collision; } dgCollision *dgMeshEffect::CreateConvexCollision(dgFloat64 tolerance, dgInt32 shapeID, const dgMatrix &srcMatrix) const { dgStack poolPtr(m_pointCount * 2); dgVector *const pool = &poolPtr[0]; dgBigVector minBox; dgBigVector maxBox; CalculateAABB(minBox, maxBox); dgVector com((minBox + maxBox).Scale(dgFloat32(0.5f))); dgInt32 count = 0; dgInt32 mark = IncLRU(); dgPolyhedra::Iterator iter(*this); for (iter.Begin(); iter; iter++) { dgEdge *const vertex = &(*iter); if (vertex->m_mark != mark) { dgEdge *ptr = vertex; do { ptr->m_mark = mark; ptr = ptr->m_twin->m_next; } while (ptr != vertex); if (count < dgInt32(poolPtr.GetElementsCount())) { const dgBigVector p = m_points[vertex->m_incidentVertex]; pool[count] = dgVector(p) - com; count++; } } } dgMatrix matrix(srcMatrix); matrix.m_posit += matrix.RotateVector(com); matrix.m_posit.m_w = dgFloat32(1.0f); dgStack buffer( dgInt32(2 + 3 * count + sizeof(dgMatrix) / sizeof(dgInt32))); memset(&buffer[0], 0, size_t(buffer.GetSizeInBytes())); buffer[0] = m_convexHullCollision; buffer[1] = shapeID; for (dgInt32 i = 0; i < count; i++) { buffer[2 + i * 3 + 0] = dgInt32(dgCollision::Quantize(pool[i].m_x)); buffer[2 + i * 3 + 1] = dgInt32(dgCollision::Quantize(pool[i].m_y)); buffer[2 + i * 3 + 2] = dgInt32(dgCollision::Quantize(pool[i].m_z)); } memcpy(&buffer[2 + count * 3], &matrix, sizeof(dgMatrix)); dgUnsigned32 crc = dgCollision::MakeCRC(&buffer[0], buffer.GetSizeInBytes()); dgCollisionConvexHull *collision = new (GetAllocator()) dgCollisionConvexHull( GetAllocator(), crc, count, sizeof(dgVector), dgFloat32(tolerance), &pool[0].m_x, matrix); if (!collision->GetVertexCount()) { collision->Release(); collision = NULL; } else { collision->SetUserDataID(dgUnsigned32(shapeID)); } return collision; } /* dgEdge* dgMeshEffect::InsertFaceVertex (dgEdge* const face, const dgVector& point) { dgInt32 v0; dgInt32 v1; dgInt32 v2; dgInt32 vertexIndex; dgInt32 attibuteIndex; dgFloat32 va; dgFloat32 vb; dgFloat32 vc; dgFloat32 den; dgFloat32 alpha0; dgFloat32 alpha1; dgFloat32 alpha2; dgFloat32 alpha3; dgFloat32 alpha4; dgFloat32 alpha5; dgFloat32 alpha6; dgVertexAtribute attribute; dgEdge* face0; dgEdge* face1; dgEdge* face2; dgEdge* edge0; dgEdge* twin0; dgEdge* edge1; dgEdge* twin1; dgEdge* edge2; dgEdge* twin2; v0 = face->m_incidentVertex; v1 = face->m_next->m_incidentVertex; v2 = face->m_prev->m_incidentVertex; const dgVector& p0 = m_points[v0]; const dgVector& p1 = m_points[v1]; const dgVector& p2 = m_points[v2]; dgVector p10 (p1 - p0); dgVector p20 (p2 - p0); dgVector p_p0 (point - p0); dgVector p_p1 (point - p1); dgVector p_p2 (point - p2); alpha1 = p10 % p_p0; alpha2 = p20 % p_p0; alpha3 = p10 % p_p1; alpha4 = p20 % p_p1; alpha5 = p10 % p_p2; alpha6 = p20 % p_p2; NEWTON_ASSERT (!((alpha1 <= dgFloat32 (0.0f)) && (alpha2 <= dgFloat32 (0.0f)))); NEWTON_ASSERT (!((alpha6 >= dgFloat32 (0.0f)) && (alpha5 <= alpha6))); NEWTON_ASSERT (!((alpha3 >= dgFloat32 (0.0f)) && (alpha4 <= alpha3))); vc = alpha1 * alpha4 - alpha3 * alpha2; vb = alpha5 * alpha2 - alpha1 * alpha6; va = alpha3 * alpha6 - alpha5 * alpha4; NEWTON_ASSERT (!((vc <= dgFloat32 (0.0f)) && (alpha1 >= dgFloat32 (0.0f)) && (alpha3 <= dgFloat32 (0.0f)))); NEWTON_ASSERT (!((vb <= dgFloat32 (0.0f)) && (alpha2 >= dgFloat32 (0.0f)) && (alpha6 <= dgFloat32 (0.0f)))); NEWTON_ASSERT (!((va <= dgFloat32 (0.0f)) && ((alpha4 - alpha3) >= dgFloat32 (0.0f)) && ((alpha5 - alpha6) >= dgFloat32 (0.0f)))); den = float(dgFloat32 (1.0f)) / (va + vb + vc); alpha0 = va * den; alpha1 = vb * den; alpha2 = vc * den; //dgVector p (p0.Scale (alpha0) + p1.Scale (alpha1) + p2.Scale (alpha2)); //alpha3 *= 1; const dgVertexAtribute& attr0 = m_attib[face->m_userData]; const dgVertexAtribute& attr1 = m_attib[face->m_next->m_userData]; const dgVertexAtribute& attr2 = m_attib[face->m_prev->m_userData]; dgVector normal (attr0.m_normal.m_x * alpha0 + attr1.m_normal.m_x * alpha1 + attr0.m_normal.m_x * alpha2, attr0.m_normal.m_y * alpha0 + attr1.m_normal.m_y * alpha1 + attr0.m_normal.m_y * alpha2, attr0.m_normal.m_z * alpha0 + attr1.m_normal.m_z * alpha1 + attr0.m_normal.m_z * alpha2, dgFloat32 (0.0f)); normal = normal.Scale (dgRsqrt (normal % normal)); attribute.m_vertex.m_x = point.m_x; attribute.m_vertex.m_y = point.m_y; attribute.m_vertex.m_z = point.m_z; attribute.m_normal.m_y = normal.m_y; attribute.m_normal.m_z = normal.m_z; attribute.m_normal.m_x = normal.m_x; attribute.m_normal.m_y = normal.m_y; attribute.m_normal.m_z = normal.m_z; attribute.m_u = attr0.m_u * alpha0 + attr1.m_u * alpha1 + attr2.m_u * alpha2; attribute.m_v = attr0.m_v * alpha0 + attr1.m_v * alpha1 + attr2.m_v * alpha2; NEWTON_ASSERT (attr0.m_material == attr1.m_material); NEWTON_ASSERT (attr0.m_material == attr2.m_material); AddVertex (&attribute.m_vertex.m_x, attr0.m_material); vertexIndex = m_pointCount - 1; attibuteIndex = m_atribCount - 1; face0 = face; face1 = face->m_next; face2 = face->m_prev; edge0 = AddHalfEdge(vertexIndex, v0); twin0 = AddHalfEdge(v0, vertexIndex); edge1 = AddHalfEdge(vertexIndex, v1); twin1 = AddHalfEdge(v1, vertexIndex); edge2 = AddHalfEdge(vertexIndex, v2); twin2 = AddHalfEdge(v2, vertexIndex); edge0->m_incidentFace = face->m_incidentFace; twin0->m_incidentFace = face->m_incidentFace; edge1->m_incidentFace = face->m_incidentFace; twin1->m_incidentFace = face->m_incidentFace; edge2->m_incidentFace = face->m_incidentFace; twin2->m_incidentFace = face->m_incidentFace; edge0->m_userData = attibuteIndex; edge1->m_userData = attibuteIndex; edge2->m_userData = attibuteIndex; twin0->m_userData = face0->m_userData; edge1->m_userData = face1->m_userData; edge2->m_userData = face2->m_userData; edge0->m_twin = twin0; twin0->m_twin = edge0; edge1->m_twin = twin1; twin1->m_twin = edge1; edge2->m_twin = twin2; twin2->m_twin = edge2; edge0->m_next = face0; edge1->m_next = face1; edge2->m_next = face2; edge0->m_prev = twin1; edge1->m_prev = twin2; edge2->m_prev = twin0; twin0->m_next = edge2; twin1->m_next = edge0; twin2->m_next = edge1; twin0->m_prev = face2; twin1->m_prev = face0; twin2->m_prev = face1; face0->m_next = twin1; face1->m_next = twin2; face2->m_next = twin0; face0->m_prev = edge0; face1->m_prev = edge1; face2->m_prev = edge2; return edge0; } dgInt32 dgMeshEffect::RayIntersection (dgFloat32& p0p1, const dgVector& p0, const dgVector& p1, dgFloat32& q0q1, const dgVector& q0, const dgVector& q1) const { dgInt32 ret; dgFloat64 a; dgFloat64 b; dgFloat64 c; dgFloat64 d; dgFloat64 e; dgFloat64 D; dgBigVector ray_p0 (p0); dgBigVector ray_p1 (p1); dgBigVector ray_q0 (q0); dgBigVector ray_q1 (q1); dgBigVector u (ray_p1 - ray_p0); dgBigVector v (ray_q1 - ray_q0); a = u % u; // always >= 0 b = u % v; c = v % v; // always >= 0 D = a*c - b*b; // always >= 0 ret = 0; if (D > dgFloat64 (1.0e-8f)) { // the lines are almost parallel dgFloat64 sN; dgFloat64 tN; dgFloat64 fracsN; dgFloat64 fractN; dgBigVector w (ray_p0 - ray_q0); ret = 1; d = u % w; e = v % w; sN = (b*e - c*d) / D; tN = (a*e - b*d) / D; fracsN = DG_QUANTIZE_TOLERANCE / sqrt (a); fractN = DG_QUANTIZE_TOLERANCE / sqrt (c); if (sN < -fracsN) { ret = 0; } else if (sN < fracsN) { sN = dgFloat64 (0.0f); } if (sN > (dgFloat64 (1.0f) + fracsN)) { ret = 0; } else if (sN > (dgFloat64 (1.0f) - fracsN)) { sN = dgFloat64 (1.0f); } if (tN < -fractN) { ret = 0; } else if (tN < fractN) { tN = dgFloat64 (0.0f); } if (tN > (dgFloat64 (1.0f) + fractN)) { ret = 0; } else if (tN > (dgFloat64 (1.0f) - fractN)) { tN = dgFloat64 (1.0f); } if (ret) { dgBigVector p (ray_p0 + u.Scale (sN)); dgBigVector q (ray_q0 + v.Scale (tN)); dgBigVector dist (p - q); d = dist % dist; if (d > (dgFloat32 (16.0f) * DG_QUANTIZE_TOLERANCE * DG_QUANTIZE_TOLERANCE)) { ret = 0; } } p0p1 = dgFloat32 (sN); q0q1 = dgFloat32 (tN); } return ret; } */ void dgMeshEffect::TransformMesh(const dgMatrix &matrix) { dgMatrix normalMatrix(matrix); normalMatrix.m_posit = dgVector(dgFloat32(0.0f), dgFloat32(0.0f), dgFloat32(0.0f), dgFloat32(1.0f)); matrix.TransformTriplex(&m_points->m_x, sizeof(dgBigVector), &m_points->m_x, sizeof(dgBigVector), m_pointCount); matrix.TransformTriplex(&m_attib[0].m_vertex.m_x, sizeof(dgVertexAtribute), &m_attib[0].m_vertex.m_x, sizeof(dgVertexAtribute), m_atribCount); normalMatrix.TransformTriplex(&m_attib[0].m_normal_x, sizeof(dgVertexAtribute), &m_attib[0].m_normal_x, sizeof(dgVertexAtribute), m_atribCount); } dgMeshEffect::dgVertexAtribute dgMeshEffect::InterpolateEdge(dgEdge *const edge, dgFloat64 param) const { dgVertexAtribute attrEdge; dgFloat64 t1 = param; dgFloat64 t0 = dgFloat64(1.0f) - t1; NEWTON_ASSERT(t1 >= dgFloat64(0.0f)); NEWTON_ASSERT(t1 <= dgFloat64(1.0f)); const dgVertexAtribute &attrEdge0 = m_attib[edge->m_userData]; const dgVertexAtribute &attrEdge1 = m_attib[edge->m_next->m_userData]; attrEdge.m_vertex.m_x = attrEdge0.m_vertex.m_x * t0 + attrEdge1.m_vertex.m_x * t1; attrEdge.m_vertex.m_y = attrEdge0.m_vertex.m_y * t0 + attrEdge1.m_vertex.m_y * t1; attrEdge.m_vertex.m_z = attrEdge0.m_vertex.m_z * t0 + attrEdge1.m_vertex.m_z * t1; attrEdge.m_vertex.m_w = dgFloat32(0.0f); attrEdge.m_normal_x = attrEdge0.m_normal_x * t0 + attrEdge1.m_normal_x * t1; attrEdge.m_normal_y = attrEdge0.m_normal_y * t0 + attrEdge1.m_normal_y * t1; attrEdge.m_normal_z = attrEdge0.m_normal_z * t0 + attrEdge1.m_normal_z * t1; attrEdge.m_u0 = attrEdge0.m_u0 * t0 + attrEdge1.m_u0 * t1; attrEdge.m_v0 = attrEdge0.m_v0 * t0 + attrEdge1.m_v0 * t1; attrEdge.m_u1 = attrEdge0.m_u1 * t0 + attrEdge1.m_u1 * t1; attrEdge.m_v1 = attrEdge0.m_v1 * t0 + attrEdge1.m_v1 * t1; attrEdge.m_material = attrEdge0.m_material; return attrEdge; } bool dgMeshEffect::Sanity() const { NEWTON_ASSERT(0); return false; /* Iterator iter (*this); for (iter.Begin(); iter; iter ++) { const dgEdge* const edge = &iter.GetNode()->GetInfo(); if (edge->m_incidentFace > 0) { const dgVertexAtribute& attrEdge0 = m_attib[edge->m_userData]; dgVector p0 (m_points[edge->m_incidentVertex]); dgVector q0 (attrEdge0.m_vertex); dgVector delta0 (p0 - q0); dgFloat32 error0 = delta0 % delta0; if (error0 > dgFloat32 (1.0e-15f)) { return false; } const dgVertexAtribute& attrEdge1 = m_attib[edge->m_next->m_userData]; dgVector p1 (m_points[edge->m_next->m_incidentVertex]); dgVector q1 (attrEdge1.m_vertex); dgVector delta1 (p1 - q1); dgFloat32 error1 = delta1 % delta1; if (error1 > dgFloat32 (1.0e-15f)) { return false; } } } return true; */ } dgEdge *dgMeshEffect::InsertEdgeVertex(dgEdge *const edge, dgFloat64 param) { dgEdge *const twin = edge->m_twin; dgVertexAtribute attrEdge(InterpolateEdge(edge, param)); dgVertexAtribute attrTwin(InterpolateEdge(twin, dgFloat32(1.0f) - param)); attrTwin.m_vertex = attrEdge.m_vertex; AddPoint(&attrEdge.m_vertex.m_x, dgFastInt(attrEdge.m_material)); AddAtribute(attrTwin); dgInt32 edgeAttrV0 = dgInt32(edge->m_userData); dgInt32 twinAttrV0 = dgInt32(twin->m_userData); dgEdge *const faceA0 = edge->m_next; dgEdge *const faceA1 = edge->m_prev; dgEdge *const faceB0 = twin->m_next; dgEdge *const faceB1 = twin->m_prev; // SpliteEdgeAndTriangulate (m_pointCount - 1, edge); SpliteEdge(m_pointCount - 1, edge); faceA0->m_prev->m_userData = dgUnsigned64(m_atribCount - 2); faceA1->m_next->m_userData = dgUnsigned64(edgeAttrV0); faceB0->m_prev->m_userData = dgUnsigned64(m_atribCount - 1); faceB1->m_next->m_userData = dgUnsigned64(twinAttrV0); return faceA1->m_next; } dgMeshEffect::dgVertexAtribute dgMeshEffect::InterpolateVertex( const dgBigVector &srcPoint, dgEdge *const face) const { // this should use Googol extended precision floats, because some face coming from Voronoi decomposition and booleans // clipping has extreme aspect ratios, for now just use float64 const dgBigVector point(srcPoint); dgVertexAtribute attribute; attribute.clear(); dgFloat64 tol = dgFloat32(1.0e-4f); for (dgInt32 i = 0; i < 4; i++) { dgEdge *ptr = face; dgEdge *const edge0 = ptr; dgBigVector q0(m_points[ptr->m_incidentVertex]); ptr = ptr->m_next; const dgEdge *edge1 = ptr; dgBigVector q1(m_points[ptr->m_incidentVertex]); ptr = ptr->m_next; const dgEdge *edge2 = ptr; do { const dgBigVector q2(m_points[ptr->m_incidentVertex]); dgBigVector p10(q1 - q0); dgBigVector p20(q2 - q0); #if 0 && defined(_DEBUG) // NEWTON_ASSERT is disabled so this whole calculation is useless dgFloat64 dot = p20 % p10; dgFloat64 mag1 = p10 % p10; dgFloat64 mag2 = p20 % p20; dgFloat64 collinear = dot * dot - mag2 * mag1; NEWTON_ASSERT(fabs(collinear) > dgFloat64(1.0e-8f)); #endif dgBigVector p_p0(point - q0); dgBigVector p_p1(point - q1); dgBigVector p_p2(point - q2); dgFloat64 p_alpha1 = p10 % p_p0; dgFloat64 p_alpha2 = p20 % p_p0; dgFloat64 p_alpha3 = p10 % p_p1; dgFloat64 p_alpha4 = p20 % p_p1; dgFloat64 p_alpha5 = p10 % p_p2; dgFloat64 p_alpha6 = p20 % p_p2; dgFloat64 vc = p_alpha1 * p_alpha4 - p_alpha3 * p_alpha2; dgFloat64 vb = p_alpha5 * p_alpha2 - p_alpha1 * p_alpha6; dgFloat64 va = p_alpha3 * p_alpha6 - p_alpha5 * p_alpha4; dgFloat64 den = va + vb + vc; dgFloat64 minError = den * (-tol); dgFloat64 maxError = den * (dgFloat32(1.0f) + tol); if ((va > minError) && (vb > minError) && (vc > minError) && (va < maxError) && (vb < maxError) && (vc < maxError)) { edge2 = ptr; den = dgFloat64(1.0f) / (va + vb + vc); dgFloat64 alpha0 = dgFloat32(va * den); dgFloat64 alpha1 = dgFloat32(vb * den); dgFloat64 alpha2 = dgFloat32(vc * den); const dgVertexAtribute &attr0 = m_attib[edge0->m_userData]; const dgVertexAtribute &attr1 = m_attib[edge1->m_userData]; const dgVertexAtribute &attr2 = m_attib[edge2->m_userData]; dgBigVector normal( attr0.m_normal_x * alpha0 + attr1.m_normal_x * alpha1 + attr2.m_normal_x * alpha2, attr0.m_normal_y * alpha0 + attr1.m_normal_y * alpha1 + attr2.m_normal_y * alpha2, attr0.m_normal_z * alpha0 + attr1.m_normal_z * alpha1 + attr2.m_normal_z * alpha2, dgFloat32(0.0f)); normal = normal.Scale(dgFloat64(1.0f) / sqrt(normal % normal)); #if 0 && defined(_DEBUG) // NEWTON_ASSERT is disabled so this whole calculation is useless dgBigVector testPoint( attr0.m_vertex.m_x * alpha0 + attr1.m_vertex.m_x * alpha1 + attr2.m_vertex.m_x * alpha2, attr0.m_vertex.m_y * alpha0 + attr1.m_vertex.m_y * alpha1 + attr2.m_vertex.m_y * alpha2, attr0.m_vertex.m_z * alpha0 + attr1.m_vertex.m_z * alpha1 + attr2.m_vertex.m_z * alpha2, dgFloat32(0.0f)); NEWTON_ASSERT(fabs(testPoint.m_x - point.m_x) < dgFloat32(1.0e-2f)); NEWTON_ASSERT(fabs(testPoint.m_y - point.m_y) < dgFloat32(1.0e-2f)); NEWTON_ASSERT(fabs(testPoint.m_z - point.m_z) < dgFloat32(1.0e-2f)); #endif attribute.m_vertex.m_x = point.m_x; attribute.m_vertex.m_y = point.m_y; attribute.m_vertex.m_z = point.m_z; attribute.m_vertex.m_w = point.m_w; attribute.m_normal_x = normal.m_x; attribute.m_normal_y = normal.m_y; attribute.m_normal_z = normal.m_z; attribute.m_u0 = attr0.m_u0 * alpha0 + attr1.m_u0 * alpha1 + attr2.m_u0 * alpha2; attribute.m_v0 = attr0.m_v0 * alpha0 + attr1.m_v0 * alpha1 + attr2.m_v0 * alpha2; attribute.m_u1 = attr0.m_u1 * alpha0 + attr1.m_u1 * alpha1 + attr2.m_u1 * alpha2; attribute.m_v1 = attr0.m_v1 * alpha0 + attr1.m_v1 * alpha1 + attr2.m_v1 * alpha2; attribute.m_material = attr0.m_material; NEWTON_ASSERT(attr0.m_material == attr1.m_material); NEWTON_ASSERT(attr0.m_material == attr2.m_material); return attribute; } q1 = q2; edge1 = ptr; ptr = ptr->m_next; } while (ptr != face); tol *= dgFloat64(2.0f); } // this should never happens NEWTON_ASSERT(0); return attribute; } void dgMeshEffect::MergeFaces(const dgMeshEffect *const source) { dgInt32 mark = source->IncLRU(); dgPolyhedra::Iterator iter(*source); for (iter.Begin(); iter; iter++) { dgEdge *const edge = &(*iter); if ((edge->m_incidentFace > 0) && (edge->m_mark < mark)) { dgVertexAtribute face[DG_MESH_EFFECT_POINT_SPLITED]; dgInt32 count = 0; dgEdge *ptr = edge; do { ptr->m_mark = mark; face[count] = source->m_attib[ptr->m_userData]; count++; NEWTON_ASSERT(count < dgInt32(sizeof(face) / sizeof(face[0]))); ptr = ptr->m_next; } while (ptr != edge); AddPolygon(count, &face[0].m_vertex.m_x, sizeof(dgVertexAtribute), dgFastInt(face[0].m_material)); } } } void dgMeshEffect::ReverseMergeFaces(dgMeshEffect *const source) { dgInt32 mark = source->IncLRU(); dgPolyhedra::Iterator iter(*source); for (iter.Begin(); iter; iter++) { dgEdge *const edge = &(*iter); if ((edge->m_incidentFace > 0) && (edge->m_mark < mark)) { dgVertexAtribute face[DG_MESH_EFFECT_POINT_SPLITED]; dgInt32 count = 0; dgEdge *ptr = edge; do { ptr->m_mark = mark; face[count] = source->m_attib[ptr->m_userData]; face[count].m_normal_x *= dgFloat32(-1.0f); face[count].m_normal_y *= dgFloat32(-1.0f); face[count].m_normal_z *= dgFloat32(-1.0f); count++; NEWTON_ASSERT(count < dgInt32(sizeof(face) / sizeof(face[0]))); ptr = ptr->m_prev; } while (ptr != edge); AddPolygon(count, &face[0].m_vertex.m_x, sizeof(dgVertexAtribute), dgFastInt(face[0].m_material)); } } } void dgMeshEffect::FilterCoplanarFaces(const dgMeshEffect *const coplanarFaces, dgFloat32 sign) { const dgFloat64 tol = dgFloat64(1.0e-5f); const dgFloat64 tol2 = tol * tol; dgInt32 mark = IncLRU(); Iterator iter(*this); for (iter.Begin(); iter;) { dgEdge *const face = &(*iter); iter++; if ((face->m_mark != mark) && (face->m_incidentFace > 0)) { dgEdge *ptr = face; do { ptr->m_mark = mark; ptr = ptr->m_next; } while (ptr != face); dgBigVector normal( FaceNormal(face, &m_points[0].m_x, sizeof(dgBigVector))); normal = normal.Scale(sign); dgBigVector origin(m_points[face->m_incidentVertex]); dgFloat64 error2 = (normal % normal) * tol2; dgInt32 capMark = coplanarFaces->IncLRU(); Iterator capIter(*coplanarFaces); for (capIter.Begin(); capIter; capIter++) { dgEdge *const capFace = &(*capIter); if ((capFace->m_mark != capMark) && (capFace->m_incidentFace > 0)) { dgEdge *ptrCF = capFace; do { ptrCF->m_mark = capMark; ptrCF = ptrCF->m_next; } while (ptrCF != capFace); dgBigVector capNormal( coplanarFaces->FaceNormal(capFace, &coplanarFaces->m_points[0].m_x, sizeof(dgBigVector))); if ((capNormal % normal) > dgFloat64(0.0f)) { dgBigVector capOrigin( coplanarFaces->m_points[capFace->m_incidentVertex]); dgFloat64 dist = normal % (capOrigin - origin); if ((dist * dist) < error2) { DeleteFace(face); iter.Begin(); break; } } } } } } } dgMeshEffect *dgMeshEffect::Union(const dgMatrix &matrix, const dgMeshEffect *const clipMesh) const { dgMeshEffect clipper(*clipMesh); clipper.TransformMesh(matrix); DG_MESG_EFFECT_BOOLEAN_INIT(); ClipMesh(&clipper, &leftMeshSource, &rightMeshSource, &sourceCoplanar); clipper.ClipMesh(this, &leftMeshClipper, &rightMeshClipper, &clipperCoplanar); if (rightMeshSource || rightMeshClipper) { result = new (GetAllocator()) dgMeshEffect(GetAllocator(), true); result->BeginPolygon(); if (rightMeshSource) { result->MergeFaces(rightMeshSource); } if (rightMeshClipper) { result->MergeFaces(rightMeshClipper); } if (clipperCoplanar && sourceCoplanar) { // sourceCoplanar->FilterCoplanarFaces (clipperCoplanar, dgFloat32 (-1.0f)); // result->MergeFaces(sourceCoplanar); clipperCoplanar->FilterCoplanarFaces(sourceCoplanar, dgFloat32(-1.0f)); result->MergeFaces(clipperCoplanar); } result->EndPolygon(dgFloat64(1.0e-5f)); if (!result->GetCount()) { result->Release(); result = NULL; } } DG_MESG_EFFECT_BOOLEAN_FINISH(); return result; } dgMeshEffect *dgMeshEffect::Intersection(const dgMatrix &matrix, const dgMeshEffect *const clipMesh) const { dgMeshEffect clipper(*clipMesh); clipper.TransformMesh(matrix); DG_MESG_EFFECT_BOOLEAN_INIT(); ClipMesh(&clipper, &leftMeshSource, &rightMeshSource, &sourceCoplanar); clipper.ClipMesh(this, &leftMeshClipper, &rightMeshClipper, &clipperCoplanar); if (leftMeshSource || leftMeshClipper) { result = new (GetAllocator()) dgMeshEffect(GetAllocator(), true); result->BeginPolygon(); if (leftMeshSource) { result->MergeFaces(leftMeshSource); } if (leftMeshClipper) { result->MergeFaces(leftMeshClipper); } if (clipperCoplanar && sourceCoplanar) { sourceCoplanar->FilterCoplanarFaces(clipperCoplanar, dgFloat32(-1.0f)); result->MergeFaces(sourceCoplanar); } result->EndPolygon(dgFloat64(1.0e-5f)); if (!result->GetCount()) { result->Release(); result = NULL; } } DG_MESG_EFFECT_BOOLEAN_FINISH(); return result; } dgMeshEffect *dgMeshEffect::Difference(const dgMatrix &matrix, const dgMeshEffect *const clipMesh) const { dgMeshEffect clipper(*clipMesh); clipper.TransformMesh(matrix); DG_MESG_EFFECT_BOOLEAN_INIT(); ClipMesh(&clipper, &leftMeshSource, &rightMeshSource, &sourceCoplanar); if (rightMeshSource) { result = new (GetAllocator()) dgMeshEffect(GetAllocator(), true); result->BeginPolygon(); if (rightMeshSource) { result->MergeFaces(rightMeshSource); } clipper.ClipMesh(this, &leftMeshClipper, &rightMeshClipper, &clipperCoplanar); if (leftMeshClipper || clipperCoplanar) { if (leftMeshClipper) { result->ReverseMergeFaces(leftMeshClipper); } if (clipperCoplanar && sourceCoplanar) { NEWTON_ASSERT(sourceCoplanar); clipperCoplanar->FilterCoplanarFaces(sourceCoplanar, dgFloat32(1.0f)); result->ReverseMergeFaces(clipperCoplanar); } } result->EndPolygon(dgFloat64(1.0e-5f)); if (!result->GetCount()) { result->Release(); result = NULL; } } DG_MESG_EFFECT_BOOLEAN_FINISH(); return result; } void dgMeshEffect::ClipMesh(const dgMatrix &matrix, const dgMeshEffect *const clipMesh, dgMeshEffect **const back, dgMeshEffect **const front) const { NEWTON_ASSERT(0); /* dgMeshEffect clipper (*clipMesh); clipper.TransformMesh (matrix); dgMeshEffect* backMeshSource = NULL; dgMeshEffect* frontMeshSource = NULL; dgMeshEffect* backMeshClipper = NULL; dgMeshEffect* frontMeshClipper = NULL; ClipMesh (&clipper, &backMeshSource, &frontMeshSource); if (backMeshSource && frontMeshSource) { clipper.ClipMesh (this, &backMeshClipper, &frontMeshClipper); if (backMeshSource && frontMeshSource) { dgMeshEffect* backMesh; dgMeshEffect* frontMesh; backMesh = new (GetAllocator()) dgMeshEffect (GetAllocator(), true); frontMesh = new (GetAllocator()) dgMeshEffect (GetAllocator(), true); backMesh->BeginPolygon(); frontMesh->BeginPolygon(); backMesh->MergeFaces(backMeshSource); backMesh->MergeFaces(backMeshClipper); frontMesh->MergeFaces(frontMeshSource); frontMesh->ReverseMergeFaces(backMeshClipper); backMesh->EndPolygon(dgFloat64 (1.0e-5f)); frontMesh->EndPolygon(dgFloat64 (1.0e-5f)); *back = backMesh; *front = frontMesh; } } if (backMeshClipper) { delete backMeshClipper; } if (frontMeshClipper) { delete frontMeshClipper; } if (backMeshSource) { delete backMeshSource; } if (frontMeshSource) { delete frontMeshSource; } */ } dgMeshEffectSolidTree *dgMeshEffect::CreateSolidTree() const { dgMeshEffectSolidTree *tree = NULL; dgInt32 mark = IncLRU(); dgPolyhedra::Iterator iter(*this); for (iter.Begin(); iter; iter++) { dgEdge *const face = &(*iter); if ((face->m_incidentFace > 0) && (face->m_mark != mark)) { dgEdge *ptr = face; do { ptr->m_mark = mark; ptr = ptr->m_next; } while (ptr != face); if (ptr->m_next->m_next->m_next == ptr) { if (!tree) { dgBigVector normal( FaceNormal(face, &m_points[0][0], sizeof(dgBigVector))); dgFloat64 mag2 = normal % normal; if (mag2 > dgFloat32(1.0e-10f)) { tree = new (GetAllocator()) dgMeshEffectSolidTree(*this, face); } } else { tree->AddFace(*this, face); } } else { dgMeshEffect flatFace(GetAllocator(), true); dgInt32 count = 0; dgVertexAtribute points[256]; flatFace.BeginPolygon(); dgEdge *ptrF = face; do { points[count] = m_attib[ptrF->m_userData]; count++; ptrF = ptrF->m_next; } while (ptrF != face); flatFace.AddPolygon(count, &points[0].m_vertex.m_x, sizeof(dgVertexAtribute), 0); flatFace.EndPolygon(dgFloat64(1.0e-5f)); dgInt32 flatMark = flatFace.IncLRU(); dgPolyhedra::Iterator flatIter(flatFace); for (flatIter.Begin(); flatIter; flatIter++) { dgEdge *const faceI = &(*flatIter); if ((faceI->m_incidentFace > 0) && (faceI->m_mark != flatMark)) { dgEdge *ptrFI = faceI; do { ptrFI->m_mark = flatMark; ptrFI = ptrFI->m_next; } while (ptrFI != faceI); if (!tree) { dgBigVector normal( flatFace.FaceNormal(faceI, &flatFace.m_points[0][0], sizeof(dgBigVector))); dgFloat64 mag2 = normal % normal; if (mag2 > dgFloat32(1.0e-10f)) { tree = new (GetAllocator()) dgMeshEffectSolidTree(flatFace, faceI); } } else { tree->AddFace(flatFace, faceI); } } } } } } NEWTON_ASSERT(tree); return tree; } void dgMeshEffect::DestroySolidTree(dgMeshEffectSolidTree *const tree) { delete tree; } void dgMeshEffect::ClipMesh(const dgMeshEffect *const clipMesh, dgMeshEffect **const left, dgMeshEffect **const right, dgMeshEffect **const coplanar) const { const dgMeshEffectSolidTree *const clipper = clipMesh->CreateSolidTree(); NEWTON_ASSERT(clipper); ClipMesh(clipper, left, right, coplanar); delete clipper; } bool dgMeshEffect::CheckIntersection( const dgMeshEffectSolidTree *const solidTree, dgFloat64 scale) const { NEWTON_ASSERT(0); return false; /* if (solidTree) { dgInt32 mark; dgInt32 count; dgVector center (dgFloat32 (0.0f), dgFloat32 (0.0f), dgFloat32 (0.0f), dgFloat32 (0.0f)); count = 0; mark = IncLRU(); dgPolyhedra::Iterator iter (*this); for (iter.Begin(); iter; iter ++){ dgEdge* face; face = &(*iter); if (face->m_mark != mark) { dgEdge* ptr; ptr = face; do { ptr->m_mark = mark; ptr = ptr->m_twin->m_next; } while (ptr != face); count ++; center += m_points[face->m_incidentVertex]; } } center = center.Scale (dgFloat32 (1.0f) / dgFloat32(count)); dgMatrix matrix (dgGetIdentityMatrix()); matrix[0][0] = scale; matrix[1][1] = scale; matrix[2][2] = scale; matrix.m_posit = center - matrix.RotateVector(center); matrix[3][3] = dgFloat32 (1.0f); mark = IncLRU(); for (iter.Begin(); iter; iter ++){ dgEdge* face; face = &(*iter); if (face->m_incidentFace > 0) { if (face->m_mark != mark) { dgInt32 stack; dgInt32 frontCount; dgInt32 backCount; dgEdge* ptr; dgMeshTreeCSGFace* meshFace; dgMeshTreeCSGPointsPool points; dgMeshTreeCSGFace* faceOnStack[DG_MESH_EFFECT_BOLLEAN_STACK]; const dgMeshEffectSolidTree* stackPool[DG_MESH_EFFECT_BOLLEAN_STACK]; backCount = 0; frontCount = 0; meshFace = new (GetAllocator()) dgMeshTreeCSGFace(GetAllocator()); ptr = face; do { dgInt32 index; index = points.AddPoint (matrix.TransformVector(m_points[ptr->m_incidentVertex])); meshFace->AddPoint (index); ptr->m_mark = mark; ptr = ptr->m_next; } while (ptr != face); stack = 1; stackPool[0] = solidTree; faceOnStack[0] = meshFace; meshFace->AddRef(); while (stack) { dgMeshTreeCSGFace* rootFace; dgMeshTreeCSGFace* backFace; dgMeshTreeCSGFace* frontFace; const dgMeshEffectSolidTree* root; stack --; root = stackPool[stack]; rootFace = faceOnStack[stack]; ClipFace (root->m_plane, rootFace, &backFace, &frontFace, points); rootFace->Release(); if (frontFace) { NEWTON_ASSERT (frontFace->CheckConvex(this, face, points)); if (root->m_front) { stackPool[stack] = root->m_front; faceOnStack[stack] = frontFace; stack ++; NEWTON_ASSERT (stack < sizeof (stackPool) / sizeof (stackPool[0])); } else { frontFace->Release(); frontCount ++; } } if (backFace) { NEWTON_ASSERT (backFace->CheckConvex(this, face, points)); if (root->m_back) { stackPool[stack] = root->m_back; faceOnStack[stack] = backFace; stack ++; NEWTON_ASSERT (stack < sizeof (stackPool) / sizeof (stackPool[0])); } else { backFace->Release(); backCount ++; } } } meshFace->Release(); if (backCount) { return true; } } } } } return false; */ } void dgMeshEffect::PlaneClipMesh(const dgMeshEffect *planeMesh, dgMeshEffect **back, dgMeshEffect **front) const { NEWTON_ASSERT(0); /* dgEdge* face; dgMeshEffect* backMesh; dgMeshEffect* frontMesh; NEWTON_ASSERT (planeMesh->m_isFlagFace); face = &planeMesh->GetRoot()->GetInfo(); if (face->m_incidentFace < 0) { face = face->m_twin; } NEWTON_ASSERT (face->m_incidentFace > 0); dgVector normal (planeMesh->FaceNormal (face, &planeMesh->m_points[0][0], sizeof (dgVector))); normal = normal.Scale (dgRsqrt (normal % normal)); const dgVector& point = planeMesh->m_points[face->m_incidentVertex]; dgPlane plane (normal, -(point % normal)); dgMeshEffect tmp (*this); tmp.PlaneClipMesh (plane, left, right); // NEWTON_ASSERT (tmp.CheckSingleMesh()); backMesh = *left; frontMesh = *right; if (backMesh && frontMesh) { NEWTON_ASSERT (backMesh->GetCount()); NEWTON_ASSERT (frontMesh->GetCount()); if (!(backMesh->PlaneApplyCap (planeMesh, plane) && frontMesh->PlaneApplyCap (planeMesh, plane.Scale (dgFloat32 (-1.0f))))) { backMesh->Release(); frontMesh->Release(); *left = NULL; *right = NULL; } else { backMesh->Triangulate (); frontMesh->Triangulate (); // NEWTON_ASSERT (frontMesh->CheckSingleMesh()); // NEWTON_ASSERT (backMesh->CheckSingleMesh()); } } */ } void dgMeshEffect::PlaneClipMesh(const dgMatrix &planeMatrix, const dgMatrix &planeTextMatrix, dgInt32 planeMaterial, dgMeshEffect **const left, dgMeshEffect **const right) const { *left = NULL; *right = NULL; dgTree leftFilter(GetAllocator()); dgTree rightFilter(GetAllocator()); dgStack vertexSidePool(GetCount() * 2 + 256); dgInt8 *const vertexSide = &vertexSidePool[0]; dgBigPlane plane(planeMatrix.m_front, -(planeMatrix.m_front % planeMatrix.m_posit)); plane = plane.Scale(dgFloat64(1.0) / sqrt(plane % plane)); dgMeshEffect mesh(*this); dgInt32 backCount = 0; dgInt32 frontCount = 0; dgPolyhedra::Iterator iter(mesh); dgInt32 mark = mesh.IncLRU(); for (iter.Begin(); iter; iter++) { dgEdge *const vertex = &(*iter); if (vertex->m_mark != mark) { dgEdge *ptr = vertex; do { ptr->m_mark = mark; ptr = ptr->m_twin->m_next; } while (ptr != vertex); dgFloat64 test = plane.Evalue(mesh.m_points[vertex->m_incidentVertex]); if (test >= dgFloat32(1.0e-3f)) { frontCount++; vertexSide[vertex->m_incidentVertex] = 1; } else if (test <= dgFloat32(-1.0e-3f)) { backCount++; vertexSide[vertex->m_incidentVertex] = -2; } else { vertexSide[vertex->m_incidentVertex] = 0; } mesh.m_points[vertex->m_incidentVertex].m_w = test; } } if ((frontCount == 0) || (backCount == 0)) { return; } mark = mesh.IncLRU(); for (iter.Begin(); iter;) { dgEdge *const edge = &(*iter); iter++; if (&(*iter) == edge->m_twin) { iter++; } if (edge->m_mark != mark) { edge->m_mark = mark; edge->m_twin->m_mark = mark; if (vertexSide[edge->m_incidentVertex] * vertexSide[edge->m_twin->m_incidentVertex] < 0) { dgFloat64 test0 = mesh.m_points[edge->m_incidentVertex].m_w; dgBigVector dp( mesh.m_points[edge->m_twin->m_incidentVertex] - mesh.m_points[edge->m_incidentVertex]); dgFloat64 param = -test0 / (plane % dp); dgEdge *const ptr = mesh.InsertEdgeVertex(edge, param); ptr->m_mark = mark; ptr->m_next->m_mark = mark; ptr->m_twin->m_mark = mark; ptr->m_twin->m_prev->m_mark = mark; vertexSide[mesh.m_pointCount - 1] = 0; } } } mark = mesh.IncLRU(); for (iter.Begin(); iter; iter++) { dgEdge *const face = &(*iter); if ((face->m_incidentFace > 0) && (face->m_mark != mark) && (vertexSide[face->m_incidentVertex] == 0) && (vertexSide[face->m_next->m_incidentVertex] < 0)) { dgEdge *ptr = face; do { ptr->m_mark = mark; ptr = ptr->m_next; } while (ptr != face); dgInt32 side = 0; ptr = face->m_next; do { side |= vertexSide[ptr->m_incidentVertex]; if (vertexSide[ptr->m_incidentVertex] == 0) { NEWTON_ASSERT(side != -1); NEWTON_ASSERT(side <= 0); if (side < 0) { if (ptr->m_next != face) { dgEdge *const back = mesh.AddHalfEdge(ptr->m_incidentVertex, face->m_incidentVertex); dgEdge *const front = mesh.AddHalfEdge(face->m_incidentVertex, ptr->m_incidentVertex); NEWTON_ASSERT(back); NEWTON_ASSERT(front); back->m_mark = mark; front->m_mark = mark; back->m_incidentFace = face->m_incidentFace; front->m_incidentFace = face->m_incidentFace; back->m_userData = ptr->m_userData; front->m_userData = face->m_userData; back->m_twin = front; front->m_twin = back; back->m_next = face; front->m_next = ptr; back->m_prev = ptr->m_prev; front->m_prev = face->m_prev; ptr->m_prev->m_next = back; ptr->m_prev = front; face->m_prev->m_next = front; face->m_prev = back; } else { // dgEdge* const back = ptr; NEWTON_ASSERT(ptr); dgEdge *const front = ptr->m_twin; NEWTON_ASSERT(front); dgEdge *ptr1 = front; do { ptr1->m_mark = mark; ptr1 = ptr1->m_next; } while (ptr1 != front); } } break; } ptr = ptr->m_next; } while (ptr != face); } } dgMeshEffect *backMesh = new (GetAllocator()) dgMeshEffect(GetAllocator(), true); dgMeshEffect *frontMesh = new (GetAllocator()) dgMeshEffect(GetAllocator(), true); mark = mesh.IncLRU(); backMesh->BeginPolygon(); frontMesh->BeginPolygon(); for (iter.Begin(); iter; iter++) { dgEdge *const face = &(*iter); if ((face->m_incidentFace > 0) && (face->m_mark != mark) && (vertexSide[face->m_incidentVertex] != 0)) { dgVertexAtribute att[128]; dgInt32 count = 0; dgEdge *ptr = face; do { att[count] = mesh.m_attib[ptr->m_userData]; count++; ptr->m_mark = mark; ptr = ptr->m_next; } while (ptr != face); if (vertexSide[face->m_incidentVertex] > 0) { frontMesh->AddPolygon(count, &att[0].m_vertex.m_x, sizeof(dgVertexAtribute), dgFastInt(att[0].m_material)); } else { backMesh->AddPolygon(count, &att[0].m_vertex.m_x, sizeof(dgVertexAtribute), dgFastInt(att[0].m_material)); } } } backMesh->EndPolygon(dgFloat64(1.0e-5f)); frontMesh->EndPolygon(dgFloat64(1.0e-5f)); if (!(backMesh->GetCount() && frontMesh->GetCount())) { backMesh->Release(); frontMesh->Release(); frontMesh = NULL; backMesh = NULL; } if (backMesh && frontMesh) { NEWTON_ASSERT(backMesh->GetCount()); NEWTON_ASSERT(frontMesh->GetCount()); dgBigVector min; dgBigVector max; CalculateAABB(min, max); max -= min; dgFloat64 size = GetMax(max.m_x, max.m_y, max.m_z); dgMeshEffect planeMesh(GetAllocator(), planeMatrix, dgFloat32(size), dgFloat32(size), planeMaterial, planeTextMatrix, planeTextMatrix); if (!(backMesh->PlaneApplyCap(&planeMesh, plane) && frontMesh->PlaneApplyCap(&planeMesh, plane.Scale(dgFloat32(-1.0f))))) { backMesh->Release(); frontMesh->Release(); *left = NULL; *right = NULL; // } else { // backMesh->Triangulate (); // frontMesh->Triangulate (); } } *left = backMesh; *right = frontMesh; } bool dgMeshEffect::CheckSingleMesh() const { NEWTON_ASSERT(0); return false; /* bool ret; dgPolyhedra firstSegment(GetAllocator()); dgPolyhedra secundSegment(GetAllocator()); dgPolyhedra::Iterator iter (*this); for (iter.Begin(); iter; iter ++){ dgFloat32 err2; dgEdge* vertex; vertex = &(*iter); if (vertex->m_incidentFace >= 0) { dgVector p (m_attib[vertex->m_userData].m_vertex.m_x, m_attib[vertex->m_userData].m_vertex.m_y, m_attib[vertex->m_userData].m_vertex.m_z, dgFloat32 (0.0f)); dgVector err (m_points[vertex->m_incidentVertex] - p); err2 = err % err; NEWTON_ASSERT (err2 < dgFloat32 (1.0e-10f)); } } BeginConectedSurface(); GetConectedSurface (firstSegment); GetConectedSurface (secundSegment); EndConectedSurface(); ret = (firstSegment.GetCount() > 0) & (secundSegment.GetCount() == 0); return ret; */ } dgInt32 dgMeshEffect::PlaneApplyCap(const dgMeshEffect *planeMesh, const dgBigPlane &faceNormal) { dgEdge *plane = &planeMesh->GetRoot()->GetInfo(); if (plane->m_incidentFace < 0) { plane = plane->m_twin; } NEWTON_ASSERT(plane->m_incidentFace > 0); dgInt32 ret = 0; dgInt32 mark = IncLRU(); dgPolyhedra::Iterator iter(*this); for (iter.Begin(); iter;) { dgEdge *face = &(*iter); iter++; if ((face->m_incidentFace < 0) && (face->m_mark != mark)) { dgFloat64 maxDist = dgFloat32(0.0f); dgEdge *ptr = face; do { maxDist = GetMax(maxDist, fabs(faceNormal.Evalue(m_points[ptr->m_incidentVertex]))); ptr->m_mark = mark; ptr = ptr->m_next; } while (ptr != face); if (maxDist <= dgFloat32(1.5e-3f)) { bool haveColinear = true; ptr = face; while (haveColinear) { haveColinear = false; do { if (ptr->m_next->m_twin->m_next->m_twin != ptr) { dgBigVector e0( m_points[ptr->m_next->m_incidentVertex] - m_points[ptr->m_incidentVertex]); dgBigVector e1( m_points[ptr->m_next->m_next->m_incidentVertex] - m_points[ptr->m_next->m_incidentVertex]); dgFloat64 mag00 = e0 % e0; dgFloat64 mag11 = e1 % e1; dgFloat64 mag01 = e0 % e1; dgFloat64 epsilon = dgFloat64(1.0e-6f) * mag00 * mag11; dgFloat64 err = mag01 * mag01 - mag00 * mag11; if (fabs(err) < epsilon) { NEWTON_ASSERT(ptr->m_twin->m_incidentFace >= 0); dgBigVector normal0( FaceNormal(ptr->m_twin, &m_points[0].m_x, sizeof(dgBigVector))); mag00 = normal0 % normal0; dgEdge *ptr1 = ptr->m_twin->m_prev->m_twin; do { dgBigVector normal1( FaceNormal(ptr1->m_twin, &m_points[0].m_x, sizeof(dgBigVector))); mag11 = normal1 % normal1; mag01 = normal0 % normal1; epsilon = dgFloat64(1.0e-6f) * mag00 * mag11; err = mag01 * mag01 - mag00 * mag11; if (fabs(err) < epsilon) { if (iter && ((&(*iter) == ptr1) || (&(*iter) == ptr1->m_twin))) { iter--; } if (iter && ((&(*iter) == ptr1) || (&(*iter) == ptr1->m_twin))) { iter--; } haveColinear = true; DeleteEdge(ptr1); ptr1 = ptr->m_twin; } ptr1 = ptr1->m_prev->m_twin; } while (ptr1 != ptr->m_next); if (ptr->m_next->m_twin->m_next->m_twin == ptr) { if (iter && ((&(*iter) == ptr->m_next) || (&(*iter) == ptr->m_next->m_twin))) { iter--; if (iter && ((&(*iter) == ptr->m_next) || (&(*iter) == ptr->m_next->m_twin))) { iter--; } } if (ptr->m_next == face) { face = face->m_prev; } ptr->m_twin->m_userData = ptr->m_next->m_twin->m_userData; ptr->m_twin->m_incidentVertex = ptr->m_next->m_twin->m_incidentVertex; dgEdge *const next = ptr->m_next; ptr->m_next->m_next->m_prev = ptr; ptr->m_next = ptr->m_next->m_next; ptr->m_twin->m_prev->m_prev->m_next = ptr->m_twin; ptr->m_twin->m_prev = ptr->m_twin->m_prev->m_prev; next->m_next = next->m_twin; next->m_prev = next->m_twin; next->m_twin->m_next = next; next->m_twin->m_prev = next; DeleteEdge(next); dgTreeNode *node = GetNodeFromInfo(*ptr); dgPairKey key0(ptr->m_incidentVertex, ptr->m_twin->m_incidentVertex); if (Find(key0.GetVal())) { return 0; } node = ReplaceKey(node, key0.GetVal()); node = GetNodeFromInfo(*ptr->m_twin); dgPairKey key1(ptr->m_twin->m_incidentVertex, ptr->m_incidentVertex); if (Find(key1.GetVal())) { return 0; } node = ReplaceKey(node, key1.GetVal()); } } } ptr = ptr->m_next; } while (ptr != face); } ptr = face; do { dgVertexAtribute attrib( planeMesh->InterpolateVertex(m_points[ptr->m_incidentVertex], plane)); attrib.m_normal_x = faceNormal.m_x; attrib.m_normal_y = faceNormal.m_y; attrib.m_normal_z = faceNormal.m_z; AddAtribute(attrib); ptr->m_userData = m_atribCount - 1; ptr->m_incidentFace = 1; ptr = ptr->m_next; } while (ptr != face); // dgVector normal; // TriangulateFace (face, &m_points[0].m_x, sizeof (dgVector), normal); ret = 1; } } } return ret; } bool dgMeshEffect::HasOpenEdges() const { dgPolyhedra::Iterator iter(*this); for (iter.Begin(); iter; iter++) { dgEdge *const face = &(*iter); if (face->m_incidentFace < 0) { return true; } } return false; } dgFloat64 dgMeshEffect::CalculateVolume() const { NEWTON_ASSERT(0); return 0; /* dgPolyhedraMassProperties localData; dgInt32 mark = IncLRU(); dgPolyhedra::Iterator iter (*this); for (iter.Begin(); iter; iter ++){ dgInt32 count; dgEdge* ptr; dgEdge* face; dgVector points[256]; face = &(*iter); if ((face->m_incidentFace > 0) && (face->m_mark != mark)) { count = 0; ptr = face; do { points[count] = m_points[ptr->m_incidentVertex]; count ++; ptr->m_mark = mark; ptr = ptr->m_next; } while (ptr != face); localData.AddCGFace (count, points); } } dgFloat32 volume; dgVector p0; dgVector p1; dgVector com; dgVector inertia; dgVector crossInertia; volume = localData.MassProperties (com, inertia, crossInertia); return volume; */ } bool dgMeshEffect::SeparateDuplicateLoops(dgEdge *const face) { for (dgEdge *ptr0 = face; ptr0 != face->m_prev; ptr0 = ptr0->m_next) { dgInt32 index = ptr0->m_incidentVertex; dgEdge *ptr1 = ptr0->m_next; do { if (ptr1->m_incidentVertex == index) { dgEdge *const ptr00 = ptr0->m_prev; dgEdge *const ptr11 = ptr1->m_prev; ptr00->m_next = ptr1; ptr1->m_prev = ptr00; ptr11->m_next = ptr0; ptr0->m_prev = ptr11; return true; } ptr1 = ptr1->m_next; } while (ptr1 != face); } return false; } dgMeshEffect *dgMeshEffect::GetNextLayer(dgInt32 mark) const { Iterator iter(*this); dgEdge *edge = NULL; for (iter.Begin(); iter; iter++) { edge = &(*iter); if ((edge->m_mark < mark) && (edge->m_incidentFace > 0)) { break; } } if (!edge) { return NULL; } dgInt32 layer = dgInt32(m_points[edge->m_incidentVertex].m_w); dgPolyhedra polyhedra(GetAllocator()); polyhedra.BeginFace(); for (iter.Begin(); iter; iter++) { dgEdge *const edgeI = &(*iter); if ((edgeI->m_mark < mark) && (edgeI->m_incidentFace > 0)) { dgInt32 thislayer = dgInt32(m_points[edgeI->m_incidentVertex].m_w); if (thislayer == layer) { dgEdge *ptr = edgeI; dgInt32 count = 0; dgInt32 faceIndex[256]; dgInt64 faceDataIndex[256]; do { ptr->m_mark = mark; faceIndex[count] = ptr->m_incidentVertex; faceDataIndex[count] = ptr->m_userData; count++; NEWTON_ASSERT(count < dgInt32(sizeof(faceIndex) / sizeof(faceIndex[0]))); ptr = ptr->m_next; } while (ptr != edgeI); polyhedra.AddFace(count, &faceIndex[0], &faceDataIndex[0]); } } } polyhedra.EndFace(); dgMeshEffect *solid = NULL; if (polyhedra.GetCount()) { solid = new (GetAllocator()) dgMeshEffect(polyhedra, *this); solid->SetLRU(mark); } return solid; } void dgMeshEffect::ClipMesh(const dgMeshEffectSolidTree *const clipper, dgMeshEffect **const left, dgMeshEffect **const right, dgMeshEffect **const coplanar) const { dgMeshEffect mesh(dgMeshEffect(*this)); mesh.Triangulate(); dgMeshEffect *const backMesh = new (GetAllocator()) dgMeshEffect( GetAllocator(), true); dgMeshEffect *const frontMesh = new (GetAllocator()) dgMeshEffect( GetAllocator(), true); dgMeshEffect *const meshCoplanar = new (GetAllocator()) dgMeshEffect( GetAllocator(), true); backMesh->BeginPolygon(); frontMesh->BeginPolygon(); meshCoplanar->BeginPolygon(); dgInt32 mark = mesh.IncLRU(); dgPolyhedra::Iterator iter(mesh); for (iter.Begin(); iter; iter++) { dgEdge *const face = &(*iter); if ((face->m_incidentFace > 0) && (face->m_mark != mark)) { dgEdge *ptr = face; do { ptr->m_mark = mark; ptr = ptr->m_next; } while (ptr != face); dgList faceList(GetAllocator()); dgMeshTreeCSGFace *faceOnStack[DG_MESH_EFFECT_BOLLEAN_STACK]; const dgMeshEffectSolidTree *stackPool[DG_MESH_EFFECT_BOLLEAN_STACK]; dgInt32 stack = 1; dgMeshTreeCSGFace *const originalFace = new (GetAllocator()) dgMeshTreeCSGFace(mesh, face); faceOnStack[0] = originalFace; stackPool[0] = clipper; dgInt32 backCount = 0; dgInt32 frontCount = 0; bool hasCoplanar = false; originalFace->AddRef(); // xxx ++; // dgMatrix xxxx (originalFace->DebugMatrix()); // if (xxx == 1582) { // originalFace->Trace(xxxx); // } while (stack) { stack--; dgMeshTreeCSGFace *const treeFace = faceOnStack[stack]; const dgMeshEffectSolidTree *const root = stackPool[stack]; NEWTON_ASSERT(root->m_planeType == dgMeshEffectSolidTree::m_divider); dgMeshTreeCSGFace *backFace; dgMeshTreeCSGFace *frontFace; treeFace->Clip(root->m_plane, &backFace, &frontFace); treeFace->Release(); if (!(frontFace || backFace)) { NEWTON_ASSERT(0); /* hasCoplanar = true; if (!((root->m_front->m_planeType == dgMeshEffectSolidTree::m_divider) || (root->m_back->m_planeType == dgMeshEffectSolidTree::m_divider))) { NEWTON_ASSERT (face->DetermineSide(clipper) != 0); faceList.Append(face); } else { //NEWTON_ASSERT (!(root->m_front && root->m_back)); if (root->m_front->m_planeType == dgMeshEffectSolidTree::m_divider) { stackPool[stack] = root->m_front; faceOnStack[stack] = face; stack ++; NEWTON_ASSERT (stack < sizeof (stackPool) / sizeof (stackPool[0])); } else { //if (root->m_back) { NEWTON_ASSERT (root->m_back->m_planeType == dgMeshEffectSolidTree::m_divider); stackPool[stack] = root->m_back; faceOnStack[stack] = face; stack ++; NEWTON_ASSERT (stack < sizeof (stackPool) / sizeof (stackPool[0])); } } */ } else { if (frontFace) { if (root->m_front->m_planeType == dgMeshEffectSolidTree::m_divider) { stackPool[stack] = root->m_front; faceOnStack[stack] = frontFace; stack++; NEWTON_ASSERT(stack < dgInt32(sizeof(stackPool) / sizeof(stackPool[0]))); } else { // if (xxx == 485){ // frontFace->Trace(xxxx); // } frontCount++; frontFace->m_side = dgMeshEffectSolidTree::m_empty; NEWTON_ASSERT( clipper->GetFaceSide(frontFace) == dgMeshEffectSolidTree::m_empty); faceList.Append(frontFace); } } if (backFace) { if (root->m_back->m_planeType == dgMeshEffectSolidTree::m_divider) { stackPool[stack] = root->m_back; faceOnStack[stack] = backFace; stack++; NEWTON_ASSERT(stack < dgInt32(sizeof(stackPool) / sizeof(stackPool[0]))); } else { // if (xxx == 485){ // backFace->Trace(xxxx); // } backCount++; backFace->m_side = dgMeshEffectSolidTree::m_solid; NEWTON_ASSERT( clipper->GetFaceSide(backFace) == dgMeshEffectSolidTree::m_solid); faceList.Append(backFace); } } } } NEWTON_ASSERT(faceList.GetCount()); if (!hasCoplanar && ((backCount == 0) || (frontCount == 0))) { dgInt32 count = 0; dgMeshEffect::dgVertexAtribute facePoints[256]; for (dgMeshTreeCSGFace::dgListNode *node = originalFace->GetFirst(); node; node = node->GetNext()) { // facePoints[count] = node->GetInfo().GetPoint(); dgBigVector p(node->GetInfo().m_x.GetAproximateValue(), node->GetInfo().m_y.GetAproximateValue(), node->GetInfo().m_z.GetAproximateValue(), dgFloat64(0.0)); facePoints[count] = mesh.InterpolateVertex(p, face); facePoints[count].m_vertex = p; count++; } if (frontCount) { #if 0 && defined(_DEBUG) // NEWTON_ASSERT is disabled so this whole calculation is useless for (dgList::dgListNode *node1 = faceList.GetFirst(); node1; node1 = node1->GetNext()) { dgMeshTreeCSGFace *const dface = node1->GetInfo(); NEWTON_ASSERT( clipper->GetFaceSide(dface) == dgMeshEffectSolidTree::m_empty); } #endif frontMesh->AddPolygon(count, &facePoints[0].m_vertex.m_x, sizeof(dgVertexAtribute), dgFastInt(facePoints[0].m_material)); } else { #if 0 && defined(_DEBUG) // NEWTON_ASSERT is disabled so this whole calculation is useless for (dgList::dgListNode *dnode1 = faceList.GetFirst(); dnode1; dnode1 = dnode1->GetNext()) { dgMeshTreeCSGFace *const dface = dnode1->GetInfo(); NEWTON_ASSERT( clipper->GetFaceSide(dface) == dgMeshEffectSolidTree::m_solid); } #endif backMesh->AddPolygon(count, &facePoints[0].m_vertex.m_x, sizeof(dgVertexAtribute), dgFastInt(facePoints[0].m_material)); } } else { for (dgList::dgListNode *node = faceList.GetFirst(); node->GetNext(); node = node->GetNext()) { dgMeshTreeCSGFace *const face0 = node->GetInfo(); for (dgList::dgListNode *node1 = node->GetNext(); node1; node1 = node1->GetNext()) { dgMeshTreeCSGFace *const face1 = node1->GetInfo(); face0->MergeMissingVertex(face1); face1->MergeMissingVertex(face0); } } for (dgList::dgListNode *node1 = faceList.GetFirst(); node1; node1 = node1->GetNext()) { dgMeshTreeCSGFace *const treFace = node1->GetInfo(); // xxx1 ++; // if (xxx1 == 24310) // face->Trace(xxxx); dgInt32 count = 0; dgVertexAtribute facePoints[256]; for (dgMeshTreeCSGFace::dgListNode *node = treFace->GetFirst(); node; node = node->GetNext()) { dgBigVector p(node->GetInfo().m_x.GetAproximateValue(), node->GetInfo().m_y.GetAproximateValue(), node->GetInfo().m_z.GetAproximateValue(), dgFloat64(0.0)); facePoints[count] = mesh.InterpolateVertex(p, face); facePoints[count].m_vertex = p; count++; } switch (treFace->m_side) { case dgMeshEffectSolidTree::m_divider: { NEWTON_ASSERT(0); meshCoplanar->AddPolygon(count, &facePoints[0].m_vertex.m_x, sizeof(dgVertexAtribute), dgFastInt(facePoints[0].m_material)); break; } case dgMeshEffectSolidTree::m_solid: { backMesh->AddPolygon(count, &facePoints[0].m_vertex.m_x, sizeof(dgVertexAtribute), dgFastInt(facePoints[0].m_material)); break; } case dgMeshEffectSolidTree::m_empty: { frontMesh->AddPolygon(count, &facePoints[0].m_vertex.m_x, sizeof(dgVertexAtribute), dgFastInt(facePoints[0].m_material)); break; } } } } originalFace->Release(); for (dgList::dgListNode *node = faceList.GetFirst(); node; node = node->GetNext()) { dgMeshTreeCSGFace *const faceT = node->GetInfo(); faceT->Release(); } } } backMesh->EndPolygon(dgFloat64(dgFloat64(1.0e-5f))); frontMesh->EndPolygon(dgFloat64(dgFloat64(1.0e-5f))); meshCoplanar->EndPolygon(dgFloat64(dgFloat64(1.0e-5f))); if (backMesh->GetCount() && frontMesh->GetCount()) { *left = backMesh; *right = frontMesh; } else if (frontMesh->GetCount()) { *left = NULL; *right = frontMesh; backMesh->Release(); } else if (backMesh->GetCount()) { *right = NULL; *left = backMesh; frontMesh->Release(); } else { NEWTON_ASSERT(0); *right = NULL; *left = NULL; backMesh->Release(); frontMesh->Release(); } *coplanar = NULL; if (meshCoplanar->GetCount()) { *coplanar = meshCoplanar; } else { meshCoplanar->Release(); } } void dgMeshEffect::RepairTJoints(bool triangulate) { dgInt32 mark = IncLRU(); dgPolyhedra::Iterator iter(*this); #ifdef _DEBUG for (iter.Begin(); iter; iter++) { dgEdge *const face = &(*iter); if ((face->m_incidentFace < 0) && (face->m_mark != mark)) { for (dgEdge *ptr = face; ptr != face->m_prev; ptr = ptr->m_next) { dgBigVector p0(m_points[ptr->m_incidentVertex]); for (dgEdge *ptr1 = ptr->m_next; ptr1 != face; ptr1 = ptr1->m_next) { if (ptr->m_incidentVertex != ptr1->m_incidentVertex) { dgBigVector p1(m_points[ptr1->m_incidentVertex]); dgBigVector dp(p1 - p0); dgFloat64 err2(dp % dp); if (err2 < dgFloat64(1.0e-16f)) { // NEWTON_ASSERT (0); } } } } } } mark = IncLRU(); #endif for (iter.Begin(); iter;) { dgEdge *const face = &(*iter); iter++; if ((face->m_incidentFace < 0) && (face->m_mark != mark)) { // vertices project while (SeparateDuplicateLoops(face)) ; dgBigVector dir(dgFloat64(0.0f), dgFloat64(0.0f), dgFloat64(0.0f), dgFloat64(0.0f)); dgFloat64 lengh2 = dgFloat64(0.0f); dgEdge *ptr = face; do { dgBigVector dir1( m_points[ptr->m_next->m_incidentVertex] - m_points[ptr->m_incidentVertex]); dgFloat64 val = dir1 % dir1; if (val > lengh2) { lengh2 = val; dir = dir1; } ptr = ptr->m_next; } while (ptr != face); NEWTON_ASSERT(lengh2 > dgFloat32(0.0f)); dgEdge *lastEdge = NULL; dgEdge *firstEdge = NULL; dgFloat64 minVal = dgFloat64(-1.0e10f); dgFloat64 maxVal = dgFloat64(-1.0e10f); ptr = face; do { const dgBigVector &p = m_points[ptr->m_incidentVertex]; dgFloat64 val = p % dir; if (val > maxVal) { maxVal = val; lastEdge = ptr; } val *= dgFloat64(-1.0f); if (val > minVal) { minVal = val; firstEdge = ptr; } ptr->m_mark = mark; ptr = ptr->m_next; } while (ptr != face); NEWTON_ASSERT(firstEdge); NEWTON_ASSERT(lastEdge); bool isTJoint = true; dgBigVector point0(m_points[firstEdge->m_incidentVertex]); dgBigVector point1(m_points[lastEdge->m_incidentVertex]); dgBigVector pnt1pnt0(point1 - point0); dgFloat64 den = pnt1pnt0 % pnt1pnt0; ptr = firstEdge->m_next; do { dgBigVector point2(m_points[ptr->m_incidentVertex]); dgFloat64 num = (point2 - point0) % pnt1pnt0; dgBigVector q(point0 + pnt1pnt0.Scale(num / den)); dgBigVector dist(point2 - q); dgFloat64 err2 = dist % dist; isTJoint &= (err2 < (dgFloat64(1.0e-4f) * dgFloat64(1.0e-4f))); ptr = ptr->m_next; } while (isTJoint && (ptr != firstEdge)); if (isTJoint) { do { dgEdge *next = NULL; const dgBigVector p0 = m_points[firstEdge->m_incidentVertex]; const dgBigVector p1 = m_points[firstEdge->m_next->m_incidentVertex]; const dgBigVector p2 = m_points[firstEdge->m_prev->m_incidentVertex]; dgBigVector p1p0(p1 - p0); dgBigVector p2p0(p2 - p0); dgFloat64 dist10 = p1p0 % p1p0; dgFloat64 dist20 = p2p0 % p2p0; dgEdge *begin = NULL; dgEdge *last = NULL; if (dist20 > dist10) { dgFloat64 t = (p1p0 % p2p0) / dist20; NEWTON_ASSERT(t > dgFloat32(0.0f)); NEWTON_ASSERT(t < dgFloat32(1.0f)); if (firstEdge->m_next->m_next->m_next != firstEdge) { ConectVertex(firstEdge->m_prev, firstEdge->m_next); next = firstEdge->m_next->m_twin->m_next; } NEWTON_ASSERT(firstEdge->m_next->m_next->m_next == firstEdge); #if 0 && defined(_DEBUG) // NEWTON_ASSERT is disabled so this whole calculation is useless dgEdge *tmp = firstEdge->m_twin; do { NEWTON_ASSERT(tmp->m_incidentFace > 0); tmp = tmp->m_next; } while (tmp != firstEdge->m_twin); #endif begin = firstEdge->m_next; last = firstEdge; firstEdge->m_userData = firstEdge->m_prev->m_twin->m_userData; firstEdge->m_incidentFace = firstEdge->m_prev->m_twin->m_incidentFace; dgVertexAtribute attrib( InterpolateEdge(firstEdge->m_prev->m_twin, t)); attrib.m_vertex = m_points[firstEdge->m_next->m_incidentVertex]; AddAtribute(attrib); firstEdge->m_next->m_incidentFace = firstEdge->m_prev->m_twin->m_incidentFace; firstEdge->m_next->m_userData = dgUnsigned64(m_atribCount - 1); bool restart = false; if ((firstEdge->m_prev == &(*iter)) || (firstEdge->m_prev->m_twin == &(*iter))) { restart = true; } DeleteEdge(firstEdge->m_prev); if (restart) { iter.Begin(); } } else { NEWTON_ASSERT(dist20 < dist10); dgFloat64 t = (p1p0 % p2p0) / dist10; NEWTON_ASSERT(t > dgFloat32(0.0f)); NEWTON_ASSERT(t < dgFloat32(1.0f)); if (firstEdge->m_next->m_next->m_next != firstEdge) { ConectVertex(firstEdge->m_next, firstEdge->m_prev); next = firstEdge->m_next->m_twin; } NEWTON_ASSERT(firstEdge->m_next->m_next->m_next == firstEdge); #if 0 && defined(_DEBUG) // NEWTON_ASSERT is disabled so this whole calculation is useless dgEdge *tmp = firstEdge->m_twin; do { NEWTON_ASSERT(tmp->m_incidentFace > 0); tmp = tmp->m_next; } while (tmp != firstEdge->m_twin); #endif begin = firstEdge->m_prev; last = firstEdge->m_next; firstEdge->m_next->m_userData = firstEdge->m_twin->m_userData; firstEdge->m_next->m_incidentFace = firstEdge->m_twin->m_incidentFace; dgVertexAtribute attrib( InterpolateEdge(firstEdge->m_twin, dgFloat64(1.0f) - t)); attrib.m_vertex = m_points[firstEdge->m_prev->m_incidentVertex]; AddAtribute(attrib); firstEdge->m_prev->m_incidentFace = firstEdge->m_twin->m_incidentFace; firstEdge->m_prev->m_userData = dgUnsigned64(m_atribCount - 1); bool restart = false; if ((firstEdge == &(*iter)) || (firstEdge->m_twin == &(*iter))) { restart = true; } DeleteEdge(firstEdge); if (restart) { iter.Begin(); } } if (triangulate) { NEWTON_ASSERT(begin); NEWTON_ASSERT(last); for (dgEdge *ptrI = begin->m_next->m_next; ptrI != last; ptrI = ptrI->m_next) { dgEdge *const e = AddHalfEdge(begin->m_incidentVertex, ptrI->m_incidentVertex); dgEdge *const t = AddHalfEdge(ptrI->m_incidentVertex, begin->m_incidentVertex); if (e && t) { NEWTON_ASSERT(e); NEWTON_ASSERT(t); e->m_twin = t; t->m_twin = e; e->m_incidentFace = ptrI->m_incidentFace; t->m_incidentFace = ptrI->m_incidentFace; e->m_userData = last->m_next->m_userData; t->m_userData = ptrI->m_userData; t->m_prev = ptrI->m_prev; ptrI->m_prev->m_next = t; e->m_next = ptrI; ptrI->m_prev = e; t->m_next = last->m_next; e->m_prev = last; last->m_next->m_prev = t; last->m_next = e; } } } firstEdge = next; } while (firstEdge); } } } DeleteDegenerateFaces(&m_points[0].m_x, sizeof(m_points[0]), dgFloat64(1.0e-7f)); }