summaryrefslogtreecommitdiff
path: root/src/libs/din/din.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/libs/din/din.c')
-rw-r--r--src/libs/din/din.c147
1 files changed, 147 insertions, 0 deletions
diff --git a/src/libs/din/din.c b/src/libs/din/din.c
new file mode 100644
index 0000000..2293c30
--- /dev/null
+++ b/src/libs/din/din.c
@@ -0,0 +1,147 @@
+/* implements a classical perlin noise function */
+/* https://en.wikipedia.org/wiki/Perlin_noise */
+
+#include <stdlib.h>
+
+#include "din.h"
+#include "v3f.h"
+
+typedef struct din_t {
+ int width, height, depth;
+ v3f_t grid[];
+} din_t;
+
+
+/* return random number between -1 and +1 */
+static inline float randf(void)
+{
+ return 2.f / RAND_MAX * rand() - 1.f;
+}
+
+
+void din_randomize(din_t *din)
+{
+ int x, y, z;
+
+ for (z = 0; z < din->depth; z++) {
+ for (y = 0; y < din->height; y++) {
+ for (x = 0; x < din->width; x++) {
+ v3f_t r;
+
+ r.x = randf();
+ r.y = randf();
+ r.z = randf();
+
+ din->grid[z * din->width * din->height + y * din->width + x] = v3f_normalize(&r);
+ }
+ }
+ }
+}
+
+
+din_t * din_new(int width, int height, int depth)
+{
+ din_t *din;
+
+ din = calloc(1, sizeof(din_t) + (sizeof(v3f_t) * (width * height * depth)));
+ if (!din)
+ return NULL;
+
+ din->width = width;
+ din->height = height;
+ din->depth = depth;
+
+ din_randomize(din);
+
+ return din;
+}
+
+
+void din_free(din_t *din)
+{
+ free(din);
+}
+
+
+static inline float dotgradient(const din_t *din, int x, int y, int z, const v3f_t coordinate)
+{
+ v3f_t distance = v3f_sub(&coordinate, &(v3f_t){.x = x, .y = y, .z = z});
+
+ return v3f_dot(&din->grid[z * din->width * din->height + y * din->width + x], &distance);
+}
+
+
+static inline float lerp(float a, float b, float t)
+{
+ return (1.0f - t) * a + t * b;
+}
+
+
+static inline float clamp(float x, float lowerlimit, float upperlimit) {
+ if (x < lowerlimit)
+ x = lowerlimit;
+
+ if (x > upperlimit)
+ x = upperlimit;
+
+ return x;
+}
+
+
+static inline float smootherstep(float edge0, float edge1, float x) {
+ x = clamp((x - edge0) / (edge1 - edge0), 0.f, 1.f);
+
+ return x * x * x * (x * (x * 6.f - 15.f) + 10.f);
+}
+
+
+/* coordinate is in a unit cube of -1...+1 */
+float din(din_t *din, v3f_t coordinate)
+{
+ int x0, y0, z0, x1, y1, z1;
+ float i1, i2, ii1, ii2;
+ float tx, ty, tz;
+ float n0, n1;
+
+ coordinate.x = 1.f + (coordinate.x * .5f + .5f) * (float)(din->width - 2);
+ coordinate.y = 1.f + (coordinate.y * .5f + .5f) * (float)(din->height - 2);
+ coordinate.z = 1.f + (coordinate.z * .5f + .5f) * (float)(din->depth - 2);
+
+ x0 = floorf(coordinate.x);
+ y0 = floorf(coordinate.y);
+ z0 = floorf(coordinate.z);
+
+ x1 = x0 + 1.f;
+ y1 = y0 + 1.f;
+ z1 = z0 + 1.f;
+
+ tx = coordinate.x - (float)x0;
+ ty = coordinate.y - (float)y0;
+ tz = coordinate.z - (float)z0;
+
+ n0 = dotgradient(din, x0, y0, z0, coordinate);
+ n1 = dotgradient(din, x1, y0, z0, coordinate);
+ tx = smootherstep(0.f, 1.f, tx);
+ i1 = lerp(n0, n1, tx);
+
+ n0 = dotgradient(din, x0, y1, z0, coordinate);
+ n1 = dotgradient(din, x1, y1, z0, coordinate);
+ i2 = lerp(n0, n1, tx);
+
+ ty = smootherstep(0.f, 1.f, ty);
+ ii1 = lerp(i1, i2, ty);
+
+ n0 = dotgradient(din, x0, y0, z1, coordinate);
+ n1 = dotgradient(din, x1, y0, z1, coordinate);
+ i1 = lerp(n0, n1, tx);
+
+ n0 = dotgradient(din, x0, y1, z1, coordinate);
+ n1 = dotgradient(din, x1, y1, z1, coordinate);
+ i2 = lerp(n0, n1, tx);
+
+ ii2 = lerp(i1, i2, ty);
+
+ tz = smootherstep(0.f, 1.f, tz);
+
+ return lerp(ii1, ii2, tz);
+}
© All Rights Reserved