diff --git a/include/bounce/quickhull/qh_hull.h b/include/bounce/quickhull/qh_hull.h index 6b51010..f05325e 100644 --- a/include/bounce/quickhull/qh_hull.h +++ b/include/bounce/quickhull/qh_hull.h @@ -58,8 +58,8 @@ struct qhFace b3Vec3 center; b3Plane plane; - u32 VertexCount() const; - u32 EdgeCount() const; + u32 GetVertexCount() const; + u32 GetEdgeCount() const; qhHalfEdge* FindTwin(const qhVertex* tail, const qhVertex* head) const; void ComputeCenterAndPlane(); }; @@ -89,12 +89,8 @@ struct qhVertex qhFace* conflictFace; }; -// Given a number of points return the required memory size in bytes for constructing the -// convex hull of those points. Use this function before allocating the memory buffer passed -// as argument to Construct. -u32 qhGetMemorySize(u32 V); - -// A convex hull builder. Given a list of points constructs its convex hull. +// A convex hull builder. +// Given a list of points constructs its convex hull. // The output convex hull might contain polygonal faces and not only triangles. // Coplanar face merging is necessary for stable physics simulation. class qhHull @@ -102,18 +98,23 @@ class qhHull public: qhHull(); ~qhHull(); - - // Entry point of qhHull. - // Construct this hull given a memory buffer and a list of points. - // Use qhGetMemorySize to see how many free bytes should be available in the buffer. - void Construct(void* memory, const b3Array& vertices); - - // Get the list of faces in this hull. - const qhList& GetFaceList() const; + + // Construct this hull given a memory buffer and an array of points. + // Use qhGetBufferCapacity to get the buffer capacity from the point array size. + void Construct(void* buffer, const b3Vec3* vertices, u32 vertexCount); // Get the number of iterations this algorithm ran. u32 GetIterations() const; + // Get the list of faces in this convex hull. + const qhList& GetFaceList() const; + + // Get the number of unique edges in this convex hull. + // u32 GetEdgeCount() const; + + // Get the number of unique vertices in this convex hull. + // u32 GetVertexCount() const; + // Validate this hull. void Validate() const; void Validate(const qhFace* face) const; @@ -122,7 +123,7 @@ public: // Draw this hull. void Draw() const; private: - bool BuildInitialHull(const b3Array& vertices); + bool BuildInitialHull(const b3Vec3* vertices, u32 count); qhVertex* NextVertex(); @@ -146,13 +147,13 @@ private: // Coplanarity tolerance float32 m_tolerance; - + + // Number of Quickhull iterations + u32 m_iteration; + // List of faces qhList m_faceList; - // Number of Quickhull iterations - u32 m_iteration; - // Memory qhVertex* AllocateVertex(); void FreeVertex(qhVertex* p); diff --git a/include/bounce/quickhull/qh_hull.inl b/include/bounce/quickhull/qh_hull.inl index 6569aa7..47eb0d0 100644 --- a/include/bounce/quickhull/qh_hull.inl +++ b/include/bounce/quickhull/qh_hull.inl @@ -1,5 +1,7 @@ // qhHull.h +// Lists + template inline void qhList::PushFront(T* link) { @@ -38,7 +40,9 @@ inline T* qhList::Remove(T* link) return next; } -inline u32 qhFace::VertexCount() const +// qhFace + +inline u32 qhFace::GetVertexCount() const { u32 count = 0; qhHalfEdge* e = edge; @@ -50,7 +54,7 @@ inline u32 qhFace::VertexCount() const return count; } -inline u32 qhFace::EdgeCount() const +inline u32 qhFace::GetEdgeCount() const { u32 count = 0; qhHalfEdge* e = edge; @@ -81,7 +85,7 @@ inline qhHalfEdge* qhFace::FindTwin(const qhVertex* tail, const qhVertex* head) return NULL; } -inline b3Vec3 b3Newell(const b3Vec3& a, const b3Vec3& b) +static inline b3Vec3 b3Newell(const b3Vec3& a, const b3Vec3& b) { return b3Vec3((a.y - b.y) * (a.z + b.z), (a.z - b.z) * (a.x + b.x), (a.x - b.x) * (a.y + b.y)); } @@ -116,29 +120,21 @@ inline void qhFace::ComputeCenterAndPlane() center = c; } -inline qhHalfEdge* qhHull::FindTwin(const qhVertex* tail, const qhVertex* head) const -{ - qhFace* face = m_faceList.head; - while (face) - { - qhHalfEdge* e = face->FindTwin(tail, head); - if (e) - { - return e; - } - face = face->next; - } - return NULL; -} +// qhHull -inline u32 qhGetMemorySize(u32 V) +// Given a number of points return the required memory size in +// bytes for constructing the convex hull of those points. +// This function uses constant expression (C++11). Therefore, you can evaluate +// its value at compile-time. That is particularly usefull when you want to +// create a stack buffer from a constant number of vertices. +// Due to the constexpr specifier, this function is automatically inlined. +constexpr u32 qhGetBufferCapacity(u32 pointCount) { + u32 V = pointCount; u32 E = 3 * V - 6; u32 HE = 2 * E; u32 F = 2 * V - 4; - // V - E + F = 2 - HE *= 2; F *= 2; @@ -149,16 +145,16 @@ inline u32 qhGetMemorySize(u32 V) return size; } -inline const qhList& qhHull::GetFaceList() const -{ - return m_faceList; -} - inline u32 qhHull::GetIterations() const { return m_iteration; } +inline const qhList& qhHull::GetFaceList() const +{ + return m_faceList; +} + inline qhVertex* qhHull::AllocateVertex() { qhVertex* v = m_freeVertices; @@ -197,4 +193,19 @@ inline void qhHull::FreeFace(qhFace* f) f->state = qhFace::e_deleted; f->freeNext = m_freeFaces; m_freeFaces = f; +} + +inline qhHalfEdge* qhHull::FindTwin(const qhVertex* tail, const qhVertex* head) const +{ + qhFace* face = m_faceList.head; + while (face) + { + qhHalfEdge* e = face->FindTwin(tail, head); + if (e) + { + return e; + } + face = face->next; + } + return NULL; } \ No newline at end of file diff --git a/src/bounce/quickhull/qh_hull.cpp b/src/bounce/quickhull/qh_hull.cpp index 2714eb7..994ecb8 100644 --- a/src/bounce/quickhull/qh_hull.cpp +++ b/src/bounce/quickhull/qh_hull.cpp @@ -20,7 +20,7 @@ #include #include -static float32 qhFindAABB(u32 iMin[3], u32 iMax[3], const b3Array& vertices) +static float32 qhFindAABB(u32 iMin[3], u32 iMax[3], const b3Vec3* vertices, u32 count) { b3Vec3 min(B3_MAX_FLOAT, B3_MAX_FLOAT, B3_MAX_FLOAT); iMin[0] = 0; @@ -32,21 +32,21 @@ static float32 qhFindAABB(u32 iMin[3], u32 iMax[3], const b3Array& verti iMax[1] = 0; iMax[2] = 0; - for (u32 i = 0; i < vertices.Count(); ++i) + for (u32 i = 0; i < count; ++i) { - b3Vec3 p = vertices[i]; + b3Vec3 v = vertices[i]; for (u32 j = 0; j < 3; ++j) { - if (p[j] < min[j]) + if (v[j] < min[j]) { - min[j] = p[j]; + min[j] = v[j]; iMin[j] = i; } - if (p[j] > max[j]) + if (v[j] > max[j]) { - max[j] = p[j]; + max[j] = v[j]; iMax[j] = i; } } @@ -63,11 +63,11 @@ qhHull::~qhHull() { } -void qhHull::Construct(void* memory, const b3Array& vs) +void qhHull::Construct(void* memory, const b3Vec3* vs, u32 count) { // Euler's formula // V - E + F = 2 - u32 V = vs.Count(); + u32 V = count; u32 E = 3 * V - 6; u32 HE = 2 * E; u32 F = 2 * V - 4; @@ -103,7 +103,7 @@ void qhHull::Construct(void* memory, const b3Array& vs) m_faceList.count = 0; m_iteration = 0; - if (!BuildInitialHull(vs)) + if (!BuildInitialHull(vs, count)) { return; } @@ -119,9 +119,9 @@ void qhHull::Construct(void* memory, const b3Array& vs) } } -bool qhHull::BuildInitialHull(const b3Array& vertices) +bool qhHull::BuildInitialHull(const b3Vec3* vertices, u32 vertexCount) { - if (vertices.Count() < 4) + if (vertexCount < 4) { B3_ASSERT(false); return false; @@ -134,7 +134,7 @@ bool qhHull::BuildInitialHull(const b3Array& vertices) // canonical axes. // Store tolerance for coplanarity checks. u32 aabbMin[3], aabbMax[3]; - m_tolerance = qhFindAABB(aabbMin, aabbMax, vertices); + m_tolerance = qhFindAABB(aabbMin, aabbMax, vertices, vertexCount); // Find the longest segment. float32 d0 = 0.0f; @@ -173,7 +173,7 @@ bool qhHull::BuildInitialHull(const b3Array& vertices) // Find the triangle which has the largest area. float32 a0 = 0.0f; - for (u32 i = 0; i < vertices.Count(); ++i) + for (u32 i = 0; i < vertexCount; ++i) { if (i == i1 || i == i2) { @@ -214,7 +214,7 @@ bool qhHull::BuildInitialHull(const b3Array& vertices) // Find the furthest point from the triangle plane. float32 d0 = 0.0f; - for (u32 i = 0; i < vertices.Count(); ++i) + for (u32 i = 0; i < vertexCount; ++i) { if (i == i1 || i == i2 || i == i3) { @@ -280,7 +280,7 @@ bool qhHull::BuildInitialHull(const b3Array& vertices) // Add remaining points to the hull. // Assign closest face plane to each of them. - for (u32 i = 0; i < vertices.Count(); ++i) + for (u32 i = 0; i < vertexCount; ++i) { if (i == i1 || i == i2 || i == i3 || i == i4) {