/* Silkworm - Verlet cloth physics in C * * Copyright (c) 2021 Evan Hemsley * * This software is provided 'as-is', without any express or implied warranty. * In no event will the authors be held liable for any damages arising from * the use of this software. * * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software in a * product, an acknowledgment in the product documentation would be * appreciated but is not required. * * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * * 3. This notice may not be removed or altered from any source distribution. * * Evan "cosmonaut" Hemsley * */ #include "Silkworm.h" #include typedef struct Silkworm_Context { Silkworm_Group **groups; uint32_t groupCount; } Silkworm_Context; static Silkworm_Context *context = NULL; #define CONSTRAINT_ITERATION_COUNT 3 /* TODO: make this a parameter? */ void Silkworm_Init() { context = malloc(sizeof(Silkworm_Context)); context->groups = NULL; context->groupCount = 0; } void Silkworm_Update() { int32_t i, j, iteration; Silkworm_Group *group; Silkworm_Link *link; for (iteration = 0; iteration < CONSTRAINT_ITERATION_COUNT; iteration += 1) { for (i = 0; i < context->groupCount; i += 1) { group = context->groups[i]; for (j = 0; j < group->linkCount; j += 1) { link = group->links[j]; double diffX = link->a->position.x - link->b->position.y; double diffY = link->a->position.y - link->b->position.y; double d = sqrt(diffX * diffX + diffY * diffY); double difference = (link->distance - d) / d; double translateX = diffX * 0.5 * difference; double translateY = diffY * 0.5 * difference; double distanceMoved = sqrt(translateX * translateX + translateY * translateY); } } } } double Silkworm_CreateGroup() { context->groups = realloc(context->groups, sizeof(Silkworm_Group*) * (context->groupCount + 1)); Silkworm_Group* group = malloc(sizeof(Silkworm_Group)); group->nodes = NULL; group->nodeCount = 0; group->links = NULL; group->linkCount = 0; context->groups[context->groupCount] = group; context->groupCount += 1; group->id.i = context->groupCount; return group->id.d; } static inline Silkworm_Group* LookupGroup(double groupId) { Silkworm_ID gId; gId.d = groupId; return context->groups[gId.i]; } static inline Silkworm_Node* LookupNode(double groupId, double nodeId) { Silkworm_ID nId; nId.d = nodeId; return LookupGroup(groupId)->nodes[nId.i]; } double Silkworm_CreateNode(double groupId, double xPosition, double yPosition, double mass, double friction, double radius, double pushFactor) { Silkworm_Group *group = LookupGroup(groupId); Silkworm_ID nodeId; nodeId.i = group->nodeCount; Silkworm_Node *node = malloc(sizeof(Silkworm_Node)); node->id = nodeId; node->position.x = xPosition; node->position.y = yPosition; node->previousPosition.x = xPosition; node->previousPosition.y = yPosition; node->velocity.x = 0; node->velocity.y = 0; node->acceleration.x = 0; node->acceleration.y = 0; node->mass = mass; node->friction = friction; node->radius = radius; node->pushFactor = pushFactor; node->pinned = false; node->destroyable = false; group->nodes = realloc(group->nodes, sizeof(Silkworm_Node*) * (group->nodeCount + 1)); group->nodes[group->nodeCount] = node; group->nodeCount += 1; return nodeId.d; } void Silkworm_NodeSetVelocity(double groupId, double nodeId, double xVelocity, double yVelocity) { LookupNode(groupId, nodeId)->velocity.x = xVelocity; LookupNode(groupId, nodeId)->velocity.y = yVelocity; } void Silkworm_NodeSetAcceleration(double groupId, double nodeId, double xAcceleration, double yAcceleration) { LookupNode(groupId, nodeId)->acceleration.x = xAcceleration; LookupNode(groupId, nodeId)->acceleration.y = yAcceleration; } void Silkworm_NodeSetDestroyable(double groupId, double nodeId) { LookupNode(groupId, nodeId)->destroyable = true; } void Silkworm_NodePin(double groupId, double nodeId) { LookupNode(groupId, nodeId)->pinned = true; } void Silkworm_NodeUnpin(double groupId, double nodeId) { LookupNode(groupId, nodeId)->pinned = false; } double Silkworm_CreateLink(double groupId, double aId, double bId, double distance, double tearThreshold) { Silkworm_Group *group = LookupGroup(groupId); Silkworm_Node *nodeA = LookupNode(groupId, aId); Silkworm_Node *nodeB = LookupNode(groupId, bId); Silkworm_ID linkId; linkId.i = group->linkCount; Silkworm_Link *link = malloc(sizeof(Silkworm_Link)); link->id = linkId; link->a = nodeA; link->b = nodeB; link->distance = distance; link->tearThreshold = tearThreshold; group->links = realloc(group->links, sizeof(Silkworm_Link*) * (group->linkCount + 1)); group->links[group->linkCount] = link; group->linkCount += 1; return linkId.d; }