using System; using System.Diagnostics.CodeAnalysis; namespace Dashboard { /// /// Pixel format for images. /// [Flags] public enum PixelFormat { None = 0, R8I = R | I8, Rg8I = Rg | I8, Rgb8I = Rgb | I8, Rgba8I = Rgba | I8, R16F = R | F16, Rg16F = Rg | F16, Rgb16F = Rgb | F16, Rgba16F = Rgba | F16, // Channels R = 0x01, Rg = 0x02, Rgb = 0x03, Rgba = 0x04, A = 0x05, ColorMask = 0x0F, I8 = 0x10, F16 = 0x20, TypeMask = 0xF0, } /// /// 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; } }