namespace Sand.ChunkPrototype; internal sealed class ChunkFieldPage { public ChunkFieldPage(int width, int height) { Width = width; Height = height; WindX = new float[width * height]; WindY = new float[width * height]; ForceX = new float[width * height]; ForceY = new float[width * height]; Pressure = new float[width * height]; } public int Width { get; } public int Height { get; } public float[] WindX { get; } public float[] WindY { get; } public float[] ForceX { get; } public float[] ForceY { get; } public float[] Pressure { get; } public int ActiveCellCount { get; private set; } public int LastDecayedFrame { get; set; } public bool TryGetCell(int localX, int localY, out FieldCellData cell) { var index = GetIndex(localX, localY); cell = new FieldCellData(WindX[index], WindY[index], ForceX[index], ForceY[index], Pressure[index]); return !cell.IsEffectivelyZero; } public FieldCellData GetCell(int localX, int localY) { var index = GetIndex(localX, localY); return new FieldCellData(WindX[index], WindY[index], ForceX[index], ForceY[index], Pressure[index]); } public void SetCell(int localX, int localY, FieldCellData value) { var index = GetIndex(localX, localY); var wasZero = IsEffectivelyZero(index); var nowZero = value.IsEffectivelyZero; WindX[index] = value.WindX; WindY[index] = value.WindY; ForceX[index] = value.ForceX; ForceY[index] = value.ForceY; Pressure[index] = value.Pressure; if (wasZero && !nowZero) { ActiveCellCount++; } else if (!wasZero && nowZero) { ActiveCellCount--; } } public bool IsEmpty() => ActiveCellCount == 0; public IEnumerable<(int LocalX, int LocalY, FieldCellData Cell)> EnumerateActiveCells() { for (var y = 0; y < Height; y++) { for (var x = 0; x < Width; x++) { var index = GetIndex(x, y); if (IsEffectivelyZero(index)) { continue; } yield return (x, y, new FieldCellData(WindX[index], WindY[index], ForceX[index], ForceY[index], Pressure[index])); } } } private bool IsEffectivelyZero(int index) => MathF.Abs(WindX[index]) < 0.01f && MathF.Abs(WindY[index]) < 0.01f && MathF.Abs(ForceX[index]) < 0.01f && MathF.Abs(ForceY[index]) < 0.01f && MathF.Abs(Pressure[index]) < 0.01f; private int GetIndex(int localX, int localY) => (localY * Width) + localX; } internal readonly record struct FieldCellData(float WindX, float WindY, float ForceX, float ForceY, float Pressure) { public bool IsEffectivelyZero => MathF.Abs(WindX) < 0.01f && MathF.Abs(WindY) < 0.01f && MathF.Abs(ForceX) < 0.01f && MathF.Abs(ForceY) < 0.01f && MathF.Abs(Pressure) < 0.01f; }