btrfs: [] on the end of a struct field is a variable length array.
[haiku.git] / headers / libs / agg / agg_color_rgba.h
blobbefa1650fa3152a358154727933e072184464a69
1 //----------------------------------------------------------------------------
2 // Anti-Grain Geometry - Version 2.4
3 // Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com)
4 //
5 // Permission to copy, use, modify, sell and distribute this software
6 // is granted provided this copyright notice appears in all copies.
7 // This software is provided "as is" without express or implied
8 // warranty, and with no claim as to its suitability for any purpose.
9 //
10 //----------------------------------------------------------------------------
12 // Adaptation for high precision colors has been sponsored by
13 // Liberty Technology Systems, Inc., visit http://lib-sys.com
15 // Liberty Technology Systems, Inc. is the provider of
16 // PostScript and PDF technology for software developers.
17 //
18 //----------------------------------------------------------------------------
19 // Contact: mcseem@antigrain.com
20 // mcseemagg@yahoo.com
21 // http://www.antigrain.com
22 //----------------------------------------------------------------------------
24 #ifndef AGG_COLOR_RGBA_INCLUDED
25 #define AGG_COLOR_RGBA_INCLUDED
27 #include <math.h>
28 #include "agg_basics.h"
30 namespace agg
32 // Supported byte orders for RGB and RGBA pixel formats
33 //=======================================================================
34 struct order_rgb { enum rgb_e { R=0, G=1, B=2, rgb_tag }; }; //----order_rgb
35 struct order_bgr { enum bgr_e { B=0, G=1, R=2, rgb_tag }; }; //----order_bgr
36 struct order_rgba { enum rgba_e { R=0, G=1, B=2, A=3, rgba_tag }; }; //----order_rgba
37 struct order_argb { enum argb_e { A=0, R=1, G=2, B=3, rgba_tag }; }; //----order_argb
38 struct order_abgr { enum abgr_e { A=0, B=1, G=2, R=3, rgba_tag }; }; //----order_abgr
39 struct order_bgra { enum bgra_e { B=0, G=1, R=2, A=3, rgba_tag }; }; //----order_bgra
41 //====================================================================rgba
42 struct rgba
44 typedef double value_type;
46 double r;
47 double g;
48 double b;
49 double a;
51 //--------------------------------------------------------------------
52 rgba() {}
54 //--------------------------------------------------------------------
55 rgba(double r_, double g_, double b_, double a_=1.0) :
56 r(r_), g(g_), b(b_), a(a_) {}
58 //--------------------------------------------------------------------
59 rgba(const rgba& c, double a_) : r(c.r), g(c.g), b(c.b), a(a_) {}
61 //--------------------------------------------------------------------
62 void clear()
64 r = g = b = a = 0;
67 //--------------------------------------------------------------------
68 const rgba& transparent()
70 a = 0.0;
71 return *this;
74 //--------------------------------------------------------------------
75 const rgba& opacity(double a_)
77 if(a_ < 0.0) a_ = 0.0;
78 if(a_ > 1.0) a_ = 1.0;
79 a = a_;
80 return *this;
83 //--------------------------------------------------------------------
84 double opacity() const
86 return a;
89 //--------------------------------------------------------------------
90 const rgba& premultiply()
92 r *= a;
93 g *= a;
94 b *= a;
95 return *this;
98 //--------------------------------------------------------------------
99 const rgba& premultiply(double a_)
101 if(a <= 0.0 || a_ <= 0.0)
103 r = g = b = a = 0.0;
104 return *this;
106 a_ /= a;
107 r *= a_;
108 g *= a_;
109 b *= a_;
110 a = a_;
111 return *this;
114 //--------------------------------------------------------------------
115 const rgba& demultiply()
117 if(a == 0)
119 r = g = b = 0;
120 return *this;
122 double a_ = 1.0 / a;
123 r *= a_;
124 g *= a_;
125 b *= a_;
126 return *this;
130 //--------------------------------------------------------------------
131 rgba gradient(rgba c, double k) const
133 rgba ret;
134 ret.r = r + (c.r - r) * k;
135 ret.g = g + (c.g - g) * k;
136 ret.b = b + (c.b - b) * k;
137 ret.a = a + (c.a - a) * k;
138 return ret;
141 //--------------------------------------------------------------------
142 static rgba no_color() { return rgba(0,0,0,0); }
144 //--------------------------------------------------------------------
145 static rgba from_wavelength(double wl, double gamma = 1.0);
147 //--------------------------------------------------------------------
148 explicit rgba(double wavelen, double gamma=1.0)
150 *this = from_wavelength(wavelen, gamma);
155 //----------------------------------------------------------------rgba_pre
156 inline rgba rgba_pre(double r, double g, double b, double a=1.0)
158 return rgba(r, g, b, a).premultiply();
160 inline rgba rgba_pre(const rgba& c)
162 return rgba(c).premultiply();
164 inline rgba rgba_pre(const rgba& c, double a)
166 return rgba(c, a).premultiply();
169 //------------------------------------------------------------------------
170 inline rgba rgba::from_wavelength(double wl, double gamma)
172 rgba t(0.0, 0.0, 0.0);
174 if(wl >= 380.0 && wl <= 440.0)
176 t.r = -1.0 * (wl - 440.0) / (440.0 - 380.0);
177 t.b = 1.0;
179 else
180 if(wl >= 440.0 && wl <= 490.0)
182 t.g = (wl - 440.0) / (490.0 - 440.0);
183 t.b = 1.0;
185 else
186 if(wl >= 490.0 && wl <= 510.0)
188 t.g = 1.0;
189 t.b = -1.0 * (wl - 510.0) / (510.0 - 490.0);
191 else
192 if(wl >= 510.0 && wl <= 580.0)
194 t.r = (wl - 510.0) / (580.0 - 510.0);
195 t.g = 1.0;
197 else
198 if(wl >= 580.0 && wl <= 645.0)
200 t.r = 1.0;
201 t.g = -1.0 * (wl - 645.0) / (645.0 - 580.0);
203 else
204 if(wl >= 645.0 && wl <= 780.0)
206 t.r = 1.0;
209 double s = 1.0;
210 if(wl > 700.0) s = 0.3 + 0.7 * (780.0 - wl) / (780.0 - 700.0);
211 else if(wl < 420.0) s = 0.3 + 0.7 * (wl - 380.0) / (420.0 - 380.0);
213 t.r = pow(t.r * s, gamma);
214 t.g = pow(t.g * s, gamma);
215 t.b = pow(t.b * s, gamma);
216 return t;
222 //===================================================================rgba8
223 struct rgba8
225 typedef int8u value_type;
226 typedef int32u calc_type;
227 typedef int32 long_type;
228 enum base_scale_e
230 base_shift = 8,
231 base_scale = 1 << base_shift,
232 base_mask = base_scale - 1
234 typedef rgba8 self_type;
237 value_type r;
238 value_type g;
239 value_type b;
240 value_type a;
242 //--------------------------------------------------------------------
243 rgba8() {}
245 //--------------------------------------------------------------------
246 rgba8(unsigned r_, unsigned g_, unsigned b_, unsigned a_=base_mask) :
247 r(value_type(r_)),
248 g(value_type(g_)),
249 b(value_type(b_)),
250 a(value_type(a_)) {}
252 //--------------------------------------------------------------------
253 rgba8(const rgba& c, double a_) :
254 r((value_type)uround(c.r * double(base_mask))),
255 g((value_type)uround(c.g * double(base_mask))),
256 b((value_type)uround(c.b * double(base_mask))),
257 a((value_type)uround(a_ * double(base_mask))) {}
259 //--------------------------------------------------------------------
260 rgba8(const self_type& c, unsigned a_) :
261 r(c.r), g(c.g), b(c.b), a(value_type(a_)) {}
263 //--------------------------------------------------------------------
264 rgba8(const rgba& c) :
265 r((value_type)uround(c.r * double(base_mask))),
266 g((value_type)uround(c.g * double(base_mask))),
267 b((value_type)uround(c.b * double(base_mask))),
268 a((value_type)uround(c.a * double(base_mask))) {}
270 //--------------------------------------------------------------------
271 void clear()
273 r = g = b = a = 0;
276 //--------------------------------------------------------------------
277 const self_type& transparent()
279 a = 0;
280 return *this;
283 //--------------------------------------------------------------------
284 const self_type& opacity(double a_)
286 if(a_ < 0.0) a_ = 0.0;
287 if(a_ > 1.0) a_ = 1.0;
288 a = (value_type)uround(a_ * double(base_mask));
289 return *this;
292 //--------------------------------------------------------------------
293 double opacity() const
295 return double(a) / double(base_mask);
298 //--------------------------------------------------------------------
299 AGG_INLINE const self_type& premultiply()
301 if(a == base_mask) return *this;
302 if(a == 0)
304 r = g = b = 0;
305 return *this;
307 r = value_type((calc_type(r) * a) >> base_shift);
308 g = value_type((calc_type(g) * a) >> base_shift);
309 b = value_type((calc_type(b) * a) >> base_shift);
310 return *this;
313 //--------------------------------------------------------------------
314 AGG_INLINE const self_type& premultiply(unsigned a_)
316 if(a == base_mask && a_ >= base_mask) return *this;
317 if(a == 0 || a_ == 0)
319 r = g = b = a = 0;
320 return *this;
322 calc_type r_ = (calc_type(r) * a_) / a;
323 calc_type g_ = (calc_type(g) * a_) / a;
324 calc_type b_ = (calc_type(b) * a_) / a;
325 r = value_type((r_ > a_) ? a_ : r_);
326 g = value_type((g_ > a_) ? a_ : g_);
327 b = value_type((b_ > a_) ? a_ : b_);
328 a = value_type(a_);
329 return *this;
332 //--------------------------------------------------------------------
333 AGG_INLINE const self_type& demultiply()
335 if(a == base_mask) return *this;
336 if(a == 0)
338 r = g = b = 0;
339 return *this;
341 calc_type r_ = (calc_type(r) * base_mask) / a;
342 calc_type g_ = (calc_type(g) * base_mask) / a;
343 calc_type b_ = (calc_type(b) * base_mask) / a;
344 r = value_type((r_ > calc_type(base_mask)) ? calc_type(base_mask) : r_);
345 g = value_type((g_ > calc_type(base_mask)) ? calc_type(base_mask) : g_);
346 b = value_type((b_ > calc_type(base_mask)) ? calc_type(base_mask) : b_);
347 return *this;
350 //--------------------------------------------------------------------
351 AGG_INLINE self_type gradient(const self_type& c, double k) const
353 self_type ret;
354 calc_type ik = uround(k * base_scale);
355 ret.r = value_type(calc_type(r) + (((calc_type(c.r) - r) * ik) >> base_shift));
356 ret.g = value_type(calc_type(g) + (((calc_type(c.g) - g) * ik) >> base_shift));
357 ret.b = value_type(calc_type(b) + (((calc_type(c.b) - b) * ik) >> base_shift));
358 ret.a = value_type(calc_type(a) + (((calc_type(c.a) - a) * ik) >> base_shift));
359 return ret;
362 //--------------------------------------------------------------------
363 AGG_INLINE void add(const self_type& c, unsigned cover)
365 calc_type cr, cg, cb, ca;
366 if(cover == cover_mask)
368 if(c.a == base_mask)
370 *this = c;
372 else
374 cr = r + c.r; r = (cr > calc_type(base_mask)) ? calc_type(base_mask) : cr;
375 cg = g + c.g; g = (cg > calc_type(base_mask)) ? calc_type(base_mask) : cg;
376 cb = b + c.b; b = (cb > calc_type(base_mask)) ? calc_type(base_mask) : cb;
377 ca = a + c.a; a = (ca > calc_type(base_mask)) ? calc_type(base_mask) : ca;
380 else
382 cr = r + ((c.r * cover + cover_mask/2) >> cover_shift);
383 cg = g + ((c.g * cover + cover_mask/2) >> cover_shift);
384 cb = b + ((c.b * cover + cover_mask/2) >> cover_shift);
385 ca = a + ((c.a * cover + cover_mask/2) >> cover_shift);
386 r = (cr > calc_type(base_mask)) ? calc_type(base_mask) : cr;
387 g = (cg > calc_type(base_mask)) ? calc_type(base_mask) : cg;
388 b = (cb > calc_type(base_mask)) ? calc_type(base_mask) : cb;
389 a = (ca > calc_type(base_mask)) ? calc_type(base_mask) : ca;
393 //--------------------------------------------------------------------
394 template<class GammaLUT>
395 AGG_INLINE void apply_gamma_dir(const GammaLUT& gamma)
397 r = gamma.dir(r);
398 g = gamma.dir(g);
399 b = gamma.dir(b);
402 //--------------------------------------------------------------------
403 template<class GammaLUT>
404 AGG_INLINE void apply_gamma_inv(const GammaLUT& gamma)
406 r = gamma.inv(r);
407 g = gamma.inv(g);
408 b = gamma.inv(b);
411 //--------------------------------------------------------------------
412 static self_type no_color() { return self_type(0,0,0,0); }
414 //--------------------------------------------------------------------
415 static self_type from_wavelength(double wl, double gamma = 1.0)
417 return self_type(rgba::from_wavelength(wl, gamma));
422 //-------------------------------------------------------------rgba8_pre
423 inline rgba8 rgba8_pre(unsigned r, unsigned g, unsigned b,
424 unsigned a = rgba8::base_mask)
426 return rgba8(r,g,b,a).premultiply();
428 inline rgba8 rgba8_pre(const rgba8& c)
430 return rgba8(c).premultiply();
432 inline rgba8 rgba8_pre(const rgba8& c, unsigned a)
434 return rgba8(c,a).premultiply();
436 inline rgba8 rgba8_pre(const rgba& c)
438 return rgba8(c).premultiply();
440 inline rgba8 rgba8_pre(const rgba& c, double a)
442 return rgba8(c,a).premultiply();
446 //-----------------------------------------------------------rgb8_packed
447 inline rgba8 rgb8_packed(unsigned v)
449 return rgba8((v >> 16) & 0xFF, (v >> 8) & 0xFF, v & 0xFF);
452 //-----------------------------------------------------------bgr8_packed
453 inline rgba8 bgr8_packed(unsigned v)
455 return rgba8(v & 0xFF, (v >> 8) & 0xFF, (v >> 16) & 0xFF);
458 //----------------------------------------------------------argb8_packed
459 inline rgba8 argb8_packed(unsigned v)
461 return rgba8((v >> 16) & 0xFF, (v >> 8) & 0xFF, v & 0xFF, v >> 24);
471 //=================================================================rgba16
472 struct rgba16
474 typedef int16u value_type;
475 typedef int32u calc_type;
476 typedef int64 long_type;
477 enum base_scale_e
479 base_shift = 16,
480 base_scale = 1 << base_shift,
481 base_mask = base_scale - 1
483 typedef rgba16 self_type;
485 value_type r;
486 value_type g;
487 value_type b;
488 value_type a;
490 //--------------------------------------------------------------------
491 rgba16() {}
493 //--------------------------------------------------------------------
494 rgba16(unsigned r_, unsigned g_, unsigned b_, unsigned a_=base_mask) :
495 r(value_type(r_)),
496 g(value_type(g_)),
497 b(value_type(b_)),
498 a(value_type(a_)) {}
500 //--------------------------------------------------------------------
501 rgba16(const self_type& c, unsigned a_) :
502 r(c.r), g(c.g), b(c.b), a(value_type(a_)) {}
504 //--------------------------------------------------------------------
505 rgba16(const rgba& c) :
506 r((value_type)uround(c.r * double(base_mask))),
507 g((value_type)uround(c.g * double(base_mask))),
508 b((value_type)uround(c.b * double(base_mask))),
509 a((value_type)uround(c.a * double(base_mask))) {}
511 //--------------------------------------------------------------------
512 rgba16(const rgba& c, double a_) :
513 r((value_type)uround(c.r * double(base_mask))),
514 g((value_type)uround(c.g * double(base_mask))),
515 b((value_type)uround(c.b * double(base_mask))),
516 a((value_type)uround(a_ * double(base_mask))) {}
518 //--------------------------------------------------------------------
519 rgba16(const rgba8& c) :
520 r(value_type((value_type(c.r) << 8) | c.r)),
521 g(value_type((value_type(c.g) << 8) | c.g)),
522 b(value_type((value_type(c.b) << 8) | c.b)),
523 a(value_type((value_type(c.a) << 8) | c.a)) {}
525 //--------------------------------------------------------------------
526 rgba16(const rgba8& c, unsigned a_) :
527 r(value_type((value_type(c.r) << 8) | c.r)),
528 g(value_type((value_type(c.g) << 8) | c.g)),
529 b(value_type((value_type(c.b) << 8) | c.b)),
530 a(value_type(( a_ << 8) | c.a)) {}
532 //--------------------------------------------------------------------
533 void clear()
535 r = g = b = a = 0;
538 //--------------------------------------------------------------------
539 const self_type& transparent()
541 a = 0;
542 return *this;
545 //--------------------------------------------------------------------
546 AGG_INLINE const self_type& opacity(double a_)
548 if(a_ < 0.0) a_ = 0.0;
549 if(a_ > 1.0) a_ = 1.0;
550 a = (value_type)uround(a_ * double(base_mask));
551 return *this;
554 //--------------------------------------------------------------------
555 double opacity() const
557 return double(a) / double(base_mask);
560 //--------------------------------------------------------------------
561 AGG_INLINE const self_type& premultiply()
563 if(a == base_mask) return *this;
564 if(a == 0)
566 r = g = b = 0;
567 return *this;
569 r = value_type((calc_type(r) * a) >> base_shift);
570 g = value_type((calc_type(g) * a) >> base_shift);
571 b = value_type((calc_type(b) * a) >> base_shift);
572 return *this;
575 //--------------------------------------------------------------------
576 AGG_INLINE const self_type& premultiply(unsigned a_)
578 if(a == base_mask && a_ >= base_mask) return *this;
579 if(a == 0 || a_ == 0)
581 r = g = b = a = 0;
582 return *this;
584 calc_type r_ = (calc_type(r) * a_) / a;
585 calc_type g_ = (calc_type(g) * a_) / a;
586 calc_type b_ = (calc_type(b) * a_) / a;
587 r = value_type((r_ > a_) ? a_ : r_);
588 g = value_type((g_ > a_) ? a_ : g_);
589 b = value_type((b_ > a_) ? a_ : b_);
590 a = value_type(a_);
591 return *this;
594 //--------------------------------------------------------------------
595 AGG_INLINE const self_type& demultiply()
597 if(a == base_mask) return *this;
598 if(a == 0)
600 r = g = b = 0;
601 return *this;
603 calc_type r_ = (calc_type(r) * base_mask) / a;
604 calc_type g_ = (calc_type(g) * base_mask) / a;
605 calc_type b_ = (calc_type(b) * base_mask) / a;
606 r = value_type((r_ > calc_type(base_mask)) ? calc_type(base_mask) : r_);
607 g = value_type((g_ > calc_type(base_mask)) ? calc_type(base_mask) : g_);
608 b = value_type((b_ > calc_type(base_mask)) ? calc_type(base_mask) : b_);
609 return *this;
612 //--------------------------------------------------------------------
613 AGG_INLINE self_type gradient(const self_type& c, double k) const
615 self_type ret;
616 calc_type ik = uround(k * base_scale);
617 ret.r = value_type(calc_type(r) + (((calc_type(c.r) - r) * ik) >> base_shift));
618 ret.g = value_type(calc_type(g) + (((calc_type(c.g) - g) * ik) >> base_shift));
619 ret.b = value_type(calc_type(b) + (((calc_type(c.b) - b) * ik) >> base_shift));
620 ret.a = value_type(calc_type(a) + (((calc_type(c.a) - a) * ik) >> base_shift));
621 return ret;
624 //--------------------------------------------------------------------
625 AGG_INLINE void add(const self_type& c, unsigned cover)
627 calc_type cr, cg, cb, ca;
628 if(cover == cover_mask)
630 if(c.a == base_mask)
632 *this = c;
634 else
636 cr = r + c.r; r = (cr > calc_type(base_mask)) ? calc_type(base_mask) : cr;
637 cg = g + c.g; g = (cg > calc_type(base_mask)) ? calc_type(base_mask) : cg;
638 cb = b + c.b; b = (cb > calc_type(base_mask)) ? calc_type(base_mask) : cb;
639 ca = a + c.a; a = (ca > calc_type(base_mask)) ? calc_type(base_mask) : ca;
642 else
644 cr = r + ((c.r * cover + cover_mask) >> cover_shift);
645 cg = g + ((c.g * cover + cover_mask) >> cover_shift);
646 cb = b + ((c.b * cover + cover_mask) >> cover_shift);
647 ca = a + ((c.a * cover + cover_mask) >> cover_shift);
648 r = (cr > calc_type(base_mask)) ? calc_type(base_mask) : cr;
649 g = (cg > calc_type(base_mask)) ? calc_type(base_mask) : cg;
650 b = (cb > calc_type(base_mask)) ? calc_type(base_mask) : cb;
651 a = (ca > calc_type(base_mask)) ? calc_type(base_mask) : ca;
655 //--------------------------------------------------------------------
656 template<class GammaLUT>
657 AGG_INLINE void apply_gamma_dir(const GammaLUT& gamma)
659 r = gamma.dir(r);
660 g = gamma.dir(g);
661 b = gamma.dir(b);
664 //--------------------------------------------------------------------
665 template<class GammaLUT>
666 AGG_INLINE void apply_gamma_inv(const GammaLUT& gamma)
668 r = gamma.inv(r);
669 g = gamma.inv(g);
670 b = gamma.inv(b);
673 //--------------------------------------------------------------------
674 static self_type no_color() { return self_type(0,0,0,0); }
676 //--------------------------------------------------------------------
677 static self_type from_wavelength(double wl, double gamma = 1.0)
679 return self_type(rgba::from_wavelength(wl, gamma));
685 //--------------------------------------------------------------rgba16_pre
686 inline rgba16 rgba16_pre(unsigned r, unsigned g, unsigned b,
687 unsigned a = rgba16::base_mask)
689 return rgba16(r,g,b,a).premultiply();
691 inline rgba16 rgba16_pre(const rgba16& c, unsigned a)
693 return rgba16(c,a).premultiply();
695 inline rgba16 rgba16_pre(const rgba& c)
697 return rgba16(c).premultiply();
699 inline rgba16 rgba16_pre(const rgba& c, double a)
701 return rgba16(c,a).premultiply();
703 inline rgba16 rgba16_pre(const rgba8& c)
705 return rgba16(c).premultiply();
707 inline rgba16 rgba16_pre(const rgba8& c, unsigned a)
709 return rgba16(c,a).premultiply();
716 #endif