Files
NazaraEngine/thirdparty/src/newton/dgCore/dgPolygonSoupBuilder.cpp
2020-09-06 17:09:19 +02:00

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;
}