node to triangle lookups

main
cosmonaut 2021-09-24 13:48:35 -07:00
parent a479c66969
commit 2fc8d0a781
2 changed files with 245 additions and 102 deletions

View File

@ -29,6 +29,174 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
typedef struct Silkworm_Vector2
{
float x;
float y;
} Silkworm_Vector2;
typedef struct Silkworm_Link Silkworm_Link;
typedef struct Silkworm_Node
{
uint64_t id;
Silkworm_Vector2 position;
Silkworm_Vector2 previousPosition;
Silkworm_Vector2 velocity;
Silkworm_Vector2 acceleration;
float mass;
float friction;
float radius;
float pinned;
float pushFactor;
bool destroyable;
bool markedForDestroy; /* mutual recursion on nodes/links so this makes it easier to track destroys */
Silkworm_Link** links;
uint32_t linkCount;
} Silkworm_Node;
struct Silkworm_Link
{
uint64_t id;
Silkworm_Node* a;
Silkworm_Node* b;
float distance;
float tearThreshold;
bool markedForDestroy; /* mutual recursion on nodes/links so this makes it easier to track destroys */
};
typedef enum Silkworm_ClothTriangleOrientation
{
UpperLeft,
BottomRight
} Silkworm_ClothTriangleOrientation;
typedef struct Silkworm_Triangle
{
uint64_t id;
Silkworm_Node* a;
Silkworm_Node* b;
Silkworm_Node* c;
uint32_t aHorizontalIndex;
uint32_t bHorizontalIndex;
uint32_t cHorizontalIndex;
uint32_t aVerticalIndex;
uint32_t bVerticalIndex;
uint32_t cVerticalIndex;
Silkworm_ClothTriangleOrientation orientation;
} Silkworm_Triangle;
typedef struct NodeTriangleHashMap
{
Silkworm_Node* key;
uint32_t *indexArray;
uint32_t indexArrayCount;
} NodeTriangleHashMap;
typedef struct NodeTriangleHashArray
{
NodeTriangleHashMap* elements;
uint32_t count;
} NodeTriangleHashArray;
#define NUM_NODE_TRIANGLE_HASH_BUCKETS 1031
typedef struct NodeTriangleHashTable
{
NodeTriangleHashArray buckets[NUM_NODE_TRIANGLE_HASH_BUCKETS];
} NodeTriangleHashTable;
static inline uint64_t NodeTriangleHashTable_GetHashCode(Silkworm_Node *key)
{
return 97 + (uint64_t)(size_t)key;
}
static inline uint32_t* NodeTriangleHashTable_Fetch(
NodeTriangleHashTable *table,
Silkworm_Node *key,
uint32_t *arrayCount
) {
uint32_t i;
uint64_t hashcode = NodeTriangleHashTable_GetHashCode(key);
NodeTriangleHashArray* arr = &table->buckets[hashcode % NUM_NODE_TRIANGLE_HASH_BUCKETS];
for (i = 0; i < arr->count; i += 1)
{
if (arr->elements[i].key == key)
{
*arrayCount = arr->elements[i].indexArrayCount;
return arr->elements[i].indexArray;
}
}
*arrayCount = 0;
return NULL;
}
static inline void NodeTriangleHashTable_Insert(
NodeTriangleHashTable* table,
Silkworm_Node* key,
uint32_t index
) {
uint32_t i;
uint64_t hashcode = NodeTriangleHashTable_GetHashCode(key);
NodeTriangleHashArray* arr = &table->buckets[hashcode % NUM_NODE_TRIANGLE_HASH_BUCKETS];
bool foundKey = false;
for (i = 0; i < arr->count; i += 1)
{
if (arr->elements[i].key == key)
{
arr->elements[i].indexArray = realloc(arr->elements[i].indexArray, sizeof(uint32_t) * (arr->elements[i].indexArrayCount + 1));
arr->elements[i].indexArray[arr->elements[i].indexArrayCount] = index;
arr->elements[i].indexArrayCount += 1;
foundKey = true;
break;
}
}
if (!foundKey)
{
arr->elements = realloc(arr->elements, sizeof(NodeTriangleHashMap) * (arr->count + 1));
arr->elements[arr->count].key = key;
arr->elements[arr->count].indexArray = malloc(sizeof(uint32_t));
arr->elements[arr->count].indexArray[0] = index;
arr->elements[arr->count].indexArrayCount = 1;
arr->count += 1;
}
}
typedef struct Silkworm_Cloth
{
uint64_t id;
float windFactor;
uint32_t horizontalNodeCount;
uint32_t verticalNodeCount;
uint64_t** nodeIndices; /* x by y grid of indices */
Silkworm_Triangle** triangles; /* array of pointers so we can use NULL */
uint32_t triangleCount;
NodeTriangleHashTable nodeHash;
} Silkworm_Cloth;
typedef struct Silkworm_Rope
{
uint32_t nodeCount;
uint32_t* nodeIndices;
} Silkworm_Rope;
typedef struct Silkworm_Color typedef struct Silkworm_Color
{ {
uint8_t r; uint8_t r;
@ -156,6 +324,15 @@ void Silkworm_Internal_DestroyCloth(Silkworm_Cloth* cloth)
context->cloths[cloth->id] = NULL; context->cloths[cloth->id] = NULL;
for (i = 0; i < NUM_NODE_TRIANGLE_HASH_BUCKETS; i += 1)
{
for (j = 0; j < cloth->nodeHash.buckets[i].count; j += 1)
{
free(cloth->nodeHash.buckets[i].elements[j].indexArray);
}
free(cloth->nodeHash.buckets[i].elements);
}
for (i = 0; i < cloth->horizontalNodeCount; i += 1) for (i = 0; i < cloth->horizontalNodeCount; i += 1)
{ {
for (j = 0; j < cloth->verticalNodeCount; j += 1) for (j = 0; j < cloth->verticalNodeCount; j += 1)
@ -184,7 +361,7 @@ void Silkworm_DestroyCloth(double clothId)
void Silkworm_PerformDestroys() void Silkworm_PerformDestroys()
{ {
uint32_t i, j; uint32_t i, j, k;
for (i = 0; i < context->linkCount; i += 1) for (i = 0; i < context->linkCount; i += 1)
{ {
@ -222,8 +399,32 @@ void Silkworm_PerformDestroys()
for (i = 0; i < context->nodeCount; i += 1) for (i = 0; i < context->nodeCount; i += 1)
{ {
if (context->nodes[i] != NULL && context->nodes[i]->markedForDestroy) Silkworm_Node* node = context->nodes[i];
if (node != NULL && node->markedForDestroy)
{ {
/* find cloth to remove from relevant triangles */
for (j = 0; j < context->clothCount; j += 1)
{
Silkworm_Cloth* cloth = context->cloths[j];
if (cloth != NULL)
{
uint32_t triangleIndexCount = 0;
uint32_t* triangleIndices = NodeTriangleHashTable_Fetch(&cloth->nodeHash, node, &triangleIndexCount);
for (k = 0; k < triangleIndexCount; k += 1)
{
uint32_t triangleIndex = triangleIndices[k];
if (cloth->triangles[triangleIndex] != NULL)
{
free(cloth->triangles[triangleIndex]);
cloth->triangles[triangleIndex] = NULL;
}
}
}
}
free(context->nodes[i]->links); free(context->nodes[i]->links);
free(context->nodes[i]); free(context->nodes[i]);
context->nodes[i] = NULL; context->nodes[i] = NULL;
@ -396,25 +597,10 @@ void Silkworm_ClothNodeUnpin(double clothId, double i, double j)
void Silkworm_ClothNodeDestroy(double clothId, double i, double j) void Silkworm_ClothNodeDestroy(double clothId, double i, double j)
{ {
uint32_t iterator;
Silkworm_Cloth* cloth = LookupCloth(clothId); Silkworm_Cloth* cloth = LookupCloth(clothId);
uint64_t nodeIndex = cloth->nodeIndices[(uint64_t)i][(uint64_t)j]; uint64_t nodeIndex = cloth->nodeIndices[(uint64_t)i][(uint64_t)j];
Silkworm_Node* node = context->nodes[nodeIndex]; Silkworm_Node* node = context->nodes[nodeIndex];
Silkworm_DestroyNode(nodeIndex); Silkworm_DestroyNode(nodeIndex);
/* fixme: this should be hashed */
for (iterator = 0; iterator < cloth->triangleCount; iterator += 1)
{
if (cloth->triangles[iterator] != NULL)
{
if (cloth->triangles[iterator]->a == node || cloth->triangles[iterator]->b == node || cloth->triangles[iterator]->c == node)
{
free(cloth->triangles[iterator]);
cloth->triangles[iterator] = NULL;
}
}
}
} }
double Silkworm_CreateLink(double aId, double bId, double distance, double tearThreshold) double Silkworm_CreateLink(double aId, double bId, double distance, double tearThreshold)
@ -490,6 +676,12 @@ double Silkworm_CreateCloth(double xPosition, double yPosition, double horizonta
cloth->id = id; cloth->id = id;
for (i = 0; i < NUM_NODE_TRIANGLE_HASH_BUCKETS; i += 1)
{
cloth->nodeHash.buckets[i].elements = NULL;
cloth->nodeHash.buckets[i].count = 0;
}
for (i = 0; i < horizontalNodeCount; i += 1) for (i = 0; i < horizontalNodeCount; i += 1)
{ {
cloth->nodeIndices[i] = malloc(sizeof(uint64_t) * cloth->verticalNodeCount); cloth->nodeIndices[i] = malloc(sizeof(uint64_t) * cloth->verticalNodeCount);
@ -534,6 +726,10 @@ double Silkworm_CreateCloth(double xPosition, double yPosition, double horizonta
cloth->triangles[triangleIndex]->cHorizontalIndex = i; cloth->triangles[triangleIndex]->cHorizontalIndex = i;
cloth->triangles[triangleIndex]->cVerticalIndex = j + 1; cloth->triangles[triangleIndex]->cVerticalIndex = j + 1;
NodeTriangleHashTable_Insert(&cloth->nodeHash, context->nodes[cloth->nodeIndices[i][j]], triangleIndex);
NodeTriangleHashTable_Insert(&cloth->nodeHash, context->nodes[cloth->nodeIndices[i + 1][j]], triangleIndex);
NodeTriangleHashTable_Insert(&cloth->nodeHash, context->nodes[cloth->nodeIndices[i][j + 1]], triangleIndex);
triangleIndex += 1; triangleIndex += 1;
} }
@ -555,6 +751,10 @@ double Silkworm_CreateCloth(double xPosition, double yPosition, double horizonta
cloth->triangles[triangleIndex]->cHorizontalIndex = i; cloth->triangles[triangleIndex]->cHorizontalIndex = i;
cloth->triangles[triangleIndex]->cVerticalIndex = j - 1; cloth->triangles[triangleIndex]->cVerticalIndex = j - 1;
NodeTriangleHashTable_Insert(&cloth->nodeHash, context->nodes[cloth->nodeIndices[i][j]], triangleIndex);
NodeTriangleHashTable_Insert(&cloth->nodeHash, context->nodes[cloth->nodeIndices[i - 1][j]], triangleIndex);
NodeTriangleHashTable_Insert(&cloth->nodeHash, context->nodes[cloth->nodeIndices[i][j - 1]], triangleIndex);
triangleIndex += 1; triangleIndex += 1;
} }
} }
@ -731,6 +931,31 @@ double Silkworm_ClothFillTriangleBuffer(double clothId, double leftUV, double wi
return (double)triangleCount; return (double)triangleCount;
} }
void Silkworm_DestroyNodesInRadius(double x, double y, double radius)
{
/* TODO: spatial hash implementation */
uint32_t i;
for (i = 0; i < context->nodeCount; i += 1)
{
Silkworm_Node* node = context->nodes[i];
if (node != NULL)
{
float xDistance = (float)fabs((float)x - node->position.x);
float yDistance = (float)fabs((float)y - node->position.y);
float squareDistance = xDistance * xDistance + yDistance * yDistance;
if (squareDistance <= radius * radius)
{
Silkworm_DestroyNode(i);
}
}
}
}
void Silkworm_ClearAll() void Silkworm_ClearAll()
{ {
uint32_t i; uint32_t i;

View File

@ -43,90 +43,6 @@
extern "C" { extern "C" {
#endif /* __cplusplus */ #endif /* __cplusplus */
typedef struct Silkworm_Vector2
{
float x;
float y;
} Silkworm_Vector2;
typedef struct Silkworm_Link Silkworm_Link;
typedef struct Silkworm_Node
{
uint64_t id;
Silkworm_Vector2 position;
Silkworm_Vector2 previousPosition;
Silkworm_Vector2 velocity;
Silkworm_Vector2 acceleration;
float mass;
float friction;
float radius;
float pinned;
float pushFactor;
bool destroyable;
bool markedForDestroy; /* mutual recursion on nodes/links so this makes it easier to track destroys */
Silkworm_Link** links;
uint32_t linkCount;
} Silkworm_Node;
struct Silkworm_Link
{
uint64_t id;
Silkworm_Node *a;
Silkworm_Node *b;
float distance;
float tearThreshold;
bool markedForDestroy; /* mutual recursion on nodes/links so this makes it easier to track destroys */
};
typedef enum Silkworm_ClothTriangleOrientation
{
UpperLeft,
BottomRight
} Silkworm_ClothTriangleOrientation;
typedef struct Silkworm_Triangle
{
uint64_t id;
Silkworm_Node* a;
Silkworm_Node* b;
Silkworm_Node* c;
uint32_t aHorizontalIndex;
uint32_t bHorizontalIndex;
uint32_t cHorizontalIndex;
uint32_t aVerticalIndex;
uint32_t bVerticalIndex;
uint32_t cVerticalIndex;
Silkworm_ClothTriangleOrientation orientation;
} Silkworm_Triangle;
typedef struct Silkworm_Cloth
{
uint64_t id;
float windFactor;
uint32_t horizontalNodeCount;
uint32_t verticalNodeCount;
uint64_t **nodeIndices; /* x by y grid of indices */
Silkworm_Triangle **triangles; /* array of pointers so we can use NULL */
uint32_t triangleCount;
} Silkworm_Cloth;
typedef struct Silkworm_Rope
{
uint32_t nodeCount;
uint32_t *nodeIndices;
} Silkworm_Rope;
/* Version API */ /* Version API */
#define SILKWORM_ABI_VERSION 0 #define SILKWORM_ABI_VERSION 0
@ -148,7 +64,6 @@ SILKWORMAPI double Silkworm_CreateNode(double xPosition, double yPosition, doubl
SILKWORMAPI void Silkworm_NodeSetDestroyable(double nodeId); SILKWORMAPI void Silkworm_NodeSetDestroyable(double nodeId);
SILKWORMAPI double Silkworm_CreateLink(double aId, double bId, double distance, double tearThreshold); SILKWORMAPI double Silkworm_CreateLink(double aId, double bId, double distance, double tearThreshold);
SILKWORMAPI double Silkworm_CreateCloth(double xPosition, double yPosition, double horizontalNodeCount, double verticalNodeCount, double mass, double friction, double windFactor, double tearThreshold); SILKWORMAPI double Silkworm_CreateCloth(double xPosition, double yPosition, double horizontalNodeCount, double verticalNodeCount, double mass, double friction, double windFactor, double tearThreshold);
@ -161,6 +76,9 @@ SILKWORMAPI void Silkworm_SetTriangleBuffer(const char* bufferId);
SILKWORMAPI double Silkworm_ClothFillTriangleBuffer(double clothId, double leftUV, double widthUV, double topUV, double heightUV); SILKWORMAPI double Silkworm_ClothFillTriangleBuffer(double clothId, double leftUV, double widthUV, double topUV, double heightUV);
SILKWORMAPI void Silkworm_DestroyNode(double nodeId); SILKWORMAPI void Silkworm_DestroyNode(double nodeId);
SILKWORMAPI void Silkworm_DestroyNodesInRadius(double x, double y, double radius);
SILKWORMAPI void Silkworm_ClearAll(); SILKWORMAPI void Silkworm_ClearAll();
#endif /* SILKWORM_H */ #endif /* SILKWORM_H */