void cBioGenMultiStepMap::BuildTemperatureHumidityMaps(int a_ChunkX, int a_ChunkZ, IntMap & a_TemperatureMap, IntMap & a_HumidityMap) { // Linear interpolation over 8x8 blocks; use double for better precision: DblMap TemperatureMap; DblMap HumidityMap; for (int z = 0; z < 17; z += 8) { float NoiseCoordZ = (float)(a_ChunkZ * cChunkDef::Width + z) / m_LandBiomesSize; for (int x = 0; x < 17; x += 8) { float NoiseCoordX = (float)(a_ChunkX * cChunkDef::Width + x) / m_LandBiomesSize; double NoiseT = m_Noise1.CubicNoise2D( NoiseCoordX, NoiseCoordZ); NoiseT += 0.5 * m_Noise2.CubicNoise2D(2 * NoiseCoordX, 2 * NoiseCoordZ); NoiseT += 0.1 * m_Noise3.CubicNoise2D(8 * NoiseCoordX, 8 * NoiseCoordZ); TemperatureMap[x + 17 * z] = NoiseT; double NoiseH = m_Noise4.CubicNoise2D( NoiseCoordX, NoiseCoordZ); NoiseH += 0.5 * m_Noise5.CubicNoise2D(2 * NoiseCoordX, 2 * NoiseCoordZ); NoiseH += 0.1 * m_Noise6.CubicNoise2D(8 * NoiseCoordX, 8 * NoiseCoordZ); HumidityMap[x + 17 * z] = NoiseH; } // for x } // for z LinearUpscale2DArrayInPlace(TemperatureMap, 17, 17, 8, 8); LinearUpscale2DArrayInPlace(HumidityMap, 17, 17, 8, 8); // Re-map into integral values in [0 .. 255] range: for (size_t idx = 0; idx < ARRAYCOUNT(a_TemperatureMap); idx++) { a_TemperatureMap[idx] = std::max(0, std::min(255, (int)(128 + TemperatureMap[idx] * 128))); a_HumidityMap[idx] = std::max(0, std::min(255, (int)(128 + HumidityMap[idx] * 128))); } }
void cBioGenDistortedVoronoi::GenBiomes(int a_ChunkX, int a_ChunkZ, cChunkDef::BiomeMap & a_BiomeMap) { int BaseZ = cChunkDef::Width * a_ChunkZ; int BaseX = cChunkDef::Width * a_ChunkX; // Distortions for linear interpolation: int DistortX[cChunkDef::Width + 1][cChunkDef::Width + 1]; int DistortZ[cChunkDef::Width + 1][cChunkDef::Width + 1]; for (int x = 0; x <= 4; x++) for (int z = 0; z <= 4; z++) { Distort(BaseX + x * 4, BaseZ + z * 4, DistortX[4 * x][4 * z], DistortZ[4 * x][4 * z]); } LinearUpscale2DArrayInPlace(&DistortX[0][0], cChunkDef::Width + 1, cChunkDef::Width + 1, 4, 4); LinearUpscale2DArrayInPlace(&DistortZ[0][0], cChunkDef::Width + 1, cChunkDef::Width + 1, 4, 4); for (int z = 0; z < cChunkDef::Width; z++) { for (int x = 0; x < cChunkDef::Width; x++) { int VoronoiCellValue = m_Voronoi.GetValueAt(DistortX[x][z], DistortZ[x][z]) / 8; cChunkDef::SetBiome(a_BiomeMap, x, z, m_Biomes[VoronoiCellValue % m_BiomesCount]); } // for x } // for z }
void cHeiGenBiomal::GenHeightMap(int a_ChunkX, int a_ChunkZ, cChunkDef::HeightMap & a_HeightMap) { // Generate a 3x3 chunk area of biomes around this chunk: BiomeNeighbors Biomes; for (int z = -1; z <= 1; z++) { for (int x = -1; x <= 1; x++) { m_BiomeGen.GenBiomes(a_ChunkX + x, a_ChunkZ + z, Biomes[x + 1][z + 1]); } // for x } // for z /* _X 2013_04_22: There's no point in precalculating the entire perlin noise arrays, too many values are calculated uselessly, resulting in speed DEcrease. */ //* // Linearly interpolate 4x4 blocks of heightmap: // Must be done on a floating point datatype, else the results are ugly! const int STEPZ = 4; // Must be a divisor of 16 const int STEPX = 4; // Must be a divisor of 16 NOISE_DATATYPE Height[17 * 17]; for (int z = 0; z < 17; z += STEPZ) { for (int x = 0; x < 17; x += STEPX) { Height[x + 17 * z] = GetHeightAt(x, z, a_ChunkX, a_ChunkZ, Biomes); } } LinearUpscale2DArrayInPlace(Height, 17, 17, STEPX, STEPZ); // Copy into the heightmap for (int z = 0; z < cChunkDef::Width; z++) { for (int x = 0; x < cChunkDef::Width; x++) { cChunkDef::SetHeight(a_HeightMap, x, z, (int)Height[x + 17 * z]); } } //*/ /* // For each height, go through neighboring biomes and add up their idea of height: for (int z = 0; z < cChunkDef::Width; z++) { for (int x = 0; x < cChunkDef::Width; x++) { cChunkDef::SetHeight(a_HeightMap, x, z, GetHeightAt(x, z, a_ChunkX, a_ChunkZ, Biomes)); } // for x } //*/ }
void cBioGenTwoLevel::GenBiomes(int a_ChunkX, int a_ChunkZ, cChunkDef::BiomeMap & a_BiomeMap) { int BaseZ = cChunkDef::Width * a_ChunkZ; int BaseX = cChunkDef::Width * a_ChunkX; // Distortions for linear interpolation: int DistortX[cChunkDef::Width + 1][cChunkDef::Width + 1]; int DistortZ[cChunkDef::Width + 1][cChunkDef::Width + 1]; for (int x = 0; x <= 4; x++) for (int z = 0; z <= 4; z++) { int BlockX = BaseX + x * 4; int BlockZ = BaseZ + z * 4; float BlockXF = (float)(16 * BlockX) / 128; float BlockZF = (float)(16 * BlockZ) / 128; double NoiseX = m_Noise.CubicNoise3D(BlockXF / 16, BlockZF / 16, 1000); NoiseX += 0.5 * m_Noise.CubicNoise3D(BlockXF / 8, BlockZF / 8, 2000); NoiseX += 0.08 * m_Noise.CubicNoise3D(BlockXF, BlockZF, 3000); double NoiseZ = m_Noise.CubicNoise3D(BlockXF / 16, BlockZF / 16, 4000); NoiseZ += 0.5 * m_Noise.CubicNoise3D(BlockXF / 8, BlockZF / 8, 5000); NoiseZ += 0.08 * m_Noise.CubicNoise3D(BlockXF, BlockZF, 6000); DistortX[4 * x][4 * z] = BlockX + (int)(64 * NoiseX); DistortZ[4 * x][4 * z] = BlockZ + (int)(64 * NoiseZ); } LinearUpscale2DArrayInPlace(&DistortX[0][0], cChunkDef::Width + 1, cChunkDef::Width + 1, 4, 4); LinearUpscale2DArrayInPlace(&DistortZ[0][0], cChunkDef::Width + 1, cChunkDef::Width + 1, 4, 4); // Apply distortion to each block coord, then query the voronoi maps for biome group and biome index and choose biome based on that: for (int z = 0; z < cChunkDef::Width; z++) { for (int x = 0; x < cChunkDef::Width; x++) { int BiomeGroup = m_VoronoiLarge.GetValueAt(DistortX[x][z], DistortZ[x][z]) / 7; int MinDist1, MinDist2; int BiomeIdx = m_VoronoiSmall.GetValueAt(DistortX[x][z], DistortZ[x][z], MinDist1, MinDist2) / 11; cChunkDef::SetBiome(a_BiomeMap, x, z, SelectBiome(BiomeGroup, BiomeIdx, (MinDist1 < MinDist2 / 4) ? 0 : 1)); } } }
void cNoise3DComposable::GenerateNoiseArrayIfNeeded(int a_ChunkX, int a_ChunkZ) { if ((a_ChunkX == m_LastChunkX) && (a_ChunkZ == m_LastChunkZ)) { // The noise for this chunk is already generated in m_Noise return; } m_LastChunkX = a_ChunkX; m_LastChunkZ = a_ChunkZ; // Upscaling parameters: const int UPSCALE_X = 8; const int UPSCALE_Y = 4; const int UPSCALE_Z = 8; // Precalculate a "height" array: NOISE_DATATYPE Height[17 * 17]; // x + 17 * z for (int z = 0; z < 17; z += UPSCALE_Z) { NOISE_DATATYPE NoiseZ = ((NOISE_DATATYPE)(a_ChunkZ * cChunkDef::Width + z)) / m_FrequencyZ; for (int x = 0; x < 17; x += UPSCALE_X) { NOISE_DATATYPE NoiseX = ((NOISE_DATATYPE)(a_ChunkX * cChunkDef::Width + x)) / m_FrequencyX; NOISE_DATATYPE val = abs(m_Noise1.CubicNoise2D(NoiseX / 5, NoiseZ / 5)) * m_HeightAmplification + 1; Height[x + 17 * z] = val * val * val; } } for (int y = 0; y < 257; y += UPSCALE_Y) { NOISE_DATATYPE NoiseY = ((NOISE_DATATYPE)y) / m_FrequencyY; NOISE_DATATYPE AddHeight = (y - m_MidPoint) / 20; AddHeight *= AddHeight * AddHeight; NOISE_DATATYPE * CurFloor = &(m_NoiseArray[y * 17 * 17]); for (int z = 0; z < 17; z += UPSCALE_Z) { NOISE_DATATYPE NoiseZ = ((NOISE_DATATYPE)(a_ChunkZ * cChunkDef::Width + z)) / m_FrequencyZ; for (int x = 0; x < 17; x += UPSCALE_X) { NOISE_DATATYPE NoiseX = ((NOISE_DATATYPE)(a_ChunkX * cChunkDef::Width + x)) / m_FrequencyX; CurFloor[x + 17 * z] = m_Noise1.CubicNoise3D(NoiseX, NoiseY, NoiseZ) * (NOISE_DATATYPE)0.5 + m_Noise2.CubicNoise3D(NoiseX / 2, NoiseY / 2, NoiseZ / 2) + m_Noise3.CubicNoise3D(NoiseX / 4, NoiseY / 4, NoiseZ / 4) * 2 + AddHeight / Height[x + 17 * z]; } } // Linear-interpolate this XZ floor: LinearUpscale2DArrayInPlace(CurFloor, 17, 17, UPSCALE_X, UPSCALE_Z); } // Finish the 3D linear interpolation by interpolating between each XZ-floors on the Y axis for (int y = 1; y < cChunkDef::Height; y++) { if ((y % UPSCALE_Y) == 0) { // This is the interpolation source floor, already calculated continue; } int LoFloorY = (y / UPSCALE_Y) * UPSCALE_Y; int HiFloorY = LoFloorY + UPSCALE_Y; NOISE_DATATYPE * LoFloor = &(m_NoiseArray[LoFloorY * 17 * 17]); NOISE_DATATYPE * HiFloor = &(m_NoiseArray[HiFloorY * 17 * 17]); NOISE_DATATYPE * CurFloor = &(m_NoiseArray[y * 17 * 17]); NOISE_DATATYPE Ratio = ((NOISE_DATATYPE)(y % UPSCALE_Y)) / UPSCALE_Y; int idx = 0; for (int z = 0; z < cChunkDef::Width; z++) { for (int x = 0; x < cChunkDef::Width; x++) { CurFloor[idx] = LoFloor[idx] + (HiFloor[idx] - LoFloor[idx]) * Ratio; idx += 1; } idx += 1; // Skipping one X column } } // The noise array is now fully interpolated /* // DEBUG: Output two images of the array, sliced by XY and XZ: cFile f1; if (f1.Open(Printf("Chunk_%d_%d_XY.raw", a_ChunkX, a_ChunkZ), cFile::fmWrite)) { for (int z = 0; z < cChunkDef::Width; z++) { for (int y = 0; y < cChunkDef::Height; y++) { int idx = y * 17 * 17 + z * 17; unsigned char buf[16]; for (int x = 0; x < cChunkDef::Width; x++) { buf[x] = (unsigned char)(std::min(256, std::max(0, (int)(128 + 128 * m_Noise[idx++])))); } f1.Write(buf, 16); } // for y } // for z } // if (XY file open) cFile f2; if (f2.Open(Printf("Chunk_%d_%d_XZ.raw", a_ChunkX, a_ChunkZ), cFile::fmWrite)) { for (int y = 0; y < cChunkDef::Height; y++) { for (int z = 0; z < cChunkDef::Width; z++) { int idx = y * 17 * 17 + z * 17; unsigned char buf[16]; for (int x = 0; x < cChunkDef::Width; x++) { buf[x] = (unsigned char)(std::min(256, std::max(0, (int)(128 + 128 * m_Noise[idx++])))); } f2.Write(buf, 16); } // for z } // for y } // if (XZ file open) */ }
void cBioGenMultiStepMap::DecideOceanLandMushroom(int a_ChunkX, int a_ChunkZ, cChunkDef::BiomeMap & a_BiomeMap) { // Distorted Voronoi over 3 biomes, with mushroom having only a special occurence. // Prepare a distortion lookup table, by distorting a 5x5 area and using that as 1:4 zoom (linear interpolate): int BaseZ = cChunkDef::Width * a_ChunkZ; int BaseX = cChunkDef::Width * a_ChunkX; int DistortX[cChunkDef::Width + 1][cChunkDef::Width + 1]; int DistortZ[cChunkDef::Width + 1][cChunkDef::Width + 1]; int DistortSize = m_OceanCellSize / 2; for (int x = 0; x <= 4; x++) for (int z = 0; z <= 4; z++) { Distort(BaseX + x * 4, BaseZ + z * 4, DistortX[4 * x][4 * z], DistortZ[4 * x][4 * z], DistortSize); } LinearUpscale2DArrayInPlace(&DistortX[0][0], cChunkDef::Width + 1, cChunkDef::Width + 1, 4, 4); LinearUpscale2DArrayInPlace(&DistortZ[0][0], cChunkDef::Width + 1, cChunkDef::Width + 1, 4, 4); // Prepare a 9x9 area of neighboring cell seeds // (assuming that 7x7 cell area is larger than a chunk being generated) const int NEIGHBORHOOD_SIZE = 4; // How many seeds in each direction to check int CellX = BaseX / m_OceanCellSize; int CellZ = BaseZ / m_OceanCellSize; int SeedX[2 * NEIGHBORHOOD_SIZE + 1][2 * NEIGHBORHOOD_SIZE + 1]; int SeedZ[2 * NEIGHBORHOOD_SIZE + 1][2 * NEIGHBORHOOD_SIZE + 1]; EMCSBiome SeedV[2 * NEIGHBORHOOD_SIZE + 1][2 * NEIGHBORHOOD_SIZE + 1]; for (int xc = 0; xc < 2 * NEIGHBORHOOD_SIZE + 1; xc++) { int RealCellX = xc + CellX - NEIGHBORHOOD_SIZE; int CellBlockX = RealCellX * m_OceanCellSize; for (int zc = 0; zc < 2 * NEIGHBORHOOD_SIZE + 1; zc++) { int RealCellZ = zc + CellZ - NEIGHBORHOOD_SIZE; int CellBlockZ = RealCellZ * m_OceanCellSize; int OffsetX = (m_Noise2.IntNoise3DInt(RealCellX, 16 * RealCellX + 32 * RealCellZ, RealCellZ) / 8) % m_OceanCellSize; int OffsetZ = (m_Noise4.IntNoise3DInt(RealCellX, 32 * RealCellX - 16 * RealCellZ, RealCellZ) / 8) % m_OceanCellSize; SeedX[xc][zc] = CellBlockX + OffsetX; SeedZ[xc][zc] = CellBlockZ + OffsetZ; SeedV[xc][zc] = (((m_Noise6.IntNoise3DInt(RealCellX, RealCellX - RealCellZ + 1000, RealCellZ) / 11) % 256) > 90) ? biOcean : (biInvalidBiome); } // for z } // for x for (int xc = 1; xc < 2 * NEIGHBORHOOD_SIZE; xc++) for (int zc = 1; zc < 2 * NEIGHBORHOOD_SIZE; zc++) { if ( (SeedV[xc ][zc] == biOcean) && (SeedV[xc - 1][zc] == biOcean) && (SeedV[xc + 1][zc] == biOcean) && (SeedV[xc ][zc - 1] == biOcean) && (SeedV[xc ][zc + 1] == biOcean) && (SeedV[xc - 1][zc - 1] == biOcean) && (SeedV[xc + 1][zc - 1] == biOcean) && (SeedV[xc - 1][zc + 1] == biOcean) && (SeedV[xc + 1][zc + 1] == biOcean) ) { SeedV[xc][zc] = biMushroomIsland; } } // For each column find the nearest distorted cell and use its value as the biome: int MushroomOceanThreshold = m_OceanCellSize * m_OceanCellSize * m_MushroomIslandSize / 1024; int MushroomShoreThreshold = m_OceanCellSize * m_OceanCellSize * m_MushroomIslandSize / 2048; for (int z = 0; z < cChunkDef::Width; z++) { for (int x = 0; x < cChunkDef::Width; x++) { int AbsoluteZ = DistortZ[x][z]; int AbsoluteX = DistortX[x][z]; int MinDist = m_OceanCellSize * m_OceanCellSize * 16; // There has to be a cell closer than this EMCSBiome Biome = biPlains; // Find the nearest cell seed: for (int xs = 1; xs < 2 * NEIGHBORHOOD_SIZE; xs++) for (int zs = 1; zs < 2 * NEIGHBORHOOD_SIZE; zs++) { int Dist = (SeedX[xs][zs] - AbsoluteX) * (SeedX[xs][zs] - AbsoluteX) + (SeedZ[xs][zs] - AbsoluteZ) * (SeedZ[xs][zs] - AbsoluteZ); if (Dist >= MinDist) { continue; } MinDist = Dist; Biome = SeedV[xs][zs]; // Shrink mushroom biome and add a shore: if (Biome == biMushroomIsland) { if (Dist > MushroomOceanThreshold) { Biome = biOcean; } else if (Dist > MushroomShoreThreshold) { Biome = biMushroomShore; } } } // for zs, xs cChunkDef::SetBiome(a_BiomeMap, x, z, Biome); } // for x } // for z }