//$ Copyright 2015-22, Code Respawn Technologies Pvt Ltd - All Rights Reserved $// using System.Collections.Generic; using UnityEngine; namespace DungeonArchitect.Utils.Noise { public interface INoiseTable { void Init(int InSize, System.Random random); float GetNoise(float u, float v); NoiseTableCell GetCell(float x, float y); } public interface INoisePolicy { float Sample(float x, float y, INoiseTable NoiseTable); T GetRandom(System.Random random); } public struct NoiseTableCell { public T N00; public T N10; public T N01; public T N11; }; public abstract class NoiseTable : INoiseTable { private int size; private List data = new List(); protected INoisePolicy noisePolicy; protected abstract INoisePolicy CreateNoisePolicy(); public void Init(int size, System.Random random) { this.size = size; noisePolicy = CreateNoisePolicy(); int NumElements = size * size; data = new List(new T[NumElements]); int LastIdx = size - 1; for (int y = 0; y < size; y++) { for (int x = 0; x < size; x++) { if (x == LastIdx || y == LastIdx) { int ix = x % LastIdx; int iy = y % LastIdx; data[IDX(x, y)] = data[IDX(ix, iy)]; } else { data[IDX(x, y)] = noisePolicy.GetRandom(random); } } } } public NoiseTableCell GetCell(float x, float y) { int x0 = Mathf.FloorToInt(x) % size; int y0 = Mathf.FloorToInt(y) % size; int x1 = (x0 + 1) % size; int y1 = (y0 + 1) % size; var cell = new NoiseTableCell(); cell.N00 = data[IDX(x0, y0)]; cell.N10 = data[IDX(x1, y0)]; cell.N01 = data[IDX(x0, y1)]; cell.N11 = data[IDX(x1, y1)]; return cell; } public float GetNoise(float u, float v) { float x = u * (size - 1); float y = v * (size - 1); return noisePolicy.Sample(x, y, this); } public float GetNoiseFBM(Vector2 p, int octaves) { p /= size; float noise = 0; float amp = 1; // 0.457345f; for (int i = 0; i < octaves; i++) { noise += amp * GetNoise(p.x, p.y); p *= 1.986576f; amp *= 0.5f; } noise = 0.5f + noise * 0.5f; return Mathf.Clamp01(noise); } T GetTableData(int x, int y) { return data[IDX(x, y)]; } int GetSize() { return size; } int IDX(int x, int y) { return y * size + x; } } public class GradientNoisePolicy : INoisePolicy { public float Sample(float x, float y, INoiseTable NoiseTable) { var Cell = NoiseTable.GetCell(x, y); float fx = x % 1; float fy = y % 1; var P = new Vector2(fx, fy); return Mathf.Lerp( Mathf.Lerp( Vector2.Dot(Cell.N00, P - new Vector2(0, 0)), Vector2.Dot(Cell.N10, P - new Vector2(1, 0)), fx), Mathf.Lerp( Vector2.Dot(Cell.N01, P - new Vector2(0, 1)), Vector2.Dot(Cell.N11, P - new Vector2(1, 1)), fx), fy); } public Vector2 GetRandom(System.Random random) { var angle = random.NextFloat() * Mathf.PI * 2.0f; return new Vector2( Mathf.Cos(angle), Mathf.Sin(angle)); } } public class GradientNoiseTable : NoiseTable { protected override INoisePolicy CreateNoisePolicy() { return new GradientNoisePolicy(); } } }