2013-07-29 07:13:03 -04:00
|
|
|
|
|
|
|
// EndGen.cpp
|
|
|
|
|
|
|
|
// Implements the cEndGen class representing the generator for the End, both as a HeightGen and CompositionGen
|
|
|
|
|
|
|
|
#include "Globals.h"
|
|
|
|
#include "EndGen.h"
|
2014-10-23 09:15:10 -04:00
|
|
|
#include "../IniFile.h"
|
2013-07-29 07:13:03 -04:00
|
|
|
#include "../LinearUpscale.h"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
enum
|
|
|
|
{
|
|
|
|
// Interpolation cell size:
|
|
|
|
INTERPOL_X = 4,
|
|
|
|
INTERPOL_Y = 4,
|
|
|
|
INTERPOL_Z = 4,
|
2013-11-16 13:57:03 -05:00
|
|
|
|
2013-07-29 07:13:03 -04:00
|
|
|
// Size of chunk data, downscaled before interpolation:
|
|
|
|
DIM_X = 16 / INTERPOL_X + 1,
|
|
|
|
DIM_Y = 256 / INTERPOL_Y + 1,
|
|
|
|
DIM_Z = 16 / INTERPOL_Z + 1,
|
|
|
|
} ;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2014-07-17 16:15:34 -04:00
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
2013-07-29 07:13:03 -04:00
|
|
|
// cEndGen:
|
|
|
|
|
|
|
|
cEndGen::cEndGen(int a_Seed) :
|
|
|
|
m_Seed(a_Seed),
|
|
|
|
m_IslandSizeX(256),
|
|
|
|
m_IslandSizeY(96),
|
|
|
|
m_IslandSizeZ(256),
|
|
|
|
m_FrequencyX(80),
|
|
|
|
m_FrequencyY(80),
|
2014-12-21 15:59:44 -05:00
|
|
|
m_FrequencyZ(80),
|
2015-01-23 10:38:23 -05:00
|
|
|
m_MinChunkX(0),
|
|
|
|
m_MaxChunkX(0),
|
|
|
|
m_MinChunkZ(0),
|
|
|
|
m_MaxChunkZ(0),
|
2019-09-08 09:40:12 -04:00
|
|
|
m_LastChunkCoords(0x7fffffff, 0x7fffffff) // Use dummy coords that won't ever be used by real chunks
|
2013-07-29 07:13:03 -04:00
|
|
|
{
|
|
|
|
m_Perlin.AddOctave(1, 1);
|
|
|
|
m_Perlin.AddOctave(2, 0.5);
|
|
|
|
m_Perlin.AddOctave(4, 0.25);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2014-05-31 17:28:51 -04:00
|
|
|
void cEndGen::InitializeCompoGen(cIniFile & a_IniFile)
|
2013-07-29 07:13:03 -04:00
|
|
|
{
|
|
|
|
m_IslandSizeX = a_IniFile.GetValueSetI("Generator", "EndGenIslandSizeX", m_IslandSizeX);
|
|
|
|
m_IslandSizeY = a_IniFile.GetValueSetI("Generator", "EndGenIslandSizeY", m_IslandSizeY);
|
|
|
|
m_IslandSizeZ = a_IniFile.GetValueSetI("Generator", "EndGenIslandSizeZ", m_IslandSizeZ);
|
|
|
|
|
2015-08-04 18:24:59 -04:00
|
|
|
m_FrequencyX = static_cast<NOISE_DATATYPE>(a_IniFile.GetValueSetF("Generator", "EndGenFrequencyX", m_FrequencyX));
|
|
|
|
m_FrequencyY = static_cast<NOISE_DATATYPE>(a_IniFile.GetValueSetF("Generator", "EndGenFrequencyY", m_FrequencyY));
|
|
|
|
m_FrequencyZ = static_cast<NOISE_DATATYPE>(a_IniFile.GetValueSetF("Generator", "EndGenFrequencyZ", m_FrequencyZ));
|
2013-11-16 13:57:03 -05:00
|
|
|
|
2013-07-29 07:13:03 -04:00
|
|
|
// Recalculate the min and max chunk coords of the island
|
|
|
|
m_MaxChunkX = (m_IslandSizeX + cChunkDef::Width - 1) / cChunkDef::Width;
|
|
|
|
m_MinChunkX = -m_MaxChunkX;
|
|
|
|
m_MaxChunkZ = (m_IslandSizeZ + cChunkDef::Width - 1) / cChunkDef::Width;
|
|
|
|
m_MinChunkZ = -m_MaxChunkZ;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2019-09-08 09:40:12 -04:00
|
|
|
void cEndGen::PrepareState(cChunkCoords a_ChunkCoords)
|
2013-07-29 07:13:03 -04:00
|
|
|
{
|
2019-09-08 09:40:12 -04:00
|
|
|
ASSERT(!IsChunkOutsideRange(a_ChunkCoords)); // Should be filtered before calling this function
|
2013-11-16 13:57:03 -05:00
|
|
|
|
2019-09-08 09:40:12 -04:00
|
|
|
if (m_LastChunkCoords == a_ChunkCoords)
|
2013-07-29 07:13:03 -04:00
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
2013-11-16 13:57:03 -05:00
|
|
|
|
2019-09-08 09:40:12 -04:00
|
|
|
m_LastChunkCoords = a_ChunkCoords;
|
2013-11-16 13:57:03 -05:00
|
|
|
|
2013-07-29 07:13:03 -04:00
|
|
|
GenerateNoiseArray();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void cEndGen::GenerateNoiseArray(void)
|
|
|
|
{
|
|
|
|
NOISE_DATATYPE NoiseData[DIM_X * DIM_Y * DIM_Z]; // [x + DIM_X * z + DIM_X * DIM_Z * y]
|
|
|
|
NOISE_DATATYPE Workspace[DIM_X * DIM_Y * DIM_Z]; // [x + DIM_X * z + DIM_X * DIM_Z * y]
|
2013-11-16 13:57:03 -05:00
|
|
|
|
2013-07-29 07:13:03 -04:00
|
|
|
// Generate the downscaled noise:
|
2019-09-08 09:40:12 -04:00
|
|
|
NOISE_DATATYPE StartX = static_cast<NOISE_DATATYPE>(m_LastChunkCoords.m_ChunkX * cChunkDef::Width) / m_FrequencyX;
|
|
|
|
NOISE_DATATYPE EndX = static_cast<NOISE_DATATYPE>((m_LastChunkCoords.m_ChunkX + 1) * cChunkDef::Width) / m_FrequencyX;
|
|
|
|
NOISE_DATATYPE StartZ = static_cast<NOISE_DATATYPE>(m_LastChunkCoords.m_ChunkZ * cChunkDef::Width) / m_FrequencyZ;
|
|
|
|
NOISE_DATATYPE EndZ = static_cast<NOISE_DATATYPE>((m_LastChunkCoords.m_ChunkZ + 1) * cChunkDef::Width) / m_FrequencyZ;
|
2013-07-29 07:13:03 -04:00
|
|
|
NOISE_DATATYPE StartY = 0;
|
2015-08-04 18:24:59 -04:00
|
|
|
NOISE_DATATYPE EndY = static_cast<NOISE_DATATYPE>(257) / m_FrequencyY;
|
2013-07-29 07:13:03 -04:00
|
|
|
m_Perlin.Generate3D(NoiseData, DIM_X, DIM_Z, DIM_Y, StartX, EndX, StartZ, EndZ, StartY, EndY, Workspace);
|
2013-11-16 13:57:03 -05:00
|
|
|
|
2013-07-29 07:13:03 -04:00
|
|
|
// Add distance:
|
|
|
|
int idx = 0;
|
|
|
|
for (int y = 0; y < DIM_Y; y++)
|
|
|
|
{
|
2015-08-04 18:24:59 -04:00
|
|
|
NOISE_DATATYPE ValY = static_cast<NOISE_DATATYPE>(2 * INTERPOL_Y * y - m_IslandSizeY) / m_IslandSizeY;
|
2013-07-29 07:13:03 -04:00
|
|
|
ValY = ValY * ValY;
|
|
|
|
for (int z = 0; z < DIM_Z; z++)
|
|
|
|
{
|
2019-09-08 09:40:12 -04:00
|
|
|
NOISE_DATATYPE ValZ = static_cast<NOISE_DATATYPE>(m_LastChunkCoords.m_ChunkZ * cChunkDef::Width + (z * cChunkDef::Width / (DIM_Z - 1))) / m_IslandSizeZ;
|
2013-07-29 07:13:03 -04:00
|
|
|
ValZ = ValZ * ValZ;
|
|
|
|
for (int x = 0; x < DIM_X; x++)
|
|
|
|
{
|
|
|
|
// NOISE_DATATYPE ValX = StartX + (EndX - StartX) * x / (DIM_X - 1);
|
2019-09-08 09:40:12 -04:00
|
|
|
NOISE_DATATYPE ValX = static_cast<NOISE_DATATYPE>(m_LastChunkCoords.m_ChunkX * cChunkDef::Width + (x * cChunkDef::Width / (DIM_X - 1))) / m_IslandSizeX;
|
2013-07-29 07:13:03 -04:00
|
|
|
ValX = ValX * ValX;
|
|
|
|
NoiseData[idx++] += ValX + ValZ + ValY;
|
|
|
|
} // for x
|
|
|
|
} // for z
|
|
|
|
} // for y
|
2013-11-16 13:57:03 -05:00
|
|
|
|
2013-07-29 07:13:03 -04:00
|
|
|
// Upscale into real chunk size:
|
|
|
|
LinearUpscale3DArray(NoiseData, DIM_X, DIM_Z, DIM_Y, m_NoiseArray, INTERPOL_X, INTERPOL_Z, INTERPOL_Y);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2013-11-16 13:57:03 -05:00
|
|
|
|
2019-09-08 09:40:12 -04:00
|
|
|
bool cEndGen::IsChunkOutsideRange(cChunkCoords a_ChunkCoords)
|
2013-07-29 07:13:03 -04:00
|
|
|
{
|
|
|
|
return (
|
2019-09-08 09:40:12 -04:00
|
|
|
(a_ChunkCoords.m_ChunkX < m_MinChunkX) || (a_ChunkCoords.m_ChunkX > m_MaxChunkX) ||
|
|
|
|
(a_ChunkCoords.m_ChunkZ < m_MinChunkZ) || (a_ChunkCoords.m_ChunkZ > m_MaxChunkZ)
|
2013-11-16 13:57:03 -05:00
|
|
|
);
|
2013-07-29 07:13:03 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2019-09-08 09:40:12 -04:00
|
|
|
void cEndGen::GenShape(cChunkCoords a_ChunkCoords, cChunkDesc::Shape & a_Shape)
|
2013-07-29 07:13:03 -04:00
|
|
|
{
|
2014-11-12 15:24:26 -05:00
|
|
|
// If the chunk is outside out range, fill the shape with zeroes:
|
2019-09-08 09:40:12 -04:00
|
|
|
if (IsChunkOutsideRange(a_ChunkCoords))
|
2013-07-29 07:13:03 -04:00
|
|
|
{
|
2014-11-12 15:24:26 -05:00
|
|
|
for (size_t i = 0; i < ARRAYCOUNT(a_Shape); i++)
|
2013-07-29 07:13:03 -04:00
|
|
|
{
|
2014-11-12 15:24:26 -05:00
|
|
|
a_Shape[i] = 0;
|
2013-07-29 07:13:03 -04:00
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
2013-11-16 13:57:03 -05:00
|
|
|
|
2019-09-08 09:40:12 -04:00
|
|
|
PrepareState(a_ChunkCoords);
|
2013-11-16 13:57:03 -05:00
|
|
|
|
2015-08-04 18:24:59 -04:00
|
|
|
int MaxY = std::min(static_cast<int>(1.75 * m_IslandSizeY + 1), cChunkDef::Height - 1);
|
2013-07-29 07:13:03 -04:00
|
|
|
for (int z = 0; z < cChunkDef::Width; z++)
|
|
|
|
{
|
|
|
|
for (int x = 0; x < cChunkDef::Width; x++)
|
|
|
|
{
|
2014-11-12 15:24:26 -05:00
|
|
|
for (int y = 0; y < MaxY; y++)
|
2013-07-29 07:13:03 -04:00
|
|
|
{
|
2014-11-12 15:24:26 -05:00
|
|
|
a_Shape[(x + 16 * z) * 256 + y] = (m_NoiseArray[y * 17 * 17 + z * 17 + z] > 0) ? 1 : 0;
|
|
|
|
}
|
|
|
|
for (int y = MaxY; y < cChunkDef::Height; y++)
|
|
|
|
{
|
|
|
|
a_Shape[(x + 16 * z) * 256 + y] = 0;
|
|
|
|
}
|
2013-07-29 07:13:03 -04:00
|
|
|
} // for x
|
|
|
|
} // for z
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2014-11-12 15:24:26 -05:00
|
|
|
void cEndGen::ComposeTerrain(cChunkDesc & a_ChunkDesc, const cChunkDesc::Shape & a_Shape)
|
2013-07-29 07:13:03 -04:00
|
|
|
{
|
2014-11-12 15:24:26 -05:00
|
|
|
a_ChunkDesc.FillBlocks(E_BLOCK_AIR, 0);
|
2013-07-29 07:13:03 -04:00
|
|
|
for (int z = 0; z < cChunkDef::Width; z++)
|
|
|
|
{
|
|
|
|
for (int x = 0; x < cChunkDef::Width; x++)
|
|
|
|
{
|
2014-11-12 15:24:26 -05:00
|
|
|
for (int y = 0; y < cChunkDef::Height; y++)
|
2013-07-29 07:13:03 -04:00
|
|
|
{
|
2014-11-12 15:24:26 -05:00
|
|
|
if (a_Shape[(x + 16 * z) * 256 + y] != 0)
|
2013-07-29 07:13:03 -04:00
|
|
|
{
|
2014-11-12 15:24:26 -05:00
|
|
|
a_ChunkDesc.SetBlockType(x, y, z, E_BLOCK_END_STONE);
|
2013-07-29 07:13:03 -04:00
|
|
|
}
|
|
|
|
} // for y
|
|
|
|
} // for x
|
|
|
|
} // for z
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|