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;