4317 lines
127 KiB
C++
4317 lines
127 KiB
C++
/* Copyright (c) <2003-2011> <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.
|
|
*/
|
|
|
|
#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<dgInt32> 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<dgInt32> materialIndex(builder.m_faceCount);
|
|
dgStack<dgInt32> 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<dgInt32> 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<dgBigVector> points(m_pointCount);
|
|
dgStack<dgVertexAtribute> 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<dgInt32> 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<dgBigVector> 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<dgVertexAtribute> 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());
|
|
|
|
dgStack<dgVector>cylinder (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;
|
|
}
|
|
|
|
dgStack<dgVertexAtribute>attribArray (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<dgBigVector> 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<dgVertexAtribute> 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<dgVertexAtribute> 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<dgVertexAtribute> 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<dgBigVector> faceNormal(GetCount());
|
|
dgStack<dgVertexAtribute> 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<dgInt32> indexMap(m_pointCount);
|
|
dgStack<dgInt32> 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<dgInt32> 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<dgInt32, dgInt32> 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<dgInt32, dgInt32>::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<dgInt32, dgInt32>::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<dgConflictEdge>::dgListNode* node = conlictFaceList.GetFirst(); node; ) {
|
|
dgList<dgConflictEdge>::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<dgInt8> 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<dgVector> 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<dgInt32> 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<dgFlatClipEdgeAttr, dgEdge *> leftFilter(GetAllocator());
|
|
dgTree<dgFlatClipEdgeAttr, dgEdge *> rightFilter(GetAllocator());
|
|
dgStack<dgInt8> 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<dgMeshTreeCSGFace *> 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<dgMeshTreeCSGFace *>::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<dgMeshTreeCSGFace *>::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<dgMeshTreeCSGFace *>::dgListNode *node = faceList.GetFirst();
|
|
node->GetNext(); node = node->GetNext()) {
|
|
dgMeshTreeCSGFace *const face0 = node->GetInfo();
|
|
for (dgList<dgMeshTreeCSGFace *>::dgListNode *node1 = node->GetNext();
|
|
node1; node1 = node1->GetNext()) {
|
|
dgMeshTreeCSGFace *const face1 = node1->GetInfo();
|
|
face0->MergeMissingVertex(face1);
|
|
face1->MergeMissingVertex(face0);
|
|
}
|
|
}
|
|
|
|
for (dgList<dgMeshTreeCSGFace *>::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<dgMeshTreeCSGFace *>::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));
|
|
}
|