bunch of new cloth API stuff

main
cosmonaut 2021-09-23 14:41:15 -07:00
parent 7fe8190a0e
commit a479c66969
2 changed files with 281 additions and 77 deletions

View File

@ -47,18 +47,19 @@ typedef struct Silkworm_Context
Silkworm_Cloth** cloths; Silkworm_Cloth** cloths;
uint32_t clothCount; uint32_t clothCount;
uint32_t clothCapacity;
uint64_t* nodeIndicesToDestroy;
uint32_t nodeIndicesToDestroyCount;
uint64_t* linkIndicesToDestroy;
uint32_t linkIndicesToDestroyCount;
uint64_t* nodeIndexStack; uint64_t* nodeIndexStack;
uint32_t nodeIndexStackCount; uint32_t nodeIndexStackCount;
uint32_t nodeIndexStackCapacity;
uint64_t* linkIndexStack; uint64_t* linkIndexStack;
uint32_t linkIndexStackCount; uint32_t linkIndexStackCount;
uint32_t linkIndexStackCapacity;
uint64_t* clothIndexStack;
uint32_t clothIndexStackCount;
uint32_t clothIndexStackCapacity;
float gravity; float gravity;
float xBound; float xBound;
@ -78,30 +79,167 @@ void Silkworm_Init()
context->nodes = NULL; context->nodes = NULL;
context->nodeCount = 0; context->nodeCount = 0;
context->links = NULL; context->links = NULL;
context->linkCount = 0; context->linkCount = 0;
context->nodeIndicesToDestroy = NULL;
context->nodeIndicesToDestroyCount = 0;
context->linkIndicesToDestroy = NULL;
context->linkIndicesToDestroyCount = 0;
context->nodeIndexStack = NULL;
context->nodeIndexStackCount = 0;
context->linkIndexStack = NULL;
context->linkIndexStackCount = 0;
context->cloths = NULL; context->cloths = NULL;
context->clothCount = 0; context->clothCount = 0;
context->nodeIndexStackCapacity = 16;
context->nodeIndexStack = malloc(sizeof(uint64_t) * context->nodeIndexStackCapacity);
context->nodeIndexStackCount = 0;
context->linkIndexStackCapacity = 16;
context->linkIndexStack = malloc(sizeof(uint64_t) * context->linkIndexStackCapacity);
context->linkIndexStackCount = 0;
context->clothIndexStackCapacity = 16;
context->clothIndexStack = malloc(sizeof(uint64_t) * context->clothIndexStackCapacity);
context->clothIndexStackCount = 0;
context->gravity = 200; context->gravity = 200;
context->xBound = 1000; context->xBound = 1000;
context->yBound = 1000; context->yBound = 1000;
context->clothDensity = 4; context->clothDensity = 4;
} }
static inline Silkworm_Node* LookupNode(uint64_t nodeId)
{
return context->nodes[nodeId];
}
static inline Silkworm_Link* LookupLink(uint64_t linkId)
{
return context->links[linkId];
}
static inline Silkworm_Cloth* LookupCloth(uint64_t clothId)
{
return context->cloths[clothId];
}
/* we defer actual destruction to Update to avoid issues with NULL */
void Silkworm_DestroyNode(double nodeId)
{
uint32_t i;
Silkworm_Node* node = LookupNode((uint64_t)nodeId);
if (node != NULL)
{
node->markedForDestroy = true;
for (i = 0; i < node->linkCount; i += 1)
{
if (node->links[i] != NULL)
{
node->links[i]->markedForDestroy = true;
}
}
}
}
void Silkworm_Internal_DestroyLink(Silkworm_Link* link)
{
link->markedForDestroy = true;
}
void Silkworm_DestroyLink(double linkId)
{
Silkworm_Internal_DestroyLink(LookupLink((uint64_t)linkId));
}
void Silkworm_Internal_DestroyCloth(Silkworm_Cloth* cloth)
{
uint32_t i, j;
context->cloths[cloth->id] = NULL;
for (i = 0; i < cloth->horizontalNodeCount; i += 1)
{
for (j = 0; j < cloth->verticalNodeCount; j += 1)
{
Silkworm_DestroyNode((double)cloth->nodeIndices[i][j]);
}
free(cloth->nodeIndices[i]);
}
free(cloth->nodeIndices);
free(cloth);
if (context->clothIndexStackCount >= context->clothIndexStackCapacity)
{
context->clothIndexStackCapacity *= 2;
context->nodeIndexStack = realloc(context->nodeIndexStack, sizeof(uint64_t) * context->nodeIndexStackCapacity);
}
context->clothIndexStack[context->clothIndexStackCount] = cloth->id;
context->clothIndexStackCount += 1;
}
void Silkworm_DestroyCloth(double clothId)
{
Silkworm_Internal_DestroyCloth(LookupCloth((uint64_t)clothId));
}
void Silkworm_PerformDestroys()
{
uint32_t i, j;
for (i = 0; i < context->linkCount; i += 1)
{
if (context->links[i] != NULL && context->links[i]->markedForDestroy)
{
for (j = 0; j < context->links[i]->a->linkCount; j += 1)
{
if (context->links[i]->a->links[j] == context->links[i])
{
context->links[i]->a->links[j] = NULL;
}
}
for (j = 0; j < context->links[i]->b->linkCount; j += 1)
{
if (context->links[i]->b->links[j] == context->links[i])
{
context->links[i]->b->links[j] = NULL;
}
}
free(context->links[i]);
context->links[i] = NULL;
if (context->linkIndexStackCount >= context->linkIndexStackCapacity)
{
context->linkIndexStackCapacity *= 2;
context->linkIndexStack = realloc(context->linkIndexStack, sizeof(uint64_t) * context->linkIndexStackCapacity);
}
context->linkIndexStack[context->linkIndexStackCount] = i;
context->linkIndexStackCount += 1;
}
}
for (i = 0; i < context->nodeCount; i += 1)
{
if (context->nodes[i] != NULL && context->nodes[i]->markedForDestroy)
{
free(context->nodes[i]->links);
free(context->nodes[i]);
context->nodes[i] = NULL;
if (context->nodeIndexStackCount >= context->nodeIndexStackCapacity)
{
context->nodeIndexStackCapacity *= 2;
context->nodeIndexStack = realloc(context->nodeIndexStack, sizeof(uint64_t) * context->nodeIndexStackCapacity);
}
context->nodeIndexStack[context->nodeIndexStackCount] = i;
context->nodeIndexStackCount += 1;
}
}
}
void Silkworm_Update(double deltaTime) void Silkworm_Update(double deltaTime)
{ {
uint32_t i, j; uint32_t i, j;
@ -131,9 +269,7 @@ void Silkworm_Update(double deltaTime)
if (distanceMoved > link->tearThreshold) if (distanceMoved > link->tearThreshold)
{ {
context->linkIndicesToDestroy = realloc(context->linkIndicesToDestroy, sizeof(uint64_t) * (context->linkIndicesToDestroyCount + 1)); Silkworm_DestroyLink((double)link->id);
context->linkIndicesToDestroy[context->linkIndicesToDestroyCount] = link->id;
context->linkIndicesToDestroyCount += 1;
} }
else else
{ {
@ -151,7 +287,6 @@ void Silkworm_Update(double deltaTime)
} }
} }
} }
} }
for (j = 0; j < context->nodeCount; j += 1) for (j = 0; j < context->nodeCount; j += 1)
@ -179,50 +314,13 @@ void Silkworm_Update(double deltaTime)
if (fabs(node->position.x) > context->xBound || fabs(node->position.x) > context->yBound) if (fabs(node->position.x) > context->xBound || fabs(node->position.x) > context->yBound)
{ {
context->nodeIndicesToDestroy = realloc(context->nodeIndicesToDestroy, sizeof(uint64_t) * (context->nodeIndicesToDestroyCount + 1)); Silkworm_DestroyNode((double)node->id);
context->nodeIndicesToDestroy[context->nodeIndicesToDestroyCount] = node->id;
context->nodeIndicesToDestroyCount += 1;
} }
} }
} }
} }
for (j = 0; j < context->nodeIndicesToDestroyCount; j += 1) Silkworm_PerformDestroys();
{
uint64_t nodeIndex = context->nodeIndicesToDestroy[j];
free(context->nodes[nodeIndex]);
context->nodes[nodeIndex] = NULL;
context->nodeIndexStack = realloc(context->nodeIndexStack, sizeof(uint64_t) * (context->nodeIndexStackCount + 1));
context->nodeIndexStack[context->nodeIndexStackCount] = nodeIndex;
context->nodeIndexStackCount += 1;
}
for (j = 0; j < context->linkIndicesToDestroyCount; j += 1)
{
uint64_t linkIndex = context->linkIndicesToDestroy[j];
free(context->links[linkIndex]);
context->links[linkIndex] = NULL;
context->linkIndexStack = realloc(context->linkIndexStack, sizeof(uint64_t) * (context->linkIndexStackCount + 1));
context->linkIndexStack[context->linkIndexStackCount] = linkIndex;
context->linkIndexStackCount += 1;
}
context->nodeIndicesToDestroyCount = 0;
context->linkIndicesToDestroyCount = 0;
}
static inline Silkworm_Node* LookupNode(double nodeId)
{
return context->nodes[(uint64_t)nodeId];
}
static inline Silkworm_Cloth* LookupCloth(double clothId)
{
return context->cloths[(uint64_t)clothId];
} }
double Silkworm_CreateNode(double xPosition, double yPosition, double mass, double friction, double radius, double pushFactor) double Silkworm_CreateNode(double xPosition, double yPosition, double mass, double friction, double radius, double pushFactor)
@ -233,20 +331,18 @@ double Silkworm_CreateNode(double xPosition, double yPosition, double mass, doub
if (context->nodeIndexStackCount > 0) if (context->nodeIndexStackCount > 0)
{ {
id = context->nodeIndexStack[context->nodeIndexStackCount - 1]; id = context->nodeIndexStack[context->nodeIndexStackCount - 1];
context->nodeIndexStack = realloc(context->nodeIndexStack, sizeof(uint64_t) * (context->nodeIndexStackCount - 1));
context->nodeIndexStackCount -= 1; context->nodeIndexStackCount -= 1;
context->nodes[id] = node;
} }
else else
{ {
id = context->nodeCount; id = context->nodeCount;
context->nodes = realloc(context->nodes, sizeof(Silkworm_Node*) * (context->nodeCount + 1)); context->nodes = realloc(context->nodes, sizeof(Silkworm_Node*) * (context->nodeCount + 1));
context->nodes[context->nodeCount] = node;
context->nodeCount += 1; context->nodeCount += 1;
} }
context->nodes[id] = node;
node->id = id; node->id = id;
node->position.x = (float)xPosition; node->position.x = (float)xPosition;
node->position.y = (float)yPosition; node->position.y = (float)yPosition;
@ -262,6 +358,9 @@ double Silkworm_CreateNode(double xPosition, double yPosition, double mass, doub
node->pushFactor = (float)pushFactor; node->pushFactor = (float)pushFactor;
node->pinned = false; node->pinned = false;
node->destroyable = false; node->destroyable = false;
node->markedForDestroy = false;
node->links = NULL;
node->linkCount = 0;
return (double)node->id; return (double)node->id;
} }
@ -295,6 +394,29 @@ void Silkworm_ClothNodeUnpin(double clothId, double i, double j)
context->nodes[cloth->nodeIndices[(uint64_t)i][(uint64_t)j]]->pinned = false; context->nodes[cloth->nodeIndices[(uint64_t)i][(uint64_t)j]]->pinned = false;
} }
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) double Silkworm_CreateLink(double aId, double bId, double distance, double tearThreshold)
{ {
Silkworm_Node *nodeA = LookupNode(aId); Silkworm_Node *nodeA = LookupNode(aId);
@ -307,25 +429,32 @@ double Silkworm_CreateLink(double aId, double bId, double distance, double tearT
if (context->linkIndexStackCount > 0) if (context->linkIndexStackCount > 0)
{ {
id = context->linkIndexStack[context->linkIndexStackCount - 1]; id = context->linkIndexStack[context->linkIndexStackCount - 1];
context->linkIndexStack = realloc(context->linkIndexStack, sizeof(uint64_t) * (context->linkIndexStackCount - 1));
context->linkIndexStackCount -= 1; context->linkIndexStackCount -= 1;
context->links[id] = link;
} }
else else
{ {
id = context->linkCount; id = context->linkCount;
context->links = realloc(context->links, sizeof(Silkworm_Link*) * (context->linkCount + 1)); context->links = realloc(context->links, sizeof(Silkworm_Link*) * (context->linkCount + 1));
context->links[context->linkCount] = link;
context->linkCount += 1; context->linkCount += 1;
} }
context->links[id] = link;
link->id = id; link->id = id;
link->a = nodeA; link->a = nodeA;
link->b = nodeB; link->b = nodeB;
link->distance = (float)distance; link->distance = (float)distance;
link->tearThreshold = (float)tearThreshold; link->tearThreshold = (float)tearThreshold;
link->markedForDestroy = false;
link->a->links = realloc(link->a->links, sizeof(Silkworm_Link*) * (link->a->linkCount + 1));
link->a->links[link->a->linkCount] = link;
link->a->linkCount += 1;
link->b->links = realloc(link->b->links, sizeof(Silkworm_Link*) * (link->b->linkCount + 1));
link->b->links[link->b->linkCount] = link;
link->b->linkCount += 1;
return (double)link->id; return (double)link->id;
} }
@ -341,10 +470,25 @@ double Silkworm_CreateCloth(double xPosition, double yPosition, double horizonta
cloth->verticalNodeCount = (uint32_t) verticalNodeCount; cloth->verticalNodeCount = (uint32_t) verticalNodeCount;
cloth->nodeIndices = malloc(sizeof(uint64_t*) * cloth->horizontalNodeCount); cloth->nodeIndices = malloc(sizeof(uint64_t*) * cloth->horizontalNodeCount);
cloth->id = context->clothCount; uint64_t id;
if (context->clothIndexStackCount > 0)
{
id = context->clothIndexStack[context->clothIndexStackCount - 1];
context->clothIndexStackCount -= 1;
context->cloths[id] = cloth;
}
else
{
id = context->clothCount;
context->cloths = realloc(context->cloths, sizeof(Silkworm_Cloth*) * (context->clothCount + 1)); context->cloths = realloc(context->cloths, sizeof(Silkworm_Cloth*) * (context->clothCount + 1));
context->cloths[context->clothCount] = cloth; context->cloths[id] = cloth;
context->clothCount += 1; context->clothCount += 1;
}
cloth->id = id;
for (i = 0; i < horizontalNodeCount; i += 1) for (i = 0; i < horizontalNodeCount; i += 1)
{ {
@ -437,6 +581,35 @@ double Silkworm_CreateCloth(double xPosition, double yPosition, double horizonta
return (double)cloth->id; return (double)cloth->id;
} }
void Silkworm_ApplyWind(double xSpeed, double ySpeed)
{
uint32_t i, j, k;
Silkworm_Cloth* cloth;
Silkworm_Node* node;
for (i = 0; i < context->clothCount; i += 1)
{
if (context->cloths[i] != NULL)
{
cloth = context->cloths[i];
for (j = 0; j < cloth->horizontalNodeCount; j += 1)
{
for (k = 0; k < cloth->verticalNodeCount; k += 1)
{
node = context->nodes[cloth->nodeIndices[j][k]];
if (node != NULL && !node->pinned)
{
node->position.x += (float)xSpeed * 0.05f * cloth->windFactor;
node->position.y += (float)ySpeed * 0.05f * cloth->windFactor;
}
}
}
}
}
}
void Silkworm_SetTriangleBuffer(const char* bufferId) void Silkworm_SetTriangleBuffer(const char* bufferId)
{ {
context->currentBufferAddress = (uint8_t*)bufferId; context->currentBufferAddress = (uint8_t*)bufferId;
@ -557,3 +730,18 @@ double Silkworm_ClothFillTriangleBuffer(double clothId, double leftUV, double wi
return (double)triangleCount; return (double)triangleCount;
} }
void Silkworm_ClearAll()
{
uint32_t i;
for (i = 0; i < context->clothCount; i += 1)
{
if (context->cloths[i] != NULL)
{
Silkworm_Internal_DestroyCloth(context->cloths[i]);
}
}
Silkworm_PerformDestroys();
}

View File

@ -49,6 +49,8 @@ typedef struct Silkworm_Vector2
float y; float y;
} Silkworm_Vector2; } Silkworm_Vector2;
typedef struct Silkworm_Link Silkworm_Link;
typedef struct Silkworm_Node typedef struct Silkworm_Node
{ {
uint64_t id; uint64_t id;
@ -62,16 +64,23 @@ typedef struct Silkworm_Node
float pinned; float pinned;
float pushFactor; float pushFactor;
bool destroyable; 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; } Silkworm_Node;
typedef struct Silkworm_Link struct Silkworm_Link
{ {
uint64_t id; uint64_t id;
Silkworm_Node *a; Silkworm_Node *a;
Silkworm_Node *b; Silkworm_Node *b;
float distance; float distance;
float tearThreshold; float tearThreshold;
} Silkworm_Link;
bool markedForDestroy; /* mutual recursion on nodes/links so this makes it easier to track destroys */
};
typedef enum Silkworm_ClothTriangleOrientation typedef enum Silkworm_ClothTriangleOrientation
{ {
@ -133,18 +142,25 @@ typedef struct Silkworm_Rope
SILKWORMAPI void Silkworm_Init(); SILKWORMAPI void Silkworm_Init();
SILKWORMAPI void Silkworm_Update(double delta); SILKWORMAPI void Silkworm_Update(double delta);
SILKWORMAPI void Silkworm_ApplyWind(double xSpeed, double ySpeed);
SILKWORMAPI double Silkworm_CreateNode(double xPosition, double yPosition, double mass, double friction, double radius, double pushFactor); SILKWORMAPI double Silkworm_CreateNode(double xPosition, double yPosition, double mass, double friction, double radius, double pushFactor);
SILKWORMAPI void Silkworm_NodeSetDestroyable(double nodeId); SILKWORMAPI void Silkworm_NodeSetDestroyable(double nodeId);
SILKWORMAPI void Silkworm_ClothNodePin(double clothId, double i, double j);
SILKWORMAPI void Silkworm_ClothNodeUnpin(double clothId, double i, double j);
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);
SILKWORMAPI void Silkworm_ClothNodePin(double clothId, double i, double j);
SILKWORMAPI void Silkworm_ClothNodeUnpin(double clothId, double i, double j);
SILKWORMAPI void Silkworm_ClothNodeDestroy(double clothId, double i, double j);
SILKWORMAPI void Silkworm_DestroyCloth(double clothId);
SILKWORMAPI void Silkworm_SetTriangleBuffer(const char* bufferId); 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_ClearAll();
#endif /* SILKWORM_H */ #endif /* SILKWORM_H */