From 4ebe826eeaaf231557355de436f3e0c4fbb27639 Mon Sep 17 00:00:00 2001 From: Irlan <-> Date: Fri, 20 Apr 2018 23:37:59 -0300 Subject: [PATCH] remove quickhull array dependency (except for drawing) --- include/bounce/quickhull/qh_hull.h | 30 +-- include/bounce/quickhull/qh_hull.inl | 23 +- src/bounce/collision/shapes/qhull.cpp | 4 +- src/bounce/quickhull/qh_hull.cpp | 330 +++++++++++++------------- 4 files changed, 200 insertions(+), 187 deletions(-) diff --git a/include/bounce/quickhull/qh_hull.h b/include/bounce/quickhull/qh_hull.h index f05325e..7bcbe65 100644 --- a/include/bounce/quickhull/qh_hull.h +++ b/include/bounce/quickhull/qh_hull.h @@ -20,7 +20,6 @@ #define QH_HULL_H #include -#include template struct qhList @@ -100,7 +99,7 @@ public: ~qhHull(); // 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); // Get the number of iterations this algorithm ran. @@ -128,21 +127,18 @@ private: qhVertex* NextVertex(); void AddVertex(qhVertex* v); - - void BuildHorizon(b3Array& horizon, qhVertex* eye); - - void BuildHorizon(b3Array& horizon, qhVertex* eye, qhHalfEdge* e0, qhFace* f); - + + void BuildHorizon(qhVertex* eye); + void BuildHorizon(qhVertex* eye, qhHalfEdge* e0, qhFace* f); + + void AddNewFaces(qhVertex* eye); + void MergeFaces(); + bool MergeFace(qhFace* face); + qhFace* AddTriangle(qhVertex* v1, qhVertex* v2, qhVertex* v3); qhHalfEdge* AddAdjoiningTriangle(qhVertex* v, qhHalfEdge* he); - void AddNewFaces(b3Array& newFaces, qhVertex* eye, const b3Array& horizon); - - bool MergeFace(qhFace* face); - - void MergeFaces(b3Array& newFaces); - qhHalfEdge* FindTwin(const qhVertex* tail, const qhVertex* head) const; // Coplanarity tolerance @@ -163,10 +159,16 @@ private: qhFace* AllocateFace(); void FreeFace(qhFace* p); - + qhVertex* m_freeVertices; qhHalfEdge* m_freeEdges; qhFace* m_freeFaces; + + qhHalfEdge** m_horizon; + u32 m_horizonCount; + + qhFace** m_newFaces; + u32 m_newFaceCount; }; #include diff --git a/include/bounce/quickhull/qh_hull.inl b/include/bounce/quickhull/qh_hull.inl index 47eb0d0..8dd62cd 100644 --- a/include/bounce/quickhull/qh_hull.inl +++ b/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 // 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) +constexpr u32 qhGetBufferSize(u32 pointCount) { + u32 size = 0; + + // Hull using Euler's Formula u32 V = pointCount; u32 E = 3 * V - 6; u32 HE = 2 * E; u32 F = 2 * V - 4; - - HE *= 2; - F *= 2; - - u32 size = 0; + size += V * sizeof(qhVertex); size += HE * sizeof(qhHalfEdge); 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; } diff --git a/src/bounce/collision/shapes/qhull.cpp b/src/bounce/collision/shapes/qhull.cpp index 3b36aa2..11de698 100644 --- a/src/bounce/collision/shapes/qhull.cpp +++ b/src/bounce/collision/shapes/qhull.cpp @@ -175,8 +175,8 @@ void b3QHull::Set(const b3Vec3* points, u32 count) // Create a convex hull. // Allocate memory buffer for the worst case. - const u32 qhBufferCapacity = qhGetBufferCapacity(B3_MAX_HULL_VERTICES); - u8 qhBuffer[qhBufferCapacity]; + const u32 qhBufferSize = qhGetBufferSize(B3_MAX_HULL_VERTICES); + u8 qhBuffer[qhBufferSize]; // Build qhHull hull; diff --git a/src/bounce/quickhull/qh_hull.cpp b/src/bounce/quickhull/qh_hull.cpp index 994ecb8..bfbaae8 100644 --- a/src/bounce/quickhull/qh_hull.cpp +++ b/src/bounce/quickhull/qh_hull.cpp @@ -17,6 +17,7 @@ */ #include +#include #include #include @@ -98,7 +99,13 @@ void qhHull::Construct(void* memory, const b3Vec3* vs, u32 count) f->conflictList.count = 0; 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.count = 0; m_iteration = 0; @@ -346,45 +353,12 @@ qhVertex* qhHull::NextVertex() void qhHull::AddVertex(qhVertex* eye) { - b3StackArray horizon; - BuildHorizon(horizon, eye); - - b3StackArray newFaces; - AddNewFaces(newFaces, eye, horizon); - - MergeFaces(newFaces); + BuildHorizon(eye); + AddNewFaces(eye); + MergeFaces(); } -void qhHull::BuildHorizon(b3Array& horizon, 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(horizon, eye, adjEdge, adjFace); - } - else - { - horizon.PushBack(edge); - } - } - - edge = edge->next; - - } while (edge != edge0); -} - -void qhHull::BuildHorizon(b3Array& horizon, qhVertex* eye) +void qhHull::BuildHorizon(qhVertex* eye) { // Clean visited flags { @@ -402,12 +376,150 @@ void qhHull::BuildHorizon(b3Array& horizon, qhVertex* eye) } } - // todo - // Iterative DFS. - // Ensure CCW order of horizon edges. - // 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) @@ -503,116 +615,6 @@ qhHalfEdge* qhHull::AddAdjoiningTriangle(qhVertex* eye, qhHalfEdge* horizonEdge) return e1; } -void qhHull::AddNewFaces(b3Array& newFaces, qhVertex* eye, const b3Array& 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) { qhHalfEdge* e = rightFace->edge; @@ -691,22 +693,18 @@ bool qhHull::MergeFace(qhFace* rightFace) return false; } -void qhHull::MergeFaces(b3Array& 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) { continue; } - // todo - // Fix topological and geometrical errors. - - // Merge the faces while there is no face left - // to merge. + // Merge the faces while there is no face left to merge. while (MergeFace(f)); } } @@ -754,23 +752,25 @@ void qhHull::Validate() const void qhHull::Draw() const { + b3StackArray polygon; + qhFace* face = m_faceList.head; while (face) { + polygon.Resize(0); + b3Vec3 c = face->center; b3Vec3 n = face->plane.normal; - b3StackArray vs; - const qhHalfEdge* begin = face->edge; const qhHalfEdge* edge = begin; do { - vs.PushBack(edge->tail->position); + polygon.PushBack(edge->tail->position); edge = edge->next; } 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; while (v)