From 0c0d1b67f5c5717751e6e8a6dd1d30c8cdd7e14a Mon Sep 17 00:00:00 2001 From: cosmonaut Date: Wed, 29 Sep 2021 20:12:33 -0700 Subject: [PATCH] rope tech --- src/Silkworm.c | 390 ++++++++++++++++++++++++++++++++++++++++++------- src/Silkworm.h | 6 + 2 files changed, 342 insertions(+), 54 deletions(-) diff --git a/src/Silkworm.c b/src/Silkworm.c index 33dff9c..7598379 100644 --- a/src/Silkworm.c +++ b/src/Silkworm.c @@ -29,12 +29,33 @@ #include #include +#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); diff --git a/src/Silkworm.h b/src/Silkworm.h index 19d9414..898e5ce 100644 --- a/src/Silkworm.h +++ b/src/Silkworm.h @@ -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();