PixelPoint.cs
namespace Sandbox;

/// <summary>
/// Integer 2D point used for pixel-space coordinates.
/// Replaces float positions with exact pixel addressing.
/// </summary>
public struct PixelPoint : IEquatable<PixelPoint>
{
	public int X;
	public int Y;

	public PixelPoint( int x, int y )
	{
		X = x;
		Y = y;
	}

	/// <summary>
	/// Manhattan distance between two points.
	/// Cheaper than Euclidean and often sufficient for grid-based logic.
	/// </summary>
	public int Distance( PixelPoint other )
	{
		return Math.Abs( X - other.X ) + Math.Abs( Y - other.Y );
	}

	public static PixelPoint operator +( PixelPoint a, PixelPoint b ) => new( a.X + b.X, a.Y + b.Y );
	public static PixelPoint operator -( PixelPoint a, PixelPoint b ) => new( a.X - b.X, a.Y - b.Y );
	public static PixelPoint operator -( PixelPoint a ) => new( -a.X, -a.Y );
	public static PixelPoint operator *( PixelPoint a, int scale ) => new( a.X * scale, a.Y * scale );
	public static bool operator ==( PixelPoint a, PixelPoint b ) => a.X == b.X && a.Y == b.Y;
	public static bool operator !=( PixelPoint a, PixelPoint b ) => !(a == b);

	public static implicit operator Vector2( PixelPoint p ) => new( p.X, p.Y );
	public static implicit operator PixelPoint( Vector2 v ) => new( (int)v.x, (int)v.y );

	public static readonly PixelPoint Zero = new( 0, 0 );

	public bool Equals( PixelPoint other ) => X == other.X && Y == other.Y;
	public override bool Equals( object obj ) => obj is PixelPoint other && Equals( other );
	public override int GetHashCode() => HashCode.Combine( X, Y );
	public override string ToString() => $"({X}, {Y})";
}