1 module rip.color.rgb; 2 3 private 4 { 5 import std.math; 6 import std.string; 7 8 import rip.color.color; 9 import rip.rt.rgbCaching; 10 import rip.concepts.templates; 11 import rip.utils.staticFuncs; 12 } 13 14 /++ 15 Digital implementation of RGB color format. 16 +/ 17 class RGB : Color!(ubyte, 3) 18 { 19 protected 20 { 21 @property void R(T)(T value) { 22 super[0] = value; 23 } 24 25 @property void G(T)(T value) { 26 super[1] = value; 27 } 28 29 @property void B(T)(T value) { 30 super[2] = value; 31 } 32 33 @property auto R(T = ubyte)() const { 34 return super.getTypedByIndex!T(0); 35 } 36 37 @property auto G(T = ubyte)() const { 38 return super.getTypedByIndex!T(1); 39 } 40 41 @property auto B(T = ubyte)() const { 42 return super.getTypedByIndex!T(2); 43 } 44 } 45 46 /++ 47 + Parametrized ctor for working with any arithmetic types 48 + Params: 49 + red = red componemt 50 + green = green componemt 51 + blue = blue componemt 52 +/ 53 this(T, U, V)(T red, U green, V blue) 54 if (allArithmetic!(T, U, V)) 55 { 56 super(red, green, blue); 57 } 58 59 public static RGB getColor(T, U, V)(T red, U green, V blue) { 60 version(RgbCachingOn) { 61 if(useRgbCaching) 62 return rgbManager.getColor(red, green, blue); 63 } 64 65 return new RGB(red, green, blue); 66 } 67 68 public static RGB getColor(RGB color) { 69 version(RgbCachingOn) { 70 if(useRgbCaching) 71 return rgbManager.getColor(color); 72 } 73 74 return color; 75 } 76 77 /++ 78 Mixins for typed getter 79 +/ 80 alias red = R; 81 alias green = G; 82 alias blue = B; 83 84 /++ ditto +/ 85 mixin(addTypedGetter!("0.3f * R + 0.59f * G + 0.11f * B", "luminance")); 86 87 /++ 88 Funcs for changing components of color 89 +/ 90 alias setRed = R; 91 alias setGreen = G; 92 alias setBlue = B; 93 94 /++ 95 Params: 96 rhs = second color 97 Returns: 98 Distance between two colors in RGB space 99 +/ 100 T distance(T)(RGB rhs) 101 { 102 auto dRed = (this.red!float - rhs.red!float) ^^ 2; 103 auto dGreen = (this.green!float - rhs.green!float) ^^ 2; 104 auto dBlue = (this.blue!float - rhs.blue!float) ^^ 2; 105 106 return sqrt(dRed + dGreen + dBlue); 107 } 108 109 /++ 110 Arithmetic operations for colors 111 Params: 112 rhs = second color 113 +/ 114 RGB opBinary(string op)(auto ref RGB rhs) 115 { 116 RGB result; 117 118 static if (isGeneralOperation(op)) 119 { 120 mixin("result = RGB.getColor(" ~ 121 "this.red!ubyte " ~ op ~ " rhs.red!ubyte," ~ 122 "this.green!ubyte " ~ op ~ " rhs.green!ubyte," ~ 123 "this.blue!ubyte " ~ op ~ "rhs.blue!ubyte" ~ ");" 124 ); 125 } 126 else 127 { 128 mixin("result = RGB.getColor(" ~ 129 "this.red!long " ~ op ~ " rhs.red!long," ~ 130 "this.green!long " ~ op ~ " rhs.green!long," ~ 131 "this.blue!long " ~ op ~ "rhs.green!long" ~ ");" 132 ); 133 } 134 135 return result; 136 } 137 138 /++ ditto +/ 139 void opOpAssign(string op)(auto ref RGB rhs) 140 { 141 mixin("setChannels( 142 this.red!float " ~ op ~" rhs.red!float, 143 this.green!float " ~ op ~" rhs.green!float, 144 this.blue!float " ~ op ~" rhs.blue!float);"); 145 } 146 147 /++ 148 Arithmetic operations between color and arithmetic types 149 Params: 150 rhs = variable 151 +/ 152 RGB opBinary(string op, T)(auto ref T rhs) 153 if (allArithmetic!T) 154 { 155 RGB result; 156 157 static if (isGeneralOperation(op)) 158 { 159 mixin("result = RGB.getColor(" ~ 160 "this.red!float " ~ op ~ " cast(float) rhs," ~ 161 "this.green!float " ~ op ~ " cast(float) rhs," ~ 162 "this.blue!float " ~ op ~ " cast(float) rhs," ~ ");" 163 ); 164 } 165 else 166 { 167 mixin("result = RGB.getColor(" ~ 168 "this.red!long " ~ op ~ " cast(long) rhs," ~ 169 "this.green!long " ~ op ~ " cast(long) rhs," ~ 170 "this.blue!long " ~ op ~ "cast(long) rhs," ~ ");" 171 ); 172 } 173 174 return result; 175 } 176 177 /++ ditto +/ 178 RGB opBinaryRight(string op, T)(auto ref T rhs) 179 if (allArithmetic!T) 180 { 181 RGB result; 182 183 static if (isGeneralOperation(op)) 184 { 185 mixin("result = RGB.getColor(" ~ 186 "this.red!float " ~ op ~ " cast(float) rhs," ~ 187 "this.green!float " ~ op ~ " cast(float) rhs," ~ 188 "this.blue!float " ~ op ~ " cast(float) rhs," ~ ");" 189 ); 190 } 191 else 192 { 193 mixin("result = RGB.getColor(" ~ 194 "this.red!long " ~ op ~ " cast(long) rhs," ~ 195 "this.green!long " ~ op ~ " cast(long) rhs," ~ 196 "this.blue!long " ~ op ~ "cast(long) rhs," ~ ");" 197 ); 198 } 199 200 return result; 201 } 202 203 /++ 204 Gamma correction 205 Params: 206 coefficient = ... 207 power = ... 208 Returns: 209 Corrected color 210 +/ 211 RGB gamma(T, U)(T coefficient, U power) 212 if (allArithmetic!(T, U)) 213 { 214 auto red = cast(float) coefficient * ((this.red!float / 255.0) ^^ cast(float) power); 215 auto green = cast(float) coefficient * ((this.green!float / 255.0) ^^ cast(float) power); 216 auto blue = cast(float) coefficient * ((this.blue!float / 255.0) ^^ cast(float) power); 217 218 return RGB.getColor(red * 255.0, green * 255.0, blue * 255.0); 219 } 220 221 /++ 222 Logarithm of the color 223 Params: 224 base = base of logarithm 225 Returns: 226 New color - logarithm of the color 227 +/ 228 RGB log(T)(T base = cast(T) 2) 229 if (allArithmetic!(T, U)) 230 { 231 assert(base != 0); 232 auto red = (R == 0) ? 0 : log(this.red!float / 255.0) / log(cast(float) base); 233 auto green = (G == 0) ? 0 : log(this.green!float / 255.0) / log(cast(float) base); 234 auto blue = (B == 0) ? 0 : log(this.blue!float / 255.0) / log(cast(float) base); 235 236 return RGB.getColor(red * 255.0, green * 255.0, blue * 255.0); 237 } 238 239 /++ 240 Inversion 241 Returns: 242 New inverted color 243 +/ 244 RGB invert() 245 { 246 return RGB.getColor(255 - R, 255 - G, 255 - B); 247 } 248 249 /++ +/ 250 override string toString() 251 { 252 return format("RGB(%d, %d, %d)", R, G, B); 253 } 254 255 version(RgbCachingOn) { 256 257 static int getCached() { 258 return rgbManager.getCached; 259 } 260 261 } 262 } 263 264 alias RGBColor = RGB;