From bca93b17dabe166d9e52945987acb4d079d71e0f Mon Sep 17 00:00:00 2001 From: NiLSPACE Date: Sun, 11 Oct 2020 17:44:57 +0200 Subject: Simple end gen (#4973) * Fixed current end generator * Implemented new simplified end generation which includes a void between the main island and other islands * Fixed basic style * Hopefully fixed clang errors. --- src/Generating/EndGen.cpp | 148 ++++++++++++++++++++++++---------------------- src/Generating/EndGen.h | 27 ++++----- 2 files changed, 89 insertions(+), 86 deletions(-) diff --git a/src/Generating/EndGen.cpp b/src/Generating/EndGen.cpp index 4e5e1a809..72dc180e7 100644 --- a/src/Generating/EndGen.cpp +++ b/src/Generating/EndGen.cpp @@ -34,28 +34,41 @@ enum cEndGen::cEndGen(int a_Seed) : m_Seed(a_Seed), - m_IslandSizeX(256), - m_IslandSizeY(96), - m_IslandSizeZ(256), + m_Perlin(a_Seed), + m_VoidOffsetNoise(a_Seed + 1000), + m_AirThresholdMainIsland(0.0f), + m_AirThresholdOtherIslands(0.5f), + m_MainIslandSize(450), + m_BaseHeight(64), + m_TerrainTopMultiplier(10), + m_TerrainBottomMultiplier(40), + m_VoidOffsetNoiseMultiplier(50), m_FrequencyX(80), m_FrequencyY(80), - m_FrequencyZ(80), - m_LastChunkCoords(0x7fffffff, 0x7fffffff) // Use dummy coords that won't ever be used by real chunks + m_FrequencyZ(80) { m_Perlin.AddOctave(1, 1); m_Perlin.AddOctave(2, 0.5); m_Perlin.AddOctave(4, 0.25); + + m_VoidOffsetNoise.AddOctave(1, 1); + m_VoidOffsetNoise.AddOctave(2, 0.5); + m_VoidOffsetNoise.AddOctave(4, 0.25); } -void cEndGen::InitializeCompoGen(cIniFile & a_IniFile) +void cEndGen::InitializeShapeGen(cIniFile & a_IniFile) { - m_IslandSizeX = a_IniFile.GetValueSetI("Generator", "EndGenIslandSizeX", m_IslandSizeX); - m_IslandSizeY = a_IniFile.GetValueSetI("Generator", "EndGenIslandSizeY", m_IslandSizeY); - m_IslandSizeZ = a_IniFile.GetValueSetI("Generator", "EndGenIslandSizeZ", m_IslandSizeZ); + m_AirThresholdMainIsland = static_cast(a_IniFile.GetValueSetF("Generator", "EndGenAirThresholdMainIsland", m_AirThresholdMainIsland)); + m_AirThresholdOtherIslands = static_cast(a_IniFile.GetValueSetF("Generator", "EndGenAirThresholdOtherIslands", m_AirThresholdOtherIslands)); + m_MainIslandSize = a_IniFile.GetValueSetI("Generator", "EndGenMainIslandSize", m_MainIslandSize); + m_BaseHeight = a_IniFile.GetValueSetI("Generator", "EndGenBaseHeight", m_BaseHeight); + m_TerrainTopMultiplier = a_IniFile.GetValueSetI("Generator", "EndGenTerrainTopMultipler", m_TerrainTopMultiplier); + m_TerrainBottomMultiplier = a_IniFile.GetValueSetI("Generator", "EndGenTerrainBottomMultiplier", m_TerrainBottomMultiplier); + m_VoidOffsetNoiseMultiplier = a_IniFile.GetValueSetI("Generator", "EndGenVoidOffsetNoiseMultiplier", m_VoidOffsetNoiseMultiplier); m_FrequencyX = static_cast(a_IniFile.GetValueSetF("Generator", "EndGenFrequencyX", m_FrequencyX)); m_FrequencyY = static_cast(a_IniFile.GetValueSetF("Generator", "EndGenFrequencyY", m_FrequencyY)); @@ -66,83 +79,78 @@ void cEndGen::InitializeCompoGen(cIniFile & a_IniFile) -void cEndGen::PrepareState(cChunkCoords a_ChunkCoords) +void cEndGen::GenShape(cChunkCoords a_ChunkCoords, cChunkDesc::Shape & a_Shape) { - if (m_LastChunkCoords == a_ChunkCoords) + for (size_t i = 0; i < ARRAYCOUNT(a_Shape); i++) { - return; + a_Shape[i] = 0; } - m_LastChunkCoords = a_ChunkCoords; - - GenerateNoiseArray(); -} - + NOISE_DATATYPE NoiseData[cChunkDef::Width * cChunkDef::Width]; + NOISE_DATATYPE VoidOffsetData[cChunkDef::Width * cChunkDef::Width]; + NOISE_DATATYPE Workspace[cChunkDef::Width * cChunkDef::Width]; + NOISE_DATATYPE StartX = static_cast(a_ChunkCoords.m_ChunkX * cChunkDef::Width) / m_FrequencyX; + NOISE_DATATYPE EndX = static_cast((a_ChunkCoords.m_ChunkX + 1) * cChunkDef::Width) / m_FrequencyX; + NOISE_DATATYPE StartZ = static_cast(a_ChunkCoords.m_ChunkZ * cChunkDef::Width) / m_FrequencyZ; + NOISE_DATATYPE EndZ = static_cast((a_ChunkCoords.m_ChunkZ + 1) * cChunkDef::Width) / m_FrequencyZ; + m_Perlin.Generate2D(NoiseData, cChunkDef::Width, cChunkDef::Width, StartX, EndX, StartZ, EndZ, Workspace); + m_VoidOffsetNoise.Generate2D(VoidOffsetData, cChunkDef::Width, cChunkDef::Width, StartX, EndX, StartZ, EndZ, Workspace); - - -void cEndGen::GenerateNoiseArray(void) -{ - NOISE_DATATYPE NoiseData[DIM_X * DIM_Y * DIM_Z]; // [x + DIM_X * z + DIM_X * DIM_Z * y] - NOISE_DATATYPE Workspace[DIM_X * DIM_Y * DIM_Z]; // [x + DIM_X * z + DIM_X * DIM_Z * y] - - // Generate the downscaled noise: - NOISE_DATATYPE StartX = static_cast(m_LastChunkCoords.m_ChunkX * cChunkDef::Width) / m_FrequencyX; - NOISE_DATATYPE EndX = static_cast((m_LastChunkCoords.m_ChunkX + 1) * cChunkDef::Width) / m_FrequencyX; - NOISE_DATATYPE StartZ = static_cast(m_LastChunkCoords.m_ChunkZ * cChunkDef::Width) / m_FrequencyZ; - NOISE_DATATYPE EndZ = static_cast((m_LastChunkCoords.m_ChunkZ + 1) * cChunkDef::Width) / m_FrequencyZ; - NOISE_DATATYPE StartY = 0; - NOISE_DATATYPE EndY = static_cast(257) / m_FrequencyY; - m_Perlin.Generate3D(NoiseData, DIM_X, DIM_Z, DIM_Y, StartX, EndX, StartZ, EndZ, StartY, EndY, Workspace); - - // Add distance: - int idx = 0; - for (int y = 0; y < DIM_Y; y++) + for (int z = 0; z < cChunkDef::Width; z++) { - NOISE_DATATYPE ValY = static_cast(2 * INTERPOL_Y * y - m_IslandSizeY) / m_IslandSizeY; - ValY = ValY * ValY; - for (int z = 0; z < DIM_Z; z++) + for (int x = 0; x < cChunkDef::Width; x++) { - NOISE_DATATYPE ValZ = static_cast(m_LastChunkCoords.m_ChunkZ * cChunkDef::Width + (z * cChunkDef::Width / (DIM_Z - 1))) / m_IslandSizeZ; - ValZ = ValZ * ValZ; - for (int x = 0; x < DIM_X; x++) - { - // NOISE_DATATYPE ValX = StartX + (EndX - StartX) * x / (DIM_X - 1); - NOISE_DATATYPE ValX = static_cast(m_LastChunkCoords.m_ChunkX * cChunkDef::Width + (x * cChunkDef::Width / (DIM_X - 1))) / m_IslandSizeX; - ValX = ValX * ValX; - NoiseData[idx++] += ValX + ValZ + ValY; - } // for x - } // for z - } // for y - - // Upscale into real chunk size: - LinearUpscale3DArray(NoiseData, DIM_X, DIM_Z, DIM_Y, m_NoiseArray, INTERPOL_X, INTERPOL_Z, INTERPOL_Y); -} - - + NOISE_DATATYPE noise = NoiseData[z * cChunkDef::Width + x]; + // The distance from spawn is used to create the void between the main island and the other islands. + double distanceFromSpawn = cChunkDef::RelativeToAbsolute({ x, 0, z }, a_ChunkCoords).Length(); + // The main island can get a different airthreshold. This way the other island can be more sparse while the main island + // is one big island. + if (distanceFromSpawn > m_MainIslandSize) + { + if (noise <= m_AirThresholdOtherIslands) + { + continue; + } + noise -= m_AirThresholdOtherIslands; + } + else + { + if (noise <= m_AirThresholdMainIsland) + { + continue; + } + noise -= m_AirThresholdMainIsland; + } + NOISE_DATATYPE voidOffset = VoidOffsetData[z * cChunkDef::Width + x]; -void cEndGen::GenShape(cChunkCoords a_ChunkCoords, cChunkDesc::Shape & a_Shape) -{ - PrepareState(a_ChunkCoords); - int MaxY = std::min(static_cast(1.75 * m_IslandSizeY + 1), cChunkDef::Height - 1); - for (int z = 0; z < cChunkDef::Width; z++) - { - for (int x = 0; x < cChunkDef::Width; x++) - { - for (int y = 0; y < MaxY; y++) + double maxHeightLimit; + if (distanceFromSpawn > m_MainIslandSize * 3) { - a_Shape[y + x * 256 + z * 256 * 16] = (m_NoiseArray[y * 17 * 17 + z * 17 + x] <= 0) ? 1 : 0; + // The distance from spawn is so big we don't need to calculate the max height anymore. + // In fact, if we don't cut it off somewhere there is a chance the maxheight gets too big which + // can cause corrupted looking terrain. + maxHeightLimit = static_cast(cChunkDef::Height); } - for (int y = MaxY; y < cChunkDef::Height; y++) + else { - a_Shape[y + x * 256 + z * 256 * 16] = 0; + // Create a void between the main island and the other island using the formula 'x^3 - 3 * x' where x is distance from spawn. + double pow = std::pow((distanceFromSpawn - m_MainIslandSize) / m_MainIslandSize, 3); + double mult = 3 * ((distanceFromSpawn - m_MainIslandSize) / m_MainIslandSize); + maxHeightLimit = Clamp((pow - mult) * 100 + static_cast(voidOffset) * m_VoidOffsetNoiseMultiplier, 0.0, static_cast(cChunkDef::Height)); } - } // for x - } // for z + int maxHeight = static_cast(Clamp(m_BaseHeight + static_cast(noise) * m_TerrainTopMultiplier, 0.0, maxHeightLimit)); + int minHeight = static_cast(Clamp(m_BaseHeight - static_cast(noise) * m_TerrainBottomMultiplier, 0.0, static_cast(cChunkDef::Height))); + + for (int y = minHeight; y < maxHeight; y++) + { + a_Shape[y + x * 256 + z * 256 * 16] = 1; + } + } + } } diff --git a/src/Generating/EndGen.h b/src/Generating/EndGen.h index c1c6f00b6..bd1debdeb 100644 --- a/src/Generating/EndGen.h +++ b/src/Generating/EndGen.h @@ -30,33 +30,28 @@ protected: /** The Perlin noise used for generating */ cPerlinNoise m_Perlin; + cPerlinNoise m_VoidOffsetNoise; - // XYZ size of the "island", in blocks: - int m_IslandSizeX; - int m_IslandSizeY; - int m_IslandSizeZ; + NOISE_DATATYPE m_AirThresholdMainIsland; + NOISE_DATATYPE m_AirThresholdOtherIslands; + int m_MainIslandSize; + int m_BaseHeight; + int m_TerrainTopMultiplier; + int m_TerrainBottomMultiplier; + int m_VoidOffsetNoiseMultiplier; // XYZ Frequencies of the noise functions: NOISE_DATATYPE m_FrequencyX; NOISE_DATATYPE m_FrequencyY; NOISE_DATATYPE m_FrequencyZ; - // Noise array for the last chunk (in the noise range) - cChunkCoords m_LastChunkCoords; - NOISE_DATATYPE m_NoiseArray[17 * 17 * 257]; // x + 17 * z + 17 * 17 * y - - - /** Unless the LastChunk coords are equal to coords given, prepares the internal state (noise array) */ - void PrepareState(cChunkCoords a_ChunkCoords); - - /** Generates the m_NoiseArray array for the current chunk */ - void GenerateNoiseArray(void); - // cTerrainShapeGen overrides: virtual void GenShape(cChunkCoords a_ChunkCoords, cChunkDesc::Shape & a_Shape) override; // cTerrainCompositionGen overrides: virtual void ComposeTerrain(cChunkDesc & a_ChunkDesc, const cChunkDesc::Shape & a_Shape) override; - virtual void InitializeCompoGen(cIniFile & a_IniFile) override; + + // cTerrainShapeGen overrides: + virtual void InitializeShapeGen(cIniFile & a_IniFile) override; } ; -- cgit v1.2.3