node to triangle lookups
							parent
							
								
									a479c66969
								
							
						
					
					
						commit
						2fc8d0a781
					
				
							
								
								
									
										259
									
								
								src/Silkworm.c
								
								
								
								
							
							
						
						
									
										259
									
								
								src/Silkworm.c
								
								
								
								
							| 
						 | 
				
			
			@ -29,6 +29,174 @@
 | 
			
		|||
#include <stdlib.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
 | 
			
		||||
typedef struct Silkworm_Vector2
 | 
			
		||||
{
 | 
			
		||||
	float x;
 | 
			
		||||
	float y;
 | 
			
		||||
} Silkworm_Vector2;
 | 
			
		||||
 | 
			
		||||
typedef struct Silkworm_Link Silkworm_Link;
 | 
			
		||||
 | 
			
		||||
typedef struct Silkworm_Node
 | 
			
		||||
{
 | 
			
		||||
	uint64_t id;
 | 
			
		||||
	Silkworm_Vector2 position;
 | 
			
		||||
	Silkworm_Vector2 previousPosition;
 | 
			
		||||
	Silkworm_Vector2 velocity;
 | 
			
		||||
	Silkworm_Vector2 acceleration;
 | 
			
		||||
	float mass;
 | 
			
		||||
	float friction;
 | 
			
		||||
	float radius;
 | 
			
		||||
	float pinned;
 | 
			
		||||
	float pushFactor;
 | 
			
		||||
	bool destroyable;
 | 
			
		||||
 | 
			
		||||
	bool markedForDestroy; /* mutual recursion on nodes/links so this makes it easier to track destroys */
 | 
			
		||||
 | 
			
		||||
	Silkworm_Link** links;
 | 
			
		||||
	uint32_t linkCount;
 | 
			
		||||
} Silkworm_Node;
 | 
			
		||||
 | 
			
		||||
struct Silkworm_Link
 | 
			
		||||
{
 | 
			
		||||
	uint64_t id;
 | 
			
		||||
	Silkworm_Node* a;
 | 
			
		||||
	Silkworm_Node* b;
 | 
			
		||||
	float distance;
 | 
			
		||||
	float tearThreshold;
 | 
			
		||||
 | 
			
		||||
	bool markedForDestroy; /* mutual recursion on nodes/links so this makes it easier to track destroys */
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
typedef enum Silkworm_ClothTriangleOrientation
 | 
			
		||||
{
 | 
			
		||||
	UpperLeft,
 | 
			
		||||
	BottomRight
 | 
			
		||||
} Silkworm_ClothTriangleOrientation;
 | 
			
		||||
 | 
			
		||||
typedef struct Silkworm_Triangle
 | 
			
		||||
{
 | 
			
		||||
	uint64_t id;
 | 
			
		||||
	Silkworm_Node* a;
 | 
			
		||||
	Silkworm_Node* b;
 | 
			
		||||
	Silkworm_Node* c;
 | 
			
		||||
 | 
			
		||||
	uint32_t aHorizontalIndex;
 | 
			
		||||
	uint32_t bHorizontalIndex;
 | 
			
		||||
	uint32_t cHorizontalIndex;
 | 
			
		||||
 | 
			
		||||
	uint32_t aVerticalIndex;
 | 
			
		||||
	uint32_t bVerticalIndex;
 | 
			
		||||
	uint32_t cVerticalIndex;
 | 
			
		||||
 | 
			
		||||
	Silkworm_ClothTriangleOrientation orientation;
 | 
			
		||||
} Silkworm_Triangle;
 | 
			
		||||
 | 
			
		||||
typedef struct NodeTriangleHashMap
 | 
			
		||||
{
 | 
			
		||||
	Silkworm_Node* key;
 | 
			
		||||
	uint32_t *indexArray;
 | 
			
		||||
	uint32_t indexArrayCount;
 | 
			
		||||
} NodeTriangleHashMap;
 | 
			
		||||
 | 
			
		||||
typedef struct NodeTriangleHashArray
 | 
			
		||||
{
 | 
			
		||||
	NodeTriangleHashMap* elements;
 | 
			
		||||
	uint32_t count;
 | 
			
		||||
} NodeTriangleHashArray;
 | 
			
		||||
 | 
			
		||||
#define NUM_NODE_TRIANGLE_HASH_BUCKETS 1031
 | 
			
		||||
 | 
			
		||||
typedef struct NodeTriangleHashTable
 | 
			
		||||
{
 | 
			
		||||
	NodeTriangleHashArray buckets[NUM_NODE_TRIANGLE_HASH_BUCKETS];
 | 
			
		||||
} NodeTriangleHashTable;
 | 
			
		||||
 | 
			
		||||
static inline uint64_t NodeTriangleHashTable_GetHashCode(Silkworm_Node *key)
 | 
			
		||||
{
 | 
			
		||||
	return 97 + (uint64_t)(size_t)key;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline uint32_t* NodeTriangleHashTable_Fetch(
 | 
			
		||||
	NodeTriangleHashTable *table,
 | 
			
		||||
	Silkworm_Node *key,
 | 
			
		||||
	uint32_t *arrayCount
 | 
			
		||||
) {
 | 
			
		||||
	uint32_t i;
 | 
			
		||||
	uint64_t hashcode = NodeTriangleHashTable_GetHashCode(key);
 | 
			
		||||
	NodeTriangleHashArray* arr = &table->buckets[hashcode % NUM_NODE_TRIANGLE_HASH_BUCKETS];
 | 
			
		||||
 | 
			
		||||
	for (i = 0; i < arr->count; i += 1)
 | 
			
		||||
	{
 | 
			
		||||
		if (arr->elements[i].key == key)
 | 
			
		||||
		{
 | 
			
		||||
			*arrayCount = arr->elements[i].indexArrayCount;
 | 
			
		||||
			return arr->elements[i].indexArray;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	*arrayCount = 0;
 | 
			
		||||
	return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline void NodeTriangleHashTable_Insert(
 | 
			
		||||
	NodeTriangleHashTable* table,
 | 
			
		||||
	Silkworm_Node* key,
 | 
			
		||||
	uint32_t index
 | 
			
		||||
) {
 | 
			
		||||
	uint32_t i;
 | 
			
		||||
	uint64_t hashcode = NodeTriangleHashTable_GetHashCode(key);
 | 
			
		||||
	NodeTriangleHashArray* arr = &table->buckets[hashcode % NUM_NODE_TRIANGLE_HASH_BUCKETS];
 | 
			
		||||
	bool foundKey = false;
 | 
			
		||||
 | 
			
		||||
	for (i = 0; i < arr->count; i += 1)
 | 
			
		||||
	{
 | 
			
		||||
		if (arr->elements[i].key == key)
 | 
			
		||||
		{
 | 
			
		||||
			arr->elements[i].indexArray = realloc(arr->elements[i].indexArray, sizeof(uint32_t) * (arr->elements[i].indexArrayCount + 1));
 | 
			
		||||
			arr->elements[i].indexArray[arr->elements[i].indexArrayCount] = index;
 | 
			
		||||
			arr->elements[i].indexArrayCount += 1;
 | 
			
		||||
			foundKey = true;
 | 
			
		||||
			break;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!foundKey)
 | 
			
		||||
	{
 | 
			
		||||
		arr->elements = realloc(arr->elements, sizeof(NodeTriangleHashMap) * (arr->count + 1));
 | 
			
		||||
 | 
			
		||||
		arr->elements[arr->count].key = key;
 | 
			
		||||
		arr->elements[arr->count].indexArray = malloc(sizeof(uint32_t));
 | 
			
		||||
		arr->elements[arr->count].indexArray[0] = index;
 | 
			
		||||
		arr->elements[arr->count].indexArrayCount = 1;
 | 
			
		||||
 | 
			
		||||
		arr->count += 1;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
typedef struct Silkworm_Cloth
 | 
			
		||||
{
 | 
			
		||||
	uint64_t id;
 | 
			
		||||
	float windFactor;
 | 
			
		||||
 | 
			
		||||
	uint32_t horizontalNodeCount;
 | 
			
		||||
	uint32_t verticalNodeCount;
 | 
			
		||||
 | 
			
		||||
	uint64_t** nodeIndices; /* x by y grid of indices */
 | 
			
		||||
 | 
			
		||||
	Silkworm_Triangle** triangles; /* array of pointers so we can use NULL */
 | 
			
		||||
	uint32_t triangleCount;
 | 
			
		||||
 | 
			
		||||
	NodeTriangleHashTable nodeHash;
 | 
			
		||||
} Silkworm_Cloth;
 | 
			
		||||
 | 
			
		||||
typedef struct Silkworm_Rope
 | 
			
		||||
{
 | 
			
		||||
	uint32_t nodeCount;
 | 
			
		||||
 | 
			
		||||
	uint32_t* nodeIndices;
 | 
			
		||||
} Silkworm_Rope;
 | 
			
		||||
 | 
			
		||||
typedef struct Silkworm_Color
 | 
			
		||||
{
 | 
			
		||||
	uint8_t r;
 | 
			
		||||
| 
						 | 
				
			
			@ -156,6 +324,15 @@ void Silkworm_Internal_DestroyCloth(Silkworm_Cloth* cloth)
 | 
			
		|||
 | 
			
		||||
	context->cloths[cloth->id] = NULL;
 | 
			
		||||
 | 
			
		||||
	for (i = 0; i < NUM_NODE_TRIANGLE_HASH_BUCKETS; i += 1)
 | 
			
		||||
	{
 | 
			
		||||
		for (j = 0; j < cloth->nodeHash.buckets[i].count; j += 1)
 | 
			
		||||
		{
 | 
			
		||||
			free(cloth->nodeHash.buckets[i].elements[j].indexArray);
 | 
			
		||||
		}
 | 
			
		||||
		free(cloth->nodeHash.buckets[i].elements);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for (i = 0; i < cloth->horizontalNodeCount; i += 1)
 | 
			
		||||
	{
 | 
			
		||||
		for (j = 0; j < cloth->verticalNodeCount; j += 1)
 | 
			
		||||
| 
						 | 
				
			
			@ -184,7 +361,7 @@ void Silkworm_DestroyCloth(double clothId)
 | 
			
		|||
 | 
			
		||||
void Silkworm_PerformDestroys()
 | 
			
		||||
{
 | 
			
		||||
	uint32_t i, j;
 | 
			
		||||
	uint32_t i, j, k;
 | 
			
		||||
 | 
			
		||||
	for (i = 0; i < context->linkCount; i += 1)
 | 
			
		||||
	{
 | 
			
		||||
| 
						 | 
				
			
			@ -222,8 +399,32 @@ void Silkworm_PerformDestroys()
 | 
			
		|||
 | 
			
		||||
	for (i = 0; i < context->nodeCount; i += 1)
 | 
			
		||||
	{
 | 
			
		||||
		if (context->nodes[i] != NULL && context->nodes[i]->markedForDestroy)
 | 
			
		||||
		Silkworm_Node* node = context->nodes[i];
 | 
			
		||||
		if (node != NULL && node->markedForDestroy)
 | 
			
		||||
		{
 | 
			
		||||
			/* find cloth to remove from relevant triangles */
 | 
			
		||||
			for (j = 0; j < context->clothCount; j += 1)
 | 
			
		||||
			{
 | 
			
		||||
				Silkworm_Cloth* cloth = context->cloths[j];
 | 
			
		||||
 | 
			
		||||
				if (cloth != NULL)
 | 
			
		||||
				{
 | 
			
		||||
					uint32_t triangleIndexCount = 0;
 | 
			
		||||
					uint32_t* triangleIndices = NodeTriangleHashTable_Fetch(&cloth->nodeHash, node, &triangleIndexCount);
 | 
			
		||||
 | 
			
		||||
					for (k = 0; k < triangleIndexCount; k += 1)
 | 
			
		||||
					{
 | 
			
		||||
						uint32_t triangleIndex = triangleIndices[k];
 | 
			
		||||
 | 
			
		||||
						if (cloth->triangles[triangleIndex] != NULL)
 | 
			
		||||
						{
 | 
			
		||||
							free(cloth->triangles[triangleIndex]);
 | 
			
		||||
							cloth->triangles[triangleIndex] = NULL;
 | 
			
		||||
						}
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			free(context->nodes[i]->links);
 | 
			
		||||
			free(context->nodes[i]);
 | 
			
		||||
			context->nodes[i] = NULL;
 | 
			
		||||
| 
						 | 
				
			
			@ -396,25 +597,10 @@ void Silkworm_ClothNodeUnpin(double clothId, double i, double j)
 | 
			
		|||
 | 
			
		||||
void Silkworm_ClothNodeDestroy(double clothId, double i, double j)
 | 
			
		||||
{
 | 
			
		||||
	uint32_t iterator;
 | 
			
		||||
 | 
			
		||||
	Silkworm_Cloth* cloth = LookupCloth(clothId);
 | 
			
		||||
	uint64_t nodeIndex = cloth->nodeIndices[(uint64_t)i][(uint64_t)j];
 | 
			
		||||
	Silkworm_Node* node = context->nodes[nodeIndex];
 | 
			
		||||
	Silkworm_DestroyNode(nodeIndex);
 | 
			
		||||
 | 
			
		||||
	/* fixme: this should be hashed */
 | 
			
		||||
	for (iterator = 0; iterator < cloth->triangleCount; iterator += 1)
 | 
			
		||||
	{
 | 
			
		||||
		if (cloth->triangles[iterator] != NULL)
 | 
			
		||||
		{
 | 
			
		||||
			if (cloth->triangles[iterator]->a == node || cloth->triangles[iterator]->b == node || cloth->triangles[iterator]->c == node)
 | 
			
		||||
			{
 | 
			
		||||
				free(cloth->triangles[iterator]);
 | 
			
		||||
				cloth->triangles[iterator] = NULL;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
double Silkworm_CreateLink(double aId, double bId, double distance, double tearThreshold)
 | 
			
		||||
| 
						 | 
				
			
			@ -490,6 +676,12 @@ double Silkworm_CreateCloth(double xPosition, double yPosition, double horizonta
 | 
			
		|||
 | 
			
		||||
	cloth->id = id;
 | 
			
		||||
 | 
			
		||||
	for (i = 0; i < NUM_NODE_TRIANGLE_HASH_BUCKETS; i += 1)
 | 
			
		||||
	{
 | 
			
		||||
		cloth->nodeHash.buckets[i].elements = NULL;
 | 
			
		||||
		cloth->nodeHash.buckets[i].count = 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for (i = 0; i < horizontalNodeCount; i += 1)
 | 
			
		||||
	{
 | 
			
		||||
		cloth->nodeIndices[i] = malloc(sizeof(uint64_t) * cloth->verticalNodeCount);
 | 
			
		||||
| 
						 | 
				
			
			@ -534,6 +726,10 @@ double Silkworm_CreateCloth(double xPosition, double yPosition, double horizonta
 | 
			
		|||
				cloth->triangles[triangleIndex]->cHorizontalIndex = i;
 | 
			
		||||
				cloth->triangles[triangleIndex]->cVerticalIndex = j + 1;
 | 
			
		||||
 | 
			
		||||
				NodeTriangleHashTable_Insert(&cloth->nodeHash, context->nodes[cloth->nodeIndices[i][j]], triangleIndex);
 | 
			
		||||
				NodeTriangleHashTable_Insert(&cloth->nodeHash, context->nodes[cloth->nodeIndices[i + 1][j]], triangleIndex);
 | 
			
		||||
				NodeTriangleHashTable_Insert(&cloth->nodeHash, context->nodes[cloth->nodeIndices[i][j + 1]], triangleIndex);
 | 
			
		||||
 | 
			
		||||
				triangleIndex += 1;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -555,6 +751,10 @@ double Silkworm_CreateCloth(double xPosition, double yPosition, double horizonta
 | 
			
		|||
				cloth->triangles[triangleIndex]->cHorizontalIndex = i;
 | 
			
		||||
				cloth->triangles[triangleIndex]->cVerticalIndex = j - 1;
 | 
			
		||||
 | 
			
		||||
				NodeTriangleHashTable_Insert(&cloth->nodeHash, context->nodes[cloth->nodeIndices[i][j]], triangleIndex);
 | 
			
		||||
				NodeTriangleHashTable_Insert(&cloth->nodeHash, context->nodes[cloth->nodeIndices[i - 1][j]], triangleIndex);
 | 
			
		||||
				NodeTriangleHashTable_Insert(&cloth->nodeHash, context->nodes[cloth->nodeIndices[i][j - 1]], triangleIndex);
 | 
			
		||||
 | 
			
		||||
				triangleIndex += 1;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
| 
						 | 
				
			
			@ -731,6 +931,31 @@ double Silkworm_ClothFillTriangleBuffer(double clothId, double leftUV, double wi
 | 
			
		|||
	return (double)triangleCount;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Silkworm_DestroyNodesInRadius(double x, double y, double radius)
 | 
			
		||||
{
 | 
			
		||||
	/* TODO: spatial hash implementation */
 | 
			
		||||
 | 
			
		||||
	uint32_t i;
 | 
			
		||||
 | 
			
		||||
	for (i = 0; i < context->nodeCount; i += 1)
 | 
			
		||||
	{
 | 
			
		||||
		Silkworm_Node* node = context->nodes[i];
 | 
			
		||||
 | 
			
		||||
		if (node != NULL)
 | 
			
		||||
		{
 | 
			
		||||
			float xDistance = (float)fabs((float)x - node->position.x);
 | 
			
		||||
			float yDistance = (float)fabs((float)y - node->position.y);
 | 
			
		||||
 | 
			
		||||
			float squareDistance = xDistance * xDistance + yDistance * yDistance;
 | 
			
		||||
 | 
			
		||||
			if (squareDistance <= radius * radius)
 | 
			
		||||
			{
 | 
			
		||||
				Silkworm_DestroyNode(i);
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Silkworm_ClearAll()
 | 
			
		||||
{
 | 
			
		||||
	uint32_t i;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -43,90 +43,6 @@
 | 
			
		|||
extern "C" {
 | 
			
		||||
#endif /* __cplusplus */
 | 
			
		||||
 | 
			
		||||
typedef struct Silkworm_Vector2
 | 
			
		||||
{
 | 
			
		||||
	float x;
 | 
			
		||||
	float y;
 | 
			
		||||
} Silkworm_Vector2;
 | 
			
		||||
 | 
			
		||||
typedef struct Silkworm_Link Silkworm_Link;
 | 
			
		||||
 | 
			
		||||
typedef struct Silkworm_Node
 | 
			
		||||
{
 | 
			
		||||
	uint64_t id;
 | 
			
		||||
	Silkworm_Vector2 position;
 | 
			
		||||
	Silkworm_Vector2 previousPosition;
 | 
			
		||||
	Silkworm_Vector2 velocity;
 | 
			
		||||
	Silkworm_Vector2 acceleration;
 | 
			
		||||
	float mass;
 | 
			
		||||
	float friction;
 | 
			
		||||
	float radius;
 | 
			
		||||
	float pinned;
 | 
			
		||||
	float pushFactor;
 | 
			
		||||
	bool destroyable;
 | 
			
		||||
 | 
			
		||||
	bool markedForDestroy; /* mutual recursion on nodes/links so this makes it easier to track destroys */
 | 
			
		||||
 | 
			
		||||
	Silkworm_Link** links;
 | 
			
		||||
	uint32_t linkCount;
 | 
			
		||||
} Silkworm_Node;
 | 
			
		||||
 | 
			
		||||
struct Silkworm_Link
 | 
			
		||||
{
 | 
			
		||||
	uint64_t id;
 | 
			
		||||
	Silkworm_Node *a;
 | 
			
		||||
	Silkworm_Node *b;
 | 
			
		||||
	float distance;
 | 
			
		||||
	float tearThreshold;
 | 
			
		||||
 | 
			
		||||
	bool markedForDestroy; /* mutual recursion on nodes/links so this makes it easier to track destroys */
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
typedef enum Silkworm_ClothTriangleOrientation
 | 
			
		||||
{
 | 
			
		||||
	UpperLeft,
 | 
			
		||||
	BottomRight
 | 
			
		||||
} Silkworm_ClothTriangleOrientation;
 | 
			
		||||
 | 
			
		||||
typedef struct Silkworm_Triangle
 | 
			
		||||
{
 | 
			
		||||
	uint64_t id;
 | 
			
		||||
	Silkworm_Node* a;
 | 
			
		||||
	Silkworm_Node* b;
 | 
			
		||||
	Silkworm_Node* c;
 | 
			
		||||
 | 
			
		||||
	uint32_t aHorizontalIndex;
 | 
			
		||||
	uint32_t bHorizontalIndex;
 | 
			
		||||
	uint32_t cHorizontalIndex;
 | 
			
		||||
 | 
			
		||||
	uint32_t aVerticalIndex;
 | 
			
		||||
	uint32_t bVerticalIndex;
 | 
			
		||||
	uint32_t cVerticalIndex;
 | 
			
		||||
 | 
			
		||||
	Silkworm_ClothTriangleOrientation orientation;
 | 
			
		||||
} Silkworm_Triangle;
 | 
			
		||||
 | 
			
		||||
typedef struct Silkworm_Cloth
 | 
			
		||||
{
 | 
			
		||||
	uint64_t id;
 | 
			
		||||
	float windFactor;
 | 
			
		||||
 | 
			
		||||
	uint32_t horizontalNodeCount;
 | 
			
		||||
	uint32_t verticalNodeCount;
 | 
			
		||||
 | 
			
		||||
	uint64_t **nodeIndices; /* x by y grid of indices */
 | 
			
		||||
 | 
			
		||||
	Silkworm_Triangle **triangles; /* array of pointers so we can use NULL */
 | 
			
		||||
	uint32_t triangleCount;
 | 
			
		||||
} Silkworm_Cloth;
 | 
			
		||||
 | 
			
		||||
typedef struct Silkworm_Rope
 | 
			
		||||
{
 | 
			
		||||
	uint32_t nodeCount;
 | 
			
		||||
 | 
			
		||||
	uint32_t *nodeIndices;
 | 
			
		||||
} Silkworm_Rope;
 | 
			
		||||
 | 
			
		||||
/* Version API */
 | 
			
		||||
 | 
			
		||||
#define SILKWORM_ABI_VERSION	 0
 | 
			
		||||
| 
						 | 
				
			
			@ -148,7 +64,6 @@ SILKWORMAPI double Silkworm_CreateNode(double xPosition, double yPosition, doubl
 | 
			
		|||
 | 
			
		||||
SILKWORMAPI void Silkworm_NodeSetDestroyable(double nodeId);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
SILKWORMAPI double Silkworm_CreateLink(double aId, double bId, double distance, double tearThreshold);
 | 
			
		||||
 | 
			
		||||
SILKWORMAPI double Silkworm_CreateCloth(double xPosition, double yPosition, double horizontalNodeCount, double verticalNodeCount, double mass, double friction, double windFactor, double tearThreshold);
 | 
			
		||||
| 
						 | 
				
			
			@ -161,6 +76,9 @@ SILKWORMAPI void Silkworm_SetTriangleBuffer(const char* bufferId);
 | 
			
		|||
SILKWORMAPI double Silkworm_ClothFillTriangleBuffer(double clothId, double leftUV, double widthUV, double topUV, double heightUV);
 | 
			
		||||
 | 
			
		||||
SILKWORMAPI void Silkworm_DestroyNode(double nodeId);
 | 
			
		||||
 | 
			
		||||
SILKWORMAPI void Silkworm_DestroyNodesInRadius(double x, double y, double radius);
 | 
			
		||||
 | 
			
		||||
SILKWORMAPI void Silkworm_ClearAll();
 | 
			
		||||
 | 
			
		||||
#endif /* SILKWORM_H */
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue