]> git.lizzy.rs Git - minetest.git/blobdiff - src/mapgen_fractal.cpp
Remove ClientMap::m_camera_mutex
[minetest.git] / src / mapgen_fractal.cpp
index a1abcffed939595a4e669279bd10870c0e15cfc2..8a5c1e2bc8dde8b2d87f80d6c305880f15d6f9a7 100644 (file)
@@ -28,6 +28,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "content_sao.h"
 #include "nodedef.h"
 #include "voxelalgorithms.h"
+//#include "profiler.h" // For TimeTaker
 #include "settings.h" // For g_settings
 #include "emerge.h"
 #include "dungeongen.h"
@@ -40,7 +41,6 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 
 
 FlagDesc flagdesc_mapgen_fractal[] = {
-       {"julia", MGFRACTAL_JULIA},
        {NULL,    0}
 };
 
@@ -58,28 +58,31 @@ MapgenFractal::MapgenFractal(int mapgenid, MapgenParams *params, EmergeManager *
        this->ystride = csize.X;
        this->zstride = csize.X * (csize.Y + 2);
 
-       this->biomemap        = new u8[csize.X * csize.Z];
-       this->heightmap       = new s16[csize.X * csize.Z];
-       this->heatmap         = NULL;
-       this->humidmap        = NULL;
+       this->biomemap  = new u8[csize.X * csize.Z];
+       this->heightmap = new s16[csize.X * csize.Z];
+       this->heatmap   = NULL;
+       this->humidmap  = NULL;
 
        MapgenFractalParams *sp = (MapgenFractalParams *)params->sparams;
        this->spflags = sp->spflags;
+
+       this->fractal    = sp->fractal;
        this->iterations = sp->iterations;
-       this->scale_x = sp->scale_x;
-       this->scale_y = sp->scale_y;
-       this->scale_z = sp->scale_z;
-       this->offset_x = sp->offset_x;
-       this->offset_y = sp->offset_y;
-       this->offset_z = sp->offset_z;
-       this->slice_w = sp->slice_w;
+       this->scale      = sp->scale;
+       this->offset     = sp->offset;
+       this->slice_w    = sp->slice_w;
+
        this->julia_x = sp->julia_x;
        this->julia_y = sp->julia_y;
        this->julia_z = sp->julia_z;
        this->julia_w = sp->julia_w;
 
+       this->formula = fractal / 2 + fractal % 2;
+       this->julia   = fractal % 2 == 0;
+
        //// 2D terrain noise
-       noise_seabed = new Noise(&sp->np_seabed, seed, csize.X, csize.Z);
+       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
        noise_cave1 = new Noise(&sp->np_cave1, seed, csize.X, csize.Y + 2, csize.Z);
@@ -123,7 +126,7 @@ MapgenFractal::MapgenFractal(int mapgenid, MapgenParams *params, EmergeManager *
 MapgenFractal::~MapgenFractal()
 {
        delete noise_seabed;
-
+       delete noise_filler_depth;
        delete noise_cave1;
        delete noise_cave2;
 
@@ -141,22 +144,21 @@ MapgenFractalParams::MapgenFractalParams()
 {
        spflags = 0;
 
-       iterations = 9;
-       scale_x = 1024.0;
-       scale_y = 256.0;
-       scale_z = 1024.0;
-       offset_x = -1.75;
-       offset_y = 0.0;
-       offset_z = 0.0;
+       fractal = 1;
+       iterations = 11;
+       scale = v3f(4096.0, 1024.0, 4096.0);
+       offset = v3f(1.79, 0.0, 0.0);
        slice_w = 0.0;
+
        julia_x = 0.33;
        julia_y = 0.33;
        julia_z = 0.33;
        julia_w = 0.33;
 
-       np_seabed = NoiseParams(-14, 9,  v3f(600, 600, 600), 41900, 5, 0.6, 2.0);
-       np_cave1  = NoiseParams(0,   12, v3f(128, 128, 128), 52534, 4, 0.5, 2.0);
-       np_cave2  = NoiseParams(0,   12, v3f(128, 128, 128), 10325, 4, 0.5, 2.0);
+       np_seabed       = NoiseParams(-14, 9,   v3f(600, 600, 600), 41900, 5, 0.6, 2.0);
+       np_filler_depth = NoiseParams(0,   1.2, v3f(150, 150, 150), 261,   3, 0.7, 2.0);
+       np_cave1        = NoiseParams(0,   12,  v3f(96,  96,  96),  52534, 4, 0.5, 2.0);
+       np_cave2        = NoiseParams(0,   12,  v3f(96,  96,  96),  10325, 4, 0.5, 2.0);
 }
 
 
@@ -164,20 +166,19 @@ void MapgenFractalParams::readParams(const Settings *settings)
 {
        settings->getFlagStrNoEx("mgfractal_spflags", spflags, flagdesc_mapgen_fractal);
 
+       settings->getU16NoEx("mgfractal_fractal", fractal);
        settings->getU16NoEx("mgfractal_iterations", iterations);
-       settings->getFloatNoEx("mgfractal_scale_x", scale_x);
-       settings->getFloatNoEx("mgfractal_scale_y", scale_y);
-       settings->getFloatNoEx("mgfractal_scale_z", scale_z);
-       settings->getFloatNoEx("mgfractal_offset_x", offset_x);
-       settings->getFloatNoEx("mgfractal_offset_y", offset_y);
-       settings->getFloatNoEx("mgfractal_offset_z", offset_z);
+       settings->getV3FNoEx("mgfractal_scale", scale);
+       settings->getV3FNoEx("mgfractal_offset", offset);
        settings->getFloatNoEx("mgfractal_slice_w", slice_w);
+
        settings->getFloatNoEx("mgfractal_julia_x", julia_x);
        settings->getFloatNoEx("mgfractal_julia_y", julia_y);
        settings->getFloatNoEx("mgfractal_julia_z", julia_z);
        settings->getFloatNoEx("mgfractal_julia_w", julia_w);
 
        settings->getNoiseParams("mgfractal_np_seabed", np_seabed);
+       settings->getNoiseParams("mgfractal_np_filler_depth", np_filler_depth);
        settings->getNoiseParams("mgfractal_np_cave1", np_cave1);
        settings->getNoiseParams("mgfractal_np_cave2", np_cave2);
 }
@@ -187,20 +188,19 @@ void MapgenFractalParams::writeParams(Settings *settings) const
 {
        settings->setFlagStr("mgfractal_spflags", spflags, flagdesc_mapgen_fractal, U32_MAX);
 
+       settings->setU16("mgfractal_fractal", fractal);
        settings->setU16("mgfractal_iterations", iterations);
-       settings->setFloat("mgfractal_scale_x", scale_x);
-       settings->setFloat("mgfractal_scale_y", scale_y);
-       settings->setFloat("mgfractal_scale_z", scale_z);
-       settings->setFloat("mgfractal_offset_x", offset_x);
-       settings->setFloat("mgfractal_offset_y", offset_y);
-       settings->setFloat("mgfractal_offset_z", offset_z);
+       settings->setV3F("mgfractal_scale", scale);
+       settings->setV3F("mgfractal_offset", offset);
        settings->setFloat("mgfractal_slice_w", slice_w);
+
        settings->setFloat("mgfractal_julia_x", julia_x);
        settings->setFloat("mgfractal_julia_y", julia_y);
        settings->setFloat("mgfractal_julia_z", julia_z);
        settings->setFloat("mgfractal_julia_w", julia_w);
 
        settings->setNoiseParams("mgfractal_np_seabed", np_seabed);
+       settings->setNoiseParams("mgfractal_np_filler_depth", np_filler_depth);
        settings->setNoiseParams("mgfractal_np_cave1", np_cave1);
        settings->setNoiseParams("mgfractal_np_cave2", np_cave2);
 }
@@ -209,17 +209,28 @@ void MapgenFractalParams::writeParams(Settings *settings) const
 /////////////////////////////////////////////////////////////////
 
 
-int MapgenFractal::getGroundLevelAtPoint(v2s16 p)
+int MapgenFractal::getSpawnLevelAtPoint(v2s16 p)
 {
-       s16 search_start = 128;
-       s16 search_end = -128;
-
-       for (s16 y = search_start; y >= search_end; y--) {
-               if (getFractalAtPoint(p.X, y, p.Y))
-                       return y;
+       bool solid_below = false;  // Dry solid node is present below to spawn on
+       u8 air_count = 0;  // Consecutive air nodes above the dry solid node
+       s16 seabed_level = NoisePerlin2D(&noise_seabed->np, p.X, p.Y, seed);
+       // Seabed can rise above water_level or might be raised to create dry land
+       s16 search_start = MYMAX(seabed_level, water_level + 1);
+       if (seabed_level > water_level)
+               solid_below = true;
+               
+       for (s16 y = search_start; y <= search_start + 128; y++) {
+               if (getFractalAtPoint(p.X, y, p.Y)) {  // Fractal node
+                       solid_below = true;
+                       air_count = 0;
+               } else if (solid_below) {  // Air above solid node
+                       air_count++;
+                       if (air_count == 2)
+                               return y - 2;
+               }
        }
 
-       return -MAX_MAP_GENERATION_LIMIT;
+       return MAX_MAP_GENERATION_LIMIT;  // Unsuitable spawn point
 }
 
 
@@ -312,7 +323,8 @@ void MapgenFractal::makeChunk(BlockMakeData *data)
        }
 
        // Generate the registered decorations
-       m_emerge->decomgr->placeAllDecos(this, blockseed, node_min, node_max);
+       if (flags & MG_DECORATIONS)
+               m_emerge->decomgr->placeAllDecos(this, blockseed, node_min, node_max);
 
        // Generate the registered ores
        m_emerge->oremgr->placeAllOres(this, blockseed, node_min, node_max);
@@ -338,17 +350,15 @@ void MapgenFractal::makeChunk(BlockMakeData *data)
 void MapgenFractal::calculateNoise()
 {
        //TimeTaker t("calculateNoise", NULL, PRECISION_MICRO);
-       int x = node_min.X;
-       int y = node_min.Y - 1;
-       int z = node_min.Z;
+       s16 x = node_min.X;
+       s16 z = node_min.Z;
 
        noise_seabed->perlinMap2D(x, z);
 
-       if (flags & MG_CAVES) {
-               noise_cave1->perlinMap3D(x, y, z);
-               noise_cave2->perlinMap3D(x, y, z);
-       }
+       // Cave noises are calculated in generateCaves()
+       // only if solid terrain is present in mapchunk
 
+       noise_filler_depth->perlinMap2D(x, z);
        noise_heat->perlinMap2D(x, z);
        noise_humidity->perlinMap2D(x, z);
        noise_heat_blend->perlinMap2D(x, z);
@@ -369,19 +379,19 @@ bool MapgenFractal::getFractalAtPoint(s16 x, s16 y, s16 z)
 {
        float cx, cy, cz, cw, ox, oy, oz, ow;
 
-       if (spflags & MGFRACTAL_JULIA) {  // Julia set
+       if (julia) {  // Julia set
                cx = julia_x;
                cy = julia_y;
                cz = julia_z;
                cw = julia_w;
-               ox = (float)x / scale_x + offset_x;
-               oy = (float)y / scale_y + offset_y;
-               oz = (float)z / scale_z + offset_z;
+               ox = (float)x / scale.X - offset.X;
+               oy = (float)y / scale.Y - offset.Y;
+               oz = (float)z / scale.Z - offset.Z;
                ow = slice_w;
        } else {  // Mandelbrot set
-               cx = (float)x / scale_x + offset_x;
-               cy = (float)y / scale_y + offset_y;
-               cz = (float)z / scale_z + offset_z;
+               cx = (float)x / scale.X - offset.X;
+               cy = (float)y / scale.Y - offset.Y;
+               cz = (float)z / scale.Z - offset.Z;
                cw = slice_w;
                ox = 0.0f;
                oy = 0.0f;
@@ -389,12 +399,88 @@ bool MapgenFractal::getFractalAtPoint(s16 x, s16 y, s16 z)
                ow = 0.0f;
        }
 
+       float nx = 0.0f;
+       float ny = 0.0f;
+       float nz = 0.0f;
+       float nw = 0.0f;
+
        for (u16 iter = 0; iter < iterations; iter++) {
-               // 4D "Roundy" Mandelbrot set
-               float nx = ox * ox - oy * oy - oz * oz - ow * ow + cx;
-               float ny = 2.0f * (ox * oy + oz * ow) + cy;
-               float nz = 2.0f * (ox * oz + oy * ow) + cz;
-               float nw = 2.0f * (ox * ow + oy * oz) + cw;
+
+               if (formula == 1) {  // 4D "Roundy"
+                       nx = ox * ox - oy * oy - oz * oz - ow * ow + cx;
+                       ny = 2.0f * (ox * oy + oz * ow) + cy;
+                       nz = 2.0f * (ox * oz + oy * ow) + cz;
+                       nw = 2.0f * (ox * ow + oy * oz) + cw;
+               } else if (formula == 2) {  // 4D "Squarry"
+                       nx = ox * ox - oy * oy - oz * oz - ow * ow + cx;
+                       ny = 2.0f * (ox * oy + oz * ow) + cy;
+                       nz = 2.0f * (ox * oz + oy * ow) + cz;
+                       nw = 2.0f * (ox * ow - oy * oz) + cw;
+               } else if (formula == 3) {  // 4D "Mandy Cousin"
+                       nx = ox * ox - oy * oy - oz * oz + ow * ow + cx;
+                       ny = 2.0f * (ox * oy + oz * ow) + cy;
+                       nz = 2.0f * (ox * oz + oy * ow) + cz;
+                       nw = 2.0f * (ox * ow + oy * oz) + cw;
+               } else if (formula == 4) {  // 4D "Variation"
+                       nx = ox * ox - oy * oy - oz * oz - ow * ow + cx;
+                       ny = 2.0f * (ox * oy + oz * ow) + cy;
+                       nz = 2.0f * (ox * oz - oy * ow) + cz;
+                       nw = 2.0f * (ox * ow + oy * oz) + cw;
+               } else if (formula == 5) {  // 3D "Mandelbrot/Mandelbar"
+                       nx = ox * ox - oy * oy - oz * oz + cx;
+                       ny = 2.0f * ox * oy + cy;
+                       nz = -2.0f * ox * oz + cz;
+               } else if (formula == 6) {  // 3D "Christmas Tree"
+                       // Altering the formula here is necessary to avoid division by zero
+                       if (fabs(oz) < 0.000000001f) {
+                               nx = ox * ox - oy * oy - oz * oz + cx;
+                               ny = 2.0f * oy * ox + cy;
+                               nz = 4.0f * oz * ox + cz;
+                       } else {
+                               float a = (2.0f * ox) / (sqrt(oy * oy + oz * oz));
+                               nx = ox * ox - oy * oy - oz * oz + cx;
+                               ny = a * (oy * oy - oz * oz) + cy;
+                               nz = a * 2.0f * oy * oz + cz;
+                       }
+               } else if (formula == 7) {  // 3D "Mandelbulb"
+                       if (fabs(oy) < 0.000000001f) {
+                               nx = ox * ox - oz * oz + cx;
+                               ny = cy;
+                               nz = -2.0f * oz * sqrt(ox * ox) + cz;
+                       } else {
+                               float a = 1.0f - (oz * oz) / (ox * ox + oy * oy);
+                               nx = (ox * ox - oy * oy) * a + cx;
+                               ny = 2.0f * ox * oy * a + cy;
+                               nz = -2.0f * oz * sqrt(ox * ox + oy * oy) + cz;
+                       }
+               } else if (formula == 8) {  // 3D "Cosine Mandelbulb"
+                       if (fabs(oy) < 0.000000001f) {
+                               nx = 2.0f * ox * oz + cx;
+                               ny = 4.0f * oy * oz + cy;
+                               nz = oz * oz - ox * ox - oy * oy + cz;
+                       } else {
+                               float a = (2.0f * oz) / sqrt(ox * ox + oy * oy);
+                               nx = (ox * ox - oy * oy) * a + cx;
+                               ny = 2.0f * ox * oy * a + cy;
+                               nz = oz * oz - ox * ox - oy * oy + cz;
+                       }
+               } else if (formula == 9) {  // 4D "Mandelbulb"
+                       float rxy = sqrt(ox * ox + oy * oy);
+                       float rxyz = sqrt(ox * ox + oy * oy + oz * oz);
+                       if (fabs(ow) < 0.000000001f && fabs(oz) < 0.000000001f) {
+                               nx = (ox * ox - oy * oy) + cx;
+                               ny = 2.0f * ox * oy + cy;
+                               nz = -2.0f * rxy * oz + cz;
+                               nw = 2.0f * rxyz * ow + cw;
+                       } else {
+                               float a = 1.0f - (ow * ow) / (rxyz * rxyz);
+                               float b = a * (1.0f - (oz * oz) / (rxy * rxy));
+                               nx = (ox * ox - oy * oy) * b + cx;
+                               ny = 2.0f * ox * oy * b + cy;
+                               nz = -2.0f * rxy * oz * a + cz;
+                               nw = 2.0f * rxyz * ow + cw;
+                       }
+               }
 
                if (nx * nx + ny * ny + nz * nz + nw * nw > 4.0f)
                        return false;
@@ -484,7 +570,8 @@ MgStoneType MapgenFractal::generateBiomes(float *heat_map, float *humidity_map)
                                        (c == c_water_source && (air_above || !biome))) {
                                biome = bmgr->getBiome(heat_map[index], humidity_map[index], y);
                                depth_top = biome->depth_top;
-                               base_filler = depth_top + biome->depth_filler;
+                               base_filler = MYMAX(depth_top + biome->depth_filler
+                                       + noise_filler_depth->result[index], 0);
                                depth_water_top = biome->depth_water_top;
 
                                // Detect stone type for dungeons during every biome calculation.
@@ -594,22 +681,45 @@ void MapgenFractal::dustTopNodes()
 
 void MapgenFractal::generateCaves(s16 max_stone_y)
 {
-       if (max_stone_y >= node_min.Y) {
-               u32 index = 0;
+       if (max_stone_y < node_min.Y)
+               return;
 
-               for (s16 z = node_min.Z; z <= node_max.Z; z++)
-               for (s16 y = node_min.Y - 1; y <= node_max.Y + 1; y++) {
-                       u32 vi = vm->m_area.index(node_min.X, y, z);
-                       for (s16 x = node_min.X; x <= node_max.X; x++, vi++, index++) {
-                               float d1 = contour(noise_cave1->result[index]);
-                               float d2 = contour(noise_cave2->result[index]);
-                               if (d1 * d2 > 0.3) {
-                                       content_t c = vm->m_data[vi].getContent();
-                                       if (!ndef->get(c).is_ground_content || c == CONTENT_AIR)
-                                               continue;
-
-                                       vm->m_data[vi] = MapNode(CONTENT_AIR);
-                               }
+       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);
+
+       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
+               u32 vi = vm->m_area.index(x, node_max.Y + 1, z);
+               u32 index3d = (z - node_min.Z) * zstride + (csize.Y + 1) * ystride +
+                       (x - node_min.X);
+               // Biome of column
+               Biome *biome = (Biome *)bmgr->getRaw(biomemap[index2d]);
+
+               for (s16 y = node_max.Y + 1; 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 > 0.3f && ndef->get(c).is_ground_content) {
+                               // In tunnel and ground content, excavate
+                               vm->m_data[vi] = MapNode(CONTENT_AIR);
+                       } else if (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;
+                       } else {
+                               column_is_open = false;
                        }
                }
        }
@@ -618,9 +728,9 @@ void MapgenFractal::generateCaves(s16 max_stone_y)
                return;
 
        PseudoRandom ps(blockseed + 21343);
-       u32 bruises_count = (ps.range(1, 4) == 1) ? ps.range(1, 2) : 0;
+       u32 bruises_count = ps.range(0, 2);
        for (u32 i = 0; i < bruises_count; i++) {
-               CaveFractal cave(this, &ps);
+               CaveV5 cave(this, &ps);
                cave.makeCave(node_min, node_max, max_stone_y);
        }
 }