1 /* 2 * Copyright (c) 2017-2019 sel-project 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining a copy 5 * of this software and associated documentation files (the "Software"), to deal 6 * in the Software without restriction, including without limitation the rights 7 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 * copies of the Software, and to permit persons to whom the Software is 9 * furnished to do so, subject to the following conditions: 10 * 11 * The above copyright notice and this permission notice shall be included in all 12 * copies or substantial portions of the Software. 13 * 14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 * SOFTWARE. 21 * 22 */ 23 /** 24 * Copyright: Copyright (c) 2017-2019 sel-project 25 * License: MIT 26 * Authors: Kripth 27 * Source: $(HTTP github.com/sel-project/selery/source/selery/util/color.d, selery/util/color.d) 28 */ 29 module selery.util.color; 30 31 import std.conv : to; 32 33 /** 34 * Container for an rgba colour. 35 * Example: 36 * --- 37 * Color c = new Color(255, 0, 0); 38 * c.blue = 255; 39 * assert(c == new Color(255, 0, 255)); 40 * --- 41 */ 42 class Color { 43 44 public ubyte r, g, b, a; 45 46 alias red = this.r; 47 alias green = this.g; 48 alias blue = this.b; 49 alias alpha = this.a; 50 51 /** 52 * Constructs a colour using rgb(a) values (in range 0..255). 53 * By default alpha is 0% transparent (255). 54 */ 55 public pure nothrow @safe @nogc this(ubyte r, ubyte g, ubyte b, ubyte a=0xFF) { 56 this.r = r; 57 this.g = g; 58 this.b = b; 59 this.a = a; 60 } 61 62 /** 63 * Creates the average colour of the given one. 64 * Example: 65 * --- 66 * assert(new Color([new Color(200, 0, 0), new Color(0, 200, 0)]) == new Color(100, 100, 0)); 67 * --- 68 */ 69 public @safe this(Color[] colors) { 70 uint r, g, b, a; 71 foreach(Color color ; colors) { 72 r += color.r; 73 g += color.g; 74 b += color.b; 75 a += color.a; 76 } 77 this.r = to!ubyte(r / colors.length); 78 this.g = to!ubyte(g / colors.length); 79 this.b = to!ubyte(b / colors.length); 80 this.a = to!ubyte(a / colors.length); 81 } 82 83 /** 84 * Encodes the colour as an unsigned integer to 85 * be used in the network operations or to be saved. 86 */ 87 public pure nothrow @property @safe @nogc uint rgb() { 88 return (this.r << 16) | (this.g << 8) | this.b; 89 } 90 91 /// ditto 92 public pure nothrow @property @safe @nogc uint rgba() { 93 return (this.rgb << 8) | a; 94 } 95 96 /// ditto 97 public pure nothrow @property @safe @nogc uint argb() { 98 return (a << 24) | this.rgb; 99 } 100 101 /** 102 * Checks if the colour is completely transparent (with 103 * the alpha channel equals to 0). 104 * Example: 105 * --- 106 * assert(!new Color(0, 0, 0, 1).transparent); 107 * assert(Colors.TRANSPARENT.transparent); 108 * --- 109 */ 110 public pure nothrow @property @safe @nogc bool transparent() { 111 return this.alpha == 0; 112 } 113 114 /** 115 * Sets the colour as transparent (with alpha = 0) or 116 * opaque (with alpha = 255). 117 */ 118 public pure nothrow @property @safe @nogc bool transparent(bool transparent) { 119 return (this.alpha = (transparent ? 0 : 255)) == 0; 120 } 121 122 /** 123 * Compares two colours. 124 * Returns: true if red, green, blue an alpha are equals, false otherwise 125 */ 126 public override bool opEquals(Object o) { 127 if(cast(Color)o) { 128 Color c = cast(Color)o; 129 return this.r == c.r && this.g == c.g && this.b == c.b && this.a == c.a; 130 } 131 return false; 132 } 133 134 /** 135 * Converts and hexadecimal representation of a colour into 136 * a Color object. 137 * Returns: a Color object or null if the string's length is invalid 138 * Throws: 139 * ConvException if one of the string is not an hexadecimal number 140 * Example: 141 * --- 142 * assert(Color.fromString("00CC00").green == 204); 143 * assert(Color.fromString("123456").rgb == 0x123456); 144 * assert(Color.fromString("01F") == Color.fromString("0011FF")); 145 * --- 146 */ 147 public static pure @safe Color fromString(string c) { 148 if(c.length == 6) { 149 return new Color(to!ubyte(c[0..2], 16), to!ubyte(c[2..4], 16), to!ubyte(c[4..6], 16)); 150 } else if(c.length == 3) { 151 return fromString([c[0], c[0], c[1], c[1], c[2], c[2]].idup); 152 } else { 153 return null; 154 } 155 } 156 157 /** 158 * Converts an rgb-encoded integer to a Color. 159 * Example: 160 * --- 161 * assert(Color.fromRGB(0x0000FF).blue == 255); 162 * assert(Color.fromRGB(0x111111).green == 17); 163 * --- 164 */ 165 public static pure nothrow @safe Color fromRGB(uint c) { 166 return new Color((c >> 16) & 255, (c >> 8) & 255, c & 255); 167 } 168 169 } 170 171 /** 172 * Interface for object that have colours. 173 * Example: 174 * --- 175 * if(cast(Colorable)object) { 176 * object.to!Colorable.color = Color(1, 100, 5); 177 * } 178 * --- 179 */ 180 interface Colorable { 181 182 /** 183 * Gets the current colour. 184 * Example: 185 * --- 186 * if(object.color is null || object.color.transparent) { 187 * writeln("There's no colour!"); 188 * } 189 * --- 190 */ 191 public @property @safe Color color(); 192 193 /** 194 * Sets the colour for this object. 195 * Example: 196 * --- 197 * if(object.color is null) { 198 * object.color = Color.fromString("003311"); 199 * } 200 * --- 201 */ 202 public @property @safe Color color(Color color); 203 204 } 205 206 /** 207 * Useful collection of colours to be used for dying, choosing 208 * block's colours and colouring maps. 209 * Example: 210 * --- 211 * leatherHelmet.color = Colors.cocoa; 212 * 213 * world[0, 64, 0] = Blocks.wool[Colors.Wool.brown]; 214 * --- 215 */ 216 final class Colors { 217 218 @disable this(); 219 220 public static const(Color) transparent = new Color(0, 0, 0, 0); 221 222 public static const(Color) black = Color.fromRGB(0x191919); 223 public static const(Color) red = Color.fromRGB(0x993333); 224 public static const(Color) green = Color.fromRGB(0x667F33); 225 public static const(Color) cocoa = Color.fromRGB(0x664C33); 226 public static const(Color) lapis = Color.fromRGB(0x334CB2); 227 public static const(Color) purple = Color.fromRGB(0x7F3FB2); 228 public static const(Color) cyan = Color.fromRGB(0x4C7F99); 229 public static const(Color) lightGray = Color.fromRGB(0x999999); 230 public static const(Color) gray = Color.fromRGB(0x4C4C4C); 231 public static const(Color) pink = Color.fromRGB(0xF27FA5); 232 public static const(Color) lime = Color.fromRGB(0x7FCC19); 233 public static const(Color) yellow = Color.fromRGB(0xE5E533); 234 public static const(Color) blue = Color.fromRGB(0x6699D8); 235 public static const(Color) magenta = Color.fromRGB(0xB24CD8); 236 public static const(Color) orange = Color.fromRGB(0xD87F33); 237 public static const(Color) white = Color.fromRGB(0xFFFFFF); 238 239 enum Wool : ubyte { 240 241 white = 0, 242 orange = 1, 243 magenta = 2, 244 lightBlue = 3, 245 yellow = 4, 246 lime = 5, 247 pink = 6, 248 gray = 7, 249 lightGray = 8, 250 cyan = 9, 251 purple = 10, 252 blue = 11, 253 brown = 12, 254 green = 13, 255 red = 14, 256 black = 15 257 258 } 259 260 alias Carpet = Wool; 261 262 alias Sheep = Wool; 263 264 alias StainedClay = Wool; 265 266 alias StainedGlass = Wool; 267 268 }