1091 lines
31 KiB
C++
1091 lines
31 KiB
C++
/* Copyright (c) <2003-2019> <Julio Jerez, Newton Game Dynamics>
|
|
*
|
|
* This software is provided 'as-is', without any express or implied
|
|
* warranty. In no event will the authors be held liable for any damages
|
|
* arising from the use of this software.
|
|
*
|
|
* Permission is granted to anyone to use this software for any purpose,
|
|
* including commercial applications, and to alter it and redistribute it
|
|
* freely, subject to the following restrictions:
|
|
*
|
|
* 1. The origin of this software must not be misrepresented; you must not
|
|
* claim that you wrote the original software. If you use this software
|
|
* in a product, an acknowledgment in the product documentation would be
|
|
* appreciated but is not required.
|
|
*
|
|
* 2. Altered source versions must be plainly marked as such, and must not be
|
|
* misrepresented as being the original software.
|
|
*
|
|
* 3. This notice may not be removed or altered from any source distribution.
|
|
*/
|
|
|
|
/****************************************************************************
|
|
*
|
|
* Visual C++ 6.0 created by: Julio Jerez
|
|
*
|
|
****************************************************************************/
|
|
#include "dgStdafx.h"
|
|
#include "dgStack.h"
|
|
#include "dgMatrix.h"
|
|
#include "dgMemory.h"
|
|
#include "dgPolyhedra.h"
|
|
#include "dgPolygonSoupBuilder.h"
|
|
|
|
#define DG_POINTS_RUN (512 * 1024)
|
|
|
|
|
|
|
|
class dgPolygonSoupDatabaseBuilder::dgFaceInfo
|
|
{
|
|
public:
|
|
dgInt32 indexCount;
|
|
dgInt32 indexStart;
|
|
};
|
|
|
|
class dgPolygonSoupDatabaseBuilder::dgFaceBucket: public dgList<dgFaceInfo>
|
|
{
|
|
public:
|
|
dgFaceBucket (dgMemoryAllocator* const allocator)
|
|
:dgList<dgFaceInfo>(allocator)
|
|
{
|
|
}
|
|
};
|
|
|
|
class dgPolygonSoupDatabaseBuilder::dgFaceMap: public dgTree<dgFaceBucket, dgInt32>
|
|
{
|
|
public:
|
|
dgFaceMap (dgMemoryAllocator* const allocator, dgPolygonSoupDatabaseBuilder& builder)
|
|
:dgTree<dgFaceBucket, dgInt32>(allocator)
|
|
{
|
|
dgInt32 polygonIndex = 0;
|
|
dgInt32 faceCount = builder.m_faceCount;
|
|
const dgInt32* const faceVertexCounts = &builder.m_faceVertexCount[0];
|
|
const dgInt32* const faceVertexIndex = &builder.m_vertexIndex[0];
|
|
for (dgInt32 i = 0; i < faceCount; i ++) {
|
|
dgInt32 count = faceVertexCounts[i];
|
|
dgInt32 attribute = faceVertexIndex[polygonIndex + count - 1];
|
|
|
|
dgTreeNode* node = Find(attribute);
|
|
if (!node) {
|
|
dgFaceBucket tmp (GetAllocator());
|
|
node = Insert(tmp, attribute);
|
|
}
|
|
|
|
dgFaceBucket& bucket = node->GetInfo();
|
|
dgFaceInfo& face = bucket.Append()->GetInfo();
|
|
face.indexCount = count;
|
|
face.indexStart = polygonIndex;
|
|
polygonIndex += count;
|
|
}
|
|
}
|
|
};
|
|
|
|
class dgPolygonSoupDatabaseBuilder::dgPolySoupFilterAllocator: public dgPolyhedra
|
|
{
|
|
public:
|
|
dgPolySoupFilterAllocator (dgMemoryAllocator* const allocator)
|
|
:dgPolyhedra (allocator)
|
|
{
|
|
}
|
|
|
|
~dgPolySoupFilterAllocator ()
|
|
{
|
|
}
|
|
|
|
dgInt32 AddFilterFace (dgUnsigned32 count, dgInt32* const pool)
|
|
{
|
|
BeginFace();
|
|
dgAssert (count);
|
|
bool reduction = true;
|
|
while (reduction && !AddFace (dgInt32 (count), pool)) {
|
|
reduction = false;
|
|
if (count >3) {
|
|
for (dgUnsigned32 i = 0; i < count; i ++) {
|
|
for (dgUnsigned32 j = i + 1; j < count; j ++) {
|
|
if (pool[j] == pool[i]) {
|
|
for (i = j; i < count - 1; i ++) {
|
|
pool[i] = pool[i + 1];
|
|
}
|
|
count --;
|
|
i = count;
|
|
reduction = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
EndFace();
|
|
return reduction ? dgInt32 (count) : 0;
|
|
}
|
|
};
|
|
|
|
|
|
dgPolygonSoupDatabaseBuilder::dgPolygonSoupDatabaseBuilder (dgMemoryAllocator* const allocator)
|
|
:m_faceVertexCount(allocator)
|
|
,m_vertexIndex(allocator)
|
|
,m_normalIndex(allocator)
|
|
,m_vertexPoints(allocator)
|
|
,m_normalPoints(allocator)
|
|
{
|
|
m_run = DG_POINTS_RUN;
|
|
m_faceCount = 0;
|
|
m_indexCount = 0;
|
|
m_vertexCount = 0;
|
|
m_normalCount = 0;
|
|
m_allocator = allocator;
|
|
}
|
|
|
|
dgPolygonSoupDatabaseBuilder::dgPolygonSoupDatabaseBuilder (const dgPolygonSoupDatabaseBuilder& source)
|
|
:m_faceVertexCount(source.m_allocator)
|
|
,m_vertexIndex(source.m_allocator)
|
|
,m_normalIndex(source.m_allocator)
|
|
,m_vertexPoints(source.m_allocator)
|
|
,m_normalPoints(source.m_allocator)
|
|
{
|
|
m_run = DG_POINTS_RUN;
|
|
m_faceCount = source.m_faceCount;
|
|
m_indexCount = source.m_indexCount;
|
|
m_vertexCount = source.m_vertexCount;
|
|
m_normalCount = source.m_normalCount;
|
|
m_allocator = source.m_allocator;
|
|
|
|
m_vertexIndex[m_indexCount-1] = 0;
|
|
m_faceVertexCount[m_faceCount-1] = 0;
|
|
m_vertexPoints[m_vertexCount-1].m_w = 0;
|
|
|
|
memcpy (&m_vertexIndex[0], &source.m_vertexIndex[0], sizeof (dgInt32) * m_indexCount);
|
|
memcpy (&m_faceVertexCount[0], &source.m_faceVertexCount[0], sizeof (dgInt32) * m_faceCount);
|
|
memcpy (&m_vertexPoints[0], &source.m_vertexPoints[0], sizeof (dgBigVector) * m_vertexCount);
|
|
|
|
if (m_normalCount) {
|
|
m_normalIndex[m_faceCount-1] = 0;
|
|
m_normalPoints[m_normalCount - 1].m_w = 0;
|
|
|
|
memcpy (&m_normalIndex[0], &source.m_normalIndex[0], sizeof (dgInt32) * m_faceCount);
|
|
memcpy (&m_normalPoints[0], &source.m_normalPoints[0], sizeof (dgBigVector) * m_normalCount);
|
|
} else {
|
|
m_normalIndex[0] = 0;
|
|
m_normalPoints[0].m_w = 0;
|
|
}
|
|
}
|
|
|
|
dgPolygonSoupDatabaseBuilder::~dgPolygonSoupDatabaseBuilder ()
|
|
{
|
|
}
|
|
|
|
void dgPolygonSoupDatabaseBuilder::Begin()
|
|
{
|
|
m_run = DG_POINTS_RUN;
|
|
m_faceCount = 0;
|
|
m_indexCount = 0;
|
|
m_vertexCount = 0;
|
|
m_normalCount = 0;
|
|
}
|
|
|
|
void dgPolygonSoupDatabaseBuilder::SavePLY(const char* const fileName) const
|
|
{
|
|
FILE* const file = fopen(fileName, "wb");
|
|
|
|
fprintf(file, "ply\n");
|
|
fprintf(file, "format ascii 1.0\n");
|
|
|
|
//dgInt32 faceCount = 0;
|
|
fprintf(file, "element vertex %d\n", m_vertexCount);
|
|
fprintf(file, "property float x\n");
|
|
fprintf(file, "property float y\n");
|
|
fprintf(file, "property float z\n");
|
|
fprintf(file, "element face %d\n", m_faceCount);
|
|
fprintf(file, "property list uchar int vertex_index\n");
|
|
fprintf(file, "end_header\n");
|
|
|
|
for (dgInt32 i = 0; i < m_vertexCount; i ++) {
|
|
const dgBigVector& point = m_vertexPoints[i];
|
|
fprintf(file, "%f %f %f\n", point.m_x, point.m_y, point.m_z);
|
|
}
|
|
|
|
dgInt32 index = 0;
|
|
for (dgInt32 i = 0; i < m_faceCount; i ++) {
|
|
dgInt32 count = m_faceVertexCount[i];
|
|
fprintf(file, "%d", count - 1);
|
|
for (dgInt32 j = 0; j < count - 1; j++) {
|
|
fprintf(file, " %d", m_vertexIndex[index + j]);
|
|
}
|
|
index += count;
|
|
fprintf(file, "\n");
|
|
}
|
|
fclose(file);
|
|
}
|
|
|
|
void dgPolygonSoupDatabaseBuilder::AddMesh (const dgFloat32* const vertex, dgInt32 vertexCount, dgInt32 strideInBytes, dgInt32 faceCount,
|
|
const dgInt32* const faceArray, const dgInt32* const indexArray, const dgInt32* const faceMaterialId, const dgMatrix& worldMatrix)
|
|
{
|
|
dgInt32 faces[256];
|
|
dgInt32 pool[2048];
|
|
|
|
m_vertexPoints[m_vertexCount + vertexCount].m_x = dgFloat64 (0.0f);
|
|
dgBigVector* const vertexPool = &m_vertexPoints[m_vertexCount];
|
|
|
|
worldMatrix.TransformTriplex (&vertexPool[0].m_x, sizeof (dgBigVector), vertex, strideInBytes, vertexCount);
|
|
for (dgInt32 i = 0; i < vertexCount; i ++) {
|
|
vertexPool[i].m_w = dgFloat64 (0.0f);
|
|
}
|
|
|
|
dgInt32 totalIndexCount = faceCount;
|
|
for (dgInt32 i = 0; i < faceCount; i ++) {
|
|
totalIndexCount += faceArray[i];
|
|
}
|
|
|
|
m_vertexIndex[m_indexCount + totalIndexCount] = 0;
|
|
m_faceVertexCount[m_faceCount + faceCount] = 0;
|
|
|
|
dgInt32 k = 0;
|
|
for (dgInt32 i = 0; i < faceCount; i ++) {
|
|
dgInt32 count = faceArray[i];
|
|
for (dgInt32 j = 0; j < count; j ++) {
|
|
dgInt32 index = indexArray[k];
|
|
pool[j] = index + m_vertexCount;
|
|
k ++;
|
|
}
|
|
|
|
dgInt32 convexFaces = 0;
|
|
if (count == 3) {
|
|
convexFaces = 1;
|
|
dgBigVector p0 (m_vertexPoints[pool[2]]);
|
|
p0 = p0 & dgBigVector::m_triplexMask;
|
|
for (dgInt32 j = 0; j < 3; j ++) {
|
|
dgBigVector p1 (m_vertexPoints[pool[j]]);
|
|
p1 = p1 & dgBigVector::m_triplexMask;
|
|
dgBigVector edge (p1 - p0);
|
|
dgFloat64 mag2 = edge.DotProduct(edge).GetScalar();
|
|
if (mag2 < dgFloat32 (1.0e-6f)) {
|
|
convexFaces = 0;
|
|
}
|
|
p0 = p1;
|
|
}
|
|
|
|
if (convexFaces) {
|
|
dgBigVector edge0 (m_vertexPoints[pool[2]] - m_vertexPoints[pool[0]]);
|
|
dgBigVector edge1 (m_vertexPoints[pool[1]] - m_vertexPoints[pool[0]]);
|
|
dgAssert (edge0.m_w == dgFloat32 (0.0f));
|
|
dgAssert (edge1.m_w == dgFloat32 (0.0f));
|
|
dgBigVector normal (edge0.CrossProduct(edge1));
|
|
dgFloat64 mag2 = normal.DotProduct(normal).GetScalar();
|
|
if (mag2 < dgFloat32 (1.0e-8f)) {
|
|
convexFaces = 0;
|
|
}
|
|
}
|
|
|
|
if (convexFaces) {
|
|
faces[0] = 3;
|
|
}
|
|
|
|
} else {
|
|
convexFaces = AddConvexFace (count, pool, faces);
|
|
}
|
|
|
|
dgInt32 indexAcc = 0;
|
|
for (dgInt32 j = 0; j < convexFaces; j ++) {
|
|
dgInt32 count1 = faces[j];
|
|
m_vertexIndex[m_indexCount + count1] = faceMaterialId[i];
|
|
for (dgInt32 m = 0; m < count1; m ++) {
|
|
m_vertexIndex[m_indexCount + m] = pool[indexAcc + m];
|
|
}
|
|
indexAcc += count1;
|
|
m_indexCount += (count1 + 1);
|
|
m_faceVertexCount[m_faceCount] = count1 + 1;
|
|
m_faceCount ++;
|
|
}
|
|
}
|
|
m_vertexCount += vertexCount;
|
|
m_run -= vertexCount;
|
|
if (m_run <= 0) {
|
|
PackArray();
|
|
}
|
|
}
|
|
|
|
void dgPolygonSoupDatabaseBuilder::PackArray()
|
|
{
|
|
dgStack<dgInt32> indexMapPool (m_vertexCount);
|
|
dgInt32* const indexMap = &indexMapPool[0];
|
|
m_vertexCount = dgVertexListToIndexList (&m_vertexPoints[0].m_x, sizeof (dgBigVector), 3, m_vertexCount, &indexMap[0], dgFloat32 (1.0e-6f));
|
|
|
|
dgInt32 k = 0;
|
|
for (dgInt32 i = 0; i < m_faceCount; i ++) {
|
|
dgInt32 count = m_faceVertexCount[i] - 1;
|
|
for (dgInt32 j = 0; j < count; j ++) {
|
|
dgInt32 index = m_vertexIndex[k];
|
|
index = indexMap[index];
|
|
m_vertexIndex[k] = index;
|
|
k ++;
|
|
}
|
|
k ++;
|
|
}
|
|
|
|
m_run = DG_POINTS_RUN;
|
|
}
|
|
|
|
void dgPolygonSoupDatabaseBuilder::Finalize()
|
|
{
|
|
if (m_faceCount) {
|
|
dgStack<dgInt32> indexMapPool (m_indexCount + m_vertexCount);
|
|
|
|
dgInt32* const indexMap = &indexMapPool[0];
|
|
m_vertexCount = dgVertexListToIndexList (&m_vertexPoints[0].m_x, sizeof (dgBigVector), 3, m_vertexCount, &indexMap[0], dgFloat32 (1.0e-4f));
|
|
|
|
dgInt32 k = 0;
|
|
for (dgInt32 i = 0; i < m_faceCount; i ++) {
|
|
dgInt32 count = m_faceVertexCount[i] - 1;
|
|
for (dgInt32 j = 0; j < count; j ++) {
|
|
dgInt32 index = m_vertexIndex[k];
|
|
index = indexMap[index];
|
|
m_vertexIndex[k] = index;
|
|
k ++;
|
|
}
|
|
k ++;
|
|
}
|
|
OptimizeByIndividualFaces();
|
|
}
|
|
}
|
|
|
|
void dgPolygonSoupDatabaseBuilder::FinalizeAndOptimize()
|
|
{
|
|
Finalize();
|
|
dgPolyhedra polyhedra(m_allocator);
|
|
dgPolygonSoupDatabaseBuilder source(*this);
|
|
dgPolygonSoupDatabaseBuilder leftOver(m_allocator);
|
|
dgInt32 tmpIndexPool[1024];
|
|
dgVector tmpVertexPool[1024];
|
|
|
|
Begin();
|
|
leftOver.Begin();
|
|
polyhedra.BeginFace ();
|
|
dgInt32 faceIndexNumber = 0;
|
|
dgInt32 attribute = m_vertexIndex[0];
|
|
|
|
for (dgInt32 i = 0; i < source.m_faceCount; i ++) {
|
|
dgInt32 indexCount = source.m_faceVertexCount[i];
|
|
dgAssert (indexCount < 1024);
|
|
|
|
dgEdge* const face = polyhedra.AddFace(indexCount - 1, &source.m_vertexIndex[faceIndexNumber]);
|
|
if (!face) {
|
|
for (dgInt32 j = 0; j < indexCount - 1; j ++) {
|
|
dgInt32 index = source.m_vertexIndex[faceIndexNumber + j];
|
|
tmpVertexPool[j] = source.m_vertexPoints[index];
|
|
tmpIndexPool[j] = j;
|
|
}
|
|
dgInt32 faceArray = indexCount - 1;
|
|
leftOver.AddMesh (&tmpVertexPool[0].m_x, indexCount, sizeof (tmpVertexPool[0]), 1, &faceArray, tmpIndexPool, &attribute, dgGetIdentityMatrix());
|
|
} else {
|
|
// set the attribute
|
|
dgEdge* ptr = face;
|
|
do {
|
|
ptr->m_userData = dgUnsigned64 (attribute);
|
|
ptr = ptr->m_next;
|
|
} while (ptr != face);
|
|
}
|
|
faceIndexNumber += indexCount;
|
|
}
|
|
polyhedra.EndFace();
|
|
|
|
dgPolyhedra facesLeft(m_allocator);
|
|
facesLeft.BeginFace();
|
|
polyhedra.ConvexPartition (&source.m_vertexPoints[0].m_x, source.m_vertexPoints.GetElementSize(), &facesLeft);
|
|
facesLeft.EndFace();
|
|
|
|
dgInt32 mark = polyhedra.IncLRU();
|
|
dgPolyhedra::Iterator iter (polyhedra);
|
|
for (iter.Begin(); iter; iter ++) {
|
|
dgEdge* const edge = &(*iter);
|
|
if (edge->m_incidentFace < 0) {
|
|
continue;
|
|
}
|
|
if (edge->m_mark == mark) {
|
|
continue;
|
|
}
|
|
|
|
dgEdge* ptr = edge;
|
|
dgInt32 indexCount = 0;
|
|
do {
|
|
ptr->m_mark = mark;
|
|
tmpVertexPool[indexCount] = source.m_vertexPoints[ptr->m_incidentVertex];
|
|
tmpIndexPool[indexCount] = indexCount;
|
|
indexCount ++;
|
|
ptr = ptr->m_next;
|
|
} while (ptr != edge);
|
|
|
|
if (indexCount >= 3) {
|
|
AddMesh (&tmpVertexPool[0].m_x, indexCount, sizeof (tmpVertexPool[0]), 1, &indexCount, tmpIndexPool, &attribute, dgGetIdentityMatrix());
|
|
}
|
|
}
|
|
|
|
|
|
mark = facesLeft.IncLRU();
|
|
dgPolyhedra::Iterator iter1 (facesLeft);
|
|
for (iter1.Begin(); iter1; iter1 ++) {
|
|
dgEdge* const edge = &(*iter1);
|
|
if (edge->m_incidentFace < 0) {
|
|
continue;
|
|
}
|
|
if (edge->m_mark == mark) {
|
|
continue;
|
|
}
|
|
|
|
dgEdge* ptr = edge;
|
|
dgInt32 indexCount = 0;
|
|
do {
|
|
ptr->m_mark = mark;
|
|
tmpVertexPool[indexCount] = source.m_vertexPoints[ptr->m_incidentVertex];
|
|
tmpIndexPool[indexCount] = indexCount;
|
|
indexCount ++;
|
|
ptr = ptr->m_next;
|
|
} while (ptr != edge);
|
|
if (indexCount >= 3) {
|
|
AddMesh (&tmpVertexPool[0].m_x, indexCount, sizeof (dgVector), 1, &indexCount, tmpIndexPool, &attribute, dgGetIdentityMatrix());
|
|
}
|
|
}
|
|
|
|
faceIndexNumber = 0;
|
|
for (dgInt32 i = 0; i < leftOver.m_faceCount; i ++) {
|
|
dgInt32 indexCount = leftOver.m_faceVertexCount[i] - 1;
|
|
for (dgInt32 j = 0; j < indexCount; j ++) {
|
|
dgInt32 index = leftOver.m_vertexIndex[faceIndexNumber + j];
|
|
tmpVertexPool[j] = leftOver.m_vertexPoints[index];
|
|
tmpIndexPool[j] = j;
|
|
}
|
|
dgInt32 faceArray = indexCount;
|
|
AddMesh (&tmpVertexPool[0].m_x, indexCount, sizeof (tmpVertexPool[0]), 1, &faceArray, tmpIndexPool, &attribute, dgGetIdentityMatrix());
|
|
|
|
faceIndexNumber += (indexCount + 1);
|
|
}
|
|
|
|
Finalize();
|
|
}
|
|
|
|
void dgPolygonSoupDatabaseBuilder::OptimizeByIndividualFaces()
|
|
{
|
|
dgInt32* const faceArray = &m_faceVertexCount[0];
|
|
dgInt32* const indexArray = &m_vertexIndex[0];
|
|
|
|
dgInt32* const oldFaceArray = &m_faceVertexCount[0];
|
|
dgInt32* const oldIndexArray = &m_vertexIndex[0];
|
|
|
|
dgInt32 polygonIndex = 0;
|
|
dgInt32 newFaceCount = 0;
|
|
dgInt32 newIndexCount = 0;
|
|
for (dgInt32 i = 0; i < m_faceCount; i ++) {
|
|
dgInt32 oldCount = oldFaceArray[i];
|
|
dgInt32 count = FilterFace (oldCount - 1, &oldIndexArray[polygonIndex]);
|
|
if (count) {
|
|
faceArray[newFaceCount] = count + 1;
|
|
for (dgInt32 j = 0; j < count; j ++) {
|
|
indexArray[newIndexCount + j] = oldIndexArray[polygonIndex + j];
|
|
}
|
|
indexArray[newIndexCount + count] = oldIndexArray[polygonIndex + oldCount - 1];
|
|
newFaceCount ++;
|
|
newIndexCount += (count + 1);
|
|
}
|
|
polygonIndex += oldCount;
|
|
}
|
|
dgAssert (polygonIndex == m_indexCount);
|
|
m_faceCount = newFaceCount;
|
|
m_indexCount = newIndexCount;
|
|
}
|
|
|
|
|
|
void dgPolygonSoupDatabaseBuilder::End(bool optimize)
|
|
{
|
|
if (optimize) {
|
|
dgPolygonSoupDatabaseBuilder copy (*this);
|
|
dgFaceMap faceMap (m_allocator, copy);
|
|
|
|
Begin();
|
|
dgFaceMap::Iterator iter (faceMap);
|
|
for (iter.Begin(); iter; iter ++) {
|
|
const dgFaceBucket& bucket = iter.GetNode()->GetInfo();
|
|
Optimize(iter.GetNode()->GetKey(), bucket, copy);
|
|
}
|
|
}
|
|
Finalize();
|
|
|
|
// build the normal array and adjacency array
|
|
// calculate all face the normals
|
|
dgInt32 indexCount = 0;
|
|
m_normalPoints[m_faceCount].m_x = dgFloat64 (0.0f);
|
|
for (dgInt32 i = 0; i < m_faceCount; i ++) {
|
|
dgInt32 faceIndexCount = m_faceVertexCount[i];
|
|
|
|
const dgInt32* const ptr = &m_vertexIndex[indexCount];
|
|
dgBigVector v0 (&m_vertexPoints[ptr[0]].m_x);
|
|
dgBigVector v1 (&m_vertexPoints[ptr[1]].m_x);
|
|
dgBigVector e0 (v1 - v0);
|
|
dgBigVector normal0 (dgBigVector::m_zero);
|
|
for (dgInt32 j = 2; j < faceIndexCount - 1; j ++) {
|
|
dgBigVector v2 (&m_vertexPoints[ptr[j]].m_x);
|
|
dgBigVector e1 (v2 - v0);
|
|
normal0 += e0.CrossProduct(e1);
|
|
e0 = e1;
|
|
}
|
|
dgBigVector normal (normal0.Normalize());
|
|
|
|
m_normalPoints[i].m_x = normal.m_x;
|
|
m_normalPoints[i].m_y = normal.m_y;
|
|
m_normalPoints[i].m_z = normal.m_z;
|
|
m_normalPoints[i].m_w = dgFloat32 (0.0f);
|
|
indexCount += faceIndexCount;
|
|
}
|
|
// compress normals array
|
|
m_normalIndex[m_faceCount] = 0;
|
|
m_normalCount = dgVertexListToIndexList(&m_normalPoints[0].m_x, sizeof (dgBigVector), 3, m_faceCount, &m_normalIndex[0], dgFloat32 (1.0e-6f));
|
|
}
|
|
|
|
|
|
void dgPolygonSoupDatabaseBuilder::Optimize(dgInt32 faceId, const dgFaceBucket& faceBucket, const dgPolygonSoupDatabaseBuilder& source)
|
|
{
|
|
#define DG_MESH_PARTITION_SIZE (1024 * 4)
|
|
|
|
const dgInt32* const indexArray = &source.m_vertexIndex[0];
|
|
const dgBigVector* const points = &source.m_vertexPoints[0];
|
|
|
|
dgVector face[256];
|
|
dgInt32 faceIndex[256];
|
|
if (faceBucket.GetCount() >= DG_MESH_PARTITION_SIZE) {
|
|
dgStack<dgFaceBucket::dgListNode*> array(faceBucket.GetCount());
|
|
dgInt32 count = 0;
|
|
for (dgFaceBucket::dgListNode* node = faceBucket.GetFirst(); node; node = node->GetNext()) {
|
|
array[count] = node;
|
|
count ++;
|
|
}
|
|
|
|
dgInt32 stack = 1;
|
|
dgInt32 segments[32][2];
|
|
|
|
segments[0][0] = 0;
|
|
segments[0][1] = count;
|
|
|
|
while (stack) {
|
|
stack --;
|
|
dgInt32 faceStart = segments[stack][0];
|
|
dgInt32 faceCount = segments[stack][1];
|
|
|
|
if (faceCount <= DG_MESH_PARTITION_SIZE) {
|
|
|
|
dgPolygonSoupDatabaseBuilder tmpBuilder (m_allocator);
|
|
for (dgInt32 i = 0; i < faceCount; i ++) {
|
|
const dgFaceInfo& faceInfo = array[faceStart + i]->GetInfo();
|
|
|
|
dgInt32 count1 = faceInfo.indexCount - 1;
|
|
dgInt32 start1 = faceInfo.indexStart;
|
|
dgAssert (faceId == indexArray[start1 + count1]);
|
|
for (dgInt32 j = 0; j < count1; j ++) {
|
|
dgInt32 index = indexArray[start1 + j];
|
|
face[j] = points[index];
|
|
faceIndex[j] = j;
|
|
}
|
|
dgInt32 faceIndexCount = count1;
|
|
tmpBuilder.AddMesh (&face[0].m_x, count1, sizeof (dgVector), 1, &faceIndexCount, &faceIndex[0], &faceId, dgGetIdentityMatrix());
|
|
}
|
|
tmpBuilder.FinalizeAndOptimize ();
|
|
|
|
dgInt32 faceIndexNumber = 0;
|
|
for (dgInt32 i = 0; i < tmpBuilder.m_faceCount; i ++) {
|
|
dgInt32 indexCount = tmpBuilder.m_faceVertexCount[i] - 1;
|
|
for (dgInt32 j = 0; j < indexCount; j ++) {
|
|
dgInt32 index = tmpBuilder.m_vertexIndex[faceIndexNumber + j];
|
|
face[j] = tmpBuilder.m_vertexPoints[index];
|
|
faceIndex[j] = j;
|
|
}
|
|
dgInt32 faceArray = indexCount;
|
|
AddMesh (&face[0].m_x, indexCount, sizeof (dgVector), 1, &faceArray, faceIndex, &faceId, dgGetIdentityMatrix());
|
|
|
|
faceIndexNumber += (indexCount + 1);
|
|
}
|
|
|
|
} else {
|
|
dgBigVector median (dgFloat32 (0.0f), dgFloat32 (0.0f), dgFloat32 (0.0f), dgFloat32 (0.0f));
|
|
dgBigVector varian (dgFloat32 (0.0f), dgFloat32 (0.0f), dgFloat32 (0.0f), dgFloat32 (0.0f));
|
|
for (dgInt32 i = 0; i < faceCount; i ++) {
|
|
const dgFaceInfo& faceInfo = array[faceStart + i]->GetInfo();
|
|
dgInt32 count1 = faceInfo.indexCount - 1;
|
|
dgInt32 start1 = faceInfo.indexStart;
|
|
dgBigVector p0 (dgFloat32 ( 1.0e10f), dgFloat32 ( 1.0e10f), dgFloat32 ( 1.0e10f), dgFloat32 (0.0f));
|
|
dgBigVector p1 (dgFloat32 (-1.0e10f), dgFloat32 (-1.0e10f), dgFloat32 (-1.0e10f), dgFloat32 (0.0f));
|
|
for (dgInt32 j = 0; j < count1; j ++) {
|
|
dgInt32 index = indexArray[start1 + j];
|
|
const dgBigVector& p = points[index];
|
|
dgAssert(p.m_w == dgFloat32(0.0f));
|
|
p0 = p0.GetMin(p);
|
|
p1 = p1.GetMax(p);
|
|
}
|
|
dgBigVector p ((p0 + p1).Scale (0.5f));
|
|
median += p;
|
|
varian += p * p;
|
|
}
|
|
|
|
varian = varian.Scale (dgFloat32 (faceCount)) - median * median;
|
|
|
|
dgInt32 axis = 0;
|
|
dgFloat32 maxVarian = dgFloat32 (-1.0e10f);
|
|
for (dgInt32 i = 0; i < 3; i ++) {
|
|
if (varian[i] > maxVarian) {
|
|
axis = i;
|
|
maxVarian = dgFloat32 (varian[i]);
|
|
}
|
|
}
|
|
dgBigVector center = median.Scale (dgFloat32 (1.0f) / dgFloat32 (faceCount));
|
|
dgFloat64 axisVal = center[axis];
|
|
|
|
dgInt32 leftCount = 0;
|
|
dgInt32 lastFace = faceCount;
|
|
|
|
for (dgInt32 i = 0; i < lastFace; i ++) {
|
|
dgInt32 side = 0;
|
|
const dgFaceInfo& faceInfo = array[faceStart + i]->GetInfo();
|
|
|
|
dgInt32 start1 = faceInfo.indexStart;
|
|
dgInt32 count1 = faceInfo.indexCount - 1;
|
|
for (dgInt32 j = 0; j < count1; j ++) {
|
|
dgInt32 index = indexArray[start1 + j];
|
|
const dgBigVector& p = points[index];
|
|
if (p[axis] > axisVal) {
|
|
side = 1;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (side) {
|
|
dgSwap (array[faceStart + i], array[faceStart + lastFace - 1]);
|
|
lastFace --;
|
|
i --;
|
|
} else {
|
|
leftCount ++;
|
|
}
|
|
}
|
|
dgAssert (leftCount);
|
|
dgAssert (leftCount < faceCount);
|
|
|
|
segments[stack][0] = faceStart;
|
|
segments[stack][1] = leftCount;
|
|
stack ++;
|
|
|
|
segments[stack][0] = faceStart + leftCount;
|
|
segments[stack][1] = faceCount - leftCount;
|
|
stack ++;
|
|
}
|
|
}
|
|
|
|
} else {
|
|
dgPolygonSoupDatabaseBuilder tmpBuilder (m_allocator);
|
|
for (dgFaceBucket::dgListNode* node = faceBucket.GetFirst(); node; node = node->GetNext()) {
|
|
const dgFaceInfo& faceInfo = node->GetInfo();
|
|
|
|
dgInt32 count = faceInfo.indexCount - 1;
|
|
dgInt32 start = faceInfo.indexStart;
|
|
dgAssert (faceId == indexArray[start + count]);
|
|
for (dgInt32 j = 0; j < count; j ++) {
|
|
dgInt32 index = indexArray[start + j];
|
|
face[j] = points[index];
|
|
faceIndex[j] = j;
|
|
}
|
|
dgInt32 faceIndexCount = count;
|
|
tmpBuilder.AddMesh (&face[0].m_x, count, sizeof (dgVector), 1, &faceIndexCount, &faceIndex[0], &faceId, dgGetIdentityMatrix());
|
|
}
|
|
tmpBuilder.FinalizeAndOptimize ();
|
|
|
|
dgInt32 faceIndexNumber = 0;
|
|
for (dgInt32 i = 0; i < tmpBuilder.m_faceCount; i ++) {
|
|
dgInt32 indexCount = tmpBuilder.m_faceVertexCount[i] - 1;
|
|
for (dgInt32 j = 0; j < indexCount; j ++) {
|
|
dgInt32 index = tmpBuilder.m_vertexIndex[faceIndexNumber + j];
|
|
face[j] = tmpBuilder.m_vertexPoints[index];
|
|
faceIndex[j] = j;
|
|
}
|
|
dgInt32 faceArray = indexCount;
|
|
AddMesh (&face[0].m_x, indexCount, sizeof (dgVector), 1, &faceArray, faceIndex, &faceId, dgGetIdentityMatrix());
|
|
|
|
faceIndexNumber += (indexCount + 1);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
dgInt32 dgPolygonSoupDatabaseBuilder::FilterFace (dgInt32 count, dgInt32* const pool)
|
|
{
|
|
if (count == 3) {
|
|
dgBigVector p0 (m_vertexPoints[pool[2]]);
|
|
p0 = p0 & dgBigVector::m_triplexMask;
|
|
for (dgInt32 i = 0; i < 3; i ++) {
|
|
dgBigVector p1 (m_vertexPoints[pool[i]]);
|
|
p1 = p1 & dgBigVector::m_triplexMask;
|
|
dgBigVector edge (p1 - p0);
|
|
dgFloat64 mag2 = edge.DotProduct(edge).GetScalar();
|
|
if (mag2 < dgFloat32 (1.0e-6f)) {
|
|
count = 0;
|
|
}
|
|
p0 = p1;
|
|
}
|
|
|
|
if (count == 3) {
|
|
dgBigVector edge0 (m_vertexPoints[pool[2]] - m_vertexPoints[pool[0]]);
|
|
dgBigVector edge1 (m_vertexPoints[pool[1]] - m_vertexPoints[pool[0]]);
|
|
dgBigVector normal (edge0.CrossProduct(edge1));
|
|
|
|
dgAssert(edge0.m_w == dgFloat32(0.0f));
|
|
dgAssert(edge1.m_w == dgFloat32(0.0f));
|
|
dgAssert (normal.m_w == dgFloat32 (0.0f));
|
|
dgFloat64 mag2 = normal.DotProduct(normal).GetScalar();
|
|
if (mag2 < dgFloat32 (1.0e-8f)) {
|
|
count = 0;
|
|
}
|
|
}
|
|
} else {
|
|
dgPolySoupFilterAllocator polyhedra(m_allocator);
|
|
count = polyhedra.AddFilterFace (dgUnsigned32 (count), pool);
|
|
|
|
if (!count) {
|
|
return 0;
|
|
}
|
|
|
|
dgEdge* edge = &polyhedra.GetRoot()->GetInfo();
|
|
if (edge->m_incidentFace < 0) {
|
|
edge = edge->m_twin;
|
|
}
|
|
|
|
bool flag = true;
|
|
while (flag) {
|
|
flag = false;
|
|
if (count >= 3) {
|
|
dgEdge* ptr = edge;
|
|
|
|
dgBigVector p0 (&m_vertexPoints[ptr->m_incidentVertex].m_x);
|
|
p0 = p0 & dgBigVector::m_triplexMask;
|
|
do {
|
|
dgBigVector p1 (&m_vertexPoints[ptr->m_next->m_incidentVertex].m_x);
|
|
p1 = p1 & dgBigVector::m_triplexMask;
|
|
dgBigVector e0 (p1 - p0);
|
|
dgFloat64 mag2 = e0.DotProduct(e0).GetScalar();
|
|
if (mag2 < dgFloat32 (1.0e-6f)) {
|
|
count --;
|
|
flag = true;
|
|
edge = ptr->m_next;
|
|
ptr->m_prev->m_next = ptr->m_next;
|
|
ptr->m_next->m_prev = ptr->m_prev;
|
|
ptr->m_twin->m_next->m_prev = ptr->m_twin->m_prev;
|
|
ptr->m_twin->m_prev->m_next = ptr->m_twin->m_next;
|
|
break;
|
|
}
|
|
p0 = p1;
|
|
ptr = ptr->m_next;
|
|
} while (ptr != edge);
|
|
}
|
|
}
|
|
if (count >= 3) {
|
|
flag = true;
|
|
dgBigVector normal (polyhedra.FaceNormal (edge, &m_vertexPoints[0].m_x, sizeof (dgBigVector)));
|
|
dgAssert (normal.m_w == dgFloat32 (0.0f));
|
|
|
|
dgAssert (normal.DotProduct(normal).GetScalar() > dgFloat32 (1.0e-10f));
|
|
normal = normal.Scale (dgFloat64 (1.0f) / sqrt (normal.DotProduct(normal).GetScalar() + dgFloat32 (1.0e-24f)));
|
|
|
|
while (flag) {
|
|
flag = false;
|
|
if (count >= 3) {
|
|
dgEdge* ptr = edge;
|
|
|
|
dgBigVector p0 (&m_vertexPoints[ptr->m_prev->m_incidentVertex].m_x);
|
|
dgBigVector p1 (&m_vertexPoints[ptr->m_incidentVertex].m_x);
|
|
|
|
p0 = p0 & dgBigVector::m_triplexMask;
|
|
p1 = p1 & dgBigVector::m_triplexMask;
|
|
dgBigVector e0 (p1 - p0);
|
|
e0 = e0.Scale (dgFloat64 (1.0f) / sqrt (e0.DotProduct(e0).GetScalar() + dgFloat32(1.0e-24f)));
|
|
do {
|
|
dgBigVector p2 (&m_vertexPoints[ptr->m_next->m_incidentVertex].m_x);
|
|
p2 = p2 & dgBigVector::m_triplexMask;
|
|
dgBigVector e1 (p2 - p1);
|
|
|
|
e1 = e1.Scale (dgFloat64 (1.0f) / sqrt (e1.DotProduct(e1).GetScalar() + dgFloat32(1.0e-24f)));
|
|
dgFloat64 mag2 = e1.DotProduct(e0).GetScalar();
|
|
if (mag2 > dgFloat32 (0.9999f)) {
|
|
count --;
|
|
flag = true;
|
|
edge = ptr->m_next;
|
|
ptr->m_prev->m_next = ptr->m_next;
|
|
ptr->m_next->m_prev = ptr->m_prev;
|
|
ptr->m_twin->m_next->m_prev = ptr->m_twin->m_prev;
|
|
ptr->m_twin->m_prev->m_next = ptr->m_twin->m_next;
|
|
break;
|
|
}
|
|
|
|
dgBigVector n (e0.CrossProduct(e1));
|
|
dgAssert (n.m_w == dgFloat32 (0.0f));
|
|
mag2 = n.DotProduct(normal).GetScalar();
|
|
if (mag2 < dgFloat32 (1.0e-5f)) {
|
|
count --;
|
|
flag = true;
|
|
edge = ptr->m_next;
|
|
ptr->m_prev->m_next = ptr->m_next;
|
|
ptr->m_next->m_prev = ptr->m_prev;
|
|
ptr->m_twin->m_next->m_prev = ptr->m_twin->m_prev;
|
|
ptr->m_twin->m_prev->m_next = ptr->m_twin->m_next;
|
|
break;
|
|
}
|
|
|
|
e0 = e1;
|
|
p1 = p2;
|
|
ptr = ptr->m_next;
|
|
} while (ptr != edge);
|
|
}
|
|
}
|
|
}
|
|
|
|
dgEdge* first = edge;
|
|
if (count >= 3) {
|
|
dgFloat64 best = dgFloat32 (2.0f);
|
|
dgEdge* ptr = edge;
|
|
|
|
dgBigVector p0 (&m_vertexPoints[ptr->m_incidentVertex].m_x);
|
|
dgBigVector p1 (&m_vertexPoints[ptr->m_next->m_incidentVertex].m_x);
|
|
p0 = p0 & dgBigVector::m_triplexMask;
|
|
p1 = p1 & dgBigVector::m_triplexMask;
|
|
dgBigVector e0 (p1 - p0);
|
|
e0 = e0.Scale (dgFloat64 (1.0f) / sqrt (e0.DotProduct(e0).GetScalar() + dgFloat32(1.0e-24f)));
|
|
do {
|
|
dgBigVector p2 (&m_vertexPoints[ptr->m_next->m_next->m_incidentVertex].m_x);
|
|
p2 = p2 & dgBigVector::m_triplexMask;
|
|
dgBigVector e1 (p2 - p1);
|
|
|
|
e1 = e1.Scale (dgFloat64 (1.0f) / sqrt (e1.DotProduct(e1).GetScalar() + dgFloat32(1.0e-24f)));
|
|
dgFloat64 mag2 = fabs (e1.DotProduct(e0).GetScalar());
|
|
if (mag2 < best) {
|
|
best = mag2;
|
|
first = ptr;
|
|
}
|
|
|
|
e0 = e1;
|
|
p1 = p2;
|
|
ptr = ptr->m_next;
|
|
} while (ptr != edge);
|
|
|
|
count = 0;
|
|
ptr = first;
|
|
do {
|
|
pool[count] = ptr->m_incidentVertex;
|
|
count ++;
|
|
ptr = ptr->m_next;
|
|
} while (ptr != first);
|
|
}
|
|
|
|
#ifdef _DEBUG
|
|
if (count >= 3) {
|
|
dgInt32 j0 = count - 2;
|
|
dgInt32 j1 = count - 1;
|
|
dgBigVector normal (polyhedra.FaceNormal (edge, &m_vertexPoints[0].m_x, sizeof (dgBigVector)));
|
|
dgAssert (normal.m_w == dgFloat32 (0.0f));
|
|
for (dgInt32 j2 = 0; j2 < count; j2 ++) {
|
|
dgBigVector p0 (&m_vertexPoints[pool[j0]].m_x);
|
|
dgBigVector p1 (&m_vertexPoints[pool[j1]].m_x);
|
|
dgBigVector p2 (&m_vertexPoints[pool[j2]].m_x);
|
|
p0 = p0 & dgBigVector::m_triplexMask;
|
|
p1 = p1 & dgBigVector::m_triplexMask;
|
|
p2 = p2 & dgBigVector::m_triplexMask;
|
|
|
|
dgBigVector e0 ((p0 - p1));
|
|
dgBigVector e1 ((p2 - p1));
|
|
|
|
dgBigVector n (e1.CrossProduct(e0));
|
|
dgAssert (n.DotProduct(normal).GetScalar() > dgFloat32 (0.0f));
|
|
j0 = j1;
|
|
j1 = j2;
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
|
|
return (count >= 3) ? count : 0;
|
|
}
|
|
|
|
|
|
dgInt32 dgPolygonSoupDatabaseBuilder::AddConvexFace (dgInt32 count, dgInt32* const pool, dgInt32* const facesArray)
|
|
{
|
|
dgPolySoupFilterAllocator polyhedra(m_allocator);
|
|
|
|
count = polyhedra.AddFilterFace(dgUnsigned32 (count), pool);
|
|
|
|
dgEdge* edge = &polyhedra.GetRoot()->GetInfo();
|
|
if (edge->m_incidentFace < 0) {
|
|
edge = edge->m_twin;
|
|
}
|
|
|
|
|
|
dgInt32 isconvex = 1;
|
|
dgInt32 facesCount = 0;
|
|
|
|
dgInt32 flag = 1;
|
|
while (flag) {
|
|
flag = 0;
|
|
if (count >= 3) {
|
|
dgEdge* ptr = edge;
|
|
|
|
dgBigVector p0 (&m_vertexPoints[ptr->m_incidentVertex].m_x);
|
|
do {
|
|
dgBigVector p1 (&m_vertexPoints[ptr->m_next->m_incidentVertex].m_x);
|
|
dgBigVector e0 (p1 - p0);
|
|
dgFloat64 mag2 = e0.DotProduct3(e0);
|
|
if (mag2 < dgFloat32 (1.0e-6f)) {
|
|
count --;
|
|
flag = 1;
|
|
edge = ptr->m_next;
|
|
ptr->m_prev->m_next = ptr->m_next;
|
|
ptr->m_next->m_prev = ptr->m_prev;
|
|
ptr->m_twin->m_next->m_prev = ptr->m_twin->m_prev;
|
|
ptr->m_twin->m_prev->m_next = ptr->m_twin->m_next;
|
|
break;
|
|
}
|
|
p0 = p1;
|
|
ptr = ptr->m_next;
|
|
} while (ptr != edge);
|
|
}
|
|
}
|
|
if (count >= 3) {
|
|
flag = 1;
|
|
|
|
while (flag) {
|
|
flag = 0;
|
|
if (count >= 3) {
|
|
dgEdge* ptr = edge;
|
|
|
|
dgBigVector p0 (&m_vertexPoints[ptr->m_prev->m_incidentVertex].m_x);
|
|
dgBigVector p1 (&m_vertexPoints[ptr->m_incidentVertex].m_x);
|
|
dgBigVector e0 (p1 - p0);
|
|
e0 = e0.Scale (dgFloat64 (1.0f) / sqrt (e0.DotProduct3(e0) + dgFloat32(1.0e-24f)));
|
|
do {
|
|
dgBigVector p2 (&m_vertexPoints[ptr->m_next->m_incidentVertex].m_x);
|
|
dgBigVector e1 (p2 - p1);
|
|
|
|
e1 = e1.Scale (dgFloat64 (1.0f) / sqrt (e1.DotProduct3(e1) + dgFloat32(1.0e-24f)));
|
|
dgFloat64 mag2 = e1.DotProduct3(e0);
|
|
if (mag2 > dgFloat32 (0.9999f)) {
|
|
count --;
|
|
flag = 1;
|
|
edge = ptr->m_next;
|
|
ptr->m_prev->m_next = ptr->m_next;
|
|
ptr->m_next->m_prev = ptr->m_prev;
|
|
ptr->m_twin->m_next->m_prev = ptr->m_twin->m_prev;
|
|
ptr->m_twin->m_prev->m_next = ptr->m_twin->m_next;
|
|
break;
|
|
}
|
|
|
|
e0 = e1;
|
|
p1 = p2;
|
|
ptr = ptr->m_next;
|
|
} while (ptr != edge);
|
|
}
|
|
}
|
|
|
|
dgBigVector normal (polyhedra.FaceNormal (edge, &m_vertexPoints[0].m_x, sizeof (dgBigVector)));
|
|
dgFloat64 mag2 = normal.DotProduct3(normal);
|
|
if (mag2 < dgFloat32 (1.0e-8f)) {
|
|
return 0;
|
|
}
|
|
normal = normal.Scale (dgFloat64 (1.0f) / sqrt (mag2));
|
|
|
|
if (count >= 3) {
|
|
dgEdge* ptr = edge;
|
|
dgBigVector p0 (&m_vertexPoints[ptr->m_prev->m_incidentVertex].m_x);
|
|
dgBigVector p1 (&m_vertexPoints[ptr->m_incidentVertex].m_x);
|
|
dgBigVector e0 (p1 - p0);
|
|
e0 = e0.Scale (dgFloat64 (1.0f) / sqrt (e0.DotProduct3(e0) + dgFloat32(1.0e-24f)));
|
|
do {
|
|
dgBigVector p2 (&m_vertexPoints[ptr->m_next->m_incidentVertex].m_x);
|
|
dgBigVector e1 (p2 - p1);
|
|
|
|
e1 = e1.Scale (dgFloat64 (1.0f) / sqrt (e1.DotProduct3(e1) + dgFloat32(1.0e-24f)));
|
|
|
|
dgBigVector n (e0.CrossProduct(e1));
|
|
dgFloat64 magnitud2 = n.DotProduct3(normal);
|
|
if (magnitud2 < dgFloat32 (1.0e-5f)) {
|
|
isconvex = 0;
|
|
break;
|
|
}
|
|
|
|
e0 = e1;
|
|
p1 = p2;
|
|
ptr = ptr->m_next;
|
|
} while (ptr != edge);
|
|
}
|
|
}
|
|
|
|
if (isconvex) {
|
|
dgEdge* const first = edge;
|
|
if (count >= 3) {
|
|
count = 0;
|
|
dgEdge* ptr = first;
|
|
do {
|
|
pool[count] = ptr->m_incidentVertex;
|
|
count ++;
|
|
ptr = ptr->m_next;
|
|
} while (ptr != first);
|
|
facesArray[facesCount] = count;
|
|
facesCount = 1;
|
|
}
|
|
} else {
|
|
dgPolyhedra leftOver(m_allocator);
|
|
dgPolyhedra polyhedra2(m_allocator);
|
|
dgEdge* ptr = edge;
|
|
count = 0;
|
|
do {
|
|
pool[count] = ptr->m_incidentVertex;
|
|
count ++;
|
|
ptr = ptr->m_next;
|
|
} while (ptr != edge);
|
|
|
|
|
|
polyhedra2.BeginFace();
|
|
polyhedra2.AddFace (count, pool);
|
|
polyhedra2.EndFace();
|
|
leftOver.BeginFace();
|
|
polyhedra2.ConvexPartition (&m_vertexPoints[0].m_x, m_vertexPoints.GetElementSize(), &leftOver);
|
|
leftOver.EndFace();
|
|
|
|
#if _DEBUG
|
|
if (leftOver.GetCount()) {
|
|
dgTrace (("warning: %d faces with more that a one shared edge\n", leftOver.GetCount()));
|
|
dgTrace ((" this mesh is not a manifold and may lead to collision malfunctions\n"));
|
|
}
|
|
#endif
|
|
|
|
dgInt32 mark = polyhedra2.IncLRU();
|
|
dgInt32 index = 0;
|
|
dgPolyhedra::Iterator iter (polyhedra2);
|
|
for (iter.Begin(); iter; iter ++) {
|
|
dgEdge* const edge1 = &(*iter);
|
|
if (edge1->m_incidentFace < 0) {
|
|
continue;
|
|
}
|
|
if (edge1->m_mark == mark) {
|
|
continue;
|
|
}
|
|
|
|
ptr = edge1;
|
|
count = 0;
|
|
do {
|
|
ptr->m_mark = mark;
|
|
pool[index] = ptr->m_incidentVertex;
|
|
index ++;
|
|
count ++;
|
|
ptr = ptr->m_next;
|
|
} while (ptr != edge1);
|
|
|
|
facesArray[facesCount] = count;
|
|
facesCount ++;
|
|
}
|
|
}
|
|
|
|
return facesCount;
|
|
}
|
|
|
|
|
|
|
|
|