summaryrefslogtreecommitdiffstats
path: root/src/Generating
diff options
context:
space:
mode:
Diffstat (limited to 'src/Generating')
-rw-r--r--src/Generating/BioGen.cpp93
-rw-r--r--src/Generating/IntGen.h954
2 files changed, 1047 insertions, 0 deletions
diff --git a/src/Generating/BioGen.cpp b/src/Generating/BioGen.cpp
index 203faff56..c9405040f 100644
--- a/src/Generating/BioGen.cpp
+++ b/src/Generating/BioGen.cpp
@@ -5,6 +5,7 @@
#include "Globals.h"
#include "BioGen.h"
+#include "IntGen.h"
#include "../IniFile.h"
#include "../LinearUpscale.h"
@@ -917,6 +918,94 @@ void cBioGenTwoLevel::InitializeBiomeGen(cIniFile & a_IniFile)
////////////////////////////////////////////////////////////////////////////////
+// cBioGenGrown:
+
+class cBioGenGrown:
+ public cBiomeGen
+{
+public:
+ cBioGenGrown(int a_Seed)
+ {
+ auto FinalRivers =
+ std::make_shared<cIntGenSmooth<8>> (a_Seed + 1,
+ std::make_shared<cIntGenRiver <10>> (a_Seed + 2,
+ std::make_shared<cIntGenZoom <12>> (a_Seed + 3,
+ std::make_shared<cIntGenSmooth<8>> (a_Seed + 4,
+ std::make_shared<cIntGenZoom <10>> (a_Seed + 5,
+ std::make_shared<cIntGenZoom <7>> (a_Seed + 6,
+ std::make_shared<cIntGenZoom <5>> (a_Seed + 7,
+ std::make_shared<cIntGenZoom <4>> (a_Seed + 8,
+ std::make_shared<cIntGenZoom <4>> (a_Seed + 9,
+ std::make_shared<cIntGenZoom <4>> (a_Seed + 10,
+ std::make_shared<cIntGenZoom <4>> (a_Seed + 11,
+ std::make_shared<cIntGenChoice<2, 4>>(a_Seed + 12
+ ))))))))))));
+
+ auto FinalBiomes =
+ std::make_shared<cIntGenSmooth <8>> (a_Seed + 1008,
+ std::make_shared<cIntGenZoom <10>>(a_Seed + 15,
+ std::make_shared<cIntGenSmooth <7>> (a_Seed + 1000,
+ std::make_shared<cIntGenZoom <9>> (a_Seed + 16,
+ std::make_shared<cIntGenSmooth <6>> (a_Seed + 1001,
+ std::make_shared<cIntGenZoom <8>> (a_Seed,
+ std::make_shared<cIntGenSmooth <6>> (a_Seed + 1002,
+ std::make_shared<cIntGenZoom <8>> (a_Seed + 1,
+ std::make_shared<cIntGenBeaches <6>> (
+ std::make_shared<cIntGenSmooth <8>> (a_Seed + 1002,
+ std::make_shared<cIntGenZoom <10>>(a_Seed + 2,
+ std::make_shared<cIntGenZoom <7>> (a_Seed + 3,
+ std::make_shared<cIntGenAddIslands <5>> (a_Seed + 2004, 10,
+ std::make_shared<cIntGenZoom <5>> (a_Seed + 4,
+ std::make_shared<cIntGenAddToOcean <4>> (a_Seed + 9, 50, biMushroomIsland,
+ std::make_shared<cIntGenZoom <6>> (a_Seed + 8,
+ std::make_shared<cIntGenAddToOcean <5>> (a_Seed + 10, 500, biDeepOcean,
+ std::make_shared<cIntGenBiomes <7>> (a_Seed + 3000,
+ std::make_shared<cIntGenZoom <7>> (a_Seed + 5,
+ std::make_shared<cIntGenBiomeGroupEdges<5>> (
+ std::make_shared<cIntGenSmooth <7>> (a_Seed + 1003,
+ std::make_shared<cIntGenZoom <9>> (a_Seed + 7,
+ std::make_shared<cIntGenReplaceRandomly<6>> (bgJungle, bgTemperate, 50, a_Seed + 100,
+ std::make_shared<cIntGenReplaceRandomly<6>> (bgIce, bgTemperate, 50, a_Seed + 101,
+ std::make_shared<cIntGenAddIslands <6>> (a_Seed + 2000, 70,
+ std::make_shared<cIntGenSmooth <6>> (a_Seed + 1004,
+ std::make_shared<cIntGenZoom <8>> (a_Seed + 10,
+ std::make_shared<cIntGenAddIslands <6>> (a_Seed + 2003, 50,
+ std::make_shared<cIntGenZoom <6>> (a_Seed + 11,
+ std::make_shared<cIntLandOcean <5>> (a_Seed + 100, 65
+ ))))))))))))))))))))))))))))));
+
+ m_Gen =
+ std::make_shared<cIntGenSmooth <16>>(a_Seed,
+ std::make_shared<cIntGenZoom <18>>(a_Seed,
+ std::make_shared<cIntGenSmooth <11>>(a_Seed,
+ std::make_shared<cIntGenZoom <13>>(a_Seed,
+ std::make_shared<cIntGenMixRivers<8>> (
+ FinalBiomes, FinalRivers
+ )))));
+ }
+
+ virtual void GenBiomes(int a_ChunkX, int a_ChunkZ, cChunkDef::BiomeMap & a_Biomes) override
+ {
+ cIntGen<16, 16>::Values vals;
+ m_Gen->GetInts(a_ChunkX * cChunkDef::Width, a_ChunkZ * cChunkDef::Width, vals);
+ for (int z = 0; z < cChunkDef::Width; z++)
+ {
+ for (int x = 0; x < cChunkDef::Width; x++)
+ {
+ cChunkDef::SetBiome(a_Biomes, x, z, (EMCSBiome)vals[x + cChunkDef::Width * z]);
+ }
+ }
+ }
+
+protected:
+ cIntGenPtr<16, 16> m_Gen;
+};
+
+
+
+
+
+////////////////////////////////////////////////////////////////////////////////
// cBiomeGen:
cBiomeGenPtr cBiomeGen::CreateBiomeGen(cIniFile & a_IniFile, int a_Seed, bool & a_CacheOffByDefault)
@@ -952,6 +1041,10 @@ cBiomeGenPtr cBiomeGen::CreateBiomeGen(cIniFile & a_IniFile, int a_Seed, bool &
{
res = new cBioGenTwoLevel(a_Seed);
}
+ else if (NoCaseCompare(BiomeGenName, "grown") == 0)
+ {
+ res = new cBioGenGrown(a_Seed);
+ }
else
{
if (NoCaseCompare(BiomeGenName, "multistepmap") != 0)
diff --git a/src/Generating/IntGen.h b/src/Generating/IntGen.h
new file mode 100644
index 000000000..ae940232f
--- /dev/null
+++ b/src/Generating/IntGen.h
@@ -0,0 +1,954 @@
+
+// IntGen.h
+
+// Declares the cIntGen class and descendants for generating and filtering various 2D arrays of ints
+
+/*
+The integers generated may be interpreted in several ways:
+- land/see designators
+ - 0 = ocean
+ - >0 = land
+- biome group designators
+ - 0 = ocean
+ - 1 = desert biomes
+ - 2 = temperate biomes
+ - 3 = mountains (hills and forests)
+ - 4 = jungle
+ - 5 = ice biomes
+- biome IDs
+The interpretation depends on the generator used and on the position in the chain.
+
+The generators can be chained together - one produces data that another one consumes.
+Some of such chain connections require changing the data dimensions between the two, which is handled automatically
+by using templates.
+*/
+
+
+
+
+
+#pragma once
+
+#include "../BiomeDef.h"
+
+
+
+
+
+/** Constants representing the biome group designators. */
+const int bgOcean = 0;
+const int bgDesert = 1;
+const int bgTemperate = 2;
+const int bgMountains = 3;
+const int bgJungle = 4;
+const int bgIce = 5;
+const int bgMax = 5; // Maximum biome group value
+
+
+
+
+
+/** Interface that all the generator classes provide. */
+template <int SizeX, int SizeZ = SizeX>
+class cIntGen
+{
+public:
+ /** Holds the array of values generated by this class (descendant). */
+ typedef int Values[SizeX * SizeZ];
+
+ /** Generates the array of templated size into a_Values, based on given min coords. */
+ virtual void GetInts(int a_MinX, int a_MinZ, Values & a_Values) = 0;
+};
+
+template <int SizeX, int SizeZ = SizeX>
+using cIntGenPtr = std::shared_ptr<cIntGen<SizeX, SizeZ>>;
+
+
+
+
+
+
+/** Provides additional cNoise member and its helper functions. */
+template <int SizeX, int SizeZ = SizeX>
+class cIntGenWithNoise :
+ public cIntGen<SizeX, SizeZ>
+{
+ typedef cIntGen<SizeX, SizeZ> super;
+
+public:
+ cIntGenWithNoise(int a_Seed) :
+ m_Noise(a_Seed)
+ {
+ }
+
+protected:
+ cNoise m_Noise;
+
+ /** Chooses one of a_Val1 or a_Val2, based on m_Noise and the coordinates for querying the noise. */
+ int ChooseRandomOne(int a_RndX, int a_RndZ, int a_Val1, int a_Val2)
+ {
+ int rnd = m_Noise.IntNoise2DInt(a_RndX, a_RndZ) / 7;
+ return ((rnd & 1) == 0) ? a_Val1 : a_Val2;
+ }
+
+ /** Chooses one of a_ValN, based on m_Noise and the coordinates for querying the noise. */
+ int ChooseRandomOne(int a_RndX, int a_RndZ, int a_Val1, int a_Val2, int a_Val3, int a_Val4)
+ {
+ int rnd = m_Noise.IntNoise2DInt(a_RndX, a_RndZ) / 7;
+ switch (rnd % 4)
+ {
+ case 0: return a_Val1;
+ case 1: return a_Val2;
+ case 2: return a_Val3;
+ default: return a_Val4;
+ }
+ }
+};
+
+
+
+
+
+
+/** Generates a 2D array of random integers in the specified range [0 .. Range). */
+template <int Range, int SizeX, int SizeZ = SizeX>
+class cIntGenChoice :
+ public cIntGenWithNoise<SizeX, SizeZ>
+{
+ typedef cIntGenWithNoise<SizeX, SizeZ> super;
+
+public:
+ cIntGenChoice(int a_Seed) :
+ super(a_Seed)
+ {
+ }
+
+
+ virtual void GetInts(int a_MinX, int a_MinZ, Values & a_Values) override
+ {
+ for (int z = 0; z < SizeZ; z++)
+ {
+ int BaseZ = a_MinZ + z;
+ for (int x = 0; x < SizeX; x++)
+ {
+ a_Values[x + SizeX * z] = (m_Noise.IntNoise2DInt(a_MinX + x, BaseZ) / 7) % Range;
+ }
+ } // for z
+ }
+};
+
+
+
+
+
+
+/** Decides between the ocean and landmass biomes.
+Has a threshold (in percent) of how much land, the larger the threshold, the more land.
+Generates 0 for ocean, biome group ID for landmass. */
+template <int SizeX, int SizeZ = SizeX>
+class cIntLandOcean :
+ public cIntGenWithNoise<SizeX, SizeZ>
+{
+ typedef cIntGenWithNoise<SizeX, SizeZ> super;
+
+public:
+ cIntLandOcean(int a_Seed, int a_Threshold) :
+ super(a_Seed),
+ m_Threshold(a_Threshold)
+ {
+ }
+
+
+ virtual void GetInts(int a_MinX, int a_MinZ, Values & a_Values) override
+ {
+ for (int z = 0; z < SizeZ; z++)
+ {
+ int BaseZ = a_MinZ + z;
+ for (int x = 0; x < SizeX; x++)
+ {
+ int rnd = (m_Noise.IntNoise2DInt(a_MinX + x, BaseZ) / 7);
+ a_Values[x + SizeX * z] = ((rnd % 100) < m_Threshold) ? ((rnd / 128) % bgMax + 1) : 0;
+ }
+ }
+ }
+
+protected:
+ int m_Threshold;
+};
+
+
+
+
+
+template <int SizeX, int SizeZ = SizeX>
+class cIntGenZoom :
+ public cIntGenWithNoise<SizeX, SizeZ>
+{
+ typedef cIntGenWithNoise<SizeX, SizeZ> super;
+
+protected:
+ static const int m_LowerSizeX = (SizeX / 2) + 2;
+ static const int m_LowerSizeZ = (SizeZ / 2) + 2;
+
+public:
+ typedef cIntGenPtr<m_LowerSizeX, m_LowerSizeZ> Underlying;
+
+
+ cIntGenZoom(int a_Seed, Underlying a_UnderlyingGen) :
+ super(a_Seed),
+ m_UnderlyingGen(a_UnderlyingGen)
+ {
+ }
+
+
+ virtual void GetInts(int a_MinX, int a_MinZ, Values & a_Values) override
+ {
+ // Generate the underlying data with half the resolution:
+ int lowerMinX = a_MinX >> 1;
+ int lowerMinZ = a_MinZ >> 1;
+ int Underlying[m_LowerSizeX * m_LowerSizeZ];
+ m_UnderlyingGen->GetInts(lowerMinX, lowerMinZ, Underlying);
+ const int lowStepX = (m_LowerSizeX - 1) * 2;
+ const int lowStepZ = (m_LowerSizeZ - 1) * 2;
+ int Cache[lowStepX * lowStepZ];
+
+ // Discreet-interpolate the values into twice the size:
+ for (int z = 0; z < m_LowerSizeZ - 1; ++z)
+ {
+ int idx = (z * 2) * lowStepX;
+ int PrevZ0 = Underlying[z * m_LowerSizeX];
+ int PrevZ1 = Underlying[(z + 1) * m_LowerSizeX];
+
+ for (int x = 0; x < m_LowerSizeX - 1; ++x)
+ {
+ int ValX1Z0 = Underlying[x + 1 + z * m_LowerSizeX];
+ int ValX1Z1 = Underlying[x + 1 + (z + 1) * m_LowerSizeX];
+ int RndX = (x + lowerMinX) * 2;
+ int RndZ = (z + lowerMinZ) * 2;
+ Cache[idx] = PrevZ0;
+ Cache[idx + lowStepX] = ChooseRandomOne(RndX, RndZ, PrevZ0, PrevZ1);
+ idx++;
+ Cache[idx] = ChooseRandomOne(RndX, RndZ, PrevZ0, ValX1Z0);
+ Cache[idx + lowStepX] = ChooseRandomOne(RndX, RndZ, PrevZ0, ValX1Z0, PrevZ1, ValX1Z1);
+ idx++;
+ PrevZ0 = ValX1Z0;
+ PrevZ1 = ValX1Z1;
+ }
+ }
+
+ // Copy from Cache into a_Values; take into account the even/odd offsets in a_Min:
+ for (int z = 0; z < SizeZ; ++z)
+ {
+ memcpy(a_Values + z * SizeX, Cache + (z + (a_MinZ & 1)) * lowStepX + (a_MinX & 1), SizeX * sizeof(int));
+ }
+ }
+
+protected:
+ Underlying m_UnderlyingGen;
+};
+
+
+
+
+
+template <int SizeX, int SizeZ = SizeX>
+class cIntGenSmooth :
+ public cIntGenWithNoise<SizeX, SizeZ>
+{
+ typedef cIntGenWithNoise<SizeX, SizeZ> super;
+ static const int m_UnderlyingSizeX = SizeX + 2;
+ static const int m_UnderlyingSizeZ = SizeZ + 2;
+
+public:
+ typedef cIntGenPtr<m_UnderlyingSizeX, m_UnderlyingSizeZ> Underlying;
+
+
+ cIntGenSmooth(int a_Seed, Underlying a_Underlying) :
+ super(a_Seed),
+ m_Underlying(a_Underlying)
+ {
+ }
+
+
+ virtual void GetInts(int a_MinX, int a_MinZ, Values & a_Values) override
+ {
+ // Generate the underlying values:
+ int Cache[(SizeX + 2) * (SizeZ + 2)];
+ m_Underlying->GetInts(a_MinX - 1, a_MinZ - 1, Cache);
+
+ // Smooth - for each square check if the surroundings are the same, if so, expand them diagonally.
+ // Also get rid of single-pixel irregularities (A-B-A):
+ for (int z = 0; z < SizeZ; z++)
+ {
+ int NoiseZ = a_MinZ + z;
+ for (int x = 0; x < SizeX; x++)
+ {
+ int val = Cache[x + 1 + (z + 1) * m_UnderlyingSizeX];
+ int Above = Cache[x + 1 + z * m_UnderlyingSizeX];
+ int Below = Cache[x + 1 + (z + 2) * m_UnderlyingSizeX];
+ int Left = Cache[x + (z + 1) * m_UnderlyingSizeX];
+ int Right = Cache[x + 2 + (z + 1) * m_UnderlyingSizeX];
+
+ if ((Left == Right) && (Above == Below))
+ {
+ if (((m_Noise.IntNoise2DInt(a_MinX + x, NoiseZ) / 7) % 2) == 0)
+ {
+ val = Left;
+ }
+ else
+ {
+ val = Above;
+ }
+ }
+ else
+ {
+ if (Left == Right)
+ {
+ val = Left;
+ }
+
+ if (Above == Below)
+ {
+ val = Above;
+ }
+ }
+
+ a_Values[x + z * SizeX] = val;
+ }
+ }
+ }
+
+protected:
+ Underlying m_Underlying;
+};
+
+
+
+
+
+template<int SizeX, int SizeZ = SizeX>
+class cIntGenBeaches :
+ public cIntGen<SizeX, SizeZ>
+{
+ typedef cIntGen<SizeX, SizeZ> super;
+ static const int m_UnderlyingSizeX = SizeX + 2;
+ static const int m_UnderlyingSizeZ = SizeZ + 2;
+
+public:
+ typedef cIntGenPtr<m_UnderlyingSizeX, m_UnderlyingSizeZ> Underlying;
+
+
+ cIntGenBeaches(Underlying a_Underlying) :
+ m_Underlying(a_Underlying)
+ {
+ }
+
+
+ virtual void GetInts(int a_MinX, int a_MinZ, Values & a_Values) override
+ {
+ // Map for biome -> its beach:
+ static const int ToBeach[] =
+ {
+ /* biOcean */ biOcean,
+ /* biPlains */ biBeach,
+ /* biDesert */ biBeach,
+ /* biExtremeHills */ biStoneBeach,
+ /* biForest */ biBeach,
+ /* biTaiga */ biColdBeach,
+ /* biSwampland */ biSwampland,
+ /* biRiver */ biRiver,
+ /* biNether */ biNether,
+ /* biEnd */ biEnd,
+ /* biFrozenOcean */ biColdBeach,
+ /* biFrozenRiver */ biColdBeach,
+ /* biIcePlains */ biColdBeach,
+ /* biIceMountains */ biColdBeach,
+ /* biMushroomIsland */ biMushroomShore,
+ /* biMushroomShore */ biMushroomShore,
+ /* biBeach */ biBeach,
+ /* biDesertHills */ biBeach,
+ /* biForestHills */ biBeach,
+ /* biTaigaHills */ biColdBeach,
+ /* biExtremeHillsEdge */ biStoneBeach,
+ /* biJungle */ biBeach,
+ /* biJungleHills */ biBeach,
+ /* biJungleEdge */ biBeach,
+ /* biDeepOcean */ biOcean,
+ /* biStoneBeach */ biStoneBeach,
+ /* biColdBeach */ biColdBeach,
+ /* biBirchForest */ biBeach,
+ /* biBirchForestHills */ biBeach,
+ /* biRoofedForest */ biBeach,
+ /* biColdTaiga */ biColdBeach,
+ /* biColdTaigaHills */ biColdBeach,
+ /* biMegaTaiga */ biStoneBeach,
+ /* biMegaTaigaHills */ biStoneBeach,
+ /* biExtremeHillsPlus */ biStoneBeach,
+ /* biSavanna */ biBeach,
+ /* biSavannaPlateau */ biBeach,
+ /* biMesa */ biMesa,
+ /* biMesaPlateauF */ biMesa,
+ /* biMesaPlateau */ biMesa,
+ };
+
+ // Generate the underlying values:
+ int Cache[m_UnderlyingSizeX * m_UnderlyingSizeZ];
+ m_Underlying->GetInts(a_MinX - 1, a_MinZ - 1, Cache);
+
+ // Add beaches between ocean and biomes:
+ for (int z = 0; z < SizeZ; z++)
+ {
+ for (int x = 0; x < SizeX; x++)
+ {
+ int val = Cache[x + 1 + (z + 1) * m_UnderlyingSizeX];
+ int Above = Cache[x + 1 + z * m_UnderlyingSizeX];
+ int Below = Cache[x + 1 + (z + 2) * m_UnderlyingSizeX];
+ int Left = Cache[x + (z + 1) * m_UnderlyingSizeX];
+ int Right = Cache[x + 2 + (z + 1) * m_UnderlyingSizeX];
+ if (!IsBiomeOcean(val))
+ {
+ if (IsBiomeOcean(Above) || IsBiomeOcean(Below) || IsBiomeOcean(Left) || IsBiomeOcean(Right))
+ {
+ val = ToBeach[(val % 128) % ARRAYCOUNT(ToBeach)];
+ }
+ }
+ a_Values[x + z * SizeX] = val;
+ }
+ }
+ }
+
+protected:
+ Underlying m_Underlying;
+};
+
+
+
+
+
+/** Generates the underlying numbers and then randomly changes some zeroes into nonzeroes. */
+template <int SizeX, int SizeZ = SizeX>
+class cIntGenAddIslands :
+ public cIntGenWithNoise<SizeX, SizeZ>
+{
+ typedef cIntGenWithNoise<SizeX, SizeZ> super;
+
+public:
+ typedef cIntGenPtr<SizeX, SizeZ> Underlying;
+
+
+ cIntGenAddIslands(int a_Seed, int a_Threshold, Underlying a_Underlying) :
+ super(a_Seed),
+ m_Threshold(a_Threshold),
+ m_Underlying(a_Underlying)
+ {
+ }
+
+
+ virtual void GetInts(int a_MinX, int a_MinZ, Values & a_Values) override
+ {
+ m_Underlying->GetInts(a_MinX, a_MinZ, a_Values);
+ for (int z = 0; z < SizeZ; z++)
+ {
+ for (int x = 0; x < SizeX; x++)
+ {
+ if (a_Values[x + z * SizeX] == 0)
+ {
+ int rnd = m_Noise.IntNoise2DInt(a_MinX + x, a_MinZ + z) / 7;
+ if (rnd % 100 < m_Threshold)
+ {
+ a_Values[x + z * SizeX] = (rnd / 100) % 4;
+ }
+ }
+ }
+ }
+ }
+
+protected:
+ int m_Threshold;
+
+ Underlying m_Underlying;
+};
+
+
+
+
+
+/** A filter that adds an edge biome group between two biome groups that need an edge between them. */
+template <int SizeX, int SizeZ = SizeX>
+class cIntGenBiomeGroupEdges :
+ public cIntGen<SizeX, SizeZ>
+{
+ typedef cIntGen<SizeX, SizeZ> super;
+
+ static const int m_UnderlyingSizeX = SizeX + 2;
+ static const int m_UnderlyingSizeZ = SizeZ + 2;
+
+public:
+
+ typedef cIntGenPtr<m_UnderlyingSizeX, m_UnderlyingSizeZ> Underlying;
+
+ cIntGenBiomeGroupEdges(Underlying a_Underlying) :
+ m_Underlying(a_Underlying)
+ {
+ }
+
+
+ virtual void GetInts(int a_MinX, int a_MinZ, Values & a_Values)
+ {
+ // Generate the underlying biome groups:
+ int Cache[m_UnderlyingSizeX * m_UnderlyingSizeZ];
+ m_Underlying->GetInts(a_MinX, a_MinZ, Cache);
+
+ // Change the biomes on incompatible edges into an edge biome:
+ for (int z = 0; z < SizeZ; z++)
+ {
+ for (int x = 0; x < SizeX; x++)
+ {
+ int v = Cache[x + 1 + (z + 1) * m_UnderlyingSizeX];
+ int Above = Cache[x + 1 + z * m_UnderlyingSizeX];
+ int Below = Cache[x + 1 + (z + 2) * m_UnderlyingSizeX];
+ int Left = Cache[x + (z + 1) * m_UnderlyingSizeX];
+ int Right = Cache[x + 2 + (z + 1) * m_UnderlyingSizeX];
+ switch (v)
+ {
+ // Oceans don't need any edges:
+ case bgOcean:
+ {
+ v = bgOcean;
+ break;
+ }
+
+ // Desert should neighbor only oceans, desert and temperates; change to temperate when another:
+ case bgDesert:
+ {
+ if (
+ !IsDesertCompatible(Above) ||
+ !IsDesertCompatible(Below) ||
+ !IsDesertCompatible(Left) ||
+ !IsDesertCompatible(Right)
+ )
+ {
+ v = bgTemperate;
+ }
+ break;
+ }
+
+ // Ice should not neighbor deserts; change to temperate:
+ case bgIce:
+ {
+ if (
+ (Above == bgDesert) ||
+ (Below == bgDesert) ||
+ (Left == bgDesert) ||
+ (Right == bgDesert)
+ )
+ {
+ v = bgTemperate;
+ }
+ break;
+ }
+
+ // Jungle should not neighbor Desert or Ice; change to temperate:
+ case bgJungle:
+ {
+ if (
+ !IsJungleCompatible(Above) ||
+ !IsJungleCompatible(Below) ||
+ !IsJungleCompatible(Left) ||
+ !IsJungleCompatible(Right)
+ )
+ {
+ v = bgTemperate;
+ }
+ }
+ }
+ a_Values[x + z * SizeX] = v;
+ } // for x
+ } // for z
+ }
+
+protected:
+ Underlying m_Underlying;
+
+
+ inline bool IsDesertCompatible(int a_BiomeGroup)
+ {
+ return ((a_BiomeGroup == bgOcean) || (a_BiomeGroup == bgDesert) || (a_BiomeGroup == bgTemperate));
+ }
+
+ inline bool IsJungleCompatible(int a_BiomeGroup)
+ {
+ return ((a_BiomeGroup != bgDesert) && (a_BiomeGroup != bgIce));
+ }
+};
+
+
+
+
+
+template <int SizeX, int SizeZ = SizeX>
+class cIntGenBiomes :
+ public cIntGenWithNoise<SizeX, SizeZ>
+{
+ typedef cIntGenWithNoise<SizeX, SizeZ> super;
+
+public:
+ typedef cIntGenPtr<SizeX, SizeZ> Underlying;
+
+
+ cIntGenBiomes(int a_Seed, Underlying a_Underlying) :
+ super(a_Seed),
+ m_Underlying(a_Underlying)
+ {
+ }
+
+
+ virtual void GetInts(int a_MinX, int a_MinZ, Values & a_Values) override
+ {
+ // Define the per-biome-group biomes:
+ static const int OceanBiomes[] =
+ {
+ biOcean, // biDeepOcean,
+ };
+
+ static const int DesertBiomes[] =
+ {
+ biDesert, biDesert, biSavanna, biPlains,
+ };
+
+ static const int TemperateBiomes[] =
+ {
+ biForest, biRoofedForest, biExtremeHills, biPlains, biBirchForest, biSwampland,
+ };
+
+ static const int MountainBiomes[] =
+ {
+ biExtremeHills, biForest, biTaiga, biPlains,
+ };
+
+ static const int JungleBiomes[] =
+ {
+ biJungle, biJungle, biForest,
+ };
+
+ static const int IceBiomes[] =
+ {
+ biIcePlains, biIcePlains, biColdTaiga,
+ };
+
+ static const cBiomesInGroups BiomesInGroups[] =
+ {
+ { static_cast<int>(ARRAYCOUNT(OceanBiomes)), OceanBiomes},
+ { static_cast<int>(ARRAYCOUNT(DesertBiomes)), DesertBiomes},
+ { static_cast<int>(ARRAYCOUNT(TemperateBiomes)), TemperateBiomes},
+ { static_cast<int>(ARRAYCOUNT(MountainBiomes)), MountainBiomes},
+ { static_cast<int>(ARRAYCOUNT(JungleBiomes)), JungleBiomes},
+ { static_cast<int>(ARRAYCOUNT(IceBiomes)), IceBiomes},
+ };
+
+ // Generate the underlying values, representing biome groups:
+ m_Underlying->GetInts(a_MinX, a_MinZ, a_Values);
+
+ // Overwrite each biome group with a random biome from that group:
+ for (int z = 0; z < SizeZ; z++)
+ {
+ int IdxZ = z * SizeX;
+ for (int x = 0; x < SizeX; x++)
+ {
+ int val = a_Values[x + IdxZ];
+ const cBiomesInGroups & Biomes = BiomesInGroups[val % ARRAYCOUNT(BiomesInGroups)];
+ int rnd = (m_Noise.IntNoise2DInt(x + a_MinX, z + a_MinZ) / 7);
+ a_Values[x + IdxZ] = Biomes.Biomes[rnd % Biomes.Count];
+ }
+ }
+ }
+
+protected:
+
+ struct cBiomesInGroups
+ {
+ const int Count;
+ const int * Biomes;
+ };
+
+
+ /** The underlying int generator */
+ Underlying m_Underlying;
+};
+
+
+
+
+
+template <int SizeX, int SizeZ = SizeX>
+class cIntGenReplaceRandomly :
+ public cIntGenWithNoise<SizeX, SizeZ>
+{
+ typedef cIntGenWithNoise<SizeX, SizeZ> super;
+
+public:
+ typedef cIntGenPtr<SizeX, SizeZ> Underlying;
+
+
+ cIntGenReplaceRandomly(int a_From, int a_To, int a_Chance, int a_Seed, Underlying a_Underlying) :
+ super(a_Seed),
+ m_From(a_From),
+ m_To(a_To),
+ m_Chance(a_Chance),
+ m_Underlying(a_Underlying)
+ {
+ }
+
+
+ virtual void GetInts(int a_MinX, int a_MinZ, Values & a_Values) override
+ {
+ // Generate the underlying values:
+ m_Underlying->GetInts(a_MinX, a_MinZ, a_Values);
+
+ // Replace some of the values:
+ for (int z = 0; z < SizeZ; z++)
+ {
+ int idxZ = z * SizeX;
+ for (int x = 0; x < SizeX; x++)
+ {
+ int idx = x + idxZ;
+ if (a_Values[idx] == m_From)
+ {
+ int rnd = m_Noise.IntNoise2DInt(x + a_MinX, z + a_MinZ) / 7;
+ if (rnd % 100 < m_Chance)
+ {
+ a_Values[idx] = m_To;
+ }
+ }
+ }
+ } // for z
+ }
+
+
+protected:
+ int m_From;
+ int m_To;
+ int m_Chance;
+ Underlying m_Underlying;
+};
+
+
+
+
+
+/** Mixer that joins together finalized biomes and rivers.
+It first checks for oceans; if there's no ocean, it checks for a river. */
+template <int SizeX, int SizeZ = SizeX>
+class cIntGenMixRivers:
+ public cIntGen<SizeX, SizeZ>
+{
+ typedef cIntGen<SizeX, SizeZ> super;
+
+public:
+ typedef cIntGenPtr<SizeX, SizeZ> Underlying;
+
+
+ cIntGenMixRivers(Underlying a_Biomes, Underlying a_Rivers):
+ m_Biomes(a_Biomes),
+ m_Rivers(a_Rivers)
+ {
+ }
+
+
+ virtual void GetInts(int a_MinX, int a_MinZ, Values & a_Values) override
+ {
+ // Generate the underlying data:
+ m_Biomes->GetInts(a_MinX, a_MinZ, a_Values);
+ Values Rivers;
+ m_Rivers->GetInts(a_MinX, a_MinZ, Rivers);
+
+ // Mix the values:
+ for (int z = 0; z < SizeZ; z++)
+ {
+ int idxZ = z * SizeX;
+ for (int x = 0; x < SizeX; x++)
+ {
+ int idx = x + idxZ;
+ if (IsBiomeOcean(a_Values[idx]))
+ {
+ // Oceans are kept without any changes
+ continue;
+ }
+ if (Rivers[idx] != biRiver)
+ {
+ // There's no river, keep the current value
+ continue;
+ }
+
+ // There's a river, change the output to a river or a frozen river, based on the original biome:
+ if (IsBiomeVeryCold((EMCSBiome)a_Values[idx]))
+ {
+ a_Values[idx] = biFrozenRiver;
+ }
+ else
+ {
+ a_Values[idx] = biRiver;
+ }
+ } // for x
+ } // for z
+ }
+
+protected:
+ Underlying m_Biomes;
+ Underlying m_Rivers;
+};
+
+
+
+
+
+/** Generates a river based on the underlying data.
+This is basically an edge detector over the underlying data. The rivers are the edges where the underlying data
+changes from one pixel to its neighbor. */
+template <int SizeX, int SizeZ = SizeX>
+class cIntGenRiver:
+ public cIntGenWithNoise<SizeX, SizeZ>
+{
+ typedef cIntGenWithNoise<SizeX, SizeZ> super;
+ static const int UnderlyingSizeX = SizeX + 2;
+ static const int UnderlyingSizeZ = SizeZ + 2;
+
+public:
+ typedef cIntGenPtr<UnderlyingSizeX, UnderlyingSizeZ> Underlying;
+
+
+ cIntGenRiver(int a_Seed, Underlying a_Underlying):
+ super(a_Seed),
+ m_Underlying(a_Underlying)
+ {
+ }
+
+
+ virtual void GetInts(int a_MinX, int a_MinZ, Values & a_Values) override
+ {
+ // Generate the underlying data:
+ int Cache[UnderlyingSizeX * UnderlyingSizeZ];
+ m_Underlying->GetInts(a_MinX - 1, a_MinZ - 1, Cache);
+
+ // Detect the edges:
+ for (int z = 0; z < SizeZ; z++)
+ {
+ for (int x = 0; x < SizeX; x++)
+ {
+ int Above = Cache[x + 1 + z * UnderlyingSizeX];
+ int Below = Cache[x + 1 + (z + 2) * UnderlyingSizeX];
+ int Left = Cache[x + (z + 1) * UnderlyingSizeX];
+ int Right = Cache[x + 2 + (z + 1) * UnderlyingSizeX];
+ int val = Cache[x + 1 + (z + 1) * UnderlyingSizeX];
+
+ if ((val == Above) && (val == Below) && (val == Left) && (val == Right))
+ {
+ val = 0;
+ }
+ else
+ {
+ val = biRiver;
+ }
+ a_Values[x + z * SizeX] = val;
+ } // for x
+ } // for z
+ }
+
+protected:
+ Underlying m_Underlying;
+};
+
+
+
+
+
+/** Turns some of the oceans into the specified biome. Used for mushroom and deep ocean.
+The biome is only placed if at least 3 of its neighbors are ocean and only with the specified chance. */
+template <int SizeX, int SizeZ = SizeX>
+class cIntGenAddToOcean:
+ public cIntGenWithNoise<SizeX, SizeZ>
+{
+ typedef cIntGenWithNoise<SizeX, SizeZ> super;
+ static const int UnderlyingSizeX = SizeX + 2;
+ static const int UnderlyingSizeZ = SizeZ + 2;
+
+public:
+ typedef cIntGenPtr<UnderlyingSizeX, UnderlyingSizeZ> Underlying;
+
+
+ cIntGenAddToOcean(int a_Seed, int a_Chance, int a_ToValue, Underlying a_Underlying):
+ super(a_Seed),
+ m_Chance(a_Chance),
+ m_ToValue(a_ToValue),
+ m_Underlying(a_Underlying)
+ {
+ }
+
+
+ virtual void GetInts(int a_MinX, int a_MinZ, Values & a_Values) override
+ {
+ // Generate the underlying data:
+ int Cache[UnderlyingSizeX * UnderlyingSizeZ];
+ m_Underlying->GetInts(a_MinX - 1, a_MinZ - 1, Cache);
+
+ // Add the mushroom islands:
+ for (int z = 0; z < SizeZ; z++)
+ {
+ for (int x = 0; x < SizeX; x++)
+ {
+ int val = Cache[x + 1 + (z + 1) * UnderlyingSizeX];
+ if (!IsBiomeOcean(val))
+ {
+ a_Values[x + z * SizeX] = val;
+ continue;
+ }
+
+ // Count the ocean neighbors:
+ int Above = Cache[x + 1 + z * UnderlyingSizeX];
+ int Below = Cache[x + 1 + (z + 2) * UnderlyingSizeX];
+ int Left = Cache[x + (z + 1) * UnderlyingSizeX];
+ int Right = Cache[x + 2 + (z + 1) * UnderlyingSizeX];
+ int NumOceanNeighbors = 0;
+ if (IsBiomeOcean(Above))
+ {
+ NumOceanNeighbors += 1;
+ }
+ if (IsBiomeOcean(Above))
+ {
+ NumOceanNeighbors += 1;
+ }
+ if (IsBiomeOcean(Above))
+ {
+ NumOceanNeighbors += 1;
+ }
+ if (IsBiomeOcean(Above))
+ {
+ NumOceanNeighbors += 1;
+ }
+
+ // If at least 3 ocean neighbors and the chance is right, change:
+ if ((NumOceanNeighbors >= 3) && ((m_Noise.IntNoise2DInt(x + a_MinX, z + a_MinZ) / 7) % 1000 < m_Chance))
+ {
+ a_Values[x + z * SizeX] = m_ToValue;
+ }
+ else
+ {
+ a_Values[x + z * SizeX] = val;
+ }
+ } // for x
+ } // for z
+ }
+
+protected:
+ /** Chance, in permille, of changing the biome. */
+ int m_Chance;
+
+ /** The value to change the ocean into. */
+ int m_ToValue;
+
+ Underlying m_Underlying;
+};
+
+
+
+