remove quickhull array dependency (except for drawing)
This commit is contained in:
parent
bd4ca5d143
commit
4ebe826eea
@ -20,7 +20,6 @@
|
|||||||
#define QH_HULL_H
|
#define QH_HULL_H
|
||||||
|
|
||||||
#include <bounce/common/geometry.h>
|
#include <bounce/common/geometry.h>
|
||||||
#include <bounce/common/template/array.h>
|
|
||||||
|
|
||||||
template<class T>
|
template<class T>
|
||||||
struct qhList
|
struct qhList
|
||||||
@ -100,7 +99,7 @@ public:
|
|||||||
~qhHull();
|
~qhHull();
|
||||||
|
|
||||||
// Construct this hull given a memory buffer and an array of points.
|
// Construct this hull given a memory buffer and an array of points.
|
||||||
// Use qhGetBufferCapacity to get the buffer capacity from the point array size.
|
// Use qhGetBufferSize to get the buffer size given the number of points.
|
||||||
void Construct(void* buffer, const b3Vec3* vertices, u32 vertexCount);
|
void Construct(void* buffer, const b3Vec3* vertices, u32 vertexCount);
|
||||||
|
|
||||||
// Get the number of iterations this algorithm ran.
|
// Get the number of iterations this algorithm ran.
|
||||||
@ -129,20 +128,17 @@ private:
|
|||||||
|
|
||||||
void AddVertex(qhVertex* v);
|
void AddVertex(qhVertex* v);
|
||||||
|
|
||||||
void BuildHorizon(b3Array<qhHalfEdge*>& horizon, qhVertex* eye);
|
void BuildHorizon(qhVertex* eye);
|
||||||
|
void BuildHorizon(qhVertex* eye, qhHalfEdge* e0, qhFace* f);
|
||||||
|
|
||||||
void BuildHorizon(b3Array<qhHalfEdge*>& horizon, qhVertex* eye, qhHalfEdge* e0, qhFace* f);
|
void AddNewFaces(qhVertex* eye);
|
||||||
|
void MergeFaces();
|
||||||
|
bool MergeFace(qhFace* face);
|
||||||
|
|
||||||
qhFace* AddTriangle(qhVertex* v1, qhVertex* v2, qhVertex* v3);
|
qhFace* AddTriangle(qhVertex* v1, qhVertex* v2, qhVertex* v3);
|
||||||
|
|
||||||
qhHalfEdge* AddAdjoiningTriangle(qhVertex* v, qhHalfEdge* he);
|
qhHalfEdge* AddAdjoiningTriangle(qhVertex* v, qhHalfEdge* he);
|
||||||
|
|
||||||
void AddNewFaces(b3Array<qhFace*>& newFaces, qhVertex* eye, const b3Array<qhHalfEdge*>& horizon);
|
|
||||||
|
|
||||||
bool MergeFace(qhFace* face);
|
|
||||||
|
|
||||||
void MergeFaces(b3Array<qhFace*>& newFaces);
|
|
||||||
|
|
||||||
qhHalfEdge* FindTwin(const qhVertex* tail, const qhVertex* head) const;
|
qhHalfEdge* FindTwin(const qhVertex* tail, const qhVertex* head) const;
|
||||||
|
|
||||||
// Coplanarity tolerance
|
// Coplanarity tolerance
|
||||||
@ -167,6 +163,12 @@ private:
|
|||||||
qhVertex* m_freeVertices;
|
qhVertex* m_freeVertices;
|
||||||
qhHalfEdge* m_freeEdges;
|
qhHalfEdge* m_freeEdges;
|
||||||
qhFace* m_freeFaces;
|
qhFace* m_freeFaces;
|
||||||
|
|
||||||
|
qhHalfEdge** m_horizon;
|
||||||
|
u32 m_horizonCount;
|
||||||
|
|
||||||
|
qhFace** m_newFaces;
|
||||||
|
u32 m_newFaceCount;
|
||||||
};
|
};
|
||||||
|
|
||||||
#include <bounce/quickhull/qh_hull.inl>
|
#include <bounce/quickhull/qh_hull.inl>
|
||||||
|
@ -128,20 +128,31 @@ inline void qhFace::ComputeCenterAndPlane()
|
|||||||
// its value at compile-time. That is particularly usefull when you want to
|
// its value at compile-time. That is particularly usefull when you want to
|
||||||
// create a stack buffer from a constant number of vertices.
|
// create a stack buffer from a constant number of vertices.
|
||||||
// Due to the constexpr specifier, this function is automatically inlined.
|
// Due to the constexpr specifier, this function is automatically inlined.
|
||||||
constexpr u32 qhGetBufferCapacity(u32 pointCount)
|
constexpr u32 qhGetBufferSize(u32 pointCount)
|
||||||
{
|
{
|
||||||
|
u32 size = 0;
|
||||||
|
|
||||||
|
// Hull using Euler's Formula
|
||||||
u32 V = pointCount;
|
u32 V = pointCount;
|
||||||
u32 E = 3 * V - 6;
|
u32 E = 3 * V - 6;
|
||||||
u32 HE = 2 * E;
|
u32 HE = 2 * E;
|
||||||
u32 F = 2 * V - 4;
|
u32 F = 2 * V - 4;
|
||||||
|
|
||||||
HE *= 2;
|
|
||||||
F *= 2;
|
|
||||||
|
|
||||||
u32 size = 0;
|
|
||||||
size += V * sizeof(qhVertex);
|
size += V * sizeof(qhVertex);
|
||||||
size += HE * sizeof(qhHalfEdge);
|
size += HE * sizeof(qhHalfEdge);
|
||||||
size += F * sizeof(qhFace);
|
size += F * sizeof(qhFace);
|
||||||
|
|
||||||
|
// Extra
|
||||||
|
size += HE * sizeof(qhHalfEdge);
|
||||||
|
size += F * sizeof(qhFace);
|
||||||
|
|
||||||
|
// Horizon
|
||||||
|
size += HE * sizeof(qhHalfEdge*);
|
||||||
|
|
||||||
|
// New Faces
|
||||||
|
// One face per horizon edge
|
||||||
|
size += HE * sizeof(qhFace*);
|
||||||
|
|
||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -175,8 +175,8 @@ void b3QHull::Set(const b3Vec3* points, u32 count)
|
|||||||
// Create a convex hull.
|
// Create a convex hull.
|
||||||
|
|
||||||
// Allocate memory buffer for the worst case.
|
// Allocate memory buffer for the worst case.
|
||||||
const u32 qhBufferCapacity = qhGetBufferCapacity(B3_MAX_HULL_VERTICES);
|
const u32 qhBufferSize = qhGetBufferSize(B3_MAX_HULL_VERTICES);
|
||||||
u8 qhBuffer[qhBufferCapacity];
|
u8 qhBuffer[qhBufferSize];
|
||||||
|
|
||||||
// Build
|
// Build
|
||||||
qhHull hull;
|
qhHull hull;
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <bounce/quickhull/qh_hull.h>
|
#include <bounce/quickhull/qh_hull.h>
|
||||||
|
#include <bounce/common/template/array.h>
|
||||||
#include <bounce/common/template/stack.h>
|
#include <bounce/common/template/stack.h>
|
||||||
#include <bounce/common/draw.h>
|
#include <bounce/common/draw.h>
|
||||||
|
|
||||||
@ -99,6 +100,12 @@ void qhHull::Construct(void* memory, const b3Vec3* vs, u32 count)
|
|||||||
FreeFace(f);
|
FreeFace(f);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m_horizon = (qhHalfEdge**)((u8*)faces + F * sizeof(qhFace*));
|
||||||
|
m_horizonCount = 0;
|
||||||
|
|
||||||
|
m_newFaces = (qhFace**)((u8*)m_horizon + HE * sizeof(qhHalfEdge*));
|
||||||
|
m_newFaceCount = 0;
|
||||||
|
|
||||||
m_faceList.head = NULL;
|
m_faceList.head = NULL;
|
||||||
m_faceList.count = 0;
|
m_faceList.count = 0;
|
||||||
m_iteration = 0;
|
m_iteration = 0;
|
||||||
@ -346,45 +353,12 @@ qhVertex* qhHull::NextVertex()
|
|||||||
|
|
||||||
void qhHull::AddVertex(qhVertex* eye)
|
void qhHull::AddVertex(qhVertex* eye)
|
||||||
{
|
{
|
||||||
b3StackArray<qhHalfEdge*, 32> horizon;
|
BuildHorizon(eye);
|
||||||
BuildHorizon(horizon, eye);
|
AddNewFaces(eye);
|
||||||
|
MergeFaces();
|
||||||
b3StackArray<qhFace*, 32> newFaces;
|
|
||||||
AddNewFaces(newFaces, eye, horizon);
|
|
||||||
|
|
||||||
MergeFaces(newFaces);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void qhHull::BuildHorizon(b3Array<qhHalfEdge*>& horizon, qhVertex* eye, qhHalfEdge* edge0, qhFace* face)
|
void qhHull::BuildHorizon(qhVertex* eye)
|
||||||
{
|
|
||||||
// Mark face as visible/visited.
|
|
||||||
face->state = qhFace::e_visible;
|
|
||||||
|
|
||||||
qhHalfEdge* edge = edge0;
|
|
||||||
|
|
||||||
do
|
|
||||||
{
|
|
||||||
qhHalfEdge* adjEdge = edge->twin;
|
|
||||||
qhFace* adjFace = adjEdge->face;
|
|
||||||
|
|
||||||
if (adjFace->state == qhFace::e_invisible)
|
|
||||||
{
|
|
||||||
if (b3Distance(eye->position, adjFace->plane) > m_tolerance)
|
|
||||||
{
|
|
||||||
BuildHorizon(horizon, eye, adjEdge, adjFace);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
horizon.PushBack(edge);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
edge = edge->next;
|
|
||||||
|
|
||||||
} while (edge != edge0);
|
|
||||||
}
|
|
||||||
|
|
||||||
void qhHull::BuildHorizon(b3Array<qhHalfEdge*>& horizon, qhVertex* eye)
|
|
||||||
{
|
{
|
||||||
// Clean visited flags
|
// Clean visited flags
|
||||||
{
|
{
|
||||||
@ -402,12 +376,150 @@ void qhHull::BuildHorizon(b3Array<qhHalfEdge*>& horizon, qhVertex* eye)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// todo
|
|
||||||
// Iterative DFS.
|
|
||||||
// Ensure CCW order of horizon edges.
|
|
||||||
|
|
||||||
// Build horizon.
|
// Build horizon.
|
||||||
BuildHorizon(horizon, eye, eye->conflictFace->edge, eye->conflictFace);
|
m_horizonCount = 0;
|
||||||
|
BuildHorizon(eye, eye->conflictFace->edge, eye->conflictFace);
|
||||||
|
}
|
||||||
|
|
||||||
|
void qhHull::BuildHorizon(qhVertex* eye, qhHalfEdge* edge0, qhFace* face)
|
||||||
|
{
|
||||||
|
// Mark face as visible/visited.
|
||||||
|
face->state = qhFace::e_visible;
|
||||||
|
|
||||||
|
qhHalfEdge* edge = edge0;
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
qhHalfEdge* adjEdge = edge->twin;
|
||||||
|
qhFace* adjFace = adjEdge->face;
|
||||||
|
|
||||||
|
if (adjFace->state == qhFace::e_invisible)
|
||||||
|
{
|
||||||
|
if (b3Distance(eye->position, adjFace->plane) > m_tolerance)
|
||||||
|
{
|
||||||
|
BuildHorizon(eye, adjEdge, adjFace);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_horizon[m_horizonCount++] = edge;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
edge = edge->next;
|
||||||
|
|
||||||
|
} while (edge != edge0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void qhHull::AddNewFaces(qhVertex* eye)
|
||||||
|
{
|
||||||
|
m_newFaceCount = 0;
|
||||||
|
|
||||||
|
B3_ASSERT(m_horizonCount > 0);
|
||||||
|
|
||||||
|
qhHalfEdge* beginEdge = NULL;
|
||||||
|
qhHalfEdge* prevEdge = NULL;
|
||||||
|
|
||||||
|
{
|
||||||
|
qhHalfEdge* edge = m_horizon[0];
|
||||||
|
qhHalfEdge* leftEdge = AddAdjoiningTriangle(eye, edge);
|
||||||
|
qhHalfEdge* rightEdge = leftEdge->prev;
|
||||||
|
|
||||||
|
prevEdge = rightEdge;
|
||||||
|
|
||||||
|
beginEdge = leftEdge;
|
||||||
|
|
||||||
|
m_newFaces[m_newFaceCount++] = leftEdge->face;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (u32 i = 1; i < m_horizonCount - 1; ++i)
|
||||||
|
{
|
||||||
|
qhHalfEdge* edge = m_horizon[i];
|
||||||
|
qhHalfEdge* leftEdge = AddAdjoiningTriangle(eye, edge);
|
||||||
|
qhHalfEdge* rightEdge = leftEdge->prev;
|
||||||
|
|
||||||
|
leftEdge->twin = prevEdge;
|
||||||
|
prevEdge->twin = leftEdge;
|
||||||
|
|
||||||
|
prevEdge = rightEdge;
|
||||||
|
|
||||||
|
m_newFaces[m_newFaceCount++] = leftEdge->face;
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
qhHalfEdge* edge = m_horizon[m_horizonCount - 1];
|
||||||
|
qhHalfEdge* leftEdge = AddAdjoiningTriangle(eye, edge);
|
||||||
|
qhHalfEdge* rightEdge = leftEdge->prev;
|
||||||
|
|
||||||
|
leftEdge->twin = prevEdge;
|
||||||
|
prevEdge->twin = leftEdge;
|
||||||
|
|
||||||
|
rightEdge->twin = beginEdge;
|
||||||
|
beginEdge->twin = rightEdge;
|
||||||
|
|
||||||
|
m_newFaces[m_newFaceCount++] = leftEdge->face;
|
||||||
|
}
|
||||||
|
|
||||||
|
qhFace* f = m_faceList.head;
|
||||||
|
while (f)
|
||||||
|
{
|
||||||
|
if (f->state == qhFace::e_invisible)
|
||||||
|
{
|
||||||
|
f = f->next;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Partition conflict vertices.
|
||||||
|
qhVertex* v = f->conflictList.head;
|
||||||
|
while (v)
|
||||||
|
{
|
||||||
|
b3Vec3 p = v->position;
|
||||||
|
|
||||||
|
// Use tolerance and discard internal points.
|
||||||
|
float32 max = m_tolerance;
|
||||||
|
qhFace* iMax = NULL;
|
||||||
|
|
||||||
|
for (u32 i = 0; i < m_newFaceCount; ++i)
|
||||||
|
{
|
||||||
|
qhFace* newFace = m_newFaces[i];
|
||||||
|
float32 d = b3Distance(p, newFace->plane);
|
||||||
|
if (d > max)
|
||||||
|
{
|
||||||
|
max = d;
|
||||||
|
iMax = newFace;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (iMax)
|
||||||
|
{
|
||||||
|
qhVertex* v0 = v;
|
||||||
|
v->conflictFace = NULL;
|
||||||
|
v = f->conflictList.Remove(v);
|
||||||
|
iMax->conflictList.PushFront(v0);
|
||||||
|
v0->conflictFace = iMax;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
qhVertex* v0 = v;
|
||||||
|
v->conflictFace = NULL;
|
||||||
|
v = f->conflictList.Remove(v);
|
||||||
|
FreeVertex(v0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove face half-edges.
|
||||||
|
qhHalfEdge* e = f->edge;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
qhHalfEdge* e0 = e;
|
||||||
|
e = e->next;
|
||||||
|
FreeEdge(e0);
|
||||||
|
} while (e != f->edge);
|
||||||
|
|
||||||
|
// Remove face.
|
||||||
|
qhFace* f0 = f;
|
||||||
|
f = m_faceList.Remove(f);
|
||||||
|
FreeFace(f0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
qhFace* qhHull::AddTriangle(qhVertex* v1, qhVertex* v2, qhVertex* v3)
|
qhFace* qhHull::AddTriangle(qhVertex* v1, qhVertex* v2, qhVertex* v3)
|
||||||
@ -503,116 +615,6 @@ qhHalfEdge* qhHull::AddAdjoiningTriangle(qhVertex* eye, qhHalfEdge* horizonEdge)
|
|||||||
return e1;
|
return e1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void qhHull::AddNewFaces(b3Array<qhFace*>& newFaces, qhVertex* eye, const b3Array<qhHalfEdge*>& horizon)
|
|
||||||
{
|
|
||||||
newFaces.Reserve(horizon.Count());
|
|
||||||
|
|
||||||
qhHalfEdge* beginEdge = NULL;
|
|
||||||
qhHalfEdge* prevEdge = NULL;
|
|
||||||
|
|
||||||
{
|
|
||||||
qhHalfEdge* edge = horizon[0];
|
|
||||||
qhHalfEdge* leftEdge = AddAdjoiningTriangle(eye, edge);
|
|
||||||
qhHalfEdge* rightEdge = leftEdge->prev;
|
|
||||||
|
|
||||||
prevEdge = rightEdge;
|
|
||||||
|
|
||||||
beginEdge = leftEdge;
|
|
||||||
|
|
||||||
newFaces.PushBack(leftEdge->face);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (u32 i = 1; i < horizon.Count() - 1; ++i)
|
|
||||||
{
|
|
||||||
qhHalfEdge* edge = horizon[i];
|
|
||||||
qhHalfEdge* leftEdge = AddAdjoiningTriangle(eye, edge);
|
|
||||||
qhHalfEdge* rightEdge = leftEdge->prev;
|
|
||||||
|
|
||||||
leftEdge->twin = prevEdge;
|
|
||||||
prevEdge->twin = leftEdge;
|
|
||||||
|
|
||||||
prevEdge = rightEdge;
|
|
||||||
|
|
||||||
newFaces.PushBack(leftEdge->face);
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
qhHalfEdge* edge = horizon[horizon.Count() - 1];
|
|
||||||
qhHalfEdge* leftEdge = AddAdjoiningTriangle(eye, edge);
|
|
||||||
qhHalfEdge* rightEdge = leftEdge->prev;
|
|
||||||
|
|
||||||
leftEdge->twin = prevEdge;
|
|
||||||
prevEdge->twin = leftEdge;
|
|
||||||
|
|
||||||
rightEdge->twin = beginEdge;
|
|
||||||
beginEdge->twin = rightEdge;
|
|
||||||
|
|
||||||
newFaces.PushBack(leftEdge->face);
|
|
||||||
}
|
|
||||||
|
|
||||||
qhFace* f = m_faceList.head;
|
|
||||||
while (f)
|
|
||||||
{
|
|
||||||
if (f->state == qhFace::e_invisible)
|
|
||||||
{
|
|
||||||
f = f->next;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Partition conflict vertices.
|
|
||||||
qhVertex* v = f->conflictList.head;
|
|
||||||
while (v)
|
|
||||||
{
|
|
||||||
b3Vec3 p = v->position;
|
|
||||||
|
|
||||||
// Use tolerance and discard internal points.
|
|
||||||
float32 max = m_tolerance;
|
|
||||||
qhFace* iMax = NULL;
|
|
||||||
|
|
||||||
for (u32 i = 0; i < newFaces.Count(); ++i)
|
|
||||||
{
|
|
||||||
qhFace* newFace = newFaces[i];
|
|
||||||
float32 d = b3Distance(p, newFace->plane);
|
|
||||||
if (d > max)
|
|
||||||
{
|
|
||||||
max = d;
|
|
||||||
iMax = newFace;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (iMax)
|
|
||||||
{
|
|
||||||
qhVertex* v0 = v;
|
|
||||||
v->conflictFace = NULL;
|
|
||||||
v = f->conflictList.Remove(v);
|
|
||||||
iMax->conflictList.PushFront(v0);
|
|
||||||
v0->conflictFace = iMax;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
qhVertex* v0 = v;
|
|
||||||
v->conflictFace = NULL;
|
|
||||||
v = f->conflictList.Remove(v);
|
|
||||||
FreeVertex(v0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Remove face half-edges.
|
|
||||||
qhHalfEdge* e = f->edge;
|
|
||||||
do
|
|
||||||
{
|
|
||||||
qhHalfEdge* e0 = e;
|
|
||||||
e = e->next;
|
|
||||||
FreeEdge(e0);
|
|
||||||
} while (e != f->edge);
|
|
||||||
|
|
||||||
// Remove face.
|
|
||||||
qhFace* f0 = f;
|
|
||||||
f = m_faceList.Remove(f);
|
|
||||||
FreeFace(f0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool qhHull::MergeFace(qhFace* rightFace)
|
bool qhHull::MergeFace(qhFace* rightFace)
|
||||||
{
|
{
|
||||||
qhHalfEdge* e = rightFace->edge;
|
qhHalfEdge* e = rightFace->edge;
|
||||||
@ -691,22 +693,18 @@ bool qhHull::MergeFace(qhFace* rightFace)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void qhHull::MergeFaces(b3Array<qhFace*>& newFaces)
|
void qhHull::MergeFaces()
|
||||||
{
|
{
|
||||||
for (u32 i = 0; i < newFaces.Count(); ++i)
|
for (u32 i = 0; i < m_newFaceCount; ++i)
|
||||||
{
|
{
|
||||||
qhFace* f = newFaces[i];
|
qhFace* f = m_newFaces[i];
|
||||||
|
|
||||||
if (f->state == qhFace::e_deleted)
|
if (f->state == qhFace::e_deleted)
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// todo
|
// Merge the faces while there is no face left to merge.
|
||||||
// Fix topological and geometrical errors.
|
|
||||||
|
|
||||||
// Merge the faces while there is no face left
|
|
||||||
// to merge.
|
|
||||||
while (MergeFace(f));
|
while (MergeFace(f));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -754,23 +752,25 @@ void qhHull::Validate() const
|
|||||||
|
|
||||||
void qhHull::Draw() const
|
void qhHull::Draw() const
|
||||||
{
|
{
|
||||||
|
b3StackArray<b3Vec3, 256> polygon;
|
||||||
|
|
||||||
qhFace* face = m_faceList.head;
|
qhFace* face = m_faceList.head;
|
||||||
while (face)
|
while (face)
|
||||||
{
|
{
|
||||||
|
polygon.Resize(0);
|
||||||
|
|
||||||
b3Vec3 c = face->center;
|
b3Vec3 c = face->center;
|
||||||
b3Vec3 n = face->plane.normal;
|
b3Vec3 n = face->plane.normal;
|
||||||
|
|
||||||
b3StackArray<b3Vec3, 32> vs;
|
|
||||||
|
|
||||||
const qhHalfEdge* begin = face->edge;
|
const qhHalfEdge* begin = face->edge;
|
||||||
const qhHalfEdge* edge = begin;
|
const qhHalfEdge* edge = begin;
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
vs.PushBack(edge->tail->position);
|
polygon.PushBack(edge->tail->position);
|
||||||
edge = edge->next;
|
edge = edge->next;
|
||||||
} while (edge != begin);
|
} while (edge != begin);
|
||||||
|
|
||||||
b3Draw_draw->DrawSolidPolygon(n, vs.Begin(), vs.Count(), b3Color(1.0f, 1.0f, 1.0f, 0.5f));
|
b3Draw_draw->DrawSolidPolygon(n, polygon.Begin(), polygon.Count(), b3Color(1.0f, 1.0f, 1.0f, 0.5f));
|
||||||
|
|
||||||
qhVertex* v = face->conflictList.head;
|
qhVertex* v = face->conflictList.head;
|
||||||
while (v)
|
while (v)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user