X-Git-Url: https://git.lizzy.rs/?a=blobdiff_plain;f=src%2Fcavegen.cpp;h=e666345177209c0c484e5be89acbb92bcf81fc70;hb=e6e5fa3bf8853f149fdef16b39af3981097176a4;hp=1c25ce71198d535e30e5d5dc6e9bcd0b1399545b;hpb=c4e083f7e142d8e25e906bb19f9b1f03bb7b430d;p=dragonfireclient.git diff --git a/src/cavegen.cpp b/src/cavegen.cpp index 1c25ce711..e66634517 100644 --- a/src/cavegen.cpp +++ b/src/cavegen.cpp @@ -35,7 +35,7 @@ static NoiseParams nparams_caveliquids(0, 1, v3f(150.0, 150.0, 150.0), 776, 3, 0 CavesNoiseIntersection::CavesNoiseIntersection( INodeDefManager *nodedef, BiomeManager *biomemgr, v3s16 chunksize, - NoiseParams *np_cave1, NoiseParams *np_cave2, int seed, float cave_width) + NoiseParams *np_cave1, NoiseParams *np_cave2, s32 seed, float cave_width) { assert(nodedef); assert(biomemgr); @@ -73,19 +73,25 @@ void CavesNoiseIntersection::generateCaves(MMVManip *vm, 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; + const v3s16 &em = vm->m_area.getExtent(); + u32 index2d = 0; // Biomemap index 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 + bool is_under_river = false; // Is column under river water + bool is_under_tunnel = false; // Is tunnel or is under tunnel + bool is_top_filler_above = false; // Is top or filler above node + // Indexes at column top 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); + (x - nmin.X); // 3D noise index // Biome of column Biome *biome = (Biome *)m_bmgr->getRaw(biomemap[index2d]); - + u16 depth_top = biome->depth_top; + u16 base_filler = depth_top + biome->depth_filler; + u16 depth_riverbed = biome->depth_riverbed; + u16 nplaced = 0; // 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. @@ -93,13 +99,22 @@ void CavesNoiseIntersection::generateCaves(MMVManip *vm, 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; + is_top_filler_above = false; + continue; + } + + if (c == biome->c_river_water) { + column_is_open = true; + is_under_river = true; + is_top_filler_above = false; continue; } + // Ground float d1 = contour(noise_cave1->result[index3d]); float d2 = contour(noise_cave2->result[index3d]); @@ -107,22 +122,149 @@ void CavesNoiseIntersection::generateCaves(MMVManip *vm, 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 + is_under_tunnel = true; + // If tunnel roof is top or filler, replace with stone + if (is_top_filler_above) + vm->m_data[vi + em.X] = MapNode(biome->c_stone); + is_top_filler_above = false; + } else if (column_is_open && is_under_tunnel && + (c == biome->c_stone || c == biome->c_filler)) { + // Tunnel entrance floor, place biome surface nodes + if (is_under_river) { + if (nplaced < depth_riverbed) { + vm->m_data[vi] = MapNode(biome->c_riverbed); + is_top_filler_above = true; + nplaced++; + } else { + // Disable top/filler placement + column_is_open = false; + is_under_river = false; + is_under_tunnel = false; + } + } else if (nplaced < depth_top) { vm->m_data[vi] = MapNode(biome->c_top); + is_top_filler_above = true; + nplaced++; + } else if (nplaced < base_filler) { + vm->m_data[vi] = MapNode(biome->c_filler); + is_top_filler_above = true; + nplaced++; + } else { + // Disable top/filler placement + column_is_open = false; + is_under_tunnel = false; + } + } else { + // Not tunnel or tunnel entrance floor + // Check node for possible replacing with stone for tunnel roof + if (c == biome->c_top || c == biome->c_filler) + is_top_filler_above = true; column_is_open = false; - is_tunnel = false; } } } } +//// +//// CavernsNoise +//// + +CavernsNoise::CavernsNoise( + INodeDefManager *nodedef, v3s16 chunksize, NoiseParams *np_cavern, + s32 seed, float cavern_limit, float cavern_taper, float cavern_threshold) +{ + assert(nodedef); + + m_ndef = nodedef; + + m_csize = chunksize; + m_cavern_limit = cavern_limit; + m_cavern_taper = cavern_taper; + m_cavern_threshold = cavern_threshold; + + m_ystride = m_csize.X; + m_zstride_1d = m_csize.X * (m_csize.Y + 1); + + // Noise is 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_cavern = new Noise(np_cavern, seed, m_csize.X, m_csize.Y + 1, m_csize.Z); + + c_water_source = m_ndef->getId("mapgen_water_source"); + if (c_water_source == CONTENT_IGNORE) + c_water_source = CONTENT_AIR; + + c_lava_source = m_ndef->getId("mapgen_lava_source"); + if (c_lava_source == CONTENT_IGNORE) + c_lava_source = CONTENT_AIR; +} + + +CavernsNoise::~CavernsNoise() +{ + delete noise_cavern; +} + + +bool CavernsNoise::generateCaverns(MMVManip *vm, v3s16 nmin, v3s16 nmax) +{ + assert(vm); + + // Calculate noise + noise_cavern->perlinMap3D(nmin.X, nmin.Y - 1, nmin.Z); + + // Cache cavern_amp values + float *cavern_amp = new float[m_csize.Y + 1]; + u8 cavern_amp_index = 0; // Index zero at column top + for (s16 y = nmax.Y; y >= nmin.Y - 1; y--, cavern_amp_index++) { + cavern_amp[cavern_amp_index] = + MYMIN((m_cavern_limit - y) / (float)m_cavern_taper, 1.0f); + } + + //// Place nodes + bool near_cavern = false; + const 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++) { + // Reset cave_amp index to column top + cavern_amp_index = 0; + // Initial voxelmanip index at column top + u32 vi = vm->m_area.index(x, nmax.Y, z); + // Initial 3D noise index at column top + u32 index3d = (z - nmin.Z) * m_zstride_1d + m_csize.Y * m_ystride + + (x - nmin.X); + // Don't excavate the overgenerated stone at node_max.Y + 1, + // this creates a 'roof' over the cavern, preventing light in + // caverns at mapchunk borders when generating mapchunks upwards. + // This 'roof' is excavated 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), + cavern_amp_index++) { + content_t c = vm->m_data[vi].getContent(); + float n_absamp_cavern = fabs(noise_cavern->result[index3d]) * + cavern_amp[cavern_amp_index]; + // Disable CavesRandomWalk at a safe distance from caverns + // to avoid excessively spreading liquids in caverns. + if (n_absamp_cavern > m_cavern_threshold - 0.1f) { + near_cavern = true; + if (n_absamp_cavern > m_cavern_threshold && + m_ndef->get(c).is_ground_content) + vm->m_data[vi] = MapNode(CONTENT_AIR); + } + } + } + + delete[] cavern_amp; + + return near_cavern; +} + + //// //// CavesRandomWalk //// @@ -130,10 +272,11 @@ void CavesNoiseIntersection::generateCaves(MMVManip *vm, CavesRandomWalk::CavesRandomWalk( INodeDefManager *ndef, GenerateNotifier *gennotify, - int seed, + s32 seed, int water_level, content_t water_source, - content_t lava_source) + content_t lava_source, + int lava_depth) { assert(ndef); @@ -142,7 +285,7 @@ CavesRandomWalk::CavesRandomWalk( this->seed = seed; this->water_level = water_level; this->np_caveliquids = &nparams_caveliquids; - this->lava_depth = DEFAULT_LAVA_DEPTH; + this->lava_depth = lava_depth; c_water_source = water_source; if (c_water_source == CONTENT_IGNORE) @@ -389,7 +532,7 @@ void CavesRandomWalk::carveRoute(v3f vec, float f, bool randomize_xz) v3s16 p(cp.X + x0, cp.Y + y0, cp.Z + z0); p += of; - if (vm->m_area.contains(p) == false) + if (!vm->m_area.contains(p)) continue; u32 i = vm->m_area.index(p); @@ -693,7 +836,7 @@ void CavesV6::carveRoute(v3f vec, float f, bool randomize_xz, v3s16 p(cp.X + x0, cp.Y + y0, cp.Z + z0); p += of; - if (vm->m_area.contains(p) == false) + if (!vm->m_area.contains(p)) continue; u32 i = vm->m_area.index(p); @@ -732,7 +875,8 @@ inline s16 CavesV6::getSurfaceFromHeightmap(v3s16 p) p.X >= node_min.X && p.X <= node_max.X) { u32 index = (p.Z - node_min.Z) * ystride + (p.X - node_min.X); return heightmap[index]; - } else { - return water_level; } + + return water_level; + }