1 module skia.SKColorF;
2 
3 import skia.Definitions;
4 import skia.SkiaApi;
5 import skia.SKColor;
6 
7 import std.algorithm;
8 import std.math;
9 
10 struct SKColorF
11 {
12 	enum float EPSILON = 0.001f;
13 
14 	enum SKColorF Empty = SKColorF(0, 0, 0, 0);
15 
16 	this(float red, float green, float blue)
17 	{
18 		fR = red;
19 		fG = green;
20 		fB = blue;
21 		fA = 1f;
22 	}
23 
24 	this(float red, float green, float blue, float alpha)
25 	{
26 		fR = red;
27 		fG = green;
28 		fB = blue;
29 		fA = alpha;
30 	}
31 
32 	// float fR
33 	private const float fR;
34 	const float Red() {
35         return fR;
36     }
37 
38 	// float fG
39 	private const float fG;
40 	const float Green() { 
41         return fG;
42     }
43 
44 	// float fB
45 	private const float fB;
46 	const float Blue() {
47         return fB;
48     }
49 
50 	// float fA
51 	private const float fA;
52 	const float Alpha() {
53         return fA;
54     }
55 
56 	// const bool Equals (SKColorF obj) {
57 	// 	return fR == obj.fR && fG == obj.fG && fB == obj.fB && fA == obj.fA
58 	// }
59 
60 	// const override bool Equals (object obj) {
61 	// 	return obj is SKColorF f && Equals (f)
62 	// }
63 
64 	// static bool operator == (SKColorF left, SKColorF right) {
65 	// 	return left.Equals (right)
66 	// }
67 
68 	// static bool operator != (SKColorF left, SKColorF right) {
69 	// 	return !left.Equals (right)
70 	// }
71 
72 	// const override int GetHashCode ()
73 	// {
74 	// 	var hash = new HashCode ();
75 	// 	hash.Add (fR);
76 	// 	hash.Add (fG);
77 	// 	hash.Add (fB);
78 	// 	hash.Add (fA);
79 	// 	return hash.ToHashCode ();
80 	// }
81 
82 	SKColorF WithRed(float red)
83 	{
84 		return SKColorF(red, fG, fB, fA);
85 	}
86 
87 	SKColorF WithGreen(float green)
88 	{
89 		return SKColorF(fR, green, fB, fA);
90 	}
91 
92 	SKColorF WithBlue(float blue)
93 	{
94 		return SKColorF(fR, fG, blue, fA);
95 	}
96 
97 	SKColorF WithAlpha(float alpha)
98 	{
99 		return SKColorF(fR, fG, fB, alpha);
100 	}
101 
102 	float Hue()
103 	{
104 		float h;
105 		float s;
106 		float v;
107 		ToHsv(h, s, v);
108 		return h;
109 	}
110 
111 	SKColorF Clamp()
112 	{
113 		return SKColorF(Clamp(fR), Clamp(fG), Clamp(fB), Clamp(fA));
114 
115 
116 	}
117 
118 	private static float Clamp(float v)
119 	{
120 		if (v > 1f)
121 			return 1f;
122 		if (v < 0f)
123 			return 0f;
124 		return v;
125 	}	
126 
127 	static SKColorF FromHsl(float h, float s, float l, float a = 1f)
128 	{
129 		// convert from percentages
130 		h = h / 360f;
131 		s = s / 100f;
132 		l = l / 100f;
133 
134 		// RGB results from 0 to 1
135 		auto r = l;
136 		auto g = l;
137 		auto b = l;
138 
139 		// HSL from 0 to 1
140 		if (abs(s) > EPSILON)
141 		{
142 			float v2;
143 			if (l < 0.5f)
144 				v2 = l * (1f + s);
145 			else
146 				v2 = (l + s) - (s * l);
147 
148 			auto v1 = 2f * l - v2;
149 
150 			r = HueToRgb(v1, v2, h + (1f / 3f));
151 			g = HueToRgb(v1, v2, h);
152 			b = HueToRgb(v1, v2, h - (1f / 3f));
153 		}
154 
155 		return SKColorF(r, g, b, a);
156 	}
157 
158 	private static float HueToRgb(float v1, float v2, float vH)
159 	{
160 		if (vH < 0f)
161 			vH += 1f;
162 		if (vH > 1f)
163 			vH -= 1f;
164 
165 		if ((6f * vH) < 1f)
166 			return (v1 + (v2 - v1) * 6f * vH);
167 		if ((2f * vH) < 1f)
168 			return (v2);
169 		if ((3f * vH) < 2f)
170 			return (v1 + (v2 - v1) * ((2f / 3f) - vH) * 6f);
171 		return (v1);
172 	}
173 
174 	static SKColorF FromHsv(float h, float s, float v, float a = 1f)
175 	{
176 		// convert from percentages
177 		h = h / 360f;
178 		s = s / 100f;
179 		v = v / 100f;
180 
181 		// RGB results from 0 to 1
182 		auto r = v;
183 		auto g = v;
184 		auto b = v;
185 
186 		// HSL from 0 to 1
187 		if (abs(s) > EPSILON)
188 		{
189 			h = h * 6f;
190 			if (abs(h - 6f) < EPSILON)
191 				h = 0f; // H must be < 1
192 
193 			int hInt = cast(int) h;
194 			auto v1 = v * (1f - s);
195 			auto v2 = v * (1f - s * (h - hInt));
196 			auto v3 = v * (1f - s * (1f - (h - hInt)));
197 
198 			if (hInt == 0)
199 			{
200 				r = v;
201 				g = v3;
202 				b = v1;
203 			}
204 			else if (hInt == 1)
205 			{
206 				r = v2;
207 				g = v;
208 				b = v1;
209 			}
210 			else if (hInt == 2)
211 			{
212 				r = v1;
213 				g = v;
214 				b = v3;
215 			}
216 			else if (hInt == 3)
217 			{
218 				r = v1;
219 				g = v2;
220 				b = v;
221 			}
222 			else if (hInt == 4)
223 			{
224 				r = v3;
225 				g = v1;
226 				b = v;
227 			}
228 			else
229 			{
230 				r = v;
231 				g = v1;
232 				b = v2;
233 			}
234 		}
235 
236 		return SKColorF(r, g, b, a);
237 	}
238 
239 	void ToHsl(ref float h, ref float s, ref float l)
240 	{
241 		// RGB from 0 to 1
242 		auto r = fR;
243 		auto g = fG;
244 		auto b = fB;
245 
246 		auto min = std.algorithm.min(std.algorithm.min(r, g), b); // min value of RGB
247 		auto max = std.algorithm.max(std.algorithm.max(r, g), b); // max value of RGB
248 		auto delta = max - min; // delta RGB value
249 
250 		// default to a gray, no chroma...
251 		h = 0f;
252 		s = 0f;
253 		l = (max + min) / 2f;
254 
255 		// chromatic data...
256 		if (abs(delta) > EPSILON)
257 		{
258 			if (l < 0.5f)
259 				s = delta / (max + min);
260 			else
261 				s = delta / (2f - max - min);
262 
263 			auto deltaR = (((max - r) / 6f) + (delta / 2f)) / delta;
264 			auto deltaG = (((max - g) / 6f) + (delta / 2f)) / delta;
265 			auto deltaB = (((max - b) / 6f) + (delta / 2f)) / delta;
266 
267 			if (abs(r - max) < EPSILON) // r == max
268 				h = deltaB - deltaG;
269 			else if (abs(g - max) < EPSILON) // g == max
270 				h = (1f / 3f) + deltaR - deltaB;
271 			else // b == max
272 				h = (2f / 3f) + deltaG - deltaR;
273 
274 			if (h < 0f)
275 				h += 1f;
276 			if (h > 1f)
277 				h -= 1f;
278 		}
279 
280 		// convert to percentages
281 		h = h * 360f;
282 		s = s * 100f;
283 		l = l * 100f;
284 	}
285 
286 	void ToHsv(ref float h, ref float s, ref float v)
287 	{
288 		// RGB from 0 to 1
289 		auto r = fR;
290 		auto g = fG;
291 		auto b = fB;
292 
293 		auto min = std.algorithm.min(std.algorithm.min(r, g), b); // min value of RGB
294 		auto max = std.algorithm.max(std.algorithm.max(r, g), b); // max value of RGB
295 		auto delta = max - min; // delta RGB value 
296 
297 		// default to a gray, no chroma...
298 		h = 0;
299 		s = 0;
300 		v = max;
301 
302 		// chromatic data...
303 		if (abs(delta) > EPSILON)
304 		{
305 			s = delta / max;
306 
307 			auto deltaR = (((max - r) / 6f) + (delta / 2f)) / delta;
308 			auto deltaG = (((max - g) / 6f) + (delta / 2f)) / delta;
309 			auto deltaB = (((max - b) / 6f) + (delta / 2f)) / delta;
310 
311 			if (abs(r - max) < EPSILON) // r == max
312 				h = deltaB - deltaG;
313 			else if (abs(g - max) < EPSILON) // g == max
314 				h = (1f / 3f) + deltaR - deltaB;
315 			else // b == max
316 				h = (2f / 3f) + deltaG - deltaR;
317 
318 			if (h < 0f)
319 				h += 1f;
320 			if (h > 1f)
321 				h -= 1f;
322 		}
323 
324 		// convert to percentages
325 		h = h * 360f;
326 		s = s * 100f;
327 		v = v * 100f;
328 	}
329 
330 	string ToString()
331 	{
332 		return (cast(SKColor) this).ToString();
333 	}
334 
335 	SKColor opCast(T)() if (is(T == SKColor))
336 	{
337 		return SKColor(SkiaApi.sk_color4f_to_color(&this));
338 	}
339 
340 }