From d9e69c8f05613fca474d4981fdd0a9c3608e312a Mon Sep 17 00:00:00 2001
From: cosmonaut <evan@moonside.games>
Date: Tue, 5 Oct 2021 17:57:25 -0700
Subject: [PATCH] ABI refactor because game maker is silly

---
 src/snowstorm.c           | 94 ++++++++++++++++++++++-----------------
 src/snowstorm.h           | 25 ++++++-----
 visualc/Snowstorm.vcxproj |  2 +-
 3 files changed, 68 insertions(+), 53 deletions(-)

diff --git a/src/snowstorm.c b/src/snowstorm.c
index 2a1e7d1..f2dc6f4 100644
--- a/src/snowstorm.c
+++ b/src/snowstorm.c
@@ -118,6 +118,8 @@ static Snowstorm_Matrix3x2 Matrix3x2_CreateRotation(float radians)
 	float c, s;
 	float epsilon = 0.001f * PI / 180; /* 0.1 % of a degree */
 
+	radians = fmodf(radians, PI * 2);
+
 	if (radians > -epsilon && radians < epsilon)
 	{
 		/* Exact case for zero rotation. */
@@ -217,6 +219,8 @@ typedef struct Snowstorm_Context
 
 	Snowstorm_Vector2 wind;
 
+	float particleSize;
+
 	float leftBound;
 	float topBound;
 	float rightBound;
@@ -256,19 +260,29 @@ static inline float RandomRange(float min, float max)
 	return Random(max - min) + min;
 }
 
+/* i wanted to use pointers but game maker mangles string to pointer casts. oh well */
+static Snowstorm_Context *contexts = NULL;
+static uint32_t contextCount = 0;
+
 void Snowstorm_Init()
 {
 	srand((unsigned int)time(NULL));
 }
 
-const char* Snowstorm_Create()
+/* FIXME: we should reuse IDs when contexts are destroyed */
+double Snowstorm_Create(double particleSize, double leftBound, double topBound, double rightBound, double bottomBound)
 {
-	Snowstorm_Context *context = malloc(sizeof(Snowstorm_Context));
+	contexts = realloc(contexts, sizeof(Snowstorm_Context) * (contextCount + 1));
+	contextCount += 1;
+
+	Snowstorm_Context* context = &contexts[contextCount - 1];
 
 	context->particleCapacity = 128;
 	context->particles = malloc(sizeof(Snowstorm_Particle) * context->particleCapacity);
 	context->particleCount = 0;
 
+	context->particleSize = particleSize;
+
 	context->leftBound = -10;
 	context->rightBound = 490;
 	context->topBound = -10;
@@ -282,37 +296,37 @@ const char* Snowstorm_Create()
 
 	context->currentBufferAddress = NULL;
 
-	return (const char*)context;
+	return (double)(contextCount - 1);
 }
 
-void Snowstorm_SetUVCount(const char *contextPointer, double count)
+void Snowstorm_SetUVCount(double contextId, double count)
 {
-	Snowstorm_Context *context = (Snowstorm_Context*)contextPointer;
+	Snowstorm_Context* context = &contexts[(uint32_t)contextId];
 
 	context->uvCount = (uint32_t)count;
 	context->uvs = realloc(context->uvs, sizeof(Snowstorm_UV) * context->uvCount);
 }
 
-void Snowstorm_SetLeftTopUV(const char *contextPointer, double index, double left, double top)
+void Snowstorm_SetLeftTopUV(double contextId, double index, double left, double top)
 {
-	Snowstorm_Context* context = (Snowstorm_Context*)contextPointer;
+	Snowstorm_Context* context = &contexts[(uint32_t)contextId];
 
 	context->uvs[(uint32_t)index].left = left;
 	context->uvs[(uint32_t)index].top = top;
 }
 
-void Snowstorm_SetRightBottomUV(const char* contextPointer, double index, double right, double bottom)
+void Snowstorm_SetRightBottomUV(double contextId, double index, double right, double bottom)
 {
-	Snowstorm_Context* context = (Snowstorm_Context*)contextPointer;
+	Snowstorm_Context* context = &contexts[(uint32_t)contextId];
 
 	context->uvs[(uint32_t)index].right = right;
 	context->uvs[(uint32_t)index].bottom = bottom;
 }
 
-void Snowstorm_Update(const char *contextPointer)
+void Snowstorm_Update(double contextId)
 {
 	uint32_t i;
-	Snowstorm_Context* context = (Snowstorm_Context*)contextPointer;
+	Snowstorm_Context* context = &contexts[(uint32_t)contextId];
 
 	for (i = 0; i < context->particleCount; i += 1)
 	{
@@ -321,7 +335,7 @@ void Snowstorm_Update(const char *contextPointer)
 		particle->time += particle->timeRate;
 
 		float speed = Vector2_Magnitude(particle->velocity);
-		float rotation = sinf(particle->time / (speed * 100)) * particle->directionVariance;
+		float rotation = sinf(particle->time / (speed * 100)) * particle->directionVariance * (PI / 180.0f); // degrees to radians
 
 		float windSpeed = Vector2_Magnitude(context->wind);
 		Snowstorm_Vector2 wind = Vector2_Normalize(context->wind);
@@ -342,10 +356,10 @@ void Snowstorm_Update(const char *contextPointer)
 	}
 }
 
-void Snowstorm_ApplyChaos(const char* contextPointer, double directionChaos, double speedChaos)
+void Snowstorm_ApplyChaos(double contextId, double directionChaos, double speedChaos)
 {
 	uint32_t i;
-	Snowstorm_Context* context = (Snowstorm_Context*)contextPointer;
+	Snowstorm_Context* context = &contexts[(uint32_t)contextId];
 
 	for (i = 0; i < context->particleCount; i += 1)
 	{
@@ -356,17 +370,17 @@ void Snowstorm_ApplyChaos(const char* contextPointer, double directionChaos, dou
 	}
 }
 
-void Snowstorm_ApplyWind(const char *contextPointer, double xSpeed, double ySpeed)
+void Snowstorm_ApplyWind(double contextId, double xSpeed, double ySpeed)
 {
-	Snowstorm_Context* context = (Snowstorm_Context*)contextPointer;
+	Snowstorm_Context* context = &contexts[(uint32_t)contextId];
 	context->wind.x = (float)xSpeed;
 	context->wind.y = (float)ySpeed;
 }
 
-void Snowstorm_SetParticles(const char *contextPointer, double count)
+void Snowstorm_SetParticles(double contextId, double count)
 {
 	uint32_t i;
-	Snowstorm_Context* context = (Snowstorm_Context*)contextPointer;
+	Snowstorm_Context* context = &contexts[(uint32_t)contextId];
 
 	if (count > context->particleCapacity)
 	{
@@ -395,30 +409,32 @@ void Snowstorm_SetParticles(const char *contextPointer, double count)
 		particle->rotation = 0;
 		particle->uvIndex = rand() % context->uvCount;
 	}
+
+	context->particleCount = count;
 }
 
-void Snowstorm_SetBufferAddress(const char *contextPointer, const char* bufferAddress)
+void Snowstorm_SetBufferAddress(double contextId, const char* bufferAddress)
 {
-	Snowstorm_Context* context = (Snowstorm_Context*)contextPointer;
+	Snowstorm_Context* context = &contexts[(uint32_t)contextId];
 	context->currentBufferAddress = (uint8_t*)bufferAddress;
 }
 
-double Snowstorm_RequiredSnowBufferSize(const char *contextPointer)
+double Snowstorm_RequiredSnowBufferSize(double contextId)
 {
-	Snowstorm_Context* context = (Snowstorm_Context*)contextPointer;
+	Snowstorm_Context* context = &contexts[(uint32_t)contextId];
 	return (double)context->particleCount * 6 * (sizeof(Snowstorm_Vector2) + sizeof(Snowstorm_Color) + (2 * sizeof(float)));
 }
 
-double Snowstorm_FillSnowBuffer(const char *contextPointer)
+double Snowstorm_FillSnowBuffer(double contextId, double red, double green, double blue)
 {
 	uint32_t i, vertexCount;
-	Snowstorm_Context* context = (Snowstorm_Context*)contextPointer;
+	Snowstorm_Context* context = &contexts[(uint32_t)contextId];
 	uint8_t* bufferAddress = context->currentBufferAddress;
 
 	Snowstorm_Color color;
-	color.r = 255;
-	color.g = 255;
-	color.b = 255;
+	color.r = (uint8_t)red;
+	color.g = (uint8_t)green;
+	color.b = (uint8_t)blue;
 	color.a = 255;
 	
 	vertexCount = 0;
@@ -432,21 +448,21 @@ double Snowstorm_FillSnowBuffer(const char *contextPointer)
 		Snowstorm_Vector2 leftBottom;
 		Snowstorm_Vector2 rightBottom;
 
-		leftTop.x = -particle->scale.x;
-		leftTop.y = -particle->scale.y;
+		leftTop.x = context->particleSize * -particle->scale.x / 4;
+		leftTop.y = context->particleSize * -particle->scale.y / 4;
 
-		rightTop.x = particle->scale.x;
-		rightTop.y = -particle->scale.y;
+		rightTop.x = context->particleSize * particle->scale.x / 4;
+		rightTop.y = context->particleSize * -particle->scale.y / 4;
 
-		leftBottom.x = -particle->scale.x;
-		leftBottom.y = particle->scale.y;
+		leftBottom.x = context->particleSize * -particle->scale.x / 4;
+		leftBottom.y = context->particleSize * particle->scale.y / 4;
 
-		rightBottom.x = particle->scale.x;
-		rightBottom.y = particle->scale.y;
+		rightBottom.x = context->particleSize * particle->scale.x / 4;
+		rightBottom.y = context->particleSize * particle->scale.y / 4;
 
 		Snowstorm_Matrix3x2 translation = Matrix3x2_CreateTranslation(particle->position.x, particle->position.y);
 		Snowstorm_Matrix3x2 rotation = Matrix3x2_CreateRotation(particle->rotation);
-		Snowstorm_Matrix3x2 transform = Matrix3x2_Multiply(translation, rotation);
+		Snowstorm_Matrix3x2 transform = Matrix3x2_Multiply(rotation, translation);
 
 		leftTop = Vector2_Transform(leftTop, transform);
 		rightTop = Vector2_Transform(rightTop, transform);
@@ -536,9 +552,9 @@ double Snowstorm_FillSnowBuffer(const char *contextPointer)
 	return (double)vertexCount;
 }
 
-void Snowstorm_Destroy(const char *contextPointer)
+void Snowstorm_Destroy(double contextId)
 {
-	Snowstorm_Context* context = (Snowstorm_Context*)contextPointer;
+	Snowstorm_Context* context = &contexts[(uint32_t)contextId];
 
 	if (context->particles != NULL)
 	{
@@ -549,6 +565,4 @@ void Snowstorm_Destroy(const char *contextPointer)
 	{
 		free(context->uvs);
 	}
-
-	free(context);
 }
diff --git a/src/snowstorm.h b/src/snowstorm.h
index eb6ff89..5a335db 100644
--- a/src/snowstorm.h
+++ b/src/snowstorm.h
@@ -57,23 +57,24 @@ extern "C" {
 )
 
 SNOWSTORMAPI void Snowstorm_Init();
-SNOWSTORMAPI const char* Snowstorm_Create(); /* have to return a string because game maker lol */
-SNOWSTORMAPI void Snowstorm_SetUVCount(const char *contextPointer, double count);
+SNOWSTORMAPI double Snowstorm_Create(double particleSize, double leftBound, double topBound, double rightBound, double bottomBound);
+
+SNOWSTORMAPI void Snowstorm_SetUVCount(double contextId, double count);
 /* i split these up because game maker cant have more than 4 arguments with different types lol */
-SNOWSTORMAPI void Snowstorm_SetLeftTopUV(const char *contextPointer, double index, double left, double top); 
-SNOWSTORMAPI void Snowstorm_SetRightBottomUV(const char* contextPointer, double index, double right, double bottom);
+SNOWSTORMAPI void Snowstorm_SetLeftTopUV(double contextId, double index, double left, double top);
+SNOWSTORMAPI void Snowstorm_SetRightBottomUV(double contextId, double index, double right, double bottom);
 
-SNOWSTORMAPI void Snowstorm_Update(const char *contextPointer);
-SNOWSTORMAPI void Snowstorm_ApplyWind(const char *contextPointer, double xSpeed, double ySpeed);
-SNOWSTORMAPI void Snowstorm_ApplyChaos(const char* contextPointer, double directionChaos, double speedChaos);
-SNOWSTORMAPI void Snowstorm_SetParticles(const char *contextPointer, double count);
+SNOWSTORMAPI void Snowstorm_Update(double contextId);
+SNOWSTORMAPI void Snowstorm_ApplyWind(double contextId, double xSpeed, double ySpeed);
+SNOWSTORMAPI void Snowstorm_ApplyChaos(double contextId, double directionChaos, double speedChaos);
+SNOWSTORMAPI void Snowstorm_SetParticles(double contextId, double count);
 
-SNOWSTORMAPI void Snowstorm_SetBufferAddress(const char *contextPointer, const char* bufferId);
+SNOWSTORMAPI void Snowstorm_SetBufferAddress(double contextId, const char* bufferId);
 
-SNOWSTORMAPI double Snowstorm_RequiredSnowBufferSize(const char *contextPointer);
-SNOWSTORMAPI double Snowstorm_FillSnowBuffer(const char *contextPointer);
+SNOWSTORMAPI double Snowstorm_RequiredSnowBufferSize(double contextId);
+SNOWSTORMAPI double Snowstorm_FillSnowBuffer(double contextId, double red, double green, double blue);
 
-SNOWSTORMAPI void Snowstorm_Destroy(const char *contextPointer);
+SNOWSTORMAPI void Snowstorm_Destroy(double contextId);
 
 #ifdef __cplusplus
 }
diff --git a/visualc/Snowstorm.vcxproj b/visualc/Snowstorm.vcxproj
index 3c5fccc..28302bc 100644
--- a/visualc/Snowstorm.vcxproj
+++ b/visualc/Snowstorm.vcxproj
@@ -45,7 +45,7 @@
     <PlatformToolset>v142</PlatformToolset>
   </PropertyGroup>
   <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
-    <PlatformToolset>v142</PlatformToolset>
+    <PlatformToolset>ClangCL</PlatformToolset>
   </PropertyGroup>
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
   <ImportGroup Label="ExtensionSettings">