FlagDesc flagdesc_mapgen_fractal[] = {
- {"julia", MGFRACTAL_JULIA},
{NULL, 0}
};
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 = sp->scale;
+ this->scale = sp->scale;
+ this->offset = sp->offset;
+ this->slice_w = sp->slice_w;
- this->moffset = sp->moffset;
- this->mslice_w = sp->mslice_w;
-
- this->joffset = sp->joffset;
- this->jslice_w = sp->jslice_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);
MapgenFractal::~MapgenFractal()
{
delete noise_seabed;
-
+ delete noise_filler_depth;
delete noise_cave1;
delete noise_cave2;
{
spflags = 0;
- iterations = 9;
- scale = v3f(1024.0, 256.0, 1024.0);
-
- moffset = v3f(1.75, 0.0, 0.0); // Mandelbrot set only
- mslice_w = 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;
- joffset = v3f(0.0, 1.0, 0.0); // Julia set only
- jslice_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);
}
{
settings->getFlagStrNoEx("mgfractal_spflags", spflags, flagdesc_mapgen_fractal);
+ settings->getU16NoEx("mgfractal_fractal", fractal);
settings->getU16NoEx("mgfractal_iterations", iterations);
settings->getV3FNoEx("mgfractal_scale", scale);
+ settings->getV3FNoEx("mgfractal_offset", offset);
+ settings->getFloatNoEx("mgfractal_slice_w", slice_w);
- settings->getV3FNoEx("mgfractal_moffset", moffset);
- settings->getFloatNoEx("mgfractal_mslice_w", mslice_w);
-
- settings->getV3FNoEx("mgfractal_joffset", joffset);
- settings->getFloatNoEx("mgfractal_jslice_w", jslice_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);
}
{
settings->setFlagStr("mgfractal_spflags", spflags, flagdesc_mapgen_fractal, U32_MAX);
+ settings->setU16("mgfractal_fractal", fractal);
settings->setU16("mgfractal_iterations", iterations);
settings->setV3F("mgfractal_scale", scale);
+ settings->setV3F("mgfractal_offset", offset);
+ settings->setFloat("mgfractal_slice_w", slice_w);
- settings->setV3F("mgfractal_moffset", moffset);
- settings->setFloat("mgfractal_mslice_w", mslice_w);
-
- settings->setV3F("mgfractal_joffset", joffset);
- settings->setFloat("mgfractal_jslice_w", jslice_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);
}
/////////////////////////////////////////////////////////////////
-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
}
}
// 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);
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);
{
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 - joffset.X;
- oy = (float)y / scale.Y - joffset.Y;
- oz = (float)z / scale.Z - joffset.Z;
- ow = jslice_w;
+ 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 - moffset.X;
- cy = (float)y / scale.Y - moffset.Y;
- cz = (float)z / scale.Z - moffset.Z;
- cw = mslice_w;
+ 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;
oz = 0.0f;
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;
(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.
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.4f) {
- 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;
}
}
}
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);
}
}