namespace VoxelEngine.World.WorldGen; // A jittered-grid Voronoi partition. Pure integer-hash based, fully deterministic. public sealed class VoronoiCells { public readonly record struct Cell(int Id, float CenterX, float CenterZ); private readonly int _seed; private readonly float _cellSize; public VoronoiCells(int seed, float cellSize) { this._seed = seed; this._cellSize = cellSize; } public Cell Nearest(float x, float z) { int gx = (int)System.MathF.Floor(x / this._cellSize); int gz = (int)System.MathF.Floor(z / this._cellSize); float bestDist = float.MaxValue; int bestId = 0; float bestCx = 0f, bestCz = 0f; for (int oz = -1; oz <= 1; oz++) for (int ox = -1; ox <= 1; ox++) { int cgx = gx + ox; int cgz = gz + oz; float jitterX = VoronoiCells.Jitter(cgx, cgz, this._seed); float jitterZ = VoronoiCells.Jitter(cgx, cgz, this._seed + 9871); float cx = (cgx + jitterX) * this._cellSize; float cz = (cgz + jitterZ) * this._cellSize; float dx = cx - x, dz = cz - z; float dist = dx * dx + dz * dz; if (dist < bestDist) { bestDist = dist; bestId = (int)VoronoiCells.Hash(cgx, cgz, this._seed); bestCx = cx; bestCz = cz; } } return new Cell(bestId, bestCx, bestCz); } private static float Jitter(int x, int z, int seed) => (VoronoiCells.Hash(x, z, seed) & 0xFFFFFF) / (float)0x1000000; // [0,1) private static uint Hash(int x, int z, int seed) { unchecked { uint h = (uint)(x * 374761393 + z * 668265263 + seed * 362437); h = (h ^ (h >> 13)) * 1274126177u; return h ^ (h >> 16); } } }