node to triangle lookups
parent
a479c66969
commit
2fc8d0a781
259
src/Silkworm.c
259
src/Silkworm.c
|
@ -29,6 +29,174 @@
|
|||
#include <stdlib.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
|
||||
{
|
||||
uint8_t r;
|
||||
|
@ -156,6 +324,15 @@ void Silkworm_Internal_DestroyCloth(Silkworm_Cloth* cloth)
|
|||
|
||||
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 (j = 0; j < cloth->verticalNodeCount; j += 1)
|
||||
|
@ -184,7 +361,7 @@ void Silkworm_DestroyCloth(double clothId)
|
|||
|
||||
void Silkworm_PerformDestroys()
|
||||
{
|
||||
uint32_t i, j;
|
||||
uint32_t i, j, k;
|
||||
|
||||
for (i = 0; i < context->linkCount; i += 1)
|
||||
{
|
||||
|
@ -222,8 +399,32 @@ void Silkworm_PerformDestroys()
|
|||
|
||||
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]);
|
||||
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)
|
||||
{
|
||||
uint32_t iterator;
|
||||
|
||||
Silkworm_Cloth* cloth = LookupCloth(clothId);
|
||||
uint64_t nodeIndex = cloth->nodeIndices[(uint64_t)i][(uint64_t)j];
|
||||
Silkworm_Node* node = context->nodes[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)
|
||||
|
@ -490,6 +676,12 @@ double Silkworm_CreateCloth(double xPosition, double yPosition, double horizonta
|
|||
|
||||
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)
|
||||
{
|
||||
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]->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;
|
||||
}
|
||||
|
||||
|
@ -555,6 +751,10 @@ double Silkworm_CreateCloth(double xPosition, double yPosition, double horizonta
|
|||
cloth->triangles[triangleIndex]->cHorizontalIndex = i;
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
@ -731,6 +931,31 @@ double Silkworm_ClothFillTriangleBuffer(double clothId, double leftUV, double wi
|
|||
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()
|
||||
{
|
||||
uint32_t i;
|
||||
|
|
|
@ -43,90 +43,6 @@
|
|||
extern "C" {
|
||||
#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 */
|
||||
|
||||
#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 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);
|
||||
|
@ -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 void Silkworm_DestroyNode(double nodeId);
|
||||
|
||||
SILKWORMAPI void Silkworm_DestroyNodesInRadius(double x, double y, double radius);
|
||||
|
||||
SILKWORMAPI void Silkworm_ClearAll();
|
||||
|
||||
#endif /* SILKWORM_H */
|
||||
|
|
Loading…
Reference in New Issue