diff --git a/finders.c b/finders.c index 90ed652..1f1f348 100644 --- a/finders.c +++ b/finders.c @@ -4409,8 +4409,8 @@ int getParaRange(const DoublePerlinNoise *para, double *pmin, double *pmax, int maxrad, maxiter; int err = 1; - *pmin = DBL_MAX; - *pmax = -DBL_MAX; + if (pmin) *pmin = DBL_MAX; + if (pmax) *pmax = -DBL_MAX; lmin = DBL_MAX, lmax = 0; for (i = 0; i < para->octA.octcnt; i++) @@ -4436,8 +4436,8 @@ int getParaRange(const DoublePerlinNoise *para, double *pmin, double *pmax, if (err) return err; } - if (v < *pmin) *pmin = v; - if (v > *pmax) *pmax = v; + if (pmin && v < *pmin) *pmin = v; + if (pmax && v > *pmax) *pmax = v; } } return 0; @@ -4451,14 +4451,20 @@ int getParaRange(const DoublePerlinNoise *para, double *pmin, double *pmax, { for (i = 0; i < w; i += step) { - v = getParaDescent(para, +factor, x, z, w, h, i, j, - step, step, dr, data, func); - if (v != v) goto L_end; - if (v < *pmin) *pmin = v; - v = -getParaDescent(para, -factor, x, z, w, h, i, j, - step, step, dr, data, func); - if (v != v) goto L_end; - if (v > *pmax) *pmax = v; + if (pmin) + { + v = getParaDescent(para, +factor, x, z, w, h, i, j, + step, step, dr, data, func); + if (v != v) goto L_end; + if (v < *pmin) *pmin = v; + } + if (pmax) + { + v = -getParaDescent(para, -factor, x, z, w, h, i, j, + step, step, dr, data, func); + if (v != v) goto L_end; + if (v > *pmax) *pmax = v; + } } } @@ -4498,93 +4504,97 @@ int getParaRange(const DoublePerlinNoise *para, double *pmin, double *pmax, skipsiz = (ww+1) * (hh+1) * sizeof(*skip); skip = (char*) malloc(skipsiz); - // look for minima - memset(skip, 0, skipsiz); + if (pmin) + { // look for minima + memset(skip, 0, skipsiz); - for (jj = 0; jj <= hh; jj++) - { - j = jj * step; if (j >= h) j = h-1; - for (ii = 0; ii <= ww; ii++) + for (jj = 0; jj <= hh; jj++) { - i = ii * step; if (i >= w) i = w-1; - if (skip[jj*ww+ii]) continue; - - v = factor * sampleDoublePerlin(para, x+i, 0, z+j); - if (func) + j = jj * step; if (j >= h) j = h-1; + for (ii = 0; ii <= ww; ii++) { - int e = func(data, x+i, z+j, v); - if (e) - { - err = e; - goto L_end; - } - } - // not looking for maxima yet, but we'll update the bounds anyway - if (v > *pmax) *pmax = v; + i = ii * step; if (i >= w) i = w-1; + if (skip[jj*ww+ii]) continue; - dr = beta * (v - *pmin) / vdif; - if (dr > 1.0) - { // difference is too large -> mark visinity to be skipped - int a, b, r = (int) dr; - for (b = 0; b < r; b++) + v = factor * sampleDoublePerlin(para, x+i, 0, z+j); + if (func) { - if (b+jj < 0 || b+jj >= hh) continue; - for (a = -r+1; a < r; a++) + int e = func(data, x+i, z+j, v); + if (e) { - if (a+ii < 0 || a+ii >= ww) continue; - skip[(b+jj)*ww + (a+ii)] = 1; + err = e; + goto L_end; } } - continue; + // not looking for maxima yet, but update the bounds anyway + if (pmax && v > *pmax) *pmax = v; + + dr = beta * (v - *pmin) / vdif; + if (dr > 1.0) + { // difference is too large -> mark visinity to be skipped + int a, b, r = (int) dr; + for (b = 0; b < r; b++) + { + if (b+jj < 0 || b+jj >= hh) continue; + for (a = -r+1; a < r; a++) + { + if (a+ii < 0 || a+ii >= ww) continue; + skip[(b+jj)*ww + (a+ii)] = 1; + } + } + continue; + } + v = getParaDescent(para, +factor, x, z, w, h, i, j, + maxrad, maxiter, dr, data, func); + if (v != v) goto L_end; + if (v < *pmin) *pmin = v; } - v = getParaDescent(para, +factor, x, z, w, h, i, j, - maxrad, maxiter, dr, data, func); - if (v != v) goto L_end; - if (v < *pmin) *pmin = v; } } - // look for maxima - memset(skip, 0, skipsiz); + if (pmax) + { // look for maxima + memset(skip, 0, skipsiz); - for (jj = 0; jj <= hh; jj++) - { - j = jj * step; if (j >= h) j = h-1; - for (ii = 0; ii <= ww; ii++) + for (jj = 0; jj <= hh; jj++) { - i = ii * step; if (i >= w) i = w-1; - if (skip[jj*ww+ii]) continue; - - v = -factor * sampleDoublePerlin(para, x+i, 0, z+j); - if (func) + j = jj * step; if (j >= h) j = h-1; + for (ii = 0; ii <= ww; ii++) { - int e = func(data, x+i, z+j, -v); - if (e) - { - err = e; - goto L_end; - } - } + i = ii * step; if (i >= w) i = w-1; + if (skip[jj*ww+ii]) continue; - dr = beta * (v + *pmax) / vdif; - if (dr > 1.0) - { // difference too large -> mark visinity to be skipped - int a, b, r = (int) dr; - for (b = 0; b < r; b++) + v = -factor * sampleDoublePerlin(para, x+i, 0, z+j); + if (func) { - if (b+jj < 0 || b+jj >= hh) continue; - for (a = -r+1; a < r; a++) + int e = func(data, x+i, z+j, -v); + if (e) { - if (a+ii < 0 || a+ii >= ww) continue; - skip[(b+jj)*ww + (a+ii)] = 1; + err = e; + goto L_end; } } - continue; + + dr = beta * (v + *pmax) / vdif; + if (dr > 1.0) + { // difference too large -> mark visinity to be skipped + int a, b, r = (int) dr; + for (b = 0; b < r; b++) + { + if (b+jj < 0 || b+jj >= hh) continue; + for (a = -r+1; a < r; a++) + { + if (a+ii < 0 || a+ii >= ww) continue; + skip[(b+jj)*ww + (a+ii)] = 1; + } + } + continue; + } + v = -getParaDescent(para, -factor, x, z, w, h, i, j, + maxrad, maxiter, dr, data, func); + if (v != v) goto L_end; + if (v > *pmax) *pmax = v; } - v = -getParaDescent(para, -factor, x, z, w, h, i, j, - maxrad, maxiter, dr, data, func); - if (v != v) goto L_end; - if (v > *pmax) *pmax = v; } } diff --git a/finders.h b/finders.h index bcdc910..4b8576b 100644 --- a/finders.h +++ b/finders.h @@ -623,7 +623,7 @@ double getParaDescent(const DoublePerlinNoise *para, double factor, * error is returned. * * The results are written to pmin and pmax (which would be cast to an integer - * during boime mapping). + * during boime mapping). Nullable, to look for minima and maxima separately. */ int getParaRange(const DoublePerlinNoise *para, double *pmin, double *pmax, int x, int z, int w, int h, void *data, int (*func)(void*,int,int,double)); diff --git a/makefile b/makefile index 37873bd..34888b6 100644 --- a/makefile +++ b/makefile @@ -21,7 +21,7 @@ debug: CFLAGS += -DDEBUG -O0 -ggdb3 debug: libcubiomes release: CFLAGS += -O3 -g3 release: libcubiomes -native: CFLAGS += -O3 -march=native +native: CFLAGS += -O3 -march=native -ffast-math native: libcubiomes ifeq ($(OS),Windows_NT) diff --git a/noise.c b/noise.c index f66d68d..a297407 100644 --- a/noise.c +++ b/noise.c @@ -5,11 +5,6 @@ #include -double maintainPrecision(double x) -{ - return x - floor(x / 33554432.0 + 0.5) * 33554432.0; -} - // grad() /* static double indexedLerp(int idx, double d1, double d2, double d3) @@ -61,17 +56,18 @@ void perlinInit(PerlinNoise *noise, uint64_t *seed) noise->amplitude = 1.0; noise->lacunarity = 1.0; + uint8_t *idx = noise->d; for (i = 0; i < 256; i++) { - noise->d[i] = i; + idx[i] = i; } for (i = 0; i < 256; i++) { int j = nextInt(seed, 256 - i) + i; - uint8_t n = noise->d[i]; - noise->d[i] = noise->d[j]; - noise->d[j] = n; - noise->d[i + 256] = noise->d[i]; + uint8_t n = idx[i]; + idx[i] = idx[j]; + idx[j] = n; + idx[i + 256] = idx[i]; } } @@ -85,30 +81,31 @@ void xPerlinInit(PerlinNoise *noise, Xoroshiro *xr) noise->amplitude = 1.0; noise->lacunarity = 1.0; + uint8_t *idx = noise->d; for (i = 0; i < 256; i++) { - noise->d[i] = i; + idx[i] = i; } for (i = 0; i < 256; i++) { int j = xNextInt(xr, 256 - i) + i; - uint8_t n = noise->d[i]; - noise->d[i] = noise->d[j]; - noise->d[j] = n; - noise->d[i + 256] = noise->d[i]; + uint8_t n = idx[i]; + idx[i] = idx[j]; + idx[j] = n; + idx[i + 256] = idx[i]; } } - double samplePerlin(const PerlinNoise *noise, double d1, double d2, double d3, double yamp, double ymin) { d1 += noise->a; d2 += noise->b; d3 += noise->c; - int i1 = (int)d1 - (int)(d1 < 0); - int i2 = (int)d2 - (int)(d2 < 0); - int i3 = (int)d3 - (int)(d3 < 0); + const uint8_t *idx = noise->d; + int i1 = (int) floor(d1); + int i2 = (int) floor(d2); + int i3 = (int) floor(d3); d1 -= i1; d2 -= i2; d3 -= i3; @@ -126,21 +123,22 @@ double samplePerlin(const PerlinNoise *noise, double d1, double d2, double d3, i2 &= 0xff; i3 &= 0xff; - int a1 = noise->d[i1] + i2; - int a2 = noise->d[a1] + i3; - int a3 = noise->d[a1+1] + i3; - int b1 = noise->d[i1+1] + i2; - int b2 = noise->d[b1] + i3; - int b3 = noise->d[b1+1] + i3; + int a1 = idx[i1] + i2; + int b1 = idx[i1+1] + i2; - double l1 = indexedLerp(noise->d[a2], d1, d2, d3); - double l2 = indexedLerp(noise->d[b2], d1-1, d2, d3); - double l3 = indexedLerp(noise->d[a3], d1, d2-1, d3); - double l4 = indexedLerp(noise->d[b3], d1-1, d2-1, d3); - double l5 = indexedLerp(noise->d[a2+1], d1, d2, d3-1); - double l6 = indexedLerp(noise->d[b2+1], d1-1, d2, d3-1); - double l7 = indexedLerp(noise->d[a3+1], d1, d2-1, d3-1); - double l8 = indexedLerp(noise->d[b3+1], d1-1, d2-1, d3-1); + int a2 = idx[a1] + i3; + int a3 = idx[a1+1] + i3; + int b2 = idx[b1] + i3; + int b3 = idx[b1+1] + i3; + + double l1 = indexedLerp(idx[a2], d1, d2, d3); + double l2 = indexedLerp(idx[b2], d1-1, d2, d3); + double l3 = indexedLerp(idx[a3], d1, d2-1, d3); + double l4 = indexedLerp(idx[b3], d1-1, d2-1, d3); + double l5 = indexedLerp(idx[a2+1], d1, d2, d3-1); + double l6 = indexedLerp(idx[b2+1], d1-1, d2, d3-1); + double l7 = indexedLerp(idx[a3+1], d1, d2-1, d3-1); + double l8 = indexedLerp(idx[b3+1], d1-1, d2-1, d3-1); l1 = lerp(t1, l1, l2); l3 = lerp(t1, l3, l4); @@ -192,7 +190,6 @@ double sampleSimplex2D(const PerlinNoise *noise, double x, double y) return 70.0 * t; } - void octaveInit(OctaveNoise *noise, uint64_t *seed, PerlinNoise *octaves, int omin, int len) { diff --git a/noise.h b/noise.h index 610b113..26c58c1 100644 --- a/noise.h +++ b/noise.h @@ -2,6 +2,7 @@ #define NOISE_H_ #include "rng.h" +#include STRUCT(PerlinNoise) { @@ -30,7 +31,15 @@ extern "C" #endif /// Helper -double maintainPrecision(double x); +static inline ATTR(hot, const) +double maintainPrecision(double x) +{ // This is a highly performance critical function that is used to correct + // progressing errors from float-maths. However, since cubiomes uses + // doubles anyway, this seems useless in practice. + + //return x - round(x / 33554432.0) * 33554432.0; + return x; +} /// Perlin noise void perlinInit(PerlinNoise *noise, uint64_t *seed);