optimize conversion

This commit is contained in:
Irlan 2018-04-20 19:24:01 -03:00
parent ece8cea0c7
commit 1f3fe9f873

View File

@ -24,25 +24,31 @@
// //
struct b3PointerIndex struct b3PointerIndex
{ {
void* key; void* pointer;
u8 value; u8 index;
}; };
// //
template<u32 N> template<u32 N>
struct b3PointerMap struct b3PIMap
{ {
void Add(const b3PointerIndex& entry) b3PIMap()
{ {
m_entries.PushBack(entry); count = 0;
} }
b3PointerIndex* Find(void* key) void Add(const b3PointerIndex& pi)
{ {
for (u32 i = 0; i < m_entries.Count(); ++i) B3_ASSERT(count < N);
pis[count++] = pi;
}
b3PointerIndex* Find(void* pointer)
{
for (u32 i = 0; i < count; ++i)
{ {
b3PointerIndex* index = m_entries.Get(i); b3PointerIndex* index = pis + i;
if (index->key == key) if (index->pointer == pointer)
{ {
return index; return index;
} }
@ -50,7 +56,8 @@ struct b3PointerMap
return NULL; return NULL;
} }
b3StackArray<b3PointerIndex, N> m_entries; u32 count;
b3PointerIndex pis[N];
}; };
// //
@ -129,15 +136,21 @@ static b3Vec3 b3ComputeCentroid(b3QHull* hull)
void b3QHull::Set(const b3Vec3* points, u32 count) void b3QHull::Set(const b3Vec3* points, u32 count)
{ {
B3_ASSERT(count >= 4 && count <= B3_MAX_HULL_VERTICES);
// Clamp vertices into range [0, B3_MAX_HULL_VERTICES]
u32 n = b3Min(count, u32(B3_MAX_HULL_VERTICES));
// Copy points into local buffer, remove coincident points. // Copy points into local buffer, remove coincident points.
b3StackArray<b3Vec3, B3_MAX_HULL_VERTICES> ps; b3Vec3 ps[B3_MAX_HULL_VERTICES];
for (u32 i = 0; i < count; ++i) u32 psCount = 0;
for (u32 i = 0; i < n; ++i)
{ {
b3Vec3 p = points[i]; b3Vec3 p = points[i];
bool unique = true; bool unique = true;
for (u32 j = 0; j < ps.Count(); ++j) for (u32 j = 0; j < psCount; ++j)
{ {
const float32 kTol = 0.5f * B3_LINEAR_SLOP; const float32 kTol = 0.5f * B3_LINEAR_SLOP;
if (b3DistanceSquared(p, ps[j]) < kTol * kTol) if (b3DistanceSquared(p, ps[j]) < kTol * kTol)
@ -149,60 +162,43 @@ void b3QHull::Set(const b3Vec3* points, u32 count)
if (unique) if (unique)
{ {
ps.PushBack(p); ps[psCount++] = p;
} }
} }
if (ps.Count() < 3) if (psCount < 4)
{ {
// Polyhedron is degenerate. // Polyhedron is degenerate.
return; return;
} }
// Create a convex hull. // Create a convex hull.
u32 qh_size = qhGetMemorySize(ps.Count());
void* qh_memory = b3Alloc(qh_size); // Allocate memory buffer for the worst case.
const u32 qhBufferCapacity = qhGetBufferCapacity(B3_MAX_HULL_VERTICES);
u8 qhBuffer[qhBufferCapacity];
// Build
qhHull hull; qhHull hull;
hull.Construct(qh_memory, ps); hull.Construct(qhBuffer, ps, psCount);
// Count vertices, edges, and faces in the convex hull.
u32 V = 0;
u32 E = 0;
u32 F = 0;
const qhList<qhFace>& faceList = hull.GetFaceList(); const qhList<qhFace>& faceList = hull.GetFaceList();
if (faceList.count > B3_MAX_HULL_FACES)
qhFace* face = faceList.head;
while (face)
{ {
qhHalfEdge* e = face->edge; // Face excess
do return;
{
++E;
++V;
e = e->next;
} while (e != face->edge);
++F;
face = face->next;
} }
if (V > B3_MAX_HULL_VERTICES || E > B3_MAX_HULL_EDGES || F > B3_MAX_HULL_FACES) // Cheaply convert the constructed hull into a run-time hull.
{
b3Free(qh_memory);
return;
}
// Convert the constructed hull into a run-time hull.
vertexCount = 0; vertexCount = 0;
edgeCount = 0; edgeCount = 0;
faceCount = 0; faceCount = 0;
b3PointerMap<B3_MAX_HULL_VERTICES> vertexMap; // These structures map vertex/edge pointers to indices in the run-time hull
b3PointerMap<B3_MAX_HULL_EDGES> edgeMap; b3PIMap<B3_MAX_HULL_VERTICES> vertexMap;
b3PIMap<B3_MAX_HULL_EDGES> edgeMap;
face = faceList.head; qhFace* face = faceList.head;
while (face) while (face)
{ {
// Collected face half-edges // Collected face half-edges
@ -216,42 +212,61 @@ void b3QHull::Set(const b3Vec3* points, u32 count)
qhVertex* v1 = edge->tail; qhVertex* v1 = edge->tail;
qhVertex* v2 = twin->tail; qhVertex* v2 = twin->tail;
// Are the vertices unique?
b3PointerIndex* mv1 = vertexMap.Find(v1); b3PointerIndex* mv1 = vertexMap.Find(v1);
b3PointerIndex* mv2 = vertexMap.Find(v2); b3PointerIndex* mv2 = vertexMap.Find(v2);
u8 iv1; u8 iv1;
if (mv1) if (mv1)
{ {
iv1 = mv1->value; iv1 = mv1->index;
} }
else else
{ {
B3_ASSERT(vertexCount < V); // Vertex excess
if (vertexCount == B3_MAX_HULL_VERTICES)
{
vertexCount = 0;
edgeCount = 0;
faceCount = 0;
return;
}
vertices[vertexCount] = v1->position;
iv1 = vertexCount; iv1 = vertexCount;
vertices[iv1] = v1->position;
vertexMap.Add({ v1, iv1 });
++vertexCount; ++vertexCount;
vertexMap.Add({ v1, iv1 });
} }
u8 iv2; u8 iv2;
if (mv2) if (mv2)
{ {
iv2 = mv2->value; iv2 = mv2->index;
} }
else else
{ {
B3_ASSERT(vertexCount < V); // Vertex excess
if (vertexCount == B3_MAX_HULL_VERTICES)
{
vertexCount = 0;
edgeCount = 0;
faceCount = 0;
return;
}
vertices[vertexCount] = v2->position;
iv2 = vertexCount; iv2 = vertexCount;
vertices[iv2] = v2->position;
vertexMap.Add({ v2, iv2 });
++vertexCount; ++vertexCount;
vertexMap.Add({ v2, iv2 });
} }
b3PointerIndex* mte = edgeMap.Find(edge); b3PointerIndex* mte = edgeMap.Find(edge);
if (mte) if (mte)
{ {
u8 ie2 = mte->value; u8 ie2 = mte->index;
b3HalfEdge* e2 = edges + ie2; b3HalfEdge* e2 = edges + ie2;
B3_ASSERT(e2->face == B3_NULL_HULL_FEATURE); B3_ASSERT(e2->face == B3_NULL_HULL_FEATURE);
e2->face = u8(faceCount); e2->face = u8(faceCount);
@ -259,12 +274,19 @@ void b3QHull::Set(const b3Vec3* points, u32 count)
} }
else else
{ {
B3_ASSERT(edgeCount < E); // Edge excess
if (edgeCount + 2 >= B3_MAX_HULL_EDGES)
{
vertexCount = 0;
edgeCount = 0;
faceCount = 0;
return;
}
u8 ie1 = edgeCount; u8 ie1 = edgeCount;
b3HalfEdge* e1 = edges + edgeCount; b3HalfEdge* e1 = edges + edgeCount;
++edgeCount; ++edgeCount;
B3_ASSERT(edgeCount < E);
u8 ie2 = edgeCount; u8 ie2 = edgeCount;
b3HalfEdge* e2 = edges + edgeCount; b3HalfEdge* e2 = edges + edgeCount;
++edgeCount; ++edgeCount;
@ -285,28 +307,29 @@ void b3QHull::Set(const b3Vec3* points, u32 count)
edge = edge->next; edge = edge->next;
} while (edge != face->edge); } while (edge != face->edge);
B3_ASSERT(faceEdges.Count() > 0);
b3Face* f = faces + faceCount; B3_ASSERT(faceCount < B3_MAX_HULL_FACES);
f->edge = faceEdges[0];
for (u32 i = 0; i < faceEdges.Count(); ++i)
{
u32 j = i < faceEdges.Count() - 1 ? i + 1 : 0;
edges[faceEdges[i]].next = faceEdges[j];
}
planes[faceCount] = face->plane; planes[faceCount] = face->plane;
B3_ASSERT(faceCount < F); b3Face* f = faces + faceCount;
++faceCount; ++faceCount;
B3_ASSERT(faceEdges.Count() > 0);
f->edge = faceEdges[0];
// Link face half-edges
for (u32 i = 0; i < faceEdges.Count(); ++i)
{
u8 edge = faceEdges[i];
u32 j = i < faceEdges.Count() - 1 ? i + 1 : 0;
edges[edge].next = faceEdges[j];
}
face = face->next; face = face->next;
} }
//
b3Free(qh_memory);
// Validate // Validate
Validate(); Validate();