PageRenderTime 93ms CodeModel.GetById 34ms app.highlight 54ms RepoModel.GetById 2ms app.codeStats 0ms

/core/color.d

http://github.com/wilkie/djehuty
D | 449 lines | 357 code | 67 blank | 25 comment | 90 complexity | dff41e30c6446827c9162070724e6eb2 MD5 | raw file
  1/*
  2 * color.d
  3 *
  4 * This file has an implementation of a platform neutral Color datatype.
  5 *
  6 * Author: Dave Wilkinson
  7 *
  8 */
  9
 10module core.color;
 11
 12import platform.definitions;
 13
 14import core.definitions;
 15import core.parameters;
 16
 17import core.util;
 18
 19// Color
 20
 21
 22
 23static if (Colorbpp == Parameter_Colorbpp.Color8bpp) {
 24	alias ubyte ColorComponent;
 25	alias uint ColorValue;
 26}
 27else static if (Colorbpp == Parameter_Colorbpp.Color16bpp) {
 28	alias ushort ColorComponent;
 29	alias ulong ColorValue;
 30}
 31else {
 32	alias ubyte ColorComponent;
 33	alias uint ColorValue;
 34	pragma(msg, "WARNING: Colorbpp parameter is not set!");
 35}
 36
 37static if (ColorType == Parameter_ColorType.ColorRGBA) {
 38	align(1) struct _comps {
 39		ColorComponent r;
 40		ColorComponent g;
 41		ColorComponent b;
 42		ColorComponent a;
 43	}
 44}
 45else static if (ColorType == Parameter_ColorType.ColorBGRA) {
 46	align(1) struct _comps{
 47		ColorComponent b;
 48		ColorComponent g;
 49		ColorComponent r;
 50		ColorComponent a;
 51	}
 52}
 53else static if (ColorType == Parameter_ColorType.ColorABGR) {
 54	align(1) struct _comps {
 55		ColorComponent a;
 56		ColorComponent b;
 57		ColorComponent g;
 58		ColorComponent r;
 59	}
 60}
 61else static if (ColorType == Parameter_ColorType.ColorARGB) {
 62	align(1) struct _comps {
 63		ColorComponent a;
 64		ColorComponent r;
 65		ColorComponent g;
 66		ColorComponent b;
 67	}
 68}
 69else {
 70	align(1) struct _comps {
 71		ColorComponent r;
 72		ColorComponent g;
 73		ColorComponent b;
 74		ColorComponent a;
 75	}
 76	pragma(msg, "WARNING: ColorType parameter is not set!");
 77}
 78
 79
 80// a small function to convert an 8bpp value into
 81// the native bits per pixel (which is either 8bpp or 16bpp)
 82template _8toNativebpp(double comp) {
 83	const ColorComponent _8toNativebpp = cast(ColorComponent)(comp * cast(double)((1 << (ColorComponent.sizeof*8)) - 1));
 84}
 85
 86// Section: Types
 87
 88// Description: This abstracts a color type.  Internally, the structure is different for each platform depending on the native component ordering and the bits per pixel for the platform.
 89union Color {
 90public:
 91
 92	// -- Predefined values
 93
 94	// Description: Black!
 95	static const Color Black 		= { _internal: { components: {r: _8toNativebpp!(0.0), g: _8toNativebpp!(0.0), b: _8toNativebpp!(0.0), a: _8toNativebpp!(1.0) } } };
 96
 97	static const Color Green		= { _internal: { components: {r: _8toNativebpp!(0.0), g: _8toNativebpp!(1.0), b: _8toNativebpp!(0.0), a: _8toNativebpp!(1.0) } } };
 98	static const Color Red		= { _internal: { components: {r: _8toNativebpp!(1.0), g: _8toNativebpp!(0.0), b: _8toNativebpp!(0.0), a: _8toNativebpp!(1.0) } } };
 99	static const Color Blue 		= { _internal: { components: {r: _8toNativebpp!(0.0), g: _8toNativebpp!(0.0), b: _8toNativebpp!(1.0), a: _8toNativebpp!(1.0) } } };
100
101	static const Color Magenta 	= { _internal: { components: {r: _8toNativebpp!(1.0), g: _8toNativebpp!(0.0), b: _8toNativebpp!(1.0), a: _8toNativebpp!(1.0) } } };
102	static const Color Yellow 	= { _internal: { components: {r: _8toNativebpp!(1.0), g: _8toNativebpp!(1.0), b: _8toNativebpp!(0.0), a: _8toNativebpp!(1.0) } } };
103	static const Color Cyan 		= { _internal: { components: {r: _8toNativebpp!(0.0), g: _8toNativebpp!(1.0), b: _8toNativebpp!(1.0), a: _8toNativebpp!(1.0) } } };
104
105	static const Color DarkGreen		= { _internal: { components: {r: _8toNativebpp!(0.0), g: _8toNativebpp!(0.5), b: _8toNativebpp!(0.0), a: _8toNativebpp!(1.0) } } };
106	static const Color DarkRed		= { _internal: { components: {r: _8toNativebpp!(0.5), g: _8toNativebpp!(0.0), b: _8toNativebpp!(0.0), a: _8toNativebpp!(1.0) } } };
107	static const Color DarkBlue 		= { _internal: { components: {r: _8toNativebpp!(0.0), g: _8toNativebpp!(0.0), b: _8toNativebpp!(0.5), a: _8toNativebpp!(1.0) } } };
108
109	static const Color DarkMagenta 	= { _internal: { components: {r: _8toNativebpp!(0.5), g: _8toNativebpp!(0.0), b: _8toNativebpp!(0.5), a: _8toNativebpp!(1.0) } } };
110	static const Color DarkYellow 	= { _internal: { components: {r: _8toNativebpp!(0.5), g: _8toNativebpp!(0.5), b: _8toNativebpp!(0.0), a: _8toNativebpp!(1.0) } } };
111	static const Color DarkCyan 		= { _internal: { components: {r: _8toNativebpp!(0.0), g: _8toNativebpp!(0.5), b: _8toNativebpp!(0.5), a: _8toNativebpp!(1.0) } } };
112
113	static const Color DarkGray	= { _internal: { components: {r: _8toNativebpp!(0.5), g: _8toNativebpp!(0.5), b: _8toNativebpp!(0.5), a: _8toNativebpp!(1.0) } } };
114	static const Color Gray 		= { _internal: { components: {r: _8toNativebpp!(0.75), g: _8toNativebpp!(0.75), b: _8toNativebpp!(0.75), a: _8toNativebpp!(1.0) } } };
115
116	static const Color White 		= { _internal: { components: {r: _8toNativebpp!(1.0), g: _8toNativebpp!(1.0), b: _8toNativebpp!(1.0), a: _8toNativebpp!(1.0) } } };
117
118	// --
119
120	// Description: This function will set the color given the red, green, blue, and alpha components.
121	static Color fromRGBA(double r, double g, double b, double a) {
122		Color ret;
123		ret.red = r;
124		ret.green = g;
125		ret.blue = b;
126		ret.alpha = a;
127		return ret;
128	}
129
130	// Description: This function will set the color given the red, green, and blue components.
131	static Color fromRGB(double r, double g, double b) {
132		Color ret;
133		ret.red = r;
134		ret.green = g;
135		ret.blue = b;
136		ret.alpha = 1.0;
137		return ret;
138	}
139
140	// Description: This function will set the color given the hue, saturation, luminance, and alpha components.
141	static Color fromHSLA(double h, double s, double l, double a) {
142		Color ret;
143		ret.hue = h;
144		ret.sat = s;
145		ret.lum = l;
146		ret.alpha = a;
147		return ret;
148	}
149
150	// Description: This function will set the color given the hue, saturation, and luminance components.
151	static Color fromHSL(ubyte h, ubyte s, ubyte l) {
152		Color ret;
153		ret.hue = h;
154		ret.sat = s;
155		ret.lum = l;
156		ret.alpha = 1.0;
157		return ret;
158	}
159
160	double blue() {
161		static if (Colorbpp == Parameter_Colorbpp.Color8bpp) {
162			return cast(double)_internal.components.b / cast(double)0xFF;
163		}
164		else {
165			return cast(double)_internal.components.b / cast(double)0xFFFF;
166		}
167	}
168
169	void blue(double val) {
170		static if (Colorbpp == Parameter_Colorbpp.Color8bpp) {
171			_internal.components.b = cast(ubyte)(0xffp0 * val);
172		}
173		else {
174			_internal.components.b = cast(ubyte)(0xffffp0 * val);
175		}
176	}
177
178	double green() {
179		static if (Colorbpp == Parameter_Colorbpp.Color8bpp) {
180			return cast(double)_internal.components.g / cast(double)0xFF;
181		}
182		else {
183			return cast(double)_internal.components.g / cast(double)0xFFFF;
184		}
185	}
186
187	void green(ubyte val) {
188		static if (Colorbpp == Parameter_Colorbpp.Color8bpp) {
189			_internal.components.g = val;
190		}
191		else {
192			_internal.components.g = (cast(double)val / cast(double)0xFF) * 0xFFFF;
193		}
194	}
195
196	void green(double val) {
197		static if (Colorbpp == Parameter_Colorbpp.Color8bpp) {
198			_internal.components.g = cast(ubyte)(0xffp0 * val);
199		}
200		else {
201			_internal.components.g = cast(ubyte)(0xffffp0 * val);
202		}
203	}
204
205	double red() {
206		static if (Colorbpp == Parameter_Colorbpp.Color8bpp) {
207			return cast(double)_internal.components.r / cast(double)0xFF;
208		}
209		else {
210			return cast(double)_internal.components.r / cast(double)0xFFFF;
211		}
212	}
213
214	void red(ubyte val) {
215		static if (Colorbpp == Parameter_Colorbpp.Color8bpp) {
216			_internal.components.r = val;
217		}
218		else {
219			_internal.components.r = (cast(double)val / cast(double)0xFF) * 0xFFFF;
220		}
221	}
222
223	void red(double val) {
224		static if (Colorbpp == Parameter_Colorbpp.Color8bpp) {
225			_internal.components.r = cast(ubyte)(0xffp0 * val);
226		}
227		else {
228			_internal.components.r = cast(ubyte)(0xffffp0 * val);
229		}
230	}
231
232	double alpha() {
233		static if (Colorbpp == Parameter_Colorbpp.Color8bpp) {
234			return cast(double)_internal.components.a / cast(double)0xFF;
235		}
236		else {
237			return cast(double)_internal.components.a / cast(double)0xFFFF;
238		}
239	}
240
241	void alpha(double val) {
242		static if (Colorbpp == Parameter_Colorbpp.Color8bpp) {
243			_internal.components.a = cast(ubyte)(0xffp0 * val);
244		}
245		else {
246			_internal.components.a = cast(ubyte)(0xffffp0 * val);
247		}
248	}
249
250	void hue(double val) {
251		if (!_hslValid) {
252			_calculateHSL();
253		}
254		_hue = val;
255		_calculateFromHSL();
256	}
257
258	double hue() {
259		if (_hslValid) {
260			return _hue;
261		}
262		
263		_calculateHSL();
264		return _hue;
265	}
266
267	void sat(double val) {
268		if (!_hslValid) {
269			_calculateHSL();
270		}
271		_sat = val;
272		_calculateFromHSL();
273	}
274
275	double sat() {
276		if (_hslValid) {
277			return _sat;
278		}
279
280		_calculateHSL();
281		return _sat;
282	}
283
284	void lum(double val) {
285		if (!_hslValid) {
286			_calculateHSL();
287		}
288		_lum = val;
289		_calculateFromHSL();
290	}
291
292	double lum() {
293		if (_hslValid) {
294			return _lum;
295		}
296
297		_calculateHSL();
298		return _lum;
299	}
300
301	ColorValue value() {
302		return _internal.clr;
303	}
304
305private:
306
307	union internal {
308		_comps components;
309
310		ColorValue clr;
311	}
312
313	internal _internal;
314
315	// cache HSL values
316	bool _hslValid;
317	double _hue;
318	double _sat;
319	double _lum;
320
321	void _calculateFromHSL() {
322		if (_sat == 0) {
323			this.red = _lum;
324			this.blue = _lum;
325			this.green = _lum;
326			return;
327		}
328
329		double p;
330		double q;
331		if (_lum < 0.5) {
332			q = _lum * (1.0 + _sat);
333		}
334		else {
335			q = _lum + _sat - (_lum * _sat);
336		}
337
338		p = (2.0 * _lum) - q;
339
340		double[3] ctmp;
341
342		ctmp[0] = _hue + (1.0/3.0);
343		ctmp[1] = _hue;
344		ctmp[2] = _hue - (1.0/3.0);
345
346		for(size_t i = 0; i < 3; i++) {
347			if (ctmp[i] < 0) {
348				ctmp[i] += 1.0;
349			}
350			else if (ctmp[i] > 1) {
351				ctmp[i] -= 1.0;
352			}
353
354			if (ctmp[i] < (1.0 / 6.0)) {
355				ctmp[i] = p + ((q - p) * 6.0 * ctmp[i]);
356			}
357			else if (ctmp[i] < 0.5) {
358				ctmp[i] = q;
359			}
360			else if (ctmp[i] < (2.0 / 3.0)) {
361				ctmp[i] = p + (q - p) * ((2.0 / 3.0) - ctmp[i]) * 6.0;
362			}
363			else {
364				ctmp[i] = p;
365			}
366		}
367
368		this.red = ctmp[0];
369		this.green = ctmp[1];
370		this.blue = ctmp[2];
371	}
372
373	void _calculateHSL() {
374		// find min and max values
375
376		double min, max;
377		double r,g,b;
378		r = this.red;
379		g = this.green;
380		b = this.blue;
381
382		uint maxColor;
383
384		if (r<=g && r<=b) {
385			min = r;
386			if (g<b) {
387				max = b;
388				maxColor = 2;
389			}
390			else {
391				max = g;
392				maxColor = 1;
393			}
394		}
395		else if (g<=b && g<=r) {
396			min = g;
397			if (r<b) {
398				max = b;
399				maxColor = 2;
400			}
401			else {
402				max = r;
403				maxColor = 0;
404			}
405		}
406		else {
407			min = b;
408			if (r<g) {
409				max = g;
410				maxColor = 1;
411			}
412			else {
413				max = r;
414				maxColor = 0;
415			}
416		}
417
418		// find luminance
419		_lum = (max + min) * 0.5;
420
421		if (max == min) {
422			_sat = 0;
423			_hue = 0;
424			_hslValid = true;
425			return;
426		}
427
428		// find the saturation
429		if (_lum < 0.5) {
430			_sat = (max - min) / (max + min);
431		}
432		else {
433			_sat = (max - min) / (2.0 - max - min);
434		}
435
436		// find hue
437		if (maxColor == 0) {
438			_hue = (g - b) / (max - min);
439		}
440		else if (maxColor == 1){
441			_hue = 2.0 + (b - r) / (max - min);
442		}
443		else {
444			_hue = 4.0 + (r - g) / (max - min);
445		}
446		_hue /= 6.0;
447		_hslValid = true;
448	}
449}