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//----------------------------------------------------------------------------
11// Contact: mcseem@antigrain.com
12//          mcseemagg@yahoo.com
13//          http://www.antigrain.com
14//----------------------------------------------------------------------------
15//
16// Adaptation for high precision colors has been sponsored by
17// Liberty Technology Systems, Inc., visit http://lib-sys.com
18//
19// Liberty Technology Systems, Inc. is the provider of
20// PostScript and PDF technology for software developers.
21//
22//----------------------------------------------------------------------------
23//
24// color types gray8, gray16
25//
26//----------------------------------------------------------------------------
27
28#ifndef AGG_COLOR_GRAY_INCLUDED
29#define AGG_COLOR_GRAY_INCLUDED
30
31#include "agg_basics.h"
32#include "agg_color_rgba.h"
33
34namespace agg
35{
36
37    //===================================================================gray8
38    struct gray8
39    {
40        typedef int8u  value_type;
41        typedef int32u calc_type;
42        typedef int32  long_type;
43        enum base_scale_e
44        {
45            base_shift = 8,
46            base_scale = 1 << base_shift,
47            base_mask  = base_scale - 1
48        };
49        typedef gray8 self_type;
50
51        value_type v;
52        value_type a;
53
54        //--------------------------------------------------------------------
55        gray8() {}
56
57        //--------------------------------------------------------------------
58        explicit gray8(unsigned v_, unsigned a_=base_mask) :
59            v(int8u(v_)), a(int8u(a_)) {}
60
61        //--------------------------------------------------------------------
62        gray8(const self_type& c, unsigned a_) :
63            v(c.v), a(value_type(a_)) {}
64
65        //--------------------------------------------------------------------
66        gray8(const rgba& c) :
67            v((value_type)uround((0.299*c.r + 0.587*c.g + 0.114*c.b) * double(base_mask))),
68            a((value_type)uround(c.a * double(base_mask))) {}
69
70        //--------------------------------------------------------------------
71        gray8(const rgba& c, double a_) :
72            v((value_type)uround((0.299*c.r + 0.587*c.g + 0.114*c.b) * double(base_mask))),
73            a((value_type)uround(a_ * double(base_mask))) {}
74
75        //--------------------------------------------------------------------
76        gray8(const rgba8& c) :
77            v((c.r*77 + c.g*150 + c.b*29) >> 8),
78            a(c.a) {}
79
80        //--------------------------------------------------------------------
81        gray8(const rgba8& c, unsigned a_) :
82            v((c.r*77 + c.g*150 + c.b*29) >> 8),
83            a(a_) {}
84
85        //--------------------------------------------------------------------
86        void clear()
87        {
88            v = a = 0;
89        }
90
91        //--------------------------------------------------------------------
92        const self_type& transparent()
93        {
94            a = 0;
95            return *this;
96        }
97
98        //--------------------------------------------------------------------
99        void opacity(double a_)
100        {
101            if(a_ < 0.0) a_ = 0.0;
102            if(a_ > 1.0) a_ = 1.0;
103            a = (value_type)uround(a_ * double(base_mask));
104        }
105
106        //--------------------------------------------------------------------
107        double opacity() const
108        {
109            return double(a) / double(base_mask);
110        }
111
112
113        //--------------------------------------------------------------------
114        const self_type& premultiply()
115        {
116            if(a == base_mask) return *this;
117            if(a == 0)
118            {
119                v = 0;
120                return *this;
121            }
122            v = value_type((calc_type(v) * a) >> base_shift);
123            return *this;
124        }
125
126        //--------------------------------------------------------------------
127        const self_type& premultiply(unsigned a_)
128        {
129            if(a == base_mask && a_ >= base_mask) return *this;
130            if(a == 0 || a_ == 0)
131            {
132                v = a = 0;
133                return *this;
134            }
135            calc_type v_ = (calc_type(v) * a_) / a;
136            v = value_type((v_ > a_) ? a_ : v_);
137            a = value_type(a_);
138            return *this;
139        }
140
141        //--------------------------------------------------------------------
142        const self_type& demultiply()
143        {
144            if(a == base_mask) return *this;
145            if(a == 0)
146            {
147                v = 0;
148                return *this;
149            }
150            calc_type v_ = (calc_type(v) * base_mask) / a;
151            v = value_type((v_ > base_mask) ? base_mask : v_);
152            return *this;
153        }
154
155        //--------------------------------------------------------------------
156        self_type gradient(self_type c, double k) const
157        {
158            self_type ret;
159            calc_type ik = uround(k * base_scale);
160            ret.v = value_type(calc_type(v) + (((calc_type(c.v) - v) * ik) >> base_shift));
161            ret.a = value_type(calc_type(a) + (((calc_type(c.a) - a) * ik) >> base_shift));
162            return ret;
163        }
164
165        //--------------------------------------------------------------------
166        AGG_INLINE void add(const self_type& c, unsigned cover)
167        {
168            calc_type cv, ca;
169            if(cover == cover_mask)
170            {
171                if(c.a == base_mask)
172                {
173                    *this = c;
174                }
175                else
176                {
177                    cv = v + c.v; v = (cv > calc_type(base_mask)) ? calc_type(base_mask) : cv;
178                    ca = a + c.a; a = (ca > calc_type(base_mask)) ? calc_type(base_mask) : ca;
179                }
180            }
181            else
182            {
183                cv = v + ((c.v * cover + cover_mask/2) >> cover_shift);
184                ca = a + ((c.a * cover + cover_mask/2) >> cover_shift);
185                v = (cv > calc_type(base_mask)) ? calc_type(base_mask) : cv;
186                a = (ca > calc_type(base_mask)) ? calc_type(base_mask) : ca;
187            }
188        }
189
190        //--------------------------------------------------------------------
191        static self_type no_color() { return self_type(0,0); }
192    };
193
194
195    //-------------------------------------------------------------gray8_pre
196    inline gray8 gray8_pre(unsigned v, unsigned a = gray8::base_mask)
197    {
198        return gray8(v,a).premultiply();
199    }
200    inline gray8 gray8_pre(const gray8& c, unsigned a)
201    {
202        return gray8(c,a).premultiply();
203    }
204    inline gray8 gray8_pre(const rgba& c)
205    {
206        return gray8(c).premultiply();
207    }
208    inline gray8 gray8_pre(const rgba& c, double a)
209    {
210        return gray8(c,a).premultiply();
211    }
212    inline gray8 gray8_pre(const rgba8& c)
213    {
214        return gray8(c).premultiply();
215    }
216    inline gray8 gray8_pre(const rgba8& c, unsigned a)
217    {
218        return gray8(c,a).premultiply();
219    }
220
221
222
223
224    //==================================================================gray16
225    struct gray16
226    {
227        typedef int16u value_type;
228        typedef int32u calc_type;
229        typedef int64  long_type;
230        enum base_scale_e
231        {
232            base_shift = 16,
233            base_scale = 1 << base_shift,
234            base_mask  = base_scale - 1
235        };
236        typedef gray16 self_type;
237
238        value_type v;
239        value_type a;
240
241        //--------------------------------------------------------------------
242        gray16() {}
243
244        //--------------------------------------------------------------------
245        explicit gray16(unsigned v_, unsigned a_=base_mask) :
246            v(int16u(v_)), a(int16u(a_)) {}
247
248        //--------------------------------------------------------------------
249        gray16(const self_type& c, unsigned a_) :
250            v(c.v), a(value_type(a_)) {}
251
252        //--------------------------------------------------------------------
253        gray16(const rgba& c) :
254            v((value_type)uround((0.299*c.r + 0.587*c.g + 0.114*c.b) * double(base_mask))),
255            a((value_type)uround(c.a * double(base_mask))) {}
256
257        //--------------------------------------------------------------------
258        gray16(const rgba& c, double a_) :
259            v((value_type)uround((0.299*c.r + 0.587*c.g + 0.114*c.b) * double(base_mask))),
260            a((value_type)uround(a_ * double(base_mask))) {}
261
262        //--------------------------------------------------------------------
263        gray16(const rgba8& c) :
264            v(c.r*77 + c.g*150 + c.b*29),
265            a((value_type(c.a) << 8) | c.a) {}
266
267        //--------------------------------------------------------------------
268        gray16(const rgba8& c, unsigned a_) :
269            v(c.r*77 + c.g*150 + c.b*29),
270            a((value_type(a_) << 8) | c.a) {}
271
272        //--------------------------------------------------------------------
273        void clear()
274        {
275            v = a = 0;
276        }
277
278        //--------------------------------------------------------------------
279        const self_type& transparent()
280        {
281            a = 0;
282            return *this;
283        }
284
285        //--------------------------------------------------------------------
286        void opacity(double a_)
287        {
288            if(a_ < 0.0) a_ = 0.0;
289            if(a_ > 1.0) a_ = 1.0;
290            a = (value_type)uround(a_ * double(base_mask));
291        }
292
293        //--------------------------------------------------------------------
294        double opacity() const
295        {
296            return double(a) / double(base_mask);
297        }
298
299
300        //--------------------------------------------------------------------
301        const self_type& premultiply()
302        {
303            if(a == base_mask) return *this;
304            if(a == 0)
305            {
306                v = 0;
307                return *this;
308            }
309            v = value_type((calc_type(v) * a) >> base_shift);
310            return *this;
311        }
312
313        //--------------------------------------------------------------------
314        const self_type& premultiply(unsigned a_)
315        {
316            if(a == base_mask && a_ >= base_mask) return *this;
317            if(a == 0 || a_ == 0)
318            {
319                v = a = 0;
320                return *this;
321            }
322            calc_type v_ = (calc_type(v) * a_) / a;
323            v = value_type((v_ > a_) ? a_ : v_);
324            a = value_type(a_);
325            return *this;
326        }
327
328        //--------------------------------------------------------------------
329        const self_type& demultiply()
330        {
331            if(a == base_mask) return *this;
332            if(a == 0)
333            {
334                v = 0;
335                return *this;
336            }
337            calc_type v_ = (calc_type(v) * base_mask) / a;
338            v = value_type((v_ > base_mask) ? base_mask : v_);
339            return *this;
340        }
341
342        //--------------------------------------------------------------------
343        self_type gradient(self_type c, double k) const
344        {
345            self_type ret;
346            calc_type ik = uround(k * base_scale);
347            ret.v = value_type(calc_type(v) + (((calc_type(c.v) - v) * ik) >> base_shift));
348            ret.a = value_type(calc_type(a) + (((calc_type(c.a) - a) * ik) >> base_shift));
349            return ret;
350        }
351
352        //--------------------------------------------------------------------
353        AGG_INLINE void add(const self_type& c, unsigned cover)
354        {
355            calc_type cv, ca;
356            if(cover == cover_mask)
357            {
358                if(c.a == base_mask)
359                {
360                    *this = c;
361                }
362                else
363                {
364                    cv = v + c.v; v = (cv > calc_type(base_mask)) ? calc_type(base_mask) : cv;
365                    ca = a + c.a; a = (ca > calc_type(base_mask)) ? calc_type(base_mask) : ca;
366                }
367            }
368            else
369            {
370                cv = v + ((c.v * cover + cover_mask/2) >> cover_shift);
371                ca = a + ((c.a * cover + cover_mask/2) >> cover_shift);
372                v = (cv > calc_type(base_mask)) ? calc_type(base_mask) : cv;
373                a = (ca > calc_type(base_mask)) ? calc_type(base_mask) : ca;
374            }
375        }
376
377        //--------------------------------------------------------------------
378        static self_type no_color() { return self_type(0,0); }
379    };
380
381
382    //------------------------------------------------------------gray16_pre
383    inline gray16 gray16_pre(unsigned v, unsigned a = gray16::base_mask)
384    {
385        return gray16(v,a).premultiply();
386    }
387    inline gray16 gray16_pre(const gray16& c, unsigned a)
388    {
389        return gray16(c,a).premultiply();
390    }
391    inline gray16 gray16_pre(const rgba& c)
392    {
393        return gray16(c).premultiply();
394    }
395    inline gray16 gray16_pre(const rgba& c, double a)
396    {
397        return gray16(c,a).premultiply();
398    }
399    inline gray16 gray16_pre(const rgba8& c)
400    {
401        return gray16(c).premultiply();
402    }
403    inline gray16 gray16_pre(const rgba8& c, unsigned a)
404    {
405        return gray16(c,a).premultiply();
406    }
407
408
409}
410
411
412
413
414#endif
415