Added Comments
Added ability to hold shift and skip the terrain generation when loading Added ability for the perlin terrain to save a raw image of the terrain to use as a cache
This commit is contained in:
@ -2,17 +2,29 @@
|
||||
|
||||
PerlinTerrainNode::PerlinTerrainNode(wstring name, wstring seed, float chunkSize, int widthX, int widthZ, float waterHeight, int cellSizeX, int cellSizeZ) : TerrainNode(name, seed, waterHeight, widthX, widthZ, cellSizeX, cellSizeZ)
|
||||
{
|
||||
// Set the chink size
|
||||
_chunkSize = chunkSize;
|
||||
|
||||
GeneratePerlinValues();
|
||||
if (!GeneratePerlinHeights())
|
||||
// Check if a cache image exists and load it if so
|
||||
if (!ReadCache())
|
||||
{
|
||||
_initError = true;
|
||||
// No Cache image existed so generate the perlin noise map
|
||||
GeneratePerlinValues();
|
||||
if (!GeneratePerlinHeights())
|
||||
{
|
||||
_initError = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// The generation was successful, save it to the cache
|
||||
CacheOutput();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PerlinTerrainNode::GeneratePerlinValues()
|
||||
{
|
||||
// Setup the RNG
|
||||
std::seed_seq seedGenerator(_seedString.begin(), _seedString.end());
|
||||
std::mt19937 generator;
|
||||
generator.seed(seedGenerator);
|
||||
@ -20,9 +32,12 @@ void PerlinTerrainNode::GeneratePerlinValues()
|
||||
char bufferChar;
|
||||
int newPosition;
|
||||
|
||||
// Clear the permutation array so we can reinsert a new copy
|
||||
_p.clear();
|
||||
copy(_staticP.begin(), _staticP.end(), back_inserter(_p));
|
||||
|
||||
// Loop through and alternate the numbers so they are in a random position, this will not create any new numbers so we should always have what we started with
|
||||
// just in a different order
|
||||
for (int i = 0; i < 512; i++)
|
||||
{
|
||||
newPosition = dist(generator);
|
||||
@ -32,20 +47,83 @@ void PerlinTerrainNode::GeneratePerlinValues()
|
||||
}
|
||||
}
|
||||
|
||||
bool PerlinTerrainNode::ReadCache()
|
||||
{
|
||||
ifstream cachedImage;
|
||||
string stringSeed = string(_seedString.begin(), _seedString.end());
|
||||
string chunkSizeString = to_string(_chunkSize);
|
||||
replace(chunkSizeString.begin(), chunkSizeString.end(), '.', '_');
|
||||
cachedImage.open("TerrainCache\\cache_" + stringSeed + "_" + chunkSizeString + ".raw", std::ios_base::binary);
|
||||
|
||||
// Couldnt open the cache, either doesnt exist or some issue opening the file, a new one should be generated
|
||||
if (!cachedImage)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Load the files bytes into a vector we can foreach loop
|
||||
vector<char> fileBytes((istreambuf_iterator<char>(cachedImage)), (istreambuf_iterator<char>()));
|
||||
|
||||
for (BYTE currentByte : fileBytes)
|
||||
{
|
||||
// Change the number back into a float value, some precision is lost because of this but i cant notice it really
|
||||
float heightValue = currentByte / 255.0f;
|
||||
_heightValues.push_back(heightValue);
|
||||
}
|
||||
|
||||
cachedImage.close();
|
||||
return true;
|
||||
}
|
||||
|
||||
void PerlinTerrainNode::CacheOutput()
|
||||
{
|
||||
// Create a unique string name for the seed and cluster size given
|
||||
string stringSeed = string(_seedString.begin(), _seedString.end());
|
||||
string chunkSizeString = to_string(_chunkSize);
|
||||
replace(chunkSizeString.begin(), chunkSizeString.end(), '.', '_');
|
||||
ofstream output("TerrainCache\\cache_" + stringSeed + "_" + chunkSizeString + ".raw", std::ios_base::binary);
|
||||
|
||||
// Loop through the height values array
|
||||
int current = 0;
|
||||
for (float value : _heightValues)
|
||||
{
|
||||
// Force the value to be within 255, we lose some precision from this conversion but to generate an image it has to be this way
|
||||
BYTE currentByte = (int)(255 * value) & 0xff;
|
||||
|
||||
// Write the value to the file buffer
|
||||
output << currentByte;
|
||||
|
||||
// Constantly flush the buffer so that we dont have it waiting in memory for too long
|
||||
if (current >= 100)
|
||||
{
|
||||
output.flush();
|
||||
current = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
current++;
|
||||
}
|
||||
}
|
||||
|
||||
// Close the file
|
||||
output.close();
|
||||
}
|
||||
|
||||
// Method for filling the height values array for the terrain generation
|
||||
bool PerlinTerrainNode::GeneratePerlinHeights()
|
||||
{
|
||||
for (int z = 0; z < _gridRows; z++)
|
||||
for (int z = 0; z < (int)_gridRows; z++)
|
||||
{
|
||||
float mapZ = ((float)z / (float)_gridRows);
|
||||
|
||||
for (int x = 0; x < _gridCols; x++)
|
||||
for (int x = 0; x < (int)_gridCols; x++)
|
||||
{
|
||||
float mapX = ((float)x / (float)_gridCols);
|
||||
|
||||
//float currentHeightValue = GetPerlinValueAt(mapX, mapZ, 8, 0.85f) - 0.25f;
|
||||
float currentHeightValue = 0.0f;
|
||||
|
||||
// Octaves adds "noise" to the final outcome, 12 is really the max before it tanks the system for little effect
|
||||
int octaves = 12;
|
||||
float currentOctaveValue = 1.0f;
|
||||
float stepOff = 1.0f;
|
||||
@ -53,6 +131,7 @@ bool PerlinTerrainNode::GeneratePerlinHeights()
|
||||
// n covers the persistance, frequency and
|
||||
for (int n = 1; n <= octaves; n++)
|
||||
{
|
||||
// Generate a noise at the given position
|
||||
currentHeightValue += stepOff * GetNoiseValueAt(((float)x * currentOctaveValue) / ((float)_gridCols / _chunkSize), ((float)z * currentOctaveValue) / ((float)_gridRows / _chunkSize));
|
||||
currentOctaveValue *= 2;
|
||||
stepTotal += stepOff;
|
||||
@ -62,6 +141,7 @@ bool PerlinTerrainNode::GeneratePerlinHeights()
|
||||
|
||||
//currentHeightValue = currentHeightValue / stepTotal; // *(currentHeightValue * 2.0f);
|
||||
//currentHeightValue = currentHeightValue - floor(currentHeightValue);
|
||||
// Normalise the result to a number between 0 and 1, since most like to generate numbers between -1 and 1, we just have to add 1 and half the value
|
||||
_heightValues.push_back((currentHeightValue + 1.0f) * 0.5f);
|
||||
}
|
||||
}
|
||||
@ -76,6 +156,7 @@ float PerlinTerrainNode::Fade(float t)
|
||||
|
||||
float PerlinTerrainNode::Grad(int hash, float x, float y)
|
||||
{
|
||||
// To be honest this is something i dont really understand, it shifts bits around to see which direction we need to multiply in
|
||||
int h = hash & 7;
|
||||
float u = y;
|
||||
float v = x;
|
||||
|
Reference in New Issue
Block a user