Loading [MathJax]/extensions/MathMenu.js
Cytopia  0.3
A city building simulation game
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
TerrainGenerator Class Reference

#include <TerrainGenerator.hxx>

+ Collaboration diagram for TerrainGenerator:

Public Member Functions

 TerrainGenerator ()=default
 
 ~TerrainGenerator ()=default
 
void generateTerrain (std::vector< MapNode > &mapNodes, std::vector< MapNode * > &mapNodesInDrawingOrder)
 
void generateRiver (std::vector< MapNode > &mapNodes)
 
void loadTerrainDataFromJSON ()
 

Private Attributes

TerrainSettings m_terrainSettings
 
std::map< std::string, BiomeDatam_biomeInformation
 key: biome More...
 
std::vector< Pointm_riverSourceNodes
 

Detailed Description

Definition at line 47 of file TerrainGenerator.hxx.

Constructor & Destructor Documentation

◆ TerrainGenerator()

TerrainGenerator::TerrainGenerator ( )
default

◆ ~TerrainGenerator()

TerrainGenerator::~TerrainGenerator ( )
default

Member Function Documentation

◆ generateRiver()

void TerrainGenerator::generateRiver ( std::vector< MapNode > &  mapNodes)

Definition at line 179 of file TerrainGenerator.cxx.

180 {
181  std::unordered_set<Point> riverNodes;
182  std::vector<Point> neighbors;
183  Point curPoint, nextPoint;
184  double curHeight, nextHeight, neighborHeight;
185  int riverNumber = 0;
186 
187  for (int i = 0; i < m_riverSourceNodes.size(); i++)
188  {
189  curPoint = m_riverSourceNodes[i];
190  curHeight = mapNodes[curPoint.toIndex()].getCoordinates().rawHeight;
191 
192  while (true)
193  {
194  if (riverNodes.find(curPoint) != riverNodes.end())
195  riverNodes.insert(curPoint);
196 
197  // Find the lowest node
198  nextHeight = 32;
199  neighbors = PointFunctions::getNeighbors(curPoint, false);
200  for (int j = 0; j < neighbors.size(); ++j)
201  {
202  if (riverNodes.find(neighbors[j]) != riverNodes.end())
203  continue;
204  neighborHeight = mapNodes[neighbors[j].toIndex()].getCoordinates().rawHeight;
205  if (neighborHeight < nextHeight)
206  {
207  nextHeight = neighborHeight;
208  nextPoint = neighbors[j];
209  }
210  }
211 
212  // Add lowest nodes in the area to riverNodes
213  for (int j = 0; j < neighbors.size(); ++j)
214  {
215  neighborHeight = mapNodes[neighbors[j].toIndex()].getCoordinates().rawHeight;
216  if (neighborHeight <= nextHeight + 0.005 && (riverNodes.find(neighbors[j]) == riverNodes.end()))
217  {
218  riverNodes.insert(neighbors[j]);
219  }
220  }
221 
222  // These nodes can reach the sea, so set nodes to river
223  if (curHeight < m_terrainSettings.seaLevel)
224  {
225  for (Point point: riverNodes)
226  {
227  MapNode *node = &(mapNodes[point.toIndex()]);
228  node->setTileID("water", point);
229  }
230  riverNumber++;
231  riverNodes.clear();
232  break;
233  }
234 
235  // Terrain slight rise is not able to stop the river
236  if (nextHeight > curHeight + 0.03)
237  {
238  riverNodes.clear();
239  break;
240  }
241 
242  curPoint = nextPoint;
243  curHeight = nextHeight;
244  }
245  }
246 
247  LOG(LOG_INFO) << __func__ << __LINE__ << "Number of rivers: " << riverNumber;
248 }
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ generateTerrain()

void TerrainGenerator::generateTerrain ( std::vector< MapNode > &  mapNodes,
std::vector< MapNode * > &  mapNodesInDrawingOrder 
)

Definition at line 21 of file TerrainGenerator.cxx.

22 {
24 
25  if (m_terrainSettings.seed == 0)
26  {
27  srand(static_cast<unsigned int>(time(0)));
28  m_terrainSettings.seed = rand();
29  }
30 
31  noise::module::Perlin terrainHeightPerlin;
32  terrainHeightPerlin.SetSeed(m_terrainSettings.seed);
33  terrainHeightPerlin.SetFrequency(0.003 / 32);
34  terrainHeightPerlin.SetLacunarity(1.5);
35  terrainHeightPerlin.SetOctaveCount(16);
36  noise::module::ScaleBias terrainHeightPerlinScaled;
37  terrainHeightPerlinScaled.SetSourceModule(0, terrainHeightPerlin);
38  terrainHeightPerlinScaled.SetScale(0.25);
39  terrainHeightPerlinScaled.SetBias(-0.5);
40 
41  noise::module::RidgedMulti terrainHeightFractal;
42  terrainHeightFractal.SetSeed(m_terrainSettings.seed);
43  terrainHeightFractal.SetFrequency(0.005 / 32);
44  terrainHeightFractal.SetLacunarity(2);
45  noise::module::ScaleBias terrainHeightFractalScaled;
46  terrainHeightFractalScaled.SetSourceModule(0, terrainHeightFractal);
47  //terrainHeightFractalScaled.SetScale(0.5);
48  terrainHeightFractalScaled.SetScale(m_terrainSettings.mountainAmplitude * 0.025);
49  terrainHeightFractalScaled.SetBias(0.5);
50 
51  noise::module::Perlin terrainHeightBlendPerlin;
52  terrainHeightBlendPerlin.SetSeed(m_terrainSettings.seed + 1);
53  terrainHeightBlendPerlin.SetFrequency(0.005 / 32);
54  noise::module::ScaleBias terrainHeightBlendScale;
55  terrainHeightBlendScale.SetSourceModule(0, terrainHeightBlendPerlin);
56  terrainHeightBlendScale.SetScale(2.0);
57  terrainHeightBlendScale.SetBias(-0.1 * m_terrainSettings.mountainAmplitude);
58  noise::module::Clamp terrainHeightBlendControl;
59  terrainHeightBlendControl.SetSourceModule(0, terrainHeightBlendScale);
60  terrainHeightBlendControl.SetBounds(0, 1);
61 
62  noise::module::Blend terrainHeightBlend;
63  terrainHeightBlend.SetSourceModule(0, terrainHeightPerlinScaled);
64  terrainHeightBlend.SetSourceModule(1, terrainHeightFractalScaled);
65  terrainHeightBlend.SetControlModule(terrainHeightBlendControl);
66 
67  noise::module::ScaleBias terrainHeightScale;
68  terrainHeightScale.SetSourceModule(0, terrainHeightBlend);
69  terrainHeightScale.SetScale(20.0);
70  terrainHeightScale.SetBias(4.0);
71 
72  noise::module::Clamp terrainHeight;
73  terrainHeight.SetSourceModule(0, terrainHeightScale);
74  terrainHeight.SetBounds(0, 255);
75 
76  // Foliage
77  noise::module::Perlin foliageDensityPerlin;
78  foliageDensityPerlin.SetSeed(m_terrainSettings.seed + 1234);
79  foliageDensityPerlin.SetFrequency(0.05 / 32);
80 
81  // Arbitrary Noise
82  noise::module::Perlin highFrequencyNoise;
83  highFrequencyNoise.SetSeed(m_terrainSettings.seed + 42);
84  highFrequencyNoise.SetFrequency(1);
85 
86  const int mapSize = m_terrainSettings.mapSize;
87  const size_t vectorSize = static_cast<size_t>(mapSize * mapSize);
88  mapNodes.reserve(vectorSize);
89 
90  // River random source
91  std:: minstd_rand riverRand;
92  riverRand.seed(m_terrainSettings.seed);
93 
94  // For now, the biome string is read from settings.json for debugging
95  std::string currentBiome = Settings::instance().biome;
96 
97  // nodes need to be created at the correct vector "coordinates", or else the Z-Order will be broken
98  for (int x = 0; x < mapSize; x++)
99  {
100  for (int y = 0; y < mapSize; y++)
101  {
102  const int z = 0; // it's not possible to calculate the correct z-index, so set it later in a for loop
103  double rawHeight = terrainHeight.GetValue(x * 32, y * 32, 0.5);
104  int height = static_cast<int>(rawHeight);
105 
106  if (height < m_terrainSettings.seaLevel)
107  {
108  height = m_terrainSettings.seaLevel;
109  mapNodes.emplace_back(MapNode{Point{x, y, z, height, rawHeight}, m_biomeInformation[currentBiome].water[0]});
110  }
111  else
112  {
113  const double foliageDensity = foliageDensityPerlin.GetValue(x * 32, y * 32, height / 32.0);
114  bool placed = false;
115 
116  if (foliageDensity > 0.0 && height > m_terrainSettings.seaLevel)
117  {
118  int tileIndex = static_cast<int>(std::abs(round(highFrequencyNoise.GetValue(x * 32, y * 32, height / 32.0) * 200.0)));
119 
120  if (foliageDensity < 0.1)
121  {
122  if (tileIndex < 20)
123  {
124  tileIndex = tileIndex % static_cast<int>(m_biomeInformation[currentBiome].treesLight.size());
125  mapNodes.emplace_back(MapNode{Point{x, y, z, height, rawHeight}, m_biomeInformation[currentBiome].terrain[0],
126  m_biomeInformation[currentBiome].treesLight[tileIndex]});
127  placed = true;
128  }
129  }
130  else if (foliageDensity < 0.25)
131  {
132  if (tileIndex < 50)
133  {
134  tileIndex = tileIndex % static_cast<int>(m_biomeInformation[currentBiome].treesMedium.size());
135  mapNodes.emplace_back(MapNode{Point{x, y, z, height, rawHeight}, m_biomeInformation[currentBiome].terrain[0],
136  m_biomeInformation[currentBiome].treesMedium[tileIndex]});
137  placed = true;
138  }
139  }
140  else if (foliageDensity < 1.0 && tileIndex < 95)
141  {
142  tileIndex = tileIndex % static_cast<int>(m_biomeInformation[currentBiome].treesDense.size());
143 
144  mapNodes.emplace_back(MapNode{Point{x, y, z, height, rawHeight}, m_biomeInformation[currentBiome].terrain[0],
145  m_biomeInformation[currentBiome].treesDense[tileIndex]});
146  placed = true;
147  }
148  }
149  if (placed == false)
150  {
151  mapNodes.emplace_back(MapNode{Point{x, y, z, height, rawHeight}, m_biomeInformation[currentBiome].terrain[0]});
152  }
153 
154  if (height > m_terrainSettings.seaLevel)
155  {
156  const int riverSourcePossibility = riverRand() % m_terrainSettings.maxHeight;
157  if ((riverSourcePossibility >= (m_terrainSettings.maxHeight + m_terrainSettings.seaLevel - height)) && (riverRand() % 50 == 0))
158  {
159  m_riverSourceNodes.emplace_back(Point{x, y, z, height, rawHeight});
160  }
161  }
162  }
163  }
164  }
165 
166  int z = 0;
167  // set the z-Index for the mapNodes. It is not used, but it's better to have the correct z-index set
168  for (int y = mapSize - 1; y >= 0; y--)
169  {
170  for (int x = 0; x < mapSize; x++)
171  {
172  z++;
173  mapNodes[x * mapSize + y].setZIndex(z);
174  mapNodesInDrawingOrder.push_back(&mapNodes[x * mapSize + y]);
175  }
176  }
177 }
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ loadTerrainDataFromJSON()

void TerrainGenerator::loadTerrainDataFromJSON ( )

Definition at line 250 of file TerrainGenerator.cxx.

251 {
253  json biomeDataJsonObject = json::parse(jsonFileContent, nullptr, false);
254 
255  // check if json file can be parsed
256  if (biomeDataJsonObject.is_discarded())
257  throw ConfigurationError(TRACE_INFO "Error parsing JSON File " + string{TERRAINGEN_DATA_FILE_NAME});
258 
259  // parse biome objects
260  for (const auto &it : biomeDataJsonObject.items())
261  {
262  m_biomeInformation[it.key()] = it.value();
263  }
264 }
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

Member Data Documentation

◆ m_biomeInformation

std::map<std::string, BiomeData> TerrainGenerator::m_biomeInformation
private

key: biome

Definition at line 61 of file TerrainGenerator.hxx.

◆ m_riverSourceNodes

std::vector<Point> TerrainGenerator::m_riverSourceNodes
private

Definition at line 62 of file TerrainGenerator.hxx.

◆ m_terrainSettings

TerrainSettings TerrainGenerator::m_terrainSettings
private

Definition at line 59 of file TerrainGenerator.hxx.


The documentation for this class was generated from the following files:
TRACE_INFO
#define TRACE_INFO
Definition: Exception.hxx:12
ConfigurationError
A configuration error.
Definition: Exception.hxx:36
TerrainSettings::mountainAmplitude
int mountainAmplitude
Both amplifies the mountain noise source, as well as biasing the mountain/plains blend....
Definition: TerrainGenerator.hxx:37
TerrainSettings::seed
int seed
If the seed is 0, a random seed will be generated by TerrainGenerator::generateTerrain()
Definition: TerrainGenerator.hxx:33
Point::toIndex
int toIndex() const
calculates the index (stride) that can be used to access in Map to access mapNodes vector.
Definition: Point.hxx:80
LOG
Definition: LOG.hxx:32
LOG_INFO
@ LOG_INFO
Definition: LOG.hxx:25
TerrainGenerator::m_riverSourceNodes
std::vector< Point > m_riverSourceNodes
Definition: TerrainGenerator.hxx:62
TerrainGenerator::m_biomeInformation
std::map< std::string, BiomeData > m_biomeInformation
key: biome
Definition: TerrainGenerator.hxx:61
readFileAsString
std::string readFileAsString(const std::string &fileName, bool binaryMode)
Read contents from a file as string.
Definition: Filesystem.cxx:12
MapNode
Class that holds map nodes.
Definition: MapNode.hxx:30
PointFunctions::getNeighbors
static std::vector< Point > getNeighbors(const Point &isoCoordinates, const bool includeCentralNode, int distance=1)
Get all neighboring coordinates from provided map node isocoordinate.
Definition: PointFunctions.cxx:175
TerrainGenerator::m_terrainSettings
TerrainSettings m_terrainSettings
Definition: TerrainGenerator.hxx:59
TerrainSettings::maxHeight
int maxHeight
Definition: TerrainGenerator.hxx:35
TerrainSettings::mapSize
int mapSize
Definition: TerrainGenerator.hxx:32
TerrainGenerator::loadTerrainDataFromJSON
void loadTerrainDataFromJSON()
Definition: TerrainGenerator.cxx:250
TERRAINGEN_DATA_FILE_NAME
constexpr const char TERRAINGEN_DATA_FILE_NAME[]
Definition: Constants.hxx:25
TerrainSettings::seaLevel
int seaLevel
All tiles with elevation below this will be set as water.
Definition: TerrainGenerator.hxx:34
Point
Definition: Point.hxx:7
Singleton< Settings >::instance
static Settings & instance(void)
Get an instance of the singleton.
Definition: Singleton.hxx:15
json
nlohmann::json json
Definition: Settings.hxx:12
string
std::string string
Definition: AudioConfig.hxx:14
SettingsData::biome
std::string biome
this is used for biomedata
Definition: Settings.hxx:118
MapNode::setTileID
void setTileID(const std::string &tileType, const Point &origPoint)
Definition: MapNode.cxx:50
Point::rawHeight
double rawHeight
The raw height.
Definition: Point.hxx:29