rope tech

main
cosmonaut 2021-09-29 20:12:33 -07:00
parent b96860705d
commit 0c0d1b67f5
2 changed files with 342 additions and 54 deletions

View File

@ -29,12 +29,33 @@
#include <stdlib.h>
#include <string.h>
#define PI 3.14159265358979323846
typedef struct Silkworm_Vector2
{
float x;
float y;
} Silkworm_Vector2;
static inline Silkworm_Vector2 Vector2_Rotate(Silkworm_Vector2 vector, float angle)
{
Silkworm_Vector2 rotated;
rotated.x = vector.x * cosf(angle) - vector.y * sinf(angle);
rotated.y = vector.x * sinf(angle) + vector.y * cosf(angle);
return rotated;
}
static inline Silkworm_Vector2 Vector2_Normalize(Silkworm_Vector2 vector)
{
float length = sqrtf(vector.x * vector.x + vector.y * vector.y);
Silkworm_Vector2 normalized;
normalized.x = vector.x / length;
normalized.y = vector.y / length;
return normalized;
}
typedef struct Silkworm_Link Silkworm_Link;
typedef struct Silkworm_Node
@ -275,9 +296,16 @@ typedef struct Silkworm_Cloth
typedef struct Silkworm_Rope
{
uint64_t id;
uint64_t* nodeIndices;
uint32_t nodeCount;
uint32_t* nodeIndices;
float windFactor;
float nodeMass;
float tearThreshold;
float friction;
float pushFactor;
} Silkworm_Rope;
typedef struct Silkworm_Color
@ -298,7 +326,9 @@ typedef struct Silkworm_Context
Silkworm_Cloth** cloths;
uint32_t clothCount;
uint32_t clothCapacity;
Silkworm_Rope** ropes;
uint32_t ropeCount;
uint64_t* nodeIndexStack;
uint32_t nodeIndexStackCount;
@ -312,6 +342,10 @@ typedef struct Silkworm_Context
uint32_t clothIndexStackCount;
uint32_t clothIndexStackCapacity;
uint64_t* ropeIndexStack;
uint32_t ropeIndexStackCount;
uint32_t ropeIndexStackCapacity;
float gravity;
float xBound;
float yBound;
@ -346,6 +380,9 @@ void Silkworm_Init()
context->cloths = NULL;
context->clothCount = 0;
context->ropes = NULL;
context->ropeCount = 0;
context->nodeIndexStackCapacity = 16;
context->nodeIndexStack = malloc(sizeof(uint64_t) * context->nodeIndexStackCapacity);
context->nodeIndexStackCount = 0;
@ -358,6 +395,10 @@ void Silkworm_Init()
context->clothIndexStack = malloc(sizeof(uint64_t) * context->clothIndexStackCapacity);
context->clothIndexStackCount = 0;
context->ropeIndexStackCapacity = 16;
context->ropeIndexStack = malloc(sizeof(uint64_t) * context->ropeIndexStackCapacity);
context->ropeIndexStackCount = 0;
context->gravity = 200;
context->xBound = 1000;
context->yBound = 1000;
@ -434,61 +475,64 @@ void Silkworm_Internal_DestroyCloth(Silkworm_Cloth* cloth)
{
uint32_t i, j;
context->cloths[cloth->id] = NULL;
for (i = 0; i < NUM_NODE_TRIANGLE_HASH_BUCKETS; i += 1)
if (cloth != NULL)
{
for (j = 0; j < cloth->nodeHash.buckets[i].count; j += 1)
context->cloths[cloth->id] = NULL;
for (i = 0; i < NUM_NODE_TRIANGLE_HASH_BUCKETS; i += 1)
{
free(cloth->nodeHash.buckets[i].elements[j].indexArray);
for (j = 0; j < cloth->nodeHash.buckets[i].count; j += 1)
{
free(cloth->nodeHash.buckets[i].elements[j].indexArray);
}
if (cloth->nodeHash.buckets[i].elements != NULL)
{
free(cloth->nodeHash.buckets[i].elements);
}
}
if (cloth->nodeHash.buckets[i].elements != NULL)
for (i = 0; i < NUM_LINK_TRIANGLE_HASH_BUCKETS; i += 1)
{
free(cloth->nodeHash.buckets[i].elements);
for (j = 0; j < cloth->linkHash.buckets[i].count; j += 1)
{
free(cloth->linkHash.buckets[i].elements[j].indexArray);
}
if (cloth->linkHash.buckets[i].elements != NULL)
{
free(cloth->linkHash.buckets[i].elements);
}
}
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);
for (i = 0; i < cloth->triangleCount; i += 1)
{
if (cloth->triangles[i] != NULL)
{
free(cloth->triangles[i]);
}
}
free(cloth->triangles);
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;
free(cloth);
}
for (i = 0; i < NUM_LINK_TRIANGLE_HASH_BUCKETS; i += 1)
{
for (j = 0; j < cloth->linkHash.buckets[i].count; j += 1)
{
free(cloth->linkHash.buckets[i].elements[j].indexArray);
}
if (cloth->linkHash.buckets[i].elements != NULL)
{
free(cloth->linkHash.buckets[i].elements);
}
}
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);
for (i = 0; i < cloth->triangleCount; i += 1)
{
if (cloth->triangles[i] != NULL)
{
free(cloth->triangles[i]);
}
}
free(cloth->triangles);
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;
free(cloth);
}
void Silkworm_DestroyCloth(double clothId)
@ -859,7 +903,7 @@ double Silkworm_CreateCloth(double xPosition, double yPosition, double width, do
for (j = 0; j < cloth->verticalNodeCount; j += 1)
{
uint64_t nodeId = (uint64_t) Silkworm_CreateNode(xPosition + i * context->clothDensity, yPosition + j * context->clothDensity, mass, friction, 1, 0.5);
uint64_t nodeId = (uint64_t) Silkworm_CreateNode(xPosition + i * context->clothDensity, yPosition + j * context->clothDensity, mass, friction, 1, 1.0);
cloth->nodeIndices[i][j] = nodeId;
@ -1179,6 +1223,234 @@ double Silkworm_ClothFillTriangleBuffer(double clothId, double leftUV, double wi
return (double)triangleCount * 3;
}
Silkworm_Rope* LookupRope(double ropeId)
{
return context->ropes[(uint32_t)ropeId];
}
double Silkworm_RopeAddNode(double ropeId, double xPosition, double yPosition, double length)
{
Silkworm_Rope *rope = LookupRope(ropeId);
double nodeId = Silkworm_CreateNode(xPosition, yPosition, rope->nodeMass, rope->friction, 1.0, rope->pushFactor);
rope->nodeIndices = realloc(rope->nodeIndices, sizeof(uint64_t) * (rope->nodeCount + 1));
rope->nodeIndices[rope->nodeCount] = nodeId;
rope->nodeCount += 1;
Silkworm_Node* node = LookupNode((uint64_t)nodeId);
node->destroyable = false;
Silkworm_CreateLink((double)rope->nodeIndices[rope->nodeCount - 2], (double)rope->nodeIndices[rope->nodeCount - 1], length, rope->tearThreshold);
return nodeId;
}
double Silkworm_RopeCreate(double xPosition, double yPosition, double mass, double friction, double windFactor, double pushFactor, double tearThreshold)
{
Silkworm_Rope* rope = malloc(sizeof(Silkworm_Rope));
uint64_t id;
if (context->ropeIndexStackCount > 0)
{
id = context->ropeIndexStack[context->ropeIndexStackCount - 1];
context->ropeIndexStackCount -= 1;
context->ropes[id] = rope;
}
else
{
id = context->ropeCount;
context->ropes = realloc(context->ropes, sizeof(Silkworm_Rope*) * (context->ropeCount + 1));
context->ropes[id] = rope;
context->ropeCount += 1;
}
rope->id = id;
rope->nodeMass = mass;
rope->friction = friction;
rope->windFactor = windFactor;
rope->tearThreshold = tearThreshold;
rope->pushFactor = pushFactor;
// TODO: create first node here
rope->nodeIndices = malloc(sizeof(uint64_t));
rope->nodeCount = 1;
rope->nodeIndices[0] = Silkworm_CreateNode(xPosition, yPosition, rope->nodeMass, rope->friction, 1.0, rope->pushFactor);
Silkworm_Node* node = LookupNode(rope->nodeIndices[0]);
node->pinned = true;
node->destroyable = false;
return (double)rope->id;
}
void Silkworm_RopeDestroy(double ropeId)
{
uint32_t i;
Silkworm_Rope *rope = LookupRope(ropeId);
if (rope != NULL)
{
if (context->ropeIndexStackCount >= context->ropeIndexStackCapacity)
{
context->ropeIndexStackCapacity *= 2;
context->ropeIndexStack = realloc(context->ropeIndexStack, sizeof(uint64_t) * context->ropeIndexStackCapacity);
}
context->ropeIndexStack[context->ropeIndexStackCount] = rope->id;
context->ropeIndexStackCount += 1;
for (i = 0; i < rope->nodeCount; i += 1)
{
Silkworm_DestroyNode((double)rope->nodeIndices[i]);
}
free(rope->nodeIndices);
}
}
double Silkworm_RopeRequiredBufferSize(double ropeId)
{
Silkworm_Rope* rope = LookupRope(ropeId);
return (double)(rope->nodeCount - 1) * 6 * (sizeof(Silkworm_Vector2) + sizeof(Silkworm_Color) + (sizeof(float) * 2));
}
double Silkworm_RopeFillBuffer(double ropeId, double width, double leftUV, double widthUV, double topUV, double heightUV)
{
uint32_t i, vertexCount;
Silkworm_Rope* rope = LookupRope(ropeId);
uint8_t* bufferAddress = context->currentBufferAddress;
Silkworm_Color color;
color.r = 255;
color.g = 255;
color.b = 255;
color.a = 255;
vertexCount = 0;
for (i = 0; i < rope->nodeCount - 1; i += 1)
{
Silkworm_Node* nodeOne = LookupNode(rope->nodeIndices[i]);
Silkworm_Node* nodeTwo = LookupNode(rope->nodeIndices[i + 1]);
Silkworm_Vector2 forwardDirection;
forwardDirection.x = nodeTwo->position.x - nodeOne->position.x;
forwardDirection.y = nodeTwo->position.y - nodeOne->position.y;
float forwardLength = sqrtf(forwardDirection.x * forwardDirection.x + forwardDirection.y * forwardDirection.y);
forwardDirection = Vector2_Normalize(forwardDirection);
Silkworm_Vector2 upDirection = Vector2_Rotate(forwardDirection, PI / 2);
Silkworm_Vector2 topLeft;
topLeft.x = nodeOne->position.x + upDirection.x * width / 2;
topLeft.y = nodeOne->position.y + upDirection.y * width / 2;
Silkworm_Vector2 bottomLeft;
bottomLeft.x = nodeOne->position.x - upDirection.x * width / 2;
bottomLeft.y = nodeOne->position.y - upDirection.y * width / 2;
Silkworm_Vector2 topRight;
topRight.x = topLeft.x + forwardDirection.x * forwardLength;
topRight.y = topLeft.y + forwardDirection.y * forwardLength;
Silkworm_Vector2 bottomRight;
bottomRight.x = bottomLeft.x + forwardDirection.x * forwardLength;
bottomRight.y = bottomLeft.y + forwardDirection.y * forwardLength;
float uvLeft = (float)leftUV;
float uvRight = (float)leftUV + (float)widthUV;
float uvTop = (float)topUV;
float uvBottom = (float)topUV + (float)heightUV;
/* top left triangle */
memcpy(bufferAddress, &topLeft, sizeof(Silkworm_Vector2));
bufferAddress += sizeof(Silkworm_Vector2);
memcpy(bufferAddress, &color, sizeof(Silkworm_Color));
bufferAddress += sizeof(Silkworm_Color);
memcpy(bufferAddress, &uvLeft, sizeof(float));
bufferAddress += sizeof(float);
memcpy(bufferAddress, &uvTop, sizeof(float));
bufferAddress += sizeof(float);
memcpy(bufferAddress, &topRight, sizeof(Silkworm_Vector2));
bufferAddress += sizeof(Silkworm_Vector2);
memcpy(bufferAddress, &color, sizeof(Silkworm_Color));
bufferAddress += sizeof(Silkworm_Color);
memcpy(bufferAddress, &uvRight, sizeof(float));
bufferAddress += sizeof(float);
memcpy(bufferAddress, &uvTop, sizeof(float));
bufferAddress += sizeof(float);
memcpy(bufferAddress, &bottomLeft, sizeof(Silkworm_Vector2));
bufferAddress += sizeof(Silkworm_Vector2);
memcpy(bufferAddress, &color, sizeof(Silkworm_Color));
bufferAddress += sizeof(Silkworm_Color);
memcpy(bufferAddress, &uvLeft, sizeof(float));
bufferAddress += sizeof(float);
memcpy(bufferAddress, &uvBottom, sizeof(float));
bufferAddress += sizeof(float);
/* bottom right triangle */
memcpy(bufferAddress, &bottomLeft, sizeof(Silkworm_Vector2));
bufferAddress += sizeof(Silkworm_Vector2);
memcpy(bufferAddress, &color, sizeof(Silkworm_Color));
bufferAddress += sizeof(Silkworm_Color);
memcpy(bufferAddress, &uvLeft, sizeof(float));
bufferAddress += sizeof(float);
memcpy(bufferAddress, &uvBottom, sizeof(float));
bufferAddress += sizeof(float);
memcpy(bufferAddress, &topRight, sizeof(Silkworm_Vector2));
bufferAddress += sizeof(Silkworm_Vector2);
memcpy(bufferAddress, &color, sizeof(Silkworm_Color));
bufferAddress += sizeof(Silkworm_Color);
memcpy(bufferAddress, &uvRight, sizeof(float));
bufferAddress += sizeof(float);
memcpy(bufferAddress, &uvTop, sizeof(float));
bufferAddress += sizeof(float);
memcpy(bufferAddress, &bottomRight, sizeof(Silkworm_Vector2));
bufferAddress += sizeof(Silkworm_Vector2);
memcpy(bufferAddress, &color, sizeof(Silkworm_Color));
bufferAddress += sizeof(Silkworm_Color);
memcpy(bufferAddress, &uvRight, sizeof(float));
bufferAddress += sizeof(float);
memcpy(bufferAddress, &uvBottom, sizeof(float));
bufferAddress += sizeof(float);
vertexCount += 6;
}
return (double)vertexCount;
}
/* in bytes */
double Silkworm_GetEditorBufferRequiredSize()
{
@ -1404,8 +1676,8 @@ void Silkworm_PushNodesInRadius(double x, double y, double radius, double xDirec
if (squareDistance <= radius * radius)
{
node->position.x += (float)xDirection;
node->position.y += (float)yDirection;
node->position.x += (float)xDirection * node->pushFactor;
node->position.y += (float)yDirection * node->pushFactor;
}
}
}
@ -1597,6 +1869,14 @@ void Silkworm_ClearAll()
}
}
for (i = 0; i < context->ropeCount; i += 1)
{
if (context->ropes[i] != NULL)
{
Silkworm_RopeDestroy((double)i);
}
}
Silkworm_PerformDestroys();
}
@ -1607,10 +1887,12 @@ void Silkworm_Finish()
free(context->nodes);
free(context->links);
free(context->cloths);
free(context->ropes);
free(context->nodeIndexStack);
free(context->linkIndexStack);
free(context->clothIndexStack);
free(context->ropeIndexStack);
free(context->nodeDestructionData);
free(context->linkDestructionData);

View File

@ -79,6 +79,12 @@ SILKWORMAPI void Silkworm_DestroyCloth(double clothId);
SILKWORMAPI double Silkworm_ClothFillTriangleBuffer(double clothId, double leftUV, double widthUV, double topUV, double heightUV);
SILKWORMAPI double Silkworm_RopeCreate(double xPosition, double yPosition, double mass, double friction, double windFactor, double pushFactor, double tearThreshold);
SILKWORMAPI double Silkworm_RopeAddNode(double ropeId, double xPosition, double yPosition, double length);
SILKWORMAPI void Silkworm_RopeDestroy(double ropeId);
SILKWORMAPI double Silkworm_RopeRequiredBufferSize(double ropeId);
SILKWORMAPI double Silkworm_RopeFillBuffer(double ropeId, double width, double leftUV, double widthUV, double topUV, double heightUV);
SILKWORMAPI double Silkworm_GetEditorBufferRequiredSize();
SILKWORMAPI double Silkworm_FillEditorBuffer();