Generator: Shape initial refactoring.
The code compiles, but several structure generators are broken, crash on start.
This commit is contained in:
parent
b525eee8e0
commit
5fb2526e07
@ -10,6 +10,7 @@ SET (SRCS
|
|||||||
ChunkDesc.cpp
|
ChunkDesc.cpp
|
||||||
ChunkGenerator.cpp
|
ChunkGenerator.cpp
|
||||||
CompoGen.cpp
|
CompoGen.cpp
|
||||||
|
CompoGenBiomal.cpp
|
||||||
ComposableGenerator.cpp
|
ComposableGenerator.cpp
|
||||||
DistortedHeightmap.cpp
|
DistortedHeightmap.cpp
|
||||||
DungeonRoomsFinisher.cpp
|
DungeonRoomsFinisher.cpp
|
||||||
@ -39,6 +40,7 @@ SET (HDRS
|
|||||||
ChunkDesc.h
|
ChunkDesc.h
|
||||||
ChunkGenerator.h
|
ChunkGenerator.h
|
||||||
CompoGen.h
|
CompoGen.h
|
||||||
|
CompoGenBiomal.h
|
||||||
ComposableGenerator.h
|
ComposableGenerator.h
|
||||||
DistortedHeightmap.h
|
DistortedHeightmap.h
|
||||||
DungeonRoomsFinisher.h
|
DungeonRoomsFinisher.h
|
||||||
@ -58,6 +60,7 @@ SET (HDRS
|
|||||||
RainbowRoadsGen.h
|
RainbowRoadsGen.h
|
||||||
Ravines.h
|
Ravines.h
|
||||||
RoughRavines.h
|
RoughRavines.h
|
||||||
|
ShapeGen.cpp
|
||||||
StructGen.h
|
StructGen.h
|
||||||
TestRailsGen.h
|
TestRailsGen.h
|
||||||
Trees.h
|
Trees.h
|
||||||
|
@ -152,6 +152,52 @@ int cChunkDesc::GetHeight(int a_RelX, int a_RelZ)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cChunkDesc::SetHeightFromShape(const Shape & a_Shape)
|
||||||
|
{
|
||||||
|
for (int z = 0; z < cChunkDef::Width; z++)
|
||||||
|
{
|
||||||
|
for (int x = 0; x < cChunkDef::Width; x++)
|
||||||
|
{
|
||||||
|
for (int y = cChunkDef::Height - 1; y > 0; y--)
|
||||||
|
{
|
||||||
|
if (a_Shape[y + x * 256 + z * 16 * 256] != 0)
|
||||||
|
{
|
||||||
|
cChunkDef::SetHeight(m_HeightMap, x, z, y);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} // for y
|
||||||
|
} // for x
|
||||||
|
} // for z
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cChunkDesc::GetShapeFromHeight(Shape & a_Shape) const
|
||||||
|
{
|
||||||
|
for (int z = 0; z < cChunkDef::Width; z++)
|
||||||
|
{
|
||||||
|
for (int x = 0; x < cChunkDef::Width; x++)
|
||||||
|
{
|
||||||
|
int height = cChunkDef::GetHeight(m_HeightMap, x, z);
|
||||||
|
for (int y = 0; y <= height; y++)
|
||||||
|
{
|
||||||
|
a_Shape[y + x * 256 + z * 16 * 256] = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int y = height + 1; y < cChunkDef::Height; y++)
|
||||||
|
{
|
||||||
|
a_Shape[y + x * 256 + z * 16 * 256] = 0;
|
||||||
|
} // for y
|
||||||
|
} // for x
|
||||||
|
} // for z
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cChunkDesc::SetUseDefaultBiomes(bool a_bUseDefaultBiomes)
|
void cChunkDesc::SetUseDefaultBiomes(bool a_bUseDefaultBiomes)
|
||||||
{
|
{
|
||||||
m_bUseDefaultBiomes = a_bUseDefaultBiomes;
|
m_bUseDefaultBiomes = a_bUseDefaultBiomes;
|
||||||
@ -366,6 +412,23 @@ HEIGHTTYPE cChunkDesc::GetMaxHeight(void) const
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
HEIGHTTYPE cChunkDesc::GetMinHeight(void) const
|
||||||
|
{
|
||||||
|
HEIGHTTYPE MinHeight = m_HeightMap[0];
|
||||||
|
for (size_t i = 1; i < ARRAYCOUNT(m_HeightMap); i++)
|
||||||
|
{
|
||||||
|
if (m_HeightMap[i] < MinHeight)
|
||||||
|
{
|
||||||
|
MinHeight = m_HeightMap[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return MinHeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cChunkDesc::FillRelCuboid(
|
void cChunkDesc::FillRelCuboid(
|
||||||
int a_MinX, int a_MaxX,
|
int a_MinX, int a_MaxX,
|
||||||
int a_MinY, int a_MaxY,
|
int a_MinY, int a_MaxY,
|
||||||
|
@ -29,10 +29,17 @@ class cChunkDesc
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
// tolua_end
|
// tolua_end
|
||||||
|
|
||||||
|
/** The datatype used to represent the entire chunk worth of shape.
|
||||||
|
0 = air
|
||||||
|
1 = solid
|
||||||
|
Indexed as [y + 256 * z + 256 * 16 * x]. */
|
||||||
|
typedef Byte Shape[256 * 16 * 16];
|
||||||
|
|
||||||
/** Uncompressed block metas, 1 meta per byte */
|
/** Uncompressed block metas, 1 meta per byte */
|
||||||
typedef NIBBLETYPE BlockNibbleBytes[cChunkDef::NumBlocks];
|
typedef NIBBLETYPE BlockNibbleBytes[cChunkDef::NumBlocks];
|
||||||
|
|
||||||
|
|
||||||
cChunkDesc(int a_ChunkX, int a_ChunkZ);
|
cChunkDesc(int a_ChunkX, int a_ChunkZ);
|
||||||
~cChunkDesc();
|
~cChunkDesc();
|
||||||
|
|
||||||
@ -57,10 +64,21 @@ public:
|
|||||||
EMCSBiome GetBiome(int a_RelX, int a_RelZ);
|
EMCSBiome GetBiome(int a_RelX, int a_RelZ);
|
||||||
|
|
||||||
// These operate on the heightmap, so they could get out of sync with the data
|
// These operate on the heightmap, so they could get out of sync with the data
|
||||||
// Use UpdateHeightmap() to re-sync
|
// Use UpdateHeightmap() to re-calculate heightmap from the block data
|
||||||
void SetHeight(int a_RelX, int a_RelZ, int a_Height);
|
void SetHeight(int a_RelX, int a_RelZ, int a_Height);
|
||||||
int GetHeight(int a_RelX, int a_RelZ);
|
int GetHeight(int a_RelX, int a_RelZ);
|
||||||
|
|
||||||
|
// tolua_end
|
||||||
|
|
||||||
|
/** Sets the heightmap to match the given shape data.
|
||||||
|
Note that this ignores overhangs; the method is mostly used by old composition generators. */
|
||||||
|
void SetHeightFromShape(const Shape & a_Shape);
|
||||||
|
|
||||||
|
/** Sets the shape in a_Shape to match the heightmap stored currently in m_HeightMap. */
|
||||||
|
void GetShapeFromHeight(Shape & a_Shape) const;
|
||||||
|
|
||||||
|
// tolua_begin
|
||||||
|
|
||||||
// Default generation:
|
// Default generation:
|
||||||
void SetUseDefaultBiomes(bool a_bUseDefaultBiomes);
|
void SetUseDefaultBiomes(bool a_bUseDefaultBiomes);
|
||||||
bool IsUsingDefaultBiomes(void) const;
|
bool IsUsingDefaultBiomes(void) const;
|
||||||
@ -77,8 +95,11 @@ public:
|
|||||||
/** Reads an area from the chunk into a cBlockArea, blocktypes and blockmetas */
|
/** Reads an area from the chunk into a cBlockArea, blocktypes and blockmetas */
|
||||||
void ReadBlockArea(cBlockArea & a_Dest, int a_MinRelX, int a_MaxRelX, int a_MinRelY, int a_MaxRelY, int a_MinRelZ, int a_MaxRelZ);
|
void ReadBlockArea(cBlockArea & a_Dest, int a_MinRelX, int a_MaxRelX, int a_MinRelY, int a_MaxRelY, int a_MinRelZ, int a_MaxRelZ);
|
||||||
|
|
||||||
/** Returns the maximum height value in the heightmap */
|
/** Returns the maximum height value in the heightmap. */
|
||||||
HEIGHTTYPE GetMaxHeight(void) const;
|
HEIGHTTYPE GetMaxHeight(void) const;
|
||||||
|
|
||||||
|
/** Returns the minimum height value in the heightmap. */
|
||||||
|
HEIGHTTYPE GetMinHeight(void) const;
|
||||||
|
|
||||||
/** Fills the relative cuboid with specified block; allows cuboid out of range of this chunk */
|
/** Fills the relative cuboid with specified block; allows cuboid out of range of this chunk */
|
||||||
void FillRelCuboid(
|
void FillRelCuboid(
|
||||||
|
@ -21,8 +21,9 @@
|
|||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
// cCompoGenSameBlock:
|
// cCompoGenSameBlock:
|
||||||
|
|
||||||
void cCompoGenSameBlock::ComposeTerrain(cChunkDesc & a_ChunkDesc)
|
void cCompoGenSameBlock::ComposeTerrain(cChunkDesc & a_ChunkDesc, const cChunkDesc::Shape & a_Shape)
|
||||||
{
|
{
|
||||||
|
a_ChunkDesc.SetHeightFromShape(a_Shape);
|
||||||
a_ChunkDesc.FillBlocks(E_BLOCK_AIR, 0);
|
a_ChunkDesc.FillBlocks(E_BLOCK_AIR, 0);
|
||||||
for (int z = 0; z < cChunkDef::Width; z++)
|
for (int z = 0; z < cChunkDef::Width; z++)
|
||||||
{
|
{
|
||||||
@ -63,7 +64,7 @@ void cCompoGenSameBlock::InitializeCompoGen(cIniFile & a_IniFile)
|
|||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
// cCompoGenDebugBiomes:
|
// cCompoGenDebugBiomes:
|
||||||
|
|
||||||
void cCompoGenDebugBiomes::ComposeTerrain(cChunkDesc & a_ChunkDesc)
|
void cCompoGenDebugBiomes::ComposeTerrain(cChunkDesc & a_ChunkDesc, const cChunkDesc::Shape & a_Shape)
|
||||||
{
|
{
|
||||||
static BLOCKTYPE Blocks[] =
|
static BLOCKTYPE Blocks[] =
|
||||||
{
|
{
|
||||||
@ -92,6 +93,7 @@ void cCompoGenDebugBiomes::ComposeTerrain(cChunkDesc & a_ChunkDesc)
|
|||||||
E_BLOCK_BEDROCK,
|
E_BLOCK_BEDROCK,
|
||||||
} ;
|
} ;
|
||||||
|
|
||||||
|
a_ChunkDesc.SetHeightFromShape(a_Shape);
|
||||||
a_ChunkDesc.FillBlocks(E_BLOCK_AIR, 0);
|
a_ChunkDesc.FillBlocks(E_BLOCK_AIR, 0);
|
||||||
|
|
||||||
for (int z = 0; z < cChunkDef::Width; z++)
|
for (int z = 0; z < cChunkDef::Width; z++)
|
||||||
@ -131,7 +133,7 @@ cCompoGenClassic::cCompoGenClassic(void) :
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cCompoGenClassic::ComposeTerrain(cChunkDesc & a_ChunkDesc)
|
void cCompoGenClassic::ComposeTerrain(cChunkDesc & a_ChunkDesc, const cChunkDesc::Shape & a_Shape)
|
||||||
{
|
{
|
||||||
/* The classic composition means:
|
/* The classic composition means:
|
||||||
- 1 layer of grass, 3 of dirt and the rest stone, if the height > sealevel + beachheight
|
- 1 layer of grass, 3 of dirt and the rest stone, if the height > sealevel + beachheight
|
||||||
@ -142,6 +144,7 @@ void cCompoGenClassic::ComposeTerrain(cChunkDesc & a_ChunkDesc)
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
a_ChunkDesc.FillBlocks(E_BLOCK_AIR, 0);
|
a_ChunkDesc.FillBlocks(E_BLOCK_AIR, 0);
|
||||||
|
a_ChunkDesc.SetHeightFromShape(a_Shape);
|
||||||
|
|
||||||
// The patterns to use for different situations, must be same length!
|
// The patterns to use for different situations, must be same length!
|
||||||
const BLOCKTYPE PatternGround[] = {m_BlockTop, m_BlockMiddle, m_BlockMiddle, m_BlockMiddle} ;
|
const BLOCKTYPE PatternGround[] = {m_BlockTop, m_BlockMiddle, m_BlockMiddle, m_BlockMiddle} ;
|
||||||
@ -209,323 +212,6 @@ void cCompoGenClassic::InitializeCompoGen(cIniFile & a_IniFile)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
// cCompoGenBiomal:
|
|
||||||
|
|
||||||
void cCompoGenBiomal::ComposeTerrain(cChunkDesc & a_ChunkDesc)
|
|
||||||
{
|
|
||||||
a_ChunkDesc.FillBlocks(E_BLOCK_AIR, 0);
|
|
||||||
|
|
||||||
int ChunkX = a_ChunkDesc.GetChunkX();
|
|
||||||
int ChunkZ = a_ChunkDesc.GetChunkZ();
|
|
||||||
|
|
||||||
/*
|
|
||||||
_X 2013_04_22:
|
|
||||||
There's no point in generating the whole cubic noise at once, because the noise values are used in
|
|
||||||
only about 20 % of the cases, so the speed gained by precalculating is lost by precalculating too much data
|
|
||||||
*/
|
|
||||||
|
|
||||||
for (int z = 0; z < cChunkDef::Width; z++)
|
|
||||||
{
|
|
||||||
for (int x = 0; x < cChunkDef::Width; x++)
|
|
||||||
{
|
|
||||||
int Height = a_ChunkDesc.GetHeight(x, z);
|
|
||||||
if (Height > m_SeaLevel)
|
|
||||||
{
|
|
||||||
switch (a_ChunkDesc.GetBiome(x, z))
|
|
||||||
{
|
|
||||||
case biOcean:
|
|
||||||
case biPlains:
|
|
||||||
case biExtremeHills:
|
|
||||||
case biForest:
|
|
||||||
case biTaiga:
|
|
||||||
case biSwampland:
|
|
||||||
case biRiver:
|
|
||||||
case biFrozenOcean:
|
|
||||||
case biFrozenRiver:
|
|
||||||
case biIcePlains:
|
|
||||||
case biIceMountains:
|
|
||||||
case biForestHills:
|
|
||||||
case biTaigaHills:
|
|
||||||
case biExtremeHillsEdge:
|
|
||||||
case biJungle:
|
|
||||||
case biJungleHills:
|
|
||||||
case biJungleEdge:
|
|
||||||
case biDeepOcean:
|
|
||||||
case biStoneBeach:
|
|
||||||
case biColdBeach:
|
|
||||||
case biBirchForest:
|
|
||||||
case biBirchForestHills:
|
|
||||||
case biRoofedForest:
|
|
||||||
case biColdTaiga:
|
|
||||||
case biColdTaigaHills:
|
|
||||||
case biExtremeHillsPlus:
|
|
||||||
case biSavanna:
|
|
||||||
case biSavannaPlateau:
|
|
||||||
case biSunflowerPlains:
|
|
||||||
case biExtremeHillsM:
|
|
||||||
case biFlowerForest:
|
|
||||||
case biTaigaM:
|
|
||||||
case biSwamplandM:
|
|
||||||
case biIcePlainsSpikes:
|
|
||||||
case biJungleM:
|
|
||||||
case biJungleEdgeM:
|
|
||||||
case biBirchForestM:
|
|
||||||
case biBirchForestHillsM:
|
|
||||||
case biRoofedForestM:
|
|
||||||
case biColdTaigaM:
|
|
||||||
case biExtremeHillsPlusM:
|
|
||||||
case biSavannaM:
|
|
||||||
case biSavannaPlateauM:
|
|
||||||
{
|
|
||||||
FillColumnGrass(x, z, Height, a_ChunkDesc.GetBlockTypes());
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case biMesa:
|
|
||||||
case biMesaPlateauF:
|
|
||||||
case biMesaPlateau:
|
|
||||||
case biMesaBryce:
|
|
||||||
case biMesaPlateauFM:
|
|
||||||
case biMesaPlateauM:
|
|
||||||
{
|
|
||||||
FillColumnClay(x, z, Height, a_ChunkDesc.GetBlockTypes());
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case biMegaTaiga:
|
|
||||||
case biMegaTaigaHills:
|
|
||||||
case biMegaSpruceTaiga:
|
|
||||||
case biMegaSpruceTaigaHills:
|
|
||||||
{
|
|
||||||
FillColumnDirt(x, z, Height, a_ChunkDesc.GetBlockTypes());
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case biDesertHills:
|
|
||||||
case biDesert:
|
|
||||||
case biDesertM:
|
|
||||||
case biBeach:
|
|
||||||
{
|
|
||||||
FillColumnSand(x, z, Height, a_ChunkDesc.GetBlockTypes());
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case biMushroomIsland:
|
|
||||||
case biMushroomShore:
|
|
||||||
{
|
|
||||||
FillColumnMycelium(x, z, Height, a_ChunkDesc.GetBlockTypes());
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
{
|
|
||||||
// TODO
|
|
||||||
ASSERT(!"CompoGenBiomal: Biome not implemented yet!");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
switch (a_ChunkDesc.GetBiome(x, z))
|
|
||||||
{
|
|
||||||
case biDesert:
|
|
||||||
case biBeach:
|
|
||||||
{
|
|
||||||
// Fill with water, sand, sandstone and stone
|
|
||||||
FillColumnWaterSand(x, z, Height, a_ChunkDesc.GetBlockTypes());
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
{
|
|
||||||
// Fill with water, sand/dirt/clay mix and stone
|
|
||||||
if (m_Noise.CubicNoise2D(0.3f * (cChunkDef::Width * ChunkX + x), 0.3f * (cChunkDef::Width * ChunkZ + z)) < 0)
|
|
||||||
{
|
|
||||||
FillColumnWaterSand(x, z, Height, a_ChunkDesc.GetBlockTypes());
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
FillColumnWaterDirt(x, z, Height, a_ChunkDesc.GetBlockTypes());
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} // switch (biome)
|
|
||||||
a_ChunkDesc.SetHeight(x, z, m_SeaLevel + 1);
|
|
||||||
} // else (under water)
|
|
||||||
a_ChunkDesc.SetBlockType(x, 0, z, E_BLOCK_BEDROCK);
|
|
||||||
} // for x
|
|
||||||
} // for z
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cCompoGenBiomal::InitializeCompoGen(cIniFile & a_IniFile)
|
|
||||||
{
|
|
||||||
m_SeaLevel = a_IniFile.GetValueSetI("Generator", "BiomalSeaLevel", m_SeaLevel) - 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cCompoGenBiomal::FillColumnGrass(int a_RelX, int a_RelZ, int a_Height, cChunkDef::BlockTypes & a_BlockTypes)
|
|
||||||
{
|
|
||||||
BLOCKTYPE Pattern[] =
|
|
||||||
{
|
|
||||||
E_BLOCK_GRASS,
|
|
||||||
E_BLOCK_DIRT,
|
|
||||||
E_BLOCK_DIRT,
|
|
||||||
E_BLOCK_DIRT,
|
|
||||||
} ;
|
|
||||||
FillColumnPattern(a_RelX, a_RelZ, a_Height, a_BlockTypes, Pattern, ARRAYCOUNT(Pattern));
|
|
||||||
|
|
||||||
for (int y = a_Height - ARRAYCOUNT(Pattern); y > 0; y--)
|
|
||||||
{
|
|
||||||
cChunkDef::SetBlock(a_BlockTypes, a_RelX, y, a_RelZ, E_BLOCK_STONE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cCompoGenBiomal::FillColumnClay(int a_RelX, int a_RelZ, int a_Height, cChunkDef::BlockTypes & a_BlockTypes)
|
|
||||||
{
|
|
||||||
BLOCKTYPE Pattern[] =
|
|
||||||
{
|
|
||||||
E_BLOCK_HARDENED_CLAY,
|
|
||||||
E_BLOCK_HARDENED_CLAY,
|
|
||||||
E_BLOCK_HARDENED_CLAY,
|
|
||||||
E_BLOCK_HARDENED_CLAY,
|
|
||||||
} ;
|
|
||||||
FillColumnPattern(a_RelX, a_RelZ, a_Height, a_BlockTypes, Pattern, ARRAYCOUNT(Pattern));
|
|
||||||
|
|
||||||
for (int y = a_Height - ARRAYCOUNT(Pattern); y > 0; y--)
|
|
||||||
{
|
|
||||||
cChunkDef::SetBlock(a_BlockTypes, a_RelX, y, a_RelZ, E_BLOCK_STONE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cCompoGenBiomal::FillColumnDirt(int a_RelX, int a_RelZ, int a_Height, cChunkDef::BlockTypes & a_BlockTypes)
|
|
||||||
{
|
|
||||||
for (int y = 0; y < 4; y++)
|
|
||||||
{
|
|
||||||
if (a_Height - y < 0)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
cChunkDef::SetBlock(a_BlockTypes, a_RelX, a_Height - y, a_RelZ, E_BLOCK_DIRT);
|
|
||||||
}
|
|
||||||
for (int y = a_Height - 4; y > 0; y--)
|
|
||||||
{
|
|
||||||
cChunkDef::SetBlock(a_BlockTypes, a_RelX, y, a_RelZ, E_BLOCK_STONE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cCompoGenBiomal::FillColumnSand(int a_RelX, int a_RelZ, int a_Height, cChunkDef::BlockTypes & a_BlockTypes)
|
|
||||||
{
|
|
||||||
BLOCKTYPE Pattern[] =
|
|
||||||
{
|
|
||||||
E_BLOCK_SAND,
|
|
||||||
E_BLOCK_SAND,
|
|
||||||
E_BLOCK_SAND,
|
|
||||||
E_BLOCK_SANDSTONE,
|
|
||||||
} ;
|
|
||||||
FillColumnPattern(a_RelX, a_RelZ, a_Height, a_BlockTypes, Pattern, ARRAYCOUNT(Pattern));
|
|
||||||
|
|
||||||
for (int y = a_Height - ARRAYCOUNT(Pattern); y > 0; y--)
|
|
||||||
{
|
|
||||||
cChunkDef::SetBlock(a_BlockTypes, a_RelX, y, a_RelZ, E_BLOCK_STONE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cCompoGenBiomal::FillColumnMycelium (int a_RelX, int a_RelZ, int a_Height, cChunkDef::BlockTypes & a_BlockTypes)
|
|
||||||
{
|
|
||||||
BLOCKTYPE Pattern[] =
|
|
||||||
{
|
|
||||||
E_BLOCK_MYCELIUM,
|
|
||||||
E_BLOCK_DIRT,
|
|
||||||
E_BLOCK_DIRT,
|
|
||||||
E_BLOCK_DIRT,
|
|
||||||
} ;
|
|
||||||
FillColumnPattern(a_RelX, a_RelZ, a_Height, a_BlockTypes, Pattern, ARRAYCOUNT(Pattern));
|
|
||||||
|
|
||||||
for (int y = a_Height - ARRAYCOUNT(Pattern); y > 0; y--)
|
|
||||||
{
|
|
||||||
cChunkDef::SetBlock(a_BlockTypes, a_RelX, y, a_RelZ, E_BLOCK_STONE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cCompoGenBiomal::FillColumnWaterSand(int a_RelX, int a_RelZ, int a_Height, cChunkDef::BlockTypes & a_BlockTypes)
|
|
||||||
{
|
|
||||||
FillColumnSand(a_RelX, a_RelZ, a_Height, a_BlockTypes);
|
|
||||||
for (int y = a_Height + 1; y <= m_SeaLevel + 1; y++)
|
|
||||||
{
|
|
||||||
cChunkDef::SetBlock(a_BlockTypes, a_RelX, y, a_RelZ, E_BLOCK_STATIONARY_WATER);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cCompoGenBiomal::FillColumnWaterDirt(int a_RelX, int a_RelZ, int a_Height, cChunkDef::BlockTypes & a_BlockTypes)
|
|
||||||
{
|
|
||||||
// Dirt
|
|
||||||
BLOCKTYPE Pattern[] =
|
|
||||||
{
|
|
||||||
E_BLOCK_DIRT,
|
|
||||||
E_BLOCK_DIRT,
|
|
||||||
E_BLOCK_DIRT,
|
|
||||||
E_BLOCK_DIRT,
|
|
||||||
} ;
|
|
||||||
FillColumnPattern(a_RelX, a_RelZ, a_Height, a_BlockTypes, Pattern, ARRAYCOUNT(Pattern));
|
|
||||||
|
|
||||||
for (int y = a_Height - ARRAYCOUNT(Pattern); y > 0; y--)
|
|
||||||
{
|
|
||||||
cChunkDef::SetBlock(a_BlockTypes, a_RelX, y, a_RelZ, E_BLOCK_STONE);
|
|
||||||
}
|
|
||||||
for (int y = a_Height + 1; y <= m_SeaLevel + 1; y++)
|
|
||||||
{
|
|
||||||
cChunkDef::SetBlock(a_BlockTypes, a_RelX, y, a_RelZ, E_BLOCK_STATIONARY_WATER);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cCompoGenBiomal::FillColumnPattern(int a_RelX, int a_RelZ, int a_Height, cChunkDef::BlockTypes & a_BlockTypes, const BLOCKTYPE * a_Pattern, int a_PatternSize)
|
|
||||||
{
|
|
||||||
for (int y = a_Height, idx = 0; (y >= 0) && (idx < a_PatternSize); y--, idx++)
|
|
||||||
{
|
|
||||||
cChunkDef::SetBlock(a_BlockTypes, a_RelX, y, a_RelZ, a_Pattern[idx]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
// cCompoGenNether:
|
// cCompoGenNether:
|
||||||
|
|
||||||
@ -540,7 +226,7 @@ cCompoGenNether::cCompoGenNether(int a_Seed) :
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cCompoGenNether::ComposeTerrain(cChunkDesc & a_ChunkDesc)
|
void cCompoGenNether::ComposeTerrain(cChunkDesc & a_ChunkDesc, const cChunkDesc::Shape & a_Shape)
|
||||||
{
|
{
|
||||||
HEIGHTTYPE MaxHeight = a_ChunkDesc.GetMaxHeight();
|
HEIGHTTYPE MaxHeight = a_ChunkDesc.GetMaxHeight();
|
||||||
|
|
||||||
@ -696,7 +382,7 @@ cCompoGenCache::~cCompoGenCache()
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cCompoGenCache::ComposeTerrain(cChunkDesc & a_ChunkDesc)
|
void cCompoGenCache::ComposeTerrain(cChunkDesc & a_ChunkDesc, const cChunkDesc::Shape & a_Shape)
|
||||||
{
|
{
|
||||||
#ifdef _DEBUG
|
#ifdef _DEBUG
|
||||||
if (((m_NumHits + m_NumMisses) % 1024) == 10)
|
if (((m_NumHits + m_NumMisses) % 1024) == 10)
|
||||||
@ -739,7 +425,7 @@ void cCompoGenCache::ComposeTerrain(cChunkDesc & a_ChunkDesc)
|
|||||||
|
|
||||||
// Not in the cache:
|
// Not in the cache:
|
||||||
m_NumMisses++;
|
m_NumMisses++;
|
||||||
m_Underlying->ComposeTerrain(a_ChunkDesc);
|
m_Underlying->ComposeTerrain(a_ChunkDesc, a_Shape);
|
||||||
|
|
||||||
// Insert it as the first item in the MRU order:
|
// Insert it as the first item in the MRU order:
|
||||||
int Idx = m_CacheOrder[m_CacheSize - 1];
|
int Idx = m_CacheOrder[m_CacheSize - 1];
|
||||||
|
@ -38,7 +38,7 @@ protected:
|
|||||||
bool m_IsBedrocked;
|
bool m_IsBedrocked;
|
||||||
|
|
||||||
// cTerrainCompositionGen overrides:
|
// cTerrainCompositionGen overrides:
|
||||||
virtual void ComposeTerrain(cChunkDesc & a_ChunkDesc) override;
|
virtual void ComposeTerrain(cChunkDesc & a_ChunkDesc, const cChunkDesc::Shape & a_Shape) override;
|
||||||
virtual void InitializeCompoGen(cIniFile & a_IniFile) override;
|
virtual void InitializeCompoGen(cIniFile & a_IniFile) override;
|
||||||
} ;
|
} ;
|
||||||
|
|
||||||
@ -55,7 +55,7 @@ public:
|
|||||||
protected:
|
protected:
|
||||||
|
|
||||||
// cTerrainCompositionGen overrides:
|
// cTerrainCompositionGen overrides:
|
||||||
virtual void ComposeTerrain(cChunkDesc & a_ChunkDesc) override;
|
virtual void ComposeTerrain(cChunkDesc & a_ChunkDesc, const cChunkDesc::Shape & a_Shape) override;
|
||||||
} ;
|
} ;
|
||||||
|
|
||||||
|
|
||||||
@ -81,7 +81,7 @@ protected:
|
|||||||
BLOCKTYPE m_BlockSea;
|
BLOCKTYPE m_BlockSea;
|
||||||
|
|
||||||
// cTerrainCompositionGen overrides:
|
// cTerrainCompositionGen overrides:
|
||||||
virtual void ComposeTerrain(cChunkDesc & a_ChunkDesc) override;
|
virtual void ComposeTerrain(cChunkDesc & a_ChunkDesc, const cChunkDesc::Shape & a_Shape) override;
|
||||||
virtual void InitializeCompoGen(cIniFile & a_IniFile) override;
|
virtual void InitializeCompoGen(cIniFile & a_IniFile) override;
|
||||||
} ;
|
} ;
|
||||||
|
|
||||||
@ -89,40 +89,6 @@ protected:
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
class cCompoGenBiomal :
|
|
||||||
public cTerrainCompositionGen
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
cCompoGenBiomal(int a_Seed) :
|
|
||||||
m_Noise(a_Seed + 1000),
|
|
||||||
m_SeaLevel(62)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
|
||||||
|
|
||||||
cNoise m_Noise;
|
|
||||||
int m_SeaLevel;
|
|
||||||
|
|
||||||
// cTerrainCompositionGen overrides:
|
|
||||||
virtual void ComposeTerrain(cChunkDesc & a_ChunkDesc) override;
|
|
||||||
virtual void InitializeCompoGen(cIniFile & a_IniFile) override;
|
|
||||||
|
|
||||||
void FillColumnGrass (int a_RelX, int a_RelZ, int a_Height, cChunkDef::BlockTypes & a_BlockTypes);
|
|
||||||
void FillColumnClay (int a_RelX, int a_RelZ, int a_Height, cChunkDef::BlockTypes & a_BlockTypes);
|
|
||||||
void FillColumnDirt (int a_RelX, int a_RelZ, int a_Height, cChunkDef::BlockTypes & a_BlockTypes);
|
|
||||||
void FillColumnSand (int a_RelX, int a_RelZ, int a_Height, cChunkDef::BlockTypes & a_BlockTypes);
|
|
||||||
void FillColumnMycelium (int a_RelX, int a_RelZ, int a_Height, cChunkDef::BlockTypes & a_BlockTypes);
|
|
||||||
void FillColumnWaterSand(int a_RelX, int a_RelZ, int a_Height, cChunkDef::BlockTypes & a_BlockTypes);
|
|
||||||
void FillColumnWaterDirt(int a_RelX, int a_RelZ, int a_Height, cChunkDef::BlockTypes & a_BlockTypes);
|
|
||||||
|
|
||||||
void FillColumnPattern (int a_RelX, int a_RelZ, int a_Height, cChunkDef::BlockTypes & a_BlockTypes, const BLOCKTYPE * a_Pattern, int a_PatternSize);
|
|
||||||
} ;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class cCompoGenNether :
|
class cCompoGenNether :
|
||||||
public cTerrainCompositionGen
|
public cTerrainCompositionGen
|
||||||
{
|
{
|
||||||
@ -136,7 +102,7 @@ protected:
|
|||||||
int m_Threshold;
|
int m_Threshold;
|
||||||
|
|
||||||
// cTerrainCompositionGen overrides:
|
// cTerrainCompositionGen overrides:
|
||||||
virtual void ComposeTerrain(cChunkDesc & a_ChunkDesc) override;
|
virtual void ComposeTerrain(cChunkDesc & a_ChunkDesc, const cChunkDesc::Shape & a_Shape) override;
|
||||||
virtual void InitializeCompoGen(cIniFile & a_IniFile) override;
|
virtual void InitializeCompoGen(cIniFile & a_IniFile) override;
|
||||||
} ;
|
} ;
|
||||||
|
|
||||||
@ -153,7 +119,7 @@ public:
|
|||||||
~cCompoGenCache();
|
~cCompoGenCache();
|
||||||
|
|
||||||
// cTerrainCompositionGen override:
|
// cTerrainCompositionGen override:
|
||||||
virtual void ComposeTerrain(cChunkDesc & a_ChunkDesc) override;
|
virtual void ComposeTerrain(cChunkDesc & a_ChunkDesc, const cChunkDesc::Shape & a_Shape) override;
|
||||||
virtual void InitializeCompoGen(cIniFile & a_IniFile) override;
|
virtual void InitializeCompoGen(cIniFile & a_IniFile) override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
799
src/Generating/CompoGenBiomal.cpp
Normal file
799
src/Generating/CompoGenBiomal.cpp
Normal file
@ -0,0 +1,799 @@
|
|||||||
|
|
||||||
|
// CompoGenBiomal.cpp
|
||||||
|
|
||||||
|
// Implements the cCompoGenBiomal class representing the biome-aware composition generator
|
||||||
|
|
||||||
|
#include "Globals.h"
|
||||||
|
#include "ComposableGenerator.h"
|
||||||
|
#include "../IniFile.h"
|
||||||
|
#include "../Noise.h"
|
||||||
|
#include "../LinearUpscale.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// cPattern:
|
||||||
|
|
||||||
|
/** This class is used to store a column pattern initialized at runtime,
|
||||||
|
so that the program doesn't need to explicitly set 256 values for each pattern
|
||||||
|
Each pattern has 256 blocks so that there's no need to check pattern bounds when assigning the
|
||||||
|
pattern - there will always be enough pattern left, even for the whole-chunk-height columns. */
|
||||||
|
class cPattern
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
struct BlockInfo
|
||||||
|
{
|
||||||
|
BLOCKTYPE m_BlockType;
|
||||||
|
NIBBLETYPE m_BlockMeta;
|
||||||
|
};
|
||||||
|
|
||||||
|
cPattern(BlockInfo * a_TopBlocks, size_t a_Count)
|
||||||
|
{
|
||||||
|
// Copy the pattern into the top:
|
||||||
|
for (size_t i = 0; i < a_Count; i++)
|
||||||
|
{
|
||||||
|
m_Pattern[i] = a_TopBlocks[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fill the rest with stone:
|
||||||
|
static BlockInfo Stone = {E_BLOCK_STONE, 0};
|
||||||
|
for (size_t i = a_Count; i < cChunkDef::Height; i++)
|
||||||
|
{
|
||||||
|
m_Pattern[i] = Stone;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const BlockInfo * Get(void) const { return m_Pattern; }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
BlockInfo m_Pattern[cChunkDef::Height];
|
||||||
|
} ;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// The arrays to use for the top block pattern definitions:
|
||||||
|
|
||||||
|
static cPattern::BlockInfo tbGrass[] =
|
||||||
|
{
|
||||||
|
{E_BLOCK_GRASS, 0},
|
||||||
|
{E_BLOCK_DIRT, E_META_DIRT_NORMAL},
|
||||||
|
{E_BLOCK_DIRT, E_META_DIRT_NORMAL},
|
||||||
|
{E_BLOCK_DIRT, E_META_DIRT_NORMAL},
|
||||||
|
} ;
|
||||||
|
|
||||||
|
static cPattern::BlockInfo tbSand[] =
|
||||||
|
{
|
||||||
|
{ E_BLOCK_SAND, 0},
|
||||||
|
{ E_BLOCK_SAND, 0},
|
||||||
|
{ E_BLOCK_SAND, 0},
|
||||||
|
{ E_BLOCK_SANDSTONE, 0},
|
||||||
|
} ;
|
||||||
|
|
||||||
|
static cPattern::BlockInfo tbDirt[] =
|
||||||
|
{
|
||||||
|
{E_BLOCK_DIRT, E_META_DIRT_NORMAL},
|
||||||
|
{E_BLOCK_DIRT, E_META_DIRT_NORMAL},
|
||||||
|
{E_BLOCK_DIRT, E_META_DIRT_NORMAL},
|
||||||
|
{E_BLOCK_DIRT, E_META_DIRT_NORMAL},
|
||||||
|
} ;
|
||||||
|
|
||||||
|
static cPattern::BlockInfo tbPodzol[] =
|
||||||
|
{
|
||||||
|
{E_BLOCK_DIRT, E_META_DIRT_PODZOL},
|
||||||
|
{E_BLOCK_DIRT, E_META_DIRT_NORMAL},
|
||||||
|
{E_BLOCK_DIRT, E_META_DIRT_NORMAL},
|
||||||
|
{E_BLOCK_DIRT, E_META_DIRT_NORMAL},
|
||||||
|
} ;
|
||||||
|
|
||||||
|
static cPattern::BlockInfo tbGrassLess[] =
|
||||||
|
{
|
||||||
|
{E_BLOCK_DIRT, E_META_DIRT_GRASSLESS},
|
||||||
|
{E_BLOCK_DIRT, E_META_DIRT_NORMAL},
|
||||||
|
{E_BLOCK_DIRT, E_META_DIRT_NORMAL},
|
||||||
|
{E_BLOCK_DIRT, E_META_DIRT_NORMAL},
|
||||||
|
} ;
|
||||||
|
|
||||||
|
static cPattern::BlockInfo tbMycelium[] =
|
||||||
|
{
|
||||||
|
{E_BLOCK_MYCELIUM, 0},
|
||||||
|
{E_BLOCK_DIRT, 0},
|
||||||
|
{E_BLOCK_DIRT, 0},
|
||||||
|
{E_BLOCK_DIRT, 0},
|
||||||
|
} ;
|
||||||
|
|
||||||
|
static cPattern::BlockInfo tbGravel[] =
|
||||||
|
{
|
||||||
|
{E_BLOCK_GRAVEL, 0},
|
||||||
|
{E_BLOCK_GRAVEL, 0},
|
||||||
|
{E_BLOCK_GRAVEL, 0},
|
||||||
|
{E_BLOCK_STONE, 0},
|
||||||
|
} ;
|
||||||
|
|
||||||
|
static cPattern::BlockInfo tbStone[] =
|
||||||
|
{
|
||||||
|
{E_BLOCK_STONE, 0},
|
||||||
|
{E_BLOCK_STONE, 0},
|
||||||
|
{E_BLOCK_STONE, 0},
|
||||||
|
{E_BLOCK_STONE, 0},
|
||||||
|
} ;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Ocean floor pattern top-block definitions:
|
||||||
|
|
||||||
|
static cPattern::BlockInfo tbOFSand[] =
|
||||||
|
{
|
||||||
|
{E_BLOCK_SAND, 0},
|
||||||
|
{E_BLOCK_SAND, 0},
|
||||||
|
{E_BLOCK_SAND, 0},
|
||||||
|
{E_BLOCK_SANDSTONE, 0}
|
||||||
|
} ;
|
||||||
|
|
||||||
|
static cPattern::BlockInfo tbOFClay[] =
|
||||||
|
{
|
||||||
|
{ E_BLOCK_CLAY, 0},
|
||||||
|
{ E_BLOCK_CLAY, 0},
|
||||||
|
{ E_BLOCK_SAND, 0},
|
||||||
|
{ E_BLOCK_SAND, 0},
|
||||||
|
} ;
|
||||||
|
|
||||||
|
static cPattern::BlockInfo tbOFOrangeClay[] =
|
||||||
|
{
|
||||||
|
{ E_BLOCK_STAINED_CLAY, E_META_STAINED_GLASS_ORANGE},
|
||||||
|
{ E_BLOCK_STAINED_CLAY, E_META_STAINED_GLASS_ORANGE},
|
||||||
|
{ E_BLOCK_STAINED_CLAY, E_META_STAINED_GLASS_ORANGE},
|
||||||
|
} ;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Individual patterns to use:
|
||||||
|
|
||||||
|
static cPattern patGrass (tbGrass, ARRAYCOUNT(tbGrass));
|
||||||
|
static cPattern patSand (tbSand, ARRAYCOUNT(tbSand));
|
||||||
|
static cPattern patDirt (tbDirt, ARRAYCOUNT(tbDirt));
|
||||||
|
static cPattern patPodzol (tbPodzol, ARRAYCOUNT(tbPodzol));
|
||||||
|
static cPattern patGrassLess(tbGrassLess, ARRAYCOUNT(tbGrassLess));
|
||||||
|
static cPattern patMycelium (tbMycelium, ARRAYCOUNT(tbMycelium));
|
||||||
|
static cPattern patGravel (tbGravel, ARRAYCOUNT(tbGravel));
|
||||||
|
static cPattern patStone (tbStone, ARRAYCOUNT(tbStone));
|
||||||
|
|
||||||
|
static cPattern patOFSand (tbOFSand, ARRAYCOUNT(tbOFSand));
|
||||||
|
static cPattern patOFClay (tbOFClay, ARRAYCOUNT(tbOFClay));
|
||||||
|
static cPattern patOFOrangeClay(tbOFOrangeClay, ARRAYCOUNT(tbOFOrangeClay));
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// cCompoGenBiomal:
|
||||||
|
|
||||||
|
class cCompoGenBiomal :
|
||||||
|
public cTerrainCompositionGen
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
cCompoGenBiomal(int a_Seed) :
|
||||||
|
m_SeaLevel(62),
|
||||||
|
m_OceanFloorSelect(a_Seed + 1),
|
||||||
|
m_MesaFloor(a_Seed + 2)
|
||||||
|
{
|
||||||
|
initMesaPattern(a_Seed);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
/** The block height at which water is generated instead of air. */
|
||||||
|
int m_SeaLevel;
|
||||||
|
|
||||||
|
/** The pattern used for mesa biomes. Initialized by seed on generator creation. */
|
||||||
|
cPattern::BlockInfo m_MesaPattern[2 * cChunkDef::Height];
|
||||||
|
|
||||||
|
/** Noise used for selecting between dirt and sand on the ocean floor. */
|
||||||
|
cNoise m_OceanFloorSelect;
|
||||||
|
|
||||||
|
/** Noise used for the floor of the clay blocks in mesa biomes. */
|
||||||
|
cNoise m_MesaFloor;
|
||||||
|
|
||||||
|
|
||||||
|
// cTerrainCompositionGen overrides:
|
||||||
|
virtual void ComposeTerrain(cChunkDesc & a_ChunkDesc, const cChunkDesc::Shape & a_Shape) override
|
||||||
|
{
|
||||||
|
a_ChunkDesc.FillBlocks(E_BLOCK_AIR, 0);
|
||||||
|
for (int z = 0; z < cChunkDef::Width; z++)
|
||||||
|
{
|
||||||
|
for (int x = 0; x < cChunkDef::Width; x++)
|
||||||
|
{
|
||||||
|
ComposeColumn(a_ChunkDesc, x, z, &(a_Shape[x * 256 + z * 16 * 256]));
|
||||||
|
} // for x
|
||||||
|
} // for z
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
virtual void InitializeCompoGen(cIniFile & a_IniFile) override
|
||||||
|
{
|
||||||
|
m_SeaLevel = a_IniFile.GetValueSetI("Generator", "SeaLevel", m_SeaLevel) - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/** Initializes the m_MesaPattern with a pattern based on the generator's seed. */
|
||||||
|
void initMesaPattern(int a_Seed)
|
||||||
|
{
|
||||||
|
// In a loop, choose whether to use one, two or three layers of stained clay, then choose a color and width for each layer
|
||||||
|
// Separate each group with another layer of hardened clay
|
||||||
|
cNoise patternNoise((unsigned)a_Seed);
|
||||||
|
static NIBBLETYPE allowedColors[] =
|
||||||
|
{
|
||||||
|
E_META_STAINED_CLAY_YELLOW,
|
||||||
|
E_META_STAINED_CLAY_YELLOW,
|
||||||
|
E_META_STAINED_CLAY_RED,
|
||||||
|
E_META_STAINED_CLAY_RED,
|
||||||
|
E_META_STAINED_CLAY_WHITE,
|
||||||
|
E_META_STAINED_CLAY_BROWN,
|
||||||
|
E_META_STAINED_CLAY_BROWN,
|
||||||
|
E_META_STAINED_CLAY_BROWN,
|
||||||
|
E_META_STAINED_CLAY_ORANGE,
|
||||||
|
E_META_STAINED_CLAY_ORANGE,
|
||||||
|
E_META_STAINED_CLAY_ORANGE,
|
||||||
|
E_META_STAINED_CLAY_ORANGE,
|
||||||
|
E_META_STAINED_CLAY_ORANGE,
|
||||||
|
E_META_STAINED_CLAY_ORANGE,
|
||||||
|
E_META_STAINED_CLAY_LIGHTGRAY,
|
||||||
|
} ;
|
||||||
|
static int layerSizes[] = // Adjust the chance so that thinner layers occur more commonly
|
||||||
|
{
|
||||||
|
1, 1, 1, 1, 1, 1,
|
||||||
|
2, 2, 2, 2,
|
||||||
|
3, 3,
|
||||||
|
} ;
|
||||||
|
int idx = ARRAYCOUNT(m_MesaPattern) - 1;
|
||||||
|
while (idx >= 0)
|
||||||
|
{
|
||||||
|
// A layer group of 1 - 2 color stained clay:
|
||||||
|
int rnd = patternNoise.IntNoise1DInt(idx) / 7;
|
||||||
|
int numLayers = (rnd % 2) + 1;
|
||||||
|
rnd /= 2;
|
||||||
|
for (int lay = 0; lay < numLayers; lay++)
|
||||||
|
{
|
||||||
|
int numBlocks = layerSizes[(rnd % ARRAYCOUNT(layerSizes))];
|
||||||
|
NIBBLETYPE Color = allowedColors[(rnd / 4) % ARRAYCOUNT(allowedColors)];
|
||||||
|
if (
|
||||||
|
((numBlocks == 3) && (numLayers == 2)) || // In two-layer mode disallow the 3-high layers:
|
||||||
|
(Color == E_META_STAINED_CLAY_WHITE)) // White stained clay can ever be only 1 block high
|
||||||
|
{
|
||||||
|
numBlocks = 1;
|
||||||
|
}
|
||||||
|
numBlocks = std::min(idx + 1, numBlocks); // Limit by idx so that we don't have to check inside the loop
|
||||||
|
rnd /= 32;
|
||||||
|
for (int block = 0; block < numBlocks; block++, idx--)
|
||||||
|
{
|
||||||
|
m_MesaPattern[idx].m_BlockMeta = Color;
|
||||||
|
m_MesaPattern[idx].m_BlockType = E_BLOCK_STAINED_CLAY;
|
||||||
|
} // for block
|
||||||
|
} // for lay
|
||||||
|
|
||||||
|
// A layer of hardened clay in between the layer group:
|
||||||
|
int numBlocks = (rnd % 4) + 1; // All heights the same probability
|
||||||
|
if ((numLayers == 2) && (numBlocks < 4))
|
||||||
|
{
|
||||||
|
// For two layers of stained clay, add an extra block of hardened clay:
|
||||||
|
numBlocks++;
|
||||||
|
}
|
||||||
|
numBlocks = std::min(idx + 1, numBlocks); // Limit by idx so that we don't have to check inside the loop
|
||||||
|
for (int block = 0; block < numBlocks; block++, idx--)
|
||||||
|
{
|
||||||
|
m_MesaPattern[idx].m_BlockMeta = 0;
|
||||||
|
m_MesaPattern[idx].m_BlockType = E_BLOCK_HARDENED_CLAY;
|
||||||
|
} // for block
|
||||||
|
} // while (idx >= 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/** Composes a single column in a_ChunkDesc. Chooses what to do based on the biome in that column. */
|
||||||
|
void ComposeColumn(cChunkDesc & a_ChunkDesc, int a_RelX, int a_RelZ, const Byte * a_ShapeColumn)
|
||||||
|
{
|
||||||
|
// Frequencies for the podzol floor selecting noise:
|
||||||
|
const NOISE_DATATYPE FrequencyX = 8;
|
||||||
|
const NOISE_DATATYPE FrequencyZ = 8;
|
||||||
|
|
||||||
|
EMCSBiome Biome = a_ChunkDesc.GetBiome(a_RelX, a_RelZ);
|
||||||
|
switch (Biome)
|
||||||
|
{
|
||||||
|
case biOcean:
|
||||||
|
case biPlains:
|
||||||
|
case biForest:
|
||||||
|
case biTaiga:
|
||||||
|
case biSwampland:
|
||||||
|
case biRiver:
|
||||||
|
case biFrozenOcean:
|
||||||
|
case biFrozenRiver:
|
||||||
|
case biIcePlains:
|
||||||
|
case biIceMountains:
|
||||||
|
case biForestHills:
|
||||||
|
case biTaigaHills:
|
||||||
|
case biExtremeHillsEdge:
|
||||||
|
case biExtremeHillsPlus:
|
||||||
|
case biExtremeHills:
|
||||||
|
case biJungle:
|
||||||
|
case biJungleHills:
|
||||||
|
case biJungleEdge:
|
||||||
|
case biDeepOcean:
|
||||||
|
case biStoneBeach:
|
||||||
|
case biColdBeach:
|
||||||
|
case biBirchForest:
|
||||||
|
case biBirchForestHills:
|
||||||
|
case biRoofedForest:
|
||||||
|
case biColdTaiga:
|
||||||
|
case biColdTaigaHills:
|
||||||
|
case biSavanna:
|
||||||
|
case biSavannaPlateau:
|
||||||
|
case biSunflowerPlains:
|
||||||
|
case biFlowerForest:
|
||||||
|
case biTaigaM:
|
||||||
|
case biSwamplandM:
|
||||||
|
case biIcePlainsSpikes:
|
||||||
|
case biJungleM:
|
||||||
|
case biJungleEdgeM:
|
||||||
|
case biBirchForestM:
|
||||||
|
case biBirchForestHillsM:
|
||||||
|
case biRoofedForestM:
|
||||||
|
case biColdTaigaM:
|
||||||
|
case biSavannaM:
|
||||||
|
case biSavannaPlateauM:
|
||||||
|
{
|
||||||
|
FillColumnPattern(a_ChunkDesc, a_RelX, a_RelZ, patGrass.Get(), a_ShapeColumn);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
case biMegaTaiga:
|
||||||
|
case biMegaTaigaHills:
|
||||||
|
case biMegaSpruceTaiga:
|
||||||
|
case biMegaSpruceTaigaHills:
|
||||||
|
{
|
||||||
|
// Select the pattern to use - podzol, grass or grassless dirt:
|
||||||
|
NOISE_DATATYPE NoiseX = ((NOISE_DATATYPE)(a_ChunkDesc.GetChunkX() * cChunkDef::Width + a_RelX)) / FrequencyX;
|
||||||
|
NOISE_DATATYPE NoiseY = ((NOISE_DATATYPE)(a_ChunkDesc.GetChunkZ() * cChunkDef::Width + a_RelZ)) / FrequencyZ;
|
||||||
|
NOISE_DATATYPE Val = m_OceanFloorSelect.CubicNoise2D(NoiseX, NoiseY);
|
||||||
|
const cPattern::BlockInfo * Pattern = (Val < -0.9) ? patGrassLess.Get() : ((Val > 0) ? patPodzol.Get() : patGrass.Get());
|
||||||
|
FillColumnPattern(a_ChunkDesc, a_RelX, a_RelZ, Pattern, a_ShapeColumn);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
case biDesertHills:
|
||||||
|
case biDesert:
|
||||||
|
case biDesertM:
|
||||||
|
case biBeach:
|
||||||
|
{
|
||||||
|
FillColumnPattern(a_ChunkDesc, a_RelX, a_RelZ, patSand.Get(), a_ShapeColumn);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
case biMushroomIsland:
|
||||||
|
case biMushroomShore:
|
||||||
|
{
|
||||||
|
FillColumnPattern(a_ChunkDesc, a_RelX, a_RelZ, patMycelium.Get(), a_ShapeColumn);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
case biMesa:
|
||||||
|
case biMesaPlateauF:
|
||||||
|
case biMesaPlateau:
|
||||||
|
case biMesaBryce:
|
||||||
|
case biMesaPlateauFM:
|
||||||
|
case biMesaPlateauM:
|
||||||
|
{
|
||||||
|
// Mesa biomes need special handling, because they don't follow the usual "4 blocks from top pattern",
|
||||||
|
// instead, they provide a "from bottom" pattern with varying base height,
|
||||||
|
// usually 4 blocks below the ocean level
|
||||||
|
FillColumnMesa(a_ChunkDesc, a_RelX, a_RelZ, a_ShapeColumn);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
case biExtremeHillsPlusM:
|
||||||
|
case biExtremeHillsM:
|
||||||
|
{
|
||||||
|
// Select the pattern to use - gravel, stone or grass:
|
||||||
|
NOISE_DATATYPE NoiseX = ((NOISE_DATATYPE)(a_ChunkDesc.GetChunkX() * cChunkDef::Width + a_RelX)) / FrequencyX;
|
||||||
|
NOISE_DATATYPE NoiseY = ((NOISE_DATATYPE)(a_ChunkDesc.GetChunkZ() * cChunkDef::Width + a_RelZ)) / FrequencyZ;
|
||||||
|
NOISE_DATATYPE Val = m_OceanFloorSelect.CubicNoise2D(NoiseX, NoiseY);
|
||||||
|
const cPattern::BlockInfo * Pattern = (Val < 0.0) ? patStone.Get() : patGrass.Get();
|
||||||
|
FillColumnPattern(a_ChunkDesc, a_RelX, a_RelZ, Pattern, a_ShapeColumn);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
ASSERT(!"Unhandled biome");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} // switch (Biome)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/** Fills the specified column with the specified pattern; restarts the pattern when air is reached,
|
||||||
|
switches to ocean floor pattern if ocean is reached. Always adds bedrock at the very bottom. */
|
||||||
|
void FillColumnPattern(cChunkDesc & a_ChunkDesc, int a_RelX, int a_RelZ, const cPattern::BlockInfo * a_Pattern, const Byte * a_ShapeColumn)
|
||||||
|
{
|
||||||
|
bool HasHadWater = false;
|
||||||
|
int PatternIdx = 0;
|
||||||
|
for (int y = a_ChunkDesc.GetHeight(a_RelX, a_RelZ); y > 0; y--)
|
||||||
|
{
|
||||||
|
if (a_ShapeColumn[y] > 0)
|
||||||
|
{
|
||||||
|
// "ground" part, use the pattern:
|
||||||
|
a_ChunkDesc.SetBlockTypeMeta(a_RelX, y, a_RelZ, a_Pattern[PatternIdx].m_BlockType, a_Pattern[PatternIdx].m_BlockMeta);
|
||||||
|
PatternIdx++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// "air" or "water" part:
|
||||||
|
// Reset the pattern index to zero, so that the pattern is repeated from the top again:
|
||||||
|
PatternIdx = 0;
|
||||||
|
|
||||||
|
if (y >= m_SeaLevel)
|
||||||
|
{
|
||||||
|
// "air" part, do nothing
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
a_ChunkDesc.SetBlockType(a_RelX, y, a_RelZ, E_BLOCK_STATIONARY_WATER);
|
||||||
|
if (HasHadWater)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Select the ocean-floor pattern to use:
|
||||||
|
if (a_ChunkDesc.GetBiome(a_RelX, a_RelZ) == biDeepOcean)
|
||||||
|
{
|
||||||
|
a_Pattern = patGravel.Get();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
a_Pattern = ChooseOceanFloorPattern(a_ChunkDesc.GetChunkX(), a_ChunkDesc.GetChunkZ(), a_RelX, a_RelZ);
|
||||||
|
}
|
||||||
|
HasHadWater = true;
|
||||||
|
} // for y
|
||||||
|
a_ChunkDesc.SetBlockType(a_RelX, 0, a_RelZ, E_BLOCK_BEDROCK);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/** Fills the specified column with mesa pattern, based on the column height */
|
||||||
|
void FillColumnMesa(cChunkDesc & a_ChunkDesc, int a_RelX, int a_RelZ, const Byte * a_ShapeColumn)
|
||||||
|
{
|
||||||
|
// Frequencies for the clay floor noise:
|
||||||
|
const NOISE_DATATYPE FrequencyX = 50;
|
||||||
|
const NOISE_DATATYPE FrequencyZ = 50;
|
||||||
|
|
||||||
|
int Top = a_ChunkDesc.GetHeight(a_RelX, a_RelZ);
|
||||||
|
if (Top < m_SeaLevel)
|
||||||
|
{
|
||||||
|
// The terrain is below sealevel, handle as regular ocean with red sand floor:
|
||||||
|
FillColumnPattern(a_ChunkDesc, a_RelX, a_RelZ, patOFOrangeClay.Get(), a_ShapeColumn);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
NOISE_DATATYPE NoiseX = ((NOISE_DATATYPE)(a_ChunkDesc.GetChunkX() * cChunkDef::Width + a_RelX)) / FrequencyX;
|
||||||
|
NOISE_DATATYPE NoiseY = ((NOISE_DATATYPE)(a_ChunkDesc.GetChunkZ() * cChunkDef::Width + a_RelZ)) / FrequencyZ;
|
||||||
|
int ClayFloor = m_SeaLevel - 6 + (int)(4.f * m_MesaFloor.CubicNoise2D(NoiseX, NoiseY));
|
||||||
|
if (ClayFloor >= Top)
|
||||||
|
{
|
||||||
|
ClayFloor = Top - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Top - m_SeaLevel < 5)
|
||||||
|
{
|
||||||
|
// Simple case: top is red sand, then hardened clay down to ClayFloor, then stone:
|
||||||
|
a_ChunkDesc.SetBlockTypeMeta(a_RelX, Top, a_RelZ, E_BLOCK_SAND, E_META_SAND_RED);
|
||||||
|
for (int y = Top - 1; y >= ClayFloor; y--)
|
||||||
|
{
|
||||||
|
a_ChunkDesc.SetBlockType(a_RelX, y, a_RelZ, E_BLOCK_HARDENED_CLAY);
|
||||||
|
}
|
||||||
|
for (int y = ClayFloor - 1; y > 0; y--)
|
||||||
|
{
|
||||||
|
a_ChunkDesc.SetBlockType(a_RelX, y, a_RelZ, E_BLOCK_STONE);
|
||||||
|
}
|
||||||
|
a_ChunkDesc.SetBlockType(a_RelX, 0, a_RelZ, E_BLOCK_BEDROCK);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Difficult case: use the mesa pattern and watch for overhangs:
|
||||||
|
int PatternIdx = cChunkDef::Height - (Top - ClayFloor); // We want the block at index ClayFloor to be pattern's 256th block (first stone)
|
||||||
|
const cPattern::BlockInfo * Pattern = m_MesaPattern;
|
||||||
|
bool HasHadWater = false;
|
||||||
|
for (int y = Top; y > 0; y--)
|
||||||
|
{
|
||||||
|
if (a_ShapeColumn[y] > 0)
|
||||||
|
{
|
||||||
|
// "ground" part, use the pattern:
|
||||||
|
a_ChunkDesc.SetBlockTypeMeta(a_RelX, y, a_RelZ, Pattern[PatternIdx].m_BlockType, Pattern[PatternIdx].m_BlockMeta);
|
||||||
|
PatternIdx++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (y >= m_SeaLevel)
|
||||||
|
{
|
||||||
|
// "air" part, do nothing
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// "water" part, fill with water and choose new pattern for ocean floor, if not chosen already:
|
||||||
|
PatternIdx = 0;
|
||||||
|
a_ChunkDesc.SetBlockType(a_RelX, y, a_RelZ, E_BLOCK_STATIONARY_WATER);
|
||||||
|
if (HasHadWater)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Select the ocean-floor pattern to use:
|
||||||
|
Pattern = ChooseOceanFloorPattern(a_ChunkDesc.GetChunkX(), a_ChunkDesc.GetChunkZ(), a_RelX, a_RelZ);
|
||||||
|
HasHadWater = true;
|
||||||
|
} // for y
|
||||||
|
a_ChunkDesc.SetBlockType(a_RelX, 0, a_RelZ, E_BLOCK_BEDROCK);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/** Returns the pattern to use for an ocean floor in the specified column.
|
||||||
|
The returned pattern is guaranteed to be 256 blocks long. */
|
||||||
|
const cPattern::BlockInfo * ChooseOceanFloorPattern(int a_ChunkX, int a_ChunkZ, int a_RelX, int a_RelZ)
|
||||||
|
{
|
||||||
|
// Frequencies for the ocean floor selecting noise:
|
||||||
|
const NOISE_DATATYPE FrequencyX = 3;
|
||||||
|
const NOISE_DATATYPE FrequencyZ = 3;
|
||||||
|
|
||||||
|
// Select the ocean-floor pattern to use:
|
||||||
|
NOISE_DATATYPE NoiseX = ((NOISE_DATATYPE)(a_ChunkX * cChunkDef::Width + a_RelX)) / FrequencyX;
|
||||||
|
NOISE_DATATYPE NoiseY = ((NOISE_DATATYPE)(a_ChunkZ * cChunkDef::Width + a_RelZ)) / FrequencyZ;
|
||||||
|
NOISE_DATATYPE Val = m_OceanFloorSelect.CubicNoise2D(NoiseX, NoiseY);
|
||||||
|
if (Val < -0.95)
|
||||||
|
{
|
||||||
|
return patOFClay.Get();
|
||||||
|
}
|
||||||
|
else if (Val < 0)
|
||||||
|
{
|
||||||
|
return patOFSand.Get();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return patDirt.Get();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
/** Fills a single column with grass-based terrain (grass or water, dirt, stone). */
|
||||||
|
void FillColumnGrass(int a_RelX, int a_RelZ, const Byte * a_ShapeColumn, cChunkDesc & a_ChunkDesc)
|
||||||
|
{
|
||||||
|
static const PatternItem pattern[] =
|
||||||
|
{
|
||||||
|
{ E_BLOCK_GRASS, 0},
|
||||||
|
{ E_BLOCK_DIRT, 0},
|
||||||
|
{ E_BLOCK_DIRT, 0},
|
||||||
|
{ E_BLOCK_DIRT, 0},
|
||||||
|
} ;
|
||||||
|
FillColumnPattern(a_RelX, a_RelZ, a_ShapeColumn, a_ChunkDesc, pattern, ARRAYCOUNT(pattern));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/** Fills a single column with grass-based terrain (grass or water, dirt, stone). */
|
||||||
|
void FillColumnStone(int a_RelX, int a_RelZ, const Byte * a_ShapeColumn, cChunkDesc & a_ChunkDesc)
|
||||||
|
{
|
||||||
|
static const PatternItem pattern[] =
|
||||||
|
{
|
||||||
|
{ E_BLOCK_STONE, 0},
|
||||||
|
} ;
|
||||||
|
FillColumnPattern(a_RelX, a_RelZ, a_ShapeColumn, a_ChunkDesc, pattern, ARRAYCOUNT(pattern));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/** Fills a single column with Mesa-like terrain (variations of clay). */
|
||||||
|
void FillColumnMesa(int a_RelX, int a_RelZ, const Byte * a_ShapeColumn, cChunkDesc & a_ChunkDesc)
|
||||||
|
{
|
||||||
|
// Fill with grass and dirt on the very top of mesa plateaus:
|
||||||
|
size_t curIdx = 0;
|
||||||
|
for (int y = 255; y > m_MesaDirtLevel; y--)
|
||||||
|
{
|
||||||
|
if (a_ShapeColumn[y] > 0)
|
||||||
|
{
|
||||||
|
a_ChunkDesc.SetBlockType(a_RelX, y, a_RelZ, (curIdx > 0) ? E_BLOCK_DIRT : E_BLOCK_GRASS);
|
||||||
|
curIdx += 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
curIdx = 0;
|
||||||
|
}
|
||||||
|
} // for y
|
||||||
|
|
||||||
|
// Fill with clays from the DirtLevel down to SandLevel:
|
||||||
|
for (int y = m_MesaDirtLevel; y > m_MesaSandLevel; y--)
|
||||||
|
{
|
||||||
|
if (a_ShapeColumn[y] > 0)
|
||||||
|
{
|
||||||
|
a_ChunkDesc.SetBlockTypeMeta(a_RelX, y, a_RelZ, m_MesaPattern[y].m_BlockType, m_MesaPattern[y].m_BlockMeta);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
curIdx = 0;
|
||||||
|
}
|
||||||
|
} // for y
|
||||||
|
|
||||||
|
// If currently air, switch to red sand pattern:
|
||||||
|
static const PatternItem redSandPattern[] =
|
||||||
|
{
|
||||||
|
{ E_BLOCK_SAND, E_META_SAND_RED},
|
||||||
|
{ E_BLOCK_STAINED_CLAY, E_META_STAINED_CLAY_ORANGE},
|
||||||
|
{ E_BLOCK_STAINED_CLAY, E_META_STAINED_CLAY_ORANGE},
|
||||||
|
{ E_BLOCK_STAINED_CLAY, E_META_STAINED_CLAY_ORANGE},
|
||||||
|
};
|
||||||
|
Pattern pattern;
|
||||||
|
size_t patternSize;
|
||||||
|
if (curIdx == 0)
|
||||||
|
{
|
||||||
|
pattern = redSandPattern;
|
||||||
|
patternSize = ARRAYCOUNT(redSandPattern);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
pattern = m_MesaPattern + m_MesaSandLevel;
|
||||||
|
patternSize = static_cast<size_t>(m_MesaSandLevel);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fill with current pattern (MesaPattern or RedSand) until sealevel:
|
||||||
|
for (int y = m_MesaSandLevel; y > m_SeaLevel; y--)
|
||||||
|
{
|
||||||
|
if (a_ShapeColumn[y] > 0)
|
||||||
|
{
|
||||||
|
if (curIdx >= patternSize)
|
||||||
|
{
|
||||||
|
a_ChunkDesc.SetBlockTypeMeta(a_RelX, y, a_RelZ, E_BLOCK_STAINED_CLAY, E_META_STAINED_CLAY_ORANGE);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
a_ChunkDesc.SetBlockTypeMeta(a_RelX, y, a_RelZ, pattern[curIdx].m_BlockType, pattern[curIdx].m_BlockMeta);
|
||||||
|
}
|
||||||
|
curIdx += 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Air resets the pattern to red sand:
|
||||||
|
curIdx = 0;
|
||||||
|
pattern = redSandPattern;
|
||||||
|
patternSize = ARRAYCOUNT(redSandPattern);
|
||||||
|
}
|
||||||
|
} // for y
|
||||||
|
|
||||||
|
// If there is an ocean, fill it with water and then redsand:
|
||||||
|
int y = m_SeaLevel;
|
||||||
|
for (; y > 0; y--)
|
||||||
|
{
|
||||||
|
if ((a_ShapeColumn[y] == 0) || (curIdx >= ARRAYCOUNT(redSandPattern)))
|
||||||
|
{
|
||||||
|
// water pocket or out of red sand pattern, use stone from now on
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
a_ChunkDesc.SetBlockTypeMeta(a_RelX, y, a_RelZ, E_BLOCK_STAINED_CLAY, E_META_STAINED_CLAY_ORANGE);
|
||||||
|
curIdx = curIdx + 1;
|
||||||
|
} // for y
|
||||||
|
|
||||||
|
// The rest should be filled with stone:
|
||||||
|
for (; y > 0; y--)
|
||||||
|
{
|
||||||
|
if (a_ShapeColumn[y] > 0)
|
||||||
|
{
|
||||||
|
a_ChunkDesc.SetBlockType(a_RelX, y, a_RelZ, E_BLOCK_STONE);
|
||||||
|
}
|
||||||
|
} // for y
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/** Fills a single column with megataiga-based terrain (grass or podzol on top). */
|
||||||
|
void FillColumnMegaTaiga(int a_RelX, int a_RelZ, const Byte * a_ShapeColumn, cChunkDesc & a_ChunkDesc)
|
||||||
|
{
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/** Fills a single column with sand-based terrain (such as desert or beach). */
|
||||||
|
void FillColumnSand(int a_RelX, int a_RelZ, const Byte * a_ShapeColumn, cChunkDesc & a_ChunkDesc)
|
||||||
|
{
|
||||||
|
static const PatternItem pattern[] =
|
||||||
|
{
|
||||||
|
{ E_BLOCK_SAND, 0},
|
||||||
|
{ E_BLOCK_SAND, 0},
|
||||||
|
{ E_BLOCK_SAND, 0},
|
||||||
|
{ E_BLOCK_SANDSTONE, 0},
|
||||||
|
} ;
|
||||||
|
FillColumnPattern(a_RelX, a_RelZ, a_ShapeColumn, a_ChunkDesc, pattern, ARRAYCOUNT(pattern));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void FillColumnMycelium(int a_RelX, int a_RelZ, const Byte * a_ShapeColumn, cChunkDesc & a_ChunkDesc)
|
||||||
|
{
|
||||||
|
static const PatternItem pattern[] =
|
||||||
|
{
|
||||||
|
{ E_BLOCK_MYCELIUM, 0},
|
||||||
|
{ E_BLOCK_DIRT, 0},
|
||||||
|
{ E_BLOCK_DIRT, 0},
|
||||||
|
{ E_BLOCK_DIRT, 0},
|
||||||
|
} ;
|
||||||
|
FillColumnPattern(a_RelX, a_RelZ, a_ShapeColumn, a_ChunkDesc, pattern, ARRAYCOUNT(pattern));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/** Fills the column with the specified pattern, repeating it if there's an air pocket in between. */
|
||||||
|
void FillColumnPattern(int a_RelX, int a_RelZ, const Byte * a_ShapeColumn, cChunkDesc & a_ChunkDesc, Pattern a_Pattern, size_t a_PatternSize)
|
||||||
|
{
|
||||||
|
// Fill with pattern until sealevel:
|
||||||
|
size_t curIdx = 0;
|
||||||
|
for (int y = 255; y > m_SeaLevel; y--)
|
||||||
|
{
|
||||||
|
if (a_ShapeColumn[y] > 0)
|
||||||
|
{
|
||||||
|
// Continue with the pattern:
|
||||||
|
if (curIdx >= a_PatternSize)
|
||||||
|
{
|
||||||
|
a_ChunkDesc.SetBlockType(a_RelX, y, a_RelZ, E_BLOCK_STONE);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
a_ChunkDesc.SetBlockTypeMeta(a_RelX, y, a_RelZ, a_Pattern[curIdx].m_BlockType, a_Pattern[curIdx].m_BlockMeta);
|
||||||
|
}
|
||||||
|
curIdx += 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Air pocket, restart the pattern:
|
||||||
|
curIdx = 0;
|
||||||
|
}
|
||||||
|
} // for y
|
||||||
|
|
||||||
|
// From sealevel downward use the ocean floor pattern:
|
||||||
|
FillOceanFloor(a_RelX, a_RelZ, a_ShapeColumn, a_ChunkDesc, a_Pattern, a_PatternSize, curIdx);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/** Fills the blocks from sealevel down to bottom with ocean-floor pattern.
|
||||||
|
a_PatternStartOffset specifies the offset at which to start the pattern, in case there was air just above. */
|
||||||
|
void FillOceanFloor(int a_RelX, int a_RelZ, const Byte * a_ShapeColumn, cChunkDesc & a_ChunkDesc, Pattern a_Pattern, size_t a_PatternSize, size_t a_PatternStartOffset)
|
||||||
|
{
|
||||||
|
for (int y = m_SeaLevel; y > 0; y--)
|
||||||
|
{
|
||||||
|
if (a_ShapeColumn[y] > 0)
|
||||||
|
{
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
} // for y
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
} ;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
cTerrainCompositionGenPtr CreateCompoGenBiomal(int a_Seed)
|
||||||
|
{
|
||||||
|
return std::make_shared<cCompoGenBiomal>(a_Seed);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
21
src/Generating/CompoGenBiomal.h
Normal file
21
src/Generating/CompoGenBiomal.h
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
|
||||||
|
// CompoGenBiomal.h
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "ComposableGenerator.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/** Returns a new instance of the Biomal composition generator. */
|
||||||
|
cTerrainCompositionGenPtr CreateCompoGenBiomal(int a_Seed);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -17,6 +17,8 @@
|
|||||||
#include "StructGen.h"
|
#include "StructGen.h"
|
||||||
#include "FinishGen.h"
|
#include "FinishGen.h"
|
||||||
|
|
||||||
|
#include "CompoGenBiomal.h"
|
||||||
|
|
||||||
#include "Caves.h"
|
#include "Caves.h"
|
||||||
#include "DistortedHeightmap.h"
|
#include "DistortedHeightmap.h"
|
||||||
#include "DungeonRoomsFinisher.h"
|
#include "DungeonRoomsFinisher.h"
|
||||||
@ -39,7 +41,7 @@
|
|||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
// cTerrainCompositionGen:
|
// cTerrainCompositionGen:
|
||||||
|
|
||||||
cTerrainCompositionGenPtr cTerrainCompositionGen::CreateCompositionGen(cIniFile & a_IniFile, cBiomeGenPtr a_BiomeGen, cTerrainHeightGen & a_HeightGen, int a_Seed)
|
cTerrainCompositionGenPtr cTerrainCompositionGen::CreateCompositionGen(cIniFile & a_IniFile, cBiomeGenPtr a_BiomeGen, cTerrainShapeGenPtr a_ShapeGen, int a_Seed)
|
||||||
{
|
{
|
||||||
AString CompoGenName = a_IniFile.GetValueSet("Generator", "CompositionGen", "");
|
AString CompoGenName = a_IniFile.GetValueSet("Generator", "CompositionGen", "");
|
||||||
if (CompoGenName.empty())
|
if (CompoGenName.empty())
|
||||||
@ -48,63 +50,52 @@ cTerrainCompositionGenPtr cTerrainCompositionGen::CreateCompositionGen(cIniFile
|
|||||||
CompoGenName = "Biomal";
|
CompoGenName = "Biomal";
|
||||||
}
|
}
|
||||||
|
|
||||||
cTerrainCompositionGen * res = nullptr;
|
// Compositor list is alpha-sorted
|
||||||
if (NoCaseCompare(CompoGenName, "sameblock") == 0)
|
cTerrainCompositionGenPtr res;
|
||||||
|
if (NoCaseCompare(CompoGenName, "Biomal") == 0)
|
||||||
{
|
{
|
||||||
res = new cCompoGenSameBlock;
|
res = CreateCompoGenBiomal(a_Seed);
|
||||||
}
|
|
||||||
else if (NoCaseCompare(CompoGenName, "debugbiomes") == 0)
|
|
||||||
{
|
|
||||||
res = new cCompoGenDebugBiomes;
|
|
||||||
}
|
|
||||||
else if (NoCaseCompare(CompoGenName, "classic") == 0)
|
|
||||||
{
|
|
||||||
res = new cCompoGenClassic;
|
|
||||||
}
|
|
||||||
else if (NoCaseCompare(CompoGenName, "DistortedHeightmap") == 0)
|
|
||||||
{
|
|
||||||
res = new cDistortedHeightmap(a_Seed, a_BiomeGen);
|
|
||||||
}
|
|
||||||
else if (NoCaseCompare(CompoGenName, "end") == 0)
|
|
||||||
{
|
|
||||||
res = new cEndGen(a_Seed);
|
|
||||||
}
|
|
||||||
else if (NoCaseCompare(CompoGenName, "nether") == 0)
|
|
||||||
{
|
|
||||||
res = new cCompoGenNether(a_Seed);
|
|
||||||
}
|
}
|
||||||
else if (NoCaseCompare(CompoGenName, "BiomalNoise3D") == 0)
|
else if (NoCaseCompare(CompoGenName, "BiomalNoise3D") == 0)
|
||||||
{
|
{
|
||||||
res = new cBiomalNoise3DComposable(a_Seed, a_BiomeGen);
|
// The composition that used to be provided with BiomalNoise3D is now provided by the Biomal compositor:
|
||||||
|
res = CreateCompoGenBiomal(a_Seed);
|
||||||
|
}
|
||||||
|
else if (NoCaseCompare(CompoGenName, "Classic") == 0)
|
||||||
|
{
|
||||||
|
res = std::make_shared<cCompoGenClassic>();
|
||||||
|
}
|
||||||
|
else if (NoCaseCompare(CompoGenName, "DebugBiomes") == 0)
|
||||||
|
{
|
||||||
|
res = std::make_shared<cCompoGenDebugBiomes>();
|
||||||
|
}
|
||||||
|
else if (NoCaseCompare(CompoGenName, "DistortedHeightmap") == 0)
|
||||||
|
{
|
||||||
|
// The composition that used to be provided with DistortedHeightmap is now provided by the Biomal compositor:
|
||||||
|
res = CreateCompoGenBiomal(a_Seed);
|
||||||
|
}
|
||||||
|
else if (NoCaseCompare(CompoGenName, "End") == 0)
|
||||||
|
{
|
||||||
|
res = std::make_shared<cEndGen>(a_Seed);
|
||||||
|
}
|
||||||
|
else if (NoCaseCompare(CompoGenName, "Nether") == 0)
|
||||||
|
{
|
||||||
|
res = std::make_shared<cCompoGenNether>(a_Seed);
|
||||||
}
|
}
|
||||||
else if (NoCaseCompare(CompoGenName, "Noise3D") == 0)
|
else if (NoCaseCompare(CompoGenName, "Noise3D") == 0)
|
||||||
{
|
{
|
||||||
res = new cNoise3DComposable(a_Seed);
|
// The composition that used to be provided with Noise3D is now provided by the Biomal compositor:
|
||||||
|
res = CreateCompoGenBiomal(a_Seed);
|
||||||
}
|
}
|
||||||
else if (NoCaseCompare(CompoGenName, "biomal") == 0)
|
else if (NoCaseCompare(CompoGenName, "SameBlock") == 0)
|
||||||
{
|
{
|
||||||
res = new cCompoGenBiomal(a_Seed);
|
res = std::make_shared<cCompoGenSameBlock>();
|
||||||
|
|
||||||
/*
|
|
||||||
// Performance-testing:
|
|
||||||
LOGINFO("Measuring performance of cCompoGenBiomal...");
|
|
||||||
clock_t BeginTick = clock();
|
|
||||||
for (int x = 0; x < 500; x++)
|
|
||||||
{
|
|
||||||
cChunkDesc Desc(200 + x * 8, 200 + x * 8);
|
|
||||||
a_BiomeGen->GenBiomes(Desc.GetChunkX(), Desc.GetChunkZ(), Desc.GetBiomeMap());
|
|
||||||
a_HeightGen->GenHeightMap(Desc.GetChunkX(), Desc.GetChunkZ(), Desc.GetHeightMap());
|
|
||||||
res->ComposeTerrain(Desc);
|
|
||||||
}
|
|
||||||
clock_t Duration = clock() - BeginTick;
|
|
||||||
LOGINFO("CompositionGen for 500 chunks took %d ticks (%.02f sec)", Duration, (double)Duration / CLOCKS_PER_SEC);
|
|
||||||
//*/
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
LOGWARN("Unknown CompositionGen \"%s\", using \"Biomal\" instead.", CompoGenName.c_str());
|
LOGWARN("Unknown CompositionGen \"%s\", using \"Biomal\" instead.", CompoGenName.c_str());
|
||||||
a_IniFile.SetValue("Generator", "CompositionGen", "Biomal");
|
a_IniFile.SetValue("Generator", "CompositionGen", "Biomal");
|
||||||
return CreateCompositionGen(a_IniFile, a_BiomeGen, a_HeightGen, a_Seed);
|
return CreateCompositionGen(a_IniFile, a_BiomeGen, a_ShapeGen, a_Seed);
|
||||||
}
|
}
|
||||||
ASSERT(res != nullptr);
|
ASSERT(res != nullptr);
|
||||||
|
|
||||||
@ -124,7 +115,7 @@ cTerrainCompositionGenPtr cTerrainCompositionGen::CreateCompositionGen(cIniFile
|
|||||||
cComposableGenerator::cComposableGenerator(cChunkGenerator & a_ChunkGenerator) :
|
cComposableGenerator::cComposableGenerator(cChunkGenerator & a_ChunkGenerator) :
|
||||||
super(a_ChunkGenerator),
|
super(a_ChunkGenerator),
|
||||||
m_BiomeGen(),
|
m_BiomeGen(),
|
||||||
m_HeightGen(),
|
m_ShapeGen(),
|
||||||
m_CompositionGen()
|
m_CompositionGen()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@ -138,7 +129,7 @@ void cComposableGenerator::Initialize(cIniFile & a_IniFile)
|
|||||||
super::Initialize(a_IniFile);
|
super::Initialize(a_IniFile);
|
||||||
|
|
||||||
InitBiomeGen(a_IniFile);
|
InitBiomeGen(a_IniFile);
|
||||||
InitHeightGen(a_IniFile);
|
InitShapeGen(a_IniFile);
|
||||||
InitCompositionGen(a_IniFile);
|
InitCompositionGen(a_IniFile);
|
||||||
InitFinishGens(a_IniFile);
|
InitFinishGens(a_IniFile);
|
||||||
}
|
}
|
||||||
@ -166,15 +157,22 @@ void cComposableGenerator::DoGenerate(int a_ChunkX, int a_ChunkZ, cChunkDesc & a
|
|||||||
m_BiomeGen->GenBiomes(a_ChunkX, a_ChunkZ, a_ChunkDesc.GetBiomeMap());
|
m_BiomeGen->GenBiomes(a_ChunkX, a_ChunkZ, a_ChunkDesc.GetBiomeMap());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cChunkDesc::Shape shape;
|
||||||
if (a_ChunkDesc.IsUsingDefaultHeight())
|
if (a_ChunkDesc.IsUsingDefaultHeight())
|
||||||
{
|
{
|
||||||
m_HeightGen->GenHeightMap(a_ChunkX, a_ChunkZ, a_ChunkDesc.GetHeightMap());
|
m_ShapeGen->GenShape(a_ChunkX, a_ChunkZ, shape);
|
||||||
|
a_ChunkDesc.SetHeightFromShape(shape);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Convert the heightmap in a_ChunkDesc into shape:
|
||||||
|
a_ChunkDesc.GetShapeFromHeight(shape);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ShouldUpdateHeightmap = false;
|
bool ShouldUpdateHeightmap = false;
|
||||||
if (a_ChunkDesc.IsUsingDefaultComposition())
|
if (a_ChunkDesc.IsUsingDefaultComposition())
|
||||||
{
|
{
|
||||||
m_CompositionGen->ComposeTerrain(a_ChunkDesc);
|
m_CompositionGen->ComposeTerrain(a_ChunkDesc, shape);
|
||||||
ShouldUpdateHeightmap = true;
|
ShouldUpdateHeightmap = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -234,13 +232,15 @@ void cComposableGenerator::InitBiomeGen(cIniFile & a_IniFile)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cComposableGenerator::InitHeightGen(cIniFile & a_IniFile)
|
void cComposableGenerator::InitShapeGen(cIniFile & a_IniFile)
|
||||||
{
|
{
|
||||||
bool CacheOffByDefault = false;
|
bool CacheOffByDefault = false;
|
||||||
m_HeightGen = cTerrainHeightGen::CreateHeightGen(a_IniFile, m_BiomeGen, m_ChunkGenerator.GetSeed(), CacheOffByDefault);
|
m_ShapeGen = cTerrainShapeGen::CreateShapeGen(a_IniFile, m_BiomeGen, m_ChunkGenerator.GetSeed(), CacheOffByDefault);
|
||||||
|
|
||||||
|
/*
|
||||||
|
// TODO
|
||||||
// Add a cache, if requested:
|
// Add a cache, if requested:
|
||||||
int CacheSize = a_IniFile.GetValueSetI("Generator", "HeightGenCacheSize", CacheOffByDefault ? 0 : 64);
|
int CacheSize = a_IniFile.GetValueSetI("Generator", "ShapeGenCacheSize", CacheOffByDefault ? 0 : 64);
|
||||||
if (CacheSize > 0)
|
if (CacheSize > 0)
|
||||||
{
|
{
|
||||||
if (CacheSize < 4)
|
if (CacheSize < 4)
|
||||||
@ -253,6 +253,7 @@ void cComposableGenerator::InitHeightGen(cIniFile & a_IniFile)
|
|||||||
LOGD("Using a cache for Heightgen of size %d.", CacheSize);
|
LOGD("Using a cache for Heightgen of size %d.", CacheSize);
|
||||||
m_HeightGen = cTerrainHeightGenPtr(new cHeiGenCache(m_HeightGen, CacheSize));
|
m_HeightGen = cTerrainHeightGenPtr(new cHeiGenCache(m_HeightGen, CacheSize));
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -261,7 +262,7 @@ void cComposableGenerator::InitHeightGen(cIniFile & a_IniFile)
|
|||||||
|
|
||||||
void cComposableGenerator::InitCompositionGen(cIniFile & a_IniFile)
|
void cComposableGenerator::InitCompositionGen(cIniFile & a_IniFile)
|
||||||
{
|
{
|
||||||
m_CompositionGen = cTerrainCompositionGen::CreateCompositionGen(a_IniFile, m_BiomeGen, *m_HeightGen, m_ChunkGenerator.GetSeed());
|
m_CompositionGen = cTerrainCompositionGen::CreateCompositionGen(a_IniFile, m_BiomeGen, m_ShapeGen, m_ChunkGenerator.GetSeed());
|
||||||
|
|
||||||
int CompoGenCacheSize = a_IniFile.GetValueSetI("Generator", "CompositionGenCacheSize", 64);
|
int CompoGenCacheSize = a_IniFile.GetValueSetI("Generator", "CompositionGenCacheSize", 64);
|
||||||
if (CompoGenCacheSize > 1)
|
if (CompoGenCacheSize > 1)
|
||||||
@ -333,7 +334,7 @@ void cComposableGenerator::InitFinishGens(cIniFile & a_IniFile)
|
|||||||
int MaxSize = a_IniFile.GetValueSetI("Generator", "DungeonRoomsMaxSize", 7);
|
int MaxSize = a_IniFile.GetValueSetI("Generator", "DungeonRoomsMaxSize", 7);
|
||||||
int MinSize = a_IniFile.GetValueSetI("Generator", "DungeonRoomsMinSize", 5);
|
int MinSize = a_IniFile.GetValueSetI("Generator", "DungeonRoomsMinSize", 5);
|
||||||
AString HeightDistrib = a_IniFile.GetValueSet ("Generator", "DungeonRoomsHeightDistrib", "0, 0; 10, 10; 11, 500; 40, 500; 60, 40; 90, 1");
|
AString HeightDistrib = a_IniFile.GetValueSet ("Generator", "DungeonRoomsHeightDistrib", "0, 0; 10, 10; 11, 500; 40, 500; 60, 40; 90, 1");
|
||||||
m_FinishGens.push_back(cFinishGenPtr(new cDungeonRoomsFinisher(m_HeightGen, Seed, GridSize, MaxSize, MinSize, HeightDistrib)));
|
m_FinishGens.push_back(cFinishGenPtr(new cDungeonRoomsFinisher(m_ShapeGen, Seed, GridSize, MaxSize, MinSize, HeightDistrib)));
|
||||||
}
|
}
|
||||||
else if (NoCaseCompare(*itr, "Ice") == 0)
|
else if (NoCaseCompare(*itr, "Ice") == 0)
|
||||||
{
|
{
|
||||||
@ -342,7 +343,7 @@ void cComposableGenerator::InitFinishGens(cIniFile & a_IniFile)
|
|||||||
else if (NoCaseCompare(*itr, "LavaLakes") == 0)
|
else if (NoCaseCompare(*itr, "LavaLakes") == 0)
|
||||||
{
|
{
|
||||||
int Probability = a_IniFile.GetValueSetI("Generator", "LavaLakesProbability", 10);
|
int Probability = a_IniFile.GetValueSetI("Generator", "LavaLakesProbability", 10);
|
||||||
m_FinishGens.push_back(cFinishGenPtr(new cStructGenLakes(Seed * 5 + 16873, E_BLOCK_STATIONARY_LAVA, m_HeightGen, Probability)));
|
m_FinishGens.push_back(cFinishGenPtr(new cStructGenLakes(Seed * 5 + 16873, E_BLOCK_STATIONARY_LAVA, m_ShapeGen, Probability)));
|
||||||
}
|
}
|
||||||
else if (NoCaseCompare(*itr, "LavaSprings") == 0)
|
else if (NoCaseCompare(*itr, "LavaSprings") == 0)
|
||||||
{
|
{
|
||||||
@ -580,7 +581,7 @@ void cComposableGenerator::InitFinishGens(cIniFile & a_IniFile)
|
|||||||
}
|
}
|
||||||
else if (NoCaseCompare(*itr, "Trees") == 0)
|
else if (NoCaseCompare(*itr, "Trees") == 0)
|
||||||
{
|
{
|
||||||
m_FinishGens.push_back(cFinishGenPtr(new cStructGenTrees(Seed, m_BiomeGen, m_HeightGen, m_CompositionGen)));
|
m_FinishGens.push_back(cFinishGenPtr(new cStructGenTrees(Seed, m_BiomeGen, m_ShapeGen, m_CompositionGen)));
|
||||||
}
|
}
|
||||||
else if (NoCaseCompare(*itr, "UnderwaterBases") == 0)
|
else if (NoCaseCompare(*itr, "UnderwaterBases") == 0)
|
||||||
{
|
{
|
||||||
@ -588,7 +589,7 @@ void cComposableGenerator::InitFinishGens(cIniFile & a_IniFile)
|
|||||||
int MaxOffset = a_IniFile.GetValueSetI("Generator", "UnderwaterBaseMaxOffset", 128);
|
int MaxOffset = a_IniFile.GetValueSetI("Generator", "UnderwaterBaseMaxOffset", 128);
|
||||||
int MaxDepth = a_IniFile.GetValueSetI("Generator", "UnderwaterBaseMaxDepth", 7);
|
int MaxDepth = a_IniFile.GetValueSetI("Generator", "UnderwaterBaseMaxDepth", 7);
|
||||||
int MaxSize = a_IniFile.GetValueSetI("Generator", "UnderwaterBaseMaxSize", 128);
|
int MaxSize = a_IniFile.GetValueSetI("Generator", "UnderwaterBaseMaxSize", 128);
|
||||||
m_FinishGens.push_back(cFinishGenPtr(new cUnderwaterBaseGen(Seed, GridSize, MaxOffset, MaxDepth, MaxSize, m_BiomeGen)));
|
m_FinishGens.push_back(std::make_shared<cUnderwaterBaseGen>(Seed, GridSize, MaxOffset, MaxDepth, MaxSize, m_BiomeGen));
|
||||||
}
|
}
|
||||||
else if (NoCaseCompare(*itr, "Villages") == 0)
|
else if (NoCaseCompare(*itr, "Villages") == 0)
|
||||||
{
|
{
|
||||||
@ -598,12 +599,12 @@ void cComposableGenerator::InitFinishGens(cIniFile & a_IniFile)
|
|||||||
int MaxSize = a_IniFile.GetValueSetI("Generator", "VillageMaxSize", 128);
|
int MaxSize = a_IniFile.GetValueSetI("Generator", "VillageMaxSize", 128);
|
||||||
int MinDensity = a_IniFile.GetValueSetI("Generator", "VillageMinDensity", 50);
|
int MinDensity = a_IniFile.GetValueSetI("Generator", "VillageMinDensity", 50);
|
||||||
int MaxDensity = a_IniFile.GetValueSetI("Generator", "VillageMaxDensity", 80);
|
int MaxDensity = a_IniFile.GetValueSetI("Generator", "VillageMaxDensity", 80);
|
||||||
m_FinishGens.push_back(cFinishGenPtr(new cVillageGen(Seed, GridSize, MaxOffset, MaxDepth, MaxSize, MinDensity, MaxDensity, m_BiomeGen, m_HeightGen)));
|
m_FinishGens.push_back(std::make_shared<cVillageGen>(Seed, GridSize, MaxOffset, MaxDepth, MaxSize, MinDensity, MaxDensity, m_BiomeGen, m_CompositedHeightCache));
|
||||||
}
|
}
|
||||||
else if (NoCaseCompare(*itr, "WaterLakes") == 0)
|
else if (NoCaseCompare(*itr, "WaterLakes") == 0)
|
||||||
{
|
{
|
||||||
int Probability = a_IniFile.GetValueSetI("Generator", "WaterLakesProbability", 25);
|
int Probability = a_IniFile.GetValueSetI("Generator", "WaterLakesProbability", 25);
|
||||||
m_FinishGens.push_back(cFinishGenPtr(new cStructGenLakes(Seed * 3 + 652, E_BLOCK_STATIONARY_WATER, m_HeightGen, Probability)));
|
m_FinishGens.push_back(cFinishGenPtr(new cStructGenLakes(Seed * 3 + 652, E_BLOCK_STATIONARY_WATER, m_ShapeGen, Probability)));
|
||||||
}
|
}
|
||||||
else if (NoCaseCompare(*itr, "WaterSprings") == 0)
|
else if (NoCaseCompare(*itr, "WaterSprings") == 0)
|
||||||
{
|
{
|
||||||
|
@ -26,20 +26,16 @@ See http://forum.mc-server.org/showthread.php?tid=409 for details.
|
|||||||
|
|
||||||
// Forward-declare the shared pointers to subgenerator classes:
|
// Forward-declare the shared pointers to subgenerator classes:
|
||||||
class cBiomeGen;
|
class cBiomeGen;
|
||||||
|
class cTerrainShapeGen;
|
||||||
class cTerrainHeightGen;
|
class cTerrainHeightGen;
|
||||||
class cTerrainCompositionGen;
|
class cTerrainCompositionGen;
|
||||||
class cFinishGen;
|
class cFinishGen;
|
||||||
typedef SharedPtr<cBiomeGen> cBiomeGenPtr;
|
typedef SharedPtr<cBiomeGen> cBiomeGenPtr;
|
||||||
|
typedef SharedPtr<cTerrainShapeGen> cTerrainShapeGenPtr;
|
||||||
typedef SharedPtr<cTerrainHeightGen> cTerrainHeightGenPtr;
|
typedef SharedPtr<cTerrainHeightGen> cTerrainHeightGenPtr;
|
||||||
typedef SharedPtr<cTerrainCompositionGen> cTerrainCompositionGenPtr;
|
typedef SharedPtr<cTerrainCompositionGen> cTerrainCompositionGenPtr;
|
||||||
typedef SharedPtr<cFinishGen> cFinishGenPtr;
|
typedef SharedPtr<cFinishGen> cFinishGenPtr;
|
||||||
|
|
||||||
// fwd: Noise3DGenerator.h
|
|
||||||
class cNoise3DComposable;
|
|
||||||
|
|
||||||
// fwd: DistortedHeightmap.h
|
|
||||||
class cDistortedHeightmap;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -70,28 +66,54 @@ public:
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
/** The interface that a terrain height generator must implement
|
/** The interface that a terrain shape generator must implement
|
||||||
A terrain height generator takes chunk coords on input and outputs an array of terrain heights for that chunk.
|
A terrain shape generator takes chunk coords on input and outputs a 3D array of "shape" for that chunk. The shape here
|
||||||
The output array is sequenced in the same way as the BiomeGen's biome data.
|
represents the distinction between air and solid; there's no representation of Water since that is added by the
|
||||||
|
composition geenrator.
|
||||||
|
The output array is indexed [y + 256 * z + 16 * 256 * x], so that it's fast to later compose a single column of the terrain,
|
||||||
|
which is the dominant operation following the shape generation.
|
||||||
The generator may request biome information from the underlying BiomeGen, it may even request information for
|
The generator may request biome information from the underlying BiomeGen, it may even request information for
|
||||||
other chunks than the one it's currently generating (possibly neighbors - for averaging)
|
other chunks than the one it's currently generating (neighbors - for averaging)
|
||||||
*/
|
*/
|
||||||
|
class cTerrainShapeGen
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual ~cTerrainShapeGen() {} // Force a virtual destructor in descendants
|
||||||
|
|
||||||
|
/** Generates the shape for the given chunk */
|
||||||
|
virtual void GenShape(int a_ChunkX, int a_ChunkZ, cChunkDesc::Shape & a_Shape) = 0;
|
||||||
|
|
||||||
|
/** Reads parameters from the ini file, prepares generator for use. */
|
||||||
|
virtual void InitializeShapeGen(cIniFile & a_IniFile) {}
|
||||||
|
|
||||||
|
/** Creates the correct TerrainShapeGen descendant based on the ini file settings and the seed provided.
|
||||||
|
a_BiomeGen is the underlying biome generator, some shape generators may depend on it providing additional biomes data around the chunk
|
||||||
|
a_CacheOffByDefault gets set to whether the cache should be disabled by default
|
||||||
|
Implemented in ShapeGen.cpp!
|
||||||
|
*/
|
||||||
|
static cTerrainShapeGenPtr CreateShapeGen(cIniFile & a_IniFile, cBiomeGenPtr a_BiomeGen, int a_Seed, bool & a_CacheOffByDefault);
|
||||||
|
} ;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/** The interface that is used to query terrain height from the shape generator.
|
||||||
|
Usually the structure generators require only the final heightmap, and generating the whole shape only to
|
||||||
|
consume the heightmap is wasteful, so this interface is used instead; it has a cache implemented over it so
|
||||||
|
that data is retained. */
|
||||||
class cTerrainHeightGen
|
class cTerrainHeightGen
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
virtual ~cTerrainHeightGen() {} // Force a virtual destructor in descendants
|
virtual ~cTerrainHeightGen() {} // Force a virtual destructor in descendants
|
||||||
|
|
||||||
/** Generates heightmap for the given chunk */
|
/** Retrieves the heightmap for the specified chunk. */
|
||||||
virtual void GenHeightMap(int a_ChunkX, int a_ChunkZ, cChunkDef::HeightMap & a_HeightMap) = 0;
|
virtual void GenHeightMap(int a_ChunkX, int a_ChunkZ, cChunkDef::HeightMap & a_HeightMap) = 0;
|
||||||
|
|
||||||
/** Reads parameters from the ini file, prepares generator for use. */
|
/** Initializes the generator, reading its parameters from the INI file. */
|
||||||
virtual void InitializeHeightGen(cIniFile & a_IniFile) {}
|
virtual void InitializeHeightGen(cIniFile & a_IniFile) {}
|
||||||
|
|
||||||
/** Creates the correct TerrainHeightGen descendant based on the ini file settings and the seed provided.
|
/** Creates a cTerrainHeightGen descendant based on the INI file settings. */
|
||||||
a_BiomeGen is the underlying biome generator, some height generators may depend on it to generate more biomes
|
|
||||||
a_CacheOffByDefault gets set to whether the cache should be disabled by default
|
|
||||||
Implemented in HeiGen.cpp!
|
|
||||||
*/
|
|
||||||
static cTerrainHeightGenPtr CreateHeightGen(cIniFile & a_IniFile, cBiomeGenPtr a_BiomeGen, int a_Seed, bool & a_CacheOffByDefault);
|
static cTerrainHeightGenPtr CreateHeightGen(cIniFile & a_IniFile, cBiomeGenPtr a_BiomeGen, int a_Seed, bool & a_CacheOffByDefault);
|
||||||
} ;
|
} ;
|
||||||
|
|
||||||
@ -109,16 +131,18 @@ class cTerrainCompositionGen
|
|||||||
public:
|
public:
|
||||||
virtual ~cTerrainCompositionGen() {} // Force a virtual destructor in descendants
|
virtual ~cTerrainCompositionGen() {} // Force a virtual destructor in descendants
|
||||||
|
|
||||||
virtual void ComposeTerrain(cChunkDesc & a_ChunkDesc) = 0;
|
/** Generates the chunk's composition into a_ChunkDesc, using the terrain shape provided in a_Shape.
|
||||||
|
Is expected to fill a_ChunkDesc's heightmap with the data from a_Shape. */
|
||||||
|
virtual void ComposeTerrain(cChunkDesc & a_ChunkDesc, const cChunkDesc::Shape & a_Shape) = 0;
|
||||||
|
|
||||||
/** Reads parameters from the ini file, prepares generator for use. */
|
/** Reads parameters from the ini file, prepares generator for use. */
|
||||||
virtual void InitializeCompoGen(cIniFile & a_IniFile) {}
|
virtual void InitializeCompoGen(cIniFile & a_IniFile) {}
|
||||||
|
|
||||||
/** Creates the correct TerrainCompositionGen descendant based on the ini file settings and the seed provided.
|
/** Creates the correct TerrainCompositionGen descendant based on the ini file settings and the seed provided.
|
||||||
a_BiomeGen is the underlying biome generator, some composition generators may depend on it to generate more biomes
|
a_BiomeGen is the underlying biome generator, some composition generators may depend on it providing additional biomes around the chunk
|
||||||
a_HeightGen is the underlying height generator, some composition generators may depend on it providing additional values
|
a_ShapeGen is the underlying shape generator, some composition generators may depend on it providing additional shape around the chunk
|
||||||
*/
|
*/
|
||||||
static cTerrainCompositionGenPtr CreateCompositionGen(cIniFile & a_IniFile, cBiomeGenPtr a_BiomeGen, cTerrainHeightGen & a_HeightGen, int a_Seed);
|
static cTerrainCompositionGenPtr CreateCompositionGen(cIniFile & a_IniFile, cBiomeGenPtr a_BiomeGen, cTerrainShapeGenPtr a_ShapeGen, int a_Seed);
|
||||||
} ;
|
} ;
|
||||||
|
|
||||||
|
|
||||||
@ -128,7 +152,7 @@ public:
|
|||||||
/** The interface that a finisher must implement
|
/** The interface that a finisher must implement
|
||||||
Finisher implements changes to the chunk after the rough terrain has been generated.
|
Finisher implements changes to the chunk after the rough terrain has been generated.
|
||||||
Examples of finishers are trees, snow, ore, lilypads and others.
|
Examples of finishers are trees, snow, ore, lilypads and others.
|
||||||
Note that a worldgenerator may contain multiple finishers.
|
Note that a worldgenerator may contain multiple finishers, chained one after another.
|
||||||
Also note that previously we used to distinguish between a structuregen and a finisher; this distinction is
|
Also note that previously we used to distinguish between a structuregen and a finisher; this distinction is
|
||||||
no longer relevant, all structure generators are considered finishers now (#398)
|
no longer relevant, all structure generators are considered finishers now (#398)
|
||||||
*/
|
*/
|
||||||
@ -154,23 +178,34 @@ class cComposableGenerator :
|
|||||||
public:
|
public:
|
||||||
cComposableGenerator(cChunkGenerator & a_ChunkGenerator);
|
cComposableGenerator(cChunkGenerator & a_ChunkGenerator);
|
||||||
|
|
||||||
|
// cChunkGenerator::cGenerator overrides:
|
||||||
virtual void Initialize(cIniFile & a_IniFile) override;
|
virtual void Initialize(cIniFile & a_IniFile) override;
|
||||||
virtual void GenerateBiomes(int a_ChunkX, int a_ChunkZ, cChunkDef::BiomeMap & a_BiomeMap) override;
|
virtual void GenerateBiomes(int a_ChunkX, int a_ChunkZ, cChunkDef::BiomeMap & a_BiomeMap) override;
|
||||||
virtual void DoGenerate(int a_ChunkX, int a_ChunkZ, cChunkDesc & a_ChunkDesc) override;
|
virtual void DoGenerate(int a_ChunkX, int a_ChunkZ, cChunkDesc & a_ChunkDesc) override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
// The generation composition:
|
// The generator's composition:
|
||||||
cBiomeGenPtr m_BiomeGen;
|
/** The biome generator. */
|
||||||
cTerrainHeightGenPtr m_HeightGen;
|
cBiomeGenPtr m_BiomeGen;
|
||||||
|
|
||||||
|
/** The terrain shape generator. */
|
||||||
|
cTerrainShapeGenPtr m_ShapeGen;
|
||||||
|
|
||||||
|
/** The terrain composition generator. */
|
||||||
cTerrainCompositionGenPtr m_CompositionGen;
|
cTerrainCompositionGenPtr m_CompositionGen;
|
||||||
cFinishGenList m_FinishGens;
|
|
||||||
|
/** The cache for the heights of the composited terrain. */
|
||||||
|
cTerrainHeightGenPtr m_CompositedHeightCache;
|
||||||
|
|
||||||
|
/** The finisher generators, in the order in which they are applied. */
|
||||||
|
cFinishGenList m_FinishGens;
|
||||||
|
|
||||||
|
|
||||||
/** Reads the biome gen settings from the ini and initializes m_BiomeGen accordingly */
|
/** Reads the BiomeGen settings from the ini and initializes m_BiomeGen accordingly */
|
||||||
void InitBiomeGen(cIniFile & a_IniFile);
|
void InitBiomeGen(cIniFile & a_IniFile);
|
||||||
|
|
||||||
/** Reads the HeightGen settings from the ini and initializes m_HeightGen accordingly */
|
/** Reads the ShapeGen settings from the ini and initializes m_ShapeGen accordingly */
|
||||||
void InitHeightGen(cIniFile & a_IniFile);
|
void InitShapeGen(cIniFile & a_IniFile);
|
||||||
|
|
||||||
/** Reads the CompositionGen settings from the ini and initializes m_CompositionGen accordingly */
|
/** Reads the CompositionGen settings from the ini and initializes m_CompositionGen accordingly */
|
||||||
void InitCompositionGen(cIniFile & a_IniFile);
|
void InitCompositionGen(cIniFile & a_IniFile);
|
||||||
|
@ -14,163 +14,6 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
// cPattern:
|
|
||||||
|
|
||||||
/// This class is used to store a column pattern initialized at runtime,
|
|
||||||
/// so that the program doesn't need to explicitly set 256 values for each pattern
|
|
||||||
/// Each pattern has 256 blocks so that there's no need to check pattern bounds when assigning the
|
|
||||||
/// pattern - there will always be enough pattern left, even for the whole chunk height
|
|
||||||
class cPattern
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
cPattern(cDistortedHeightmap::sBlockInfo * a_TopBlocks, size_t a_Count)
|
|
||||||
{
|
|
||||||
// Copy the pattern into the top:
|
|
||||||
for (size_t i = 0; i < a_Count; i++)
|
|
||||||
{
|
|
||||||
m_Pattern[i] = a_TopBlocks[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fill the rest with stone:
|
|
||||||
static cDistortedHeightmap::sBlockInfo Stone = {E_BLOCK_STONE, 0};
|
|
||||||
for (size_t i = a_Count; i < cChunkDef::Height; i++)
|
|
||||||
{
|
|
||||||
m_Pattern[i] = Stone;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const cDistortedHeightmap::sBlockInfo * Get(void) const { return m_Pattern; }
|
|
||||||
|
|
||||||
protected:
|
|
||||||
cDistortedHeightmap::sBlockInfo m_Pattern[cChunkDef::Height];
|
|
||||||
} ;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
// The arrays to use for the top block pattern definitions:
|
|
||||||
|
|
||||||
static cDistortedHeightmap::sBlockInfo tbGrass[] =
|
|
||||||
{
|
|
||||||
{E_BLOCK_GRASS, 0},
|
|
||||||
{E_BLOCK_DIRT, E_META_DIRT_NORMAL},
|
|
||||||
{E_BLOCK_DIRT, E_META_DIRT_NORMAL},
|
|
||||||
{E_BLOCK_DIRT, E_META_DIRT_NORMAL},
|
|
||||||
} ;
|
|
||||||
|
|
||||||
static cDistortedHeightmap::sBlockInfo tbSand[] =
|
|
||||||
{
|
|
||||||
{ E_BLOCK_SAND, 0},
|
|
||||||
{ E_BLOCK_SAND, 0},
|
|
||||||
{ E_BLOCK_SAND, 0},
|
|
||||||
{ E_BLOCK_SANDSTONE, 0},
|
|
||||||
} ;
|
|
||||||
|
|
||||||
static cDistortedHeightmap::sBlockInfo tbDirt[] =
|
|
||||||
{
|
|
||||||
{E_BLOCK_DIRT, E_META_DIRT_NORMAL},
|
|
||||||
{E_BLOCK_DIRT, E_META_DIRT_NORMAL},
|
|
||||||
{E_BLOCK_DIRT, E_META_DIRT_NORMAL},
|
|
||||||
{E_BLOCK_DIRT, E_META_DIRT_NORMAL},
|
|
||||||
} ;
|
|
||||||
|
|
||||||
static cDistortedHeightmap::sBlockInfo tbPodzol[] =
|
|
||||||
{
|
|
||||||
{E_BLOCK_DIRT, E_META_DIRT_PODZOL},
|
|
||||||
{E_BLOCK_DIRT, E_META_DIRT_NORMAL},
|
|
||||||
{E_BLOCK_DIRT, E_META_DIRT_NORMAL},
|
|
||||||
{E_BLOCK_DIRT, E_META_DIRT_NORMAL},
|
|
||||||
} ;
|
|
||||||
|
|
||||||
static cDistortedHeightmap::sBlockInfo tbGrassLess[] =
|
|
||||||
{
|
|
||||||
{E_BLOCK_DIRT, E_META_DIRT_GRASSLESS},
|
|
||||||
{E_BLOCK_DIRT, E_META_DIRT_NORMAL},
|
|
||||||
{E_BLOCK_DIRT, E_META_DIRT_NORMAL},
|
|
||||||
{E_BLOCK_DIRT, E_META_DIRT_NORMAL},
|
|
||||||
} ;
|
|
||||||
|
|
||||||
static cDistortedHeightmap::sBlockInfo tbMycelium[] =
|
|
||||||
{
|
|
||||||
{E_BLOCK_MYCELIUM, 0},
|
|
||||||
{E_BLOCK_DIRT, 0},
|
|
||||||
{E_BLOCK_DIRT, 0},
|
|
||||||
{E_BLOCK_DIRT, 0},
|
|
||||||
} ;
|
|
||||||
|
|
||||||
static cDistortedHeightmap::sBlockInfo tbGravel[] =
|
|
||||||
{
|
|
||||||
{E_BLOCK_GRAVEL, 0},
|
|
||||||
{E_BLOCK_GRAVEL, 0},
|
|
||||||
{E_BLOCK_GRAVEL, 0},
|
|
||||||
{E_BLOCK_STONE, 0},
|
|
||||||
} ;
|
|
||||||
|
|
||||||
static cDistortedHeightmap::sBlockInfo tbStone[] =
|
|
||||||
{
|
|
||||||
{E_BLOCK_STONE, 0},
|
|
||||||
{E_BLOCK_STONE, 0},
|
|
||||||
{E_BLOCK_STONE, 0},
|
|
||||||
{E_BLOCK_STONE, 0},
|
|
||||||
} ;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
// Ocean floor pattern top-block definitions:
|
|
||||||
|
|
||||||
static cDistortedHeightmap::sBlockInfo tbOFSand[] =
|
|
||||||
{
|
|
||||||
{E_BLOCK_SAND, 0},
|
|
||||||
{E_BLOCK_SAND, 0},
|
|
||||||
{E_BLOCK_SAND, 0},
|
|
||||||
{E_BLOCK_SANDSTONE, 0}
|
|
||||||
} ;
|
|
||||||
|
|
||||||
static cDistortedHeightmap::sBlockInfo tbOFClay[] =
|
|
||||||
{
|
|
||||||
{ E_BLOCK_CLAY, 0},
|
|
||||||
{ E_BLOCK_CLAY, 0},
|
|
||||||
{ E_BLOCK_SAND, 0},
|
|
||||||
{ E_BLOCK_SAND, 0},
|
|
||||||
} ;
|
|
||||||
|
|
||||||
static cDistortedHeightmap::sBlockInfo tbOFRedSand[] =
|
|
||||||
{
|
|
||||||
{ E_BLOCK_SAND, E_META_SAND_RED},
|
|
||||||
{ E_BLOCK_SAND, E_META_SAND_RED},
|
|
||||||
{ E_BLOCK_SAND, E_META_SAND_RED},
|
|
||||||
{ E_BLOCK_SANDSTONE, 0},
|
|
||||||
} ;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
// Individual patterns to use:
|
|
||||||
|
|
||||||
static cPattern patGrass (tbGrass, ARRAYCOUNT(tbGrass));
|
|
||||||
static cPattern patSand (tbSand, ARRAYCOUNT(tbSand));
|
|
||||||
static cPattern patDirt (tbDirt, ARRAYCOUNT(tbDirt));
|
|
||||||
static cPattern patPodzol (tbPodzol, ARRAYCOUNT(tbPodzol));
|
|
||||||
static cPattern patGrassLess(tbGrassLess, ARRAYCOUNT(tbGrassLess));
|
|
||||||
static cPattern patMycelium (tbMycelium, ARRAYCOUNT(tbMycelium));
|
|
||||||
static cPattern patGravel (tbGravel, ARRAYCOUNT(tbGravel));
|
|
||||||
static cPattern patStone (tbStone, ARRAYCOUNT(tbStone));
|
|
||||||
|
|
||||||
static cPattern patOFSand (tbOFSand, ARRAYCOUNT(tbOFSand));
|
|
||||||
static cPattern patOFClay (tbOFClay, ARRAYCOUNT(tbOFClay));
|
|
||||||
static cPattern patOFRedSand(tbOFRedSand, ARRAYCOUNT(tbOFRedSand));
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
// cDistortedHeightmap:
|
// cDistortedHeightmap:
|
||||||
|
|
||||||
@ -237,7 +80,7 @@ const cDistortedHeightmap::sGenParam cDistortedHeightmap::m_GenParam[256] =
|
|||||||
{0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, // 110 .. 119
|
{0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, // 110 .. 119
|
||||||
{0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, // 120 .. 128
|
{0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, // 120 .. 128
|
||||||
|
|
||||||
// Release 1.7 /* biome variants:
|
// Release 1.7 biome variants:
|
||||||
/* biSunflowerPlains */ { 1.0f, 1.0f}, // 129
|
/* biSunflowerPlains */ { 1.0f, 1.0f}, // 129
|
||||||
/* biDesertM */ { 1.0f, 1.0f}, // 130
|
/* biDesertM */ { 1.0f, 1.0f}, // 130
|
||||||
/* biExtremeHillsM */ {16.0f, 16.0f}, // 131
|
/* biExtremeHillsM */ {16.0f, 16.0f}, // 131
|
||||||
@ -279,8 +122,6 @@ const cDistortedHeightmap::sGenParam cDistortedHeightmap::m_GenParam[256] =
|
|||||||
cDistortedHeightmap::cDistortedHeightmap(int a_Seed, cBiomeGenPtr a_BiomeGen) :
|
cDistortedHeightmap::cDistortedHeightmap(int a_Seed, cBiomeGenPtr a_BiomeGen) :
|
||||||
m_NoiseDistortX(a_Seed + 1000),
|
m_NoiseDistortX(a_Seed + 1000),
|
||||||
m_NoiseDistortZ(a_Seed + 2000),
|
m_NoiseDistortZ(a_Seed + 2000),
|
||||||
m_OceanFloorSelect(a_Seed + 3000),
|
|
||||||
m_MesaFloor(a_Seed + 4000),
|
|
||||||
m_BiomeGen(a_BiomeGen),
|
m_BiomeGen(a_BiomeGen),
|
||||||
m_UnderlyingHeiGen(new cHeiGenBiomal(a_Seed, a_BiomeGen)),
|
m_UnderlyingHeiGen(new cHeiGenBiomal(a_Seed, a_BiomeGen)),
|
||||||
m_HeightGen(m_UnderlyingHeiGen, 64),
|
m_HeightGen(m_UnderlyingHeiGen, 64),
|
||||||
@ -293,8 +134,6 @@ cDistortedHeightmap::cDistortedHeightmap(int a_Seed, cBiomeGenPtr a_BiomeGen) :
|
|||||||
m_NoiseDistortZ.AddOctave((NOISE_DATATYPE)1, (NOISE_DATATYPE)0.5);
|
m_NoiseDistortZ.AddOctave((NOISE_DATATYPE)1, (NOISE_DATATYPE)0.5);
|
||||||
m_NoiseDistortZ.AddOctave((NOISE_DATATYPE)0.5, (NOISE_DATATYPE)1);
|
m_NoiseDistortZ.AddOctave((NOISE_DATATYPE)0.5, (NOISE_DATATYPE)1);
|
||||||
m_NoiseDistortZ.AddOctave((NOISE_DATATYPE)0.25, (NOISE_DATATYPE)2);
|
m_NoiseDistortZ.AddOctave((NOISE_DATATYPE)0.25, (NOISE_DATATYPE)2);
|
||||||
|
|
||||||
InitMesaPattern(a_Seed);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -309,7 +148,7 @@ void cDistortedHeightmap::Initialize(cIniFile & a_IniFile)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Read the params from the INI file:
|
// Read the params from the INI file:
|
||||||
m_SeaLevel = a_IniFile.GetValueSetI("Generator", "DistortedHeightmapSeaLevel", 62);
|
m_SeaLevel = a_IniFile.GetValueSetI("Generator", "SeaLevel", 62);
|
||||||
m_FrequencyX = (NOISE_DATATYPE)a_IniFile.GetValueSetF("Generator", "DistortedHeightmapFrequencyX", 10);
|
m_FrequencyX = (NOISE_DATATYPE)a_IniFile.GetValueSetF("Generator", "DistortedHeightmapFrequencyX", 10);
|
||||||
m_FrequencyY = (NOISE_DATATYPE)a_IniFile.GetValueSetF("Generator", "DistortedHeightmapFrequencyY", 10);
|
m_FrequencyY = (NOISE_DATATYPE)a_IniFile.GetValueSetF("Generator", "DistortedHeightmapFrequencyY", 10);
|
||||||
m_FrequencyZ = (NOISE_DATATYPE)a_IniFile.GetValueSetF("Generator", "DistortedHeightmapFrequencyZ", 10);
|
m_FrequencyZ = (NOISE_DATATYPE)a_IniFile.GetValueSetF("Generator", "DistortedHeightmapFrequencyZ", 10);
|
||||||
@ -321,89 +160,6 @@ void cDistortedHeightmap::Initialize(cIniFile & a_IniFile)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cDistortedHeightmap::InitMesaPattern(int a_Seed)
|
|
||||||
{
|
|
||||||
// Stone in the bottom half of the pattern:
|
|
||||||
for (int i = cChunkDef::Height; i < 2 * cChunkDef::Height; i++)
|
|
||||||
{
|
|
||||||
m_MesaPattern[i].BlockMeta = 0;
|
|
||||||
m_MesaPattern[i].BlockType = E_BLOCK_STONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Stained and hardened clay in the top half of the pattern
|
|
||||||
// In a loop, choose whether to use one or two layers of stained clay, then choose a color and width for each layer
|
|
||||||
// Separate each group with another layer of hardened clay
|
|
||||||
cNoise PatternNoise((unsigned)a_Seed);
|
|
||||||
static NIBBLETYPE AllowedColors[] =
|
|
||||||
{
|
|
||||||
E_META_STAINED_CLAY_YELLOW,
|
|
||||||
E_META_STAINED_CLAY_YELLOW,
|
|
||||||
E_META_STAINED_CLAY_RED,
|
|
||||||
E_META_STAINED_CLAY_RED,
|
|
||||||
E_META_STAINED_CLAY_WHITE,
|
|
||||||
E_META_STAINED_CLAY_BROWN,
|
|
||||||
E_META_STAINED_CLAY_BROWN,
|
|
||||||
E_META_STAINED_CLAY_BROWN,
|
|
||||||
E_META_STAINED_CLAY_ORANGE,
|
|
||||||
E_META_STAINED_CLAY_ORANGE,
|
|
||||||
E_META_STAINED_CLAY_ORANGE,
|
|
||||||
E_META_STAINED_CLAY_ORANGE,
|
|
||||||
E_META_STAINED_CLAY_ORANGE,
|
|
||||||
E_META_STAINED_CLAY_ORANGE,
|
|
||||||
E_META_STAINED_CLAY_LIGHTGRAY,
|
|
||||||
} ;
|
|
||||||
static int LayerSizes[] = // Adjust the chance so that thinner layers occur more commonly
|
|
||||||
{
|
|
||||||
1, 1, 1, 1, 1, 1,
|
|
||||||
2, 2, 2, 2,
|
|
||||||
3, 3,
|
|
||||||
} ;
|
|
||||||
int Idx = cChunkDef::Height - 1;
|
|
||||||
while (Idx >= 0)
|
|
||||||
{
|
|
||||||
// A layer group of 1 - 2 color stained clay:
|
|
||||||
int Random = PatternNoise.IntNoise1DInt(Idx) / 7;
|
|
||||||
int NumLayers = (Random % 2) + 1;
|
|
||||||
Random /= 2;
|
|
||||||
for (int Lay = 0; Lay < NumLayers; Lay++)
|
|
||||||
{
|
|
||||||
int NumBlocks = LayerSizes[(Random % ARRAYCOUNT(LayerSizes))];
|
|
||||||
NIBBLETYPE Color = AllowedColors[(Random / 4) % ARRAYCOUNT(AllowedColors)];
|
|
||||||
if (
|
|
||||||
((NumBlocks == 3) && (NumLayers == 2)) || // In two-layer mode disallow the 3-high layers:
|
|
||||||
(Color == E_META_STAINED_CLAY_WHITE)) // White stained clay can ever be only 1 block high
|
|
||||||
{
|
|
||||||
NumBlocks = 1;
|
|
||||||
}
|
|
||||||
NumBlocks = std::min(Idx + 1, NumBlocks); // Limit by Idx so that we don't have to check inside the loop
|
|
||||||
Random /= 32;
|
|
||||||
for (int Block = 0; Block < NumBlocks; Block++, Idx--)
|
|
||||||
{
|
|
||||||
m_MesaPattern[Idx].BlockMeta = Color;
|
|
||||||
m_MesaPattern[Idx].BlockType = E_BLOCK_STAINED_CLAY;
|
|
||||||
} // for Block
|
|
||||||
} // for Lay
|
|
||||||
|
|
||||||
// A layer of hardened clay in between the layer group:
|
|
||||||
int NumBlocks = (Random % 4) + 1; // All heights the same probability
|
|
||||||
if ((NumLayers == 2) && (NumBlocks < 4))
|
|
||||||
{
|
|
||||||
// For two layers of stained clay, add an extra block of hardened clay:
|
|
||||||
NumBlocks++;
|
|
||||||
}
|
|
||||||
NumBlocks = std::min(Idx + 1, NumBlocks); // Limit by Idx so that we don't have to check inside the loop
|
|
||||||
for (int Block = 0; Block < NumBlocks; Block++, Idx--)
|
|
||||||
{
|
|
||||||
m_MesaPattern[Idx].BlockMeta = 0;
|
|
||||||
m_MesaPattern[Idx].BlockType = E_BLOCK_HARDENED_CLAY;
|
|
||||||
} // for Block
|
|
||||||
} // while (Idx >= 0)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cDistortedHeightmap::PrepareState(int a_ChunkX, int a_ChunkZ)
|
void cDistortedHeightmap::PrepareState(int a_ChunkX, int a_ChunkZ)
|
||||||
{
|
{
|
||||||
if ((m_CurChunkX == a_ChunkX) && (m_CurChunkZ == a_ChunkZ))
|
if ((m_CurChunkX == a_ChunkX) && (m_CurChunkZ == a_ChunkZ))
|
||||||
@ -474,23 +230,17 @@ void cDistortedHeightmap::GenerateHeightArray(void)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cDistortedHeightmap::GenHeightMap(int a_ChunkX, int a_ChunkZ, cChunkDef::HeightMap & a_HeightMap)
|
void cDistortedHeightmap::GenShape(int a_ChunkX, int a_ChunkZ, cChunkDesc::Shape & a_Shape)
|
||||||
{
|
{
|
||||||
PrepareState(a_ChunkX, a_ChunkZ);
|
PrepareState(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 x = 0; x < cChunkDef::Width; x++)
|
||||||
{
|
{
|
||||||
int NoiseArrayIdx = x + 17 * 257 * z;
|
int idx = x + 17 * 257 * z;
|
||||||
cChunkDef::SetHeight(a_HeightMap, x, z, m_SeaLevel - 1);
|
for (int y = 0; y < cChunkDef::Height; y++)
|
||||||
for (int y = cChunkDef::Height - 1; y > m_SeaLevel - 1; y--)
|
|
||||||
{
|
{
|
||||||
int HeightMapHeight = (int)m_DistortedHeightmap[NoiseArrayIdx + 17 * y];
|
a_Shape[y + x * 256 + z * 16 * 256] = (y < m_DistortedHeightmap[idx + y * 17]) ? 1 : 0;
|
||||||
if (y < HeightMapHeight)
|
|
||||||
{
|
|
||||||
cChunkDef::SetHeight(a_HeightMap, x, z, y);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} // for y
|
} // for y
|
||||||
} // for x
|
} // for x
|
||||||
} // for z
|
} // for z
|
||||||
@ -500,36 +250,7 @@ void cDistortedHeightmap::GenHeightMap(int a_ChunkX, int a_ChunkZ, cChunkDef::He
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cDistortedHeightmap::InitializeHeightGen(cIniFile & a_IniFile)
|
void cDistortedHeightmap::InitializeShapeGen(cIniFile & a_IniFile)
|
||||||
{
|
|
||||||
Initialize(a_IniFile);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cDistortedHeightmap::ComposeTerrain(cChunkDesc & a_ChunkDesc)
|
|
||||||
{
|
|
||||||
// Prepare the internal state for generating this chunk:
|
|
||||||
PrepareState(a_ChunkDesc.GetChunkX(), a_ChunkDesc.GetChunkZ());
|
|
||||||
|
|
||||||
// Compose:
|
|
||||||
a_ChunkDesc.FillBlocks(E_BLOCK_AIR, 0);
|
|
||||||
for (int z = 0; z < cChunkDef::Width; z++)
|
|
||||||
{
|
|
||||||
for (int x = 0; x < cChunkDef::Width; x++)
|
|
||||||
{
|
|
||||||
ComposeColumn(a_ChunkDesc, x, z);
|
|
||||||
} // for x
|
|
||||||
} // for z
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cDistortedHeightmap::InitializeCompoGen(cIniFile & a_IniFile)
|
|
||||||
{
|
{
|
||||||
Initialize(a_IniFile);
|
Initialize(a_IniFile);
|
||||||
}
|
}
|
||||||
@ -654,275 +375,3 @@ void cDistortedHeightmap::GetDistortAmpsAt(BiomeNeighbors & a_Neighbors, int a_R
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cDistortedHeightmap::ComposeColumn(cChunkDesc & a_ChunkDesc, int a_RelX, int a_RelZ)
|
|
||||||
{
|
|
||||||
// Frequencies for the podzol floor selecting noise:
|
|
||||||
const NOISE_DATATYPE FrequencyX = 8;
|
|
||||||
const NOISE_DATATYPE FrequencyZ = 8;
|
|
||||||
|
|
||||||
EMCSBiome Biome = a_ChunkDesc.GetBiome(a_RelX, a_RelZ);
|
|
||||||
switch (Biome)
|
|
||||||
{
|
|
||||||
case biOcean:
|
|
||||||
case biPlains:
|
|
||||||
case biForest:
|
|
||||||
case biTaiga:
|
|
||||||
case biSwampland:
|
|
||||||
case biRiver:
|
|
||||||
case biFrozenOcean:
|
|
||||||
case biFrozenRiver:
|
|
||||||
case biIcePlains:
|
|
||||||
case biIceMountains:
|
|
||||||
case biForestHills:
|
|
||||||
case biTaigaHills:
|
|
||||||
case biExtremeHillsEdge:
|
|
||||||
case biExtremeHillsPlus:
|
|
||||||
case biExtremeHills:
|
|
||||||
case biJungle:
|
|
||||||
case biJungleHills:
|
|
||||||
case biJungleEdge:
|
|
||||||
case biDeepOcean:
|
|
||||||
case biStoneBeach:
|
|
||||||
case biColdBeach:
|
|
||||||
case biBirchForest:
|
|
||||||
case biBirchForestHills:
|
|
||||||
case biRoofedForest:
|
|
||||||
case biColdTaiga:
|
|
||||||
case biColdTaigaHills:
|
|
||||||
case biSavanna:
|
|
||||||
case biSavannaPlateau:
|
|
||||||
case biSunflowerPlains:
|
|
||||||
case biFlowerForest:
|
|
||||||
case biTaigaM:
|
|
||||||
case biSwamplandM:
|
|
||||||
case biIcePlainsSpikes:
|
|
||||||
case biJungleM:
|
|
||||||
case biJungleEdgeM:
|
|
||||||
case biBirchForestM:
|
|
||||||
case biBirchForestHillsM:
|
|
||||||
case biRoofedForestM:
|
|
||||||
case biColdTaigaM:
|
|
||||||
case biSavannaM:
|
|
||||||
case biSavannaPlateauM:
|
|
||||||
{
|
|
||||||
FillColumnPattern(a_ChunkDesc, a_RelX, a_RelZ, patGrass.Get());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
case biMegaTaiga:
|
|
||||||
case biMegaTaigaHills:
|
|
||||||
case biMegaSpruceTaiga:
|
|
||||||
case biMegaSpruceTaigaHills:
|
|
||||||
{
|
|
||||||
// Select the pattern to use - podzol, grass or grassless dirt:
|
|
||||||
NOISE_DATATYPE NoiseX = ((NOISE_DATATYPE)(m_CurChunkX * cChunkDef::Width + a_RelX)) / FrequencyX;
|
|
||||||
NOISE_DATATYPE NoiseY = ((NOISE_DATATYPE)(m_CurChunkZ * cChunkDef::Width + a_RelZ)) / FrequencyZ;
|
|
||||||
NOISE_DATATYPE Val = m_OceanFloorSelect.CubicNoise2D(NoiseX, NoiseY);
|
|
||||||
const sBlockInfo * Pattern = (Val < -0.9) ? patGrassLess.Get() : ((Val > 0) ? patPodzol.Get() : patGrass.Get());
|
|
||||||
FillColumnPattern(a_ChunkDesc, a_RelX, a_RelZ, Pattern);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
case biDesertHills:
|
|
||||||
case biDesert:
|
|
||||||
case biDesertM:
|
|
||||||
case biBeach:
|
|
||||||
{
|
|
||||||
FillColumnPattern(a_ChunkDesc, a_RelX, a_RelZ, patSand.Get());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
case biMushroomIsland:
|
|
||||||
case biMushroomShore:
|
|
||||||
{
|
|
||||||
FillColumnPattern(a_ChunkDesc, a_RelX, a_RelZ, patMycelium.Get());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
case biMesa:
|
|
||||||
case biMesaPlateauF:
|
|
||||||
case biMesaPlateau:
|
|
||||||
case biMesaBryce:
|
|
||||||
case biMesaPlateauFM:
|
|
||||||
case biMesaPlateauM:
|
|
||||||
{
|
|
||||||
// Mesa biomes need special handling, because they don't follow the usual "4 blocks from top pattern",
|
|
||||||
// instead, they provide a "from bottom" pattern with varying base height,
|
|
||||||
// usually 4 blocks below the ocean level
|
|
||||||
FillColumnMesa(a_ChunkDesc, a_RelX, a_RelZ);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
case biExtremeHillsPlusM:
|
|
||||||
case biExtremeHillsM:
|
|
||||||
{
|
|
||||||
// Select the pattern to use - gravel, stone or grass:
|
|
||||||
NOISE_DATATYPE NoiseX = ((NOISE_DATATYPE)(m_CurChunkX * cChunkDef::Width + a_RelX)) / FrequencyX;
|
|
||||||
NOISE_DATATYPE NoiseY = ((NOISE_DATATYPE)(m_CurChunkZ * cChunkDef::Width + a_RelZ)) / FrequencyZ;
|
|
||||||
NOISE_DATATYPE Val = m_OceanFloorSelect.CubicNoise2D(NoiseX, NoiseY);
|
|
||||||
const sBlockInfo * Pattern = (Val < 0.0) ? patStone.Get() : patGrass.Get();
|
|
||||||
FillColumnPattern(a_ChunkDesc, a_RelX, a_RelZ, Pattern);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
{
|
|
||||||
ASSERT(!"Unhandled biome");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
} // switch (Biome)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cDistortedHeightmap::FillColumnPattern(cChunkDesc & a_ChunkDesc, int a_RelX, int a_RelZ, const sBlockInfo * a_Pattern)
|
|
||||||
{
|
|
||||||
int NoiseArrayIdx = a_RelX + 17 * 257 * a_RelZ;
|
|
||||||
bool HasHadWater = false;
|
|
||||||
int PatternIdx = 0;
|
|
||||||
for (int y = a_ChunkDesc.GetHeight(a_RelX, a_RelZ); y > 0; y--)
|
|
||||||
{
|
|
||||||
int HeightMapHeight = (int)m_DistortedHeightmap[NoiseArrayIdx + 17 * y];
|
|
||||||
|
|
||||||
if (y < HeightMapHeight)
|
|
||||||
{
|
|
||||||
// "ground" part, use the pattern:
|
|
||||||
a_ChunkDesc.SetBlockTypeMeta(a_RelX, y, a_RelZ, a_Pattern[PatternIdx].BlockType, a_Pattern[PatternIdx].BlockMeta);
|
|
||||||
PatternIdx++;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// "air" or "water" part:
|
|
||||||
// Reset the pattern index to zero, so that the pattern is repeated from the top again:
|
|
||||||
PatternIdx = 0;
|
|
||||||
|
|
||||||
if (y >= m_SeaLevel)
|
|
||||||
{
|
|
||||||
// "air" part, do nothing
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
a_ChunkDesc.SetBlockType(a_RelX, y, a_RelZ, E_BLOCK_STATIONARY_WATER);
|
|
||||||
if (HasHadWater)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Select the ocean-floor pattern to use:
|
|
||||||
a_Pattern = a_ChunkDesc.GetBiome(a_RelX, a_RelZ) == biDeepOcean ? patGravel.Get() : ChooseOceanFloorPattern(a_RelX, a_RelZ);
|
|
||||||
HasHadWater = true;
|
|
||||||
} // for y
|
|
||||||
a_ChunkDesc.SetBlockType(a_RelX, 0, a_RelZ, E_BLOCK_BEDROCK);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cDistortedHeightmap::FillColumnMesa(cChunkDesc & a_ChunkDesc, int a_RelX, int a_RelZ)
|
|
||||||
{
|
|
||||||
// Frequencies for the clay floor noise:
|
|
||||||
const NOISE_DATATYPE FrequencyX = 50;
|
|
||||||
const NOISE_DATATYPE FrequencyZ = 50;
|
|
||||||
|
|
||||||
int Top = a_ChunkDesc.GetHeight(a_RelX, a_RelZ);
|
|
||||||
if (Top < m_SeaLevel)
|
|
||||||
{
|
|
||||||
// The terrain is below sealevel, handle as regular ocean:
|
|
||||||
FillColumnPattern(a_ChunkDesc, a_RelX, a_RelZ, patOFRedSand.Get());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
NOISE_DATATYPE NoiseX = ((NOISE_DATATYPE)(m_CurChunkX * cChunkDef::Width + a_RelX)) / FrequencyX;
|
|
||||||
NOISE_DATATYPE NoiseY = ((NOISE_DATATYPE)(m_CurChunkZ * cChunkDef::Width + a_RelZ)) / FrequencyZ;
|
|
||||||
int ClayFloor = m_SeaLevel - 6 + (int)(4.f * m_MesaFloor.CubicNoise2D(NoiseX, NoiseY));
|
|
||||||
if (ClayFloor >= Top)
|
|
||||||
{
|
|
||||||
ClayFloor = Top - 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Top - m_SeaLevel < 5)
|
|
||||||
{
|
|
||||||
// Simple case: top is red sand, then hardened clay down to ClayFloor, then stone:
|
|
||||||
a_ChunkDesc.SetBlockTypeMeta(a_RelX, Top, a_RelZ, E_BLOCK_SAND, E_META_SAND_RED);
|
|
||||||
for (int y = Top - 1; y >= ClayFloor; y--)
|
|
||||||
{
|
|
||||||
a_ChunkDesc.SetBlockType(a_RelX, y, a_RelZ, E_BLOCK_HARDENED_CLAY);
|
|
||||||
}
|
|
||||||
for (int y = ClayFloor - 1; y > 0; y--)
|
|
||||||
{
|
|
||||||
a_ChunkDesc.SetBlockType(a_RelX, y, a_RelZ, E_BLOCK_STONE);
|
|
||||||
}
|
|
||||||
a_ChunkDesc.SetBlockType(a_RelX, 0, a_RelZ, E_BLOCK_BEDROCK);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Difficult case: use the mesa pattern and watch for overhangs:
|
|
||||||
int NoiseArrayIdx = a_RelX + 17 * 257 * a_RelZ;
|
|
||||||
int PatternIdx = cChunkDef::Height - (Top - ClayFloor); // We want the block at index ClayFloor to be pattern's 256th block (first stone)
|
|
||||||
const sBlockInfo * Pattern = m_MesaPattern;
|
|
||||||
bool HasHadWater = false;
|
|
||||||
for (int y = Top; y > 0; y--)
|
|
||||||
{
|
|
||||||
int HeightMapHeight = (int)m_DistortedHeightmap[NoiseArrayIdx + 17 * y];
|
|
||||||
if (y < HeightMapHeight)
|
|
||||||
{
|
|
||||||
// "ground" part, use the pattern:
|
|
||||||
a_ChunkDesc.SetBlockTypeMeta(a_RelX, y, a_RelZ, Pattern[PatternIdx].BlockType, Pattern[PatternIdx].BlockMeta);
|
|
||||||
PatternIdx++;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (y >= m_SeaLevel)
|
|
||||||
{
|
|
||||||
// "air" part, do nothing
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// "water" part, fill with water and choose new pattern for ocean floor, if not chosen already:
|
|
||||||
PatternIdx = 0;
|
|
||||||
a_ChunkDesc.SetBlockType(a_RelX, y, a_RelZ, E_BLOCK_STATIONARY_WATER);
|
|
||||||
if (HasHadWater)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Select the ocean-floor pattern to use:
|
|
||||||
Pattern = ChooseOceanFloorPattern(a_RelX, a_RelZ);
|
|
||||||
HasHadWater = true;
|
|
||||||
} // for y
|
|
||||||
a_ChunkDesc.SetBlockType(a_RelX, 0, a_RelZ, E_BLOCK_BEDROCK);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const cDistortedHeightmap::sBlockInfo * cDistortedHeightmap::ChooseOceanFloorPattern(int a_RelX, int a_RelZ)
|
|
||||||
{
|
|
||||||
// Frequencies for the ocean floor selecting noise:
|
|
||||||
const NOISE_DATATYPE FrequencyX = 3;
|
|
||||||
const NOISE_DATATYPE FrequencyZ = 3;
|
|
||||||
|
|
||||||
// Select the ocean-floor pattern to use:
|
|
||||||
NOISE_DATATYPE NoiseX = ((NOISE_DATATYPE)(m_CurChunkX * cChunkDef::Width + a_RelX)) / FrequencyX;
|
|
||||||
NOISE_DATATYPE NoiseY = ((NOISE_DATATYPE)(m_CurChunkZ * cChunkDef::Width + a_RelZ)) / FrequencyZ;
|
|
||||||
NOISE_DATATYPE Val = m_OceanFloorSelect.CubicNoise2D(NoiseX, NoiseY);
|
|
||||||
if (Val < -0.95)
|
|
||||||
{
|
|
||||||
return patOFClay.Get();
|
|
||||||
}
|
|
||||||
else if (Val < 0)
|
|
||||||
{
|
|
||||||
return patOFSand.Get();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return patDirt.Get();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -24,17 +24,9 @@
|
|||||||
|
|
||||||
|
|
||||||
class cDistortedHeightmap :
|
class cDistortedHeightmap :
|
||||||
public cTerrainHeightGen,
|
public cTerrainShapeGen
|
||||||
public cTerrainCompositionGen
|
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
/// Structure used for storing block patterns for columns
|
|
||||||
struct sBlockInfo
|
|
||||||
{
|
|
||||||
BLOCKTYPE BlockType;
|
|
||||||
NIBBLETYPE BlockMeta;
|
|
||||||
} ;
|
|
||||||
|
|
||||||
cDistortedHeightmap(int a_Seed, cBiomeGenPtr a_BiomeGen);
|
cDistortedHeightmap(int a_Seed, cBiomeGenPtr a_BiomeGen);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
@ -52,8 +44,6 @@ protected:
|
|||||||
|
|
||||||
cPerlinNoise m_NoiseDistortX;
|
cPerlinNoise m_NoiseDistortX;
|
||||||
cPerlinNoise m_NoiseDistortZ;
|
cPerlinNoise m_NoiseDistortZ;
|
||||||
cNoise m_OceanFloorSelect; ///< Used for selecting between dirt and sand on the ocean floor
|
|
||||||
cNoise m_MesaFloor; ///< Used for the floor of the clay blocks in mesa biomes
|
|
||||||
|
|
||||||
int m_SeaLevel;
|
int m_SeaLevel;
|
||||||
NOISE_DATATYPE m_FrequencyX;
|
NOISE_DATATYPE m_FrequencyX;
|
||||||
@ -71,9 +61,9 @@ protected:
|
|||||||
cTerrainHeightGenPtr m_UnderlyingHeiGen;
|
cTerrainHeightGenPtr m_UnderlyingHeiGen;
|
||||||
|
|
||||||
/** Cache for m_UnderlyingHeiGen. */
|
/** Cache for m_UnderlyingHeiGen. */
|
||||||
cHeiGenCache m_HeightGen;
|
cHeiGenCache m_HeightGen;
|
||||||
|
|
||||||
/// Heightmap for the current chunk, before distortion (from m_HeightGen). Used for optimization.
|
/** Heightmap for the current chunk, before distortion (from m_HeightGen). Used for optimization. */
|
||||||
cChunkDef::HeightMap m_CurChunkHeights;
|
cChunkDef::HeightMap m_CurChunkHeights;
|
||||||
|
|
||||||
// Per-biome terrain generator parameters:
|
// Per-biome terrain generator parameters:
|
||||||
@ -88,54 +78,30 @@ protected:
|
|||||||
NOISE_DATATYPE m_DistortAmpX[DIM_X * DIM_Z];
|
NOISE_DATATYPE m_DistortAmpX[DIM_X * DIM_Z];
|
||||||
NOISE_DATATYPE m_DistortAmpZ[DIM_X * DIM_Z];
|
NOISE_DATATYPE m_DistortAmpZ[DIM_X * DIM_Z];
|
||||||
|
|
||||||
/// True if Initialize() has been called. Used to initialize-once even with multiple init entrypoints (HeiGen / CompoGen)
|
/** True if Initialize() has been called. Used to initialize-once even with multiple init entrypoints (HeiGen / CompoGen). */
|
||||||
bool m_IsInitialized;
|
bool m_IsInitialized;
|
||||||
|
|
||||||
/// The vertical pattern to be used for mesa biomes. Seed-dependant.
|
|
||||||
/// One Height of pattern and one Height of stone to avoid checking pattern dimensions
|
|
||||||
sBlockInfo m_MesaPattern[2 * cChunkDef::Height];
|
|
||||||
|
|
||||||
|
|
||||||
/// Initializes m_MesaPattern with a reasonable pattern of stained clay / hardened clay, based on the seed
|
/** Unless the LastChunk coords are equal to coords given, prepares the internal state (noise arrays, heightmap). */
|
||||||
void InitMesaPattern(int a_Seed);
|
|
||||||
|
|
||||||
/// Unless the LastChunk coords are equal to coords given, prepares the internal state (noise arrays, heightmap)
|
|
||||||
void PrepareState(int a_ChunkX, int a_ChunkZ);
|
void PrepareState(int a_ChunkX, int a_ChunkZ);
|
||||||
|
|
||||||
/// Generates the m_DistortedHeightmap array for the current chunk
|
/** Generates the m_DistortedHeightmap array for the current chunk. */
|
||||||
void GenerateHeightArray(void);
|
void GenerateHeightArray(void);
|
||||||
|
|
||||||
/// Calculates the heightmap value (before distortion) at the specified (floating-point) coords
|
/** Calculates the heightmap value (before distortion) at the specified (floating-point) coords. */
|
||||||
int GetHeightmapAt(NOISE_DATATYPE a_X, NOISE_DATATYPE a_Z);
|
int GetHeightmapAt(NOISE_DATATYPE a_X, NOISE_DATATYPE a_Z);
|
||||||
|
|
||||||
/// Updates m_DistortAmpX/Z[] based on m_CurChunkX and m_CurChunkZ
|
/** Updates m_DistortAmpX/Z[] based on m_CurChunkX and m_CurChunkZ. */
|
||||||
void UpdateDistortAmps(void);
|
void UpdateDistortAmps(void);
|
||||||
|
|
||||||
/// Calculates the X and Z distortion amplitudes based on the neighbors' biomes
|
/** Calculates the X and Z distortion amplitudes based on the neighbors' biomes. */
|
||||||
void GetDistortAmpsAt(BiomeNeighbors & a_Neighbors, int a_RelX, int a_RelZ, NOISE_DATATYPE & a_DistortAmpX, NOISE_DATATYPE & a_DistortAmpZ);
|
void GetDistortAmpsAt(BiomeNeighbors & a_Neighbors, int a_RelX, int a_RelZ, NOISE_DATATYPE & a_DistortAmpX, NOISE_DATATYPE & a_DistortAmpZ);
|
||||||
|
|
||||||
/// Reads the settings from the ini file. Skips reading if already initialized
|
/** Reads the settings from the ini file. Skips reading if already initialized. */
|
||||||
void Initialize(cIniFile & a_IniFile);
|
void Initialize(cIniFile & a_IniFile);
|
||||||
|
|
||||||
/// Composes a single column in a_ChunkDesc. Chooses what to do based on the biome in that column
|
|
||||||
void ComposeColumn(cChunkDesc & a_ChunkDesc, int a_RelX, int a_RelZ);
|
|
||||||
|
|
||||||
/// Fills the specified column with the specified pattern; restarts the pattern when air is reached,
|
// cTerrainShapeGen overrides:
|
||||||
/// switches to ocean floor pattern if ocean is reached. Always adds bedrock at the very bottom.
|
virtual void GenShape(int a_ChunkX, int a_ChunkZ, cChunkDesc::Shape & a_Shape) override;
|
||||||
void FillColumnPattern(cChunkDesc & a_ChunkDesc, int a_RelX, int a_RelZ, const sBlockInfo * a_Pattern);
|
virtual void InitializeShapeGen(cIniFile & a_IniFile) override;
|
||||||
|
|
||||||
/// Fills the specified column with mesa pattern, based on the column height
|
|
||||||
void FillColumnMesa(cChunkDesc & a_ChunkDesc, int a_RelX, int a_RelZ);
|
|
||||||
|
|
||||||
/// Returns the pattern to use for an ocean floor in the specified column
|
|
||||||
const sBlockInfo * ChooseOceanFloorPattern(int a_RelX, int a_RelZ);
|
|
||||||
|
|
||||||
|
|
||||||
// cTerrainHeightGen overrides:
|
|
||||||
virtual void GenHeightMap(int a_ChunkX, int a_ChunkZ, cChunkDef::HeightMap & a_HeightMap) override;
|
|
||||||
virtual void InitializeHeightGen(cIniFile & a_IniFile) override;
|
|
||||||
|
|
||||||
// cTerrainCompositionGen overrides:
|
|
||||||
virtual void ComposeTerrain(cChunkDesc & a_ChunkDesc) override;
|
|
||||||
virtual void InitializeCompoGen(cIniFile & a_IniFile) override;
|
|
||||||
} ;
|
} ;
|
||||||
|
@ -258,9 +258,9 @@ protected:
|
|||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
// cDungeonRoomsFinisher:
|
// cDungeonRoomsFinisher:
|
||||||
|
|
||||||
cDungeonRoomsFinisher::cDungeonRoomsFinisher(cTerrainHeightGenPtr a_HeightGen, int a_Seed, int a_GridSize, int a_MaxSize, int a_MinSize, const AString & a_HeightDistrib) :
|
cDungeonRoomsFinisher::cDungeonRoomsFinisher(cTerrainShapeGenPtr a_ShapeGen, int a_Seed, int a_GridSize, int a_MaxSize, int a_MinSize, const AString & a_HeightDistrib) :
|
||||||
super(a_Seed + 100, a_GridSize, a_GridSize, a_GridSize, a_GridSize, a_MaxSize, a_MaxSize, 1024),
|
super(a_Seed + 100, a_GridSize, a_GridSize, a_GridSize, a_GridSize, a_MaxSize, a_MaxSize, 1024),
|
||||||
m_HeightGen(a_HeightGen),
|
m_ShapeGen(a_ShapeGen),
|
||||||
m_MaxHalfSize((a_MaxSize + 1) / 2),
|
m_MaxHalfSize((a_MaxSize + 1) / 2),
|
||||||
m_MinHalfSize((a_MinSize + 1) / 2),
|
m_MinHalfSize((a_MinSize + 1) / 2),
|
||||||
m_HeightProbability(cChunkDef::Height)
|
m_HeightProbability(cChunkDef::Height)
|
||||||
@ -293,10 +293,14 @@ cDungeonRoomsFinisher::cStructurePtr cDungeonRoomsFinisher::CreateStructure(int
|
|||||||
int ChunkX, ChunkZ;
|
int ChunkX, ChunkZ;
|
||||||
int RelX = a_OriginX, RelY = 0, RelZ = a_OriginZ;
|
int RelX = a_OriginX, RelY = 0, RelZ = a_OriginZ;
|
||||||
cChunkDef::AbsoluteToRelative(RelX, RelY, RelZ, ChunkX, ChunkZ);
|
cChunkDef::AbsoluteToRelative(RelX, RelY, RelZ, ChunkX, ChunkZ);
|
||||||
|
/*
|
||||||
|
// TODO
|
||||||
cChunkDef::HeightMap HeightMap;
|
cChunkDef::HeightMap HeightMap;
|
||||||
m_HeightGen->GenHeightMap(ChunkX, ChunkZ, HeightMap);
|
m_HeightGen->GenHeightMap(ChunkX, ChunkZ, HeightMap);
|
||||||
int Height = cChunkDef::GetHeight(HeightMap, RelX, RelZ); // Max room height at {a_OriginX, a_OriginZ}
|
int Height = cChunkDef::GetHeight(HeightMap, RelX, RelZ); // Max room height at {a_OriginX, a_OriginZ}
|
||||||
Height = Clamp(m_HeightProbability.MapValue(rnd % m_HeightProbability.GetSum()), 10, Height - 5);
|
Height = Clamp(m_HeightProbability.MapValue(rnd % m_HeightProbability.GetSum()), 10, Height - 5);
|
||||||
|
*/
|
||||||
|
int Height = 62;
|
||||||
|
|
||||||
// Create the dungeon room descriptor:
|
// Create the dungeon room descriptor:
|
||||||
return cStructurePtr(new cDungeonRoom(a_GridX, a_GridZ, a_OriginX, a_OriginZ, HalfSizeX, HalfSizeZ, Height, m_Noise));
|
return cStructurePtr(new cDungeonRoom(a_GridX, a_GridZ, a_OriginX, a_OriginZ, HalfSizeX, HalfSizeZ, Height, m_Noise));
|
||||||
|
@ -23,15 +23,15 @@ class cDungeonRoomsFinisher :
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
/** Creates a new dungeon room finisher.
|
/** Creates a new dungeon room finisher.
|
||||||
a_HeightGen is the underlying height generator, so that the rooms can always be placed under the terrain.
|
a_ShapeGen is the underlying terrain shape generator, so that the rooms can always be placed under the terrain.
|
||||||
a_MaxSize and a_MinSize are the maximum and minimum sizes of the room's internal (air) area, in blocks across.
|
a_MaxSize and a_MinSize are the maximum and minimum sizes of the room's internal (air) area, in blocks across.
|
||||||
a_HeightDistrib is the string defining the height distribution for the rooms (cProbabDistrib format). */
|
a_HeightDistrib is the string defining the height distribution for the rooms (cProbabDistrib format). */
|
||||||
cDungeonRoomsFinisher(cTerrainHeightGenPtr a_HeightGen, int a_Seed, int a_GridSize, int a_MaxSize, int a_MinSize, const AString & a_HeightDistrib);
|
cDungeonRoomsFinisher(cTerrainShapeGenPtr a_ShapeGen, int a_Seed, int a_GridSize, int a_MaxSize, int a_MinSize, const AString & a_HeightDistrib);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
/** The height gen that is used for limiting the rooms' Y coords */
|
/** The shape gen that is used for limiting the rooms' Y coords */
|
||||||
cTerrainHeightGenPtr m_HeightGen;
|
cTerrainShapeGenPtr m_ShapeGen;
|
||||||
|
|
||||||
/** Maximum half-size (from center to wall) of the dungeon room's inner (air) area. Default is 3 (vanilla). */
|
/** Maximum half-size (from center to wall) of the dungeon room's inner (air) area. Default is 3 (vanilla). */
|
||||||
int m_MaxHalfSize;
|
int m_MaxHalfSize;
|
||||||
|
@ -147,13 +147,14 @@ bool cEndGen::IsChunkOutsideRange(int a_ChunkX, int a_ChunkZ)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cEndGen::GenHeightMap(int a_ChunkX, int a_ChunkZ, cChunkDef::HeightMap & a_HeightMap)
|
void cEndGen::GenShape(int a_ChunkX, int a_ChunkZ, cChunkDesc::Shape & a_Shape)
|
||||||
{
|
{
|
||||||
|
// If the chunk is outside out range, fill the shape with zeroes:
|
||||||
if (IsChunkOutsideRange(a_ChunkX, a_ChunkZ))
|
if (IsChunkOutsideRange(a_ChunkX, a_ChunkZ))
|
||||||
{
|
{
|
||||||
for (size_t i = 0; i < ARRAYCOUNT(a_HeightMap); i++)
|
for (size_t i = 0; i < ARRAYCOUNT(a_Shape); i++)
|
||||||
{
|
{
|
||||||
a_HeightMap[i] = 0;
|
a_Shape[i] = 0;
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -165,15 +166,14 @@ void cEndGen::GenHeightMap(int a_ChunkX, int a_ChunkZ, cChunkDef::HeightMap & a_
|
|||||||
{
|
{
|
||||||
for (int x = 0; x < cChunkDef::Width; x++)
|
for (int x = 0; x < cChunkDef::Width; x++)
|
||||||
{
|
{
|
||||||
cChunkDef::SetHeight(a_HeightMap, x, z, MaxY);
|
for (int y = 0; y < MaxY; y++)
|
||||||
for (int y = MaxY; y > 0; y--)
|
|
||||||
{
|
{
|
||||||
if (m_NoiseArray[y * 17 * 17 + z * 17 + x] <= 0)
|
a_Shape[(x + 16 * z) * 256 + y] = (m_NoiseArray[y * 17 * 17 + z * 17 + z] > 0) ? 1 : 0;
|
||||||
{
|
}
|
||||||
cChunkDef::SetHeight(a_HeightMap, x, z, y);
|
for (int y = MaxY; y < cChunkDef::Height; y++)
|
||||||
break;
|
{
|
||||||
}
|
a_Shape[(x + 16 * z) * 256 + y] = 0;
|
||||||
} // for y
|
}
|
||||||
} // for x
|
} // for x
|
||||||
} // for z
|
} // for z
|
||||||
}
|
}
|
||||||
@ -182,30 +182,18 @@ void cEndGen::GenHeightMap(int a_ChunkX, int a_ChunkZ, cChunkDef::HeightMap & a_
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cEndGen::ComposeTerrain(cChunkDesc & a_ChunkDesc)
|
void cEndGen::ComposeTerrain(cChunkDesc & a_ChunkDesc, const cChunkDesc::Shape & a_Shape)
|
||||||
{
|
{
|
||||||
if (IsChunkOutsideRange(a_ChunkDesc.GetChunkX(), a_ChunkDesc.GetChunkZ()))
|
a_ChunkDesc.FillBlocks(E_BLOCK_AIR, 0);
|
||||||
{
|
|
||||||
a_ChunkDesc.FillBlocks(E_BLOCK_AIR, 0);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
PrepareState(a_ChunkDesc.GetChunkX(), a_ChunkDesc.GetChunkZ());
|
|
||||||
|
|
||||||
int MaxY = std::min((int)(1.75 * m_IslandSizeY + 1), cChunkDef::Height - 1);
|
|
||||||
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 x = 0; x < cChunkDef::Width; x++)
|
||||||
{
|
{
|
||||||
for (int y = MaxY; y > 0; y--)
|
for (int y = 0; y < cChunkDef::Height; y++)
|
||||||
{
|
{
|
||||||
if (m_NoiseArray[y * 17 * 17 + z * 17 + x] <= 0)
|
if (a_Shape[(x + 16 * z) * 256 + y] != 0)
|
||||||
{
|
{
|
||||||
a_ChunkDesc.SetBlockTypeMeta(x, y, z, E_BLOCK_END_STONE, 0);
|
a_ChunkDesc.SetBlockType(x, y, z, E_BLOCK_END_STONE);
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
a_ChunkDesc.SetBlockTypeMeta(x, y, z, E_BLOCK_AIR, 0);
|
|
||||||
}
|
}
|
||||||
} // for y
|
} // for y
|
||||||
} // for x
|
} // for x
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
|
|
||||||
|
|
||||||
class cEndGen :
|
class cEndGen :
|
||||||
public cTerrainHeightGen,
|
public cTerrainShapeGen,
|
||||||
public cTerrainCompositionGen
|
public cTerrainCompositionGen
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@ -59,10 +59,10 @@ protected:
|
|||||||
/// Returns true if the chunk is outside of the island's dimensions
|
/// Returns true if the chunk is outside of the island's dimensions
|
||||||
bool IsChunkOutsideRange(int a_ChunkX, int a_ChunkZ);
|
bool IsChunkOutsideRange(int a_ChunkX, int a_ChunkZ);
|
||||||
|
|
||||||
// cTerrainHeightGen overrides:
|
// cTerrainShapeGen overrides:
|
||||||
virtual void GenHeightMap(int a_ChunkX, int a_ChunkZ, cChunkDef::HeightMap & a_HeightMap) override;
|
virtual void GenShape(int a_ChunkX, int a_ChunkZ, cChunkDesc::Shape & a_Shape) override;
|
||||||
|
|
||||||
// cTerrainCompositionGen overrides:
|
// cTerrainCompositionGen overrides:
|
||||||
virtual void ComposeTerrain(cChunkDesc & a_ChunkDesc) override;
|
virtual void ComposeTerrain(cChunkDesc & a_ChunkDesc, const cChunkDesc::Shape & a_Shape) override;
|
||||||
virtual void InitializeCompoGen(cIniFile & a_IniFile) override;
|
virtual void InitializeCompoGen(cIniFile & a_IniFile) override;
|
||||||
} ;
|
} ;
|
||||||
|
@ -15,7 +15,6 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
// cHeiGenFlat:
|
// cHeiGenFlat:
|
||||||
|
|
||||||
@ -133,15 +132,6 @@ void cHeiGenCache::GenHeightMap(int a_ChunkX, int a_ChunkZ, cChunkDef::HeightMap
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cHeiGenCache::InitializeHeightGen(cIniFile & a_IniFile)
|
|
||||||
{
|
|
||||||
m_HeiGenToCache->InitializeHeightGen(a_IniFile);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
bool cHeiGenCache::GetHeightAt(int a_ChunkX, int a_ChunkZ, int a_RelX, int a_RelZ, HEIGHTTYPE & a_Height)
|
bool cHeiGenCache::GetHeightAt(int a_ChunkX, int a_ChunkZ, int a_RelX, int a_RelZ, HEIGHTTYPE & a_Height)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < m_CacheSize; i++)
|
for (int i = 0; i < m_CacheSize; i++)
|
||||||
@ -750,43 +740,51 @@ cTerrainHeightGenPtr cTerrainHeightGen::CreateHeightGen(cIniFile & a_IniFile, cB
|
|||||||
}
|
}
|
||||||
|
|
||||||
a_CacheOffByDefault = false;
|
a_CacheOffByDefault = false;
|
||||||
cTerrainHeightGen * res = nullptr;
|
cTerrainHeightGenPtr res;
|
||||||
if (NoCaseCompare(HeightGenName, "flat") == 0)
|
if (NoCaseCompare(HeightGenName, "Flat") == 0)
|
||||||
{
|
{
|
||||||
res = new cHeiGenFlat;
|
res = std::make_shared<cHeiGenFlat>();
|
||||||
a_CacheOffByDefault = true; // We're generating faster than a cache would retrieve data
|
a_CacheOffByDefault = true; // We're generating faster than a cache would retrieve data
|
||||||
}
|
}
|
||||||
else if (NoCaseCompare(HeightGenName, "classic") == 0)
|
else if (NoCaseCompare(HeightGenName, "classic") == 0)
|
||||||
{
|
{
|
||||||
res = new cHeiGenClassic(a_Seed);
|
res = std::make_shared<cHeiGenClassic>(a_Seed);
|
||||||
}
|
}
|
||||||
else if (NoCaseCompare(HeightGenName, "DistortedHeightmap") == 0)
|
else if (NoCaseCompare(HeightGenName, "DistortedHeightmap") == 0)
|
||||||
{
|
{
|
||||||
res = new cDistortedHeightmap(a_Seed, a_BiomeGen);
|
// Not a heightmap-based generator, but it used to be accessible via HeightGen, so we need to skip making the default out of it
|
||||||
|
// Return an empty pointer, the caller will create the proper generator:
|
||||||
|
return cTerrainHeightGenPtr();
|
||||||
}
|
}
|
||||||
else if (NoCaseCompare(HeightGenName, "End") == 0)
|
else if (NoCaseCompare(HeightGenName, "End") == 0)
|
||||||
{
|
{
|
||||||
res = new cEndGen(a_Seed);
|
// Not a heightmap-based generator, but it used to be accessible via HeightGen, so we need to skip making the default out of it
|
||||||
|
// Return an empty pointer, the caller will create the proper generator:
|
||||||
|
return cTerrainHeightGenPtr();
|
||||||
}
|
}
|
||||||
else if (NoCaseCompare(HeightGenName, "MinMax") == 0)
|
else if (NoCaseCompare(HeightGenName, "MinMax") == 0)
|
||||||
{
|
{
|
||||||
res = new cHeiGenMinMax(a_Seed, a_BiomeGen);
|
res = std::make_shared<cHeiGenMinMax>(a_Seed, a_BiomeGen);
|
||||||
}
|
}
|
||||||
else if (NoCaseCompare(HeightGenName, "Mountains") == 0)
|
else if (NoCaseCompare(HeightGenName, "Mountains") == 0)
|
||||||
{
|
{
|
||||||
res = new cHeiGenMountains(a_Seed);
|
res = std::make_shared<cHeiGenMountains>(a_Seed);
|
||||||
}
|
}
|
||||||
else if (NoCaseCompare(HeightGenName, "BiomalNoise3D") == 0)
|
else if (NoCaseCompare(HeightGenName, "BiomalNoise3D") == 0)
|
||||||
{
|
{
|
||||||
res = new cBiomalNoise3DComposable(a_Seed, a_BiomeGen);
|
// Not a heightmap-based generator, but it used to be accessible via HeightGen, so we need to skip making the default out of it
|
||||||
|
// Return an empty pointer, the caller will create the proper generator:
|
||||||
|
return cTerrainHeightGenPtr();
|
||||||
}
|
}
|
||||||
else if (NoCaseCompare(HeightGenName, "Noise3D") == 0)
|
else if (NoCaseCompare(HeightGenName, "Noise3D") == 0)
|
||||||
{
|
{
|
||||||
res = new cNoise3DComposable(a_Seed);
|
// Not a heightmap-based generator, but it used to be accessible via HeightGen, so we need to skip making the default out of it
|
||||||
|
// Return an empty pointer, the caller will create the proper generator:
|
||||||
|
return cTerrainHeightGenPtr();
|
||||||
}
|
}
|
||||||
else if (NoCaseCompare(HeightGenName, "biomal") == 0)
|
else if (NoCaseCompare(HeightGenName, "Biomal") == 0)
|
||||||
{
|
{
|
||||||
res = new cHeiGenBiomal(a_Seed, a_BiomeGen);
|
res = std::make_shared<cHeiGenBiomal>(a_Seed, a_BiomeGen);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
// Performance-testing:
|
// Performance-testing:
|
||||||
@ -805,15 +803,14 @@ cTerrainHeightGenPtr cTerrainHeightGen::CreateHeightGen(cIniFile & a_IniFile, cB
|
|||||||
{
|
{
|
||||||
// No match found, force-set the default and retry
|
// No match found, force-set the default and retry
|
||||||
LOGWARN("Unknown HeightGen \"%s\", using \"Biomal\" instead.", HeightGenName.c_str());
|
LOGWARN("Unknown HeightGen \"%s\", using \"Biomal\" instead.", HeightGenName.c_str());
|
||||||
a_IniFile.DeleteValue("Generator", "HeightGen");
|
|
||||||
a_IniFile.SetValue("Generator", "HeightGen", "Biomal");
|
a_IniFile.SetValue("Generator", "HeightGen", "Biomal");
|
||||||
return CreateHeightGen(a_IniFile, a_BiomeGen, a_Seed, a_CacheOffByDefault);
|
return CreateHeightGen(a_IniFile, a_BiomeGen, a_Seed, a_CacheOffByDefault);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read the settings:
|
// Read the settings:
|
||||||
res->InitializeHeightGen(a_IniFile);
|
res->InitializeHeightGen(a_IniFile);
|
||||||
|
|
||||||
return cTerrainHeightGenPtr(res);
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -2,10 +2,12 @@
|
|||||||
// HeiGen.h
|
// HeiGen.h
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Interfaces to the various height generators:
|
Interfaces to the various height-based terrain shape generators:
|
||||||
- cHeiGenFlat
|
- cHeiGenFlat
|
||||||
- cHeiGenClassic
|
- cHeiGenClassic
|
||||||
- cHeiGenBiomal
|
- cHeiGenBiomal
|
||||||
|
|
||||||
|
Also implements the heightmap cache
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
@ -21,6 +23,46 @@ Interfaces to the various height generators:
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/** A simple cache that stores N most recently generated chunks' heightmaps; N being settable upon creation */
|
||||||
|
class cHeiGenCache :
|
||||||
|
public cTerrainHeightGen
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
cHeiGenCache(cTerrainHeightGenPtr a_HeiGenToCache, int a_CacheSize);
|
||||||
|
~cHeiGenCache();
|
||||||
|
|
||||||
|
// cTerrainHeightGen overrides:
|
||||||
|
virtual void GenHeightMap(int a_ChunkX, int a_ChunkZ, cChunkDef::HeightMap & a_HeightMap) override;
|
||||||
|
|
||||||
|
/** Retrieves height at the specified point in the cache, returns true if found, false if not found */
|
||||||
|
bool GetHeightAt(int a_ChunkX, int a_ChunkZ, int a_RelX, int a_RelZ, HEIGHTTYPE & a_Height);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
struct sCacheData
|
||||||
|
{
|
||||||
|
int m_ChunkX;
|
||||||
|
int m_ChunkZ;
|
||||||
|
cChunkDef::HeightMap m_HeightMap;
|
||||||
|
} ;
|
||||||
|
|
||||||
|
/** The terrain height generator that is being cached. */
|
||||||
|
cTerrainHeightGenPtr m_HeiGenToCache;
|
||||||
|
|
||||||
|
// To avoid moving large amounts of data for the MRU behavior, we MRU-ize indices to an array of the actual data
|
||||||
|
int m_CacheSize;
|
||||||
|
int * m_CacheOrder; // MRU-ized order, indices into m_CacheData array
|
||||||
|
sCacheData * m_CacheData; // m_CacheData[m_CacheOrder[0]] is the most recently used
|
||||||
|
|
||||||
|
// Cache statistics
|
||||||
|
int m_NumHits;
|
||||||
|
int m_NumMisses;
|
||||||
|
int m_TotalChain; // Number of cache items walked to get to a hit (only added for hits)
|
||||||
|
} ;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class cHeiGenFlat :
|
class cHeiGenFlat :
|
||||||
public cTerrainHeightGen
|
public cTerrainHeightGen
|
||||||
{
|
{
|
||||||
@ -40,47 +82,6 @@ protected:
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// A simple cache that stores N most recently generated chunks' heightmaps; N being settable upon creation
|
|
||||||
class cHeiGenCache :
|
|
||||||
public cTerrainHeightGen
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
cHeiGenCache(cTerrainHeightGenPtr a_HeiGenToCache, int a_CacheSize);
|
|
||||||
~cHeiGenCache();
|
|
||||||
|
|
||||||
// cTerrainHeightGen overrides:
|
|
||||||
virtual void GenHeightMap(int a_ChunkX, int a_ChunkZ, cChunkDef::HeightMap & a_HeightMap) override;
|
|
||||||
virtual void InitializeHeightGen(cIniFile & a_IniFile) override;
|
|
||||||
|
|
||||||
/// Retrieves height at the specified point in the cache, returns true if found, false if not found
|
|
||||||
bool GetHeightAt(int a_ChunkX, int a_ChunkZ, int a_RelX, int a_RelZ, HEIGHTTYPE & a_Height);
|
|
||||||
|
|
||||||
protected:
|
|
||||||
|
|
||||||
cTerrainHeightGenPtr m_HeiGenToCache;
|
|
||||||
|
|
||||||
struct sCacheData
|
|
||||||
{
|
|
||||||
int m_ChunkX;
|
|
||||||
int m_ChunkZ;
|
|
||||||
cChunkDef::HeightMap m_HeightMap;
|
|
||||||
} ;
|
|
||||||
|
|
||||||
// To avoid moving large amounts of data for the MRU behavior, we MRU-ize indices to an array of the actual data
|
|
||||||
int m_CacheSize;
|
|
||||||
int * m_CacheOrder; // MRU-ized order, indices into m_CacheData array
|
|
||||||
sCacheData * m_CacheData; // m_CacheData[m_CacheOrder[0]] is the most recently used
|
|
||||||
|
|
||||||
// Cache statistics
|
|
||||||
int m_NumHits;
|
|
||||||
int m_NumMisses;
|
|
||||||
int m_TotalChain; // Number of cache items walked to get to a hit (only added for hits)
|
|
||||||
} ;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class cHeiGenClassic :
|
class cHeiGenClassic :
|
||||||
public cTerrainHeightGen
|
public cTerrainHeightGen
|
||||||
{
|
{
|
||||||
|
@ -458,110 +458,53 @@ void cNoise3DComposable::GenerateNoiseArrayIfNeeded(int a_ChunkX, int a_ChunkZ)
|
|||||||
NOISE_DATATYPE BaseNoise[5 * 5];
|
NOISE_DATATYPE BaseNoise[5 * 5];
|
||||||
NOISE_DATATYPE BlockX = static_cast<NOISE_DATATYPE>(a_ChunkX * cChunkDef::Width);
|
NOISE_DATATYPE BlockX = static_cast<NOISE_DATATYPE>(a_ChunkX * cChunkDef::Width);
|
||||||
NOISE_DATATYPE BlockZ = static_cast<NOISE_DATATYPE>(a_ChunkZ * 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":
|
// Note that we have to swap the X and Y coords, because noise generator uses [x + SizeX * y + SizeX * SizeY * z] ordering and we want "BlockY" to be "x":
|
||||||
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_ChoiceNoise.Generate3D (ChoiceNoise, 33, 5, 5, 0, 257 / m_ChoiceFrequencyY, BlockX / m_ChoiceFrequencyX, (BlockX + 17) / m_ChoiceFrequencyX, BlockZ / m_ChoiceFrequencyZ, (BlockZ + 17) / m_ChoiceFrequencyZ, 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_DensityNoiseA.Generate3D(DensityNoiseA, 33, 5, 5, 0, 257 / m_FrequencyY, BlockX / m_FrequencyX, (BlockX + 17) / m_FrequencyX, BlockZ / m_FrequencyZ, (BlockZ + 17) / m_FrequencyZ, 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_DensityNoiseB.Generate3D(DensityNoiseB, 33, 5, 5, 0, 257 / m_FrequencyY, BlockX / m_FrequencyX, (BlockX + 17) / m_FrequencyX, BlockZ / m_FrequencyZ, (BlockZ + 17) / m_FrequencyZ, Workspace);
|
||||||
m_BaseNoise.Generate2D (BaseNoise, 5, 5, BlockX / m_BaseFrequencyX, (BlockX + 17) / m_BaseFrequencyX, BlockZ / m_FrequencyZ, (BlockZ + 17) / m_FrequencyZ, 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:
|
// Calculate the final noise based on the partial noises:
|
||||||
for (int y = 0; y < 33; y++)
|
for (int z = 0; z < 5; z++)
|
||||||
{
|
{
|
||||||
NOISE_DATATYPE AddHeight = (static_cast<NOISE_DATATYPE>(y * 8) - m_MidPoint) * m_HeightAmplification;
|
for (int x = 0; x < 5; x++)
|
||||||
|
|
||||||
// If "underground", make the terrain smoother by forcing the vertical linear gradient into steeper slope:
|
|
||||||
if (AddHeight < 0)
|
|
||||||
{
|
{
|
||||||
AddHeight *= 4;
|
NOISE_DATATYPE curBaseNoise = BaseNoise[x + 5 * z];
|
||||||
}
|
for (int y = 0; y < 33; y++)
|
||||||
|
|
||||||
for (int z = 0; z < 5; z++)
|
|
||||||
{
|
|
||||||
for (int x = 0; x < 5; x++)
|
|
||||||
{
|
{
|
||||||
int idx = x + 5 * z + 5 * 5 * y;
|
NOISE_DATATYPE AddHeight = (static_cast<NOISE_DATATYPE>(y * 8) - m_MidPoint) * m_HeightAmplification;
|
||||||
Workspace[idx] = ClampedLerp(DensityNoiseA[idx], DensityNoiseB[idx], 8 * (ChoiceNoise[idx] + 0.5f)) + AddHeight + BaseNoise[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 = 33 * x + 33 * 5 * z + y;
|
||||||
|
Workspace[idx] = ClampedLerp(DensityNoiseA[idx], DensityNoiseB[idx], 8 * (ChoiceNoise[idx] + 0.5f)) + AddHeight + curBaseNoise;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
LinearUpscale3DArray<NOISE_DATATYPE>(Workspace, 5, 5, 33, m_NoiseArray, 4, 4, 8);
|
LinearUpscale3DArray<NOISE_DATATYPE>(Workspace, 33, 5, 5, m_NoiseArray, 8, 4, 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cNoise3DComposable::GenHeightMap(int a_ChunkX, int a_ChunkZ, cChunkDef::HeightMap & a_HeightMap)
|
void cNoise3DComposable::GenShape(int a_ChunkX, int a_ChunkZ, cChunkDesc::Shape & a_Shape)
|
||||||
{
|
{
|
||||||
GenerateNoiseArrayIfNeeded(a_ChunkX, a_ChunkZ);
|
GenerateNoiseArrayIfNeeded(a_ChunkX, a_ChunkZ);
|
||||||
|
|
||||||
|
// Translate the noise array into Shape:
|
||||||
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 x = 0; x < cChunkDef::Width; x++)
|
||||||
{
|
{
|
||||||
cChunkDef::SetHeight(a_HeightMap, x, z, m_SeaLevel);
|
for (int y = 0; y < cChunkDef::Height; y++)
|
||||||
for (int y = cChunkDef::Height - 1; y > m_SeaLevel; y--)
|
|
||||||
{
|
{
|
||||||
if (m_NoiseArray[y * 17 * 17 + z * 17 + x] <= m_AirThreshold)
|
a_Shape[y + x * 256 + z * 256 * 16] = (m_NoiseArray[y + 257 * x + 257 * 17 * z] > m_AirThreshold) ? 0 : 1;
|
||||||
{
|
|
||||||
cChunkDef::SetHeight(a_HeightMap, x, z, y);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} // for y
|
|
||||||
} // for x
|
|
||||||
} // for z
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
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 x = 0; x < cChunkDef::Width; x++)
|
|
||||||
{
|
|
||||||
int LastAir = a_ChunkDesc.GetHeight(x, z) + 1;
|
|
||||||
bool HasHadWater = false;
|
|
||||||
for (int y = LastAir; y < m_SeaLevel; y++)
|
|
||||||
{
|
|
||||||
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)
|
|
||||||
{
|
|
||||||
// "air" part
|
|
||||||
LastAir = y;
|
|
||||||
if (y < m_SeaLevel)
|
|
||||||
{
|
|
||||||
a_ChunkDesc.SetBlockType(x, y, z, E_BLOCK_STATIONARY_WATER);
|
|
||||||
HasHadWater = true;
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
// "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 x
|
||||||
} // for z
|
} // for z
|
||||||
}
|
}
|
||||||
@ -671,21 +614,23 @@ void cBiomalNoise3DComposable::GenerateNoiseArrayIfNeeded(int a_ChunkX, int a_Ch
|
|||||||
NOISE_DATATYPE BaseNoise[5 * 5];
|
NOISE_DATATYPE BaseNoise[5 * 5];
|
||||||
NOISE_DATATYPE BlockX = static_cast<NOISE_DATATYPE>(a_ChunkX * cChunkDef::Width);
|
NOISE_DATATYPE BlockX = static_cast<NOISE_DATATYPE>(a_ChunkX * cChunkDef::Width);
|
||||||
NOISE_DATATYPE BlockZ = static_cast<NOISE_DATATYPE>(a_ChunkZ * 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":
|
// Note that we have to swap the X and Y coords, because noise generator uses [x + SizeX * y + SizeX * SizeY * z] ordering and we want "BlockY" to be "x":
|
||||||
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_ChoiceNoise.Generate3D (ChoiceNoise, 33, 5, 5, 0, 257 / m_ChoiceFrequencyY, BlockX / m_ChoiceFrequencyX, (BlockX + 17) / m_ChoiceFrequencyX, BlockZ / m_ChoiceFrequencyZ, (BlockZ + 17) / m_ChoiceFrequencyZ, 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_DensityNoiseA.Generate3D(DensityNoiseA, 33, 5, 5, 0, 257 / m_FrequencyY, BlockX / m_FrequencyX, (BlockX + 17) / m_FrequencyX, BlockZ / m_FrequencyZ, (BlockZ + 17) / m_FrequencyZ, 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_DensityNoiseB.Generate3D(DensityNoiseB, 33, 5, 5, 0, 257 / m_FrequencyY, BlockX / m_FrequencyX, (BlockX + 17) / m_FrequencyX, BlockZ / m_FrequencyZ, (BlockZ + 17) / m_FrequencyZ, Workspace);
|
||||||
m_BaseNoise.Generate2D (BaseNoise, 5, 5, BlockX / m_BaseFrequencyX, (BlockX + 17) / m_BaseFrequencyX, BlockZ / m_FrequencyZ, (BlockZ + 17) / m_FrequencyZ, 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:
|
// Calculate the final noise based on the partial noises:
|
||||||
for (int y = 0; y < 33; y++)
|
for (int z = 0; z < 5; z++)
|
||||||
{
|
{
|
||||||
NOISE_DATATYPE BlockHeight = static_cast<NOISE_DATATYPE>(y * 8);
|
for (int x = 0; x < 5; x++)
|
||||||
for (int z = 0; z < 5; z++)
|
|
||||||
{
|
{
|
||||||
for (int x = 0; x < 5; x++)
|
NOISE_DATATYPE curMidPoint = MidPoint[x + 5 * z];
|
||||||
|
NOISE_DATATYPE curHeightAmp = HeightAmp[x + 5 * z];
|
||||||
|
NOISE_DATATYPE curBaseNoise = BaseNoise[x + 5 * z];
|
||||||
|
for (int y = 0; y < 33; y++)
|
||||||
{
|
{
|
||||||
NOISE_DATATYPE AddHeight = (BlockHeight - MidPoint[x + 5 * z]) * HeightAmp[x + 5 * z];
|
NOISE_DATATYPE AddHeight = (static_cast<NOISE_DATATYPE>(y * 8) - curMidPoint) * curHeightAmp;
|
||||||
|
|
||||||
// If "underground", make the terrain smoother by forcing the vertical linear gradient into steeper slope:
|
// If "underground", make the terrain smoother by forcing the vertical linear gradient into steeper slope:
|
||||||
if (AddHeight < 0)
|
if (AddHeight < 0)
|
||||||
@ -693,12 +638,12 @@ void cBiomalNoise3DComposable::GenerateNoiseArrayIfNeeded(int a_ChunkX, int a_Ch
|
|||||||
AddHeight *= 4;
|
AddHeight *= 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
int idx = x + 5 * z + 5 * 5 * y;
|
int idx = 33 * x + y + 33 * 5 * z;
|
||||||
Workspace[idx] = ClampedLerp(DensityNoiseA[idx], DensityNoiseB[idx], 8 * (ChoiceNoise[idx] + 0.5f)) + AddHeight + BaseNoise[x + 5 * z];
|
Workspace[idx] = ClampedLerp(DensityNoiseA[idx], DensityNoiseB[idx], 8 * (ChoiceNoise[idx] + 0.5f)) + AddHeight + curBaseNoise;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
LinearUpscale3DArray<NOISE_DATATYPE>(Workspace, 5, 5, 33, m_NoiseArray, 4, 4, 8);
|
LinearUpscale3DArray<NOISE_DATATYPE>(Workspace, 33, 5, 5, m_NoiseArray, 8, 4, 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -778,78 +723,19 @@ void cBiomalNoise3DComposable::GetBiomeParams(EMCSBiome a_Biome, NOISE_DATATYPE
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cBiomalNoise3DComposable::GenShape(int a_ChunkX, int a_ChunkZ, cChunkDesc::Shape & a_Shape)
|
||||||
void cBiomalNoise3DComposable::GenHeightMap(int a_ChunkX, int a_ChunkZ, cChunkDef::HeightMap & a_HeightMap)
|
|
||||||
{
|
{
|
||||||
GenerateNoiseArrayIfNeeded(a_ChunkX, a_ChunkZ);
|
GenerateNoiseArrayIfNeeded(a_ChunkX, a_ChunkZ);
|
||||||
|
|
||||||
|
// Translate the noise array into Shape:
|
||||||
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 x = 0; x < cChunkDef::Width; x++)
|
||||||
{
|
{
|
||||||
cChunkDef::SetHeight(a_HeightMap, x, z, m_SeaLevel);
|
for (int y = 0; y < cChunkDef::Height; y++)
|
||||||
for (int y = cChunkDef::Height - 1; y > m_SeaLevel; y--)
|
|
||||||
{
|
{
|
||||||
if (m_NoiseArray[y * 17 * 17 + z * 17 + x] <= m_AirThreshold)
|
a_Shape[y + x * 256 + z * 256 * 16] = (m_NoiseArray[y + 257 * x + 257 * 17 * z] > m_AirThreshold) ? 0 : 1;
|
||||||
{
|
|
||||||
cChunkDef::SetHeight(a_HeightMap, x, z, y);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} // for y
|
|
||||||
} // for x
|
|
||||||
} // for z
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cBiomalNoise3DComposable::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 x = 0; x < cChunkDef::Width; x++)
|
|
||||||
{
|
|
||||||
int LastAir = a_ChunkDesc.GetHeight(x, z) + 1;
|
|
||||||
bool HasHadWater = false;
|
|
||||||
for (int y = LastAir; y < m_SeaLevel; y++)
|
|
||||||
{
|
|
||||||
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)
|
|
||||||
{
|
|
||||||
// "air" part
|
|
||||||
LastAir = y;
|
|
||||||
if (y < m_SeaLevel)
|
|
||||||
{
|
|
||||||
a_ChunkDesc.SetBlockType(x, y, z, E_BLOCK_STATIONARY_WATER);
|
|
||||||
HasHadWater = true;
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
// "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 x
|
||||||
} // for z
|
} // for z
|
||||||
}
|
}
|
||||||
@ -857,3 +743,4 @@ void cBiomalNoise3DComposable::ComposeTerrain(cChunkDesc & a_ChunkDesc)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -69,8 +69,7 @@ protected:
|
|||||||
|
|
||||||
|
|
||||||
class cNoise3DComposable :
|
class cNoise3DComposable :
|
||||||
public cTerrainHeightGen,
|
public cTerrainShapeGen
|
||||||
public cTerrainCompositionGen
|
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
cNoise3DComposable(int a_Seed);
|
cNoise3DComposable(int a_Seed);
|
||||||
@ -127,12 +126,8 @@ protected:
|
|||||||
void GenerateNoiseArrayIfNeeded(int a_ChunkX, int a_ChunkZ);
|
void GenerateNoiseArrayIfNeeded(int a_ChunkX, int a_ChunkZ);
|
||||||
|
|
||||||
// cTerrainHeightGen overrides:
|
// cTerrainHeightGen overrides:
|
||||||
virtual void GenHeightMap(int a_ChunkX, int a_ChunkZ, cChunkDef::HeightMap & a_HeightMap) override;
|
virtual void GenShape(int a_ChunkX, int a_ChunkZ, cChunkDesc::Shape & a_Shape) override;
|
||||||
virtual void InitializeHeightGen(cIniFile & a_IniFile) override { Initialize(a_IniFile); }
|
virtual void InitializeShapeGen(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); }
|
|
||||||
} ;
|
} ;
|
||||||
|
|
||||||
|
|
||||||
@ -140,8 +135,7 @@ protected:
|
|||||||
|
|
||||||
|
|
||||||
class cBiomalNoise3DComposable :
|
class cBiomalNoise3DComposable :
|
||||||
public cTerrainHeightGen,
|
public cTerrainShapeGen
|
||||||
public cTerrainCompositionGen
|
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
cBiomalNoise3DComposable(int a_Seed, cBiomeGenPtr a_BiomeGen);
|
cBiomalNoise3DComposable(int a_Seed, cBiomeGenPtr a_BiomeGen);
|
||||||
@ -194,7 +188,7 @@ protected:
|
|||||||
// Cache for the last calculated chunk (reused between heightmap and composition queries):
|
// Cache for the last calculated chunk (reused between heightmap and composition queries):
|
||||||
int m_LastChunkX;
|
int m_LastChunkX;
|
||||||
int m_LastChunkZ;
|
int m_LastChunkZ;
|
||||||
NOISE_DATATYPE m_NoiseArray[17 * 17 * 257]; // x + 17 * z + 17 * 17 * y
|
NOISE_DATATYPE m_NoiseArray[17 * 17 * 257]; // 257 * x + y + 257 * 17 * z
|
||||||
|
|
||||||
/** Weights for summing up neighboring biomes. */
|
/** Weights for summing up neighboring biomes. */
|
||||||
NOISE_DATATYPE m_Weight[AVERAGING_SIZE * 2 + 1][AVERAGING_SIZE * 2 + 1];
|
NOISE_DATATYPE m_Weight[AVERAGING_SIZE * 2 + 1][AVERAGING_SIZE * 2 + 1];
|
||||||
@ -212,13 +206,9 @@ protected:
|
|||||||
/** Returns the parameters for the specified biome. */
|
/** Returns the parameters for the specified biome. */
|
||||||
void GetBiomeParams(EMCSBiome a_Biome, NOISE_DATATYPE & a_HeightAmp, NOISE_DATATYPE & a_MidPoint);
|
void GetBiomeParams(EMCSBiome a_Biome, NOISE_DATATYPE & a_HeightAmp, NOISE_DATATYPE & a_MidPoint);
|
||||||
|
|
||||||
// cTerrainHeightGen overrides:
|
// cTerrainShapeGen overrides:
|
||||||
virtual void GenHeightMap(int a_ChunkX, int a_ChunkZ, cChunkDef::HeightMap & a_HeightMap) override;
|
virtual void GenShape(int a_ChunkX, int a_ChunkZ, cChunkDesc::Shape & a_Shape) override;
|
||||||
virtual void InitializeHeightGen(cIniFile & a_IniFile) override { Initialize(a_IniFile); }
|
virtual void InitializeShapeGen(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); }
|
|
||||||
} ;
|
} ;
|
||||||
|
|
||||||
|
|
||||||
|
140
src/Generating/ShapeGen.cpp
Normal file
140
src/Generating/ShapeGen.cpp
Normal file
@ -0,0 +1,140 @@
|
|||||||
|
|
||||||
|
// ShapeGen.cpp
|
||||||
|
|
||||||
|
// Implements the function to create a cTerrainShapeGen descendant based on INI file settings
|
||||||
|
|
||||||
|
#include "Globals.h"
|
||||||
|
#include "HeiGen.h"
|
||||||
|
#include "../IniFile.h"
|
||||||
|
#include "DistortedHeightmap.h"
|
||||||
|
#include "EndGen.h"
|
||||||
|
#include "Noise3DGenerator.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// cTerrainHeightToShapeGen:
|
||||||
|
|
||||||
|
/** Converts old-style height-generators into new-style shape-generators. */
|
||||||
|
class cTerrainHeightToShapeGen:
|
||||||
|
public cTerrainShapeGen
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
cTerrainHeightToShapeGen(cTerrainHeightGenPtr a_HeightGen):
|
||||||
|
m_HeightGen(a_HeightGen)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// cTerrainShapeGen overrides:
|
||||||
|
virtual void GenShape(int a_ChunkX, int a_ChunkZ, cChunkDesc::Shape & a_Shape) override
|
||||||
|
{
|
||||||
|
// Generate the heightmap:
|
||||||
|
cChunkDef::HeightMap heightMap;
|
||||||
|
m_HeightGen->GenHeightMap(a_ChunkX, a_ChunkZ, heightMap);
|
||||||
|
|
||||||
|
// Convert from heightmap to shape:
|
||||||
|
for (int z = 0; z < cChunkDef::Width; z++)
|
||||||
|
{
|
||||||
|
for (int x = 0; x < cChunkDef::Width; x++)
|
||||||
|
{
|
||||||
|
HEIGHTTYPE height = cChunkDef::GetHeight(heightMap, x, z) + 1;
|
||||||
|
Byte * shapeColumn = &(a_Shape[(x + 16 * z) * 256]);
|
||||||
|
for (int y = 0; y < height; y++)
|
||||||
|
{
|
||||||
|
shapeColumn[y] = 1;
|
||||||
|
}
|
||||||
|
for (int y = height; y < cChunkDef::Height; y++)
|
||||||
|
{
|
||||||
|
shapeColumn[y] = 0;
|
||||||
|
}
|
||||||
|
} // for x
|
||||||
|
} // for z
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
virtual void InitializeShapeGen(cIniFile & a_IniFile) override
|
||||||
|
{
|
||||||
|
m_HeightGen->InitializeHeightGen(a_IniFile);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
/** The height generator being converted. */
|
||||||
|
cTerrainHeightGenPtr m_HeightGen;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef SharedPtr<cTerrainHeightToShapeGen> cTerrainHeightToShapeGenPtr;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// cTerrainShapeGen:
|
||||||
|
|
||||||
|
cTerrainShapeGenPtr cTerrainShapeGen::CreateShapeGen(cIniFile & a_IniFile, cBiomeGenPtr a_BiomeGen, int a_Seed, bool & a_CacheOffByDefault)
|
||||||
|
{
|
||||||
|
AString shapeGenName = a_IniFile.GetValueSet("Generator", "ShapeGen", "");
|
||||||
|
if (shapeGenName.empty())
|
||||||
|
{
|
||||||
|
LOGWARN("[Generator] ShapeGen value not set in world.ini, using \"BiomalNoise3D\".");
|
||||||
|
shapeGenName = "BiomalNoise3D";
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the shapegen is HeightMap, redirect to older HeightMap-based generators:
|
||||||
|
if (NoCaseCompare(shapeGenName, "HeightMap") == 0)
|
||||||
|
{
|
||||||
|
cTerrainHeightGenPtr heightGen = cTerrainHeightGen::CreateHeightGen(a_IniFile, a_BiomeGen, a_Seed, a_CacheOffByDefault);
|
||||||
|
if (heightGen != nullptr)
|
||||||
|
{
|
||||||
|
return std::make_shared<cTerrainHeightToShapeGen>(heightGen);
|
||||||
|
}
|
||||||
|
|
||||||
|
// The height gen was not recognized; several heightgens were promoted to shape gens, so let's try them instead:
|
||||||
|
shapeGenName = a_IniFile.GetValue("Generator", "HeightGen", "");
|
||||||
|
if (shapeGenName.empty())
|
||||||
|
{
|
||||||
|
LOGWARNING("[Generator] ShapeGen set to HeightMap, but HeightGen not set. Reverting to \"BiomalNoise3D\".");
|
||||||
|
shapeGenName = "BiomalNoise3D";
|
||||||
|
a_IniFile.SetValue("Generator", "ShapeGen", shapeGenName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Choose the shape generator based on the name:
|
||||||
|
a_CacheOffByDefault = false;
|
||||||
|
cTerrainShapeGenPtr res;
|
||||||
|
if (NoCaseCompare(shapeGenName, "DistortedHeightmap") == 0)
|
||||||
|
{
|
||||||
|
res = std::make_shared<cDistortedHeightmap>(a_Seed, a_BiomeGen);
|
||||||
|
}
|
||||||
|
else if (NoCaseCompare(shapeGenName, "End") == 0)
|
||||||
|
{
|
||||||
|
res = std::make_shared<cEndGen>(a_Seed);
|
||||||
|
}
|
||||||
|
else if (NoCaseCompare(shapeGenName, "BiomalNoise3D") == 0)
|
||||||
|
{
|
||||||
|
res = std::make_shared<cBiomalNoise3DComposable>(a_Seed, a_BiomeGen);
|
||||||
|
}
|
||||||
|
else if (NoCaseCompare(shapeGenName, "Noise3D") == 0)
|
||||||
|
{
|
||||||
|
res = std::make_shared<cNoise3DComposable>(a_Seed);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// No match found, force-set the default and retry
|
||||||
|
LOGWARN("Unknown ShapeGen \"%s\", using \"BiomalNoise3D\" instead.", shapeGenName.c_str());
|
||||||
|
a_IniFile.SetValue("Generator", "ShapeGen", "BiomalNoise3D");
|
||||||
|
return CreateShapeGen(a_IniFile, a_BiomeGen, a_Seed, a_CacheOffByDefault);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read the settings:
|
||||||
|
res->InitializeShapeGen(a_IniFile);
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -37,10 +37,12 @@ void cStructGenTrees::GenFinish(cChunkDesc & a_ChunkDesc)
|
|||||||
Dest = &WorkerDesc;
|
Dest = &WorkerDesc;
|
||||||
WorkerDesc.SetChunkCoords(BaseX, BaseZ);
|
WorkerDesc.SetChunkCoords(BaseX, BaseZ);
|
||||||
|
|
||||||
|
// TODO: This may cause a lot of wasted calculations, instead of pulling data out of a single (cChunkDesc) cache
|
||||||
|
|
||||||
|
cChunkDesc::Shape workerShape;
|
||||||
m_BiomeGen->GenBiomes (BaseX, BaseZ, WorkerDesc.GetBiomeMap());
|
m_BiomeGen->GenBiomes (BaseX, BaseZ, WorkerDesc.GetBiomeMap());
|
||||||
m_HeightGen->GenHeightMap (BaseX, BaseZ, WorkerDesc.GetHeightMap());
|
m_ShapeGen->GenShape (BaseX, BaseZ, workerShape);
|
||||||
m_CompositionGen->ComposeTerrain(WorkerDesc);
|
m_CompositionGen->ComposeTerrain(WorkerDesc, workerShape);
|
||||||
// TODO: Free the entity lists
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -390,7 +392,7 @@ void cStructGenLakes::GenFinish(cChunkDesc & a_ChunkDesc)
|
|||||||
}
|
}
|
||||||
|
|
||||||
cBlockArea Lake;
|
cBlockArea Lake;
|
||||||
CreateLakeImage(ChunkX + x, ChunkZ + z, Lake);
|
CreateLakeImage(ChunkX + x, ChunkZ + z, a_ChunkDesc.GetMinHeight(), Lake);
|
||||||
|
|
||||||
int OfsX = Lake.GetOriginX() + x * cChunkDef::Width;
|
int OfsX = Lake.GetOriginX() + x * cChunkDef::Width;
|
||||||
int OfsZ = Lake.GetOriginZ() + z * cChunkDef::Width;
|
int OfsZ = Lake.GetOriginZ() + z * cChunkDef::Width;
|
||||||
@ -404,25 +406,13 @@ void cStructGenLakes::GenFinish(cChunkDesc & a_ChunkDesc)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cStructGenLakes::CreateLakeImage(int a_ChunkX, int a_ChunkZ, cBlockArea & a_Lake)
|
void cStructGenLakes::CreateLakeImage(int a_ChunkX, int a_ChunkZ, int a_MaxLakeHeight, cBlockArea & a_Lake)
|
||||||
{
|
{
|
||||||
a_Lake.Create(16, 8, 16);
|
a_Lake.Create(16, 8, 16);
|
||||||
a_Lake.Fill(cBlockArea::baTypes, E_BLOCK_SPONGE); // Sponge is the NOP blocktype for lake merging strategy
|
a_Lake.Fill(cBlockArea::baTypes, E_BLOCK_SPONGE); // Sponge is the NOP blocktype for lake merging strategy
|
||||||
|
|
||||||
// Find the minimum height in this chunk:
|
|
||||||
cChunkDef::HeightMap HeightMap;
|
|
||||||
m_HeiGen->GenHeightMap(a_ChunkX, a_ChunkZ, HeightMap);
|
|
||||||
HEIGHTTYPE MinHeight = HeightMap[0];
|
|
||||||
for (size_t i = 1; i < ARRAYCOUNT(HeightMap); i++)
|
|
||||||
{
|
|
||||||
if (HeightMap[i] < MinHeight)
|
|
||||||
{
|
|
||||||
MinHeight = HeightMap[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Make a random position in the chunk by using a random 16 block XZ offset and random height up to chunk's max height minus 6
|
// Make a random position in the chunk by using a random 16 block XZ offset and random height up to chunk's max height minus 6
|
||||||
MinHeight = std::max(MinHeight - 6, 2);
|
int MinHeight = std::max(a_MaxLakeHeight - 6, 2);
|
||||||
int Rnd = m_Noise.IntNoise3DInt(a_ChunkX, 128, a_ChunkZ) / 11;
|
int Rnd = m_Noise.IntNoise3DInt(a_ChunkX, 128, a_ChunkZ) / 11;
|
||||||
// Random offset [-8 .. 8], with higher probability around 0; add up four three-bit-wide randoms [0 .. 28], divide and subtract to get range
|
// Random offset [-8 .. 8], with higher probability around 0; add up four three-bit-wide randoms [0 .. 28], divide and subtract to get range
|
||||||
int OffsetX = 4 * ((Rnd & 0x07) + ((Rnd & 0x38) >> 3) + ((Rnd & 0x1c0) >> 6) + ((Rnd & 0xe00) >> 9)) / 7 - 8;
|
int OffsetX = 4 * ((Rnd & 0x07) + ((Rnd & 0x38) >> 3) + ((Rnd & 0x1c0) >> 6) + ((Rnd & 0xe00) >> 9)) / 7 - 8;
|
||||||
|
@ -24,11 +24,11 @@ class cStructGenTrees :
|
|||||||
public cFinishGen
|
public cFinishGen
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
cStructGenTrees(int a_Seed, cBiomeGenPtr a_BiomeGen, cTerrainHeightGenPtr a_HeightGen, cTerrainCompositionGenPtr a_CompositionGen) :
|
cStructGenTrees(int a_Seed, cBiomeGenPtr a_BiomeGen, cTerrainShapeGenPtr a_ShapeGen, cTerrainCompositionGenPtr a_CompositionGen) :
|
||||||
m_Seed(a_Seed),
|
m_Seed(a_Seed),
|
||||||
m_Noise(a_Seed),
|
m_Noise(a_Seed),
|
||||||
m_BiomeGen(a_BiomeGen),
|
m_BiomeGen(a_BiomeGen),
|
||||||
m_HeightGen(a_HeightGen),
|
m_ShapeGen(a_ShapeGen),
|
||||||
m_CompositionGen(a_CompositionGen)
|
m_CompositionGen(a_CompositionGen)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
@ -37,12 +37,12 @@ protected:
|
|||||||
int m_Seed;
|
int m_Seed;
|
||||||
cNoise m_Noise;
|
cNoise m_Noise;
|
||||||
cBiomeGenPtr m_BiomeGen;
|
cBiomeGenPtr m_BiomeGen;
|
||||||
cTerrainHeightGenPtr m_HeightGen;
|
cTerrainShapeGenPtr m_ShapeGen;
|
||||||
cTerrainCompositionGenPtr m_CompositionGen;
|
cTerrainCompositionGenPtr m_CompositionGen;
|
||||||
|
|
||||||
/** Generates and applies an image of a single tree.
|
/** Generates and applies an image of a single tree.
|
||||||
Parts of the tree inside the chunk are applied to a_BlockX.
|
Parts of the tree inside the chunk are applied to a_ChunkDesc.
|
||||||
Parts of the tree outside the chunk are stored in a_OutsideX
|
Parts of the tree outside the chunk are stored in a_OutsideXYZ
|
||||||
*/
|
*/
|
||||||
void GenerateSingleTree(
|
void GenerateSingleTree(
|
||||||
int a_ChunkX, int a_ChunkZ, int a_Seq,
|
int a_ChunkX, int a_ChunkZ, int a_Seq,
|
||||||
@ -51,7 +51,7 @@ protected:
|
|||||||
sSetBlockVector & a_OutsideOther
|
sSetBlockVector & a_OutsideOther
|
||||||
) ;
|
) ;
|
||||||
|
|
||||||
/// Applies an image into chunk blockdata; all blocks outside the chunk will be appended to a_Overflow
|
/** Applies an image into chunk blockdata; all blocks outside the chunk will be appended to a_Overflow. */
|
||||||
void ApplyTreeImage(
|
void ApplyTreeImage(
|
||||||
int a_ChunkX, int a_ChunkZ,
|
int a_ChunkX, int a_ChunkZ,
|
||||||
cChunkDesc & a_ChunkDesc,
|
cChunkDesc & a_ChunkDesc,
|
||||||
@ -124,27 +124,30 @@ class cStructGenLakes :
|
|||||||
public cFinishGen
|
public cFinishGen
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
cStructGenLakes(int a_Seed, BLOCKTYPE a_Fluid, cTerrainHeightGenPtr a_HeiGen, int a_Probability) :
|
cStructGenLakes(int a_Seed, BLOCKTYPE a_Fluid, cTerrainShapeGenPtr a_ShapeGen, int a_Probability) :
|
||||||
m_Noise(a_Seed),
|
m_Noise(a_Seed),
|
||||||
m_Seed(a_Seed),
|
m_Seed(a_Seed),
|
||||||
m_Fluid(a_Fluid),
|
m_Fluid(a_Fluid),
|
||||||
m_HeiGen(a_HeiGen),
|
m_ShapeGen(a_ShapeGen),
|
||||||
m_Probability(a_Probability)
|
m_Probability(a_Probability)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
cNoise m_Noise;
|
cNoise m_Noise;
|
||||||
int m_Seed;
|
int m_Seed;
|
||||||
BLOCKTYPE m_Fluid;
|
BLOCKTYPE m_Fluid;
|
||||||
cTerrainHeightGenPtr m_HeiGen;
|
cTerrainShapeGenPtr m_ShapeGen;
|
||||||
int m_Probability; ///< Chance, 0 .. 100, of a chunk having the lake
|
|
||||||
|
/** Chance, [0 .. 100], of a chunk having the lake. */
|
||||||
|
int m_Probability;
|
||||||
|
|
||||||
|
|
||||||
// cFinishGen override:
|
// cFinishGen override:
|
||||||
virtual void GenFinish(cChunkDesc & a_ChunkDesc) override;
|
virtual void GenFinish(cChunkDesc & a_ChunkDesc) override;
|
||||||
|
|
||||||
/// Creates a lake image for the specified chunk into a_Lake
|
/** Creates a lake image for the specified chunk into a_Lake. */
|
||||||
void CreateLakeImage(int a_ChunkX, int a_ChunkZ, cBlockArea & a_Lake);
|
void CreateLakeImage(int a_ChunkX, int a_ChunkZ, int a_MaxLakeHeight, cBlockArea & a_Lake);
|
||||||
} ;
|
} ;
|
||||||
|
|
||||||
|
|
||||||
|
@ -18,8 +18,8 @@
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
How village generating works:
|
How village generating works:
|
||||||
By descending from a cGridStructGen, a semi-random grid is generated. A village may be generated for each of
|
By descending from a cGridStructGen, a semi-random (jitter) grid is generated. A village may be generated for each
|
||||||
the grid's cells. Each cell checks the biomes in an entire chunk around it, only generating a village if all
|
of the grid's cells. Each cell checks the biomes in an entire chunk around it, only generating a village if all
|
||||||
biomes are village-friendly. If yes, the entire village structure is built for that cell. If not, the cell
|
biomes are village-friendly. If yes, the entire village structure is built for that cell. If not, the cell
|
||||||
is left village-less.
|
is left village-less.
|
||||||
|
|
||||||
@ -125,7 +125,7 @@ public:
|
|||||||
m_Noise(a_Seed),
|
m_Noise(a_Seed),
|
||||||
m_MaxSize(a_MaxSize),
|
m_MaxSize(a_MaxSize),
|
||||||
m_Density(a_Density),
|
m_Density(a_Density),
|
||||||
m_Borders(a_OriginX - a_MaxSize, 0, a_OriginZ - a_MaxSize, a_OriginX + a_MaxSize, 255, a_OriginZ + a_MaxSize),
|
m_Borders(a_OriginX - a_MaxSize, 0, a_OriginZ - a_MaxSize, a_OriginX + a_MaxSize, cChunkDef::Height - 1, a_OriginZ + a_MaxSize),
|
||||||
m_Prefabs(a_Prefabs),
|
m_Prefabs(a_Prefabs),
|
||||||
m_HeightGen(a_HeightGen),
|
m_HeightGen(a_HeightGen),
|
||||||
m_RoadBlock(a_RoadBlock),
|
m_RoadBlock(a_RoadBlock),
|
||||||
|
Loading…
Reference in New Issue
Block a user