From 2fd3d5202051e03303ac2b8e76976a7c4c8477f3 Mon Sep 17 00:00:00 2001 From: kwolekr Date: Sun, 7 Dec 2014 21:57:12 -0500 Subject: [PATCH] Add flags and lacunarity as new noise parameters Add 'absolute value' option to noise map functions Extend persistence modulation to 3D noise Extend 'eased' option to noise2d_perlin* functions Some noise.cpp formatting fixups --- src/cavegen.cpp | 2 +- src/dungeongen.cpp | 6 +- src/mapgen_v5.cpp | 26 ++-- src/mapgen_v6.cpp | 22 +-- src/mapgen_v7.cpp | 24 +-- src/mg_biome.cpp | 4 +- src/noise.cpp | 260 +++++++++++++++++--------------- src/noise.h | 63 +++++--- src/script/common/c_content.cpp | 22 +-- src/script/common/c_content.h | 4 +- src/script/lua_api/l_env.cpp | 6 +- src/script/lua_api/l_mapgen.cpp | 9 +- src/script/lua_api/l_noise.cpp | 53 +++++-- src/script/lua_api/l_noise.h | 4 +- src/settings.cpp | 11 +- src/test.cpp | 2 + 16 files changed, 305 insertions(+), 213 deletions(-) diff --git a/src/cavegen.cpp b/src/cavegen.cpp index 02eef72d8..4482d09d7 100644 --- a/src/cavegen.cpp +++ b/src/cavegen.cpp @@ -24,7 +24,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "mapgen_v7.h" #include "cavegen.h" -NoiseParams nparams_caveliquids(0, 1, v3f(150.0, 150.0, 150.0), 776, 3, 0.6); +NoiseParams nparams_caveliquids(0, 1, v3f(150.0, 150.0, 150.0), 776, 3, 0.6, 2.0); /////////////////////////////////////////////////////////////////////////////// diff --git a/src/dungeongen.cpp b/src/dungeongen.cpp index 2a89c714e..7462c275e 100644 --- a/src/dungeongen.cpp +++ b/src/dungeongen.cpp @@ -31,9 +31,9 @@ with this program; if not, write to the Free Software Foundation, Inc., //#define DGEN_USE_TORCHES -NoiseParams nparams_dungeon_rarity(0.0, 1.0, v3f(500.0, 500.0, 500.0), 0, 2, 0.8); -NoiseParams nparams_dungeon_wetness(0.0, 1.0, v3f(40.0, 40.0, 40.0), 32474, 4, 1.1); -NoiseParams nparams_dungeon_density(0.0, 1.0, v3f(2.5, 2.5, 2.5), 0, 2, 1.4); +NoiseParams nparams_dungeon_rarity(0.0, 1.0, v3f(500.0, 500.0, 500.0), 0, 2, 0.8, 2.0); +NoiseParams nparams_dungeon_wetness(0.0, 1.0, v3f(40.0, 40.0, 40.0), 32474, 4, 1.1, 2.0); +NoiseParams nparams_dungeon_density(0.0, 1.0, v3f(2.5, 2.5, 2.5), 0, 2, 1.4, 2.0); /////////////////////////////////////////////////////////////////////////////// diff --git a/src/mapgen_v5.cpp b/src/mapgen_v5.cpp index 33186678b..959e5c33f 100644 --- a/src/mapgen_v5.cpp +++ b/src/mapgen_v5.cpp @@ -130,14 +130,14 @@ MapgenV5::~MapgenV5() { MapgenV5Params::MapgenV5Params() { spflags = MGV5_BLOBS; - np_filler_depth = NoiseParams(0, 1, v3f(150, 150, 150), 261, 4, 0.7); - np_factor = NoiseParams(0, 1, v3f(250, 250, 250), 920381, 3, 0.45); - np_height = NoiseParams(0, 10, v3f(250, 250, 250), 84174, 4, 0.5); - np_cave1 = NoiseParams(0, 6, v3f(50, 50, 50), 52534, 4, 0.5); - np_cave2 = NoiseParams(0, 6, v3f(50, 50, 50), 10325, 4, 0.5); - np_ground = NoiseParams(0, 40, v3f(80, 80, 80), 983240, 4, 0.55); - np_crumble = NoiseParams(0, 1, v3f(20, 20, 20), 34413, 3, 1.3); - np_wetness = NoiseParams(0, 1, v3f(40, 40, 40), 32474, 4, 1.1); + np_filler_depth = NoiseParams(0, 1, v3f(150, 150, 150), 261, 4, 0.7, 2.0); + np_factor = NoiseParams(0, 1, v3f(250, 250, 250), 920381, 3, 0.45, 2.0); + np_height = NoiseParams(0, 10, v3f(250, 250, 250), 84174, 4, 0.5, 2.0); + np_cave1 = NoiseParams(0, 6, v3f(50, 50, 50), 52534, 4, 0.5, 2.0, NOISE_FLAG_EASED); + np_cave2 = NoiseParams(0, 6, v3f(50, 50, 50), 10325, 4, 0.5, 2.0, NOISE_FLAG_EASED); + np_ground = NoiseParams(0, 40, v3f(80, 80, 80), 983240, 4, 0.55, 2.0, NOISE_FLAG_EASED); + np_crumble = NoiseParams(0, 1, v3f(20, 20, 20), 34413, 3, 1.3, 2.0, NOISE_FLAG_EASED); + np_wetness = NoiseParams(0, 1, v3f(40, 40, 40), 32474, 4, 1.1, 2.0); } @@ -301,16 +301,16 @@ void MapgenV5::calculateNoise() { noise_height->perlinMap2D(x, z); noise_height->transformNoiseMap(); - noise_cave1->perlinMap3D(x, y, z, true); + noise_cave1->perlinMap3D(x, y, z); noise_cave1->transformNoiseMap(); - noise_cave2->perlinMap3D(x, y, z, true); + noise_cave2->perlinMap3D(x, y, z); noise_cave2->transformNoiseMap(); - noise_ground->perlinMap3D(x, y, z, true); + noise_ground->perlinMap3D(x, y, z); noise_ground->transformNoiseMap(); if (spflags & MGV5_BLOBS) { - noise_crumble->perlinMap3D(x, y, z, true); - noise_wetness->perlinMap3D(x, y, z, false); + noise_crumble->perlinMap3D(x, y, z); + noise_wetness->perlinMap3D(x, y, z); } noise_heat->perlinMap2D(x, z); diff --git a/src/mapgen_v6.cpp b/src/mapgen_v6.cpp index f1ba2a486..b8474cb53 100644 --- a/src/mapgen_v6.cpp +++ b/src/mapgen_v6.cpp @@ -122,17 +122,17 @@ MapgenV6Params::MapgenV6Params() { freq_desert = 0.45; freq_beach = 0.15; - np_terrain_base = NoiseParams(-4, 20.0, v3f(250.0, 250.0, 250.0), 82341, 5, 0.6); - np_terrain_higher = NoiseParams(20, 16.0, v3f(500.0, 500.0, 500.0), 85039, 5, 0.6); - np_steepness = NoiseParams(0.85,0.5, v3f(125.0, 125.0, 125.0), -932, 5, 0.7); - np_height_select = NoiseParams(0.5, 1.0, v3f(250.0, 250.0, 250.0), 4213, 5, 0.69); - np_mud = NoiseParams(4, 2.0, v3f(200.0, 200.0, 200.0), 91013, 3, 0.55); - np_beach = NoiseParams(0, 1.0, v3f(250.0, 250.0, 250.0), 59420, 3, 0.50); - np_biome = NoiseParams(0, 1.0, v3f(250.0, 250.0, 250.0), 9130, 3, 0.50); - np_cave = NoiseParams(6, 6.0, v3f(250.0, 250.0, 250.0), 34329, 3, 0.50); - np_humidity = NoiseParams(0.5, 0.5, v3f(500.0, 500.0, 500.0), 72384, 4, 0.66); - np_trees = NoiseParams(0, 1.0, v3f(125.0, 125.0, 125.0), 2, 4, 0.66); - np_apple_trees = NoiseParams(0, 1.0, v3f(100.0, 100.0, 100.0), 342902, 3, 0.45); + np_terrain_base = NoiseParams(-4, 20.0, v3f(250.0, 250.0, 250.0), 82341, 5, 0.6, 2.0); + np_terrain_higher = NoiseParams(20, 16.0, v3f(500.0, 500.0, 500.0), 85039, 5, 0.6, 2.0); + np_steepness = NoiseParams(0.85,0.5, v3f(125.0, 125.0, 125.0), -932, 5, 0.7, 2.0); + np_height_select = NoiseParams(0.5, 1.0, v3f(250.0, 250.0, 250.0), 4213, 5, 0.69, 2.0); + np_mud = NoiseParams(4, 2.0, v3f(200.0, 200.0, 200.0), 91013, 3, 0.55, 2.0); + np_beach = NoiseParams(0, 1.0, v3f(250.0, 250.0, 250.0), 59420, 3, 0.50, 2.0); + np_biome = NoiseParams(0, 1.0, v3f(250.0, 250.0, 250.0), 9130, 3, 0.50, 2.0); + np_cave = NoiseParams(6, 6.0, v3f(250.0, 250.0, 250.0), 34329, 3, 0.50, 2.0); + np_humidity = NoiseParams(0.5, 0.5, v3f(500.0, 500.0, 500.0), 72384, 4, 0.66, 2.0); + np_trees = NoiseParams(0, 1.0, v3f(125.0, 125.0, 125.0), 2, 4, 0.66, 2.0); + np_apple_trees = NoiseParams(0, 1.0, v3f(100.0, 100.0, 100.0), 342902, 3, 0.45, 2.0); } diff --git a/src/mapgen_v7.cpp b/src/mapgen_v7.cpp index 82bc4aae8..7b7377611 100644 --- a/src/mapgen_v7.cpp +++ b/src/mapgen_v7.cpp @@ -122,15 +122,15 @@ MapgenV7::~MapgenV7() { MapgenV7Params::MapgenV7Params() { spflags = MGV7_MOUNTAINS | MGV7_RIDGES; - np_terrain_base = NoiseParams(4, 70, v3f(300, 300, 300), 82341, 6, 0.7); - np_terrain_alt = NoiseParams(4, 25, v3f(600, 600, 600), 5934, 5, 0.6); - np_terrain_persist = NoiseParams(0.6, 0.1, v3f(500, 500, 500), 539, 3, 0.6); - np_height_select = NoiseParams(-0.5, 1, v3f(250, 250, 250), 4213, 5, 0.69); - np_filler_depth = NoiseParams(0, 1.2, v3f(150, 150, 150), 261, 4, 0.7); - np_mount_height = NoiseParams(100, 30, v3f(500, 500, 500), 72449, 4, 0.6); - np_ridge_uwater = NoiseParams(0, 1, v3f(500, 500, 500), 85039, 4, 0.6); - np_mountain = NoiseParams(0, 1, v3f(250, 350, 250), 5333, 5, 0.68); - np_ridge = NoiseParams(0, 1, v3f(100, 100, 100), 6467, 4, 0.75); + np_terrain_base = NoiseParams(4, 70, v3f(300, 300, 300), 82341, 6, 0.7, 2.0); + np_terrain_alt = NoiseParams(4, 25, v3f(600, 600, 600), 5934, 5, 0.6, 2.0); + np_terrain_persist = NoiseParams(0.6, 0.1, v3f(500, 500, 500), 539, 3, 0.6, 2.0); + np_height_select = NoiseParams(-0.5, 1, v3f(250, 250, 250), 4213, 5, 0.69, 2.0); + np_filler_depth = NoiseParams(0, 1.2, v3f(150, 150, 150), 261, 4, 0.7, 2.0); + np_mount_height = NoiseParams(100, 30, v3f(500, 500, 500), 72449, 4, 0.6, 2.0); + np_ridge_uwater = NoiseParams(0, 1, v3f(500, 500, 500), 85039, 4, 0.6, 2.0); + np_mountain = NoiseParams(0, 1, v3f(250, 350, 250), 5333, 5, 0.68, 2.0); + np_ridge = NoiseParams(0, 1, v3f(100, 100, 100), 6467, 4, 0.75, 2.0); } @@ -278,10 +278,10 @@ void MapgenV7::calculateNoise() { for (int i = 0; i != csize.X * csize.Z; i++) persistmap[i] = rangelim(persistmap[i], 0.4, 0.9); - noise_terrain_base->perlinMap2DModulated(x, z, persistmap); + noise_terrain_base->perlinMap2D(x, z, persistmap); noise_terrain_base->transformNoiseMap(); - noise_terrain_alt->perlinMap2DModulated(x, z, persistmap); + noise_terrain_alt->perlinMap2D(x, z, persistmap); noise_terrain_alt->transformNoiseMap(); noise_filler_depth->perlinMap2D(x, z); @@ -728,7 +728,7 @@ void MapgenV7::addTopNodes() { #endif -NoiseParams nparams_v7_def_cave(6, 6.0, v3f(250.0, 250.0, 250.0), 34329, 3, 0.50); +NoiseParams nparams_v7_def_cave(6, 6.0, v3f(250.0, 250.0, 250.0), 34329, 3, 0.50, 2.0); void MapgenV7::generateCaves(int max_stone_y) { PseudoRandom ps(blockseed + 21343); diff --git a/src/mg_biome.cpp b/src/mg_biome.cpp index 91b7290d8..dff73e34f 100644 --- a/src/mg_biome.cpp +++ b/src/mg_biome.cpp @@ -29,8 +29,8 @@ with this program; if not, write to the Free Software Foundation, Inc., const char *BiomeManager::ELEMENT_TITLE = "biome"; -NoiseParams nparams_biome_def_heat(50, 50, v3f(500.0, 500.0, 500.0), 5349, 3, 0.70); -NoiseParams nparams_biome_def_humidity(50, 50, v3f(500.0, 500.0, 500.0), 842, 3, 0.55); +NoiseParams nparams_biome_def_heat(50, 50, v3f(500.0, 500.0, 500.0), 5349, 3, 0.70, 2.0); +NoiseParams nparams_biome_def_humidity(50, 50, v3f(500.0, 500.0, 500.0), 842, 3, 0.55, 2.0); /////////////////////////////////////////////////////////////////////////////// diff --git a/src/noise.cpp b/src/noise.cpp index 2d1b8d624..ac84ab20a 100644 --- a/src/noise.cpp +++ b/src/noise.cpp @@ -29,6 +29,7 @@ #include // memset #include "debug.h" #include "util/numeric.h" +#include "util/string.h" #include "exceptions.h" #define NOISE_MAGIC_X 1619 @@ -36,6 +37,10 @@ #define NOISE_MAGIC_Z 52591 #define NOISE_MAGIC_SEED 1013 +typedef float (*Interp2dFxn)( + float v00, float v10, float v01, float v11, + float x, float y); + typedef float (*Interp3dFxn)( float v000, float v100, float v010, float v110, float v001, float v101, float v011, float v111, @@ -46,11 +51,18 @@ float cos_lookup[16] = { 1.0, -0.9238, -0.7071, -0.3826, 0, 0.3826, 0.7071, 0.9238 }; +FlagDesc flagdesc_noiseparams[] = { + {"defaults", NOISE_FLAG_DEFAULTS}, + {"eased", NOISE_FLAG_EASED}, + {"absvalue", NOISE_FLAG_ABSVALUE}, + {"pointbuffer", NOISE_FLAG_POINTBUFFER}, + {"simplex", NOISE_FLAG_SIMPLEX}, + {NULL, 0} +}; /////////////////////////////////////////////////////////////////////////////// -//noise poly: p(n) = 60493n^3 + 19990303n + 137612589 float noise2d(int x, int y, int seed) { int n = (NOISE_MAGIC_X * x + NOISE_MAGIC_Y * y @@ -79,95 +91,85 @@ float dotProduct(float vx, float vy, float wx, float wy) inline float linearInterpolation(float v0, float v1, float t) { - return v0 + (v1 - v0) * t; + return v0 + (v1 - v0) * t; } float biLinearInterpolation( - float v00, float v10, - float v01, float v11, - float x, float y) + float v00, float v10, + float v01, float v11, + float x, float y) { - float tx = easeCurve(x); - float ty = easeCurve(y); - float u = linearInterpolation(v00, v10, tx); - float v = linearInterpolation(v01, v11, tx); - return linearInterpolation(u, v, ty); + float tx = easeCurve(x); + float ty = easeCurve(y); + return ( + v00 * (1 - tx) * (1 - ty) + + v10 * tx * (1 - ty) + + v01 * (1 - tx) * ty + + v11 * tx * ty + ); + //float u = linearInterpolation(v00, v10, x); + //float v = linearInterpolation(v01, v11, x); + //return linearInterpolation(u, v, y); } float biLinearInterpolationNoEase( - float x0y0, float x1y0, - float x0y1, float x1y1, - float x, float y) -{ - float u = linearInterpolation(x0y0, x1y0, x); - float v = linearInterpolation(x0y1, x1y1, x); - return linearInterpolation(u, v, y); -} - -/* -float triLinearInterpolation( - float v000, float v100, float v010, float v110, - float v001, float v101, float v011, float v111, - float x, float y, float z) -{ - float u = biLinearInterpolation(v000, v100, v010, v110, x, y); - float v = biLinearInterpolation(v001, v101, v011, v111, x, y); - return linearInterpolation(u, v, z); -} - - -float triLinearInterpolationNoEase( - float v000, float v100, float v010, float v110, - float v001, float v101, float v011, float v111, - float x, float y, float z) + float v00, float v10, + float v01, float v11, + float x, float y) { - float u = biLinearInterpolationNoEase(v000, v100, v010, v110, x, y); - float v = biLinearInterpolationNoEase(v001, v101, v011, v111, x, y); - return linearInterpolation(u, v, z); + float tx = x; + float ty = y; + return ( + v00 * (1 - tx) * (1 - ty) + + v10 * tx * (1 - ty) + + v01 * (1 - tx) * ty + + v11 * tx * ty + ); } -*/ float triLinearInterpolation( - float v000, float v100, float v010, float v110, - float v001, float v101, float v011, float v111, - float x, float y, float z) + float v000, float v100, float v010, float v110, + float v001, float v101, float v011, float v111, + float x, float y, float z) { float tx = easeCurve(x); float ty = easeCurve(y); float tz = easeCurve(z); - return ( v000 * (1 - tx) * (1 - ty) * (1 - tz) + - v100 * tx * (1 - ty) * (1 - tz) + - v010 * (1 - tx) * ty * (1 - tz) + - v110 * tx * ty * (1 - tz) + - v001 * (1 - tx) * (1 - ty) * tz + - v101 * tx * (1 - ty) * tz + - v011 * (1 - tx) * ty * tz + - v111 * tx * ty * tz + v100 * tx * (1 - ty) * (1 - tz) + + v010 * (1 - tx) * ty * (1 - tz) + + v110 * tx * ty * (1 - tz) + + v001 * (1 - tx) * (1 - ty) * tz + + v101 * tx * (1 - ty) * tz + + v011 * (1 - tx) * ty * tz + + v111 * tx * ty * tz ); + //float u = biLinearInterpolation(v000, v100, v010, v110, x, y); + //float v = biLinearInterpolation(v001, v101, v011, v111, x, y); + //return linearInterpolation(u, v, z); } float triLinearInterpolationNoEase( - float v000, float v100, float v010, float v110, - float v001, float v101, float v011, float v111, - float x, float y, float z) + float v000, float v100, float v010, float v110, + float v001, float v101, float v011, float v111, + float x, float y, float z) { float tx = x; float ty = y; float tz = z; return ( v000 * (1 - tx) * (1 - ty) * (1 - tz) + - v100 * tx * (1 - ty) * (1 - tz) + - v010 * (1 - tx) * ty * (1 - tz) + - v110 * tx * ty * (1 - tz) + - v001 * (1 - tx) * (1 - ty) * tz + - v101 * tx * (1 - ty) * tz + - v011 * (1 - tx) * ty * tz + - v111 * tx * ty * tz + v100 * tx * (1 - ty) * (1 - tz) + + v010 * (1 - tx) * ty * (1 - tz) + + v110 * tx * ty * (1 - tz) + + v001 * (1 - tx) * (1 - ty) * tz + + v101 * tx * (1 - ty) * tz + + v011 * (1 - tx) * ty * tz + + v111 * tx * ty * tz ); } @@ -198,7 +200,7 @@ float noise2d_gradient(float x, float y, int seed) #endif -float noise2d_gradient(float x, float y, int seed) +float noise2d_gradient(float x, float y, int seed, bool eased) { // Calculate the integer coordinates int x0 = myfloor(x); @@ -212,7 +214,10 @@ float noise2d_gradient(float x, float y, int seed) float v01 = noise2d(x0, y0+1, seed); float v11 = noise2d(x0+1, y0+1, seed); // Interpolate - return biLinearInterpolation(v00, v10, v01, v11, xl, yl); + if (eased) + return biLinearInterpolation(v00, v10, v01, v11, xl, yl); + else + return biLinearInterpolationNoEase(v00, v10, v01, v11, xl, yl); } @@ -251,14 +256,14 @@ float noise3d_gradient(float x, float y, float z, int seed, bool eased) float noise2d_perlin(float x, float y, int seed, - int octaves, float persistence) + int octaves, float persistence, bool eased) { float a = 0; float f = 1.0; float g = 1.0; for (int i = 0; i < octaves; i++) { - a += g * noise2d_gradient(x * f, y * f, seed + i); + a += g * noise2d_gradient(x * f, y * f, seed + i, eased); f *= 2.0; g *= persistence; } @@ -267,14 +272,13 @@ float noise2d_perlin(float x, float y, int seed, float noise2d_perlin_abs(float x, float y, int seed, - int octaves, float persistence) + int octaves, float persistence, bool eased) { float a = 0; float f = 1.0; float g = 1.0; - for (int i = 0; i < octaves; i++) - { - a += g * fabs(noise2d_gradient(x * f, y * f, seed + i)); + for (int i = 0; i < octaves; i++) { + a += g * fabs(noise2d_gradient(x * f, y * f, seed + i, eased)); f *= 2.0; g *= persistence; } @@ -283,13 +287,12 @@ float noise2d_perlin_abs(float x, float y, int seed, float noise3d_perlin(float x, float y, float z, int seed, - int octaves, float persistence, bool eased) + int octaves, float persistence, bool eased) { float a = 0; float f = 1.0; float g = 1.0; - for (int i = 0; i < octaves; i++) - { + for (int i = 0; i < octaves; i++) { a += g * noise3d_gradient(x * f, y * f, z * f, seed + i, eased); f *= 2.0; g *= persistence; @@ -299,13 +302,12 @@ float noise3d_perlin(float x, float y, float z, int seed, float noise3d_perlin_abs(float x, float y, float z, int seed, - int octaves, float persistence, bool eased) + int octaves, float persistence, bool eased) { float a = 0; float f = 1.0; float g = 1.0; - for (int i = 0; i < octaves; i++) - { + for (int i = 0; i < octaves; i++) { a += g * fabs(noise3d_gradient(x * f, y * f, z * f, seed + i, eased)); f *= 2.0; g *= persistence; @@ -317,7 +319,7 @@ float noise3d_perlin_abs(float x, float y, float z, int seed, float contour(float v) { v = fabs(v); - if(v >= 1.0) + if (v >= 1.0) return 0.0; return (1.0 - v); } @@ -335,6 +337,12 @@ Noise::Noise(NoiseParams *np, int seed, int sx, int sy, int sz) this->sz = sz; this->noisebuf = NULL; + + if (np->flags & NOISE_FLAG_DEFAULTS) { + // By default, only 2d noise is eased. + if (sz == 1) + np->flags |= NOISE_FLAG_EASED; + } resizeNoiseBuf(sz > 1); try { @@ -437,6 +445,9 @@ void Noise::gradientMap2D( int index, i, j, x0, y0, noisex, noisey; int nlx, nly; + Interp2dFxn interpolate = (np->flags & NOISE_FLAG_EASED) ? + biLinearInterpolation : biLinearInterpolationNoEase; + x0 = floor(x); y0 = floor(y); u = x - (float)x0; @@ -463,7 +474,7 @@ void Noise::gradientMap2D( u = orig_u; noisex = 0; for (i = 0; i != sx; i++) { - buf[index++] = biLinearInterpolation(v00, v10, v01, v11, u, v); + buf[index++] = interpolate(v00, v10, v01, v11, u, v); u += step_x; if (u >= 1.0) { u -= 1.0; @@ -489,7 +500,7 @@ void Noise::gradientMap2D( void Noise::gradientMap3D( float x, float y, float z, float step_x, float step_y, float step_z, - int seed, bool eased) + int seed) { float v000, v010, v100, v110; float v001, v011, v101, v111; @@ -497,7 +508,7 @@ void Noise::gradientMap3D( int index, i, j, k, x0, y0, z0, noisex, noisey, noisez; int nlx, nly, nlz; - Interp3dFxn interpolate = eased ? + Interp3dFxn interpolate = (np->flags & NOISE_FLAG_EASED) ? triLinearInterpolation : triLinearInterpolationNoEase; x0 = floor(x); @@ -576,7 +587,7 @@ void Noise::gradientMap3D( #undef idx -float *Noise::perlinMap2D(float x, float y) +float *Noise::perlinMap2D(float x, float y, float *persistence_map) { float f = 1.0, g = 1.0; size_t bufsize = sx * sy; @@ -586,55 +597,30 @@ float *Noise::perlinMap2D(float x, float y) memset(result, 0, sizeof(float) * bufsize); - for (int oct = 0; oct < np->octaves; oct++) { - gradientMap2D(x * f, y * f, - f / np->spread.X, f / np->spread.Y, - seed + np->seed + oct); - + float *gmap = NULL; + if (persistence_map) { + gmap = new float[bufsize]; for (size_t i = 0; i != bufsize; i++) - result[i] += g * buf[i]; - - f *= 2.0; - g *= np->persist; + gmap[i] = 1.0; } - return result; -} - - -float *Noise::perlinMap2DModulated(float x, float y, float *persist_map) -{ - float f = 1.0; - size_t bufsize = sx * sy; - - x /= np->spread.X; - y /= np->spread.Y; - - memset(result, 0, sizeof(float) * bufsize); - - float *g = new float[bufsize]; - for (size_t i = 0; i != bufsize; i++) - g[i] = 1.0; - - for (int oct = 0; oct < np->octaves; oct++) { + for (size_t oct = 0; oct < np->octaves; oct++) { gradientMap2D(x * f, y * f, f / np->spread.X, f / np->spread.Y, seed + np->seed + oct); - for (size_t i = 0; i != bufsize; i++) { - result[i] += g[i] * buf[i]; - g[i] *= persist_map[i]; - } + updateResults(g, gmap, persistence_map, bufsize); - f *= 2.0; + f *= np->lacunarity; + g *= np->persist; } - delete[] g; + delete[] gmap; return result; } -float *Noise::perlinMap3D(float x, float y, float z, bool eased) +float *Noise::perlinMap3D(float x, float y, float z, float *persistence_map) { float f = 1.0, g = 1.0; size_t bufsize = sx * sy * sz; @@ -645,22 +631,58 @@ float *Noise::perlinMap3D(float x, float y, float z, bool eased) memset(result, 0, sizeof(float) * bufsize); - for (int oct = 0; oct < np->octaves; oct++) { + float *gmap = NULL; + if (persistence_map) { + gmap = new float[bufsize]; + for (size_t i = 0; i != bufsize; i++) + gmap[i] = 1.0; + } + + for (size_t oct = 0; oct < np->octaves; oct++) { gradientMap3D(x * f, y * f, z * f, f / np->spread.X, f / np->spread.Y, f / np->spread.Z, - seed + np->seed + oct, eased); + seed + np->seed + oct); - for (size_t i = 0; i != bufsize; i++) - result[i] += g * buf[i]; + updateResults(g, gmap, persistence_map, bufsize); - f *= 2.0; + f *= np->lacunarity; g *= np->persist; } + delete[] gmap; return result; } +void Noise::updateResults(float g, float *gmap, + float *persistence_map, size_t bufsize) +{ + // This looks very ugly, but it is 50-70% faster than having + // conditional statements inside the loop + if (np->flags & NOISE_FLAG_ABSVALUE) { + if (persistence_map) { + for (size_t i = 0; i != bufsize; i++) { + result[i] += gmap[i] * fabs(buf[i]); + gmap[i] *= persistence_map[i]; + } + } else { + for (size_t i = 0; i != bufsize; i++) + result[i] += g * fabs(buf[i]); + } + } else { + if (persistence_map) { + for (size_t i = 0; i != bufsize; i++) { + result[i] += gmap[i] * buf[i]; + gmap[i] *= persistence_map[i]; + } + } else { + for (size_t i = 0; i != bufsize; i++) + result[i] += g * buf[i]; + } + } +} + + void Noise::transformNoiseMap() { size_t i = 0; diff --git a/src/noise.h b/src/noise.h index 7d055d2e1..1f7bdbbf4 100644 --- a/src/noise.h +++ b/src/noise.h @@ -28,6 +28,9 @@ #include "debug.h" #include "irr_v3d.h" +#include "util/string.h" + +extern FlagDesc flagdesc_noiseparams[]; class PseudoRandom { @@ -66,6 +69,14 @@ private: int m_next; }; +#define NOISE_FLAG_DEFAULTS 0x01 +#define NOISE_FLAG_EASED 0x02 +#define NOISE_FLAG_ABSVALUE 0x04 + +//// TODO(hmmmm): implement these! +#define NOISE_FLAG_POINTBUFFER 0x08 +#define NOISE_FLAG_SIMPLEX 0x10 + struct NoiseParams { float offset; float scale; @@ -73,20 +84,32 @@ struct NoiseParams { s32 seed; u16 octaves; float persist; - bool eased; - - NoiseParams() {} + float lacunarity; + u32 flags; + + NoiseParams() { + offset = 0.0f; + scale = 1.0f; + spread = v3f(250, 250, 250); + seed = 12345; + octaves = 3; + persist = 0.6f; + lacunarity = 2.0f; + flags = NOISE_FLAG_DEFAULTS; + } - NoiseParams(float offset_, float scale_, v3f spread_, - int seed_, int octaves_, float persist_, bool eased_=false) + NoiseParams(float offset_, float scale_, v3f spread_, s32 seed_, + u16 octaves_, float persist_, float lacunarity_, + u32 flags_=NOISE_FLAG_DEFAULTS) { - offset = offset_; - scale = scale_; - spread = spread_; - seed = seed_; - octaves = octaves_; - persist = persist_; - eased = eased_; + offset = offset_; + scale = scale_; + spread = spread_; + seed = seed_; + octaves = octaves_; + persist = persist_; + lacunarity = lacunarity_; + flags = flags_; } }; @@ -123,10 +146,12 @@ public: void gradientMap3D( float x, float y, float z, float step_x, float step_y, float step_z, - int seed, bool eased=false); - float *perlinMap2D(float x, float y); - float *perlinMap2DModulated(float x, float y, float *persist_map); - float *perlinMap3D(float x, float y, float z, bool eased=false); + int seed); + + float *perlinMap2D(float x, float y, float *persistence_map=NULL); + float *perlinMap3D(float x, float y, float z, float *persistence_map=NULL); + + void updateResults(float g, float *gmap, float *persistence_map, size_t bufsize); void transformNoiseMap(); }; @@ -134,14 +159,14 @@ public: float noise2d(int x, int y, int seed); float noise3d(int x, int y, int z, int seed); -float noise2d_gradient(float x, float y, int seed); +float noise2d_gradient(float x, float y, int seed, bool eased=true); float noise3d_gradient(float x, float y, float z, int seed, bool eased=false); float noise2d_perlin(float x, float y, int seed, - int octaves, float persistence); + int octaves, float persistence, bool eased=true); float noise2d_perlin_abs(float x, float y, int seed, - int octaves, float persistence); + int octaves, float persistence, bool eased=true); float noise3d_perlin(float x, float y, float z, int seed, int octaves, float persistence, bool eased=false); diff --git a/src/script/common/c_content.cpp b/src/script/common/c_content.cpp index 799251bcf..1c78f139f 100644 --- a/src/script/common/c_content.cpp +++ b/src/script/common/c_content.cpp @@ -975,11 +975,11 @@ void luaentity_get(lua_State *L, u16 id) } /******************************************************************************/ -NoiseParams *read_noiseparams(lua_State *L, int index) +NoiseParams *get_noiseparams(lua_State *L, int index) { NoiseParams *np = new NoiseParams; - if (!read_noiseparams_nc(L, index, np)) { + if (!read_noiseparams(L, index, np)) { delete np; np = NULL; } @@ -987,7 +987,7 @@ NoiseParams *read_noiseparams(lua_State *L, int index) return np; } -bool read_noiseparams_nc(lua_State *L, int index, NoiseParams *np) +bool read_noiseparams(lua_State *L, int index, NoiseParams *np) { if (index < 0) index = lua_gettop(L) + 1 + index; @@ -995,12 +995,16 @@ bool read_noiseparams_nc(lua_State *L, int index, NoiseParams *np) if (!lua_istable(L, index)) return false; - np->offset = getfloatfield_default(L, index, "offset", 0.0); - np->scale = getfloatfield_default(L, index, "scale", 0.0); - np->persist = getfloatfield_default(L, index, "persist", 0.0); - np->seed = getintfield_default(L, index, "seed", 0); - np->octaves = getintfield_default(L, index, "octaves", 0); - np->eased = getboolfield_default(L, index, "eased", false); + np->offset = getfloatfield_default(L, index, "offset", 0.0); + np->scale = getfloatfield_default(L, index, "scale", 0.0); + np->persist = getfloatfield_default(L, index, "persist", 0.0); + np->lacunarity = getfloatfield_default(L, index, "lacunarity", 2.0); + np->seed = getintfield_default(L, index, "seed", 0); + np->octaves = getintfield_default(L, index, "octaves", 0); + + u32 flags = 0, flagmask = 0; + np->flags = getflagsfield(L, index, "flags", flagdesc_noiseparams, + &flags, &flagmask) ? flags : NOISE_FLAG_DEFAULTS; lua_getfield(L, index, "spread"); np->spread = read_v3f(L, -1); diff --git a/src/script/common/c_content.h b/src/script/common/c_content.h index 5b4dff2bd..02e3e29fa 100644 --- a/src/script/common/c_content.h +++ b/src/script/common/c_content.h @@ -147,9 +147,9 @@ bool string_to_enum (const EnumString *spec, int &result, const std::string &str); -NoiseParams* read_noiseparams (lua_State *L, int index); +NoiseParams* get_noiseparams (lua_State *L, int index); -bool read_noiseparams_nc (lua_State *L, int index, +bool read_noiseparams (lua_State *L, int index, NoiseParams *np); bool get_schematic (lua_State *L, int index, Schematic *schem, diff --git a/src/script/lua_api/l_env.cpp b/src/script/lua_api/l_env.cpp index 130b15c0b..8f1f851d7 100644 --- a/src/script/lua_api/l_env.cpp +++ b/src/script/lua_api/l_env.cpp @@ -608,13 +608,13 @@ int ModApiEnvMod::l_get_perlin_map(lua_State *L) { GET_ENV_PTR; - NoiseParams *np = read_noiseparams(L, 1); - if (!np) + NoiseParams np; + if (!read_noiseparams(L, 1, &np)) return 0; v3s16 size = read_v3s16(L, 2); int seed = (int)(env->getServerMap().getSeed()); - LuaPerlinNoiseMap *n = new LuaPerlinNoiseMap(np, seed, size); + LuaPerlinNoiseMap *n = new LuaPerlinNoiseMap(&np, seed, size); *(void **)(lua_newuserdata(L, sizeof(void *))) = n; luaL_getmetatable(L, "PerlinNoiseMap"); lua_setmetatable(L, -2); diff --git a/src/script/lua_api/l_mapgen.cpp b/src/script/lua_api/l_mapgen.cpp index 5f9266c2b..78cf389e0 100644 --- a/src/script/lua_api/l_mapgen.cpp +++ b/src/script/lua_api/l_mapgen.cpp @@ -274,7 +274,10 @@ int ModApiMapgen::l_set_noiseparam_defaults(lua_State *L) lua_pushnil(L); while (lua_next(L, 1)) { - if (read_noiseparams_nc(L, -1, &np)) { + if (read_noiseparams(L, -1, &np)) { + /// TODO(hmmmm): Update this for newer noiseparam formats + /// Right now this is safe because serializeStructToString() won't + /// touch memory outside of what the format string specifies if (!serializeStructToString(&val, NOISEPARAMS_FMT_STR, &np)) continue; if (!lua_isstring(L, -2)) @@ -406,7 +409,7 @@ int ModApiMapgen::l_register_decoration(lua_State *L) //// Get NoiseParams to define how decoration is placed lua_getfield(L, index, "noise_params"); - deco->np = read_noiseparams(L, -1); + deco->np = get_noiseparams(L, -1); lua_pop(L, 1); //// Get biomes associated with this decoration (if any) @@ -556,7 +559,7 @@ int ModApiMapgen::l_register_ore(lua_State *L) getflagsfield(L, index, "flags", flagdesc_ore, &ore->flags, NULL); lua_getfield(L, index, "noise_params"); - ore->np = read_noiseparams(L, -1); + ore->np = get_noiseparams(L, -1); lua_pop(L, 1); u32 id = oremgr->add(ore); diff --git a/src/script/lua_api/l_noise.cpp b/src/script/lua_api/l_noise.cpp index 96ed93643..2a57df0f6 100644 --- a/src/script/lua_api/l_noise.cpp +++ b/src/script/lua_api/l_noise.cpp @@ -31,6 +31,7 @@ int LuaPerlinNoise::gc_object(lua_State *L) return 0; } + int LuaPerlinNoise::l_get2d(lua_State *L) { NO_MAP_LOCK_REQUIRED; @@ -40,6 +41,8 @@ int LuaPerlinNoise::l_get2d(lua_State *L) lua_pushnumber(L, val); return 1; } + + int LuaPerlinNoise::l_get3d(lua_State *L) { NO_MAP_LOCK_REQUIRED; @@ -60,10 +63,12 @@ LuaPerlinNoise::LuaPerlinNoise(int a_seed, int a_octaves, float a_persistence, { } + LuaPerlinNoise::~LuaPerlinNoise() { } + // LuaPerlinNoise(seed, octaves, persistence, scale) // Creates an LuaPerlinNoise and leaves it on top of stack int LuaPerlinNoise::create_object(lua_State *L) @@ -80,15 +85,18 @@ int LuaPerlinNoise::create_object(lua_State *L) return 1; } + LuaPerlinNoise* LuaPerlinNoise::checkobject(lua_State *L, int narg) { NO_MAP_LOCK_REQUIRED; luaL_checktype(L, narg, LUA_TUSERDATA); void *ud = luaL_checkudata(L, narg, className); - if(!ud) luaL_typerror(L, narg, className); + if (!ud) + luaL_typerror(L, narg, className); return *(LuaPerlinNoise**)ud; // unbox pointer } + void LuaPerlinNoise::Register(lua_State *L) { lua_newtable(L); @@ -117,6 +125,7 @@ void LuaPerlinNoise::Register(lua_State *L) lua_register(L, className, create_object); } + const char LuaPerlinNoise::className[] = "PerlinNoise"; const luaL_reg LuaPerlinNoise::methods[] = { luamethod(LuaPerlinNoise, get2d), @@ -124,11 +133,11 @@ const luaL_reg LuaPerlinNoise::methods[] = { {0,0} }; + /* PerlinNoiseMap */ - int LuaPerlinNoiseMap::gc_object(lua_State *L) { LuaPerlinNoiseMap *o = *(LuaPerlinNoiseMap **)(lua_touserdata(L, 1)); @@ -136,6 +145,7 @@ int LuaPerlinNoiseMap::gc_object(lua_State *L) return 0; } + int LuaPerlinNoiseMap::l_get2dMap(lua_State *L) { NO_MAP_LOCK_REQUIRED; @@ -160,6 +170,7 @@ int LuaPerlinNoiseMap::l_get2dMap(lua_State *L) return 1; } + int LuaPerlinNoiseMap::l_get2dMap_flat(lua_State *L) { NO_MAP_LOCK_REQUIRED; @@ -181,6 +192,7 @@ int LuaPerlinNoiseMap::l_get2dMap_flat(lua_State *L) return 1; } + int LuaPerlinNoiseMap::l_get3dMap(lua_State *L) { NO_MAP_LOCK_REQUIRED; @@ -190,7 +202,7 @@ int LuaPerlinNoiseMap::l_get3dMap(lua_State *L) v3f p = read_v3f(L, 2); Noise *n = o->noise; - n->perlinMap3D(p.X, p.Y, p.Z, n->np->eased); + n->perlinMap3D(p.X, p.Y, p.Z); lua_newtable(L); for (int z = 0; z != n->sz; z++) { @@ -208,6 +220,7 @@ int LuaPerlinNoiseMap::l_get3dMap(lua_State *L) return 1; } + int LuaPerlinNoiseMap::l_get3dMap_flat(lua_State *L) { NO_MAP_LOCK_REQUIRED; @@ -216,7 +229,7 @@ int LuaPerlinNoiseMap::l_get3dMap_flat(lua_State *L) v3f p = read_v3f(L, 2); Noise *n = o->noise; - n->perlinMap3D(p.X, p.Y, p.Z, n->np->eased); + n->perlinMap3D(p.X, p.Y, p.Z); int maplen = n->sx * n->sy * n->sz; @@ -230,37 +243,42 @@ int LuaPerlinNoiseMap::l_get3dMap_flat(lua_State *L) return 1; } -LuaPerlinNoiseMap::LuaPerlinNoiseMap(NoiseParams *np, int seed, v3s16 size) { + +LuaPerlinNoiseMap::LuaPerlinNoiseMap(NoiseParams *np, int seed, v3s16 size) +{ + memcpy(&m_noise_params, np, sizeof(m_noise_params)); try { - noise = new Noise(np, seed, size.X, size.Y, size.Z); + noise = new Noise(&m_noise_params, seed, size.X, size.Y, size.Z); } catch (InvalidNoiseParamsException &e) { throw LuaError(e.what()); } } + LuaPerlinNoiseMap::~LuaPerlinNoiseMap() { - delete noise->np; delete noise; } + // LuaPerlinNoiseMap(np, size) // Creates an LuaPerlinNoiseMap and leaves it on top of stack int LuaPerlinNoiseMap::create_object(lua_State *L) { - NoiseParams *np = read_noiseparams(L, 1); - if (!np) + NoiseParams np; + if (!read_noiseparams(L, 1, &np)) return 0; v3s16 size = read_v3s16(L, 2); - LuaPerlinNoiseMap *o = new LuaPerlinNoiseMap(np, 0, size); + LuaPerlinNoiseMap *o = new LuaPerlinNoiseMap(&np, 0, size); *(void **)(lua_newuserdata(L, sizeof(void *))) = o; luaL_getmetatable(L, className); lua_setmetatable(L, -2); return 1; } -LuaPerlinNoiseMap* LuaPerlinNoiseMap::checkobject(lua_State *L, int narg) + +LuaPerlinNoiseMap *LuaPerlinNoiseMap::checkobject(lua_State *L, int narg) { luaL_checktype(L, narg, LUA_TUSERDATA); @@ -271,6 +289,7 @@ LuaPerlinNoiseMap* LuaPerlinNoiseMap::checkobject(lua_State *L, int narg) return *(LuaPerlinNoiseMap **)ud; // unbox pointer } + void LuaPerlinNoiseMap::Register(lua_State *L) { lua_newtable(L); @@ -299,6 +318,7 @@ void LuaPerlinNoiseMap::Register(lua_State *L) lua_register(L, className, create_object); } + const char LuaPerlinNoiseMap::className[] = "PerlinNoiseMap"; const luaL_reg LuaPerlinNoiseMap::methods[] = { luamethod(LuaPerlinNoiseMap, get2dMap), @@ -320,6 +340,7 @@ int LuaPseudoRandom::gc_object(lua_State *L) return 0; } + // next(self, min=0, max=32767) -> get next value int LuaPseudoRandom::l_next(lua_State *L) { @@ -354,19 +375,23 @@ LuaPseudoRandom::LuaPseudoRandom(int seed): { } + LuaPseudoRandom::~LuaPseudoRandom() { } + const PseudoRandom& LuaPseudoRandom::getItem() const { return m_pseudo; } + PseudoRandom& LuaPseudoRandom::getItem() { return m_pseudo; } + // LuaPseudoRandom(seed) // Creates an LuaPseudoRandom and leaves it on top of stack int LuaPseudoRandom::create_object(lua_State *L) @@ -379,14 +404,17 @@ int LuaPseudoRandom::create_object(lua_State *L) return 1; } + LuaPseudoRandom* LuaPseudoRandom::checkobject(lua_State *L, int narg) { luaL_checktype(L, narg, LUA_TUSERDATA); void *ud = luaL_checkudata(L, narg, className); - if(!ud) luaL_typerror(L, narg, className); + if (!ud) + luaL_typerror(L, narg, className); return *(LuaPseudoRandom**)ud; // unbox pointer } + void LuaPseudoRandom::Register(lua_State *L) { lua_newtable(L); @@ -415,6 +443,7 @@ void LuaPseudoRandom::Register(lua_State *L) lua_register(L, className, create_object); } + const char LuaPseudoRandom::className[] = "PseudoRandom"; const luaL_reg LuaPseudoRandom::methods[] = { luamethod(LuaPseudoRandom, next), diff --git a/src/script/lua_api/l_noise.h b/src/script/lua_api/l_noise.h index 65a927882..6f6173fc2 100644 --- a/src/script/lua_api/l_noise.h +++ b/src/script/lua_api/l_noise.h @@ -54,7 +54,7 @@ public: // Creates an LuaPerlinNoise and leaves it on top of stack static int create_object(lua_State *L); - static LuaPerlinNoise* checkobject(lua_State *L, int narg); + static LuaPerlinNoise *checkobject(lua_State *L, int narg); static void Register(lua_State *L); }; @@ -63,7 +63,7 @@ public: LuaPerlinNoiseMap */ class LuaPerlinNoiseMap : public ModApiBase { -private: + NoiseParams m_noise_params; Noise *noise; static const char className[]; static const luaL_reg methods[]; diff --git a/src/settings.cpp b/src/settings.cpp index fa7da806d..09b413ed0 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -350,10 +350,10 @@ bool Settings::updateConfigFile(const char *filename) std::ifstream is(filename); std::ostringstream os(std::ios_base::binary); - + bool was_modified = updateConfigObject(is, os, ""); is.close(); - + if (!was_modified) return true; @@ -591,6 +591,11 @@ bool Settings::getNoiseParamsFromGroup(const std::string &name, group->getS32NoEx("seed", np.seed); group->getU16NoEx("octaves", np.octaves); group->getFloatNoEx("persistence", np.persist); + group->getFloatNoEx("lacunarity", np.lacunarity); + + np.flags = 0; + if (!group->getFlagStrNoEx("flags", np.flags, flagdesc_noiseparams)) + np.flags = NOISE_FLAG_DEFAULTS; return true; } @@ -896,6 +901,8 @@ void Settings::setNoiseParams(const std::string &name, const NoiseParams &np) group->setS32("seed", np.seed); group->setU16("octaves", np.octaves); group->setFloat("persistence", np.persist); + group->setFloat("lacunarity", np.lacunarity); + group->setFlagStr("flags", np.flags, flagdesc_noiseparams, np.flags); Settings *old_group; { diff --git a/src/test.cpp b/src/test.cpp index 30252d85b..1a0d4bb83 100644 --- a/src/test.cpp +++ b/src/test.cpp @@ -467,6 +467,8 @@ struct TestPath: public TestBase " with leading whitespace!\n" \ "\"\"\"\n" \ "np_terrain = {\n" \ + " flags = defaults\n" \ + " lacunarity = 2\n" \ " octaves = 6\n" \ " offset = 3.5\n" \ " persistence = 0.7\n" \ -- 2.25.1