diff --git a/Dashboard/ImageProperties.cs b/Dashboard/ImageProperties.cs new file mode 100644 index 0000000..a7be347 --- /dev/null +++ b/Dashboard/ImageProperties.cs @@ -0,0 +1,196 @@ +using System; +using System.Diagnostics.CodeAnalysis; + +namespace Dashboard +{ + /// + /// Pixel format for images. + /// + public enum PixelFormat + { + R8I, + Rg8I, + Rgb8I, + Rgba8I, + R16F, + Rg816F, + Rgb16F, + Rgba16F, + } + + /// + /// Color channels for images. + /// + public enum ColorChannel + { + /// + /// The zero channel. Used for swizzle masks. + /// + Zero = 0, + + /// + /// The one channel. Used for swizzle masks. + /// + One = 1, + + /// + /// An invalid swizzle mask. + /// + Unknown = 2, + + /// + /// The red channel. + /// + Red = 4, + + /// + /// The green channel. + /// + Green = 5, + + /// + /// The blue channel. + /// + Blue = 6, + + /// + /// The alpha channel. + /// + Alpha = 7, + } + + /// + /// Defines a image swizzle mask. + /// + public struct ColorSwizzle : IEquatable + { + public short Mask; + + private const int MASK = 7; + private const int RBIT = 0; + private const int GBIT = 3; + private const int BBIT = 6; + private const int ABIT = 9; + + /// + /// Swizzle the red channel. + /// + public ColorChannel R + { + get => (ColorChannel)((Mask >> RBIT) & MASK); + set => Mask = (short)(((int)value << RBIT) | (Mask & ~(MASK << RBIT))); + } + + /// + /// Swizzle the green channel. + /// + public ColorChannel G + { + get => (ColorChannel)((Mask >> GBIT) & MASK); + set => Mask = (short)(((int)value << GBIT) | (Mask & ~(MASK << GBIT))); + } + + /// + /// Swizzle the blue channel. + /// + public ColorChannel B + { + get => (ColorChannel)((Mask >> BBIT) & MASK); + set => Mask = (short)(((int)value << BBIT) | (Mask & ~(MASK << BBIT))); + } + + /// + /// Swizzle the alpha channel. + /// + public ColorChannel A + { + get => (ColorChannel)((Mask >> ABIT) & MASK); + set => Mask = (short)(((int)value << ABIT) | (Mask & ~(MASK << ABIT))); + } + + public ColorSwizzle(short mask) + { + Mask = mask; + } + + public ColorSwizzle(ColorChannel r, ColorChannel g, ColorChannel b, ColorChannel a) + { + Mask = (short)(((int)r << RBIT) | ((int)g << GBIT) | ((int)b << BBIT) | ((int)a << ABIT)); + } + + public override string ToString() + { + return $"{GetChannelChar(R)}{GetChannelChar(G)}{GetChannelChar(B)}{GetChannelChar(A)}"; + + char GetChannelChar(ColorChannel channel) => channel switch + { + ColorChannel.Zero => '0', + ColorChannel.Red => 'R', + ColorChannel.Green => 'G', + ColorChannel.Blue => 'B', + ColorChannel.Alpha => 'A', + ColorChannel.One => '1', + _ => '?', + }; + } + + public override int GetHashCode() + { + return Mask.GetHashCode(); + } + + public override bool Equals([NotNullWhen(true)] object? obj) + { + return obj is ColorSwizzle other && Equals(other); + } + + public bool Equals(ColorSwizzle other) + { + return Mask == other.Mask; + } + + public static readonly ColorSwizzle Default = Parse("RGBA"); + public static readonly ColorSwizzle White = Parse("1111"); + public static readonly ColorSwizzle Black = Parse("0001"); + public static readonly ColorSwizzle Transparent = Parse("0000"); + public static readonly ColorSwizzle RedToGrayscale = Parse("RRR1"); + public static readonly ColorSwizzle RedToWhiteAlpha = Parse("111A"); + + public static bool TryParse(ReadOnlySpan str, out ColorSwizzle value) + { + if (str.Length < 4) + { + value = default; + return false; + } + + ColorChannel r = GetChannelFromChar(str[0]); + ColorChannel g = GetChannelFromChar(str[1]); + ColorChannel b = GetChannelFromChar(str[2]); + ColorChannel a = GetChannelFromChar(str[3]); + + value = new ColorSwizzle(r, g, b, a); + return true; + + ColorChannel GetChannelFromChar(char chr) => chr switch + { + '0' => ColorChannel.Zero, + 'R' => ColorChannel.Red, + 'G' => ColorChannel.Green, + 'B' => ColorChannel.Blue, + 'A' => ColorChannel.Alpha, + '1' => ColorChannel.One, + _ => ColorChannel.Unknown, + }; + } + + public static ColorSwizzle Parse(ReadOnlySpan str) => + TryParse(str, out ColorSwizzle value) ? value : throw new FormatException(nameof(str)); + + public static bool operator ==(ColorSwizzle left, ColorSwizzle right) => + left.Mask == right.Mask; + + public static bool operator !=(ColorSwizzle left, ColorSwizzle right) => + left.Mask != right.Mask; + } +}