commit 9c522e8447aaedc163f32cbaf986590e16d2a487 Author: Evan Hemsley Date: Mon Sep 20 18:00:44 2021 -0700 initial commit diff --git a/src/Silkworm.c b/src/Silkworm.c new file mode 100644 index 0000000..f8fa6d8 --- /dev/null +++ b/src/Silkworm.c @@ -0,0 +1,196 @@ +/* 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; +} diff --git a/src/Silkworm.h b/src/Silkworm.h new file mode 100644 index 0000000..ca830d5 --- /dev/null +++ b/src/Silkworm.h @@ -0,0 +1,121 @@ +/* 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 + * + */ + +#ifndef SILKWORM_H +#define SILKWORM_H + +#include +#include +#include + +#ifdef _WIN32 +#define SILKWORMAPI __declspec(dllexport) +#define SILKWORMCALL __cdecl +#else +#define SILKWORMAPI +#define SILKWORMCALL +#endif + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/* Game Maker only lets us use doubles in the API. So we do type punning to get integers. It's legal in C99! */ +typedef union { + int i; + double d; +} Silkworm_ID; + +typedef struct Silkworm_Vector2 +{ + double x; + double y; +} Silkworm_Vector2; + +typedef struct Silkworm_Node +{ + Silkworm_ID id; + Silkworm_Vector2 position; + Silkworm_Vector2 previousPosition; + Silkworm_Vector2 velocity; + Silkworm_Vector2 acceleration; + double mass; + double friction; + double radius; + double pinned; + double pushFactor; + bool destroyable; +} Silkworm_Node; + +typedef struct Silkworm_Link +{ + Silkworm_ID id; + Silkworm_Node *a; + Silkworm_Node *b; + double distance; + double tearThreshold; +} Silkworm_Link; + +typedef struct Silkworm_Group +{ + Silkworm_ID id; + Silkworm_Node **nodes; + uint32_t nodeCount; + + Silkworm_Link **links; + uint32_t linkCount; +} Silkworm_Group; + +/* Version API */ + +#define SILKWORM_ABI_VERSION 0 +#define SILKWORM_MAJOR_VERSION 0 +#define SILKWORM_MINOR_VERSION 1 +#define SILKWORM_PATCH_VERSION 0 +#define SILKWORM_COMPILED_VERSION ( \ + (REFRESH_ABI_VERSION * 100 * 100 * 100) + \ + (REFRESH_MAJOR_VERSION * 100 * 100) + \ + (REFRESH_MINOR_VERSION * 100) + \ + (REFRESH_PATCH_VERSION) \ +) + +SILKWORMAPI void Silkworm_Init(); +SILKWORMAPI void Silkworm_Update(); + +SILKWORMAPI double Silkworm_CreateGroup(); + +SILKWORMAPI double Silkworm_CreateNode(double groupId, double xPosition, double yPosition, double mass, double friction, double radius, double pushFactor); + +SILKWORMAPI void Silkworm_NodeSetVelocity(double groupId, double nodeId, double xVelocity, double yVelocity); +SILKWORMAPI void Silkworm_NodeSetAcceleration(double groupId, double nodeId, double xAcceleration, double yAcceleration); + +SILKWORMAPI void Silkworm_NodeSetDestroyable(double groupId, double nodeId); +SILKWORMAPI void Silkworm_NodePin(double groupId, double nodeId); +SILKWORMAPI void Silkworm_NodeUnpin(double groupId, double nodeId); + +SILKWORMAPI double Silkworm_CreateLink(double groupId, double aId, double bId, double distance, double tearThreshold); + +#endif /* SILKWORM_H */ diff --git a/visualc/Silkworm.sln b/visualc/Silkworm.sln new file mode 100644 index 0000000..4cf7abb --- /dev/null +++ b/visualc/Silkworm.sln @@ -0,0 +1,30 @@ +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 15 +VisualStudioVersion = 15.0.28307.645 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Silkworm", "Silkworm.vcxproj", "{6DB15344-E000-45CB-A48A-1D72F7D6E945}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x64 = Debug|x64 + MinSizeRel|x64 = MinSizeRel|x64 + Release|x64 = Release|x64 + RelWithDebInfo|x64 = RelWithDebInfo|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {6DB15344-E000-45CB-A48A-1D72F7D6E945}.Debug|x64.ActiveCfg = Debug|x64 + {6DB15344-E000-45CB-A48A-1D72F7D6E945}.Debug|x64.Build.0 = Debug|x64 + {6DB15344-E000-45CB-A48A-1D72F7D6E945}.MinSizeRel|x64.ActiveCfg = Release|x64 + {6DB15344-E000-45CB-A48A-1D72F7D6E945}.MinSizeRel|x64.Build.0 = Release|x64 + {6DB15344-E000-45CB-A48A-1D72F7D6E945}.Release|x64.ActiveCfg = Release|x64 + {6DB15344-E000-45CB-A48A-1D72F7D6E945}.Release|x64.Build.0 = Release|x64 + {6DB15344-E000-45CB-A48A-1D72F7D6E945}.RelWithDebInfo|x64.ActiveCfg = Release|x64 + {6DB15344-E000-45CB-A48A-1D72F7D6E945}.RelWithDebInfo|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {7B2DB465-0A55-3811-9EF4-A520B47653D2} + EndGlobalSection +EndGlobal diff --git a/visualc/Silkworm.vcxproj b/visualc/Silkworm.vcxproj new file mode 100644 index 0000000..014ab6d --- /dev/null +++ b/visualc/Silkworm.vcxproj @@ -0,0 +1,87 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + {6DB15344-E000-45CB-A48A-1D72F7D6E945} + Silkworm + 10.0.16299.0 + + + + DynamicLibrary + true + MultiByte + + + DynamicLibrary + false + true + MultiByte + + + v141 + + + v141 + + + v141 + + + v141 + + + + + + + + + + + Level3 + Disabled + + + DebugFull + + + + + Level3 + MaxSpeed + true + true + + + true + true + + + + + + + + + + + + \ No newline at end of file diff --git a/visualc/Silkworm.vcxproj.user b/visualc/Silkworm.vcxproj.user new file mode 100644 index 0000000..be25078 --- /dev/null +++ b/visualc/Silkworm.vcxproj.user @@ -0,0 +1,4 @@ + + + + \ No newline at end of file