initial commit
commit
9c522e8447
|
@ -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 <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;
|
||||||
|
}
|
|
@ -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 <evan@moonside.games>
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef SILKWORM_H
|
||||||
|
#define SILKWORM_H
|
||||||
|
|
||||||
|
#include <math.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#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 */
|
|
@ -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
|
|
@ -0,0 +1,87 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<ItemGroup Label="ProjectConfigurations">
|
||||||
|
<ProjectConfiguration Include="Debug|Win32">
|
||||||
|
<Configuration>Debug</Configuration>
|
||||||
|
<Platform>Win32</Platform>
|
||||||
|
</ProjectConfiguration>
|
||||||
|
<ProjectConfiguration Include="Release|Win32">
|
||||||
|
<Configuration>Release</Configuration>
|
||||||
|
<Platform>Win32</Platform>
|
||||||
|
</ProjectConfiguration>
|
||||||
|
<ProjectConfiguration Include="Debug|x64">
|
||||||
|
<Configuration>Debug</Configuration>
|
||||||
|
<Platform>x64</Platform>
|
||||||
|
</ProjectConfiguration>
|
||||||
|
<ProjectConfiguration Include="Release|x64">
|
||||||
|
<Configuration>Release</Configuration>
|
||||||
|
<Platform>x64</Platform>
|
||||||
|
</ProjectConfiguration>
|
||||||
|
</ItemGroup>
|
||||||
|
<PropertyGroup Label="Globals">
|
||||||
|
<ProjectGuid>{6DB15344-E000-45CB-A48A-1D72F7D6E945}</ProjectGuid>
|
||||||
|
<RootNamespace>Silkworm</RootNamespace>
|
||||||
|
<WindowsTargetPlatformVersion>10.0.16299.0</WindowsTargetPlatformVersion>
|
||||||
|
</PropertyGroup>
|
||||||
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||||
|
<PropertyGroup Condition="'$(Configuration)'=='Debug'" Label="Configuration">
|
||||||
|
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||||
|
<UseDebugLibraries>true</UseDebugLibraries>
|
||||||
|
<CharacterSet>MultiByte</CharacterSet>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)'=='Release'" Label="Configuration">
|
||||||
|
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||||
|
<UseDebugLibraries>false</UseDebugLibraries>
|
||||||
|
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||||
|
<CharacterSet>MultiByte</CharacterSet>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||||
|
<PlatformToolset>v141</PlatformToolset>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||||
|
<PlatformToolset>v141</PlatformToolset>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||||
|
<PlatformToolset>v141</PlatformToolset>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||||
|
<PlatformToolset>v141</PlatformToolset>
|
||||||
|
</PropertyGroup>
|
||||||
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||||
|
<ImportGroup Label="ExtensionSettings">
|
||||||
|
</ImportGroup>
|
||||||
|
<ImportGroup Label="PropertySheets">
|
||||||
|
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||||
|
</ImportGroup>
|
||||||
|
<PropertyGroup Label="UserMacros" />
|
||||||
|
<ItemDefinitionGroup Condition="'$(Configuration)'=='Debug'">
|
||||||
|
<ClCompile>
|
||||||
|
<WarningLevel>Level3</WarningLevel>
|
||||||
|
<Optimization>Disabled</Optimization>
|
||||||
|
</ClCompile>
|
||||||
|
<Link>
|
||||||
|
<GenerateDebugInformation>DebugFull</GenerateDebugInformation>
|
||||||
|
</Link>
|
||||||
|
</ItemDefinitionGroup>
|
||||||
|
<ItemDefinitionGroup Condition="'$(Configuration)'=='Release'">
|
||||||
|
<ClCompile>
|
||||||
|
<WarningLevel>Level3</WarningLevel>
|
||||||
|
<Optimization>MaxSpeed</Optimization>
|
||||||
|
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||||
|
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||||
|
</ClCompile>
|
||||||
|
<Link>
|
||||||
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
|
<OptimizeReferences>true</OptimizeReferences>
|
||||||
|
</Link>
|
||||||
|
</ItemDefinitionGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ClCompile Include="..\src\Silkworm.c" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ClInclude Include="..\src\Silkworm.h" />
|
||||||
|
</ItemGroup>
|
||||||
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||||
|
<ImportGroup Label="ExtensionTargets">
|
||||||
|
</ImportGroup>
|
||||||
|
</Project>
|
|
@ -0,0 +1,4 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<PropertyGroup />
|
||||||
|
</Project>
|
Loading…
Reference in New Issue