sandpypi/Sand.ChunkPrototype/ChunkFieldPage.cs

97 lines
3.0 KiB
C#

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;
}