Generator: Shape initial refactoring.
The code compiles, but several structure generators are broken, crash on start.
This commit is contained in:
799
src/Generating/CompoGenBiomal.cpp
Normal file
799
src/Generating/CompoGenBiomal.cpp
Normal file
@@ -0,0 +1,799 @@
|
||||
|
||||
// CompoGenBiomal.cpp
|
||||
|
||||
// Implements the cCompoGenBiomal class representing the biome-aware composition generator
|
||||
|
||||
#include "Globals.h"
|
||||
#include "ComposableGenerator.h"
|
||||
#include "../IniFile.h"
|
||||
#include "../Noise.h"
|
||||
#include "../LinearUpscale.h"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// cPattern:
|
||||
|
||||
/** This class is used to store a column pattern initialized at runtime,
|
||||
so that the program doesn't need to explicitly set 256 values for each pattern
|
||||
Each pattern has 256 blocks so that there's no need to check pattern bounds when assigning the
|
||||
pattern - there will always be enough pattern left, even for the whole-chunk-height columns. */
|
||||
class cPattern
|
||||
{
|
||||
public:
|
||||
struct BlockInfo
|
||||
{
|
||||
BLOCKTYPE m_BlockType;
|
||||
NIBBLETYPE m_BlockMeta;
|
||||
};
|
||||
|
||||
cPattern(BlockInfo * a_TopBlocks, size_t a_Count)
|
||||
{
|
||||
// Copy the pattern into the top:
|
||||
for (size_t i = 0; i < a_Count; i++)
|
||||
{
|
||||
m_Pattern[i] = a_TopBlocks[i];
|
||||
}
|
||||
|
||||
// Fill the rest with stone:
|
||||
static BlockInfo Stone = {E_BLOCK_STONE, 0};
|
||||
for (size_t i = a_Count; i < cChunkDef::Height; i++)
|
||||
{
|
||||
m_Pattern[i] = Stone;
|
||||
}
|
||||
}
|
||||
|
||||
const BlockInfo * Get(void) const { return m_Pattern; }
|
||||
|
||||
protected:
|
||||
BlockInfo m_Pattern[cChunkDef::Height];
|
||||
} ;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// The arrays to use for the top block pattern definitions:
|
||||
|
||||
static cPattern::BlockInfo tbGrass[] =
|
||||
{
|
||||
{E_BLOCK_GRASS, 0},
|
||||
{E_BLOCK_DIRT, E_META_DIRT_NORMAL},
|
||||
{E_BLOCK_DIRT, E_META_DIRT_NORMAL},
|
||||
{E_BLOCK_DIRT, E_META_DIRT_NORMAL},
|
||||
} ;
|
||||
|
||||
static cPattern::BlockInfo tbSand[] =
|
||||
{
|
||||
{ E_BLOCK_SAND, 0},
|
||||
{ E_BLOCK_SAND, 0},
|
||||
{ E_BLOCK_SAND, 0},
|
||||
{ E_BLOCK_SANDSTONE, 0},
|
||||
} ;
|
||||
|
||||
static cPattern::BlockInfo tbDirt[] =
|
||||
{
|
||||
{E_BLOCK_DIRT, E_META_DIRT_NORMAL},
|
||||
{E_BLOCK_DIRT, E_META_DIRT_NORMAL},
|
||||
{E_BLOCK_DIRT, E_META_DIRT_NORMAL},
|
||||
{E_BLOCK_DIRT, E_META_DIRT_NORMAL},
|
||||
} ;
|
||||
|
||||
static cPattern::BlockInfo tbPodzol[] =
|
||||
{
|
||||
{E_BLOCK_DIRT, E_META_DIRT_PODZOL},
|
||||
{E_BLOCK_DIRT, E_META_DIRT_NORMAL},
|
||||
{E_BLOCK_DIRT, E_META_DIRT_NORMAL},
|
||||
{E_BLOCK_DIRT, E_META_DIRT_NORMAL},
|
||||
} ;
|
||||
|
||||
static cPattern::BlockInfo tbGrassLess[] =
|
||||
{
|
||||
{E_BLOCK_DIRT, E_META_DIRT_GRASSLESS},
|
||||
{E_BLOCK_DIRT, E_META_DIRT_NORMAL},
|
||||
{E_BLOCK_DIRT, E_META_DIRT_NORMAL},
|
||||
{E_BLOCK_DIRT, E_META_DIRT_NORMAL},
|
||||
} ;
|
||||
|
||||
static cPattern::BlockInfo tbMycelium[] =
|
||||
{
|
||||
{E_BLOCK_MYCELIUM, 0},
|
||||
{E_BLOCK_DIRT, 0},
|
||||
{E_BLOCK_DIRT, 0},
|
||||
{E_BLOCK_DIRT, 0},
|
||||
} ;
|
||||
|
||||
static cPattern::BlockInfo tbGravel[] =
|
||||
{
|
||||
{E_BLOCK_GRAVEL, 0},
|
||||
{E_BLOCK_GRAVEL, 0},
|
||||
{E_BLOCK_GRAVEL, 0},
|
||||
{E_BLOCK_STONE, 0},
|
||||
} ;
|
||||
|
||||
static cPattern::BlockInfo tbStone[] =
|
||||
{
|
||||
{E_BLOCK_STONE, 0},
|
||||
{E_BLOCK_STONE, 0},
|
||||
{E_BLOCK_STONE, 0},
|
||||
{E_BLOCK_STONE, 0},
|
||||
} ;
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Ocean floor pattern top-block definitions:
|
||||
|
||||
static cPattern::BlockInfo tbOFSand[] =
|
||||
{
|
||||
{E_BLOCK_SAND, 0},
|
||||
{E_BLOCK_SAND, 0},
|
||||
{E_BLOCK_SAND, 0},
|
||||
{E_BLOCK_SANDSTONE, 0}
|
||||
} ;
|
||||
|
||||
static cPattern::BlockInfo tbOFClay[] =
|
||||
{
|
||||
{ E_BLOCK_CLAY, 0},
|
||||
{ E_BLOCK_CLAY, 0},
|
||||
{ E_BLOCK_SAND, 0},
|
||||
{ E_BLOCK_SAND, 0},
|
||||
} ;
|
||||
|
||||
static cPattern::BlockInfo tbOFOrangeClay[] =
|
||||
{
|
||||
{ E_BLOCK_STAINED_CLAY, E_META_STAINED_GLASS_ORANGE},
|
||||
{ E_BLOCK_STAINED_CLAY, E_META_STAINED_GLASS_ORANGE},
|
||||
{ E_BLOCK_STAINED_CLAY, E_META_STAINED_GLASS_ORANGE},
|
||||
} ;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Individual patterns to use:
|
||||
|
||||
static cPattern patGrass (tbGrass, ARRAYCOUNT(tbGrass));
|
||||
static cPattern patSand (tbSand, ARRAYCOUNT(tbSand));
|
||||
static cPattern patDirt (tbDirt, ARRAYCOUNT(tbDirt));
|
||||
static cPattern patPodzol (tbPodzol, ARRAYCOUNT(tbPodzol));
|
||||
static cPattern patGrassLess(tbGrassLess, ARRAYCOUNT(tbGrassLess));
|
||||
static cPattern patMycelium (tbMycelium, ARRAYCOUNT(tbMycelium));
|
||||
static cPattern patGravel (tbGravel, ARRAYCOUNT(tbGravel));
|
||||
static cPattern patStone (tbStone, ARRAYCOUNT(tbStone));
|
||||
|
||||
static cPattern patOFSand (tbOFSand, ARRAYCOUNT(tbOFSand));
|
||||
static cPattern patOFClay (tbOFClay, ARRAYCOUNT(tbOFClay));
|
||||
static cPattern patOFOrangeClay(tbOFOrangeClay, ARRAYCOUNT(tbOFOrangeClay));
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// cCompoGenBiomal:
|
||||
|
||||
class cCompoGenBiomal :
|
||||
public cTerrainCompositionGen
|
||||
{
|
||||
public:
|
||||
cCompoGenBiomal(int a_Seed) :
|
||||
m_SeaLevel(62),
|
||||
m_OceanFloorSelect(a_Seed + 1),
|
||||
m_MesaFloor(a_Seed + 2)
|
||||
{
|
||||
initMesaPattern(a_Seed);
|
||||
}
|
||||
|
||||
protected:
|
||||
/** The block height at which water is generated instead of air. */
|
||||
int m_SeaLevel;
|
||||
|
||||
/** The pattern used for mesa biomes. Initialized by seed on generator creation. */
|
||||
cPattern::BlockInfo m_MesaPattern[2 * cChunkDef::Height];
|
||||
|
||||
/** Noise used for selecting between dirt and sand on the ocean floor. */
|
||||
cNoise m_OceanFloorSelect;
|
||||
|
||||
/** Noise used for the floor of the clay blocks in mesa biomes. */
|
||||
cNoise m_MesaFloor;
|
||||
|
||||
|
||||
// cTerrainCompositionGen overrides:
|
||||
virtual void ComposeTerrain(cChunkDesc & a_ChunkDesc, const cChunkDesc::Shape & a_Shape) override
|
||||
{
|
||||
a_ChunkDesc.FillBlocks(E_BLOCK_AIR, 0);
|
||||
for (int z = 0; z < cChunkDef::Width; z++)
|
||||
{
|
||||
for (int x = 0; x < cChunkDef::Width; x++)
|
||||
{
|
||||
ComposeColumn(a_ChunkDesc, x, z, &(a_Shape[x * 256 + z * 16 * 256]));
|
||||
} // for x
|
||||
} // for z
|
||||
}
|
||||
|
||||
|
||||
|
||||
virtual void InitializeCompoGen(cIniFile & a_IniFile) override
|
||||
{
|
||||
m_SeaLevel = a_IniFile.GetValueSetI("Generator", "SeaLevel", m_SeaLevel) - 1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/** Initializes the m_MesaPattern with a pattern based on the generator's seed. */
|
||||
void initMesaPattern(int a_Seed)
|
||||
{
|
||||
// In a loop, choose whether to use one, two or three layers of stained clay, then choose a color and width for each layer
|
||||
// Separate each group with another layer of hardened clay
|
||||
cNoise patternNoise((unsigned)a_Seed);
|
||||
static NIBBLETYPE allowedColors[] =
|
||||
{
|
||||
E_META_STAINED_CLAY_YELLOW,
|
||||
E_META_STAINED_CLAY_YELLOW,
|
||||
E_META_STAINED_CLAY_RED,
|
||||
E_META_STAINED_CLAY_RED,
|
||||
E_META_STAINED_CLAY_WHITE,
|
||||
E_META_STAINED_CLAY_BROWN,
|
||||
E_META_STAINED_CLAY_BROWN,
|
||||
E_META_STAINED_CLAY_BROWN,
|
||||
E_META_STAINED_CLAY_ORANGE,
|
||||
E_META_STAINED_CLAY_ORANGE,
|
||||
E_META_STAINED_CLAY_ORANGE,
|
||||
E_META_STAINED_CLAY_ORANGE,
|
||||
E_META_STAINED_CLAY_ORANGE,
|
||||
E_META_STAINED_CLAY_ORANGE,
|
||||
E_META_STAINED_CLAY_LIGHTGRAY,
|
||||
} ;
|
||||
static int layerSizes[] = // Adjust the chance so that thinner layers occur more commonly
|
||||
{
|
||||
1, 1, 1, 1, 1, 1,
|
||||
2, 2, 2, 2,
|
||||
3, 3,
|
||||
} ;
|
||||
int idx = ARRAYCOUNT(m_MesaPattern) - 1;
|
||||
while (idx >= 0)
|
||||
{
|
||||
// A layer group of 1 - 2 color stained clay:
|
||||
int rnd = patternNoise.IntNoise1DInt(idx) / 7;
|
||||
int numLayers = (rnd % 2) + 1;
|
||||
rnd /= 2;
|
||||
for (int lay = 0; lay < numLayers; lay++)
|
||||
{
|
||||
int numBlocks = layerSizes[(rnd % ARRAYCOUNT(layerSizes))];
|
||||
NIBBLETYPE Color = allowedColors[(rnd / 4) % ARRAYCOUNT(allowedColors)];
|
||||
if (
|
||||
((numBlocks == 3) && (numLayers == 2)) || // In two-layer mode disallow the 3-high layers:
|
||||
(Color == E_META_STAINED_CLAY_WHITE)) // White stained clay can ever be only 1 block high
|
||||
{
|
||||
numBlocks = 1;
|
||||
}
|
||||
numBlocks = std::min(idx + 1, numBlocks); // Limit by idx so that we don't have to check inside the loop
|
||||
rnd /= 32;
|
||||
for (int block = 0; block < numBlocks; block++, idx--)
|
||||
{
|
||||
m_MesaPattern[idx].m_BlockMeta = Color;
|
||||
m_MesaPattern[idx].m_BlockType = E_BLOCK_STAINED_CLAY;
|
||||
} // for block
|
||||
} // for lay
|
||||
|
||||
// A layer of hardened clay in between the layer group:
|
||||
int numBlocks = (rnd % 4) + 1; // All heights the same probability
|
||||
if ((numLayers == 2) && (numBlocks < 4))
|
||||
{
|
||||
// For two layers of stained clay, add an extra block of hardened clay:
|
||||
numBlocks++;
|
||||
}
|
||||
numBlocks = std::min(idx + 1, numBlocks); // Limit by idx so that we don't have to check inside the loop
|
||||
for (int block = 0; block < numBlocks; block++, idx--)
|
||||
{
|
||||
m_MesaPattern[idx].m_BlockMeta = 0;
|
||||
m_MesaPattern[idx].m_BlockType = E_BLOCK_HARDENED_CLAY;
|
||||
} // for block
|
||||
} // while (idx >= 0)
|
||||
}
|
||||
|
||||
|
||||
|
||||
/** Composes a single column in a_ChunkDesc. Chooses what to do based on the biome in that column. */
|
||||
void ComposeColumn(cChunkDesc & a_ChunkDesc, int a_RelX, int a_RelZ, const Byte * a_ShapeColumn)
|
||||
{
|
||||
// Frequencies for the podzol floor selecting noise:
|
||||
const NOISE_DATATYPE FrequencyX = 8;
|
||||
const NOISE_DATATYPE FrequencyZ = 8;
|
||||
|
||||
EMCSBiome Biome = a_ChunkDesc.GetBiome(a_RelX, a_RelZ);
|
||||
switch (Biome)
|
||||
{
|
||||
case biOcean:
|
||||
case biPlains:
|
||||
case biForest:
|
||||
case biTaiga:
|
||||
case biSwampland:
|
||||
case biRiver:
|
||||
case biFrozenOcean:
|
||||
case biFrozenRiver:
|
||||
case biIcePlains:
|
||||
case biIceMountains:
|
||||
case biForestHills:
|
||||
case biTaigaHills:
|
||||
case biExtremeHillsEdge:
|
||||
case biExtremeHillsPlus:
|
||||
case biExtremeHills:
|
||||
case biJungle:
|
||||
case biJungleHills:
|
||||
case biJungleEdge:
|
||||
case biDeepOcean:
|
||||
case biStoneBeach:
|
||||
case biColdBeach:
|
||||
case biBirchForest:
|
||||
case biBirchForestHills:
|
||||
case biRoofedForest:
|
||||
case biColdTaiga:
|
||||
case biColdTaigaHills:
|
||||
case biSavanna:
|
||||
case biSavannaPlateau:
|
||||
case biSunflowerPlains:
|
||||
case biFlowerForest:
|
||||
case biTaigaM:
|
||||
case biSwamplandM:
|
||||
case biIcePlainsSpikes:
|
||||
case biJungleM:
|
||||
case biJungleEdgeM:
|
||||
case biBirchForestM:
|
||||
case biBirchForestHillsM:
|
||||
case biRoofedForestM:
|
||||
case biColdTaigaM:
|
||||
case biSavannaM:
|
||||
case biSavannaPlateauM:
|
||||
{
|
||||
FillColumnPattern(a_ChunkDesc, a_RelX, a_RelZ, patGrass.Get(), a_ShapeColumn);
|
||||
return;
|
||||
}
|
||||
|
||||
case biMegaTaiga:
|
||||
case biMegaTaigaHills:
|
||||
case biMegaSpruceTaiga:
|
||||
case biMegaSpruceTaigaHills:
|
||||
{
|
||||
// Select the pattern to use - podzol, grass or grassless dirt:
|
||||
NOISE_DATATYPE NoiseX = ((NOISE_DATATYPE)(a_ChunkDesc.GetChunkX() * cChunkDef::Width + a_RelX)) / FrequencyX;
|
||||
NOISE_DATATYPE NoiseY = ((NOISE_DATATYPE)(a_ChunkDesc.GetChunkZ() * cChunkDef::Width + a_RelZ)) / FrequencyZ;
|
||||
NOISE_DATATYPE Val = m_OceanFloorSelect.CubicNoise2D(NoiseX, NoiseY);
|
||||
const cPattern::BlockInfo * Pattern = (Val < -0.9) ? patGrassLess.Get() : ((Val > 0) ? patPodzol.Get() : patGrass.Get());
|
||||
FillColumnPattern(a_ChunkDesc, a_RelX, a_RelZ, Pattern, a_ShapeColumn);
|
||||
return;
|
||||
}
|
||||
|
||||
case biDesertHills:
|
||||
case biDesert:
|
||||
case biDesertM:
|
||||
case biBeach:
|
||||
{
|
||||
FillColumnPattern(a_ChunkDesc, a_RelX, a_RelZ, patSand.Get(), a_ShapeColumn);
|
||||
return;
|
||||
}
|
||||
|
||||
case biMushroomIsland:
|
||||
case biMushroomShore:
|
||||
{
|
||||
FillColumnPattern(a_ChunkDesc, a_RelX, a_RelZ, patMycelium.Get(), a_ShapeColumn);
|
||||
return;
|
||||
}
|
||||
|
||||
case biMesa:
|
||||
case biMesaPlateauF:
|
||||
case biMesaPlateau:
|
||||
case biMesaBryce:
|
||||
case biMesaPlateauFM:
|
||||
case biMesaPlateauM:
|
||||
{
|
||||
// Mesa biomes need special handling, because they don't follow the usual "4 blocks from top pattern",
|
||||
// instead, they provide a "from bottom" pattern with varying base height,
|
||||
// usually 4 blocks below the ocean level
|
||||
FillColumnMesa(a_ChunkDesc, a_RelX, a_RelZ, a_ShapeColumn);
|
||||
return;
|
||||
}
|
||||
|
||||
case biExtremeHillsPlusM:
|
||||
case biExtremeHillsM:
|
||||
{
|
||||
// Select the pattern to use - gravel, stone or grass:
|
||||
NOISE_DATATYPE NoiseX = ((NOISE_DATATYPE)(a_ChunkDesc.GetChunkX() * cChunkDef::Width + a_RelX)) / FrequencyX;
|
||||
NOISE_DATATYPE NoiseY = ((NOISE_DATATYPE)(a_ChunkDesc.GetChunkZ() * cChunkDef::Width + a_RelZ)) / FrequencyZ;
|
||||
NOISE_DATATYPE Val = m_OceanFloorSelect.CubicNoise2D(NoiseX, NoiseY);
|
||||
const cPattern::BlockInfo * Pattern = (Val < 0.0) ? patStone.Get() : patGrass.Get();
|
||||
FillColumnPattern(a_ChunkDesc, a_RelX, a_RelZ, Pattern, a_ShapeColumn);
|
||||
return;
|
||||
}
|
||||
default:
|
||||
{
|
||||
ASSERT(!"Unhandled biome");
|
||||
return;
|
||||
}
|
||||
} // switch (Biome)
|
||||
}
|
||||
|
||||
|
||||
|
||||
/** Fills the specified column with the specified pattern; restarts the pattern when air is reached,
|
||||
switches to ocean floor pattern if ocean is reached. Always adds bedrock at the very bottom. */
|
||||
void FillColumnPattern(cChunkDesc & a_ChunkDesc, int a_RelX, int a_RelZ, const cPattern::BlockInfo * a_Pattern, const Byte * a_ShapeColumn)
|
||||
{
|
||||
bool HasHadWater = false;
|
||||
int PatternIdx = 0;
|
||||
for (int y = a_ChunkDesc.GetHeight(a_RelX, a_RelZ); y > 0; y--)
|
||||
{
|
||||
if (a_ShapeColumn[y] > 0)
|
||||
{
|
||||
// "ground" part, use the pattern:
|
||||
a_ChunkDesc.SetBlockTypeMeta(a_RelX, y, a_RelZ, a_Pattern[PatternIdx].m_BlockType, a_Pattern[PatternIdx].m_BlockMeta);
|
||||
PatternIdx++;
|
||||
continue;
|
||||
}
|
||||
|
||||
// "air" or "water" part:
|
||||
// Reset the pattern index to zero, so that the pattern is repeated from the top again:
|
||||
PatternIdx = 0;
|
||||
|
||||
if (y >= m_SeaLevel)
|
||||
{
|
||||
// "air" part, do nothing
|
||||
continue;
|
||||
}
|
||||
|
||||
a_ChunkDesc.SetBlockType(a_RelX, y, a_RelZ, E_BLOCK_STATIONARY_WATER);
|
||||
if (HasHadWater)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Select the ocean-floor pattern to use:
|
||||
if (a_ChunkDesc.GetBiome(a_RelX, a_RelZ) == biDeepOcean)
|
||||
{
|
||||
a_Pattern = patGravel.Get();
|
||||
}
|
||||
else
|
||||
{
|
||||
a_Pattern = ChooseOceanFloorPattern(a_ChunkDesc.GetChunkX(), a_ChunkDesc.GetChunkZ(), a_RelX, a_RelZ);
|
||||
}
|
||||
HasHadWater = true;
|
||||
} // for y
|
||||
a_ChunkDesc.SetBlockType(a_RelX, 0, a_RelZ, E_BLOCK_BEDROCK);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/** Fills the specified column with mesa pattern, based on the column height */
|
||||
void FillColumnMesa(cChunkDesc & a_ChunkDesc, int a_RelX, int a_RelZ, const Byte * a_ShapeColumn)
|
||||
{
|
||||
// Frequencies for the clay floor noise:
|
||||
const NOISE_DATATYPE FrequencyX = 50;
|
||||
const NOISE_DATATYPE FrequencyZ = 50;
|
||||
|
||||
int Top = a_ChunkDesc.GetHeight(a_RelX, a_RelZ);
|
||||
if (Top < m_SeaLevel)
|
||||
{
|
||||
// The terrain is below sealevel, handle as regular ocean with red sand floor:
|
||||
FillColumnPattern(a_ChunkDesc, a_RelX, a_RelZ, patOFOrangeClay.Get(), a_ShapeColumn);
|
||||
return;
|
||||
}
|
||||
|
||||
NOISE_DATATYPE NoiseX = ((NOISE_DATATYPE)(a_ChunkDesc.GetChunkX() * cChunkDef::Width + a_RelX)) / FrequencyX;
|
||||
NOISE_DATATYPE NoiseY = ((NOISE_DATATYPE)(a_ChunkDesc.GetChunkZ() * cChunkDef::Width + a_RelZ)) / FrequencyZ;
|
||||
int ClayFloor = m_SeaLevel - 6 + (int)(4.f * m_MesaFloor.CubicNoise2D(NoiseX, NoiseY));
|
||||
if (ClayFloor >= Top)
|
||||
{
|
||||
ClayFloor = Top - 1;
|
||||
}
|
||||
|
||||
if (Top - m_SeaLevel < 5)
|
||||
{
|
||||
// Simple case: top is red sand, then hardened clay down to ClayFloor, then stone:
|
||||
a_ChunkDesc.SetBlockTypeMeta(a_RelX, Top, a_RelZ, E_BLOCK_SAND, E_META_SAND_RED);
|
||||
for (int y = Top - 1; y >= ClayFloor; y--)
|
||||
{
|
||||
a_ChunkDesc.SetBlockType(a_RelX, y, a_RelZ, E_BLOCK_HARDENED_CLAY);
|
||||
}
|
||||
for (int y = ClayFloor - 1; y > 0; y--)
|
||||
{
|
||||
a_ChunkDesc.SetBlockType(a_RelX, y, a_RelZ, E_BLOCK_STONE);
|
||||
}
|
||||
a_ChunkDesc.SetBlockType(a_RelX, 0, a_RelZ, E_BLOCK_BEDROCK);
|
||||
return;
|
||||
}
|
||||
|
||||
// Difficult case: use the mesa pattern and watch for overhangs:
|
||||
int PatternIdx = cChunkDef::Height - (Top - ClayFloor); // We want the block at index ClayFloor to be pattern's 256th block (first stone)
|
||||
const cPattern::BlockInfo * Pattern = m_MesaPattern;
|
||||
bool HasHadWater = false;
|
||||
for (int y = Top; y > 0; y--)
|
||||
{
|
||||
if (a_ShapeColumn[y] > 0)
|
||||
{
|
||||
// "ground" part, use the pattern:
|
||||
a_ChunkDesc.SetBlockTypeMeta(a_RelX, y, a_RelZ, Pattern[PatternIdx].m_BlockType, Pattern[PatternIdx].m_BlockMeta);
|
||||
PatternIdx++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (y >= m_SeaLevel)
|
||||
{
|
||||
// "air" part, do nothing
|
||||
continue;
|
||||
}
|
||||
|
||||
// "water" part, fill with water and choose new pattern for ocean floor, if not chosen already:
|
||||
PatternIdx = 0;
|
||||
a_ChunkDesc.SetBlockType(a_RelX, y, a_RelZ, E_BLOCK_STATIONARY_WATER);
|
||||
if (HasHadWater)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Select the ocean-floor pattern to use:
|
||||
Pattern = ChooseOceanFloorPattern(a_ChunkDesc.GetChunkX(), a_ChunkDesc.GetChunkZ(), a_RelX, a_RelZ);
|
||||
HasHadWater = true;
|
||||
} // for y
|
||||
a_ChunkDesc.SetBlockType(a_RelX, 0, a_RelZ, E_BLOCK_BEDROCK);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/** Returns the pattern to use for an ocean floor in the specified column.
|
||||
The returned pattern is guaranteed to be 256 blocks long. */
|
||||
const cPattern::BlockInfo * ChooseOceanFloorPattern(int a_ChunkX, int a_ChunkZ, int a_RelX, int a_RelZ)
|
||||
{
|
||||
// Frequencies for the ocean floor selecting noise:
|
||||
const NOISE_DATATYPE FrequencyX = 3;
|
||||
const NOISE_DATATYPE FrequencyZ = 3;
|
||||
|
||||
// Select the ocean-floor pattern to use:
|
||||
NOISE_DATATYPE NoiseX = ((NOISE_DATATYPE)(a_ChunkX * cChunkDef::Width + a_RelX)) / FrequencyX;
|
||||
NOISE_DATATYPE NoiseY = ((NOISE_DATATYPE)(a_ChunkZ * cChunkDef::Width + a_RelZ)) / FrequencyZ;
|
||||
NOISE_DATATYPE Val = m_OceanFloorSelect.CubicNoise2D(NoiseX, NoiseY);
|
||||
if (Val < -0.95)
|
||||
{
|
||||
return patOFClay.Get();
|
||||
}
|
||||
else if (Val < 0)
|
||||
{
|
||||
return patOFSand.Get();
|
||||
}
|
||||
else
|
||||
{
|
||||
return patDirt.Get();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
#if 0
|
||||
/** Fills a single column with grass-based terrain (grass or water, dirt, stone). */
|
||||
void FillColumnGrass(int a_RelX, int a_RelZ, const Byte * a_ShapeColumn, cChunkDesc & a_ChunkDesc)
|
||||
{
|
||||
static const PatternItem pattern[] =
|
||||
{
|
||||
{ E_BLOCK_GRASS, 0},
|
||||
{ E_BLOCK_DIRT, 0},
|
||||
{ E_BLOCK_DIRT, 0},
|
||||
{ E_BLOCK_DIRT, 0},
|
||||
} ;
|
||||
FillColumnPattern(a_RelX, a_RelZ, a_ShapeColumn, a_ChunkDesc, pattern, ARRAYCOUNT(pattern));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/** Fills a single column with grass-based terrain (grass or water, dirt, stone). */
|
||||
void FillColumnStone(int a_RelX, int a_RelZ, const Byte * a_ShapeColumn, cChunkDesc & a_ChunkDesc)
|
||||
{
|
||||
static const PatternItem pattern[] =
|
||||
{
|
||||
{ E_BLOCK_STONE, 0},
|
||||
} ;
|
||||
FillColumnPattern(a_RelX, a_RelZ, a_ShapeColumn, a_ChunkDesc, pattern, ARRAYCOUNT(pattern));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/** Fills a single column with Mesa-like terrain (variations of clay). */
|
||||
void FillColumnMesa(int a_RelX, int a_RelZ, const Byte * a_ShapeColumn, cChunkDesc & a_ChunkDesc)
|
||||
{
|
||||
// Fill with grass and dirt on the very top of mesa plateaus:
|
||||
size_t curIdx = 0;
|
||||
for (int y = 255; y > m_MesaDirtLevel; y--)
|
||||
{
|
||||
if (a_ShapeColumn[y] > 0)
|
||||
{
|
||||
a_ChunkDesc.SetBlockType(a_RelX, y, a_RelZ, (curIdx > 0) ? E_BLOCK_DIRT : E_BLOCK_GRASS);
|
||||
curIdx += 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
curIdx = 0;
|
||||
}
|
||||
} // for y
|
||||
|
||||
// Fill with clays from the DirtLevel down to SandLevel:
|
||||
for (int y = m_MesaDirtLevel; y > m_MesaSandLevel; y--)
|
||||
{
|
||||
if (a_ShapeColumn[y] > 0)
|
||||
{
|
||||
a_ChunkDesc.SetBlockTypeMeta(a_RelX, y, a_RelZ, m_MesaPattern[y].m_BlockType, m_MesaPattern[y].m_BlockMeta);
|
||||
}
|
||||
else
|
||||
{
|
||||
curIdx = 0;
|
||||
}
|
||||
} // for y
|
||||
|
||||
// If currently air, switch to red sand pattern:
|
||||
static const PatternItem redSandPattern[] =
|
||||
{
|
||||
{ E_BLOCK_SAND, E_META_SAND_RED},
|
||||
{ E_BLOCK_STAINED_CLAY, E_META_STAINED_CLAY_ORANGE},
|
||||
{ E_BLOCK_STAINED_CLAY, E_META_STAINED_CLAY_ORANGE},
|
||||
{ E_BLOCK_STAINED_CLAY, E_META_STAINED_CLAY_ORANGE},
|
||||
};
|
||||
Pattern pattern;
|
||||
size_t patternSize;
|
||||
if (curIdx == 0)
|
||||
{
|
||||
pattern = redSandPattern;
|
||||
patternSize = ARRAYCOUNT(redSandPattern);
|
||||
}
|
||||
else
|
||||
{
|
||||
pattern = m_MesaPattern + m_MesaSandLevel;
|
||||
patternSize = static_cast<size_t>(m_MesaSandLevel);
|
||||
}
|
||||
|
||||
// Fill with current pattern (MesaPattern or RedSand) until sealevel:
|
||||
for (int y = m_MesaSandLevel; y > m_SeaLevel; y--)
|
||||
{
|
||||
if (a_ShapeColumn[y] > 0)
|
||||
{
|
||||
if (curIdx >= patternSize)
|
||||
{
|
||||
a_ChunkDesc.SetBlockTypeMeta(a_RelX, y, a_RelZ, E_BLOCK_STAINED_CLAY, E_META_STAINED_CLAY_ORANGE);
|
||||
}
|
||||
else
|
||||
{
|
||||
a_ChunkDesc.SetBlockTypeMeta(a_RelX, y, a_RelZ, pattern[curIdx].m_BlockType, pattern[curIdx].m_BlockMeta);
|
||||
}
|
||||
curIdx += 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Air resets the pattern to red sand:
|
||||
curIdx = 0;
|
||||
pattern = redSandPattern;
|
||||
patternSize = ARRAYCOUNT(redSandPattern);
|
||||
}
|
||||
} // for y
|
||||
|
||||
// If there is an ocean, fill it with water and then redsand:
|
||||
int y = m_SeaLevel;
|
||||
for (; y > 0; y--)
|
||||
{
|
||||
if ((a_ShapeColumn[y] == 0) || (curIdx >= ARRAYCOUNT(redSandPattern)))
|
||||
{
|
||||
// water pocket or out of red sand pattern, use stone from now on
|
||||
break;
|
||||
}
|
||||
a_ChunkDesc.SetBlockTypeMeta(a_RelX, y, a_RelZ, E_BLOCK_STAINED_CLAY, E_META_STAINED_CLAY_ORANGE);
|
||||
curIdx = curIdx + 1;
|
||||
} // for y
|
||||
|
||||
// The rest should be filled with stone:
|
||||
for (; y > 0; y--)
|
||||
{
|
||||
if (a_ShapeColumn[y] > 0)
|
||||
{
|
||||
a_ChunkDesc.SetBlockType(a_RelX, y, a_RelZ, E_BLOCK_STONE);
|
||||
}
|
||||
} // for y
|
||||
}
|
||||
|
||||
|
||||
|
||||
/** Fills a single column with megataiga-based terrain (grass or podzol on top). */
|
||||
void FillColumnMegaTaiga(int a_RelX, int a_RelZ, const Byte * a_ShapeColumn, cChunkDesc & a_ChunkDesc)
|
||||
{
|
||||
// TODO
|
||||
}
|
||||
|
||||
|
||||
|
||||
/** Fills a single column with sand-based terrain (such as desert or beach). */
|
||||
void FillColumnSand(int a_RelX, int a_RelZ, const Byte * a_ShapeColumn, cChunkDesc & a_ChunkDesc)
|
||||
{
|
||||
static const PatternItem pattern[] =
|
||||
{
|
||||
{ E_BLOCK_SAND, 0},
|
||||
{ E_BLOCK_SAND, 0},
|
||||
{ E_BLOCK_SAND, 0},
|
||||
{ E_BLOCK_SANDSTONE, 0},
|
||||
} ;
|
||||
FillColumnPattern(a_RelX, a_RelZ, a_ShapeColumn, a_ChunkDesc, pattern, ARRAYCOUNT(pattern));
|
||||
}
|
||||
|
||||
|
||||
|
||||
void FillColumnMycelium(int a_RelX, int a_RelZ, const Byte * a_ShapeColumn, cChunkDesc & a_ChunkDesc)
|
||||
{
|
||||
static const PatternItem pattern[] =
|
||||
{
|
||||
{ E_BLOCK_MYCELIUM, 0},
|
||||
{ E_BLOCK_DIRT, 0},
|
||||
{ E_BLOCK_DIRT, 0},
|
||||
{ E_BLOCK_DIRT, 0},
|
||||
} ;
|
||||
FillColumnPattern(a_RelX, a_RelZ, a_ShapeColumn, a_ChunkDesc, pattern, ARRAYCOUNT(pattern));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/** Fills the column with the specified pattern, repeating it if there's an air pocket in between. */
|
||||
void FillColumnPattern(int a_RelX, int a_RelZ, const Byte * a_ShapeColumn, cChunkDesc & a_ChunkDesc, Pattern a_Pattern, size_t a_PatternSize)
|
||||
{
|
||||
// Fill with pattern until sealevel:
|
||||
size_t curIdx = 0;
|
||||
for (int y = 255; y > m_SeaLevel; y--)
|
||||
{
|
||||
if (a_ShapeColumn[y] > 0)
|
||||
{
|
||||
// Continue with the pattern:
|
||||
if (curIdx >= a_PatternSize)
|
||||
{
|
||||
a_ChunkDesc.SetBlockType(a_RelX, y, a_RelZ, E_BLOCK_STONE);
|
||||
}
|
||||
else
|
||||
{
|
||||
a_ChunkDesc.SetBlockTypeMeta(a_RelX, y, a_RelZ, a_Pattern[curIdx].m_BlockType, a_Pattern[curIdx].m_BlockMeta);
|
||||
}
|
||||
curIdx += 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Air pocket, restart the pattern:
|
||||
curIdx = 0;
|
||||
}
|
||||
} // for y
|
||||
|
||||
// From sealevel downward use the ocean floor pattern:
|
||||
FillOceanFloor(a_RelX, a_RelZ, a_ShapeColumn, a_ChunkDesc, a_Pattern, a_PatternSize, curIdx);
|
||||
}
|
||||
|
||||
|
||||
/** Fills the blocks from sealevel down to bottom with ocean-floor pattern.
|
||||
a_PatternStartOffset specifies the offset at which to start the pattern, in case there was air just above. */
|
||||
void FillOceanFloor(int a_RelX, int a_RelZ, const Byte * a_ShapeColumn, cChunkDesc & a_ChunkDesc, Pattern a_Pattern, size_t a_PatternSize, size_t a_PatternStartOffset)
|
||||
{
|
||||
for (int y = m_SeaLevel; y > 0; y--)
|
||||
{
|
||||
if (a_ShapeColumn[y] > 0)
|
||||
{
|
||||
// TODO
|
||||
}
|
||||
} // for y
|
||||
}
|
||||
#endif
|
||||
} ;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
cTerrainCompositionGenPtr CreateCompoGenBiomal(int a_Seed)
|
||||
{
|
||||
return std::make_shared<cCompoGenBiomal>(a_Seed);
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user