1 /** 2 Color 3 4 Copyright: (c) Enalye 2017 5 License: Zlib 6 Authors: Enalye 7 */ 8 9 module atelier.core.color; 10 11 import std.math; 12 import std.typecons; 13 import std.random; 14 public import std.algorithm.comparison : clamp; 15 16 import bindbc.sdl; 17 18 import atelier.core.stream; 19 import atelier.core.vec3; 20 21 /// An RGB color structure. 22 struct Color { 23 /// Basic color. 24 static const Color red = Color(1f, 0f, 0f); 25 /// Ditto 26 static const Color lime = Color(0f, 1f, 0f); 27 /// Ditto 28 static const Color blue = Color(0f, 0f, 1f); 29 /// Ditto 30 static const Color white = Color(1f, 1f, 1f); 31 /// Ditto 32 static const Color black = Color(0f, 0f, 0f); 33 /// Ditto 34 static const Color yellow = Color(1f, 1f, 0f); 35 /// Ditto 36 static const Color cyan = Color(0f, 1f, 1f); 37 /// Ditto 38 static const Color magenta = Color(1f, 0f, 1f); 39 /// Ditto 40 static const Color silver = Color(.75f, .75f, .75f); 41 /// Ditto 42 static const Color gray = Color(.5f, .5f, .5f); 43 /// Ditto 44 static const Color grey = Color(.5f, .5f, .5f); 45 /// Ditto 46 static const Color maroon = Color(.5f, 0f, 0f); 47 /// Ditto 48 static const Color olive = Color(.5f, .5f, 0f); 49 /// Ditto 50 static const Color green = Color(0f, .5f, 0f); 51 /// Ditto 52 static const Color purple = Color(.5f, 0f, .5f); 53 /// Ditto 54 static const Color teal = Color(.5f, 0f, .5f); 55 /// Ditto 56 static const Color navy = Color(0f, 0f, .5f); 57 /// Ditto 58 static const Color pink = Color(1f, .75f, .8f); 59 /// Ditto 60 static const Color orange = Color(1f, .65f, 0f); 61 62 static @property { 63 /// Random RGB color. 64 Color random() { 65 return Color(uniform01(), uniform01(), uniform01()); 66 } 67 } 68 69 static { 70 /// Take a 0xFFFFFF color format. 71 Color fromHex(int rgbValue) { 72 return Color((rgbValue >> 16) & 0xFF, (rgbValue >> 8) & 0xFF, rgbValue & 0xFF); 73 } 74 } 75 76 @property { 77 /// Red component, between 0 and 1. 78 float r() const { 79 return _r; 80 } 81 /// Ditto 82 float r(float red) { 83 return _r = clamp(red, 0f, 1f); 84 } 85 86 /// Green component, between 0 and 1. 87 float g() const { 88 return _g; 89 } 90 /// Ditto 91 float g(float green) { 92 return _g = clamp(green, 0f, 1f); 93 } 94 95 /// Blue component, between 0 and 1. 96 float b() const { 97 return _b; 98 } 99 /// Ditto 100 float b(float blue) { 101 return _b = clamp(blue, 0f, 1f); 102 } 103 104 /// Convert to Vec3 105 Vec3f rgb() const { 106 return Vec3f(_r, _g, _b); 107 } 108 /// Convert from Vec3 109 Vec3f rgb(Vec3f v) { 110 set(v.x, v.y, v.z); 111 return v; 112 } 113 } 114 115 private { 116 float _r = 0f, _g = 0f, _b = 0f; 117 } 118 119 /// Sets the RGB values, between 0 and 1. 120 this(float red, float green, float blue) { 121 _r = clamp(red, 0f, 1f); 122 _g = clamp(green, 0f, 1f); 123 _b = clamp(blue, 0f, 1f); 124 } 125 126 /// Sets the RGB values, between 0 and 1. 127 this(Vec3f v) { 128 _r = clamp(v.x, 0f, 1f); 129 _g = clamp(v.y, 0f, 1f); 130 _b = clamp(v.z, 0f, 1f); 131 } 132 133 /// Sets the RGB values, between 0 and 255. 134 this(int red, int green, int blue) { 135 _r = clamp(red, 0, 255) / 255f; 136 _g = clamp(green, 0, 255) / 255f; 137 _b = clamp(blue, 0, 255) / 255f; 138 } 139 140 /// Sets the RGB values, between 0 and 1. 141 void set(float red, float green, float blue) { 142 _r = clamp(red, 0f, 1f); 143 _g = clamp(green, 0f, 1f); 144 _b = clamp(blue, 0f, 1f); 145 } 146 147 /// Sets the RGB values, between 0 and 255. 148 void set(int red, int green, int blue) { 149 _r = clamp(red, 0, 255) / 255f; 150 _g = clamp(green, 0, 255) / 255f; 151 _b = clamp(blue, 0, 255) / 255f; 152 } 153 154 /// Binary operations 155 Color opBinary(string op)(const Color c) const { 156 return mixin("Color(_r " ~ op ~ " c._r, _g " ~ op ~ " c._g, _b " ~ op ~ " c._b)"); 157 } 158 159 /// Binary operations 160 Color opBinary(string op)(float s) const { 161 return mixin("Color(_r " ~ op ~ " s, _g " ~ op ~ " s, _b " ~ op ~ " s)"); 162 } 163 164 /// Binary operations 165 Color opBinaryRight(string op)(float s) const { 166 return mixin("Color(s " ~ op ~ " _r, s " ~ op ~ " _g, s " ~ op ~ " _b)"); 167 } 168 169 /// Binary operations 170 Color opOpAssign(string op)(const Color c) { 171 mixin(" 172 _r = clamp(_r " ~ op ~ "c._r, 0f, 1f); 173 _g = clamp(_g " ~ op 174 ~ "c._g, 0f, 1f); 175 _b = clamp(_b " ~ op ~ "c._b, 0f, 1f); 176 "); 177 return this; 178 } 179 180 /// Assignment 181 Color opOpAssign(string op)(float s) { 182 mixin("s = clamp(s, 0f, 1f);_r = _r" ~ op ~ "s;_g = _g" ~ op ~ "s;_b = _b" ~ op ~ "s;"); 183 return this; 184 } 185 186 /// Read from an InStream. 187 void load(InStream stream) { 188 _r = stream.read!float; 189 _g = stream.read!float; 190 _b = stream.read!float; 191 } 192 193 /// Write to an OutStream. 194 void save(OutStream stream) { 195 stream.write!float(_r); 196 stream.write!float(_g); 197 stream.write!float(_b); 198 } 199 200 /// Get the SDL struct format for colors. 201 SDL_Color toSDL() const { 202 SDL_Color sdlColor = { 203 cast(ubyte)(_r * 255f), cast(ubyte)(_g * 255f), cast(ubyte)(_b * 255f) 204 }; 205 return sdlColor; 206 } 207 } 208 209 /// Mix 50% of one color with 50% of another. 210 Color mix(Color c1, Color c2) { 211 return Color((c1._r + c2._r) / 2f, (c1._g + c2._g) / 2f, (c1._b + c2._b) / 2f); 212 }