#include "PerlinTerrainNode.h" 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) { _chunkSize = chunkSize; GeneratePerlinValues(); if (!GeneratePerlinHeights()) { _initError = true; } } void PerlinTerrainNode::GeneratePerlinValues() { std::seed_seq seedGenerator(_seedString.begin(), _seedString.end()); std::mt19937 generator; generator.seed(seedGenerator); std::uniform_int_distribution<> dist(0, 511); char bufferChar; int newPosition; _p.clear(); copy(_staticP.begin(), _staticP.end(), back_inserter(_p)); for (int i = 0; i < 512; i++) { newPosition = dist(generator); bufferChar = _p[i]; _p[i] = _p[newPosition]; _p[newPosition] = bufferChar; } } // Method for filling the height values array for the terrain generation bool PerlinTerrainNode::GeneratePerlinHeights() { for (int z = 0; z < _gridRows; z++) { float mapZ = ((float)z / (float)_gridRows); for (int x = 0; x < _gridCols; x++) { float mapX = ((float)x / (float)_gridCols); //float currentHeightValue = GetPerlinValueAt(mapX, mapZ, 8, 0.85f) - 0.25f; float currentHeightValue = 0.0f; int octaves = 12; float currentOctaveValue = 1.0f; float stepOff = 1.0f; float stepTotal = 0.0f; // n covers the persistance, frequency and for (int n = 1; n <= octaves; n++) { currentHeightValue += stepOff * GetNoiseValueAt(((float)x * currentOctaveValue) / ((float)_gridCols / _chunkSize), ((float)z * currentOctaveValue) / ((float)_gridRows / _chunkSize)); currentOctaveValue *= 2; stepTotal += stepOff; stepOff *= 0.5f; } //currentHeightValue = currentHeightValue / stepTotal; // *(currentHeightValue * 2.0f); //currentHeightValue = currentHeightValue - floor(currentHeightValue); _heightValues.push_back((currentHeightValue + 1.0f) * 0.5f); } } return true; } float PerlinTerrainNode::Fade(float t) { return t * t * t * (t * (t * 6 - 15) + 10); } float PerlinTerrainNode::Grad(int hash, float x, float y) { int h = hash & 7; float u = y; float v = x; if (h < 4) { u = x; v = y; } float outA = u; if ((h & 1)) { outA = -u; } float outB = 2.0f * v; if ((h & 2)) { outB = -2.0f * v; } return outA + outB; } // Method to get the perlin noise value at x/y float PerlinTerrainNode::GetNoiseValueAt(float x, float y) { int ix0 = (int)floor(x); int iy0 = (int)floor(y); float fx0 = x - (float)ix0; float fy0 = y - (float)iy0; float fx1 = fx0 - 1.0f; float fy1 = fy0 - 1.0f; int ix1 = (ix0 + 1) & 0xff; int iy1 = (iy0 + 1) & 0xff; ix0 = ix0 & 0xff; iy0 = iy0 & 0xff; float t = Fade(fy0); float s = Fade(fx0); float nx0 = Grad(_p[ix0 + _p[iy0]], fx0, fy0); float nx1 = Grad(_p[ix0 + _p[iy1]], fx0, fy1); float n0 = SharedMethods::Lerp(nx0, nx1, t); nx0 = Grad(_p[ix1 + _p[iy0]], fx1, fy0); nx1 = Grad(_p[ix1 + _p[iy1]], fx1, fy1); float n1 = SharedMethods::Lerp(nx0, nx1, t); return 0.507f * SharedMethods::Lerp(n0, n1, s); }