root/trunk/helix/color.d

Revision 7, 32.6 kB (checked in by nail, 6 years ago)

Added isSigned, isUnsigned templates to basic.d
Removed silly assert(0) from color.d unittest

Line 
1 /*
2 Redistribution and use in source and binary forms, with or without
3 modification, are permitted provided that the following conditions
4 are met:
5
6     Redistributions of source code must retain the above copyright
7     notice, this list of conditions and the following disclaimer.
8
9     Redistributions in binary form must reproduce the above
10     copyright notice, this list of conditions and the following
11     disclaimer in the documentation and/or other materials provided
12     with the distribution.
13
14     Neither name of Victor Nakoryakov nor the names of
15     its contributors may be used to endorse or promote products
16     derived from this software without specific prior written
17     permission.
18
19 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
22 FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
23 REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
24 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
25 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26 SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
28 STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
30 OF THE POSSIBILITY OF SUCH DAMAGE.
31
32 Copyright (C) 2006. Victor Nakoryakov.
33 */
34 /**
35 Module with classes and functions for working with _color values.
36
37 There are structs for representation Red Green Blue _color (Color3),
38 RGB+Alpha _color (Color4) and Hue Saturation Luminance triple (HSL).
39
40 All components of those structs are float values, not integers.
41 Rationale is that under different circumstances it is necessary to
42 work with different standards of integer representation. Frequently
43 one byte-wise integer layout needed for one API and another for second.
44 One can require XRGB order, another BGRA. So it's better to operate with
45 floats and to convert them to integer just when it is necessary.
46
47 Normal range for float components' values is [0; 1]. Normal range for integer
48 values is [0; 255] for Color3 and Color4, and [0; 240] for HSL. Each struct
49 has several methods to convert native float representation to integer and
50 back.
51
52 Authors:
53     Victor Nakoryakov, nail-mail[at]mail.ru
54 */
55
56 module helix.color;
57
58 private import helix.basic,
59                helix.config;
60
61 /** Defines bytes orders for float to uint conversions. */
62 enum ByteOrder
63 {
64     XRGB,        ///
65     XBGR,        /// ditto
66     RGBX,        /// ditto
67     BGRX,        /// ditto
68     ARGB = XRGB, /// ditto
69     ABGR = XBGR, /// ditto
70     RGBA = RGBX, /// ditto
71     BGRA = BGRX  /// ditto
72 }
73
74 /**
75 Wrapper template to provide possibility to use different float types
76 in implemented structs and routines.
77 */
78 private template Color(float_t)
79 {
80     private alias helix.basic.clampBelow  clampBelow;
81     private alias helix.basic.clampAbove  clampAbove;
82     private alias helix.basic.clamp       clamp;
83     private alias helix.basic.equal       equal;
84
85     private alias .Color!(float).HSL      HSLf;
86     private alias .Color!(float).Color3   Color3f;
87     private alias .Color!(float).Color4   Color4f;
88
89     private alias .Color!(double).HSL     HSLd;
90     private alias .Color!(double).Color3  Color3d;
91     private alias .Color!(double).Color4  Color4d;
92
93     private alias .Color!(real).HSL       HSLr;
94     private alias .Color!(real).Color3    Color3r;
95     private alias .Color!(real).Color4    Color4r;
96
97     private static const float_t rgbK = 255;
98     private static const float_t hslK = 240;
99
100     /************************************************************************************
101     Hue, Saturation, Luminance triple.
102     *************************************************************************************/
103     struct HSL
104     {
105         float_t h; /// Hue.
106         float_t s; /// Saturation.
107         float_t l; /// Luminance.
108
109         /**
110         Method to construct struct in C-like syntax.
111
112         Examples:
113         ------------
114         HSL hsl = HSL(0.1, 0.2, 0.3);
115         ------------
116         */
117         static HSL opCall(float_t h, float_t s, float_t l)
118         {
119             HSL hsl;
120             hsl.set(h, s, l);
121             return hsl;
122         }
123
124         /** Sets components to values of passed arguments. */
125         void set(float_t h, float_t s, float_t l)
126         {
127             this.h = h;
128             this.s = s;
129             this.l = l;
130         }
131
132         /** Returns: Integer value of corresponding component in range [0; 240]. */
133         uint hi()
134         {
135             return cast(uint)(h * hslK);
136         }
137
138         /** ditto */
139         uint si()
140         {
141             return cast(uint)(s * hslK);
142         }
143
144         /** ditto */
145         uint li()
146         {
147             return cast(uint)(l * hslK);
148         }
149
150         /**
151         Set components to values of passed arguments. It is assumed that values of
152         arguments are in range [0; 240].
153         */
154         void hi(uint h)
155         {
156             this.h = cast(float_t)h / hslK;
157         }
158
159         /** ditto */
160         void si(uint s)
161         {
162             this.s = cast(float_t)s / hslK;
163         }
164
165         /** ditto */
166         void li(uint l)
167         {
168             this.l = cast(float_t)l / hslK;
169         }
170
171         /** Component-wise equality operator. */
172         bool opEquals(HSL hsl)
173         {
174             return h == hsl.h && s == hsl.s && l == hsl.l;
175         }
176
177         /** Returns: Color3 representing the same color as this triple. */
178         Color3 toColor3()
179         {
180             const short rgbMax = cast(short)rgbK;
181             const short hslMax = cast(short)hslK;
182             short HueToRGB(short n1, short n2, short hue)
183             {
184                 // range check: note values passed add/subtract thirds of range
185                 if (hue < 0)
186                     hue += hslMax;
187
188                 if (hue > hslMax)
189                     hue -= hslMax;
190
191                 // return r,g, or b value from this tridrant
192                 if (hue < hslMax / 6)
193                     return n1 + ((n2 - n1) * hue + hslMax / 12) / (hslMax / 6);
194                 if (hue < hslMax / 2)
195                     return n2;
196                 if (hue < hslMax * 2 / 3)
197                     return n1 + ((n2 - n1) * ((hslMax * 2/3) - hue) + (hslMax / 12)) / (hslMax / 6);
198                 else
199                     return n1;
200             }
201
202             short hue = cast(short)hi;
203             short lum = cast(short)li;
204             short sat = cast(short)si;
205             short magic1, magic2; // calculated magic numbers
206
207             Color3 ret;
208
209             if (sat == 0) // achromatic case
210             {
211                 ret.set(l, l, l);
212             }
213             else // chromatic case
214             {
215                 // set up magic numbers
216                 if (lum <= hslMax / 2)
217                     magic2 = (lum * (hslMax + sat) + hslMax / 2) / hslMax;
218                 else
219                     magic2 = lum + sat - (lum * sat + hslMax / 2) / hslMax;
220
221                 magic1 = 2 * lum - magic2;
222
223                 // get RGB, change units from hslMax to [0; 1] range
224                 ret.r = cast(float_t)(HueToRGB(magic1, magic2, hue + (hslMax / 3)) * rgbMax + hslMax / 2) / hslK / rgbK;
225                 ret.g = cast(float_t)(HueToRGB(magic1, magic2, hue) * rgbMax + hslMax / 2) / hslK / rgbK;
226                 ret.b = cast(float_t)(HueToRGB(magic1, magic2, hue - (hslMax / 3)) * rgbMax + hslMax / 2) / hslK / rgbK;
227             }
228
229             return ret;
230         }
231     }
232
233     /**
234     Approximate equality function.
235     Params:
236         relprec, absprec = Parameters passed to equal function while calculations.
237                            Have the same meaning as in equal function.
238     */
239     bool equal(HSL a, HSL b, int relprec = defrelprec, int absprec = defabsprec)
240     {
241         HSL c;
242         c.set(a.h - b.h, a.s - b.s, a.l - b.l);
243         return .equal(c.h * c.h + c.s * c.s + c.l * c.l, 0, relprec, absprec);
244     }
245
246     /************************************************************************************
247     Red, Green, Blue triple.
248     *************************************************************************************/
249     struct Color3
250     {
251         align(1)
252         {
253             float_t r; /// Red.
254             float_t g; /// Green.
255             float_t b; /// Blue.
256         }
257
258         /// Color3 with all components seted to NaN.
259         static Color3 nan = { float_t.nan, float_t.nan, float_t.nan };
260
261         /**
262         Method to construct color in C-like syntax.
263
264         Examples:
265         ------------
266         Color3 c = Color3(0.1, 0.2, 0.3);
267         ------------
268         */
269         static Color3 opCall(float_t r, float_t g, float_t b)
270         {
271             Color3 v;
272             v.set(r, g, b);
273             return v;
274         }
275
276         /**
277         Method to construct color in C-like syntax from value specified
278         in uint parameter.
279
280         Params:
281             src     = uint to extract value from.
282             order   = specifies byte-wise _order in src.
283
284         Examples:
285         ------------
286         Color3 c = Color3(0x00FFEEDD, ByteOrder.XRGB);
287         ------------
288         */
289         static Color3 opCall(uint src, ByteOrder order)
290         {
291             Color3 v;
292             v.set(src, order);
293             return v;
294         }
295
296         /** Sets components to values of passed arguments. */
297         void set(float_t r, float_t g, float_t b)
298         {
299             this.r = r;
300             this.g = g;
301             this.b = b;
302         }
303
304         /**
305         Sets components according to color packed in src uint argument.
306
307         Params:
308             src     = uint to extract value from.
309             order   = specifies byte-wise component layout in src.
310         */
311         void set(uint src, ByteOrder order = ByteOrder.XRGB)
312         {
313             switch (order)
314             {
315                 case ByteOrder.XRGB:
316                     ri = (src & 0x00FF0000) >> 16;
317                     gi = (src & 0x0000FF00) >> 8;
318                     bi = (src & 0x000000FF) >> 0;
319                     break;
320
321                 case ByteOrder.XBGR:
322                     bi = (src & 0x00FF0000) >> 16;
323                     gi = (src & 0x0000FF00) >> 8;
324                     ri = (src & 0x000000FF) >> 0;
325                     break;
326
327                 case ByteOrder.RGBX:
328                     ri = (src & 0xFF000000) >>> 24;
329                     gi = (src & 0x00FF0000) >>> 16;
330                     bi = (src & 0x0000FF00) >>> 8;
331                     break;
332
333                 case ByteOrder.BGRX:
334                     bi = (src & 0xFF000000) >>> 24;
335                     gi = (src & 0x00FF0000) >>> 16;
336                     ri = (src & 0x0000FF00) >>> 8;
337                     break;
338             }
339         }
340
341         /** Returns: Whether all components are normalized numbers. */
342         bool isnormal()
343         {
344             return std.math.isnormal(r) && std.math.isnormal(g) && std.math.isnormal(b);
345         }
346
347         /**
348         Returns: Integer value of corresponding component.
349
350         Float value 0 is mapped to integer 0. Float value 1 is mapped to
351         integer 255.
352         */
353         int ri()
354         {
355             return cast(int)(r * rgbK);
356         }
357
358         /** ditto */
359         int gi()
360         {
361             return cast(int)(g * rgbK);
362         }
363
364         /** ditto */
365         int bi()
366         {
367             return cast(int)(b * rgbK);
368         }
369
370         /**
371         Sets corresponding component value to mapped value of passed argument.
372
373         Integer value 0 is mapped to float 0. Integer value 255 is mapped to
374         float 1.
375         */
376         void ri(int r)
377         {
378             this.r = cast(float_t)r / rgbK;
379         }
380
381         /** ditto */
382         void gi(int g)
383         {
384             this.g = cast(float_t)g / rgbK;
385         }
386
387         /** ditto */
388         void bi(int b)
389         {
390             this.b = cast(float_t)b / rgbK;
391         }
392
393         /**
394         Returns:
395             This color packed to uint.
396         Params:
397             order = specifies byte-wise component layout in src.
398         Throws:
399             AssertError if any component is out of range [0; 1] and module was
400             compiled with asserts.
401         */
402         uint toUint(ByteOrder order)
403         {
404             assert(ri >= 0 && ri < 256);
405             assert(gi >= 0 && gi < 256);
406             assert(bi >= 0 && bi < 256);
407
408             switch (order)
409             {
410                 case ByteOrder.XRGB: return (ri << 16) | (gi <<  8) | (bi << 0);
411                 case ByteOrder.XBGR: return (bi << 16) | (gi <<  8) | (ri << 0);
412                 case ByteOrder.RGBX: return (ri << 24) | (gi << 16) | (bi << 8);
413                 case ByteOrder.BGRX: return (bi << 24) | (gi << 16) | (ri << 8);
414             }
415
416             return 0;
417         }
418
419         /**
420         Returns:
421             HSL triple representing same color as this.
422         */
423         HSL toHSL()
424         {
425             const short hslMax = cast(short)hslK;
426             const short rgbMax = cast(short)rgbK;
427
428             ubyte h, s, l;
429             ubyte cMax, cMin;                // max and min RGB values
430             short rDelta, gDelta, bDelta;    // intermediate value: % of spread from max
431
432             // get R, G, and B out of DWORD
433             short r = ri;
434             short g = gi;
435             short b = bi;
436
437             // calculate lightness
438             cMax = max(max(r, g), b);
439             cMin = min(min(r, g), b);
440             l = ((cMax + cMin) * hslMax + rgbMax) / (2 * rgbMax);
441
442             if (cMax == cMin)                // r = g = b --> achromatic case
443             {
444                 h = s = 0;
445             }
446             else
447             {                                // chromatic case
448                 // saturation
449                 if (l <= hslMax / 2)
450                     s = ((cMax - cMin) * hslMax + (cMax + cMin) / 2) / (cMax + cMin);
451                 else
452                     s = ((cMax - cMin) * hslMax + (2 * rgbMax - cMax - cMin) / 2) / (2 * rgbMax - cMax - cMin);
453
454                 // hue
455                 rDelta = ((cMax - r) * (hslMax / 6) + (cMax - cMin) / 2) / (cMax - cMin);
456                 gDelta = ((cMax - g) * (hslMax / 6) + (cMax - cMin) / 2) / (cMax - cMin);
457                 bDelta = ((cMax - b) * (hslMax / 6) + (cMax - cMin) / 2) / (cMax - cMin);
458
459                 if (r == cMax)
460                     h = bDelta - gDelta;
461                 else if (g == cMax)
462                     h = (hslMax / 3) + rDelta - bDelta;
463                 else // B == cMax
464                     h = (2 * hslMax) / 3 + gDelta - rDelta;
465
466                 if(h < 0)
467                     h += hslMax;
468
469                 if(h > hslMax)
470                     h -= hslMax;
471             }
472
473             HSL ret;
474             ret.hi = h;
475             ret.si = s;
476             ret.li = l;
477             return ret;
478         }
479
480         /** Returns: float_t pointer to r component of this color. It's like a _ptr method for arrays. */
481         float_t* ptr()
482         {
483             return cast(float_t*)this;
484         }
485
486         /**
487         Standard operators that have meaning exactly the same as for Vector3, i.e. do
488         component-wise operations.
489
490         Note that division operators do no cheks of value of k, so in case of division
491         by 0 result vector will have infinity components. You can check this with isnormal()
492         method.
493         */
494         bool opEquals(Color3 v)
495         {
496             return r == v.r && g == v.g && b == v.b;
497         }
498
499         /** ditto */
500         Color3 opNeg()
501         {
502             return Color3(-r, -g, -b);
503         }
504
505         /** ditto */
506         Color3 opAdd(Color3 v)
507         {
508             return Color3(r + v.r, g + v.g, b + v.b);
509         }
510
511         /** ditto */
512         void opAddAssign(Color3 v)
513         {
514             r += v.r;
515             g += v.g;
516             b += v.b;
517         }
518
519         /** ditto */
520         Color3 opSub(Color3 v)
521         {
522             return Color3(r - v.r, g - v.g, b - v.b);
523         }
524
525         /** ditto */
526         void opSubAssign(Color3 v)
527         {
528             r -= v.r;
529             g -= v.g;
530             b -= v.b;
531         }
532
533         /** ditto */
534         Color3 opMul(real k)
535         {
536             return Color3(r * k, g * k, b * k);
537         }
538
539         /** ditto */
540         void opMulAssign(real k)
541         {
542             r *= k;
543             g *= k;
544             b *= k;
545         }
546
547         /** ditto */
548         Color3 opMulr(real k)
549         {
550             return Color3(r * k, g * k, b * k);
551         }
552
553         /** ditto */
554         Color3 opDiv(real k)
555         {
556             return Color3(r / k, g / k, b / k);
557         }
558
559         /** ditto */
560         void opDivAssign(real k)
561         {
562             r /= k;
563             g /= k;
564             b /= k;
565         }
566
567         /** Sets all components less than inf to inf. */
568         void clampBelow(float_t inf = 0)
569         {
570             .clampBelow(r, inf);
571             .clampBelow(g, inf);
572             .clampBelow(b, inf);
573         }
574
575         /** Returns: Copy of this color with all components less than inf seted to inf. */
576         Color3 clampedBelow(float_t inf = 0)
577         {
578             Color3 ret = *this;
579             ret.clampBelow(inf);
580             return ret;
581         }
582
583         /** Sets all components greater than sup to sup. */
584         void clampAbove(float_t sup = 1)
585         {
586             .clampAbove(r, sup);
587             .clampAbove(g, sup);
588             .clampAbove(b, sup);
589         }
590
591         /** Returns: Copy of this color with all components greater than sup seted to sup. */
592         Color3 clampedAbove(float_t sup = 1)
593         {
594             Color3 ret = *this;
595             ret.clampBelow(sup);
596             return ret;
597         }
598
599         /**
600         Sets all components less than inf to inf and
601         all components greater than sup to sup.
602         */
603         void clamp(float_t inf = 0, float_t sup = 1)
604         {
605             clampBelow(inf);
606             clampAbove(sup);
607         }
608
609         /**
610         Returns:
611             Copy of this color with all components less than inf seted to inf
612             and all components greater than sup seted to sup.
613         */
614         Color3 clamped(float_t inf = 0, float_t sup = 1)
615         {
616             Color3 ret = *this;
617             ret.clamp(inf, sup);
618             return ret;
619         }
620
621         /** Returns: Copy of this color with float type components. */
622         Color3f toColor3f()
623         {
624             return Color3f(cast(float)r, cast(float)g, cast(float)b);
625         }
626
627         /** Returns: Copy of this color with double type components. */
628         Color3d toColor3d()
629         {
630             return Color3d(cast(double)r, cast(double)g, cast(double)b);
631         }
632
633         /** Returns: Copy of this color with real type components. */
634         Color3r toColor3r()
635         {
636             return Color3r(cast(real)r, cast(real)g, cast(real)b);
637         }
638
639         /**
640         Routines known as swizzling.
641         Returns:
642             New color constructed from this one and having component values
643             that correspond to method name.
644         */
645         Color4 rgb0()    { return Color4(r, g, b, 0); }
646         Color4 rgb1()    { return Color4(r, g, b, 1); } /// ditto
647     }
648
649     /**
650     Approximate equality function.
651     Params:
652         relprec, absprec = Parameters passed to equal function while calculations.
653                            Have the same meaning as in equal function.
654     */
655     bool equal(Color3 a, Color3 b, int relprec = defrelprec, int absprec = defabsprec)
656     {
657         Color3 c = a - b;
658         return .equal(c.r * c.r + c.g * c.g + c.b * c.b, 0, relprec, absprec);
659     }
660
661     alias Lerp!(Color3).lerp lerp; /// Introduces linear interpolation function for Color3.
662
663
664     /************************************************************************************
665     Red, Green, Blue triple with additional Alpha component.
666     *************************************************************************************/
667     struct Color4
668     {
669         align(1)
670         {
671             float_t r; /// Red.
672             float_t g; /// Green.
673             float_t b; /// Blue.
674             float_t a; /// Alpha.
675         }
676
677         /// Color4 with all components seted to NaN.
678         static Color4 nan = { float_t.nan, float_t.nan, float_t.nan, float_t.nan };
679
680         /**
681         Methods to construct color in C-like syntax.
682
683         Examples:
684         ------------
685         Color4 c1 = Color4(0.1, 0.2, 0.3, 1);
686         Color3 rgb = Color3(0, 0, 0.5);
687         Color4 c2 = Color4(rgb, 1);
688         ------------
689         */
690         static Color4 opCall(float_t r, float_t g, float_t b, float_t a)
691         {
692             Color4 v;
693             v.set(r, g, b, a);
694             return v;
695         }
696
697         /** ditto */
698         static Color4 opCall(Color3 rgb, float_t a = 1)
699         {
700             Color4 v;
701             v.set(rgb, a);
702             return v;
703         }
704
705
706         /**
707         Method to construct color in C-like syntax from value specified
708         in uint parameter.
709
710         Params:
711             src     = uint to extract value from.
712             order   = specifies byte-wise _order in src.
713
714         Examples:
715         ------------
716         Color4 c = Color4(0x99FFEEDD, ByteOrder.ARGB);
717         ------------
718         */
719         static Color4 opCall(uint src, ByteOrder order)
720         {
721             Color4 v;
722             v.set(src, order);
723             return v;
724         }
725
726
727         /** Set components to values of passed arguments. */
728         void set(float_t r, float_t g, float_t b, float_t a)
729         {
730             this.r = r;
731             this.g = g;
732             this.b = b;
733             this.a = a;
734         }
735
736         /** ditto */
737         void set(Color3 rgb, float_t a)
738         {
739             this.rgb = rgb;
740             this.a = a;
741         }
742
743
744         /**
745         Sets components according to color packed in src uint argument.
746
747         Params:
748             src     = uint to extract value from.
749             order   = specifies byte-wise layout in src.
750         */
751         void set(uint src, ByteOrder order = ByteOrder.ARGB)
752         {
753             switch (order)
754             {
755                 case ByteOrder.ARGB:
756                     ai = (src & 0xFF000000) >>> 24;
757                     ri = (src & 0x00FF0000) >>> 16;
758                     gi = (src & 0x0000FF00) >>> 8;
759                     bi = (src & 0x000000FF) >>> 0;
760                     break;
761
762                 case ByteOrder.ABGR:
763                     ai = (src & 0xFF000000) >>> 24;
764                     bi = (src & 0x00FF0000) >>> 16;
765                     gi = (src & 0x0000FF00) >>> 8;
766                     ri = (src & 0x000000FF) >>> 0;
767                     break;
768
769                 case ByteOrder.RGBA:
770                     ri = (src & 0xFF000000) >>> 24;
771                     gi = (src & 0x00FF0000) >>> 16;
772                     bi = (src & 0x0000FF00) >>> 8;
773                     ai = (src & 0x000000FF) >>> 0;
774                     break;
775
776                 case ByteOrder.BGRA:
777                     bi = (src & 0xFF000000) >>> 24;
778                     gi = (src & 0x00FF0000) >>> 16;
779                     ri = (src & 0x0000FF00) >>> 8;
780                     ai = (src & 0x000000FF) >>> 0;
781                     break;
782             }
783         }
784
785         /** Returns: Whether all components are normalized numbers. */
786         bool isnormal()
787         {
788             return std.math.isnormal(r) && std.math.isnormal(g) && std.math.isnormal(b) && std.math.isnormal(a);
789         }
790
791         /**
792         Returns: Integer value of corresponding component.
793
794         Float value 0 is mapped to integer 0. Float value 1 is mapped to
795         integer 255.
796         */
797         int ri()
798         {
799             return cast(int)(r * rgbK);
800         }
801
802         /** ditto */
803         int gi()
804         {
805             return cast(int)(g * rgbK);
806         }
807
808         /** ditto */
809         int bi()
810         {
811             return cast(int)(b * rgbK);
812         }
813
814         /** ditto */
815         int ai()
816         {
817             return cast(int)(a * rgbK);
818         }
819
820         /**
821         Sets corresponding component value to mapped value of passed argument.
822
823         Integer value 0 is mapped to float 0. Integer value 255 is mapped to
824         float 1.
825         */
826         void ri(int r)
827         {
828             this.r = cast(float_t)r / rgbK;
829         }
830
831         /** ditto */
832         void gi(int g)
833         {
834             this.g = cast(float_t)g / rgbK;
835         }
836
837         /** ditto */
838         void bi(int b)
839         {
840             this.b = cast(float_t)b / rgbK;
841         }
842
843         /** ditto */
844         void ai(int a)
845         {
846             this.a = cast(float_t)a / rgbK;
847         }
848
849         /**
850         Returns:
851             This color packed to uint.
852         Params:
853             order = specifies byte-wise component layout in src.
854         Throws:
855             AssertError if any component is out of range [0; 1] and
856             module was compiled with asserts.
857         */
858         uint toUint(ByteOrder order)
859         {
860             assert(ri >= 0 && ri < 256);
861             assert(gi >= 0 && gi < 256);
862             assert(bi >= 0 && bi < 256);
863             assert(ai >= 0 && ai < 256);
864
865             switch (order)
866             {
867                 case ByteOrder.ARGB: return (ai << 24) | (ri << 16) | (gi <<  8) | (bi << 0);
868                 case ByteOrder.ABGR: return (ai << 24) | (bi << 16) | (gi <<  8) | (ri << 0);
869                 case ByteOrder.RGBA: return (ri << 24) | (gi << 16) | (bi <<  8) | (ai << 0);
870                 case ByteOrder.BGRA: return (bi << 24) | (gi << 16) | (ri <<  8) | (ai << 0);
871             }
872
873             return 0;
874         }
875
876         /**
877         Returns:
878             HSL triple representing same color as this.
879
880         Alpha value is ignored.
881         */
882         HSL toHSL()
883         {
884             return rgb.toHSL();
885         }
886
887         /** Returns: float_t pointer to r component of this color. It's like a _ptr method for arrays. */
888         float_t* ptr()
889         {
890             return cast(float_t*)this;
891         }
892
893
894         /**
895         Standard operators that have meaning exactly the same as for Vector4, i.e. do
896         component-wise operations. So alpha component equaly in rights takes place in all
897         operations, to affect just RGB part use swizzling operations.
898
899         Note that division operators do no cheks of value of k, so in case of division
900         by 0 result vector will have infinity components. You can check this with isnormal()
901         method.
902         */
903         bool opEquals(Color4 v)
904         {
905             return r == v.r && g == v.g && b == v.b && a == v.a;
906         }
907
908         /** ditto */
909         Color4 opNeg()
910         {
911             return Color4(-r, -g, -b, -a);
912         }
913
914         /** ditto */
915         Color4 opAdd(Color4 v)
916         {
917             return Color4(r + v.r, g + v.g, b + v.b, a + v.a);
918         }
919
920         /** ditto */
921         void opAddAssign(Color4 v)
922         {
923             r += v.r;
924             g += v.g;
925             b += v.b;
926             a += v.a;
927         }
928
929         /** ditto */
930         Color4 opSub(Color4 v)
931         {
932             return Color4(r - v.r, g - v.g, b - v.b, a - v.a);
933         }
934
935         /** ditto */
936         void opSubAssign(Color4 v)
937         {
938             r -= v.r;
939             g -= v.g;
940             b -= v.b;
941             a -= v.a;
942         }
943
944         /** ditto */
945         Color4 opMul(real k)
946         {
947             return Color4(r * k, g * k, b * k, a * k);
948         }
949
950         /** ditto */
951         void opMulAssign(real k)
952         {
953             r *= k;
954             g *= k;
955             b *= k;
956             a *= k;
957         }
958
959         /** ditto */
960         Color4 opMulr(real k)
961         {
962             return Color4(r * k, g * k, b * k, a * k);
963         }
964
965         /** ditto */
966         Color4 opDiv(real k)
967         {
968             return Color4(r / k, g / k, b / k, a / k);
969         }
970
971         /** ditto */
972         void opDivAssign(real k)
973         {
974             r /= k;
975             g /= k;
976             b /= k;
977             a /= k;
978         }
979
980         /** Sets all components less than inf to inf. */
981         void clampBelow(float_t inf = 0)
982         {
983             .clampBelow(r, inf);
984             .clampBelow(g, inf);
985             .clampBelow(b, inf);
986             .clampBelow(a, inf);
987         }
988
989         /** Returns: Copy of this color with all components less than inf seted to inf. */
990         Color4 clampedBelow(float_t inf = 0)
991         {
992             Color4 ret = *this;
993             ret.clampBelow(inf);
994             return ret;
995         }
996
997         /** Sets all components greater than sup to sup. */
998         void clampAbove(float_t sup = 1)
999         {
1000             .clampAbove(r, sup);
1001             .clampAbove(g, sup);
1002             .clampAbove(b, sup);
1003             .clampAbove(a, sup);
1004         }
1005
1006         /** Returns: Copy of this color with all components greater than sup seted to sup. */
1007         Color4 clampedAbove(float_t sup = 1)
1008         {
1009             Color4 ret = *this;
1010             ret.clampBelow(sup);
1011             return ret;
1012         }
1013
1014         /**
1015         Sets all components less than inf to inf and
1016         all components greater than sup to sup.
1017         */
1018         void clamp(float_t inf = 0, float_t sup = 1)
1019         {
1020             clampBelow(inf);
1021             clampAbove(sup);
1022         }
1023
1024         /**
1025         Returns:
1026             Copy of this color with all components less than inf seted to inf
1027             and all components greater than sup seted to sup.
1028         */
1029         Color4 clamped(float_t inf = 0, float_t sup = 1)
1030         {
1031             Color4 ret = *this;
1032             ret.clamp(inf, sup);
1033             return ret;
1034         }
1035
1036         /** Returns: Copy of this color with float type components. */
1037         Color4f toColor4f()
1038         {
1039             return Color4f(cast(float)r, cast(float)g, cast(float)b, cast(float)a);
1040         }
1041
1042         /** Returns: Copy of this color with double type components. */
1043         Color4d toColor4d()
1044         {
1045             return Color4d(cast(double)r, cast(double)g, cast(double)b, cast(double)a);
1046         }
1047
1048         /** Returns: Copy of this color with real type components. */
1049         Color4r toColor4r()
1050         {
1051             return Color4r(cast(real)r, cast(real)g, cast(real)b, cast(real)a);
1052         }
1053
1054         /**
1055         Routine known as swizzling.
1056         Returns:
1057             Color3 representing RGB part of this color.
1058         */
1059         Color3 rgb()
1060         {
1061             return Color3(r, g, b);
1062         }
1063
1064         /**
1065         Routine known as swizzling.
1066         Sets RGB part components to values of passed _rgb argument's components.
1067         */
1068         void rgb(Color3 rgb)
1069         {
1070             r = rgb.r;
1071             g = rgb.g;
1072             b = rgb.b;
1073         }
1074     }
1075
1076     /**
1077     Approximate equality function.
1078     Params:
1079         relprec, absprec = Parameters passed to equal function while calculations.
1080                            Have the same meaning as in equal function.
1081     */
1082     bool equal(Color4 a, Color4 b, int relprec = defrelprec, int absprec = defabsprec)
1083     {
1084         Color4 c = a - b;
1085         return .equal(c.r * c.r + c.g * c.g + c.b * c.b + c.a * c.a, 0, relprec, absprec);
1086     }
1087
1088     alias Lerp!(Color4).lerp lerp; /// Introduces linear interpolation function for Color4.
1089 }
1090
1091 alias Color!(float).HSL         HSLf;
1092 alias Color!(float).Color3      Color3f;
1093 alias Color!(float).Color4      Color4f;
1094 alias Color!(float).equal       equal;
1095 alias Color!(float).lerp        lerp;
1096
1097 alias Color!(double).HSL        HSLd;
1098 alias Color!(double).Color3     Color3d;
1099 alias Color!(double).Color4     Color4d;
1100 alias Color!(double).equal      equal;
1101 alias Color!(double).lerp       lerp;
1102
1103 alias Color!(real).HSL          HSLr;
1104 alias Color!(real).Color3       Color3r;
1105 alias Color!(real).Color4       Color4r;
1106 alias Color!(real).equal        equal;
1107 alias Color!(real).lerp         lerp;
1108
1109 alias Color!(helix.config.float_t).HSL     HSL;
1110 alias Color!(helix.config.float_t).Color3  Color3;
1111 alias Color!(helix.config.float_t).Color4  Color4;
1112
1113 unittest
1114 {
1115     Color4 a;
1116     a.set(0.1, 0.3, 0.9, 0.6);
1117     Color3 b = a.rgb;
1118     uint au = a.toUint(ByteOrder.RGBA);
1119     assert( equal( Color3(au, ByteOrder.RGBA), b ) );   
1120 }
1121
1122 unittest
1123 {
1124     Color3 c = Color3( 0.2, 0.5, 1.0 );
1125     assert( equal(c.toHSL.toColor3(), c) );
1126 }
Note: See TracBrowser for help on using the browser.