diff --git a/src/ImageSharp/PixelFormats/Rgba64.cs b/src/ImageSharp/PixelFormats/Rgba64.cs index 5d1aa0067..b2442bfea 100644 --- a/src/ImageSharp/PixelFormats/Rgba64.cs +++ b/src/ImageSharp/PixelFormats/Rgba64.cs @@ -4,6 +4,7 @@ using System; using System.Numerics; using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; namespace SixLabors.ImageSharp.PixelFormats { @@ -13,18 +14,61 @@ namespace SixLabors.ImageSharp.PixelFormats /// Ranges from [0, 0, 0, 0] to [1, 1, 1, 1] in vector form. /// /// + [StructLayout(LayoutKind.Sequential)] public struct Rgba64 : IPixel, IPackedVector { + private const float Max = 65535F; + + /// + /// Gets or sets the red component. + /// + public ushort R; + + /// + /// Gets or sets the green component. + /// + public ushort G; + + /// + /// Gets or sets the blue component. + /// + public ushort B; + + /// + /// Gets or sets the alpha component. + /// + public ushort A; + + /// + /// Initializes a new instance of the struct. + /// + /// The red component. + /// The green component. + /// The blue component. + /// The alpha component. + public Rgba64(ushort r, ushort g, ushort b, ushort a) + : this() + { + this.R = r; + this.G = g; + this.B = b; + this.A = a; + } + /// /// Initializes a new instance of the struct. /// - /// The x-component - /// The y-component - /// The z-component - /// The w-component - public Rgba64(float x, float y, float z, float w) + /// The red component. + /// The green component. + /// The blue component. + /// The alpha component. + public Rgba64(float r, float g, float b, float a) + : this() { - this.PackedValue = Pack(x, y, z, w); + this.R = (ushort)MathF.Round(r.Clamp(0, 1) * Max); + this.G = (ushort)MathF.Round(g.Clamp(0, 1) * Max); + this.B = (ushort)MathF.Round(b.Clamp(0, 1) * Max); + this.A = (ushort)MathF.Round(a.Clamp(0, 1) * Max); } /// @@ -32,12 +76,39 @@ namespace SixLabors.ImageSharp.PixelFormats /// /// The vector containing the components values. public Rgba64(Vector4 vector) + : this(vector.X, vector.Y, vector.Z, vector.W) + { + } + + /// + /// Initializes a new instance of the struct. + /// + /// The packed value. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Rgba64(ulong packed) + : this() + { + this.Rgba = packed; + } + + /// + /// Gets or sets the packed representation of the struct. + /// + public ulong Rgba { - this.PackedValue = Pack(vector.X, vector.Y, vector.Z, vector.W); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => Unsafe.As(ref this); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + set => Unsafe.As(ref this) = value; } /// - public ulong PackedValue { get; set; } + public ulong PackedValue + { + get => this.Rgba; + set => this.Rgba = value; + } /// /// Compares two objects for equality. @@ -54,7 +125,7 @@ namespace SixLabors.ImageSharp.PixelFormats [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(Rgba64 left, Rgba64 right) { - return left.PackedValue == right.PackedValue; + return left.Rgba == right.Rgba; } /// @@ -72,7 +143,7 @@ namespace SixLabors.ImageSharp.PixelFormats [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(Rgba64 left, Rgba64 right) { - return left.PackedValue != right.PackedValue; + return left.Rgba != right.Rgba; } /// @@ -96,18 +167,18 @@ namespace SixLabors.ImageSharp.PixelFormats [MethodImpl(MethodImplOptions.AggressiveInlining)] public Vector4 ToVector4() { - return new Vector4( - (this.PackedValue & 0xFFFF) / 65535F, - ((this.PackedValue >> 16) & 0xFFFF) / 65535F, - ((this.PackedValue >> 32) & 0xFFFF) / 65535F, - ((this.PackedValue >> 48) & 0xFFFF) / 65535F); + return new Vector4(this.R / Max, this.G / Max, this.B / Max, this.A / Max); } /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void PackFromVector4(Vector4 vector) { - this.PackedValue = Pack(vector.X, vector.Y, vector.Z, vector.W); + vector = Vector4.Clamp(vector, Vector4.Zero, Vector4.One) * Max; + this.R = (ushort)MathF.Round(vector.X); + this.G = (ushort)MathF.Round(vector.Y); + this.B = (ushort)MathF.Round(vector.Z); + this.A = (ushort)MathF.Round(vector.W); } /// @@ -194,7 +265,7 @@ namespace SixLabors.ImageSharp.PixelFormats [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool Equals(Rgba64 other) { - return this.PackedValue == other.PackedValue; + return this.Rgba == other.Rgba; } /// @@ -209,22 +280,5 @@ namespace SixLabors.ImageSharp.PixelFormats { return this.PackedValue.GetHashCode(); } - - /// - /// Packs the components into a . - /// - /// The x-component - /// The y-component - /// The z-component - /// The w-component - /// The containing the packed values. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static ulong Pack(float x, float y, float z, float w) - { - return (ulong)MathF.Round(x.Clamp(0, 1) * 65535F) | - ((ulong)MathF.Round(y.Clamp(0, 1) * 65535F) << 16) | - ((ulong)MathF.Round(z.Clamp(0, 1) * 65535F) << 32) | - ((ulong)MathF.Round(w.Clamp(0, 1) * 65535F) << 48); - } } -} +} \ No newline at end of file diff --git a/tests/ImageSharp.Tests/PixelFormats/Rgba64Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Rgba64Tests.cs index ffe512855..d8d6bcf8b 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Rgba64Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Rgba64Tests.cs @@ -12,7 +12,14 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats [Fact] public void Rgba64_PackedValues() { + Assert.Equal((ulong)0x73334CCC2666147B, new Rgba64(5243, 9830, 19660, 29491).PackedValue); Assert.Equal((ulong)0x73334CCC2666147B, new Rgba64(0.08f, 0.15f, 0.30f, 0.45f).PackedValue); + var rgba = new Rgba64(0x73334CCC2666147B); + Assert.Equal(5243, rgba.R); + Assert.Equal(9830, rgba.G); + Assert.Equal(19660, rgba.B); + Assert.Equal(29491, rgba.A); + // Test the limits. Assert.Equal((ulong)0x0, new Rgba64(Vector4.Zero).PackedValue); Assert.Equal(0xFFFFFFFFFFFFFFFF, new Rgba64(Vector4.One).PackedValue);