From 548d99bb456931192609e8c6fa1eb4c80679af42 Mon Sep 17 00:00:00 2001 From: kwolekr Date: Thu, 19 May 2016 03:40:22 -0400 Subject: [PATCH] Cavegen: Move V5-style caves to CavesNoiseIntersection --- src/cavegen.cpp | 96 ++++++++++++++++++++++++++++++++++++++++++ src/cavegen.h | 37 ++++++++++++++++ src/mapgen.cpp | 52 ++--------------------- src/mapgen.h | 5 +-- src/mapgen_flat.cpp | 10 +---- src/mapgen_fractal.cpp | 10 +---- src/mapgen_v5.cpp | 10 ++--- src/mapgen_v7.cpp | 10 ++--- src/mapgen_valleys.h | 3 ++ 9 files changed, 151 insertions(+), 82 deletions(-) diff --git a/src/cavegen.cpp b/src/cavegen.cpp index 5f0af9699..51309ad60 100644 --- a/src/cavegen.cpp +++ b/src/cavegen.cpp @@ -23,10 +23,106 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "mapgen_v5.h" #include "mapgen_v6.h" #include "mapgen_v7.h" +#include "mg_biome.h" #include "cavegen.h" NoiseParams nparams_caveliquids(0, 1, v3f(150.0, 150.0, 150.0), 776, 3, 0.6, 2.0); + +//// +//// CavesNoiseIntersection +//// + +CavesNoiseIntersection::CavesNoiseIntersection( + INodeDefManager *nodedef, BiomeManager *biomemgr, v3s16 chunksize, + NoiseParams *np_cave1, NoiseParams *np_cave2, int seed, float cave_width) +{ + assert(nodedef); + assert(biomemgr); + + m_ndef = nodedef; + m_bmgr = biomemgr; + + m_csize = chunksize; + m_cave_width = cave_width; + + m_ystride = m_csize.X; + m_zstride_1d = m_csize.X * (m_csize.Y + 1); + + // Noises are created using 1-down overgeneration + // A Nx-by-1-by-Nz-sized plane is at the bottom of the desired for + // re-carving the solid overtop placed for blocking sunlight + noise_cave1 = new Noise(np_cave1, seed, m_csize.X, m_csize.Y + 1, m_csize.Z); + noise_cave2 = new Noise(np_cave2, seed, m_csize.X, m_csize.Y + 1, m_csize.Z); +} + + +CavesNoiseIntersection::~CavesNoiseIntersection() +{ + delete noise_cave1; + delete noise_cave2; +} + + +void CavesNoiseIntersection::generateCaves(MMVManip *vm, + v3s16 nmin, v3s16 nmax, u8 *biomemap) +{ + assert(vm); + assert(biomemap); + + noise_cave1->perlinMap3D(nmin.X, nmin.Y - 1, nmin.Z); + noise_cave2->perlinMap3D(nmin.X, nmin.Y - 1, nmin.Z); + + v3s16 em = vm->m_area.getExtent(); + u32 index2d = 0; + + for (s16 z = nmin.Z; z <= nmax.Z; z++) + for (s16 x = nmin.X; x <= nmax.X; x++, index2d++) { + bool column_is_open = false; // Is column open to overground + bool is_tunnel = false; // Is tunnel or tunnel floor + u32 vi = vm->m_area.index(x, nmax.Y, z); + u32 index3d = (z - nmin.Z) * m_zstride_1d + m_csize.Y * m_ystride + + (x - nmin.X); + // Biome of column + Biome *biome = (Biome *)m_bmgr->getRaw(biomemap[index2d]); + + // Don't excavate the overgenerated stone at nmax.Y + 1, + // this creates a 'roof' over the tunnel, preventing light in + // tunnels at mapchunk borders when generating mapchunks upwards. + // This 'roof' is removed when the mapchunk above is generated. + for (s16 y = nmax.Y; y >= nmin.Y - 1; y--, + index3d -= m_ystride, + vm->m_area.add_y(em, vi, -1)) { + + content_t c = vm->m_data[vi].getContent(); + if (c == CONTENT_AIR || c == biome->c_water_top || + c == biome->c_water) { + column_is_open = true; + continue; + } + // Ground + float d1 = contour(noise_cave1->result[index3d]); + float d2 = contour(noise_cave2->result[index3d]); + + if (d1 * d2 > m_cave_width && m_ndef->get(c).is_ground_content) { + // In tunnel and ground content, excavate + vm->m_data[vi] = MapNode(CONTENT_AIR); + is_tunnel = true; + } else { + // Not in tunnel or not ground content + if (is_tunnel && column_is_open && + (c == biome->c_filler || c == biome->c_stone)) + // Tunnel entrance floor + vm->m_data[vi] = MapNode(biome->c_top); + + column_is_open = false; + is_tunnel = false; + } + } + } +} + + //// //// CavesRandomWalk //// diff --git a/src/cavegen.h b/src/cavegen.h index 68e0c8bc5..da0894635 100644 --- a/src/cavegen.h +++ b/src/cavegen.h @@ -25,6 +25,43 @@ with this program; if not, write to the Free Software Foundation, Inc., class GenerateNotifier; +/* + CavesNoiseIntersection is a cave digging algorithm that carves smooth, + web-like, continuous tunnels at points where the density of the intersection + between two separate 3d noises is above a certain value. This value, + cave_width, can be modified to set the effective width of these tunnels. + + This algorithm is relatively heavyweight, taking ~80ms to generate an + 80x80x80 chunk of map on a modern processor. Use sparingly! + + TODO(hmmmm): Remove dependency on biomes + TODO(hmmmm): Find alternative to overgeneration as solution for sunlight issue +*/ +class CavesNoiseIntersection { +public: + CavesNoiseIntersection(INodeDefManager *nodedef, BiomeManager *biomemgr, + v3s16 chunksize, NoiseParams *np_cave1, NoiseParams *np_cave2, + int seed, float cave_width); + ~CavesNoiseIntersection(); + + void generateCaves(MMVManip *vm, v3s16 nmin, v3s16 nmax, u8 *biomemap); + +private: + INodeDefManager *m_ndef; + BiomeManager *m_bmgr; + + // configurable parameters + v3s16 m_csize; + float m_cave_width; + + // intermediate state variables + u16 m_ystride; + u16 m_zstride_1d; + + Noise *noise_cave1; + Noise *noise_cave2; +}; + /* CavesRandomWalk is an implementation of a cave-digging algorithm that operates on the principle of a "random walk" to approximate the stochiastic diff --git a/src/mapgen.cpp b/src/mapgen.cpp index 09671d845..7e959533d 100644 --- a/src/mapgen.cpp +++ b/src/mapgen.cpp @@ -542,56 +542,10 @@ void MapgenBasic::generateCaves(s16 max_stone_y, s16 large_cave_depth) if (max_stone_y < node_min.Y) return; - noise_cave1->perlinMap3D(node_min.X, node_min.Y - 1, node_min.Z); - noise_cave2->perlinMap3D(node_min.X, node_min.Y - 1, node_min.Z); + CavesNoiseIntersection caves_noise(ndef, bmgr, csize, + &np_cave1, &np_cave2, seed, cave_width); - v3s16 em = vm->m_area.getExtent(); - u32 index2d = 0; - - for (s16 z = node_min.Z; z <= node_max.Z; z++) - for (s16 x = node_min.X; x <= node_max.X; x++, index2d++) { - bool column_is_open = false; // Is column open to overground - bool is_tunnel = false; // Is tunnel or tunnel floor - u32 vi = vm->m_area.index(x, node_max.Y, z); - u32 index3d = (z - node_min.Z) * zstride_1d + csize.Y * ystride + - (x - node_min.X); - // Biome of column - Biome *biome = (Biome *)bmgr->getRaw(biomemap[index2d]); - - // Don't excavate the overgenerated stone at node_max.Y + 1, - // this creates a 'roof' over the tunnel, preventing light in - // tunnels at mapchunk borders when generating mapchunks upwards. - // This 'roof' is removed when the mapchunk above is generated. - for (s16 y = node_max.Y; y >= node_min.Y - 1; y--, - index3d -= ystride, - vm->m_area.add_y(em, vi, -1)) { - - content_t c = vm->m_data[vi].getContent(); - if (c == CONTENT_AIR || c == biome->c_water_top || - c == biome->c_water) { - column_is_open = true; - continue; - } - // Ground - float d1 = contour(noise_cave1->result[index3d]); - float d2 = contour(noise_cave2->result[index3d]); - - if (d1 * d2 > cave_width && ndef->get(c).is_ground_content) { - // In tunnel and ground content, excavate - vm->m_data[vi] = MapNode(CONTENT_AIR); - is_tunnel = true; - } else { - // Not in tunnel or not ground content - if (is_tunnel && column_is_open && - (c == biome->c_filler || c == biome->c_stone)) - // Tunnel entrance floor - vm->m_data[vi] = MapNode(biome->c_top); - - column_is_open = false; - is_tunnel = false; - } - } - } + caves_noise.generateCaves(vm, node_min, node_max, biomemap); if (node_max.Y > large_cave_depth) return; diff --git a/src/mapgen.h b/src/mapgen.h index 3ec148296..8db01f5c1 100644 --- a/src/mapgen.h +++ b/src/mapgen.h @@ -220,8 +220,6 @@ public: BiomeManager *bmgr; Noise *noise_filler_depth; - Noise *noise_cave1; - Noise *noise_cave2; v3s16 node_min; v3s16 node_max; @@ -235,7 +233,8 @@ public: content_t c_sandstone; int ystride; - int zstride_1d; + NoiseParams np_cave1; + NoiseParams np_cave2; float cave_width; MapgenBasic(int mapgenid, MapgenParams *params, EmergeManager *emerge); diff --git a/src/mapgen_flat.cpp b/src/mapgen_flat.cpp index 2cbf9ace0..a541a54f3 100644 --- a/src/mapgen_flat.cpp +++ b/src/mapgen_flat.cpp @@ -58,8 +58,6 @@ MapgenFlat::MapgenFlat(int mapgenid, MapgenParams *params, EmergeManager *emerge //// amount of elements to skip for the next index //// for noise/height/biome maps (not vmanip) this->ystride = csize.X; - // 1-down overgeneration - this->zstride_1d = csize.X * (csize.Y + 1); this->heightmap = new s16[csize.X * csize.Z]; @@ -78,10 +76,8 @@ MapgenFlat::MapgenFlat(int mapgenid, MapgenParams *params, EmergeManager *emerge noise_terrain = new Noise(&sp->np_terrain, seed, csize.X, csize.Z); noise_filler_depth = new Noise(&sp->np_filler_depth, seed, csize.X, csize.Z); - //// 3D noise - // 1-down overgeneraion - noise_cave1 = new Noise(&sp->np_cave1, seed, csize.X, csize.Y + 1, csize.Z); - noise_cave2 = new Noise(&sp->np_cave2, seed, csize.X, csize.Y + 1, csize.Z); + MapgenBasic::np_cave1 = sp->np_cave1; + MapgenBasic::np_cave2 = sp->np_cave2; //// Initialize biome generator biomegen = emerge->biomemgr->createBiomeGen( @@ -119,8 +115,6 @@ MapgenFlat::~MapgenFlat() { delete noise_terrain; delete noise_filler_depth; - delete noise_cave1; - delete noise_cave2; delete biomegen; diff --git a/src/mapgen_fractal.cpp b/src/mapgen_fractal.cpp index 3217d52e2..dca10d253 100644 --- a/src/mapgen_fractal.cpp +++ b/src/mapgen_fractal.cpp @@ -56,8 +56,6 @@ MapgenFractal::MapgenFractal(int mapgenid, MapgenParams *params, EmergeManager * //// amount of elements to skip for the next index //// for noise/height/biome maps (not vmanip) this->ystride = csize.X; - // 1-down overgeneration - this->zstride_1d = csize.X * (csize.Y + 1); this->heightmap = new s16[csize.X * csize.Z]; @@ -79,10 +77,8 @@ MapgenFractal::MapgenFractal(int mapgenid, MapgenParams *params, EmergeManager * noise_seabed = new Noise(&sp->np_seabed, seed, csize.X, csize.Z); noise_filler_depth = new Noise(&sp->np_filler_depth, seed, csize.X, csize.Z); - //// 3D terrain noise - // 1-down overgeneraion - noise_cave1 = new Noise(&sp->np_cave1, seed, csize.X, csize.Y + 1, csize.Z); - noise_cave2 = new Noise(&sp->np_cave2, seed, csize.X, csize.Y + 1, csize.Z); + MapgenBasic::np_cave1 = sp->np_cave1; + MapgenBasic::np_cave2 = sp->np_cave2; //// Initialize biome generator biomegen = emerge->biomemgr->createBiomeGen( @@ -123,8 +119,6 @@ MapgenFractal::~MapgenFractal() { delete noise_seabed; delete noise_filler_depth; - delete noise_cave1; - delete noise_cave2; delete biomegen; diff --git a/src/mapgen_v5.cpp b/src/mapgen_v5.cpp index 6c1441bc2..0c063dc6f 100644 --- a/src/mapgen_v5.cpp +++ b/src/mapgen_v5.cpp @@ -54,8 +54,6 @@ MapgenV5::MapgenV5(int mapgenid, MapgenParams *params, EmergeManager *emerge) // amount of elements to skip for the next index // for noise/height/biome maps (not vmanip) this->ystride = csize.X; - // 1-down overgeneration - this->zstride_1d = csize.X * (csize.Y + 1); this->heightmap = new s16[csize.X * csize.Z]; @@ -72,9 +70,9 @@ MapgenV5::MapgenV5(int mapgenid, MapgenParams *params, EmergeManager *emerge) // 3D terrain noise // 1-up 1-down overgeneration noise_ground = new Noise(&sp->np_ground, seed, csize.X, csize.Y + 2, csize.Z); - // 1-down overgeneraion - noise_cave1 = new Noise(&sp->np_cave1, seed, csize.X, csize.Y + 1, csize.Z); - noise_cave2 = new Noise(&sp->np_cave2, seed, csize.X, csize.Y + 1, csize.Z); + + MapgenBasic::np_cave1 = sp->np_cave1; + MapgenBasic::np_cave2 = sp->np_cave2; //// Initialize biome generator biomegen = emerge->biomemgr->createBiomeGen( @@ -113,8 +111,6 @@ MapgenV5::~MapgenV5() delete noise_filler_depth; delete noise_factor; delete noise_height; - delete noise_cave1; - delete noise_cave2; delete noise_ground; delete biomegen; diff --git a/src/mapgen_v7.cpp b/src/mapgen_v7.cpp index e6801a24b..e297a1d3e 100644 --- a/src/mapgen_v7.cpp +++ b/src/mapgen_v7.cpp @@ -61,8 +61,6 @@ MapgenV7::MapgenV7(int mapgenid, MapgenParams *params, EmergeManager *emerge) this->ystride = csize.X; // 1-up 1-down overgeneration this->zstride_1u1d = csize.X * (csize.Y + 2); - // 1-down overgeneration - this->zstride_1d = csize.X * (csize.Y + 1); this->heightmap = new s16[csize.X * csize.Z]; this->ridge_heightmap = new s16[csize.X * csize.Z]; @@ -85,9 +83,9 @@ MapgenV7::MapgenV7(int mapgenid, MapgenParams *params, EmergeManager *emerge) // 1-up 1-down overgeneration noise_mountain = new Noise(&sp->np_mountain, seed, csize.X, csize.Y + 2, csize.Z); noise_ridge = new Noise(&sp->np_ridge, seed, csize.X, csize.Y + 2, csize.Z); - // 1-down overgeneraion - noise_cave1 = new Noise(&sp->np_cave1, seed, csize.X, csize.Y + 1, csize.Z); - noise_cave2 = new Noise(&sp->np_cave2, seed, csize.X, csize.Y + 1, csize.Z); + + MapgenBasic::np_cave1 = sp->np_cave1; + MapgenBasic::np_cave2 = sp->np_cave2; // TODO(hmmmm): should we have a way to disable biomemanager biomes? //// Initialize biome generator @@ -133,8 +131,6 @@ MapgenV7::~MapgenV7() delete noise_ridge_uwater; delete noise_mountain; delete noise_ridge; - delete noise_cave1; - delete noise_cave2; delete biomegen; diff --git a/src/mapgen_valleys.h b/src/mapgen_valleys.h index 2ab253430..4f87be6b6 100644 --- a/src/mapgen_valleys.h +++ b/src/mapgen_valleys.h @@ -100,6 +100,7 @@ private: BiomeGenOriginal *m_bgen; int zstride; + int zstride_1d; float map_gen_limit; @@ -120,6 +121,8 @@ private: Noise *noise_inter_valley_fill; Noise *noise_inter_valley_slope; Noise *noise_rivers; + Noise *noise_cave1; + Noise *noise_cave2; Noise *noise_massive_caves; Noise *noise_terrain_height; Noise *noise_valley_depth;