shithub: slug

Download patch

ref: c61556ec4bbf4bdbebf95cc70e2367a207e8eafb
parent: 307ba8a8d9d7c0088462bc4e947639b4593ce597
author: phil9 <telephil9@gmail.com>
date: Tue Dec 6 14:27:57 EST 2022

implement math.noise() function

	the implementation is Ken Perlin's reference implementation

--- a/a.h
+++ b/a.h
@@ -34,6 +34,7 @@
 double	map(double, double, double, double, double);
 double	lerp(double, double, double);
 double	randomgaussian(double, double);
+double	noise(double, double, double);
 
 extern int		drawing;
 extern int		looping;
--- a/api.c
+++ b/api.c
@@ -737,7 +737,7 @@
 	a = luaL_checknumber(L, 1);
 	b = luaL_checknumber(L, 2);
 	r = luaL_checknumber(L, 3);
-	lua_pushnumber(L, lerp(a, b, r));
+	lua_pushnumber(L, lerp(r, a, b));
 	return 1;
 }
 
@@ -766,6 +766,17 @@
 	return 1;
 }
 
+int
+cnoise(lua_State *L)
+{
+	double x, y;
+
+	x = luaL_checknumber(L, 1);
+	y = luaL_optnumber(L, 2, 0.0);
+	lua_pushnumber(L, noise(x, y, 0.0));
+	return 1;
+}
+
 void
 registerfunc(lua_State *L, const char *name, int(*f)(lua_State*))
 {
@@ -831,4 +842,5 @@
 	registermathfunc(L, "norm", cnorm);
 	registermathfunc(L, "lerp", clerp);
 	registermathfunc(L, "randomGaussian", crandomgaussian);
+	registermathfunc(L, "noise", cnoise);
 }
--- a/math.c
+++ b/math.c
@@ -1,7 +1,7 @@
 #include "a.h"
 
 double
-lerp(double a, double b, double r)
+lerp(double r, double a, double b)
 {
 	if(r < 0.0)
 		r = 0.0;
@@ -51,3 +51,70 @@
 	return y1 * sd + mean;
 }
 
+/* Perlin noise function reference implementation by Ken Perlin */
+
+int p[512] = { 151, 160, 137, 91, 90, 15, 131, 13, 201, 95, 96, 53, 194, 233, 7, 225, 140, 36, 
+               103, 30, 69, 142, 8, 99, 37, 240, 21, 10, 23, 190, 6, 148, 247, 120, 234, 75, 0, 
+               26, 197, 62, 94, 252, 219, 203, 117, 35, 11, 32, 57, 177, 33, 88, 237, 149, 56, 
+               87, 174, 20, 125, 136, 171, 168, 68, 175, 74, 165, 71, 134, 139, 48, 27, 166, 
+               77, 146, 158, 231, 83, 111, 229, 122, 60, 211, 133, 230, 220, 105, 92, 41, 55, 
+               46, 245, 40, 244, 102, 143, 54, 65, 25, 63, 161, 1, 216, 80, 73, 209, 76, 132, 
+               187, 208, 89, 18, 169, 200, 196, 135, 130, 116, 188, 159, 86, 164, 100, 109, 
+               198, 173, 186, 3, 64, 52, 217, 226, 250, 124, 123, 5, 202, 38, 147, 118, 126, 
+               255, 82, 85, 212, 207, 206, 59, 227, 47, 16, 58, 17, 182, 189, 28, 42, 223, 183, 
+               170, 213, 119, 248, 152, 2, 44, 154, 163, 70, 221, 153, 101, 155, 167, 43, 
+               172, 9, 129, 22, 39, 253, 19, 98, 108, 110, 79, 113, 224, 232, 178, 185, 112, 
+               104, 218, 246, 97, 228, 251, 34, 242, 193, 238, 210, 144, 12, 191, 179, 162, 
+               241, 81, 51, 145, 235, 249, 14, 239, 107, 49, 192, 214, 31, 181, 199, 106, 
+               157, 184, 84, 204, 176, 115, 121, 50, 45, 127, 4, 150, 254, 138, 236, 205, 
+               93, 222, 114, 67, 29, 24, 72, 243, 141, 128, 195, 78, 66, 215, 61, 156, 180 };
+
+double
+fade(double t) 
+{ 
+	return t * t * t * (t * (t * 6 - 15) + 10);
+}
+
+double
+grad(int hash, double x, double y, double z) 
+{
+	int h;
+	double u, v;
+
+	h = hash & 15;
+	u = h<8 ? x : y;
+	v = h<4 ? y : h==12||h==14 ? x : z;
+	return ((h&1) == 0 ? u : -u) + ((h&2) == 0 ? v : -v);
+}
+   
+double
+noise(double x, double y, double z)
+{
+	int X, Y, Z, A, B, AA, AB, BA, BB;
+	double u, v, w;
+
+	X = (int)floor(x) & 255;
+	Y = (int)floor(y) & 255;
+	Z = (int)floor(z) & 255;
+	x -= floor(x);                                
+	y -= floor(y);                                
+	z -= floor(z);
+	u = fade(x);
+	v = fade(y);
+	w = fade(z);
+	A = p[X  ]+Y;
+	AA = p[A]+Z;
+	AB = p[A+1]+Z;
+	B = p[X+1]+Y;
+	BA = p[B]+Z;
+	BB = p[B+1]+Z;
+
+ 	return lerp(w, lerp(v, lerp(u, grad(p[AA  ], x  , y  , z   ),
+                                   grad(p[BA  ], x-1, y  , z   )),
+                           lerp(u, grad(p[AB  ], x  , y-1, z   ),
+                                   grad(p[BB  ], x-1, y-1, z   ))),
+                   lerp(v, lerp(u, grad(p[AA+1], x  , y  , z-1 ), 
+                                   grad(p[BA+1], x-1, y  , z-1 )), 
+                           lerp(u, grad(p[AB+1], x  , y-1, z-1 ),
+                                   grad(p[BB+1], x-1, y-1, z-1 ))));
+}
--- /dev/null
+++ b/samples/noise.lua
@@ -1,0 +1,21 @@
+#!/bin/slug
+
+function setup()
+	size(400, 400)
+	background(0)
+	loadPixels()
+	for y = 1, 399 do
+		for x = 1, 399 do
+			n = math.noise(x * 0.01, y * 0.01)
+			n = n + 1.0
+			n = n / 2.0
+			v = math.floor(255 * n)
+			pixels[x + width * y] = color(v, v, v)
+		end
+	end
+	updatePixels()
+end
+
+function draw()
+	noLoop()
+end