Silkworm/src/Silkworm.c

197 lines
5.1 KiB
C

/* 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 <evan@moonside.games>
*
*/
#include "Silkworm.h"
#include <stdlib.h>
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;
}