DiamondAtmosphere.Transport.cs
using System;
namespace Diamonds;
public sealed partial class DiamondAtmosphere
{
void TransportDye( float dt, float retention )
{
Array.Clear( nextDye );
float travel = dt * FlowUnit * FlowSpeed / CellSize;
for ( int y = 0; y < Rows; y++ )
for ( int x = 0; x < Columns; x++ )
{
int own = y * Columns + x;
if ( wallDistance[own] < 0 ) continue;
// Like the menu, each destination samples where its fluid came from.
float tx = x - velocityX[own] * travel, ty = y - velocityY[own] * travel;
var point = GridToWorld( x, y );
float worldX = point.x - velocityX[own] * FlowUnit * FlowSpeed * dt;
float worldY = point.y - velocityY[own] * FlowUnit * FlowSpeed * dt;
// Reflect crossings of the playfield walls, not stationary samples in
// the offscreen reservoir. The top stays open for incoming spawn dye.
bool side = point.x >= 0 && point.x <= DiamondBoard.BoardWidth && (worldX < 0 || worldX > DiamondBoard.BoardWidth);
bool bottom = point.y <= DiamondBoard.BoardHeight && worldY > DiamondBoard.BoardHeight;
if ( side || bottom )
(tx, ty) = WorldToGrid( side ? ReflectX( worldX ) : worldX, bottom ? ReflectBottom( worldY ) : worldY );
(tx, ty) = TraceFluid( x, y, tx, ty );
tx = Math.Clamp( tx, 0, Columns - 1 ); ty = Math.Clamp( ty, 0, Rows - 1 );
int ix = Math.Min( (int)tx, Columns - 2 ), iy = Math.Min( (int)ty, Rows - 2 );
float fx = tx - ix, fy = ty - iy;
int a = iy * Columns + ix, b = a + 1, c = a + Columns, d = c + 1;
float wa = wallDistance[a] < 0 ? 0 : (1 - fx) * (1 - fy);
float wb = wallDistance[b] < 0 ? 0 : fx * (1 - fy);
float wc = wallDistance[c] < 0 ? 0 : (1 - fx) * fy;
float wd = wallDistance[d] < 0 ? 0 : fx * fy;
float weight = wa + wb + wc + wd;
float scale = weight > 0 ? retention / weight : 0;
wa *= scale; wb *= scale; wc *= scale; wd *= scale;
// Renormalize the open source samples at solid boundaries, as on the menu.
// Apply the configured fade locally; do not rescale the whole field.
for ( int color = 0; color < DiamondBoard.ColorCount; color++ )
{
nextDye[own * DiamondBoard.ColorCount + color] =
dye[a * DiamondBoard.ColorCount + color] * wa +
dye[b * DiamondBoard.ColorCount + color] * wb +
dye[c * DiamondBoard.ColorCount + color] * wc +
dye[d * DiamondBoard.ColorCount + color] * wd;
}
}
if ( !dye.AsSpan().SequenceEqual( nextDye ) ) DyeVersion++;
Array.Copy( nextDye, dye, dye.Length );
}
}