using System; using System.Globalization; namespace Oni.Imaging { internal struct Color : IEquatable { private byte b, g, r, a; public Color(byte r, byte g, byte b) : this(r, g, b, 255) { } public Color(byte r, byte g, byte b, byte a) { this.b = b; this.g = g; this.r = r; this.a = a; } public Color(Vector3 v) { r = (byte)(v.X * 255.0f); g = (byte)(v.Y * 255.0f); b = (byte)(v.Z * 255.0f); a = 255; } public Color(Vector4 v) { r = (byte)(v.X * 255.0f); g = (byte)(v.Y * 255.0f); b = (byte)(v.Z * 255.0f); a = (byte)(v.W * 255.0f); } public bool IsTransparent => a != 255; public byte R => r; public byte G => g; public byte B => b; public byte A => a; public int ToBgra32() => b | (g << 8) | (r << 16) | (a << 24); public int ToBgr565() => (b >> 3) | ((g & 0xfc) << 3) | ((r & 0xf8) << 8); public Vector3 ToVector3() => new Vector3(r, g, b) / 255.0f; public Vector4 ToVector4() => new Vector4(r, g, b, a) / 255.0f; public static bool operator ==(Color a, Color b) => a.Equals(b); public static bool operator !=(Color a, Color b) => !a.Equals(b); public bool Equals(Color color) => r == color.r && g == color.g && b == color.b && a == color.a; public override bool Equals(object obj) => obj is Color && Equals((Color)obj); public override int GetHashCode() => r.GetHashCode() ^ g.GetHashCode() ^ b.GetHashCode() ^ a.GetHashCode(); public override string ToString() => string.Format(CultureInfo.InvariantCulture, "{{R:{0} G:{1} B:{2} A:{3}}}", new object[] { r, g, b, a }); public static Color ReadBgra4444(byte[] data, int index) { int pixel = data[index + 0]; byte b = (byte)((pixel << 4) & 0xf0); byte g = (byte)(pixel & 0xf0); pixel = data[index + 1]; byte r = (byte)((pixel << 4) & 0xf0); byte a = (byte)(pixel & 0xf0); return new Color(r, g, b, a); } public static void WriteBgra4444(Color color, byte[] data, int index) { data[index + 0] = (byte)((color.b >> 4) | (color.g & 0xf0)); data[index + 1] = (byte)((color.r >> 4) | (color.a & 0xf0)); } public static Color ReadBgrx5551(byte[] data, int index) { int pixel = data[index + 0] | (data[index + 1] << 8); byte b = (byte)((pixel << 3) & 0xf8); byte g = (byte)((pixel >> 2) & 0xf8); byte r = (byte)((pixel >> 7) & 0xf8); return new Color(r, g, b); } public static void WriteBgrx5551(Color color, byte[] data, int index) { data[index + 0] = (byte)((color.b >> 3) | ((color.g & 0x38) << 2)); data[index + 1] = (byte)((color.g >> 6) | ((color.r & 0xf8) >> 1) | 0x80); } public static Color ReadBgra5551(byte[] data, int index) { int pixel = data[index + 0] | (data[index + 1] << 8); byte b = (byte)((pixel << 3) & 0xf8); byte g = (byte)((pixel >> 2) & 0xf8); byte r = (byte)((pixel >> 7) & 0xf8); byte a = (byte)((pixel >> 15) * 255); return new Color(r, g, b, a); } public static void WriteBgra5551(Color color, byte[] data, int index) { data[index + 0] = (byte)((color.b >> 3) | ((color.g & 0x38) << 2)); data[index + 1] = (byte)((color.g >> 6) | ((color.r & 0xf8) >> 1) | (color.a & 0x80)); } public static Color ReadBgr565(byte[] data, int index) { int pixel = data[index + 0] | (data[index + 1] << 8); byte b = (byte)((pixel << 3) & 0xf8); byte g = (byte)((pixel >> 3) & 0xfc); byte r = (byte)((pixel >> 8) & 0xf8); return new Color(r, g, b); } public static void WriteBgr565(Color color, byte[] data, int index) { data[index + 0] = (byte)((color.b >> 3) | ((color.g & 0x1C) << 3)); data[index + 1] = (byte)((color.g >> 5) | (color.r & 0xf8)); } public static Color ReadBgrx(byte[] data, int index) { byte b = data[index + 0]; byte g = data[index + 1]; byte r = data[index + 2]; return new Color(r, g, b); } public static void WriteBgrx(Color color, byte[] data, int index) { data[index + 0] = color.b; data[index + 1] = color.g; data[index + 2] = color.r; data[index + 3] = 255; } public static Color ReadBgra(byte[] data, int index) { byte b = data[index + 0]; byte g = data[index + 1]; byte r = data[index + 2]; byte a = data[index + 3]; return new Color(r, g, b, a); } public static void WriteBgra(Color color, byte[] data, int index) { data[index + 0] = color.b; data[index + 1] = color.g; data[index + 2] = color.r; data[index + 3] = color.a; } public static Color ReadRgbx(byte[] data, int index) { byte r = data[index + 0]; byte g = data[index + 1]; byte b = data[index + 2]; return new Color(r, g, b); } public static void WriteRgbx(Color color, byte[] data, int index) { data[index + 0] = color.r; data[index + 1] = color.g; data[index + 2] = color.b; data[index + 3] = 255; } public static Color ReadRgba(byte[] data, int index) { byte r = data[index + 0]; byte g = data[index + 1]; byte b = data[index + 2]; byte a = data[index + 3]; return new Color(r, g, b, a); } public static void WriteRgba(Color color, byte[] data, int index) { data[index + 0] = color.r; data[index + 1] = color.g; data[index + 2] = color.b; data[index + 3] = color.a; } public static Color Lerp(Color x, Color y, float amount) { byte r = (byte)MathHelper.Lerp(x.r, y.r, amount); byte g = (byte)MathHelper.Lerp(x.g, y.g, amount); byte b = (byte)MathHelper.Lerp(x.b, y.b, amount); byte a = (byte)MathHelper.Lerp(x.a, y.a, amount); return new Color(r, g, b, a); } private static readonly Color black = new Color(0, 0, 0, 255); private static readonly Color white = new Color(255, 255, 255, 255); private static readonly Color transparent = new Color(0, 0, 0, 0); public static Color White => white; public static Color Black => black; public static Color Transparent => transparent; public static bool TryParse(string s, out Color color) { color = new Color(); color.a = 255; if (string.IsNullOrEmpty(s)) return false; var tokens = s.Split(new char[0], StringSplitOptions.RemoveEmptyEntries); if (tokens.Length < 3 || tokens.Length > 4) return false; if (!byte.TryParse(tokens[0], NumberStyles.Integer, CultureInfo.InvariantCulture, out color.r)) return false; if (!byte.TryParse(tokens[1], NumberStyles.Integer, CultureInfo.InvariantCulture, out color.g)) return false; if (!byte.TryParse(tokens[2], NumberStyles.Integer, CultureInfo.InvariantCulture, out color.b)) return false; if (tokens.Length > 3 && !byte.TryParse(tokens[3], NumberStyles.Integer, CultureInfo.InvariantCulture, out color.a)) return false; return true; } public static Color Parse(string s) { Color c; if (!TryParse(s, out c)) throw new FormatException(string.Format("'{0}' is not a color", s)); return c; } } }