| 1 | using System; | 
 
 
 
 
 | 2 | using System.Globalization; | 
 
 
 
 
 | 3 |  | 
 
 
 
 
 | 4 | namespace Oni.Imaging | 
 
 
 
 
 | 5 | { | 
 
 
 
 
 | 6 | internal struct Color : IEquatable<Color> | 
 
 
 
 
 | 7 | { | 
 
 
 
 
 | 8 | private byte b, g, r, a; | 
 
 
 
 
 | 9 |  | 
 
 
 
 
 | 10 | public Color(byte r, byte g, byte b) | 
 
 
 
 
 | 11 | : this(r, g, b, 255) | 
 
 
 
 
 | 12 | { | 
 
 
 
 
 | 13 | } | 
 
 
 
 
 | 14 |  | 
 
 
 
 
 | 15 | public Color(byte r, byte g, byte b, byte a) | 
 
 
 
 
 | 16 | { | 
 
 
 
 
 | 17 | this.b = b; | 
 
 
 
 
 | 18 | this.g = g; | 
 
 
 
 
 | 19 | this.r = r; | 
 
 
 
 
 | 20 | this.a = a; | 
 
 
 
 
 | 21 | } | 
 
 
 
 
 | 22 |  | 
 
 
 
 
 | 23 | public Color(Vector3 v) | 
 
 
 
 
 | 24 | { | 
 
 
 
 
 | 25 | r = (byte)(v.X * 255.0f); | 
 
 
 
 
 | 26 | g = (byte)(v.Y * 255.0f); | 
 
 
 
 
 | 27 | b = (byte)(v.Z * 255.0f); | 
 
 
 
 
 | 28 | a = 255; | 
 
 
 
 
 | 29 | } | 
 
 
 
 
 | 30 |  | 
 
 
 
 
 | 31 | public Color(Vector4 v) | 
 
 
 
 
 | 32 | { | 
 
 
 
 
 | 33 | r = (byte)(v.X * 255.0f); | 
 
 
 
 
 | 34 | g = (byte)(v.Y * 255.0f); | 
 
 
 
 
 | 35 | b = (byte)(v.Z * 255.0f); | 
 
 
 
 
 | 36 | a = (byte)(v.W * 255.0f); | 
 
 
 
 
 | 37 | } | 
 
 
 
 
 | 38 |  | 
 
 
 
 
 | 39 | public bool IsTransparent => a != 255; | 
 
 
 
 
 | 40 |  | 
 
 
 
 
 | 41 | public byte R => r; | 
 
 
 
 
 | 42 | public byte G => g; | 
 
 
 
 
 | 43 | public byte B => b; | 
 
 
 
 
 | 44 | public byte A => a; | 
 
 
 
 
 | 45 |  | 
 
 
 
 
 | 46 | public int ToBgra32() => b | (g << 8) | (r << 16) | (a << 24); | 
 
 
 
 
 | 47 | public int ToBgr565() => (b >> 3) | ((g & 0xfc) << 3) | ((r & 0xf8) << 8); | 
 
 
 
 
 | 48 |  | 
 
 
 
 
 | 49 | public Vector3 ToVector3() => new Vector3(r, g, b) / 255.0f; | 
 
 
 
 
 | 50 | public Vector4 ToVector4() => new Vector4(r, g, b, a) / 255.0f; | 
 
 
 
 
 | 51 |  | 
 
 
 
 
 | 52 | public static bool operator ==(Color a, Color b) => a.Equals(b); | 
 
 
 
 
 | 53 | public static bool operator !=(Color a, Color b) => !a.Equals(b); | 
 
 
 
 
 | 54 |  | 
 
 
 
 
 | 55 | public bool Equals(Color color) => r == color.r && g == color.g && b == color.b && a == color.a; | 
 
 
 
 
 | 56 | public override bool Equals(object obj) => obj is Color && Equals((Color)obj); | 
 
 
 
 
 | 57 | public override int GetHashCode() => r.GetHashCode() ^ g.GetHashCode() ^ b.GetHashCode() ^ a.GetHashCode(); | 
 
 
 
 
 | 58 |  | 
 
 
 
 
 | 59 | public override string ToString() => string.Format(CultureInfo.InvariantCulture, "{{R:{0} G:{1} B:{2} A:{3}}}", new object[] { r, g, b, a }); | 
 
 
 
 
 | 60 |  | 
 
 
 
 
 | 61 | public static Color ReadBgra4444(byte[] data, int index) | 
 
 
 
 
 | 62 | { | 
 
 
 
 
 | 63 | int pixel = data[index + 0]; | 
 
 
 
 
 | 64 | byte b = (byte)((pixel << 4) & 0xf0); | 
 
 
 
 
 | 65 | byte g = (byte)(pixel & 0xf0); | 
 
 
 
 
 | 66 | pixel = data[index + 1]; | 
 
 
 
 
 | 67 | byte r = (byte)((pixel << 4) & 0xf0); | 
 
 
 
 
 | 68 | byte a = (byte)(pixel & 0xf0); | 
 
 
 
 
 | 69 |  | 
 
 
 
 
 | 70 | return new Color(r, g, b, a); | 
 
 
 
 
 | 71 | } | 
 
 
 
 
 | 72 |  | 
 
 
 
 
 | 73 | public static void WriteBgra4444(Color color, byte[] data, int index) | 
 
 
 
 
 | 74 | { | 
 
 
 
 
 | 75 | data[index + 0] = (byte)((color.b >> 4) | (color.g & 0xf0)); | 
 
 
 
 
 | 76 | data[index + 1] = (byte)((color.r >> 4) | (color.a & 0xf0)); | 
 
 
 
 
 | 77 | } | 
 
 
 
 
 | 78 |  | 
 
 
 
 
 | 79 | public static Color ReadBgrx5551(byte[] data, int index) | 
 
 
 
 
 | 80 | { | 
 
 
 
 
 | 81 | int pixel = data[index + 0] | (data[index + 1] << 8); | 
 
 
 
 
 | 82 | byte b = (byte)((pixel << 3) & 0xf8); | 
 
 
 
 
 | 83 | byte g = (byte)((pixel >> 2) & 0xf8); | 
 
 
 
 
 | 84 | byte r = (byte)((pixel >> 7) & 0xf8); | 
 
 
 
 
 | 85 |  | 
 
 
 
 
 | 86 | return new Color(r, g, b); | 
 
 
 
 
 | 87 | } | 
 
 
 
 
 | 88 |  | 
 
 
 
 
 | 89 | public static void WriteBgrx5551(Color color, byte[] data, int index) | 
 
 
 
 
 | 90 | { | 
 
 
 
 
 | 91 | data[index + 0] = (byte)((color.b >> 3) | ((color.g & 0x38) << 2)); | 
 
 
 
 
 | 92 | data[index + 1] = (byte)((color.g >> 6) | ((color.r & 0xf8) >> 1) | 0x80); | 
 
 
 
 
 | 93 | } | 
 
 
 
 
 | 94 |  | 
 
 
 
 
 | 95 | public static Color ReadBgra5551(byte[] data, int index) | 
 
 
 
 
 | 96 | { | 
 
 
 
 
 | 97 | int pixel = data[index + 0] | (data[index + 1] << 8); | 
 
 
 
 
 | 98 | byte b = (byte)((pixel << 3) & 0xf8); | 
 
 
 
 
 | 99 | byte g = (byte)((pixel >> 2) & 0xf8); | 
 
 
 
 
 | 100 | byte r = (byte)((pixel >> 7) & 0xf8); | 
 
 
 
 
 | 101 | byte a = (byte)((pixel >> 15) * 255); | 
 
 
 
 
 | 102 |  | 
 
 
 
 
 | 103 | return new Color(r, g, b, a); | 
 
 
 
 
 | 104 | } | 
 
 
 
 
 | 105 |  | 
 
 
 
 
 | 106 | public static void WriteBgra5551(Color color, byte[] data, int index) | 
 
 
 
 
 | 107 | { | 
 
 
 
 
 | 108 | data[index + 0] = (byte)((color.b >> 3) | ((color.g & 0x38) << 2)); | 
 
 
 
 
 | 109 | data[index + 1] = (byte)((color.g >> 6) | ((color.r & 0xf8) >> 1) | (color.a & 0x80)); | 
 
 
 
 
 | 110 | } | 
 
 
 
 
 | 111 |  | 
 
 
 
 
 | 112 | public static Color ReadBgr565(byte[] data, int index) | 
 
 
 
 
 | 113 | { | 
 
 
 
 
 | 114 | int pixel = data[index + 0] | (data[index + 1] << 8); | 
 
 
 
 
 | 115 | byte b = (byte)((pixel << 3) & 0xf8); | 
 
 
 
 
 | 116 | byte g = (byte)((pixel >> 3) & 0xfc); | 
 
 
 
 
 | 117 | byte r = (byte)((pixel >> 8) & 0xf8); | 
 
 
 
 
 | 118 |  | 
 
 
 
 
 | 119 | return new Color(r, g, b); | 
 
 
 
 
 | 120 | } | 
 
 
 
 
 | 121 |  | 
 
 
 
 
 | 122 | public static void WriteBgr565(Color color, byte[] data, int index) | 
 
 
 
 
 | 123 | { | 
 
 
 
 
 | 124 | data[index + 0] = (byte)((color.b >> 3) | ((color.g & 0x1C) << 3)); | 
 
 
 
 
 | 125 | data[index + 1] = (byte)((color.g >> 5) | (color.r & 0xf8)); | 
 
 
 
 
 | 126 | } | 
 
 
 
 
 | 127 |  | 
 
 
 
 
 | 128 | public static Color ReadBgrx(byte[] data, int index) | 
 
 
 
 
 | 129 | { | 
 
 
 
 
 | 130 | byte b = data[index + 0]; | 
 
 
 
 
 | 131 | byte g = data[index + 1]; | 
 
 
 
 
 | 132 | byte r = data[index + 2]; | 
 
 
 
 
 | 133 |  | 
 
 
 
 
 | 134 | return new Color(r, g, b); | 
 
 
 
 
 | 135 | } | 
 
 
 
 
 | 136 |  | 
 
 
 
 
 | 137 | public static void WriteBgrx(Color color, byte[] data, int index) | 
 
 
 
 
 | 138 | { | 
 
 
 
 
 | 139 | data[index + 0] = color.b; | 
 
 
 
 
 | 140 | data[index + 1] = color.g; | 
 
 
 
 
 | 141 | data[index + 2] = color.r; | 
 
 
 
 
 | 142 | data[index + 3] = 255; | 
 
 
 
 
 | 143 | } | 
 
 
 
 
 | 144 |  | 
 
 
 
 
 | 145 | public static Color ReadBgra(byte[] data, int index) | 
 
 
 
 
 | 146 | { | 
 
 
 
 
 | 147 | byte b = data[index + 0]; | 
 
 
 
 
 | 148 | byte g = data[index + 1]; | 
 
 
 
 
 | 149 | byte r = data[index + 2]; | 
 
 
 
 
 | 150 | byte a = data[index + 3]; | 
 
 
 
 
 | 151 |  | 
 
 
 
 
 | 152 | return new Color(r, g, b, a); | 
 
 
 
 
 | 153 | } | 
 
 
 
 
 | 154 |  | 
 
 
 
 
 | 155 | public static void WriteBgra(Color color, byte[] data, int index) | 
 
 
 
 
 | 156 | { | 
 
 
 
 
 | 157 | data[index + 0] = color.b; | 
 
 
 
 
 | 158 | data[index + 1] = color.g; | 
 
 
 
 
 | 159 | data[index + 2] = color.r; | 
 
 
 
 
 | 160 | data[index + 3] = color.a; | 
 
 
 
 
 | 161 | } | 
 
 
 
 
 | 162 |  | 
 
 
 
 
 | 163 | public static Color ReadRgbx(byte[] data, int index) | 
 
 
 
 
 | 164 | { | 
 
 
 
 
 | 165 | byte r = data[index + 0]; | 
 
 
 
 
 | 166 | byte g = data[index + 1]; | 
 
 
 
 
 | 167 | byte b = data[index + 2]; | 
 
 
 
 
 | 168 |  | 
 
 
 
 
 | 169 | return new Color(r, g, b); | 
 
 
 
 
 | 170 | } | 
 
 
 
 
 | 171 |  | 
 
 
 
 
 | 172 | public static void WriteRgbx(Color color, byte[] data, int index) | 
 
 
 
 
 | 173 | { | 
 
 
 
 
 | 174 | data[index + 0] = color.r; | 
 
 
 
 
 | 175 | data[index + 1] = color.g; | 
 
 
 
 
 | 176 | data[index + 2] = color.b; | 
 
 
 
 
 | 177 | data[index + 3] = 255; | 
 
 
 
 
 | 178 | } | 
 
 
 
 
 | 179 |  | 
 
 
 
 
 | 180 | public static Color ReadRgba(byte[] data, int index) | 
 
 
 
 
 | 181 | { | 
 
 
 
 
 | 182 | byte r = data[index + 0]; | 
 
 
 
 
 | 183 | byte g = data[index + 1]; | 
 
 
 
 
 | 184 | byte b = data[index + 2]; | 
 
 
 
 
 | 185 | byte a = data[index + 3]; | 
 
 
 
 
 | 186 |  | 
 
 
 
 
 | 187 | return new Color(r, g, b, a); | 
 
 
 
 
 | 188 | } | 
 
 
 
 
 | 189 |  | 
 
 
 
 
 | 190 | public static void WriteRgba(Color color, byte[] data, int index) | 
 
 
 
 
 | 191 | { | 
 
 
 
 
 | 192 | data[index + 0] = color.r; | 
 
 
 
 
 | 193 | data[index + 1] = color.g; | 
 
 
 
 
 | 194 | data[index + 2] = color.b; | 
 
 
 
 
 | 195 | data[index + 3] = color.a; | 
 
 
 
 
 | 196 | } | 
 
 
 
 
 | 197 |  | 
 
 
 
 
 | 198 | public static Color Lerp(Color x, Color y, float amount) | 
 
 
 
 
 | 199 | { | 
 
 
 
 
 | 200 | byte r = (byte)MathHelper.Lerp(x.r, y.r, amount); | 
 
 
 
 
 | 201 | byte g = (byte)MathHelper.Lerp(x.g, y.g, amount); | 
 
 
 
 
 | 202 | byte b = (byte)MathHelper.Lerp(x.b, y.b, amount); | 
 
 
 
 
 | 203 | byte a = (byte)MathHelper.Lerp(x.a, y.a, amount); | 
 
 
 
 
 | 204 |  | 
 
 
 
 
 | 205 | return new Color(r, g, b, a); | 
 
 
 
 
 | 206 | } | 
 
 
 
 
 | 207 |  | 
 
 
 
 
 | 208 | private static readonly Color black = new Color(0, 0, 0, 255); | 
 
 
 
 
 | 209 | private static readonly Color white = new Color(255, 255, 255, 255); | 
 
 
 
 
 | 210 | private static readonly Color transparent = new Color(0, 0, 0, 0); | 
 
 
 
 
 | 211 |  | 
 
 
 
 
 | 212 | public static Color White => white; | 
 
 
 
 
 | 213 | public static Color Black => black; | 
 
 
 
 
 | 214 | public static Color Transparent => transparent; | 
 
 
 
 
 | 215 |  | 
 
 
 
 
 | 216 | public static bool TryParse(string s, out Color color) | 
 
 
 
 
 | 217 | { | 
 
 
 
 
 | 218 | color = new Color(); | 
 
 
 
 
 | 219 | color.a = 255; | 
 
 
 
 
 | 220 |  | 
 
 
 
 
 | 221 | if (string.IsNullOrEmpty(s)) | 
 
 
 
 
 | 222 | return false; | 
 
 
 
 
 | 223 |  | 
 
 
 
 
 | 224 | var tokens = s.Split(new char[0], StringSplitOptions.RemoveEmptyEntries); | 
 
 
 
 
 | 225 |  | 
 
 
 
 
 | 226 | if (tokens.Length < 3 || tokens.Length > 4) | 
 
 
 
 
 | 227 | return false; | 
 
 
 
 
 | 228 |  | 
 
 
 
 
 | 229 | if (!byte.TryParse(tokens[0], NumberStyles.Integer, CultureInfo.InvariantCulture, out color.r)) | 
 
 
 
 
 | 230 | return false; | 
 
 
 
 
 | 231 |  | 
 
 
 
 
 | 232 | if (!byte.TryParse(tokens[1], NumberStyles.Integer, CultureInfo.InvariantCulture, out color.g)) | 
 
 
 
 
 | 233 | return false; | 
 
 
 
 
 | 234 |  | 
 
 
 
 
 | 235 | if (!byte.TryParse(tokens[2], NumberStyles.Integer, CultureInfo.InvariantCulture, out color.b)) | 
 
 
 
 
 | 236 | return false; | 
 
 
 
 
 | 237 |  | 
 
 
 
 
 | 238 | if (tokens.Length > 3 && !byte.TryParse(tokens[3], NumberStyles.Integer, CultureInfo.InvariantCulture, out color.a)) | 
 
 
 
 
 | 239 | return false; | 
 
 
 
 
 | 240 |  | 
 
 
 
 
 | 241 | return true; | 
 
 
 
 
 | 242 | } | 
 
 
 
 
 | 243 |  | 
 
 
 
 
 | 244 | public static Color Parse(string s) | 
 
 
 
 
 | 245 | { | 
 
 
 
 
 | 246 | Color c; | 
 
 
 
 
 | 247 |  | 
 
 
 
 
 | 248 | if (!TryParse(s, out c)) | 
 
 
 
 
 | 249 | throw new FormatException(string.Format("'{0}' is not a color", s)); | 
 
 
 
 
 | 250 |  | 
 
 
 
 
 | 251 | return c; | 
 
 
 
 
 | 252 | } | 
 
 
 
 
 | 253 | } | 
 
 
 
 
 | 254 | } |