Merge remote-tracking branch 'origin-master' into c++11
This commit is contained in:
parent
2ae4d2a96a
commit
187bdab4fa
@ -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
|
||||||
@ -30,8 +31,10 @@ SET (SRCS
|
|||||||
StructGen.cpp
|
StructGen.cpp
|
||||||
TestRailsGen.cpp
|
TestRailsGen.cpp
|
||||||
Trees.cpp
|
Trees.cpp
|
||||||
|
TwoHeights.cpp
|
||||||
UnderwaterBaseGen.cpp
|
UnderwaterBaseGen.cpp
|
||||||
VillageGen.cpp)
|
VillageGen.cpp
|
||||||
|
)
|
||||||
|
|
||||||
SET (HDRS
|
SET (HDRS
|
||||||
BioGen.h
|
BioGen.h
|
||||||
@ -39,7 +42,9 @@ SET (HDRS
|
|||||||
ChunkDesc.h
|
ChunkDesc.h
|
||||||
ChunkGenerator.h
|
ChunkGenerator.h
|
||||||
CompoGen.h
|
CompoGen.h
|
||||||
|
CompoGenBiomal.h
|
||||||
ComposableGenerator.h
|
ComposableGenerator.h
|
||||||
|
CompositedHeiGen.h
|
||||||
DistortedHeightmap.h
|
DistortedHeightmap.h
|
||||||
DungeonRoomsFinisher.h
|
DungeonRoomsFinisher.h
|
||||||
EndGen.h
|
EndGen.h
|
||||||
@ -58,11 +63,14 @@ 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
|
||||||
|
TwoHeights.h
|
||||||
UnderwaterBaseGen.h
|
UnderwaterBaseGen.h
|
||||||
VillageGen.h)
|
VillageGen.h
|
||||||
|
)
|
||||||
|
|
||||||
if(NOT MSVC)
|
if(NOT MSVC)
|
||||||
add_library(Generating ${SRCS} ${HDRS})
|
add_library(Generating ${SRCS} ${HDRS})
|
||||||
|
@ -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,
|
||||||
|
@ -30,9 +30,16 @@ 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 * x + 256 * 16 * z]. */
|
||||||
|
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,9 +95,12 @@ 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(
|
||||||
int a_MinX, int a_MaxX,
|
int a_MinX, int a_MaxX,
|
||||||
|
@ -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} ;
|
||||||
@ -194,7 +197,7 @@ void cCompoGenClassic::ComposeTerrain(cChunkDesc & a_ChunkDesc)
|
|||||||
|
|
||||||
void cCompoGenClassic::InitializeCompoGen(cIniFile & a_IniFile)
|
void cCompoGenClassic::InitializeCompoGen(cIniFile & a_IniFile)
|
||||||
{
|
{
|
||||||
m_SeaLevel = a_IniFile.GetValueSetI("Generator", "ClassicSeaLevel", m_SeaLevel);
|
m_SeaLevel = a_IniFile.GetValueSetI("Generator", "SeaLevel", m_SeaLevel);
|
||||||
m_BeachHeight = a_IniFile.GetValueSetI("Generator", "ClassicBeachHeight", m_BeachHeight);
|
m_BeachHeight = a_IniFile.GetValueSetI("Generator", "ClassicBeachHeight", m_BeachHeight);
|
||||||
m_BeachDepth = a_IniFile.GetValueSetI("Generator", "ClassicBeachDepth", m_BeachDepth);
|
m_BeachDepth = a_IniFile.GetValueSetI("Generator", "ClassicBeachDepth", m_BeachDepth);
|
||||||
m_BlockTop = (BLOCKTYPE)(GetIniItemSet(a_IniFile, "Generator", "ClassicBlockTop", "grass").m_ItemType);
|
m_BlockTop = (BLOCKTYPE)(GetIniItemSet(a_IniFile, "Generator", "ClassicBlockTop", "grass").m_ItemType);
|
||||||
@ -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)
|
||||||
@ -731,6 +417,7 @@ void cCompoGenCache::ComposeTerrain(cChunkDesc & a_ChunkDesc)
|
|||||||
// Use the cached data:
|
// Use the cached data:
|
||||||
memcpy(a_ChunkDesc.GetBlockTypes(), m_CacheData[Idx].m_BlockTypes, sizeof(a_ChunkDesc.GetBlockTypes()));
|
memcpy(a_ChunkDesc.GetBlockTypes(), m_CacheData[Idx].m_BlockTypes, sizeof(a_ChunkDesc.GetBlockTypes()));
|
||||||
memcpy(a_ChunkDesc.GetBlockMetasUncompressed(), m_CacheData[Idx].m_BlockMetas, sizeof(a_ChunkDesc.GetBlockMetasUncompressed()));
|
memcpy(a_ChunkDesc.GetBlockMetasUncompressed(), m_CacheData[Idx].m_BlockMetas, sizeof(a_ChunkDesc.GetBlockMetasUncompressed()));
|
||||||
|
memcpy(a_ChunkDesc.GetHeightMap(), m_CacheData[Idx].m_HeightMap, sizeof(a_ChunkDesc.GetHeightMap()));
|
||||||
|
|
||||||
m_NumHits++;
|
m_NumHits++;
|
||||||
m_TotalChain += i;
|
m_TotalChain += i;
|
||||||
@ -739,7 +426,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];
|
||||||
@ -750,6 +437,7 @@ void cCompoGenCache::ComposeTerrain(cChunkDesc & a_ChunkDesc)
|
|||||||
m_CacheOrder[0] = Idx;
|
m_CacheOrder[0] = Idx;
|
||||||
memcpy(m_CacheData[Idx].m_BlockTypes, a_ChunkDesc.GetBlockTypes(), sizeof(a_ChunkDesc.GetBlockTypes()));
|
memcpy(m_CacheData[Idx].m_BlockTypes, a_ChunkDesc.GetBlockTypes(), sizeof(a_ChunkDesc.GetBlockTypes()));
|
||||||
memcpy(m_CacheData[Idx].m_BlockMetas, a_ChunkDesc.GetBlockMetasUncompressed(), sizeof(a_ChunkDesc.GetBlockMetasUncompressed()));
|
memcpy(m_CacheData[Idx].m_BlockMetas, a_ChunkDesc.GetBlockMetasUncompressed(), sizeof(a_ChunkDesc.GetBlockMetasUncompressed()));
|
||||||
|
memcpy(m_CacheData[Idx].m_HeightMap, a_ChunkDesc.GetHeightMap(), sizeof(a_ChunkDesc.GetHeightMap()));
|
||||||
m_CacheData[Idx].m_ChunkX = ChunkX;
|
m_CacheData[Idx].m_ChunkX = ChunkX;
|
||||||
m_CacheData[Idx].m_ChunkZ = ChunkZ;
|
m_CacheData[Idx].m_ChunkZ = ChunkZ;
|
||||||
}
|
}
|
||||||
|
@ -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:
|
||||||
@ -166,6 +132,7 @@ protected:
|
|||||||
int m_ChunkZ;
|
int m_ChunkZ;
|
||||||
cChunkDef::BlockTypes m_BlockTypes;
|
cChunkDef::BlockTypes m_BlockTypes;
|
||||||
cChunkDesc::BlockNibbleBytes m_BlockMetas; // The metas are uncompressed, 1 meta per byte
|
cChunkDesc::BlockNibbleBytes m_BlockMetas; // The metas are uncompressed, 1 meta per byte
|
||||||
|
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
|
// To avoid moving large amounts of data for the MRU behavior, we MRU-ize indices to an array of the actual data
|
||||||
|
586
src/Generating/CompoGenBiomal.cpp
Normal file
586
src/Generating/CompoGenBiomal.cpp
Normal file
@ -0,0 +1,586 @@
|
|||||||
|
|
||||||
|
// CompoGenBiomal.cpp
|
||||||
|
|
||||||
|
// Implements the cCompoGenBiomal class representing the biome-aware composition generator
|
||||||
|
|
||||||
|
#include "Globals.h"
|
||||||
|
#include "ComposableGenerator.h"
|
||||||
|
#include "../IniFile.h"
|
||||||
|
#include "../Noise/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);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/** 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;
|
||||||
|
int top = std::max(m_SeaLevel, a_ChunkDesc.GetHeight(a_RelX, a_RelZ));
|
||||||
|
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, 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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} ;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
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,10 @@
|
|||||||
#include "StructGen.h"
|
#include "StructGen.h"
|
||||||
#include "FinishGen.h"
|
#include "FinishGen.h"
|
||||||
|
|
||||||
|
#include "CompoGenBiomal.h"
|
||||||
|
|
||||||
|
#include "CompositedHeiGen.h"
|
||||||
|
|
||||||
#include "Caves.h"
|
#include "Caves.h"
|
||||||
#include "DistortedHeightmap.h"
|
#include "DistortedHeightmap.h"
|
||||||
#include "DungeonRoomsFinisher.h"
|
#include "DungeonRoomsFinisher.h"
|
||||||
@ -39,7 +43,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 +52,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 +117,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 +131,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,16 +159,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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (a_ChunkDesc.IsUsingDefaultFinish())
|
if (a_ChunkDesc.IsUsingDefaultFinish())
|
||||||
@ -234,13 +233,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 +254,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,13 +263,19 @@ 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());
|
||||||
|
|
||||||
|
// Add a cache over the composition generator:
|
||||||
|
// Even a cache of size 1 is useful due to the CompositedHeiGen cache after us doing re-composition on its misses
|
||||||
int CompoGenCacheSize = a_IniFile.GetValueSetI("Generator", "CompositionGenCacheSize", 64);
|
int CompoGenCacheSize = a_IniFile.GetValueSetI("Generator", "CompositionGenCacheSize", 64);
|
||||||
if (CompoGenCacheSize > 1)
|
if (CompoGenCacheSize > 0)
|
||||||
{
|
{
|
||||||
m_CompositionGen = cTerrainCompositionGenPtr(new cCompoGenCache(m_CompositionGen, 32));
|
m_CompositionGen = std::make_shared<cCompoGenCache>(m_CompositionGen, CompoGenCacheSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Create a cache of the composited heightmaps, so that finishers may use it:
|
||||||
|
m_CompositedHeightCache = std::make_shared<cHeiGenMultiCache>(std::make_shared<cCompositedHeiGen>(m_ShapeGen, m_CompositionGen), 16, 24);
|
||||||
|
// 24 subcaches of depth 16 each = 96 KiB of RAM. Acceptable, for the amount of work this saves.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -333,7 +341,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 +350,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 +588,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 +596,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 +606,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);
|
||||||
|
49
src/Generating/CompositedHeiGen.h
Normal file
49
src/Generating/CompositedHeiGen.h
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
|
||||||
|
// CompositedHeiGen.h
|
||||||
|
|
||||||
|
// Declares the cCompositedHeiGen class representing a cTerrainHeightGen descendant that calculates heightmap of the composited terrain
|
||||||
|
// This is used to further cache heightmaps for chunks already generated for finishers that require only heightmap information
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "ComposableGenerator.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class cCompositedHeiGen:
|
||||||
|
public cTerrainHeightGen
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
cCompositedHeiGen(cTerrainShapeGenPtr a_ShapeGen, cTerrainCompositionGenPtr a_CompositionGen):
|
||||||
|
m_ShapeGen(a_ShapeGen),
|
||||||
|
m_CompositionGen(a_CompositionGen)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// cTerrainheightGen overrides:
|
||||||
|
virtual void GenHeightMap(int a_ChunkX, int a_ChunkZ, cChunkDef::HeightMap & a_HeightMap) override
|
||||||
|
{
|
||||||
|
cChunkDesc::Shape shape;
|
||||||
|
m_ShapeGen->GenShape(a_ChunkX, a_ChunkZ, shape);
|
||||||
|
cChunkDesc desc(a_ChunkX, a_ChunkZ);
|
||||||
|
desc.SetHeightFromShape(shape);
|
||||||
|
m_CompositionGen->ComposeTerrain(desc, shape);
|
||||||
|
memcpy(a_HeightMap, desc.GetHeightMap(), sizeof(a_HeightMap));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
cTerrainShapeGenPtr m_ShapeGen;
|
||||||
|
cTerrainCompositionGenPtr m_CompositionGen;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -23,17 +23,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:
|
||||||
@ -51,8 +43,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;
|
||||||
@ -70,9 +60,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:
|
||||||
@ -87,54 +77,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];
|
|
||||||
|
|
||||||
|
/** Unless the LastChunk coords are equal to coords given, prepares the internal state (noise arrays, heightmap). */
|
||||||
/// Initializes m_MesaPattern with a reasonable pattern of stained clay / hardened clay, based on the seed
|
|
||||||
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;
|
|
||||||
} ;
|
} ;
|
||||||
|
@ -78,7 +78,8 @@ protected:
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
/** Decodes the position index along the room walls into a proper 2D position for a chest. */
|
/** Decodes the position index along the room walls into a proper 2D position for a chest.
|
||||||
|
The Y coord of the returned vector specifies the chest's meta value*/
|
||||||
Vector3i DecodeChestCoords(int a_PosIdx, int a_SizeX, int a_SizeZ)
|
Vector3i DecodeChestCoords(int a_PosIdx, int a_SizeX, int a_SizeZ)
|
||||||
{
|
{
|
||||||
if (a_PosIdx < a_SizeX)
|
if (a_PosIdx < a_SizeX)
|
||||||
@ -258,9 +259,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,13 +294,21 @@ 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);
|
||||||
cChunkDef::HeightMap HeightMap;
|
cChunkDesc::Shape shape;
|
||||||
m_HeightGen->GenHeightMap(ChunkX, ChunkZ, HeightMap);
|
m_ShapeGen->GenShape(ChunkX, ChunkZ, shape);
|
||||||
int Height = cChunkDef::GetHeight(HeightMap, RelX, RelZ); // Max room height at {a_OriginX, a_OriginZ}
|
int height = 0;
|
||||||
Height = Clamp(m_HeightProbability.MapValue(rnd % m_HeightProbability.GetSum()), 10, Height - 5);
|
int idx = RelX * 256 + RelZ * 16 * 256;
|
||||||
|
for (int y = 6; y < cChunkDef::Height; y++)
|
||||||
|
{
|
||||||
|
if (shape[idx + y] != 0)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
height = Clamp(m_HeightProbability.MapValue(rnd % m_HeightProbability.GetSum()), 10, y - 5);
|
||||||
|
}
|
||||||
|
|
||||||
// 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;
|
||||||
} ;
|
} ;
|
||||||
|
@ -411,7 +411,7 @@ void cFinishGenSnow::GenFinish(cChunkDesc & a_ChunkDesc)
|
|||||||
case biFrozenOcean:
|
case biFrozenOcean:
|
||||||
{
|
{
|
||||||
int Height = a_ChunkDesc.GetHeight(x, z);
|
int Height = a_ChunkDesc.GetHeight(x, z);
|
||||||
if (cBlockInfo::IsSnowable(a_ChunkDesc.GetBlockType(x, Height, z)))
|
if (cBlockInfo::IsSnowable(a_ChunkDesc.GetBlockType(x, Height, z)) && (Height < cChunkDef::Height - 1))
|
||||||
{
|
{
|
||||||
a_ChunkDesc.SetBlockType(x, Height + 1, z, E_BLOCK_SNOW);
|
a_ChunkDesc.SetBlockType(x, Height + 1, z, E_BLOCK_SNOW);
|
||||||
a_ChunkDesc.SetHeight(x, z, Height + 1);
|
a_ChunkDesc.SetHeight(x, z, Height + 1);
|
||||||
|
@ -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++)
|
||||||
@ -159,6 +149,51 @@ bool cHeiGenCache::GetHeightAt(int a_ChunkX, int a_ChunkZ, int a_RelX, int a_Rel
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// cHeiGenMultiCache:
|
||||||
|
|
||||||
|
cHeiGenMultiCache::cHeiGenMultiCache(cTerrainHeightGenPtr a_HeiGenToCache, size_t a_SubCacheSize, size_t a_NumSubCaches):
|
||||||
|
m_NumSubCaches(a_NumSubCaches)
|
||||||
|
{
|
||||||
|
// Create the individual sub-caches:
|
||||||
|
m_SubCaches.reserve(a_NumSubCaches);
|
||||||
|
for (size_t i = 0; i < a_NumSubCaches; i++)
|
||||||
|
{
|
||||||
|
m_SubCaches.push_back(std::make_shared<cHeiGenCache>(a_HeiGenToCache, a_SubCacheSize));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cHeiGenMultiCache::GenHeightMap(int a_ChunkX, int a_ChunkZ, cChunkDef::HeightMap & a_HeightMap)
|
||||||
|
{
|
||||||
|
// Get the subcache responsible for this chunk:
|
||||||
|
const size_t cacheIdx = ((size_t)a_ChunkX + m_CoeffZ * (size_t)a_ChunkZ) % m_NumSubCaches;
|
||||||
|
|
||||||
|
// Ask the subcache:
|
||||||
|
m_SubCaches[cacheIdx]->GenHeightMap(a_ChunkX, a_ChunkZ, a_HeightMap);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
bool cHeiGenMultiCache::GetHeightAt(int a_ChunkX, int a_ChunkZ, int a_RelX, int a_RelZ, HEIGHTTYPE & a_Height)
|
||||||
|
{
|
||||||
|
// Get the subcache responsible for this chunk:
|
||||||
|
const size_t cacheIdx = ((size_t)a_ChunkX + m_CoeffZ * (size_t)a_ChunkZ) % m_NumSubCaches;
|
||||||
|
|
||||||
|
// Ask the subcache:
|
||||||
|
return m_SubCaches[cacheIdx]->GetHeightAt(a_ChunkX, a_ChunkZ, a_RelX, a_RelZ, a_Height);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
// cHeiGenClassic:
|
// cHeiGenClassic:
|
||||||
|
|
||||||
@ -750,43 +785,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,7 +848,6 @@ 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);
|
||||||
}
|
}
|
||||||
@ -813,7 +855,7 @@ cTerrainHeightGenPtr cTerrainHeightGen::CreateHeightGen(cIniFile & a_IniFile, cB
|
|||||||
// 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,78 @@ 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)
|
||||||
|
} ;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/** Caches heightmaps in multiple underlying caches to improve the distribution and lower the chain length. */
|
||||||
|
class cHeiGenMultiCache:
|
||||||
|
public cTerrainHeightGen
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
cHeiGenMultiCache(cTerrainHeightGenPtr a_HeightGenToCache, size_t a_SubCacheSize, size_t a_NumSubCaches);
|
||||||
|
|
||||||
|
// 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:
|
||||||
|
typedef SharedPtr<cHeiGenCache> cHeiGenCachePtr;
|
||||||
|
typedef std::vector<cHeiGenCachePtr> cHeiGenCachePtrs;
|
||||||
|
|
||||||
|
|
||||||
|
/** The coefficient used to turn Z coords into index (x + Coeff * z). */
|
||||||
|
static const size_t m_CoeffZ = 5;
|
||||||
|
|
||||||
|
/** Number of sub-caches, pulled out of m_SubCaches.size() for performance reasons. */
|
||||||
|
size_t m_NumSubCaches;
|
||||||
|
|
||||||
|
/** The individual sub-caches. */
|
||||||
|
cHeiGenCachePtrs m_SubCaches;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class cHeiGenFlat :
|
class cHeiGenFlat :
|
||||||
public cTerrainHeightGen
|
public cTerrainHeightGen
|
||||||
{
|
{
|
||||||
@ -40,47 +114,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
|
||||||
{
|
{
|
||||||
@ -138,6 +171,10 @@ public:
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// cTerrainHeightGen overrides:
|
||||||
|
virtual void GenHeightMap(int a_ChunkX, int a_ChunkZ, cChunkDef::HeightMap & a_HeightMap) override;
|
||||||
|
virtual void InitializeHeightGen(cIniFile & a_IniFile) override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
typedef cChunkDef::BiomeMap BiomeNeighbors[3][3];
|
typedef cChunkDef::BiomeMap BiomeNeighbors[3][3];
|
||||||
@ -155,9 +192,6 @@ protected:
|
|||||||
} ;
|
} ;
|
||||||
static const sGenParam m_GenParam[256];
|
static const sGenParam m_GenParam[256];
|
||||||
|
|
||||||
// cTerrainHeightGen overrides:
|
|
||||||
virtual void GenHeightMap(int a_ChunkX, int a_ChunkZ, cChunkDef::HeightMap & a_HeightMap) override;
|
|
||||||
virtual void InitializeHeightGen(cIniFile & a_IniFile) override;
|
|
||||||
|
|
||||||
NOISE_DATATYPE GetHeightAt(int a_RelX, int a_RelZ, int a_ChunkX, int a_ChunkZ, const BiomeNeighbors & a_BiomeNeighbors);
|
NOISE_DATATYPE GetHeightAt(int a_RelX, int a_RelZ, int a_ChunkX, int a_ChunkZ, const BiomeNeighbors & a_BiomeNeighbors);
|
||||||
} ;
|
} ;
|
||||||
|
@ -165,69 +165,6 @@ cNoise3DGenerator::cNoise3DGenerator(cChunkGenerator & a_ChunkGenerator) :
|
|||||||
m_Cubic.AddOctave(4, 0.25);
|
m_Cubic.AddOctave(4, 0.25);
|
||||||
m_Cubic.AddOctave(8, 0.125);
|
m_Cubic.AddOctave(8, 0.125);
|
||||||
m_Cubic.AddOctave(16, 0.0625);
|
m_Cubic.AddOctave(16, 0.0625);
|
||||||
|
|
||||||
#if 0
|
|
||||||
// DEBUG: Test the noise generation:
|
|
||||||
// NOTE: In order to be able to run MCS with this code, you need to increase the default thread stack size
|
|
||||||
// In MSVC, it is done in Project Settings -> Configuration Properties -> Linker -> System, set Stack reserve size to at least 64M
|
|
||||||
m_SeaLevel = 62;
|
|
||||||
m_HeightAmplification = 0;
|
|
||||||
m_MidPoint = 75;
|
|
||||||
m_FrequencyX = 4;
|
|
||||||
m_FrequencyY = 4;
|
|
||||||
m_FrequencyZ = 4;
|
|
||||||
m_AirThreshold = 0.5;
|
|
||||||
|
|
||||||
const int NumChunks = 4;
|
|
||||||
NOISE_DATATYPE Noise[NumChunks][cChunkDef::Width * cChunkDef::Width * cChunkDef::Height];
|
|
||||||
for (int x = 0; x < NumChunks; x++)
|
|
||||||
{
|
|
||||||
GenerateNoiseArray(x, 5, Noise[x]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Save in XY cuts:
|
|
||||||
cFile f1;
|
|
||||||
if (f1.Open("Test_XY.grab", cFile::fmWrite))
|
|
||||||
{
|
|
||||||
for (int z = 0; z < cChunkDef::Width; z++)
|
|
||||||
{
|
|
||||||
for (int y = 0; y < cChunkDef::Height; y++)
|
|
||||||
{
|
|
||||||
for (int i = 0; i < NumChunks; i++)
|
|
||||||
{
|
|
||||||
int idx = y * cChunkDef::Width + z * cChunkDef::Width * cChunkDef::Height;
|
|
||||||
unsigned char buf[cChunkDef::Width];
|
|
||||||
for (int x = 0; x < cChunkDef::Width; x++)
|
|
||||||
{
|
|
||||||
buf[x] = (unsigned char)(std::min(256, std::max(0, (int)(128 + 32 * Noise[i][idx++]))));
|
|
||||||
}
|
|
||||||
f1.Write(buf, cChunkDef::Width);
|
|
||||||
}
|
|
||||||
} // for y
|
|
||||||
} // for z
|
|
||||||
} // if (XY file open)
|
|
||||||
|
|
||||||
cFile f2;
|
|
||||||
if (f2.Open("Test_XZ.grab", cFile::fmWrite))
|
|
||||||
{
|
|
||||||
for (int y = 0; y < cChunkDef::Height; y++)
|
|
||||||
{
|
|
||||||
for (int z = 0; z < cChunkDef::Width; z++)
|
|
||||||
{
|
|
||||||
for (int i = 0; i < NumChunks; i++)
|
|
||||||
{
|
|
||||||
int idx = y * cChunkDef::Width + z * cChunkDef::Width * cChunkDef::Height;
|
|
||||||
unsigned char buf[cChunkDef::Width];
|
|
||||||
for (int x = 0; x < cChunkDef::Width; x++)
|
|
||||||
{
|
|
||||||
buf[x] = (unsigned char)(std::min(256, std::max(0, (int)(128 + 32 * Noise[i][idx++]))));
|
|
||||||
}
|
|
||||||
f2.Write(buf, cChunkDef::Width);
|
|
||||||
}
|
|
||||||
} // for z
|
|
||||||
} // for y
|
|
||||||
} // if (XZ file open)
|
|
||||||
#endif // 0
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -246,7 +183,7 @@ cNoise3DGenerator::~cNoise3DGenerator()
|
|||||||
void cNoise3DGenerator::Initialize(cIniFile & a_IniFile)
|
void cNoise3DGenerator::Initialize(cIniFile & a_IniFile)
|
||||||
{
|
{
|
||||||
// Params:
|
// Params:
|
||||||
m_SeaLevel = a_IniFile.GetValueSetI("Generator", "Noise3DSeaLevel", 62);
|
m_SeaLevel = a_IniFile.GetValueSetI("Generator", "SeaLevel", 62);
|
||||||
m_HeightAmplification = (NOISE_DATATYPE)a_IniFile.GetValueSetF("Generator", "Noise3DHeightAmplification", 0.1);
|
m_HeightAmplification = (NOISE_DATATYPE)a_IniFile.GetValueSetF("Generator", "Noise3DHeightAmplification", 0.1);
|
||||||
m_MidPoint = (NOISE_DATATYPE)a_IniFile.GetValueSetF("Generator", "Noise3DMidPoint", 68);
|
m_MidPoint = (NOISE_DATATYPE)a_IniFile.GetValueSetF("Generator", "Noise3DMidPoint", 68);
|
||||||
m_FrequencyX = (NOISE_DATATYPE)a_IniFile.GetValueSetF("Generator", "Noise3DFrequencyX", 8);
|
m_FrequencyX = (NOISE_DATATYPE)a_IniFile.GetValueSetF("Generator", "Noise3DFrequencyX", 8);
|
||||||
@ -454,7 +391,6 @@ void cNoise3DComposable::Initialize(cIniFile & a_IniFile)
|
|||||||
{
|
{
|
||||||
// Params:
|
// Params:
|
||||||
// The defaults generate extreme hills terrain
|
// The defaults generate extreme hills terrain
|
||||||
m_SeaLevel = a_IniFile.GetValueSetI("Generator", "Noise3DSeaLevel", 62);
|
|
||||||
m_HeightAmplification = (NOISE_DATATYPE)a_IniFile.GetValueSetF("Generator", "Noise3DHeightAmplification", 0.045);
|
m_HeightAmplification = (NOISE_DATATYPE)a_IniFile.GetValueSetF("Generator", "Noise3DHeightAmplification", 0.045);
|
||||||
m_MidPoint = (NOISE_DATATYPE)a_IniFile.GetValueSetF("Generator", "Noise3DMidPoint", 75);
|
m_MidPoint = (NOISE_DATATYPE)a_IniFile.GetValueSetF("Generator", "Noise3DMidPoint", 75);
|
||||||
m_FrequencyX = (NOISE_DATATYPE)a_IniFile.GetValueSetF("Generator", "Noise3DFrequencyX", 40);
|
m_FrequencyX = (NOISE_DATATYPE)a_IniFile.GetValueSetF("Generator", "Noise3DFrequencyX", 40);
|
||||||
@ -522,110 +458,60 @@ 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If too high, cut off any terrain:
|
||||||
|
if (y > 28)
|
||||||
|
{
|
||||||
|
AddHeight = AddHeight + static_cast<NOISE_DATATYPE>(y - 28) / 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Decide between the two density noises:
|
||||||
|
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
|
||||||
}
|
}
|
||||||
@ -650,7 +536,7 @@ cBiomalNoise3DComposable::cBiomalNoise3DComposable(int a_Seed, cBiomeGenPtr a_Bi
|
|||||||
{
|
{
|
||||||
for (int x = 0; x <= AVERAGING_SIZE * 2; x++)
|
for (int x = 0; x <= AVERAGING_SIZE * 2; x++)
|
||||||
{
|
{
|
||||||
m_Weight[z][x] = static_cast<NOISE_DATATYPE>((5 - std::abs(5 - x)) + (5 - std::abs(5 - z)));
|
m_Weight[z][x] = static_cast<NOISE_DATATYPE>((AVERAGING_SIZE - std::abs(AVERAGING_SIZE - x)) + (AVERAGING_SIZE - std::abs(AVERAGING_SIZE - z)));
|
||||||
m_WeightSum += m_Weight[z][x];
|
m_WeightSum += m_Weight[z][x];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -664,7 +550,7 @@ void cBiomalNoise3DComposable::Initialize(cIniFile & a_IniFile)
|
|||||||
{
|
{
|
||||||
// Params:
|
// Params:
|
||||||
// The defaults generate extreme hills terrain
|
// The defaults generate extreme hills terrain
|
||||||
m_SeaLevel = a_IniFile.GetValueSetI("Generator", "BiomalNoise3DSeaLevel", 62);
|
m_SeaLevel = a_IniFile.GetValueSetI("Generator", "SeaLevel", 62);
|
||||||
m_FrequencyX = (NOISE_DATATYPE)a_IniFile.GetValueSetF("Generator", "BiomalNoise3DFrequencyX", 40);
|
m_FrequencyX = (NOISE_DATATYPE)a_IniFile.GetValueSetF("Generator", "BiomalNoise3DFrequencyX", 40);
|
||||||
m_FrequencyY = (NOISE_DATATYPE)a_IniFile.GetValueSetF("Generator", "BiomalNoise3DFrequencyY", 40);
|
m_FrequencyY = (NOISE_DATATYPE)a_IniFile.GetValueSetF("Generator", "BiomalNoise3DFrequencyY", 40);
|
||||||
m_FrequencyZ = (NOISE_DATATYPE)a_IniFile.GetValueSetF("Generator", "BiomalNoise3DFrequencyZ", 40);
|
m_FrequencyZ = (NOISE_DATATYPE)a_IniFile.GetValueSetF("Generator", "BiomalNoise3DFrequencyZ", 40);
|
||||||
@ -735,34 +621,42 @@ 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)
|
||||||
{
|
{
|
||||||
AddHeight *= 4;
|
AddHeight *= 4;
|
||||||
}
|
}
|
||||||
|
// If too high, cut off any terrain:
|
||||||
|
if (y > 28)
|
||||||
|
{
|
||||||
|
AddHeight = AddHeight + static_cast<NOISE_DATATYPE>(y - 28) / 4;
|
||||||
|
}
|
||||||
|
|
||||||
int idx = x + 5 * z + 5 * 5 * y;
|
// Decide between the two density noises:
|
||||||
Workspace[idx] = ClampedLerp(DensityNoiseA[idx], DensityNoiseB[idx], 8 * (ChoiceNoise[idx] + 0.5f)) + AddHeight + BaseNoise[x + 5 * z];
|
int idx = 33 * x + y + 33 * 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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -820,72 +714,67 @@ void cBiomalNoise3DComposable::GetBiomeParams(EMCSBiome a_Biome, NOISE_DATATYPE
|
|||||||
{
|
{
|
||||||
switch (a_Biome)
|
switch (a_Biome)
|
||||||
{
|
{
|
||||||
case biBeach: a_HeightAmp = 0.3f; a_MidPoint = 62; break;
|
case biBeach: a_HeightAmp = 0.2f; a_MidPoint = 60; break;
|
||||||
case biBirchForest: a_HeightAmp = 0.1f; a_MidPoint = 64; break;
|
case biBirchForest: a_HeightAmp = 0.1f; a_MidPoint = 64; break;
|
||||||
case biBirchForestHills: a_HeightAmp = 0.075f; a_MidPoint = 68; break;
|
case biBirchForestHills: a_HeightAmp = 0.075f; a_MidPoint = 68; break;
|
||||||
case biBirchForestHillsM: a_HeightAmp = 0.075f; a_MidPoint = 68; break;
|
case biBirchForestHillsM: a_HeightAmp = 0.075f; a_MidPoint = 68; break;
|
||||||
case biBirchForestM: a_HeightAmp = 0.1f; a_MidPoint = 64; break;
|
case biBirchForestM: a_HeightAmp = 0.1f; a_MidPoint = 64; break;
|
||||||
case biColdBeach: a_HeightAmp = 0.3f; a_MidPoint = 62; break;
|
case biColdBeach: a_HeightAmp = 0.3f; a_MidPoint = 62; break;
|
||||||
case biDesertHills: a_HeightAmp = 0.075f; a_MidPoint = 68; break;
|
case biColdTaiga: a_HeightAmp = 0.1f; a_MidPoint = 64; break;
|
||||||
case biDeepOcean: a_HeightAmp = 0.17f; a_MidPoint = 35; break;
|
case biColdTaigaM: a_HeightAmp = 0.1f; a_MidPoint = 64; break;
|
||||||
case biDesert: a_HeightAmp = 0.29f; a_MidPoint = 62; break;
|
case biColdTaigaHills: a_HeightAmp = 0.075f; a_MidPoint = 68; break;
|
||||||
case biEnd: a_HeightAmp = 0.15f; a_MidPoint = 64; break;
|
case biDesertHills: a_HeightAmp = 0.075f; a_MidPoint = 68; break;
|
||||||
case biExtremeHills: a_HeightAmp = 0.045f; a_MidPoint = 75; break;
|
case biDeepOcean: a_HeightAmp = 0.17f; a_MidPoint = 35; break;
|
||||||
case biExtremeHillsPlus: a_HeightAmp = 0.04f; a_MidPoint = 80; break;
|
case biDesert: a_HeightAmp = 0.29f; a_MidPoint = 62; break;
|
||||||
case biFlowerForest: a_HeightAmp = 0.1f; a_MidPoint = 64; break;
|
case biDesertM: a_HeightAmp = 0.29f; a_MidPoint = 62; break;
|
||||||
case biForest: a_HeightAmp = 0.1f; a_MidPoint = 64; break;
|
case biEnd: a_HeightAmp = 0.15f; a_MidPoint = 64; break;
|
||||||
case biForestHills: a_HeightAmp = 0.075f; a_MidPoint = 68; break;
|
case biExtremeHills: a_HeightAmp = 0.045f; a_MidPoint = 75; break;
|
||||||
case biFrozenRiver: a_HeightAmp = 0.4f; a_MidPoint = 53; break;
|
case biExtremeHillsEdge: a_HeightAmp = 0.1f; a_MidPoint = 70; break;
|
||||||
case biFrozenOcean: a_HeightAmp = 0.17f; a_MidPoint = 47; break;
|
case biExtremeHillsM: a_HeightAmp = 0.045f; a_MidPoint = 75; break;
|
||||||
case biIceMountains: a_HeightAmp = 0.075f; a_MidPoint = 68; break;
|
case biExtremeHillsPlus: a_HeightAmp = 0.04f; a_MidPoint = 80; break;
|
||||||
case biIcePlains: a_HeightAmp = 0.3f; a_MidPoint = 62; break;
|
case biExtremeHillsPlusM: a_HeightAmp = 0.04f; a_MidPoint = 80; break;
|
||||||
case biIcePlainsSpikes: a_HeightAmp = 0.3f; a_MidPoint = 62; break;
|
case biFlowerForest: a_HeightAmp = 0.1f; a_MidPoint = 64; break;
|
||||||
case biJungle: a_HeightAmp = 0.1f; a_MidPoint = 63; break;
|
case biForest: a_HeightAmp = 0.1f; a_MidPoint = 64; break;
|
||||||
case biJungleHills: a_HeightAmp = 0.075f; a_MidPoint = 68; break;
|
case biForestHills: a_HeightAmp = 0.075f; a_MidPoint = 68; break;
|
||||||
case biJungleM: a_HeightAmp = 0.1f; a_MidPoint = 63; break;
|
case biFrozenRiver: a_HeightAmp = 0.4f; a_MidPoint = 57; break;
|
||||||
case biMegaSpruceTaigaHills: a_HeightAmp = 0.075f; a_MidPoint = 68; break;
|
case biFrozenOcean: a_HeightAmp = 0.12f; a_MidPoint = 45; break;
|
||||||
case biMegaTaigaHills: a_HeightAmp = 0.075f; a_MidPoint = 68; break;
|
case biIceMountains: a_HeightAmp = 0.075f; a_MidPoint = 68; break;
|
||||||
case biMushroomShore: a_HeightAmp = 0.15f; a_MidPoint = 15; break;
|
case biIcePlains: a_HeightAmp = 0.3f; a_MidPoint = 62; break;
|
||||||
case biOcean: a_HeightAmp = 0.3f; a_MidPoint = 62; break;
|
case biIcePlainsSpikes: a_HeightAmp = 0.3f; a_MidPoint = 62; break;
|
||||||
case biPlains: a_HeightAmp = 0.3f; a_MidPoint = 62; break;
|
case biJungle: a_HeightAmp = 0.1f; a_MidPoint = 63; break;
|
||||||
case biRiver: a_HeightAmp = 0.4f; a_MidPoint = 53; break;
|
case biJungleEdge: a_HeightAmp = 0.15f; a_MidPoint = 62; break;
|
||||||
case biSwampland: a_HeightAmp = 0.25f; a_MidPoint = 59; break;
|
case biJungleEdgeM: a_HeightAmp = 0.15f; a_MidPoint = 62; break;
|
||||||
case biSwamplandM: a_HeightAmp = 0.11f; a_MidPoint = 59; break;
|
case biJungleHills: a_HeightAmp = 0.075f; a_MidPoint = 68; break;
|
||||||
case biTaigaHills: a_HeightAmp = 0.075f; a_MidPoint = 68; break;
|
case biJungleM: a_HeightAmp = 0.1f; a_MidPoint = 63; break;
|
||||||
|
case biMegaSpruceTaiga: a_HeightAmp = 0.09f; a_MidPoint = 64; break;
|
||||||
/*
|
case biMegaSpruceTaigaHills: a_HeightAmp = 0.075f; a_MidPoint = 68; break;
|
||||||
// Still missing:
|
case biMegaTaiga: a_HeightAmp = 0.1f; a_MidPoint = 64; break;
|
||||||
case biColdTaiga: a_HeightAmp = 0.15f; a_MidPoint = 30; break;
|
case biMegaTaigaHills: a_HeightAmp = 0.075f; a_MidPoint = 68; break;
|
||||||
case biColdTaigaHills: a_HeightAmp = 0.15f; a_MidPoint = 31; break;
|
case biMesa: a_HeightAmp = 0.09f; a_MidPoint = 61; break;
|
||||||
case biColdTaigaM: a_HeightAmp = 0.15f; a_MidPoint = 70; break;
|
case biMesaBryce: a_HeightAmp = 0.15f; a_MidPoint = 61; break;
|
||||||
case biDesertM: a_HeightAmp = 0.15f; a_MidPoint = 70; break;
|
case biMesaPlateau: a_HeightAmp = 0.25f; a_MidPoint = 86; break;
|
||||||
case biExtremeHillsEdge: a_HeightAmp = 0.15f; a_MidPoint = 20; break;
|
case biMesaPlateauF: a_HeightAmp = 0.25f; a_MidPoint = 96; break;
|
||||||
case biExtremeHillsM: a_HeightAmp = 0.15f; a_MidPoint = 70; break;
|
case biMesaPlateauFM: a_HeightAmp = 0.25f; a_MidPoint = 96; break;
|
||||||
case biExtremeHillsPlusM: a_HeightAmp = 0.15f; a_MidPoint = 70; break;
|
case biMesaPlateauM: a_HeightAmp = 0.25f; a_MidPoint = 86; break;
|
||||||
case biJungleEdge: a_HeightAmp = 0.15f; a_MidPoint = 23; break;
|
case biMushroomShore: a_HeightAmp = 0.075f; a_MidPoint = 60; break;
|
||||||
case biJungleEdgeM: a_HeightAmp = 0.15f; a_MidPoint = 70; break;
|
case biMushroomIsland: a_HeightAmp = 0.06f; a_MidPoint = 80; break;
|
||||||
case biMegaSpruceTaiga: a_HeightAmp = 0.15f; a_MidPoint = 70; break;
|
case biNether: a_HeightAmp = 0.01f; a_MidPoint = 64; break;
|
||||||
case biMegaTaiga: a_HeightAmp = 0.15f; a_MidPoint = 32; break;
|
case biOcean: a_HeightAmp = 0.12f; a_MidPoint = 45; break;
|
||||||
case biMesa: a_HeightAmp = 0.15f; a_MidPoint = 37; break;
|
case biPlains: a_HeightAmp = 0.3f; a_MidPoint = 62; break;
|
||||||
case biMesaBryce: a_HeightAmp = 0.15f; a_MidPoint = 70; break;
|
case biRiver: a_HeightAmp = 0.4f; a_MidPoint = 57; break;
|
||||||
case biMesaPlateau: a_HeightAmp = 0.15f; a_MidPoint = 39; break;
|
case biRoofedForest: a_HeightAmp = 0.1f; a_MidPoint = 64; break;
|
||||||
case biMesaPlateauF: a_HeightAmp = 0.15f; a_MidPoint = 38; break;
|
case biRoofedForestM: a_HeightAmp = 0.1f; a_MidPoint = 64; break;
|
||||||
case biMesaPlateauFM: a_HeightAmp = 0.15f; a_MidPoint = 70; break;
|
case biSavanna: a_HeightAmp = 0.3f; a_MidPoint = 62; break;
|
||||||
case biMesaPlateauM: a_HeightAmp = 0.15f; a_MidPoint = 70; break;
|
case biSavannaM: a_HeightAmp = 0.3f; a_MidPoint = 62; break;
|
||||||
case biMushroomIsland: a_HeightAmp = 0.15f; a_MidPoint = 14; break;
|
case biSavannaPlateau: a_HeightAmp = 0.3f; a_MidPoint = 85; break;
|
||||||
case biNether: a_HeightAmp = 0.15f; a_MidPoint = 68; break;
|
case biSavannaPlateauM: a_HeightAmp = 0.012f; a_MidPoint = 105; break;
|
||||||
case biRoofedForest: a_HeightAmp = 0.15f; a_MidPoint = 29; break;
|
case biStoneBeach: a_HeightAmp = 0.075f; a_MidPoint = 60; break;
|
||||||
case biRoofedForestM: a_HeightAmp = 0.15f; a_MidPoint = 70; break;
|
case biSunflowerPlains: a_HeightAmp = 0.3f; a_MidPoint = 62; break;
|
||||||
case biSavanna: a_HeightAmp = 0.15f; a_MidPoint = 35; break;
|
case biSwampland: a_HeightAmp = 0.25f; a_MidPoint = 59; break;
|
||||||
case biSavannaM: a_HeightAmp = 0.15f; a_MidPoint = 70; break;
|
case biSwamplandM: a_HeightAmp = 0.11f; a_MidPoint = 59; break;
|
||||||
case biSavannaPlateau: a_HeightAmp = 0.15f; a_MidPoint = 36; break;
|
case biTaiga: a_HeightAmp = 0.1f; a_MidPoint = 64; break;
|
||||||
case biSavannaPlateauM: a_HeightAmp = 0.15f; a_MidPoint = 70; break;
|
case biTaigaM: a_HeightAmp = 0.1f; a_MidPoint = 70; break;
|
||||||
case biStoneBeach: a_HeightAmp = 0.15f; a_MidPoint = 25; break;
|
case biTaigaHills: a_HeightAmp = 0.075f; a_MidPoint = 68; break;
|
||||||
case biSunflowerPlains: a_HeightAmp = 0.15f; a_MidPoint = 70; break;
|
|
||||||
case biTaiga: a_HeightAmp = 0.15f; a_MidPoint = 65; break;
|
|
||||||
case biTaigaM: a_HeightAmp = 0.15f; a_MidPoint = 70; break;
|
|
||||||
*/
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
// Make a crazy terrain so that it stands out
|
// Make a crazy terrain so that it stands out
|
||||||
@ -899,78 +788,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
|
||||||
}
|
}
|
||||||
@ -978,3 +808,4 @@ void cBiomalNoise3DComposable::ComposeTerrain(cChunkDesc & a_ChunkDesc)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -73,8 +73,7 @@ protected:
|
|||||||
|
|
||||||
|
|
||||||
class cNoise3DComposable :
|
class cNoise3DComposable :
|
||||||
public cTerrainHeightGen,
|
public cTerrainShapeGen
|
||||||
public cTerrainCompositionGen
|
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
cNoise3DComposable(int a_Seed);
|
cNoise3DComposable(int a_Seed);
|
||||||
@ -82,20 +81,17 @@ public:
|
|||||||
void Initialize(cIniFile & a_IniFile);
|
void Initialize(cIniFile & a_IniFile);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
/** The noise that is used to choose between density noise A and B. */
|
/** The 3D noise that is used to choose between density noise A and B. */
|
||||||
cPerlinNoise m_ChoiceNoise;
|
cOctavedNoise<cInterpolNoise<Interp5Deg>> m_ChoiceNoise;
|
||||||
|
|
||||||
/** Density 3D noise, variant A. */
|
/** Density 3D noise, variant A. */
|
||||||
cPerlinNoise m_DensityNoiseA;
|
cOctavedNoise<cInterpolNoise<Interp5Deg>> m_DensityNoiseA;
|
||||||
|
|
||||||
/** Density 3D noise, variant B. */
|
/** Density 3D noise, variant B. */
|
||||||
cPerlinNoise m_DensityNoiseB;
|
cOctavedNoise<cInterpolNoise<Interp5Deg>> m_DensityNoiseB;
|
||||||
|
|
||||||
/** Heightmap-like noise used to provide variance for low-amplitude biomes. */
|
/** Heightmap-like noise used to provide variance for low-amplitude biomes. */
|
||||||
cPerlinNoise m_BaseNoise;
|
cOctavedNoise<cInterpolNoise<Interp5Deg>> m_BaseNoise;
|
||||||
|
|
||||||
/** Block height of the sealevel, used for composing the terrain. */
|
|
||||||
int m_SeaLevel;
|
|
||||||
|
|
||||||
/** The main parameter of the generator, specifies the slope of the vertical linear gradient.
|
/** The main parameter of the generator, specifies the slope of the vertical linear gradient.
|
||||||
A higher value means a steeper slope and a smaller total amplitude of the generated terrain. */
|
A higher value means a steeper slope and a smaller total amplitude of the generated terrain. */
|
||||||
@ -131,12 +127,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); }
|
|
||||||
} ;
|
} ;
|
||||||
|
|
||||||
|
|
||||||
@ -144,8 +136,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);
|
||||||
@ -153,24 +144,24 @@ public:
|
|||||||
void Initialize(cIniFile & a_IniFile);
|
void Initialize(cIniFile & a_IniFile);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
/** Number of columns around the pixel to query for biomes for averaging. */
|
/** Number of columns around the pixel to query for biomes for averaging. Must be less than or equal to 16. */
|
||||||
static const int AVERAGING_SIZE = 5;
|
static const int AVERAGING_SIZE = 9;
|
||||||
|
|
||||||
/** Type used for a single parameter across the entire (downscaled) chunk. */
|
/** Type used for a single parameter across the entire (downscaled) chunk. */
|
||||||
typedef NOISE_DATATYPE ChunkParam[5 * 5];
|
typedef NOISE_DATATYPE ChunkParam[5 * 5];
|
||||||
|
|
||||||
|
|
||||||
/** The noise that is used to choose between density noise A and B. */
|
/** The noise that is used to choose between density noise A and B. */
|
||||||
cPerlinNoise m_ChoiceNoise;
|
cOctavedNoise<cInterpolNoise<Interp5Deg>> m_ChoiceNoise;
|
||||||
|
|
||||||
/** Density 3D noise, variant A. */
|
/** Density 3D noise, variant A. */
|
||||||
cPerlinNoise m_DensityNoiseA;
|
cOctavedNoise<cInterpolNoise<Interp5Deg>> m_DensityNoiseA;
|
||||||
|
|
||||||
/** Density 3D noise, variant B. */
|
/** Density 3D noise, variant B. */
|
||||||
cPerlinNoise m_DensityNoiseB;
|
cOctavedNoise<cInterpolNoise<Interp5Deg>> m_DensityNoiseB;
|
||||||
|
|
||||||
/** Heightmap-like noise used to provide variance for low-amplitude biomes. */
|
/** Heightmap-like noise used to provide variance for low-amplitude biomes. */
|
||||||
cPerlinNoise m_BaseNoise;
|
cOctavedNoise<cInterpolNoise<Interp5Deg>> m_BaseNoise;
|
||||||
|
|
||||||
/** The underlying biome generator. */
|
/** The underlying biome generator. */
|
||||||
cBiomeGenPtr m_BiomeGen;
|
cBiomeGenPtr m_BiomeGen;
|
||||||
@ -198,7 +189,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];
|
||||||
@ -216,13 +207,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); }
|
|
||||||
} ;
|
} ;
|
||||||
|
|
||||||
|
|
||||||
|
145
src/Generating/ShapeGen.cpp
Normal file
145
src/Generating/ShapeGen.cpp
Normal file
@ -0,0 +1,145 @@
|
|||||||
|
|
||||||
|
// 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"
|
||||||
|
#include "TwoHeights.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 if (NoCaseCompare(shapeGenName, "TwoHeights") == 0)
|
||||||
|
{
|
||||||
|
res = CreateShapeGenTwoHeights(a_Seed, a_BiomeGen);
|
||||||
|
}
|
||||||
|
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,13 @@ 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);
|
WorkerDesc.SetHeightFromShape (workerShape);
|
||||||
// TODO: Free the entity lists
|
m_CompositionGen->ComposeTerrain(WorkerDesc, workerShape);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -97,7 +100,7 @@ void cStructGenTrees::GenerateSingleTree(
|
|||||||
|
|
||||||
int Height = a_ChunkDesc.GetHeight(x, z);
|
int Height = a_ChunkDesc.GetHeight(x, z);
|
||||||
|
|
||||||
if ((Height <= 0) || (Height > 240))
|
if ((Height <= 0) || (Height >= 230))
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -125,6 +128,11 @@ void cStructGenTrees::GenerateSingleTree(
|
|||||||
// Outside the chunk
|
// Outside the chunk
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
if (itr->y >= cChunkDef::Height)
|
||||||
|
{
|
||||||
|
// Above the chunk, cut off (this shouldn't happen too often, we're limiting trees to y < 230)
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
BLOCKTYPE Block = a_ChunkDesc.GetBlockType(itr->x, itr->y, itr->z);
|
BLOCKTYPE Block = a_ChunkDesc.GetBlockType(itr->x, itr->y, itr->z);
|
||||||
switch (Block)
|
switch (Block)
|
||||||
@ -159,7 +167,7 @@ void cStructGenTrees::ApplyTreeImage(
|
|||||||
// Put the generated image into a_BlockTypes, push things outside this chunk into a_Blocks
|
// Put the generated image into a_BlockTypes, push things outside this chunk into a_Blocks
|
||||||
for (sSetBlockVector::const_iterator itr = a_Image.begin(), end = a_Image.end(); itr != end; ++itr)
|
for (sSetBlockVector::const_iterator itr = a_Image.begin(), end = a_Image.end(); itr != end; ++itr)
|
||||||
{
|
{
|
||||||
if ((itr->ChunkX == a_ChunkX) && (itr->ChunkZ == a_ChunkZ))
|
if ((itr->ChunkX == a_ChunkX) && (itr->ChunkZ == a_ChunkZ) && (itr->y < cChunkDef::Height))
|
||||||
{
|
{
|
||||||
// Inside this chunk, integrate into a_ChunkDesc:
|
// Inside this chunk, integrate into a_ChunkDesc:
|
||||||
switch (a_ChunkDesc.GetBlockType(itr->x, itr->y, itr->z))
|
switch (a_ChunkDesc.GetBlockType(itr->x, itr->y, itr->z))
|
||||||
@ -390,7 +398,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 +412,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);
|
||||||
} ;
|
} ;
|
||||||
|
|
||||||
|
|
||||||
|
121
src/Generating/TwoHeights.cpp
Normal file
121
src/Generating/TwoHeights.cpp
Normal file
@ -0,0 +1,121 @@
|
|||||||
|
|
||||||
|
// TwoHeights.cpp
|
||||||
|
|
||||||
|
// Implements the cTwoHeights class representing the terrain shape generator using two switched heightmaps
|
||||||
|
|
||||||
|
#include "Globals.h"
|
||||||
|
#include "TwoHeights.h"
|
||||||
|
#include "../Noise/InterpolNoise.h"
|
||||||
|
#include "HeiGen.h"
|
||||||
|
#include "../LinearUpscale.h"
|
||||||
|
#include "../IniFile.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class cTwoHeights:
|
||||||
|
public cTerrainShapeGen
|
||||||
|
{
|
||||||
|
typedef cTerrainShapeGen super;
|
||||||
|
public:
|
||||||
|
cTwoHeights(int a_Seed, cBiomeGenPtr a_BiomeGen):
|
||||||
|
m_Seed(a_Seed),
|
||||||
|
m_Choice(a_Seed),
|
||||||
|
m_HeightA(a_Seed + 1, a_BiomeGen),
|
||||||
|
m_HeightB(a_Seed + 2, a_BiomeGen)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// cTerrainShapeGen override:
|
||||||
|
virtual void GenShape(int a_ChunkX, int a_ChunkZ, cChunkDesc::Shape & a_Shape) override
|
||||||
|
{
|
||||||
|
// Generate the two heightmaps:
|
||||||
|
cChunkDef::HeightMap heightsA;
|
||||||
|
cChunkDef::HeightMap heightsB;
|
||||||
|
m_HeightA.GenHeightMap(a_ChunkX, a_ChunkZ, heightsA);
|
||||||
|
m_HeightB.GenHeightMap(a_ChunkX, a_ChunkZ, heightsB);
|
||||||
|
|
||||||
|
// Generate the choice noise:
|
||||||
|
NOISE_DATATYPE smallChoice[33 * 5 * 5];
|
||||||
|
NOISE_DATATYPE workspace[33 * 5 * 5];
|
||||||
|
NOISE_DATATYPE startX = 0;
|
||||||
|
NOISE_DATATYPE endX = 256 * m_FrequencyY;
|
||||||
|
NOISE_DATATYPE startY = a_ChunkX * cChunkDef::Width * m_FrequencyX;
|
||||||
|
NOISE_DATATYPE endY = (a_ChunkX * cChunkDef::Width + cChunkDef::Width + 1) * m_FrequencyX;
|
||||||
|
NOISE_DATATYPE startZ = a_ChunkZ * cChunkDef::Width * m_FrequencyZ;
|
||||||
|
NOISE_DATATYPE endZ = (a_ChunkZ * cChunkDef::Width + cChunkDef::Width + 1) * m_FrequencyZ;
|
||||||
|
m_Choice.Generate3D(smallChoice, 33, 5, 5, startX, endX, startY, endY, startZ, endZ, workspace);
|
||||||
|
NOISE_DATATYPE choice[257 * 17 * 17];
|
||||||
|
LinearUpscale3DArray(smallChoice, 33, 5, 5, choice, 8, 4, 4);
|
||||||
|
|
||||||
|
// Generate the shape:
|
||||||
|
int idxShape = 0;
|
||||||
|
for (int z = 0; z < cChunkDef::Width; z++)
|
||||||
|
{
|
||||||
|
for (int x = 0; x < cChunkDef::Width; x++)
|
||||||
|
{
|
||||||
|
int idxChoice = 257 * 17 * z + 257 * x;
|
||||||
|
NOISE_DATATYPE heightA = static_cast<NOISE_DATATYPE>(cChunkDef::GetHeight(heightsA, x, z));
|
||||||
|
NOISE_DATATYPE heightB = static_cast<NOISE_DATATYPE>(cChunkDef::GetHeight(heightsB, x, z));
|
||||||
|
for (int y = 0; y < cChunkDef::Height; y++)
|
||||||
|
{
|
||||||
|
int height = static_cast<int>(ClampedLerp(heightA, heightB, choice[idxChoice++]));
|
||||||
|
a_Shape[idxShape++] = (y < height) ? 1 : 0;
|
||||||
|
}
|
||||||
|
} // for x
|
||||||
|
} // for z
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
virtual void InitializeShapeGen(cIniFile & a_IniFile)
|
||||||
|
{
|
||||||
|
m_FrequencyX = static_cast<NOISE_DATATYPE>(a_IniFile.GetValueSetF("Generator", "TwoHeightsFrequencyX", 40));
|
||||||
|
m_FrequencyY = static_cast<NOISE_DATATYPE>(a_IniFile.GetValueSetF("Generator", "TwoHeightsFrequencyY", 40));
|
||||||
|
m_FrequencyZ = static_cast<NOISE_DATATYPE>(a_IniFile.GetValueSetF("Generator", "TwoHeightsFrequencyZ", 40));
|
||||||
|
|
||||||
|
// Initialize the two underlying height generators from an empty INI file:
|
||||||
|
cIniFile empty;
|
||||||
|
m_HeightA.InitializeHeightGen(empty);
|
||||||
|
m_HeightB.InitializeHeightGen(empty);
|
||||||
|
|
||||||
|
// Add the choice octaves:
|
||||||
|
NOISE_DATATYPE freq = 0.001f;
|
||||||
|
NOISE_DATATYPE ampl = 1;
|
||||||
|
for (int i = 0; i < 4; i++)
|
||||||
|
{
|
||||||
|
m_Choice.AddOctave(freq, ampl);
|
||||||
|
freq = freq * 2;
|
||||||
|
ampl = ampl / 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
int m_Seed;
|
||||||
|
|
||||||
|
/** The noise used to decide between the two heightmaps. */
|
||||||
|
cOctavedNoise<cInterpolNoise<Interp5Deg>> m_Choice;
|
||||||
|
|
||||||
|
/** The first height generator. */
|
||||||
|
cHeiGenBiomal m_HeightA;
|
||||||
|
|
||||||
|
/** The second height generator. */
|
||||||
|
cHeiGenBiomal m_HeightB;
|
||||||
|
|
||||||
|
/** The base frequencies for m_Choice in each of the world axis directions. */
|
||||||
|
NOISE_DATATYPE m_FrequencyX, m_FrequencyY, m_FrequencyZ;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
cTerrainShapeGenPtr CreateShapeGenTwoHeights(int a_Seed, cBiomeGenPtr a_BiomeGen)
|
||||||
|
{
|
||||||
|
return std::make_shared<cTwoHeights>(a_Seed, a_BiomeGen);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
23
src/Generating/TwoHeights.h
Normal file
23
src/Generating/TwoHeights.h
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
|
||||||
|
// TwoHeights.h
|
||||||
|
|
||||||
|
// Declares the function to create a new instance of the cTwoHeights terrain shape generator
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "ComposableGenerator.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/** Creates and returns a new instance of the cTwoHeights terrain shape generator.
|
||||||
|
The instance must be Initialize()-d before it is used. */
|
||||||
|
extern cTerrainShapeGenPtr CreateShapeGenTwoHeights(int a_Seed, cBiomeGenPtr a_BiomeGen);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -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),
|
||||||
|
@ -184,9 +184,9 @@ template class SizeChecker<UInt16, 2>;
|
|||||||
|
|
||||||
// OS-dependent stuff:
|
// OS-dependent stuff:
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
#define WIN32_LEAN_AND_MEAN
|
|
||||||
|
|
||||||
#define _WIN32_WINNT_WS03 // We want to target Windows XP with Service Pack 2 & Windows Server 2003 with Service Pack 1 and higher
|
#define WIN32_LEAN_AND_MEAN
|
||||||
|
#define _WIN32_WINNT _WIN32_WINNT_WS03 // We want to target Windows XP with Service Pack 2 & Windows Server 2003 with Service Pack 1 and higher
|
||||||
|
|
||||||
#include <Windows.h>
|
#include <Windows.h>
|
||||||
#include <winsock2.h>
|
#include <winsock2.h>
|
||||||
|
@ -159,7 +159,7 @@ void cMonster::TickPathFinding()
|
|||||||
BLOCKTYPE BlockAtYP = m_World->GetBlock(gCrossCoords[i].x + PosX, PosY + 1, gCrossCoords[i].z + PosZ);
|
BLOCKTYPE BlockAtYP = m_World->GetBlock(gCrossCoords[i].x + PosX, PosY + 1, gCrossCoords[i].z + PosZ);
|
||||||
BLOCKTYPE BlockAtYPP = m_World->GetBlock(gCrossCoords[i].x + PosX, PosY + 2, gCrossCoords[i].z + PosZ);
|
BLOCKTYPE BlockAtYPP = m_World->GetBlock(gCrossCoords[i].x + PosX, PosY + 2, gCrossCoords[i].z + PosZ);
|
||||||
int LowestY = FindFirstNonAirBlockPosition(gCrossCoords[i].x + PosX, gCrossCoords[i].z + PosZ);
|
int LowestY = FindFirstNonAirBlockPosition(gCrossCoords[i].x + PosX, gCrossCoords[i].z + PosZ);
|
||||||
BLOCKTYPE BlockAtLowestY = m_World->GetBlock(gCrossCoords[i].x + PosX, LowestY, gCrossCoords[i].z + PosZ);
|
BLOCKTYPE BlockAtLowestY = (LowestY >= cChunkDef::Height) ? E_BLOCK_AIR : m_World->GetBlock(gCrossCoords[i].x + PosX, LowestY, gCrossCoords[i].z + PosZ);
|
||||||
|
|
||||||
if (
|
if (
|
||||||
(!cBlockInfo::IsSolid(BlockAtY)) &&
|
(!cBlockInfo::IsSolid(BlockAtY)) &&
|
||||||
@ -452,7 +452,7 @@ int cMonster::FindFirstNonAirBlockPosition(double a_PosX, double a_PosZ)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
while (cBlockInfo::IsSolid(m_World->GetBlock((int)floor(a_PosX), PosY, (int)floor(a_PosZ))) && (PosY < cChunkDef::Height))
|
while ((PosY < cChunkDef::Height) && cBlockInfo::IsSolid(m_World->GetBlock((int)floor(a_PosX), PosY, (int)floor(a_PosZ))))
|
||||||
{
|
{
|
||||||
PosY++;
|
PosY++;
|
||||||
}
|
}
|
||||||
|
@ -169,10 +169,12 @@ protected:
|
|||||||
/** Stores if mobile is currently moving towards the ultimate, final destination */
|
/** Stores if mobile is currently moving towards the ultimate, final destination */
|
||||||
bool m_bMovingToDestination;
|
bool m_bMovingToDestination;
|
||||||
|
|
||||||
/** Finds the first non-air block position (not the highest, as cWorld::GetHeight does)
|
/** Finds the lowest non-air block position (not the highest, as cWorld::GetHeight does)
|
||||||
If current Y is nonsolid, goes down to try to find a solid block, then returns that + 1
|
If current Y is nonsolid, goes down to try to find a solid block, then returns that + 1
|
||||||
If current Y is solid, goes up to find first nonsolid block, and returns that */
|
If current Y is solid, goes up to find first nonsolid block, and returns that.
|
||||||
|
If no suitable position is found, returns cChunkDef::Height. */
|
||||||
int FindFirstNonAirBlockPosition(double a_PosX, double a_PosZ);
|
int FindFirstNonAirBlockPosition(double a_PosX, double a_PosZ);
|
||||||
|
|
||||||
/** Returns if a monster can actually reach a given height by jumping or walking */
|
/** Returns if a monster can actually reach a given height by jumping or walking */
|
||||||
inline bool IsNextYPosReachable(int a_PosY)
|
inline bool IsNextYPosReachable(int a_PosY)
|
||||||
{
|
{
|
||||||
|
261
src/World.cpp
261
src/World.cpp
@ -72,99 +72,130 @@ const int TIME_SPAWN_DIVISOR = 148;
|
|||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
// cWorldLoadProgress:
|
// cSpawnPrepare:
|
||||||
|
|
||||||
/// A simple thread that displays the progress of world loading / saving in cWorld::InitializeSpawn()
|
/** Generates and lights the spawn area of the world. Runs as a separate thread. */
|
||||||
class cWorldLoadProgress :
|
class cSpawnPrepare:
|
||||||
public cIsThread
|
public cIsThread,
|
||||||
|
public cChunkCoordCallback
|
||||||
{
|
{
|
||||||
|
typedef cIsThread super;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
cWorldLoadProgress(cWorld * a_World) :
|
cSpawnPrepare(cWorld & a_World, int a_SpawnChunkX, int a_SpawnChunkZ, int a_PrepareDistance):
|
||||||
cIsThread("cWorldLoadProgress"),
|
super("SpawnPrepare"),
|
||||||
m_World(a_World)
|
m_World(a_World),
|
||||||
|
m_SpawnChunkX(a_SpawnChunkX),
|
||||||
|
m_SpawnChunkZ(a_SpawnChunkZ),
|
||||||
|
m_PrepareDistance(a_PrepareDistance),
|
||||||
|
m_MaxIdx(a_PrepareDistance * a_PrepareDistance),
|
||||||
|
m_NumPrepared(0),
|
||||||
|
m_LastReportChunkCount(0)
|
||||||
{
|
{
|
||||||
|
// Start the thread:
|
||||||
Start();
|
Start();
|
||||||
|
|
||||||
|
// Wait for start confirmation, so that the thread can be waited-upon after the constructor returns:
|
||||||
|
m_EvtStarted.Wait();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Stop(void)
|
|
||||||
|
// cIsThread override:
|
||||||
|
virtual void Execute(void) override
|
||||||
{
|
{
|
||||||
m_ShouldTerminate = true;
|
// Confirm thread start:
|
||||||
Wait();
|
m_EvtStarted.Set();
|
||||||
|
|
||||||
|
// Queue the initial chunks:
|
||||||
|
m_MaxIdx = m_PrepareDistance * m_PrepareDistance;
|
||||||
|
int maxQueue = std::min(m_MaxIdx - 1, 100); // Number of chunks to queue at once
|
||||||
|
m_NextIdx = maxQueue;
|
||||||
|
m_LastReportTime = std::chrono::steady_clock::now();
|
||||||
|
for (int i = 0; i < maxQueue; i++)
|
||||||
|
{
|
||||||
|
int chunkX, chunkZ;
|
||||||
|
DecodeChunkCoords(i, chunkX, chunkZ);
|
||||||
|
m_World.GetLightingThread().QueueChunk(chunkX, chunkZ, this);
|
||||||
|
} // for i
|
||||||
|
|
||||||
|
// Wait for the lighting thread to prepare everything. Event is set in the Call() callback:
|
||||||
|
m_EvtFinished.Wait();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
cWorld & m_World;
|
||||||
|
int m_SpawnChunkX;
|
||||||
|
int m_SpawnChunkZ;
|
||||||
|
int m_PrepareDistance;
|
||||||
|
|
||||||
cWorld * m_World;
|
/** The index of the next chunk to be queued in the lighting thread. */
|
||||||
|
int m_NextIdx;
|
||||||
|
|
||||||
virtual void Execute(void) override
|
/** The maximum index of the prepared chunks. Queueing stops when m_NextIdx reaches this number. */
|
||||||
|
int m_MaxIdx;
|
||||||
|
|
||||||
|
/** Total number of chunks already finished preparing. Preparation finishes when this number reaches m_MaxIdx. */
|
||||||
|
int m_NumPrepared;
|
||||||
|
|
||||||
|
/** Event used to signal that the thread has started. */
|
||||||
|
cEvent m_EvtStarted;
|
||||||
|
|
||||||
|
/** Event used to signal that the preparation is finished. */
|
||||||
|
cEvent m_EvtFinished;
|
||||||
|
|
||||||
|
/** The timestamp of the last progress report emitted. */
|
||||||
|
std::chrono::steady_clock::time_point m_LastReportTime;
|
||||||
|
|
||||||
|
/** Number of chunks prepared when the last progress report was emitted. */
|
||||||
|
int m_LastReportChunkCount;
|
||||||
|
|
||||||
|
// cChunkCoordCallback override:
|
||||||
|
virtual void Call(int a_ChunkX, int a_ChunkZ)
|
||||||
{
|
{
|
||||||
for (;;)
|
// Check if this was the last chunk:
|
||||||
|
m_NumPrepared += 1;
|
||||||
|
if (m_NumPrepared >= m_MaxIdx)
|
||||||
{
|
{
|
||||||
LOG("" SIZE_T_FMT " chunks to load, %d chunks to generate",
|
m_EvtFinished.Set();
|
||||||
m_World->GetStorage().GetLoadQueueLength(),
|
}
|
||||||
m_World->GetGenerator().GetQueueLength()
|
|
||||||
);
|
|
||||||
|
|
||||||
// Wait for 2 sec, but be "reasonably wakeable" when the thread is to finish
|
// Queue another chunk, if appropriate:
|
||||||
for (int i = 0; i < 20; i++)
|
if (m_NextIdx < m_MaxIdx)
|
||||||
{
|
|
||||||
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
|
||||||
if (m_ShouldTerminate)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} // for (-ever)
|
|
||||||
}
|
|
||||||
|
|
||||||
} ;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
// cWorldLightingProgress:
|
|
||||||
|
|
||||||
/// A simple thread that displays the progress of world lighting in cWorld::InitializeSpawn()
|
|
||||||
class cWorldLightingProgress :
|
|
||||||
public cIsThread
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
cWorldLightingProgress(cLightingThread * a_Lighting) :
|
|
||||||
cIsThread("cWorldLightingProgress"),
|
|
||||||
m_Lighting(a_Lighting)
|
|
||||||
{
|
|
||||||
Start();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Stop(void)
|
|
||||||
{
|
|
||||||
m_ShouldTerminate = true;
|
|
||||||
Wait();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
|
||||||
|
|
||||||
cLightingThread * m_Lighting;
|
|
||||||
|
|
||||||
virtual void Execute(void) override
|
|
||||||
{
|
|
||||||
for (;;)
|
|
||||||
{
|
{
|
||||||
LOG("" SIZE_T_FMT " chunks remaining to light", m_Lighting->GetQueueLength()
|
int chunkX, chunkZ;
|
||||||
);
|
DecodeChunkCoords(m_NextIdx, chunkX, chunkZ);
|
||||||
|
m_World.GetLightingThread().QueueChunk(chunkX, chunkZ, this);
|
||||||
|
m_NextIdx += 1;
|
||||||
|
}
|
||||||
|
|
||||||
// Wait for 2 sec, but be "reasonably wakeable" when the thread is to finish
|
// Report progress every 1 second:
|
||||||
for (int i = 0; i < 20; i++)
|
auto Now = std::chrono::steady_clock::now();
|
||||||
{
|
if (Now - m_LastReportTime > std::chrono::seconds(1))
|
||||||
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
{
|
||||||
if (m_ShouldTerminate)
|
float PercentDone = static_cast<float>(m_NumPrepared * 100) / m_MaxIdx;
|
||||||
{
|
float ChunkSpeed = static_cast<float>((m_NumPrepared - m_LastReportChunkCount) * 1000) / std::chrono::duration_cast<std::chrono::milliseconds>(Now - m_LastReportTime).count();
|
||||||
return;
|
LOG("Preparing spawn (%s): %.02f%% (%d/%d; %.02f chunks/s)",
|
||||||
}
|
m_World.GetName().c_str(), PercentDone, m_NumPrepared, m_MaxIdx, ChunkSpeed
|
||||||
}
|
);
|
||||||
} // for (-ever)
|
m_LastReportTime = Now;
|
||||||
|
m_LastReportChunkCount = m_NumPrepared;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/** Decodes the index into chunk coords. Provides the specific chunk ordering. */
|
||||||
|
void DecodeChunkCoords(int a_Idx, int & a_ChunkX, int & a_ChunkZ)
|
||||||
|
{
|
||||||
|
// A zigzag pattern from the top to bottom, each row alternating between forward-x and backward-x:
|
||||||
|
int z = a_Idx / m_PrepareDistance;
|
||||||
|
int x = a_Idx % m_PrepareDistance;
|
||||||
|
if ((z & 1) == 0)
|
||||||
|
{
|
||||||
|
// Reverse every second row:
|
||||||
|
x = m_PrepareDistance - 1 - x;
|
||||||
|
}
|
||||||
|
a_ChunkZ = m_SpawnChunkZ + z - m_PrepareDistance / 2;
|
||||||
|
a_ChunkX = m_SpawnChunkX + x - m_PrepareDistance / 2;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -206,7 +237,7 @@ void cWorld::cTickThread::Execute(void)
|
|||||||
while (!m_ShouldTerminate)
|
while (!m_ShouldTerminate)
|
||||||
{
|
{
|
||||||
auto NowTime = std::chrono::steady_clock::now();
|
auto NowTime = std::chrono::steady_clock::now();
|
||||||
m_World.Tick(std::chrono::duration_cast<std::chrono::milliseconds>(NowTime - LastTime).count(), std::chrono::duration_cast<std::chrono::duration<int>>(TickTime).count());
|
m_World.Tick(static_cast<float>(std::chrono::duration_cast<std::chrono::milliseconds>(NowTime - LastTime).count()), std::chrono::duration_cast<std::chrono::duration<int>>(TickTime).count());
|
||||||
TickTime = std::chrono::steady_clock::now() - NowTime;
|
TickTime = std::chrono::steady_clock::now() - NowTime;
|
||||||
|
|
||||||
if (TickTime < msPerTick)
|
if (TickTime < msPerTick)
|
||||||
@ -427,52 +458,8 @@ void cWorld::InitializeSpawn(void)
|
|||||||
int ViewDist = IniFile.GetValueSetI("SpawnPosition", "PregenerateDistance", DefaultViewDist);
|
int ViewDist = IniFile.GetValueSetI("SpawnPosition", "PregenerateDistance", DefaultViewDist);
|
||||||
IniFile.WriteFile(m_IniFileName);
|
IniFile.WriteFile(m_IniFileName);
|
||||||
|
|
||||||
LOG("Preparing spawn area in world \"%s\", %d x %d chunks, total %d chunks...", m_WorldName.c_str(), ViewDist, ViewDist, ViewDist * ViewDist);
|
cSpawnPrepare prep(*this, ChunkX, ChunkZ, ViewDist);
|
||||||
for (int x = 0; x < ViewDist; x++)
|
prep.Wait();
|
||||||
{
|
|
||||||
for (int z = 0; z < ViewDist; z++)
|
|
||||||
{
|
|
||||||
m_ChunkMap->TouchChunk(x + ChunkX-(ViewDist - 1) / 2, z + ChunkZ-(ViewDist - 1) / 2); // Queue the chunk in the generator / loader
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
// Display progress during this process:
|
|
||||||
cWorldLoadProgress Progress(this);
|
|
||||||
|
|
||||||
// Wait for the loader to finish loading
|
|
||||||
m_Storage.WaitForLoadQueueEmpty();
|
|
||||||
|
|
||||||
// Wait for the generator to finish generating
|
|
||||||
m_Generator.WaitForQueueEmpty();
|
|
||||||
|
|
||||||
// Wait for the loader to finish saving
|
|
||||||
m_Storage.WaitForSaveQueueEmpty();
|
|
||||||
|
|
||||||
Progress.Stop();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Light all chunks that have been newly generated:
|
|
||||||
LOG("Lighting spawn area in world \"%s\"...", m_WorldName.c_str());
|
|
||||||
|
|
||||||
for (int x = 0; x < ViewDist; x++)
|
|
||||||
{
|
|
||||||
int ChX = x + ChunkX-(ViewDist - 1) / 2;
|
|
||||||
for (int z = 0; z < ViewDist; z++)
|
|
||||||
{
|
|
||||||
int ChZ = z + ChunkZ-(ViewDist - 1) / 2;
|
|
||||||
if (!m_ChunkMap->IsChunkLighted(ChX, ChZ))
|
|
||||||
{
|
|
||||||
m_Lighting.QueueChunk(ChX, ChZ); // Queue the chunk in the lighting thread
|
|
||||||
}
|
|
||||||
} // for z
|
|
||||||
} // for x
|
|
||||||
|
|
||||||
{
|
|
||||||
cWorldLightingProgress Progress(&m_Lighting);
|
|
||||||
m_Lighting.WaitForQueueEmpty();
|
|
||||||
Progress.Stop();
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef TEST_LINEBLOCKTRACER
|
#ifdef TEST_LINEBLOCKTRACER
|
||||||
// DEBUG: Test out the cLineBlockTracer class by tracing a few lines:
|
// DEBUG: Test out the cLineBlockTracer class by tracing a few lines:
|
||||||
@ -735,28 +722,32 @@ void cWorld::InitialiseGeneratorDefaults(cIniFile & a_IniFile)
|
|||||||
{
|
{
|
||||||
case dimEnd:
|
case dimEnd:
|
||||||
{
|
{
|
||||||
a_IniFile.GetValueSet("Generator", "BiomeGen", "Constant");
|
a_IniFile.GetValueSet("Generator", "Generator", "Composable");
|
||||||
a_IniFile.GetValueSet("Generator", "ConstantBiome", "End");
|
a_IniFile.GetValueSet("Generator", "BiomeGen", "Constant");
|
||||||
a_IniFile.GetValueSet("Generator", "HeightGen", "Biomal");
|
a_IniFile.GetValueSet("Generator", "ConstantBiome", "End");
|
||||||
|
a_IniFile.GetValueSet("Generator", "ShapeGen", "End");
|
||||||
a_IniFile.GetValueSet("Generator", "CompositionGen", "End");
|
a_IniFile.GetValueSet("Generator", "CompositionGen", "End");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case dimOverworld:
|
case dimOverworld:
|
||||||
{
|
{
|
||||||
a_IniFile.GetValueSet("Generator", "BiomeGen", "MultiStepMap");
|
a_IniFile.GetValueSet("Generator", "Generator", "Composable");
|
||||||
a_IniFile.GetValueSet("Generator", "HeightGen", "DistortedHeightmap");
|
a_IniFile.GetValueSet("Generator", "BiomeGen", "Grown");
|
||||||
a_IniFile.GetValueSet("Generator", "CompositionGen", "DistortedHeightmap");
|
a_IniFile.GetValueSet("Generator", "ShapeGen", "BiomalNoise3D");
|
||||||
a_IniFile.GetValueSet("Generator", "Finishers", "Ravines, WormNestCaves, WaterLakes, WaterSprings, LavaLakes, LavaSprings, OreNests, Mineshafts, Trees, SprinkleFoliage, Ice, Snow, Lilypads, BottomLava, DeadBushes, PreSimulator");
|
a_IniFile.GetValueSet("Generator", "CompositionGen", "Biomal");
|
||||||
|
a_IniFile.GetValueSet("Generator", "Finishers", "Ravines, WormNestCaves, WaterLakes, WaterSprings, LavaLakes, LavaSprings, OreNests, Mineshafts, Trees, Villages, SprinkleFoliage, Ice, Snow, Lilypads, BottomLava, DeadBushes, PreSimulator");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case dimNether:
|
case dimNether:
|
||||||
{
|
{
|
||||||
a_IniFile.GetValueSet("Generator", "BiomeGen", "Constant");
|
a_IniFile.GetValueSet("Generator", "Generator", "Composable");
|
||||||
a_IniFile.GetValueSet("Generator", "ConstantBiome", "Nether");
|
a_IniFile.GetValueSet("Generator", "BiomeGen", "Constant");
|
||||||
a_IniFile.GetValueSet("Generator", "HeightGen", "Flat");
|
a_IniFile.GetValueSet("Generator", "ConstantBiome", "Nether");
|
||||||
a_IniFile.GetValueSet("Generator", "FlatHeight", "128");
|
a_IniFile.GetValueSet("Generator", "ShapeGen", "HeightMap");
|
||||||
a_IniFile.GetValueSet("Generator", "CompositionGen", "Nether");
|
a_IniFile.GetValueSet("Generator", "HeightGen", "Flat");
|
||||||
a_IniFile.GetValueSet("Generator", "Finishers", "WormNestCaves, BottomLava, LavaSprings, NetherClumpFoliage, NetherForts, PreSimulator");
|
a_IniFile.GetValueSet("Generator", "FlatHeight", "128");
|
||||||
|
a_IniFile.GetValueSet("Generator", "CompositionGen", "Nether");
|
||||||
|
a_IniFile.GetValueSet("Generator", "Finishers", "WormNestCaves, BottomLava, LavaSprings, NetherClumpFoliage, NetherForts, PreSimulator");
|
||||||
a_IniFile.GetValueSet("Generator", "BottomLavaHeight", "30");
|
a_IniFile.GetValueSet("Generator", "BottomLavaHeight", "30");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -696,6 +696,8 @@ public:
|
|||||||
inline size_t GetStorageLoadQueueLength(void) { return m_Storage.GetLoadQueueLength(); } // tolua_export
|
inline size_t GetStorageLoadQueueLength(void) { return m_Storage.GetLoadQueueLength(); } // tolua_export
|
||||||
inline size_t GetStorageSaveQueueLength(void) { return m_Storage.GetSaveQueueLength(); } // tolua_export
|
inline size_t GetStorageSaveQueueLength(void) { return m_Storage.GetSaveQueueLength(); } // tolua_export
|
||||||
|
|
||||||
|
cLightingThread & GetLightingThread(void) { return m_Lighting; }
|
||||||
|
|
||||||
void InitializeSpawn(void);
|
void InitializeSpawn(void);
|
||||||
|
|
||||||
/** Starts threads that belong to this world */
|
/** Starts threads that belong to this world */
|
||||||
|
Loading…
Reference in New Issue
Block a user