//public MapMagic.GeneratorsAsset mapMagicGens; #endif public void Generate(Data.Area area, Func <float, bool> stop = null) { if (area.pinned) { return; } change = false; if (stop != null && stop(0)) { return; } //special case for preserving a demo scene on generator change // if (area.coord.x==0 && area.coord.z==0) return; Data.Area savedArea = null; if (leaveDemoUntouched && area.coord.x == 0 && area.coord.z == 0) { savedArea = (Data.Area)area.Clone(); } if (generatorType == GeneratorType.Planar) { area.ClearLand(); area.ClearObjects(); area.ClearGrass(); Matrix matrix = new Matrix(area.rect); planarGen.Generate(matrix, stop); area.AddLayer(matrix, planarGen.blockType, heightFactor: 1, noise: null); } if (generatorType == GeneratorType.Noise) { area.ClearLand(); area.ClearObjects(); area.ClearGrass(); Noise noise = new Noise(123, permutationCount: 512); //random to floor floats Matrix noiseMatrix = new Matrix(area.rect); if (stop != null && stop(0)) { return; } if (noiseGen.enabled) { noiseGen.Generate(noiseMatrix, seed, stop); } if (stop != null && stop(0)) { return; } if (curveGen.enabled) { curveGen.Generate(noiseMatrix, stop); } if (stop != null && stop(0)) { return; } area.AddLayer(noiseMatrix, noiseGen.blockType, heightFactor: heightFactor, noise: noise); //TODO: set block types instead of magical numbers if (slopeGen.enabled) { if (stop != null && stop(0)) { return; } Matrix slopeMatrix = slopeGen.Generate(noiseMatrix, stop); area.PaintLayer(slopeMatrix, slopeGen.blockType, noise: noise, paintThickness: slopeGen.thickness); } if (cavityGen.enabled) { if (stop != null && stop(0)) { return; } Matrix cavityMatrix = cavityGen.Generate(noiseMatrix, stop); area.PaintLayer(cavityMatrix, cavityGen.blockType, noise: noise, paintThickness: cavityGen.thickness); } Matrix blurMatrix; if (blurGen.enabled) { if (stop != null && stop(0)) { return; } blurMatrix = blurGen.Generate(noiseMatrix, stop); blurMatrix.Max(noiseMatrix); area.ClampAppendLayer(blurMatrix, blurGen.blockType, noise: noise, heightFactor: heightFactor); } else { blurMatrix = noiseMatrix; } if (stainsGen.enabled) { Matrix matrix = area.GetSoilMatrix(stainsGen.soilOpacity); //Matrix stains = new Matrix(area.rect); stainsGen.Generate(matrix, seed, stop); area.PaintLayer(matrix, stainsGen.blockType, noise: noise, paintThickness: stainsGen.thickness); } if (noiseGenB.enabled) { Matrix matrix = new Matrix(area.rect); noiseGenB.Generate(matrix, seed, stop); area.SetLayer(matrix, null, noiseGenB.blockType, heightFactor: heightFactor, noise: noise); } if (scatterGen.enabled) { if (stop != null && stop(0)) { return; } SpatialHash spatialHash = new SpatialHash(new Vector2(area.rect.offset.x, area.rect.offset.z), area.rect.size.x, 16); Matrix soil = area.GetSoilMatrix(scatterGen.soilOpacity); scatterGen.Generate(spatialHash, seed, soil); foreach (SpatialObject obj in spatialHash.AllObjs()) { int x = (int)(obj.pos.x + 0.5f); int z = (int)(obj.pos.y + 0.5f); int y = (int)((obj.height + blurMatrix[x, z]) * heightFactor); area.AddObject(new CoordDir(x, y, z), (short)scatterGen.blockType); } } for (int g = 0; g < grassGens.gens.Length; g++) { GrassGenerator grassGen = grassGens.gens[g]; //if (grassGen.enabled) { if (stop != null && stop(0)) { return; } Matrix grassMatrix = area.GetSoilMatrix(grassGen.soilOpacity); grassGen.Generate(grassMatrix, seed); area.SetGrassLayer(grassMatrix, (byte)grassGen.grassType, 1, noise); } } } else if (generatorType == GeneratorType.Heightmap) { area.ClearLand(); area.ClearObjects(); area.ClearGrass(); Noise noise = new Noise(123, permutationCount: 512); //random to floor floats Matrix matrix = new Matrix(area.rect); if (stop != null && stop(0)) { return; } if (standaloneHeightGen.enabled) { standaloneHeightGen.Generate(matrix, seed, stop); } area.AddLayer(matrix, noiseGen.blockType, heightFactor: heightFactor, noise: noise); //TODO: set block types instead of magical numbers } else if (generatorType == GeneratorType.MapMagic) { #if MAPMAGIC if (stop != null && stop(0)) { return; } if (area.results == null) { area.results = new MapMagic.Chunk.Results(); } //MapMagic.Chunk.Size size = new MapMagic.Chunk.Size(area.rect.size.x,area.rect.size.x,heightFactor); if (stop != null && stop(0)) { return; } if (mapMagicGens != null) { //mapMagicGens.Calculate(area.rect.offset.x, area.rect.offset.z, area.rect.size.x, area.results, new MapMagic.Chunk.Size(area.rect.size.x,area.rect.size.x,heightFactor), seed, stop); mapMagicGens.Generate(area.results, area.rect.offset.x, area.rect.offset.z, area.rect.size.x, area.rect.size.x, heightFactor, seed, stop); } else { area.ClearLand(); area.ClearObjects(); area.ClearGrass(); } #else area.ClearLand(); area.ClearObjects(); area.ClearGrass(); #endif } if (stop != null && stop(0)) { return; } if (removeThinLayers) { area.RemoveThinLayers(minLayerThickness); } if (stop != null && stop(0)) { return; } if (polish) { area.Polish(); } //special case for preserving a demo scene on generator change if (leaveDemoUntouched && area.coord.x == 0 && area.coord.z == 0) { Matrix mask = new Matrix(new CoordRect(0, 0, area.lines.Length, area.lines.Length)); for (int x = 0; x < mask.rect.size.x; x++) { for (int z = 0; z < mask.rect.size.z; z++) { int distFromEdge = Mathf.Min(x, mask.rect.size.x - x, z, mask.rect.size.z - z); mask[x, z] = Mathf.Clamp01(distFromEdge / 50f); } } Matrix maskInverted = (Matrix)mask.Clone(); maskInverted.InvertOne(); area.MixAreas(new Data.Area[] { (Data.Area)area.Clone(), savedArea }, new Matrix[] { maskInverted, mask }); area.objects = savedArea.objects; } //area.generated = true; //area.serializable = true; }
private void GenerateSurface(ref DataChunk chunk, Point3 pos) { int x, z, position, maxY, curY; double y, fX, terrainRange, treeChance; for (ushort xz = 0; xz < 16 * 16; xz++) { x = (xz & 0x00F); z = (xz & 0x0F0) / 0x10; x += pos.X * 0x10; z += pos.Z * 0x10; terrainRange = TerrainRangeGenerator.Generate(x, z); // Roughen up the surface a little 10% y = .9 + HeightRoughner.Generate(x, z) * .1; if (terrainRange >= .5) { #region Above sealevel y *= HeightGenerator.Generate(x, z); // Apply the TerrainRange noise y *= (terrainRange - .5) * 2; // Apply the max height y *= MaxMountainHight - MinSurfaceHeight; // This is were we seperate the mountains from the hills // .5(x+4(x-.5)^3+.5) fX = y / (MaxMountainHight - MinSurfaceHeight); fX = fX + (4 * ((fX - .5) * (fX - .5) * (fX - .5)) + .5); fX /= 2; y *= fX; // Apply the min height y += MinSurfaceHeight; // Round it and apply chunk height y = Math.Ceiling(y); maxY = (int)y; y -= pos.Y * 0x10; // Ceiling check if (y > 0xF) { y = 0xF; } // Air check if (y < 0) { continue; } y *= 0x100; position = xz + (int)y; // Surface block curY = (int)(pos.Y * 0x10 + y / 0x100); if (maxY - curY == 0) { if (SurfaceEnd == pos.Y) { treeChance = 0; } else { treeChance = TreeGenerator.Generate(x, z); treeChance *= Math.Round((terrainRange - .5) * 40 > 1 ? 1 : (terrainRange - .5) * 40, 1); treeChance = Math.Round(treeChance, 1); } chunk.Blocks[position] = new DataBlock() { Material = treeChance < 1 ? MaterialType.Grass : MaterialType.Stone, Position = (ushort)position }; } else { chunk.Blocks[position] = new DataBlock() { Material = maxY - curY <= 3 ? MaterialType.Dirt : MaterialType.Stone, Position = (ushort)position }; } // Non-surface blocks while (y >= 0x100) { y -= 0x100; curY = (int)(pos.Y * 0x10 + y / 0x100); position = xz + (int)y; chunk.Blocks[position] = new DataBlock() { Material = maxY - curY <= 3 ? MaterialType.Dirt : MaterialType.Stone, Position = (ushort)position }; } #endregion } else if (terrainRange >= .475) { #region Beach // Apply the TerrainRange noise y *= 1 - (.5 - terrainRange) * 40; // Apply the min height (which is basically the max height for beaches) y *= MinSurfaceHeight + 1; // Round it and apply chunk height y = Math.Ceiling(y); maxY = (int)y; y -= pos.Y * 0x10; // Ceiling check if (y > 0xF) { y = 0xF; } // Air check if (y < 0) { continue; } y *= 0x100; // Surface block position = xz + (int)y; chunk.Blocks[position] = new DataBlock() { Material = MaterialType.Sand, Position = (ushort)position }; // Non-surface blocks while (y >= 0x100) { y -= 0x100; curY = (int)(pos.Y * 0x10 + y / 0x100); position = xz + (int)y; chunk.Blocks[position] = new DataBlock() { Material = MaterialType.Sand, Position = (ushort)position }; } #endregion } else // terrainRange < .475 { #region Ocean // TODO: Water // Apply the TerrainRange noise y *= (.475 - terrainRange) * (1 / .475); // Apply the max depth y *= MaxOceanDepth; // Round it and apply chunk height y = Math.Ceiling(y); maxY = (int)y; y -= pos.Y * 0x10; // Ceiling check if (y > 0xF) { y = 0xF; } // Air check if (y < 0) { continue; } y *= 0x100; // Surface block position = xz + (int)y; chunk.Blocks[position] = new DataBlock() { Material = MaterialType.Stone, Position = (ushort)position }; // Non-surface blocks while (y >= 0x100) { y -= 0x100; curY = (int)(pos.Y * 0x10 + y / 0x100); position = xz + (int)y; chunk.Blocks[position] = new DataBlock() { Material = MaterialType.Stone, Position = (ushort)position }; } #endregion } } }