1
0
mirror of https://github.com/moparisthebest/minetest synced 2024-08-13 16:53:49 -04:00

Move biome calculation to BiomeGen

BiomeGen defines an interface that, given a set of BiomeParams, computes biomes
for a given area using the algorithm implemented by that specific BiomeGen.
This abstracts away the old system where each mapgen supplied the noises
required for biome generation.
This commit is contained in:
kwolekr 2016-04-28 03:43:09 -04:00
parent fa6b21a15b
commit 76f4856479
16 changed files with 421 additions and 304 deletions

View File

@ -181,8 +181,6 @@ EmergeManager::~EmergeManager()
delete oremgr; delete oremgr;
delete decomgr; delete decomgr;
delete schemmgr; delete schemmgr;
delete params.sparams;
} }

View File

@ -76,10 +76,9 @@ Mapgen::Mapgen()
vm = NULL; vm = NULL;
ndef = NULL; ndef = NULL;
heightmap = NULL; biomegen = NULL;
biomemap = NULL; biomemap = NULL;
heatmap = NULL; heightmap = NULL;
humidmap = NULL;
} }
@ -94,11 +93,10 @@ Mapgen::Mapgen(int mapgenid, MapgenParams *params, EmergeManager *emerge) :
csize = v3s16(1, 1, 1) * (params->chunksize * MAP_BLOCKSIZE); csize = v3s16(1, 1, 1) * (params->chunksize * MAP_BLOCKSIZE);
vm = NULL; vm = NULL;
ndef = NULL; ndef = emerge->ndef;
heightmap = NULL; biomegen = NULL;
biomemap = NULL; biomemap = NULL;
heatmap = NULL; heightmap = NULL;
humidmap = NULL;
} }
@ -444,6 +442,14 @@ void GenerateNotifier::getEvents(
//// MapgenParams //// MapgenParams
//// ////
MapgenParams::~MapgenParams()
{
delete bparams;
delete sparams;
}
void MapgenParams::load(const Settings &settings) void MapgenParams::load(const Settings &settings)
{ {
std::string seed_str; std::string seed_str;
@ -458,10 +464,13 @@ void MapgenParams::load(const Settings &settings)
settings.getS16NoEx("water_level", water_level); settings.getS16NoEx("water_level", water_level);
settings.getS16NoEx("chunksize", chunksize); settings.getS16NoEx("chunksize", chunksize);
settings.getFlagStrNoEx("mg_flags", flags, flagdesc_mapgen); settings.getFlagStrNoEx("mg_flags", flags, flagdesc_mapgen);
settings.getNoiseParams("mg_biome_np_heat", np_biome_heat);
settings.getNoiseParams("mg_biome_np_heat_blend", np_biome_heat_blend); delete bparams;
settings.getNoiseParams("mg_biome_np_humidity", np_biome_humidity); bparams = BiomeManager::createBiomeParams(BIOMEGEN_ORIGINAL);
settings.getNoiseParams("mg_biome_np_humidity_blend", np_biome_humidity_blend); if (bparams) {
bparams->readParams(&settings);
bparams->seed = seed;
}
delete sparams; delete sparams;
MapgenFactory *mgfactory = EmergeManager::getMapgenFactory(mg_name); MapgenFactory *mgfactory = EmergeManager::getMapgenFactory(mg_name);
@ -479,10 +488,9 @@ void MapgenParams::save(Settings &settings) const
settings.setS16("water_level", water_level); settings.setS16("water_level", water_level);
settings.setS16("chunksize", chunksize); settings.setS16("chunksize", chunksize);
settings.setFlagStr("mg_flags", flags, flagdesc_mapgen, U32_MAX); settings.setFlagStr("mg_flags", flags, flagdesc_mapgen, U32_MAX);
settings.setNoiseParams("mg_biome_np_heat", np_biome_heat);
settings.setNoiseParams("mg_biome_np_heat_blend", np_biome_heat_blend); if (bparams)
settings.setNoiseParams("mg_biome_np_humidity", np_biome_humidity); bparams->writeParams(&settings);
settings.setNoiseParams("mg_biome_np_humidity_blend", np_biome_humidity_blend);
if (sparams) if (sparams)
sparams->writeParams(&settings); sparams->writeParams(&settings);

View File

@ -44,6 +44,8 @@ extern FlagDesc flagdesc_mapgen[];
extern FlagDesc flagdesc_gennotify[]; extern FlagDesc flagdesc_gennotify[];
class Biome; class Biome;
class BiomeGen;
struct BiomeParams;
class EmergeManager; class EmergeManager;
class MapBlock; class MapBlock;
class VoxelManipulator; class VoxelManipulator;
@ -115,11 +117,7 @@ struct MapgenParams {
s16 water_level; s16 water_level;
u32 flags; u32 flags;
NoiseParams np_biome_heat; BiomeParams *bparams;
NoiseParams np_biome_heat_blend;
NoiseParams np_biome_humidity;
NoiseParams np_biome_humidity_blend;
MapgenSpecificParams *sparams; MapgenSpecificParams *sparams;
MapgenParams() : MapgenParams() :
@ -128,12 +126,12 @@ struct MapgenParams {
seed(0), seed(0),
water_level(1), water_level(1),
flags(MG_CAVES | MG_LIGHT | MG_DECORATIONS), flags(MG_CAVES | MG_LIGHT | MG_DECORATIONS),
np_biome_heat(NoiseParams(50, 50, v3f(750.0, 750.0, 750.0), 5349, 3, 0.5, 2.0)), bparams(NULL),
np_biome_heat_blend(NoiseParams(0, 1.5, v3f(8.0, 8.0, 8.0), 13, 2, 1.0, 2.0)),
np_biome_humidity(NoiseParams(50, 50, v3f(750.0, 750.0, 750.0), 842, 3, 0.5, 2.0)),
np_biome_humidity_blend(NoiseParams(0, 1.5, v3f(8.0, 8.0, 8.0), 90003, 2, 1.0, 2.0)),
sparams(NULL) sparams(NULL)
{} {
}
virtual ~MapgenParams();
void load(const Settings &settings); void load(const Settings &settings);
void save(Settings &settings) const; void save(Settings &settings) const;
@ -153,10 +151,9 @@ public:
u32 blockseed; u32 blockseed;
s16 *heightmap; s16 *heightmap;
u8 *biomemap; u8 *biomemap;
float *heatmap;
float *humidmap;
v3s16 csize; v3s16 csize;
BiomeGen *biomegen;
GenerateNotifier gennotify; GenerateNotifier gennotify;
Mapgen(); Mapgen();

View File

@ -61,10 +61,7 @@ MapgenFlat::MapgenFlat(int mapgenid, MapgenParams *params, EmergeManager *emerge
// 1-down overgeneration // 1-down overgeneration
this->zstride_1d = csize.X * (csize.Y + 1); this->zstride_1d = csize.X * (csize.Y + 1);
this->biomemap = new u8[csize.X * csize.Z]; this->heightmap = new s16[csize.X * csize.Z];
this->heightmap = new s16[csize.X * csize.Z];
this->heatmap = NULL;
this->humidmap = NULL;
MapgenFlatParams *sp = (MapgenFlatParams *)params->sparams; MapgenFlatParams *sp = (MapgenFlatParams *)params->sparams;
@ -86,15 +83,12 @@ MapgenFlat::MapgenFlat(int mapgenid, MapgenParams *params, EmergeManager *emerge
noise_cave1 = new Noise(&sp->np_cave1, seed, csize.X, csize.Y + 1, csize.Z); 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); noise_cave2 = new Noise(&sp->np_cave2, seed, csize.X, csize.Y + 1, csize.Z);
//// Biome noise //// Initialize biome generator
noise_heat = new Noise(&params->np_biome_heat, seed, csize.X, csize.Z); biomegen = emerge->biomemgr->createBiomeGen(
noise_humidity = new Noise(&params->np_biome_humidity, seed, csize.X, csize.Z); BIOMEGEN_ORIGINAL, params->bparams, csize);
noise_heat_blend = new Noise(&params->np_biome_heat_blend, seed, csize.X, csize.Z); biomemap = biomegen->biomemap;
noise_humidity_blend = new Noise(&params->np_biome_humidity_blend, seed, csize.X, csize.Z);
//// Resolve nodes to be used //// Resolve nodes to be used
INodeDefManager *ndef = emerge->ndef;
c_stone = ndef->getId("mapgen_stone"); c_stone = ndef->getId("mapgen_stone");
c_water_source = ndef->getId("mapgen_water_source"); c_water_source = ndef->getId("mapgen_water_source");
c_lava_source = ndef->getId("mapgen_lava_source"); c_lava_source = ndef->getId("mapgen_lava_source");
@ -128,13 +122,9 @@ MapgenFlat::~MapgenFlat()
delete noise_cave1; delete noise_cave1;
delete noise_cave2; delete noise_cave2;
delete noise_heat; delete biomegen;
delete noise_humidity;
delete noise_heat_blend;
delete noise_humidity_blend;
delete[] heightmap; delete[] heightmap;
delete[] biomemap;
} }
@ -252,12 +242,10 @@ void MapgenFlat::makeChunk(BlockMakeData *data)
// Create heightmap // Create heightmap
updateHeightmap(node_min, node_max); updateHeightmap(node_min, node_max);
// Create biomemap at heightmap surface // Init biome generator, place biome-specific nodes, and build biomemap
bmgr->calcBiomes(csize.X, csize.Z, noise_heat->result, biomegen->calcBiomeNoise(node_min);
noise_humidity->result, heightmap, biomemap); biomegen->getBiomes(heightmap);
MgStoneType stone_type = generateBiomes();
// Actually place the biome-specific nodes
MgStoneType stone_type = generateBiomes(noise_heat->result, noise_humidity->result);
if (flags & MG_CAVES) if (flags & MG_CAVES)
generateCaves(stone_surface_max_y); generateCaves(stone_surface_max_y);
@ -343,18 +331,7 @@ void MapgenFlat::calculateNoise()
// only if solid terrain is present in mapchunk // only if solid terrain is present in mapchunk
noise_filler_depth->perlinMap2D(x, z); noise_filler_depth->perlinMap2D(x, z);
noise_heat->perlinMap2D(x, z);
noise_humidity->perlinMap2D(x, z);
noise_heat_blend->perlinMap2D(x, z);
noise_humidity_blend->perlinMap2D(x, z);
for (s32 i = 0; i < csize.X * csize.Z; i++) {
noise_heat->result[i] += noise_heat_blend->result[i];
noise_humidity->result[i] += noise_humidity_blend->result[i];
}
heatmap = noise_heat->result;
humidmap = noise_humidity->result;
//printf("calculateNoise: %dus\n", t.stop()); //printf("calculateNoise: %dus\n", t.stop());
} }
@ -406,7 +383,7 @@ s16 MapgenFlat::generateTerrain()
} }
MgStoneType MapgenFlat::generateBiomes(float *heat_map, float *humidity_map) MgStoneType MapgenFlat::generateBiomes()
{ {
v3s16 em = vm->m_area.getExtent(); v3s16 em = vm->m_area.getExtent();
u32 index = 0; u32 index = 0;
@ -443,7 +420,8 @@ MgStoneType MapgenFlat::generateBiomes(float *heat_map, float *humidity_map)
// 3. When stone or water is detected but biome has not yet been calculated. // 3. When stone or water is detected but biome has not yet been calculated.
if ((c == c_stone && (air_above || water_above || !biome)) || if ((c == c_stone && (air_above || water_above || !biome)) ||
(c == c_water_source && (air_above || !biome))) { (c == c_water_source && (air_above || !biome))) {
biome = bmgr->getBiome(heat_map[index], humidity_map[index], y); biome = biomegen->getBiomeAtIndex(index, y);
depth_top = biome->depth_top; depth_top = biome->depth_top;
base_filler = MYMAX(depth_top + biome->depth_filler base_filler = MYMAX(depth_top + biome->depth_filler
+ noise_filler_depth->result[index], 0); + noise_filler_depth->result[index], 0);

View File

@ -104,7 +104,7 @@ public:
int getSpawnLevelAtPoint(v2s16 p); int getSpawnLevelAtPoint(v2s16 p);
void calculateNoise(); void calculateNoise();
s16 generateTerrain(); s16 generateTerrain();
MgStoneType generateBiomes(float *heat_map, float *humidity_map); MgStoneType generateBiomes();
void dustTopNodes(); void dustTopNodes();
void generateCaves(s16 max_stone_y); void generateCaves(s16 max_stone_y);
}; };

View File

@ -59,10 +59,7 @@ MapgenFractal::MapgenFractal(int mapgenid, MapgenParams *params, EmergeManager *
// 1-down overgeneration // 1-down overgeneration
this->zstride_1d = csize.X * (csize.Y + 1); this->zstride_1d = csize.X * (csize.Y + 1);
this->biomemap = new u8[csize.X * csize.Z];
this->heightmap = new s16[csize.X * csize.Z]; this->heightmap = new s16[csize.X * csize.Z];
this->heatmap = NULL;
this->humidmap = NULL;
MapgenFractalParams *sp = (MapgenFractalParams *)params->sparams; MapgenFractalParams *sp = (MapgenFractalParams *)params->sparams;
@ -87,18 +84,15 @@ MapgenFractal::MapgenFractal(int mapgenid, MapgenParams *params, EmergeManager *
noise_cave1 = new Noise(&sp->np_cave1, seed, csize.X, csize.Y + 1, csize.Z); 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); noise_cave2 = new Noise(&sp->np_cave2, seed, csize.X, csize.Y + 1, csize.Z);
//// Biome noise //// Initialize biome generator
noise_heat = new Noise(&params->np_biome_heat, seed, csize.X, csize.Z); biomegen = emerge->biomemgr->createBiomeGen(
noise_humidity = new Noise(&params->np_biome_humidity, seed, csize.X, csize.Z); BIOMEGEN_ORIGINAL, params->bparams, csize);
noise_heat_blend = new Noise(&params->np_biome_heat_blend, seed, csize.X, csize.Z); biomemap = biomegen->biomemap;
noise_humidity_blend = new Noise(&params->np_biome_humidity_blend, seed, csize.X, csize.Z);
this->formula = fractal / 2 + fractal % 2; this->formula = fractal / 2 + fractal % 2;
this->julia = fractal % 2 == 0; this->julia = fractal % 2 == 0;
//// Resolve nodes to be used //// Resolve nodes to be used
INodeDefManager *ndef = emerge->ndef;
c_stone = ndef->getId("mapgen_stone"); c_stone = ndef->getId("mapgen_stone");
c_water_source = ndef->getId("mapgen_water_source"); c_water_source = ndef->getId("mapgen_water_source");
c_lava_source = ndef->getId("mapgen_lava_source"); c_lava_source = ndef->getId("mapgen_lava_source");
@ -132,13 +126,9 @@ MapgenFractal::~MapgenFractal()
delete noise_cave1; delete noise_cave1;
delete noise_cave2; delete noise_cave2;
delete noise_heat; delete biomegen;
delete noise_humidity;
delete noise_heat_blend;
delete noise_humidity_blend;
delete[] heightmap; delete[] heightmap;
delete[] biomemap;
} }
@ -217,7 +207,7 @@ int MapgenFractal::getSpawnLevelAtPoint(v2s16 p)
s16 search_start = MYMAX(seabed_level, water_level + 1); s16 search_start = MYMAX(seabed_level, water_level + 1);
if (seabed_level > water_level) if (seabed_level > water_level)
solid_below = true; solid_below = true;
for (s16 y = search_start; y <= search_start + 128; y++) { for (s16 y = search_start; y <= search_start + 128; y++) {
if (getFractalAtPoint(p.X, y, p.Y)) { // Fractal node if (getFractalAtPoint(p.X, y, p.Y)) { // Fractal node
solid_below = true; solid_below = true;
@ -268,12 +258,10 @@ void MapgenFractal::makeChunk(BlockMakeData *data)
// Create heightmap // Create heightmap
updateHeightmap(node_min, node_max); updateHeightmap(node_min, node_max);
// Create biomemap at heightmap surface // Init biome generator, place biome-specific nodes, and build biomemap
bmgr->calcBiomes(csize.X, csize.Z, noise_heat->result, biomegen->calcBiomeNoise(node_min);
noise_humidity->result, heightmap, biomemap); biomegen->getBiomes(heightmap);
MgStoneType stone_type = generateBiomes();
// Actually place the biome-specific nodes
MgStoneType stone_type = generateBiomes(noise_heat->result, noise_humidity->result);
if (flags & MG_CAVES) if (flags & MG_CAVES)
generateCaves(stone_surface_max_y); generateCaves(stone_surface_max_y);
@ -358,18 +346,7 @@ void MapgenFractal::calculateNoise()
// only if solid terrain is present in mapchunk // only if solid terrain is present in mapchunk
noise_filler_depth->perlinMap2D(x, z); noise_filler_depth->perlinMap2D(x, z);
noise_heat->perlinMap2D(x, z);
noise_humidity->perlinMap2D(x, z);
noise_heat_blend->perlinMap2D(x, z);
noise_humidity_blend->perlinMap2D(x, z);
for (s32 i = 0; i < csize.X * csize.Z; i++) {
noise_heat->result[i] += noise_heat_blend->result[i];
noise_humidity->result[i] += noise_humidity_blend->result[i];
}
heatmap = noise_heat->result;
humidmap = noise_humidity->result;
//printf("calculateNoise: %dus\n", t.stop()); //printf("calculateNoise: %dus\n", t.stop());
} }
@ -530,7 +507,7 @@ s16 MapgenFractal::generateTerrain()
} }
MgStoneType MapgenFractal::generateBiomes(float *heat_map, float *humidity_map) MgStoneType MapgenFractal::generateBiomes()
{ {
v3s16 em = vm->m_area.getExtent(); v3s16 em = vm->m_area.getExtent();
u32 index = 0; u32 index = 0;
@ -567,7 +544,8 @@ MgStoneType MapgenFractal::generateBiomes(float *heat_map, float *humidity_map)
// 3. When stone or water is detected but biome has not yet been calculated. // 3. When stone or water is detected but biome has not yet been calculated.
if ((c == c_stone && (air_above || water_above || !biome)) || if ((c == c_stone && (air_above || water_above || !biome)) ||
(c == c_water_source && (air_above || !biome))) { (c == c_water_source && (air_above || !biome))) {
biome = bmgr->getBiome(heat_map[index], humidity_map[index], y); biome = biomegen->getBiomeAtIndex(index, y);
depth_top = biome->depth_top; depth_top = biome->depth_top;
base_filler = MYMAX(depth_top + biome->depth_filler base_filler = MYMAX(depth_top + biome->depth_filler
+ noise_filler_depth->result[index], 0); + noise_filler_depth->result[index], 0);

View File

@ -88,11 +88,6 @@ public:
Noise *noise_cave1; Noise *noise_cave1;
Noise *noise_cave2; Noise *noise_cave2;
Noise *noise_heat;
Noise *noise_humidity;
Noise *noise_heat_blend;
Noise *noise_humidity_blend;
content_t c_stone; content_t c_stone;
content_t c_water_source; content_t c_water_source;
content_t c_lava_source; content_t c_lava_source;
@ -114,7 +109,7 @@ public:
void calculateNoise(); void calculateNoise();
bool getFractalAtPoint(s16 x, s16 y, s16 z); bool getFractalAtPoint(s16 x, s16 y, s16 z);
s16 generateTerrain(); s16 generateTerrain();
MgStoneType generateBiomes(float *heat_map, float *humidity_map); MgStoneType generateBiomes();
void dustTopNodes(); void dustTopNodes();
void generateCaves(s16 max_stone_y); void generateCaves(s16 max_stone_y);
}; };

View File

@ -57,10 +57,7 @@ MapgenV5::MapgenV5(int mapgenid, MapgenParams *params, EmergeManager *emerge)
// 1-down overgeneration // 1-down overgeneration
this->zstride_1d = csize.X * (csize.Y + 1); this->zstride_1d = csize.X * (csize.Y + 1);
this->biomemap = new u8[csize.X * csize.Z];
this->heightmap = new s16[csize.X * csize.Z]; this->heightmap = new s16[csize.X * csize.Z];
this->heatmap = NULL;
this->humidmap = NULL;
MapgenV5Params *sp = (MapgenV5Params *)params->sparams; MapgenV5Params *sp = (MapgenV5Params *)params->sparams;
@ -79,15 +76,12 @@ MapgenV5::MapgenV5(int mapgenid, MapgenParams *params, EmergeManager *emerge)
noise_cave1 = new Noise(&sp->np_cave1, seed, csize.X, csize.Y + 1, csize.Z); 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); noise_cave2 = new Noise(&sp->np_cave2, seed, csize.X, csize.Y + 1, csize.Z);
// Biome noise //// Initialize biome generator
noise_heat = new Noise(&params->np_biome_heat, seed, csize.X, csize.Z); biomegen = emerge->biomemgr->createBiomeGen(
noise_humidity = new Noise(&params->np_biome_humidity, seed, csize.X, csize.Z); BIOMEGEN_ORIGINAL, params->bparams, csize);
noise_heat_blend = new Noise(&params->np_biome_heat_blend, seed, csize.X, csize.Z); biomemap = biomegen->biomemap;
noise_humidity_blend = new Noise(&params->np_biome_humidity_blend, seed, csize.X, csize.Z);
//// Resolve nodes to be used //// Resolve nodes to be used
INodeDefManager *ndef = emerge->ndef;
c_stone = ndef->getId("mapgen_stone"); c_stone = ndef->getId("mapgen_stone");
c_water_source = ndef->getId("mapgen_water_source"); c_water_source = ndef->getId("mapgen_water_source");
c_lava_source = ndef->getId("mapgen_lava_source"); c_lava_source = ndef->getId("mapgen_lava_source");
@ -123,13 +117,9 @@ MapgenV5::~MapgenV5()
delete noise_cave2; delete noise_cave2;
delete noise_ground; delete noise_ground;
delete noise_heat; delete biomegen;
delete noise_humidity;
delete noise_heat_blend;
delete noise_humidity_blend;
delete[] heightmap; delete[] heightmap;
delete[] biomemap;
} }
@ -248,12 +238,10 @@ void MapgenV5::makeChunk(BlockMakeData *data)
// Create heightmap // Create heightmap
updateHeightmap(node_min, node_max); updateHeightmap(node_min, node_max);
// Create biomemap at heightmap surface // Init biome generator, place biome-specific nodes, and build biomemap
bmgr->calcBiomes(csize.X, csize.Z, noise_heat->result, biomegen->calcBiomeNoise(node_min);
noise_humidity->result, heightmap, biomemap); biomegen->getBiomes(heightmap);
MgStoneType stone_type = generateBiomes();
// Actually place the biome-specific nodes
MgStoneType stone_type = generateBiomes(noise_heat->result, noise_humidity->result);
// Generate caves // Generate caves
if ((flags & MG_CAVES) && (stone_surface_max_y >= node_min.Y)) if ((flags & MG_CAVES) && (stone_surface_max_y >= node_min.Y))
@ -343,18 +331,7 @@ void MapgenV5::calculateNoise()
// only if solid terrain is present in mapchunk // only if solid terrain is present in mapchunk
noise_filler_depth->perlinMap2D(x, z); noise_filler_depth->perlinMap2D(x, z);
noise_heat->perlinMap2D(x, z);
noise_humidity->perlinMap2D(x, z);
noise_heat_blend->perlinMap2D(x, z);
noise_humidity_blend->perlinMap2D(x, z);
for (s32 i = 0; i < csize.X * csize.Z; i++) {
noise_heat->result[i] += noise_heat_blend->result[i];
noise_humidity->result[i] += noise_humidity_blend->result[i];
}
heatmap = noise_heat->result;
humidmap = noise_humidity->result;
//printf("calculateNoise: %dus\n", t.stop()); //printf("calculateNoise: %dus\n", t.stop());
} }
@ -416,7 +393,7 @@ int MapgenV5::generateBaseTerrain()
} }
MgStoneType MapgenV5::generateBiomes(float *heat_map, float *humidity_map) MgStoneType MapgenV5::generateBiomes()
{ {
v3s16 em = vm->m_area.getExtent(); v3s16 em = vm->m_area.getExtent();
u32 index = 0; u32 index = 0;
@ -452,7 +429,8 @@ MgStoneType MapgenV5::generateBiomes(float *heat_map, float *humidity_map)
// 3. When stone or water is detected but biome has not yet been calculated. // 3. When stone or water is detected but biome has not yet been calculated.
if ((c == c_stone && (air_above || water_above || !biome)) || if ((c == c_stone && (air_above || water_above || !biome)) ||
(c == c_water_source && (air_above || !biome))) { (c == c_water_source && (air_above || !biome))) {
biome = bmgr->getBiome(heat_map[index], humidity_map[index], y); biome = biomegen->getBiomeAtIndex(index, y);
depth_top = biome->depth_top; depth_top = biome->depth_top;
base_filler = MYMAX(depth_top + biome->depth_filler base_filler = MYMAX(depth_top + biome->depth_filler
+ noise_filler_depth->result[index], 0); + noise_filler_depth->result[index], 0);

View File

@ -70,11 +70,6 @@ public:
Noise *noise_cave2; Noise *noise_cave2;
Noise *noise_ground; Noise *noise_ground;
Noise *noise_heat;
Noise *noise_humidity;
Noise *noise_heat_blend;
Noise *noise_humidity_blend;
content_t c_stone; content_t c_stone;
content_t c_water_source; content_t c_water_source;
content_t c_lava_source; content_t c_lava_source;
@ -95,7 +90,7 @@ public:
int getSpawnLevelAtPoint(v2s16 p); int getSpawnLevelAtPoint(v2s16 p);
void calculateNoise(); void calculateNoise();
int generateBaseTerrain(); int generateBaseTerrain();
MgStoneType generateBiomes(float *heat_map, float *humidity_map); MgStoneType generateBiomes();
void generateCaves(int max_stone_y); void generateCaves(int max_stone_y);
void dustTopNodes(); void dustTopNodes();
}; };

View File

@ -64,10 +64,7 @@ MapgenV7::MapgenV7(int mapgenid, MapgenParams *params, EmergeManager *emerge)
// 1-down overgeneration // 1-down overgeneration
this->zstride_1d = csize.X * (csize.Y + 1); this->zstride_1d = csize.X * (csize.Y + 1);
this->biomemap = new u8[csize.X * csize.Z];
this->heightmap = new s16[csize.X * csize.Z]; this->heightmap = new s16[csize.X * csize.Z];
this->heatmap = NULL;
this->humidmap = NULL;
this->ridge_heightmap = new s16[csize.X * csize.Z]; this->ridge_heightmap = new s16[csize.X * csize.Z];
MapgenV7Params *sp = (MapgenV7Params *)params->sparams; MapgenV7Params *sp = (MapgenV7Params *)params->sparams;
@ -92,15 +89,13 @@ MapgenV7::MapgenV7(int mapgenid, MapgenParams *params, EmergeManager *emerge)
noise_cave1 = new Noise(&sp->np_cave1, seed, csize.X, csize.Y + 1, csize.Z); 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); noise_cave2 = new Noise(&sp->np_cave2, seed, csize.X, csize.Y + 1, csize.Z);
//// Biome noise // TODO(hmmmm): should we have a way to disable biomemanager biomes?
noise_heat = new Noise(&params->np_biome_heat, seed, csize.X, csize.Z); //// Initialize biome generator
noise_humidity = new Noise(&params->np_biome_humidity, seed, csize.X, csize.Z); biomegen = emerge->biomemgr->createBiomeGen(
noise_heat_blend = new Noise(&params->np_biome_heat_blend, seed, csize.X, csize.Z); BIOMEGEN_ORIGINAL, params->bparams, csize);
noise_humidity_blend = new Noise(&params->np_biome_humidity_blend, seed, csize.X, csize.Z); biomemap = biomegen->biomemap;
//// Resolve nodes to be used //// Resolve nodes to be used
INodeDefManager *ndef = emerge->ndef;
c_stone = ndef->getId("mapgen_stone"); c_stone = ndef->getId("mapgen_stone");
c_water_source = ndef->getId("mapgen_water_source"); c_water_source = ndef->getId("mapgen_water_source");
c_lava_source = ndef->getId("mapgen_lava_source"); c_lava_source = ndef->getId("mapgen_lava_source");
@ -141,14 +136,10 @@ MapgenV7::~MapgenV7()
delete noise_cave1; delete noise_cave1;
delete noise_cave2; delete noise_cave2;
delete noise_heat; delete biomegen;
delete noise_humidity;
delete noise_heat_blend;
delete noise_humidity_blend;
delete[] ridge_heightmap; delete[] ridge_heightmap;
delete[] heightmap; delete[] heightmap;
delete[] biomemap;
} }
@ -279,12 +270,10 @@ void MapgenV7::makeChunk(BlockMakeData *data)
// Update heightmap to include mountain terrain // Update heightmap to include mountain terrain
updateHeightmap(node_min, node_max); updateHeightmap(node_min, node_max);
// Create biomemap at heightmap surface // Init biome generator, place biome-specific nodes, and build biomemap
bmgr->calcBiomes(csize.X, csize.Z, noise_heat->result, biomegen->calcBiomeNoise(node_min);
noise_humidity->result, heightmap, biomemap); biomegen->getBiomes(heightmap);
MgStoneType stone_type = generateBiomes();
// Actually place the biome-specific nodes
MgStoneType stone_type = generateBiomes(noise_heat->result, noise_humidity->result);
if (flags & MG_CAVES) if (flags & MG_CAVES)
generateCaves(stone_surface_max_y); generateCaves(stone_surface_max_y);
@ -384,35 +373,10 @@ void MapgenV7::calculateNoise()
// Cave noises are calculated in generateCaves() // Cave noises are calculated in generateCaves()
// only if solid terrain is present in mapchunk // 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);
noise_humidity_blend->perlinMap2D(x, z);
for (s32 i = 0; i < csize.X * csize.Z; i++) {
noise_heat->result[i] += noise_heat_blend->result[i];
noise_humidity->result[i] += noise_humidity_blend->result[i];
}
heatmap = noise_heat->result;
humidmap = noise_humidity->result;
//printf("calculateNoise: %dus\n", t.stop()); //printf("calculateNoise: %dus\n", t.stop());
} }
Biome *MapgenV7::getBiomeAtPoint(v3s16 p)
{
float heat = NoisePerlin2D(&noise_heat->np, p.X, p.Z, seed) +
NoisePerlin2D(&noise_heat_blend->np, p.X, p.Z, seed);
float humidity = NoisePerlin2D(&noise_humidity->np, p.X, p.Z, seed) +
NoisePerlin2D(&noise_humidity_blend->np, p.X, p.Z, seed);
s16 groundlevel = baseTerrainLevelAtPoint(p.X, p.Z);
return bmgr->getBiome(heat, humidity, groundlevel);
}
float MapgenV7::baseTerrainLevelAtPoint(s16 x, s16 z) float MapgenV7::baseTerrainLevelAtPoint(s16 x, s16 z)
{ {
float hselect = NoisePerlin2D(&noise_height_select->np, x, z, seed); float hselect = NoisePerlin2D(&noise_height_select->np, x, z, seed);
@ -553,7 +517,7 @@ void MapgenV7::generateRidgeTerrain()
} }
MgStoneType MapgenV7::generateBiomes(float *heat_map, float *humidity_map) MgStoneType MapgenV7::generateBiomes()
{ {
v3s16 em = vm->m_area.getExtent(); v3s16 em = vm->m_area.getExtent();
u32 index = 0; u32 index = 0;
@ -589,7 +553,8 @@ MgStoneType MapgenV7::generateBiomes(float *heat_map, float *humidity_map)
// 3. When stone or water is detected but biome has not yet been calculated. // 3. When stone or water is detected but biome has not yet been calculated.
if ((c == c_stone && (air_above || water_above || !biome)) || if ((c == c_stone && (air_above || water_above || !biome)) ||
(c == c_water_source && (air_above || !biome))) { (c == c_water_source && (air_above || !biome))) {
biome = bmgr->getBiome(heat_map[index], humidity_map[index], y); biome = biomegen->getBiomeAtIndex(index, y);
depth_top = biome->depth_top; depth_top = biome->depth_top;
base_filler = MYMAX(depth_top + biome->depth_filler base_filler = MYMAX(depth_top + biome->depth_filler
+ noise_filler_depth->result[index], 0); + noise_filler_depth->result[index], 0);

View File

@ -84,11 +84,6 @@ public:
Noise *noise_cave1; Noise *noise_cave1;
Noise *noise_cave2; Noise *noise_cave2;
Noise *noise_heat;
Noise *noise_humidity;
Noise *noise_heat_blend;
Noise *noise_humidity_blend;
content_t c_stone; content_t c_stone;
content_t c_water_source; content_t c_water_source;
content_t c_lava_source; content_t c_lava_source;
@ -107,7 +102,6 @@ public:
virtual void makeChunk(BlockMakeData *data); virtual void makeChunk(BlockMakeData *data);
int getSpawnLevelAtPoint(v2s16 p); int getSpawnLevelAtPoint(v2s16 p);
Biome *getBiomeAtPoint(v3s16 p);
float baseTerrainLevelAtPoint(s16 x, s16 z); float baseTerrainLevelAtPoint(s16 x, s16 z);
float baseTerrainLevelFromMap(int index); float baseTerrainLevelFromMap(int index);
@ -119,7 +113,7 @@ public:
int generateTerrain(); int generateTerrain();
void generateRidgeTerrain(); void generateRidgeTerrain();
MgStoneType generateBiomes(float *heat_map, float *humidity_map); MgStoneType generateBiomes();
void dustTopNodes(); void dustTopNodes();
void generateCaves(s16 max_stone_y); void generateCaves(s16 max_stone_y);

View File

@ -68,7 +68,7 @@ MapgenValleys::MapgenValleys(int mapgenid, MapgenParams *params, EmergeManager *
: Mapgen(mapgenid, params, emerge) : Mapgen(mapgenid, params, emerge)
{ {
this->m_emerge = emerge; this->m_emerge = emerge;
this->bmgr = emerge->biomemgr; this->bmgr = emerge->biomemgr;
//// amount of elements to skip for the next index //// amount of elements to skip for the next index
//// for noise/height/biome maps (not vmanip) //// for noise/height/biome maps (not vmanip)
@ -77,15 +77,13 @@ MapgenValleys::MapgenValleys(int mapgenid, MapgenParams *params, EmergeManager *
// 1-down overgeneration // 1-down overgeneration
this->zstride_1d = csize.X * (csize.Y + 1); this->zstride_1d = csize.X * (csize.Y + 1);
this->biomemap = new u8[csize.X * csize.Z];
this->heightmap = new s16[csize.X * csize.Z]; this->heightmap = new s16[csize.X * csize.Z];
this->heatmap = NULL;
this->humidmap = NULL;
this->map_gen_limit = MYMIN(MAX_MAP_GENERATION_LIMIT, this->map_gen_limit = MYMIN(MAX_MAP_GENERATION_LIMIT,
g_settings->getU16("map_generation_limit")); g_settings->getU16("map_generation_limit"));
MapgenValleysParams *sp = (MapgenValleysParams *)params->sparams; MapgenValleysParams *sp = (MapgenValleysParams *)params->sparams;
BiomeParamsOriginal *bp = (BiomeParamsOriginal *)params->bparams;
this->spflags = sp->spflags; this->spflags = sp->spflags;
this->altitude_chill = sp->altitude_chill; this->altitude_chill = sp->altitude_chill;
@ -113,15 +111,16 @@ MapgenValleys::MapgenValleys(int mapgenid, MapgenParams *params, EmergeManager *
noise_cave2 = new Noise(&sp->np_cave2, seed, csize.X, csize.Y + 1, csize.Z); noise_cave2 = new Noise(&sp->np_cave2, seed, csize.X, csize.Y + 1, csize.Z);
noise_massive_caves = new Noise(&sp->np_massive_caves, seed, csize.X, csize.Y + 1, csize.Z); noise_massive_caves = new Noise(&sp->np_massive_caves, seed, csize.X, csize.Y + 1, csize.Z);
//// Biome noise //// Initialize biome generator
noise_heat_blend = new Noise(&params->np_biome_heat_blend, seed, csize.X, csize.Z); // NOTE: valleys mapgen can only use BiomeGenOriginal
noise_heat = new Noise(&params->np_biome_heat, seed, csize.X, csize.Z); biomegen = emerge->biomemgr->createBiomeGen(
noise_humidity_blend = new Noise(&params->np_biome_humidity_blend, seed, csize.X, csize.Z); BIOMEGEN_ORIGINAL, params->bparams, csize);
noise_humidity = new Noise(&params->np_biome_humidity, seed, csize.X, csize.Z); biomemap = biomegen->biomemap;
m_bgen = (BiomeGenOriginal *)biomegen;
this->humid_rivers = (spflags & MGVALLEYS_HUMID_RIVERS); this->humid_rivers = (spflags & MGVALLEYS_HUMID_RIVERS);
this->use_altitude_chill = (spflags & MGVALLEYS_ALT_CHILL); this->use_altitude_chill = (spflags & MGVALLEYS_ALT_CHILL);
this->humidity_adjust = params->np_biome_humidity.offset - 50.f; this->humidity_adjust = bp->np_humidity.offset - 50.f;
// a small chance of overflows if the settings are very high // a small chance of overflows if the settings are very high
this->cave_water_max_height = water_level + MYMAX(0, water_features_lim - 4) * 50; this->cave_water_max_height = water_level + MYMAX(0, water_features_lim - 4) * 50;
@ -130,8 +129,6 @@ MapgenValleys::MapgenValleys(int mapgenid, MapgenParams *params, EmergeManager *
tcave_cache = new float[csize.Y + 2]; tcave_cache = new float[csize.Y + 2];
//// Resolve nodes to be used //// Resolve nodes to be used
INodeDefManager *ndef = emerge->ndef;
c_cobble = ndef->getId("mapgen_cobble"); c_cobble = ndef->getId("mapgen_cobble");
c_desert_stone = ndef->getId("mapgen_desert_stone"); c_desert_stone = ndef->getId("mapgen_desert_stone");
c_dirt = ndef->getId("mapgen_dirt"); c_dirt = ndef->getId("mapgen_dirt");
@ -174,12 +171,8 @@ MapgenValleys::~MapgenValleys()
delete noise_valley_depth; delete noise_valley_depth;
delete noise_valley_profile; delete noise_valley_profile;
delete noise_heat; delete biomegen;
delete noise_heat_blend;
delete noise_humidity;
delete noise_humidity_blend;
delete[] biomemap;
delete[] heightmap; delete[] heightmap;
delete[] tcave_cache; delete[] tcave_cache;
} }
@ -293,14 +286,19 @@ void MapgenValleys::makeChunk(BlockMakeData *data)
// Generate noise maps and base terrain height. // Generate noise maps and base terrain height.
calculateNoise(); calculateNoise();
// Generate biome noises. Note this must be executed strictly before
// generateTerrain, because generateTerrain depends on intermediate
// biome-related noises.
biomegen->calcBiomeNoise(node_min);
// Generate base terrain with initial heightmaps // Generate base terrain with initial heightmaps
s16 stone_surface_max_y = generateTerrain(); s16 stone_surface_max_y = generateTerrain();
// Create biomemap at heightmap surface // Build biomemap
bmgr->calcBiomes(csize.X, csize.Z, heatmap, humidmap, heightmap, biomemap); biomegen->getBiomes(heightmap);
// Actually place the biome-specific nodes // Place biome-specific nodes
MgStoneType stone_type = generateBiomes(heatmap, humidmap); MgStoneType stone_type = generateBiomes();
// Cave creation. // Cave creation.
if (flags & MG_CAVES) if (flags & MG_CAVES)
@ -391,10 +389,6 @@ void MapgenValleys::calculateNoise()
//TimeTaker tcn("actualNoise"); //TimeTaker tcn("actualNoise");
noise_filler_depth->perlinMap2D(x, z); noise_filler_depth->perlinMap2D(x, z);
noise_heat_blend->perlinMap2D(x, z);
noise_heat->perlinMap2D(x, z);
noise_humidity_blend->perlinMap2D(x, z);
noise_humidity->perlinMap2D(x, z);
noise_inter_valley_slope->perlinMap2D(x, z); noise_inter_valley_slope->perlinMap2D(x, z);
noise_rivers->perlinMap2D(x, z); noise_rivers->perlinMap2D(x, z);
noise_terrain_height->perlinMap2D(x, z); noise_terrain_height->perlinMap2D(x, z);
@ -418,9 +412,8 @@ void MapgenValleys::calculateNoise()
} }
for (s32 index = 0; index < csize.X * csize.Z; index++) { for (s32 index = 0; index < csize.X * csize.Z; index++) {
noise_heat->result[index] += noise_heat_blend->result[index] + heat_offset; m_bgen->heatmap[index] += heat_offset;
noise_humidity->result[index] *= humidity_scale; m_bgen->humidmap[index] *= humidity_scale;
noise_humidity->result[index] += noise_humidity_blend->result[index];
} }
TerrainNoise tn; TerrainNoise tn;
@ -450,9 +443,6 @@ void MapgenValleys::calculateNoise()
float mount = terrainLevelFromNoise(&tn); float mount = terrainLevelFromNoise(&tn);
noise_terrain_height->result[index] = mount; noise_terrain_height->result[index] = mount;
} }
heatmap = noise_heat->result;
humidmap = noise_humidity->result;
} }
@ -596,7 +586,7 @@ int MapgenValleys::generateTerrain()
float river_y = noise_rivers->result[index_2d]; float river_y = noise_rivers->result[index_2d];
float surface_y = noise_terrain_height->result[index_2d]; float surface_y = noise_terrain_height->result[index_2d];
float slope = noise_inter_valley_slope->result[index_2d]; float slope = noise_inter_valley_slope->result[index_2d];
float t_heat = noise_heat->result[index_2d]; float t_heat = m_bgen->heatmap[index_2d];
heightmap[index_2d] = -MAX_MAP_GENERATION_LIMIT; heightmap[index_2d] = -MAX_MAP_GENERATION_LIMIT;
@ -610,7 +600,7 @@ int MapgenValleys::generateTerrain()
t_heat -= alt_to_heat * MYMAX(surface_y, river_y) / altitude_chill; t_heat -= alt_to_heat * MYMAX(surface_y, river_y) / altitude_chill;
// If humidity is low or heat is high, lower the water table. // If humidity is low or heat is high, lower the water table.
float delta = noise_humidity->result[index_2d] - 50.f; float delta = m_bgen->humidmap[index_2d] - 50.f;
if (delta < 0.f) { if (delta < 0.f) {
float t_evap = (t_heat - 32.f) / evaporation; float t_evap = (t_heat - 32.f) / evaporation;
river_y += delta * MYMAX(t_evap, 0.08f); river_y += delta * MYMAX(t_evap, 0.08f);
@ -672,7 +662,7 @@ int MapgenValleys::generateTerrain()
// Use base ground (water table) in a riverbed, to // Use base ground (water table) in a riverbed, to
// avoid an unnatural rise in humidity. // avoid an unnatural rise in humidity.
float t_alt = MYMAX(noise_rivers->result[index_2d], (float)heightmap[index_2d]); float t_alt = MYMAX(noise_rivers->result[index_2d], (float)heightmap[index_2d]);
float humid = noise_humidity->result[index_2d]; float humid = m_bgen->humidmap[index_2d];
float water_depth = (t_alt - river_y) / humidity_dropoff; float water_depth = (t_alt - river_y) / humidity_dropoff;
humid *= 1.f + pow(0.5f, MYMAX(water_depth, 1.f)); humid *= 1.f + pow(0.5f, MYMAX(water_depth, 1.f));
@ -683,7 +673,7 @@ int MapgenValleys::generateTerrain()
if (t_alt > 0.f) if (t_alt > 0.f)
humid -= alt_to_humid * t_alt / altitude_chill; humid -= alt_to_humid * t_alt / altitude_chill;
noise_humidity->result[index_2d] = humid; m_bgen->humidmap[index_2d] = humid;
} }
// Assign the heat adjusted by any changed altitudes. // Assign the heat adjusted by any changed altitudes.
@ -693,9 +683,9 @@ int MapgenValleys::generateTerrain()
float t_alt = MYMAX(noise_rivers->result[index_2d], (float)heightmap[index_2d]); float t_alt = MYMAX(noise_rivers->result[index_2d], (float)heightmap[index_2d]);
if (humid_rivers && heightmap[index_2d] == (s16)myround(surface_y)) if (humid_rivers && heightmap[index_2d] == (s16)myround(surface_y))
// The altitude hasn't changed. Use the first result. // The altitude hasn't changed. Use the first result.
noise_heat->result[index_2d] = t_heat; m_bgen->heatmap[index_2d] = t_heat;
else if (t_alt > 0.f) else if (t_alt > 0.f)
noise_heat->result[index_2d] -= alt_to_heat * t_alt / altitude_chill; m_bgen->heatmap[index_2d] -= alt_to_heat * t_alt / altitude_chill;
} }
} }
@ -703,7 +693,7 @@ int MapgenValleys::generateTerrain()
} }
MgStoneType MapgenValleys::generateBiomes(float *heat_map, float *humidity_map) MgStoneType MapgenValleys::generateBiomes()
{ {
v3s16 em = vm->m_area.getExtent(); v3s16 em = vm->m_area.getExtent();
u32 index = 0; u32 index = 0;
@ -739,9 +729,9 @@ MgStoneType MapgenValleys::generateBiomes(float *heat_map, float *humidity_map)
// 3. When stone or water is detected but biome has not yet been calculated. // 3. When stone or water is detected but biome has not yet been calculated.
if ((c == c_stone && (air_above || water_above || !biome)) if ((c == c_stone && (air_above || water_above || !biome))
|| ((c == c_water_source || c == c_river_water_source) || ((c == c_water_source || c == c_river_water_source)
&& (air_above || !biome))) { && (air_above || !biome))) {
// Both heat and humidity have already been adjusted for altitude. // Both heat and humidity have already been adjusted for altitude.
biome = bmgr->getBiome(heat_map[index], humidity_map[index], y); biome = biomegen->getBiomeAtIndex(index, y);
depth_top = biome->depth_top; depth_top = biome->depth_top;
base_filler = MYMAX(depth_top base_filler = MYMAX(depth_top

View File

@ -39,6 +39,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#define MYCUBE(x) (x) * (x) * (x) #define MYCUBE(x) (x) * (x) * (x)
class BiomeManager; class BiomeManager;
class BiomeGenOriginal;
// Global profiler // Global profiler
//class Profiler; //class Profiler;
@ -98,6 +99,7 @@ public:
private: private:
EmergeManager *m_emerge; EmergeManager *m_emerge;
BiomeManager *bmgr; BiomeManager *bmgr;
BiomeGenOriginal *m_bgen;
int ystride; int ystride;
int zstride; int zstride;
@ -136,11 +138,6 @@ private:
Noise *noise_valley_depth; Noise *noise_valley_depth;
Noise *noise_valley_profile; Noise *noise_valley_profile;
Noise *noise_heat;
Noise *noise_heat_blend;
Noise *noise_humidity;
Noise *noise_humidity_blend;
content_t c_cobble; content_t c_cobble;
content_t c_desert_stone; content_t c_desert_stone;
content_t c_dirt; content_t c_dirt;
@ -164,9 +161,7 @@ private:
float terrainLevelFromNoise(TerrainNoise *tn); float terrainLevelFromNoise(TerrainNoise *tn);
float adjustedTerrainLevelFromNoise(TerrainNoise *tn); float adjustedTerrainLevelFromNoise(TerrainNoise *tn);
float humidityByTerrain(float humidity_base, float mount, float rivers, float valley); MgStoneType generateBiomes();
MgStoneType generateBiomes(float *heat_map, float *humidity_map);
void dustTopNodes(); void dustTopNodes();
void generateCaves(s16 max_stone_y); void generateCaves(s16 max_stone_y);

View File

@ -27,6 +27,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "util/numeric.h" #include "util/numeric.h"
#include "util/mathconstants.h" #include "util/mathconstants.h"
#include "porting.h" #include "porting.h"
#include "settings.h"
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
@ -63,49 +64,11 @@ BiomeManager::BiomeManager(IGameDef *gamedef) :
} }
BiomeManager::~BiomeManager() BiomeManager::~BiomeManager()
{ {
//if (biomecache)
// delete[] biomecache;
} }
// just a PoC, obviously needs optimization later on (precalculate this)
void BiomeManager::calcBiomes(s16 sx, s16 sy, float *heat_map,
float *humidity_map, s16 *height_map, u8 *biomeid_map)
{
for (s32 i = 0; i != sx * sy; i++) {
Biome *biome = getBiome(heat_map[i], humidity_map[i], height_map[i]);
biomeid_map[i] = biome->index;
}
}
Biome *BiomeManager::getBiome(float heat, float humidity, s16 y)
{
Biome *b, *biome_closest = NULL;
float dist_min = FLT_MAX;
for (size_t i = 1; i < m_objects.size(); i++) {
b = (Biome *)m_objects[i];
if (!b || y > b->y_max || y < b->y_min)
continue;
float d_heat = heat - b->heat_point;
float d_humidity = humidity - b->humidity_point;
float dist = (d_heat * d_heat) +
(d_humidity * d_humidity);
if (dist < dist_min) {
dist_min = dist;
biome_closest = b;
}
}
return biome_closest ? biome_closest : (Biome *)m_objects[0];
}
void BiomeManager::clear() void BiomeManager::clear()
{ {
EmergeManager *emerge = m_gamedef->getEmergeManager(); EmergeManager *emerge = m_gamedef->getEmergeManager();
@ -118,17 +81,153 @@ void BiomeManager::clear()
} }
// Don't delete the first biome // Don't delete the first biome
for (size_t i = 1; i < m_objects.size(); i++) { for (size_t i = 1; i < m_objects.size(); i++)
Biome *b = (Biome *)m_objects[i]; delete (Biome *)m_objects[i];
delete b;
}
m_objects.resize(1); m_objects.resize(1);
} }
////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
void BiomeParamsOriginal::readParams(const Settings *settings)
{
settings->getNoiseParams("mg_biome_np_heat", np_heat);
settings->getNoiseParams("mg_biome_np_heat_blend", np_heat_blend);
settings->getNoiseParams("mg_biome_np_humidity", np_humidity);
settings->getNoiseParams("mg_biome_np_humidity_blend", np_humidity_blend);
}
void BiomeParamsOriginal::writeParams(Settings *settings) const
{
settings->setNoiseParams("mg_biome_np_heat", np_heat);
settings->setNoiseParams("mg_biome_np_heat_blend", np_heat_blend);
settings->setNoiseParams("mg_biome_np_humidity", np_humidity);
settings->setNoiseParams("mg_biome_np_humidity_blend", np_humidity_blend);
}
////////////////////////////////////////////////////////////////////////////////
BiomeGenOriginal::BiomeGenOriginal(BiomeManager *biomemgr,
BiomeParamsOriginal *params, v3s16 chunksize)
{
m_bmgr = biomemgr;
m_params = params;
m_csize = chunksize;
noise_heat = new Noise(&params->np_heat,
params->seed, m_csize.X, m_csize.Z);
noise_humidity = new Noise(&params->np_humidity,
params->seed, m_csize.X, m_csize.Z);
noise_heat_blend = new Noise(&params->np_heat_blend,
params->seed, m_csize.X, m_csize.Z);
noise_humidity_blend = new Noise(&params->np_humidity_blend,
params->seed, m_csize.X, m_csize.Z);
heatmap = noise_heat->result;
humidmap = noise_humidity->result;
biomemap = new u8[m_csize.X * m_csize.Z];
}
BiomeGenOriginal::~BiomeGenOriginal()
{
delete []biomemap;
delete noise_heat;
delete noise_humidity;
delete noise_heat_blend;
delete noise_humidity_blend;
}
Biome *BiomeGenOriginal::calcBiomeAtPoint(v3s16 pos) const
{
float heat =
NoisePerlin2D(&m_params->np_heat, pos.X, pos.Z, m_params->seed) +
NoisePerlin2D(&m_params->np_heat_blend, pos.X, pos.Z, m_params->seed);
float humidity =
NoisePerlin2D(&m_params->np_humidity, pos.X, pos.Z, m_params->seed) +
NoisePerlin2D(&m_params->np_humidity_blend, pos.X, pos.Z, m_params->seed);
return calcBiomeFromNoise(heat, humidity, pos.Y);
}
void BiomeGenOriginal::calcBiomeNoise(v3s16 pmin)
{
m_pmin = pmin;
noise_heat->perlinMap2D(pmin.X, pmin.Z);
noise_humidity->perlinMap2D(pmin.X, pmin.Z);
noise_heat_blend->perlinMap2D(pmin.X, pmin.Z);
noise_humidity_blend->perlinMap2D(pmin.X, pmin.Z);
for (s32 i = 0; i < m_csize.X * m_csize.Z; i++) {
noise_heat->result[i] += noise_heat_blend->result[i];
noise_humidity->result[i] += noise_humidity_blend->result[i];
}
}
u8 *BiomeGenOriginal::getBiomes(s16 *heightmap)
{
for (s32 i = 0; i != m_csize.X * m_csize.Z; i++) {
Biome *biome = calcBiomeFromNoise(
noise_heat->result[i],
noise_humidity->result[i],
heightmap[i]);
biomemap[i] = biome->index;
}
return biomemap;
}
Biome *BiomeGenOriginal::getBiomeAtPoint(v3s16 pos) const
{
return getBiomeAtIndex(
(pos.Z - m_pmin.Z) * m_csize.X + (pos.X - m_pmin.X),
pos.Y);
}
Biome *BiomeGenOriginal::getBiomeAtIndex(size_t index, s16 y) const
{
return calcBiomeFromNoise(
noise_heat->result[index],
noise_humidity->result[index],
y);
}
Biome *BiomeGenOriginal::calcBiomeFromNoise(float heat, float humidity, s16 y) const
{
Biome *b, *biome_closest = NULL;
float dist_min = FLT_MAX;
for (size_t i = 1; i < m_bmgr->getNumObjects(); i++) {
b = (Biome *)m_bmgr->getRaw(i);
if (!b || y > b->y_max || y < b->y_min)
continue;
float d_heat = heat - b->heat_point;
float d_humidity = humidity - b->humidity_point;
float dist = (d_heat * d_heat) +
(d_humidity * d_humidity);
if (dist < dist_min) {
dist_min = dist;
biome_closest = b;
}
}
return biome_closest ? biome_closest : (Biome *)m_bmgr->getRaw(BIOME_NONE);
}
////////////////////////////////////////////////////////////////////////////////
void Biome::resolveNodeNames() void Biome::resolveNodeNames()
{ {

View File

@ -22,6 +22,16 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "objdef.h" #include "objdef.h"
#include "nodedef.h" #include "nodedef.h"
#include "noise.h"
class Settings;
class BiomeManager;
////
//// Biome
////
#define BIOME_NONE ((u8)0)
enum BiomeType enum BiomeType
{ {
@ -56,10 +66,122 @@ public:
virtual void resolveNodeNames(); virtual void resolveNodeNames();
}; };
////
//// BiomeGen
////
enum BiomeGenType {
BIOMEGEN_ORIGINAL,
};
struct BiomeParams {
virtual void readParams(const Settings *settings) = 0;
virtual void writeParams(Settings *settings) const = 0;
virtual ~BiomeParams() {}
int seed;
};
class BiomeGen {
public:
virtual ~BiomeGen() {}
virtual BiomeGenType getType() const = 0;
// Calculates the biome at the exact position provided. This function can
// be called at any time, but may be less efficient than the latter methods,
// depending on implementation.
virtual Biome *calcBiomeAtPoint(v3s16 pos) const = 0;
// Computes any intermediate results needed for biome generation. Must be
// called before using any of: getBiomes, getBiomeAtPoint, or getBiomeAtIndex.
// Calling this invalidates the previous results stored in biomemap.
virtual void calcBiomeNoise(v3s16 pmin) = 0;
// Gets all biomes in current chunk using each corresponding element of
// heightmap as the y position, then stores the results by biome index in
// biomemap (also returned)
virtual u8 *getBiomes(s16 *heightmap) = 0;
// Gets a single biome at the specified position, which must be contained
// in the region formed by m_pmin and (m_pmin + m_csize - 1).
virtual Biome *getBiomeAtPoint(v3s16 pos) const = 0;
// Same as above, but uses a raw numeric index correlating to the (x,z) position.
virtual Biome *getBiomeAtIndex(size_t index, s16 y) const = 0;
// Result of calcBiomes bulk computation.
u8 *biomemap;
protected:
BiomeManager *m_bmgr;
v3s16 m_pmin;
v3s16 m_csize;
};
////
//// BiomeGen implementations
////
//
// Original biome algorithm (Whittaker's classification + surface height)
//
struct BiomeParamsOriginal : public BiomeParams {
BiomeParamsOriginal() :
np_heat(50, 50, v3f(750.0, 750.0, 750.0), 5349, 3, 0.5, 2.0),
np_humidity(50, 50, v3f(750.0, 750.0, 750.0), 842, 3, 0.5, 2.0),
np_heat_blend(0, 1.5, v3f(8.0, 8.0, 8.0), 13, 2, 1.0, 2.0),
np_humidity_blend(0, 1.5, v3f(8.0, 8.0, 8.0), 90003, 2, 1.0, 2.0)
{
}
virtual void readParams(const Settings *settings);
virtual void writeParams(Settings *settings) const;
NoiseParams np_heat;
NoiseParams np_humidity;
NoiseParams np_heat_blend;
NoiseParams np_humidity_blend;
};
class BiomeGenOriginal : public BiomeGen {
public:
BiomeGenOriginal(BiomeManager *biomemgr,
BiomeParamsOriginal *params, v3s16 chunksize);
virtual ~BiomeGenOriginal();
BiomeGenType getType() const { return BIOMEGEN_ORIGINAL; }
Biome *calcBiomeAtPoint(v3s16 pos) const;
void calcBiomeNoise(v3s16 pmin);
u8 *getBiomes(s16 *heightmap);
Biome *getBiomeAtPoint(v3s16 pos) const;
Biome *getBiomeAtIndex(size_t index, s16 y) const;
Biome *calcBiomeFromNoise(float heat, float humidity, s16 y) const;
float *heatmap;
float *humidmap;
private:
BiomeParamsOriginal *m_params;
Noise *noise_heat;
Noise *noise_humidity;
Noise *noise_heat_blend;
Noise *noise_humidity_blend;
};
////
//// BiomeManager
////
class BiomeManager : public ObjDefManager { class BiomeManager : public ObjDefManager {
public: public:
static const char *OBJECT_TITLE;
BiomeManager(IGameDef *gamedef); BiomeManager(IGameDef *gamedef);
virtual ~BiomeManager(); virtual ~BiomeManager();
@ -73,15 +195,36 @@ public:
return new Biome; return new Biome;
} }
BiomeGen *createBiomeGen(BiomeGenType type, BiomeParams *params, v3s16 chunksize)
{
switch (type) {
case BIOMEGEN_ORIGINAL:
return new BiomeGenOriginal(this,
(BiomeParamsOriginal *)params, chunksize);
default:
return NULL;
}
}
static BiomeParams *createBiomeParams(BiomeGenType type)
{
switch (type) {
case BIOMEGEN_ORIGINAL:
return new BiomeParamsOriginal;
default:
return NULL;
}
}
virtual void clear(); virtual void clear();
void calcBiomes(s16 sx, s16 sy, float *heat_map, float *humidity_map, // Looks for pos in the biome cache, and if non-existent, looks up by noise
s16 *height_map, u8 *biomeid_map); u8 getBiomeAtPoint(v3s16 pos);
Biome *getBiome(float heat, float humidity, s16 y);
private: private:
IGameDef *m_gamedef; IGameDef *m_gamedef;
}; };
#endif
#endif

View File

@ -528,24 +528,26 @@ int ModApiMapgen::l_get_mapgen_object(lua_State *L)
return 1; return 1;
} }
case MGOBJ_BIOMEMAP: { case MGOBJ_BIOMEMAP: {
if (!mg->biomemap) if (!mg->biomegen)
return 0; return 0;
lua_newtable(L); lua_newtable(L);
for (size_t i = 0; i != maplen; i++) { for (size_t i = 0; i != maplen; i++) {
lua_pushinteger(L, mg->biomemap[i]); lua_pushinteger(L, mg->biomegen->biomemap[i]);
lua_rawseti(L, -2, i + 1); lua_rawseti(L, -2, i + 1);
} }
return 1; return 1;
} }
case MGOBJ_HEATMAP: { case MGOBJ_HEATMAP: {
if (!mg->heatmap) if (!mg->biomegen || mg->biomegen->getType() != BIOMEGEN_ORIGINAL)
return 0; return 0;
BiomeGenOriginal *bg = (BiomeGenOriginal *)mg->biomegen;
lua_newtable(L); lua_newtable(L);
for (size_t i = 0; i != maplen; i++) { for (size_t i = 0; i != maplen; i++) {
lua_pushnumber(L, mg->heatmap[i]); lua_pushnumber(L, bg->heatmap[i]);
lua_rawseti(L, -2, i + 1); lua_rawseti(L, -2, i + 1);
} }
@ -553,12 +555,14 @@ int ModApiMapgen::l_get_mapgen_object(lua_State *L)
} }
case MGOBJ_HUMIDMAP: { case MGOBJ_HUMIDMAP: {
if (!mg->humidmap) if (!mg->biomegen || mg->biomegen->getType() != BIOMEGEN_ORIGINAL)
return 0; return 0;
BiomeGenOriginal *bg = (BiomeGenOriginal *)mg->biomegen;
lua_newtable(L); lua_newtable(L);
for (size_t i = 0; i != maplen; i++) { for (size_t i = 0; i != maplen; i++) {
lua_pushnumber(L, mg->humidmap[i]); lua_pushnumber(L, bg->humidmap[i]);
lua_rawseti(L, -2, i + 1); lua_rawseti(L, -2, i + 1);
} }