summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Generating/ComposableGenerator.cpp4
-rw-r--r--src/Generating/HeiGen.cpp4
-rw-r--r--src/Generating/Noise3DGenerator.cpp304
-rw-r--r--src/Generating/Noise3DGenerator.h86
4 files changed, 369 insertions, 29 deletions
diff --git a/src/Generating/ComposableGenerator.cpp b/src/Generating/ComposableGenerator.cpp
index 169821050..5f46574c7 100644
--- a/src/Generating/ComposableGenerator.cpp
+++ b/src/Generating/ComposableGenerator.cpp
@@ -73,6 +73,10 @@ cTerrainCompositionGenPtr cTerrainCompositionGen::CreateCompositionGen(cIniFile
{
res = new cCompoGenNether(a_Seed);
}
+ else if (NoCaseCompare(CompoGenName, "BiomalNoise3D") == 0)
+ {
+ res = new cBiomalNoise3DComposable(a_Seed, a_BiomeGen);
+ }
else if (NoCaseCompare(CompoGenName, "Noise3D") == 0)
{
res = new cNoise3DComposable(a_Seed);
diff --git a/src/Generating/HeiGen.cpp b/src/Generating/HeiGen.cpp
index 28a5698e4..1d9f1e3aa 100644
--- a/src/Generating/HeiGen.cpp
+++ b/src/Generating/HeiGen.cpp
@@ -776,6 +776,10 @@ cTerrainHeightGenPtr cTerrainHeightGen::CreateHeightGen(cIniFile & a_IniFile, cB
{
res = new cHeiGenMountains(a_Seed);
}
+ else if (NoCaseCompare(HeightGenName, "BiomalNoise3D") == 0)
+ {
+ res = new cBiomalNoise3DComposable(a_Seed, a_BiomeGen);
+ }
else if (NoCaseCompare(HeightGenName, "Noise3D") == 0)
{
res = new cNoise3DComposable(a_Seed);
diff --git a/src/Generating/Noise3DGenerator.cpp b/src/Generating/Noise3DGenerator.cpp
index 885a9bab3..3f50ea0e9 100644
--- a/src/Generating/Noise3DGenerator.cpp
+++ b/src/Generating/Noise3DGenerator.cpp
@@ -444,7 +444,7 @@ void cNoise3DComposable::GenerateNoiseArrayIfNeeded(int a_ChunkX, int a_ChunkZ)
{
if ((a_ChunkX == m_LastChunkX) && (a_ChunkZ == m_LastChunkZ))
{
- // The noise for this chunk is already generated in m_Noise
+ // The noise for this chunk is already generated in m_NoiseArray
return;
}
m_LastChunkX = a_ChunkX;
@@ -485,52 +485,298 @@ void cNoise3DComposable::GenerateNoiseArrayIfNeeded(int a_ChunkX, int a_ChunkZ)
}
}
LinearUpscale3DArray<NOISE_DATATYPE>(Workspace, 5, 5, 33, m_NoiseArray, 4, 4, 8);
+}
- #if 0
- // DEBUG: Output two images of m_NoiseArray, sliced by XY and XZ, into grayscale files, to be inspected by Grabber:
- cFile f1;
- if (f1.Open(Printf("Chunk_%d_%d_XY.raw", a_ChunkX, a_ChunkZ), cFile::fmWrite))
+
+
+
+
+void cNoise3DComposable::GenHeightMap(int a_ChunkX, int a_ChunkZ, cChunkDef::HeightMap & a_HeightMap)
+{
+ GenerateNoiseArrayIfNeeded(a_ChunkX, a_ChunkZ);
+
+ for (int z = 0; z < cChunkDef::Width; z++)
{
- for (int z = 0; z < cChunkDef::Width; z++)
+ for (int x = 0; x < cChunkDef::Width; x++)
{
- for (int y = 0; y < cChunkDef::Height; y++)
+ cChunkDef::SetHeight(a_HeightMap, x, z, m_SeaLevel);
+ for (int y = cChunkDef::Height - 1; y > m_SeaLevel; y--)
{
- int idx = y * 17 * 17 + z * 17;
- unsigned char buf[16];
- for (int x = 0; x < cChunkDef::Width; x++)
+ if (m_NoiseArray[y * 17 * 17 + z * 17 + x] <= m_AirThreshold)
{
- buf[x] = (unsigned char)(std::min(256, std::max(0, (int)(128 + 32 * m_NoiseArray[idx++]))));
+ cChunkDef::SetHeight(a_HeightMap, x, z, y);
+ break;
}
- f1.Write(buf, 16);
} // for y
- } // for z
- } // if (XY file open)
+ } // for x
+ } // for z
+}
- cFile f2;
- if (f2.Open(Printf("Chunk_%d_%d_XZ.raw", a_ChunkX, a_ChunkZ), cFile::fmWrite))
+
+
+
+
+void cNoise3DComposable::ComposeTerrain(cChunkDesc & a_ChunkDesc)
+{
+ GenerateNoiseArrayIfNeeded(a_ChunkDesc.GetChunkX(), a_ChunkDesc.GetChunkZ());
+
+ a_ChunkDesc.FillBlocks(E_BLOCK_AIR, 0);
+
+ // Make basic terrain composition:
+ for (int z = 0; z < cChunkDef::Width; z++)
{
- for (int y = 0; y < cChunkDef::Height; y++)
+ for (int x = 0; x < cChunkDef::Width; x++)
{
- for (int z = 0; z < cChunkDef::Width; z++)
+ int LastAir = a_ChunkDesc.GetHeight(x, z) + 1;
+ bool HasHadWater = false;
+ for (int y = LastAir; y < m_SeaLevel; y++)
{
- int idx = y * 17 * 17 + z * 17;
- unsigned char buf[16];
- for (int x = 0; x < cChunkDef::Width; x++)
+ a_ChunkDesc.SetBlockType(x, y, z, E_BLOCK_STATIONARY_WATER);
+ }
+ for (int y = LastAir - 1; y > 0; y--)
+ {
+ if (m_NoiseArray[x + 17 * z + 17 * 17 * y] > m_AirThreshold)
{
- buf[x] = (unsigned char)(std::min(256, std::max(0, (int)(128 + 32 * m_NoiseArray[idx++]))));
+ // "air" part
+ LastAir = y;
+ if (y < m_SeaLevel)
+ {
+ a_ChunkDesc.SetBlockType(x, y, z, E_BLOCK_STATIONARY_WATER);
+ HasHadWater = true;
+ }
+ continue;
}
- f2.Write(buf, 16);
- } // for z
- } // for y
- } // if (XZ file open)
- #endif
+ // "ground" part:
+ if (LastAir - y > 4)
+ {
+ a_ChunkDesc.SetBlockType(x, y, z, E_BLOCK_STONE);
+ continue;
+ }
+ if (HasHadWater)
+ {
+ a_ChunkDesc.SetBlockType(x, y, z, E_BLOCK_SAND);
+ }
+ else
+ {
+ a_ChunkDesc.SetBlockType(x, y, z, (LastAir == y + 1) ? E_BLOCK_GRASS : E_BLOCK_DIRT);
+ }
+ } // for y
+ a_ChunkDesc.SetBlockType(x, 0, z, E_BLOCK_BEDROCK);
+ } // for x
+ } // for z
}
-void cNoise3DComposable::GenHeightMap(int a_ChunkX, int a_ChunkZ, cChunkDef::HeightMap & a_HeightMap)
+////////////////////////////////////////////////////////////////////////////////
+// cBiomalNoise3DComposable:
+
+cBiomalNoise3DComposable::cBiomalNoise3DComposable(int a_Seed, cBiomeGenPtr a_BiomeGen) :
+ m_ChoiceNoise(a_Seed),
+ m_DensityNoiseA(a_Seed + 1),
+ m_DensityNoiseB(a_Seed + 2),
+ m_BaseNoise(a_Seed + 3),
+ m_BiomeGen(a_BiomeGen)
+{
+ // Generate the weight distribution for summing up neighboring biomes:
+ m_WeightSum = 0;
+ for (int z = 0; z <= AVERAGING_SIZE * 2; z++)
+ {
+ for (int x = 0; x <= AVERAGING_SIZE * 2; x++)
+ {
+ m_Weight[z][x] = static_cast<NOISE_DATATYPE>((5 - std::abs(5 - x)) + (5 - std::abs(5 - z)));
+ m_WeightSum += m_Weight[z][x];
+ }
+ }
+}
+
+
+
+
+
+void cBiomalNoise3DComposable::Initialize(cIniFile & a_IniFile)
+{
+ // Params:
+ // The defaults generate extreme hills terrain
+ m_SeaLevel = a_IniFile.GetValueSetI("Generator", "BiomalNoise3DSeaLevel", 62);
+ m_FrequencyX = (NOISE_DATATYPE)a_IniFile.GetValueSetF("Generator", "BiomalNoise3DFrequencyX", 40);
+ m_FrequencyY = (NOISE_DATATYPE)a_IniFile.GetValueSetF("Generator", "BiomalNoise3DFrequencyY", 40);
+ m_FrequencyZ = (NOISE_DATATYPE)a_IniFile.GetValueSetF("Generator", "BiomalNoise3DFrequencyZ", 40);
+ m_BaseFrequencyX = (NOISE_DATATYPE)a_IniFile.GetValueSetF("Generator", "BiomalNoise3DBaseFrequencyX", 40);
+ m_BaseFrequencyZ = (NOISE_DATATYPE)a_IniFile.GetValueSetF("Generator", "BiomalNoise3DBaseFrequencyZ", 40);
+ m_ChoiceFrequencyX = (NOISE_DATATYPE)a_IniFile.GetValueSetF("Generator", "BiomalNoise3DChoiceFrequencyX", 40);
+ m_ChoiceFrequencyY = (NOISE_DATATYPE)a_IniFile.GetValueSetF("Generator", "BiomalNoise3DChoiceFrequencyY", 80);
+ m_ChoiceFrequencyZ = (NOISE_DATATYPE)a_IniFile.GetValueSetF("Generator", "BiomalNoise3DChoiceFrequencyZ", 40);
+ m_AirThreshold = (NOISE_DATATYPE)a_IniFile.GetValueSetF("Generator", "BiomalNoise3DAirThreshold", 0);
+ int NumChoiceOctaves = a_IniFile.GetValueSetI("Generator", "BiomalNoise3DNumChoiceOctaves", 4);
+ int NumDensityOctaves = a_IniFile.GetValueSetI("Generator", "BiomalNoise3DNumDensityOctaves", 6);
+ int NumBaseOctaves = a_IniFile.GetValueSetI("Generator", "BiomalNoise3DNumBaseOctaves", 6);
+ NOISE_DATATYPE BaseNoiseAmplitude = (NOISE_DATATYPE)a_IniFile.GetValueSetF("Generator", "BiomalNoise3DBaseAmplitude", 1);
+
+ // Add octaves for the choice noise:
+ NOISE_DATATYPE wavlen = 1, ampl = 0.5;
+ for (int i = 0; i < NumChoiceOctaves; i++)
+ {
+ m_ChoiceNoise.AddOctave(wavlen, ampl);
+ wavlen = wavlen * 2;
+ ampl = ampl / 2;
+ }
+
+ // Add octaves for the density noises:
+ wavlen = 1, ampl = 1;
+ for (int i = 0; i < NumDensityOctaves; i++)
+ {
+ m_DensityNoiseA.AddOctave(wavlen, ampl);
+ m_DensityNoiseB.AddOctave(wavlen, ampl);
+ wavlen = wavlen * 2;
+ ampl = ampl / 2;
+ }
+
+ // Add octaves for the base noise:
+ wavlen = 1, ampl = BaseNoiseAmplitude;
+ for (int i = 0; i < NumBaseOctaves; i++)
+ {
+ m_BaseNoise.AddOctave(wavlen, ampl);
+ wavlen = wavlen * 2;
+ ampl = ampl / 2;
+ }
+}
+
+
+
+
+
+void cBiomalNoise3DComposable::GenerateNoiseArrayIfNeeded(int a_ChunkX, int a_ChunkZ)
+{
+ if ((a_ChunkX == m_LastChunkX) && (a_ChunkZ == m_LastChunkZ))
+ {
+ // The noise for this chunk is already generated in m_NoiseArray
+ return;
+ }
+ m_LastChunkX = a_ChunkX;
+ m_LastChunkZ = a_ChunkZ;
+
+ // Calculate the parameters for the biomes:
+ ChunkParam MidPoint;
+ ChunkParam HeightAmp;
+ CalcBiomeParamArrays(a_ChunkX, a_ChunkZ, HeightAmp, MidPoint);
+
+ // Generate all the noises:
+ NOISE_DATATYPE ChoiceNoise[5 * 5 * 33];
+ NOISE_DATATYPE Workspace[5 * 5 * 33];
+ NOISE_DATATYPE DensityNoiseA[5 * 5 * 33];
+ NOISE_DATATYPE DensityNoiseB[5 * 5 * 33];
+ NOISE_DATATYPE BaseNoise[5 * 5];
+ NOISE_DATATYPE BlockX = static_cast<NOISE_DATATYPE>(a_ChunkX * cChunkDef::Width);
+ NOISE_DATATYPE BlockZ = static_cast<NOISE_DATATYPE>(a_ChunkZ * cChunkDef::Width);
+ // Note that we have to swap the coords, because noise generator uses [x + SizeX * y + SizeX * SizeY * z] ordering and we want "BlockY" to be "z":
+ m_ChoiceNoise.Generate3D (ChoiceNoise, 5, 5, 33, BlockX / m_ChoiceFrequencyX, (BlockX + 17) / m_ChoiceFrequencyX, BlockZ / m_ChoiceFrequencyZ, (BlockZ + 17) / m_ChoiceFrequencyZ, 0, 257 / m_ChoiceFrequencyY, Workspace);
+ m_DensityNoiseA.Generate3D(DensityNoiseA, 5, 5, 33, BlockX / m_FrequencyX, (BlockX + 17) / m_FrequencyX, BlockZ / m_FrequencyZ, (BlockZ + 17) / m_FrequencyZ, 0, 257 / m_FrequencyY, Workspace);
+ m_DensityNoiseB.Generate3D(DensityNoiseB, 5, 5, 33, BlockX / m_FrequencyX, (BlockX + 17) / m_FrequencyX, BlockZ / m_FrequencyZ, (BlockZ + 17) / m_FrequencyZ, 0, 257 / m_FrequencyY, Workspace);
+ m_BaseNoise.Generate2D (BaseNoise, 5, 5, BlockX / m_BaseFrequencyX, (BlockX + 17) / m_BaseFrequencyX, BlockZ / m_FrequencyZ, (BlockZ + 17) / m_FrequencyZ, Workspace);
+
+ // Calculate the final noise based on the partial noises:
+ for (int y = 0; y < 33; y++)
+ {
+ NOISE_DATATYPE BlockHeight = static_cast<NOISE_DATATYPE>(y * 8);
+ for (int z = 0; z < 5; z++)
+ {
+ for (int x = 0; x < 5; x++)
+ {
+ NOISE_DATATYPE AddHeight = (BlockHeight - MidPoint[x + 5 * z]) * HeightAmp[x + 5 * z];
+
+ // If "underground", make the terrain smoother by forcing the vertical linear gradient into steeper slope:
+ if (AddHeight < 0)
+ {
+ AddHeight *= 4;
+ }
+
+ int idx = x + 5 * z + 5 * 5 * y;
+ Workspace[idx] = ClampedLerp(DensityNoiseA[idx], DensityNoiseB[idx], 8 * (ChoiceNoise[idx] + 0.5f)) + AddHeight + BaseNoise[x + 5 * z];
+ }
+ }
+ }
+ LinearUpscale3DArray<NOISE_DATATYPE>(Workspace, 5, 5, 33, m_NoiseArray, 4, 4, 8);
+}
+
+
+
+
+
+void cBiomalNoise3DComposable::CalcBiomeParamArrays(int a_ChunkX, int a_ChunkZ, ChunkParam & a_HeightAmp, ChunkParam & a_MidPoint)
+{
+ // Generate the 3*3 chunks of biomes around this chunk:
+ cChunkDef::BiomeMap neighborBiomes[3 * 3];
+ for (int z = 0; z < 3; z++)
+ {
+ for (int x = 0; x < 3; x++)
+ {
+ m_BiomeGen->GenBiomes(a_ChunkX + x - 1, a_ChunkZ + z - 1, neighborBiomes[x + 3 * z]);
+ }
+ }
+
+ // Sum up the biome values:
+ for (int z = 0; z < 5; z++)
+ {
+ for (int x = 0; x < 5; x++)
+ {
+ NOISE_DATATYPE totalHeightAmp = 0;
+ NOISE_DATATYPE totalMidPoint = 0;
+ // Add up the biomes around this point:
+ for (int relz = 0; relz <= AVERAGING_SIZE * 2; ++relz)
+ {
+ int colz = 16 + z * 4 + relz - AVERAGING_SIZE; // Biome Z coord relative to the neighborBiomes start
+ int neicellz = colz / 16; // Chunk Z coord relative to the neighborBiomes start
+ int neirelz = colz % 16; // Biome Z coord relative to cz in neighborBiomes
+ for (int relx = 0; relx <= AVERAGING_SIZE * 2; ++relx)
+ {
+ int colx = 16 + x * 4 + relx - AVERAGING_SIZE; // Biome X coord relative to the neighborBiomes start
+ int neicellx = colx / 16; // Chunk X coord relative to the neighborBiomes start
+ int neirelx = colx % 16; // Biome X coord relative to cz in neighborBiomes
+ EMCSBiome biome = cChunkDef::GetBiome(neighborBiomes[neicellx + neicellz * 3], neirelx, neirelz);
+ NOISE_DATATYPE heightAmp, midPoint;
+ GetBiomeParams(biome, heightAmp, midPoint);
+ totalHeightAmp += heightAmp * m_Weight[relz][relx];
+ totalMidPoint += midPoint * m_Weight[relz][relx];
+ } // for relx
+ } // for relz
+ a_HeightAmp[x + 5 * z] = totalHeightAmp / m_WeightSum;
+ a_MidPoint[x + 5 * z] = totalMidPoint / m_WeightSum;
+ } // for x
+ } // for z
+}
+
+
+
+
+
+void cBiomalNoise3DComposable::GetBiomeParams(EMCSBiome a_Biome, NOISE_DATATYPE & a_HeightAmp, NOISE_DATATYPE & a_MidPoint)
+{
+ switch (a_Biome)
+ {
+ case biDesert: a_HeightAmp = 0.29f; a_MidPoint = 62; break; // Needs verification
+ case biExtremeHills: a_HeightAmp = 0.045f; a_MidPoint = 75; break;
+ case biPlains: a_HeightAmp = 0.3f; a_MidPoint = 62; break; // Needs verification
+ case biSwampland: a_HeightAmp = 0.25f; a_MidPoint = 59; break;
+ case biSwamplandM: a_HeightAmp = 0.11f; a_MidPoint = 59; break;
+
+ default:
+ {
+ // Make a crazy terrain so that it stands out
+ a_HeightAmp = 0.001f;
+ a_MidPoint = 90;
+ break;
+ }
+ }
+}
+
+
+
+
+
+void cBiomalNoise3DComposable::GenHeightMap(int a_ChunkX, int a_ChunkZ, cChunkDef::HeightMap & a_HeightMap)
{
GenerateNoiseArrayIfNeeded(a_ChunkX, a_ChunkZ);
@@ -555,7 +801,7 @@ void cNoise3DComposable::GenHeightMap(int a_ChunkX, int a_ChunkZ, cChunkDef::Hei
-void cNoise3DComposable::ComposeTerrain(cChunkDesc & a_ChunkDesc)
+void cBiomalNoise3DComposable::ComposeTerrain(cChunkDesc & a_ChunkDesc)
{
GenerateNoiseArrayIfNeeded(a_ChunkDesc.GetChunkX(), a_ChunkDesc.GetChunkZ());
diff --git a/src/Generating/Noise3DGenerator.h b/src/Generating/Noise3DGenerator.h
index 207aeab97..ba541fbcc 100644
--- a/src/Generating/Noise3DGenerator.h
+++ b/src/Generating/Noise3DGenerator.h
@@ -138,3 +138,89 @@ protected:
+
+class cBiomalNoise3DComposable :
+ public cTerrainHeightGen,
+ public cTerrainCompositionGen
+{
+public:
+ cBiomalNoise3DComposable(int a_Seed, cBiomeGenPtr a_BiomeGen);
+
+ void Initialize(cIniFile & a_IniFile);
+
+protected:
+ /** Number of columns around the pixel to query for biomes for averaging. */
+ static const int AVERAGING_SIZE = 5;
+
+ /** Type used for a single parameter across the entire (downscaled) chunk. */
+ typedef NOISE_DATATYPE ChunkParam[5 * 5];
+
+
+ /** The noise that is used to choose between density noise A and B. */
+ cPerlinNoise m_ChoiceNoise;
+
+ /** Density 3D noise, variant A. */
+ cPerlinNoise m_DensityNoiseA;
+
+ /** Density 3D noise, variant B. */
+ cPerlinNoise m_DensityNoiseB;
+
+ /** Heightmap-like noise used to provide variance for low-amplitude biomes. */
+ cPerlinNoise m_BaseNoise;
+
+ /** The underlying biome generator. */
+ cBiomeGenPtr m_BiomeGen;
+
+ /** Block height of the sealevel, used for composing the terrain. */
+ int m_SeaLevel;
+
+ // Frequency of the 3D noise's first octave:
+ NOISE_DATATYPE m_FrequencyX;
+ NOISE_DATATYPE m_FrequencyY;
+ NOISE_DATATYPE m_FrequencyZ;
+
+ // Frequency of the base terrain noise:
+ NOISE_DATATYPE m_BaseFrequencyX;
+ NOISE_DATATYPE m_BaseFrequencyZ;
+
+ // Frequency of the choice noise:
+ NOISE_DATATYPE m_ChoiceFrequencyX;
+ NOISE_DATATYPE m_ChoiceFrequencyY;
+ NOISE_DATATYPE m_ChoiceFrequencyZ;
+
+ // Threshold for when the values are considered air:
+ NOISE_DATATYPE m_AirThreshold;
+
+ // Cache for the last calculated chunk (reused between heightmap and composition queries):
+ int m_LastChunkX;
+ int m_LastChunkZ;
+ NOISE_DATATYPE m_NoiseArray[17 * 17 * 257]; // x + 17 * z + 17 * 17 * y
+
+ /** Weights for summing up neighboring biomes. */
+ NOISE_DATATYPE m_Weight[AVERAGING_SIZE * 2 + 1][AVERAGING_SIZE * 2 + 1];
+
+ /** The sum of m_Weight[]. */
+ NOISE_DATATYPE m_WeightSum;
+
+
+ /** Generates the 3D noise array used for terrain generation (m_NoiseArray), unless the LastChunk coords are equal to coords given */
+ void GenerateNoiseArrayIfNeeded(int a_ChunkX, int a_ChunkZ);
+
+ /** Calculates the biome-related parameters for the chunk. */
+ void CalcBiomeParamArrays(int a_ChunkX, int a_ChunkZ, ChunkParam & a_HeightAmp, ChunkParam & a_MidPoint);
+
+ /** Returns the parameters for the specified biome. */
+ void GetBiomeParams(EMCSBiome a_Biome, NOISE_DATATYPE & a_HeightAmp, NOISE_DATATYPE & a_MidPoint);
+
+ // cTerrainHeightGen overrides:
+ virtual void GenHeightMap(int a_ChunkX, int a_ChunkZ, cChunkDef::HeightMap & a_HeightMap) override;
+ virtual void InitializeHeightGen(cIniFile & a_IniFile) override { Initialize(a_IniFile); }
+
+ // cTerrainCompositionGen overrides:
+ virtual void ComposeTerrain(cChunkDesc & a_ChunkDesc) override;
+ virtual void InitializeCompoGen(cIniFile & a_IniFile) override { Initialize(a_IniFile); }
+} ;
+
+
+
+