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 #ifndef AGG_GRADIENT_LUT_INCLUDED
17 #define AGG_GRADIENT_LUT_INCLUDED
18 
19 #include "agg_array.h"
20 #include "agg_dda_line.h"
21 #include "agg_color_rgba.h"
22 #include "agg_color_gray.h"
23 
24 namespace agg
25 {
26 
27     //======================================================color_interpolator
28     template<class ColorT> struct color_interpolator
29     {
30     public:
31         typedef ColorT color_type;
32 
color_interpolatorcolor_interpolator33         color_interpolator(const color_type& c1,
34                            const color_type& c2,
35                            unsigned len) :
36             m_c1(c1),
37             m_c2(c2),
38             m_len(len),
39             m_count(0)
40         {}
41 
42         void operator ++ ()
43         {
44             ++m_count;
45         }
46 
colorcolor_interpolator47         color_type color() const
48         {
49             return m_c1.gradient(m_c2, double(m_count) / m_len);
50         }
51 
52     private:
53         color_type m_c1;
54         color_type m_c2;
55         unsigned   m_len;
56         unsigned   m_count;
57     };
58 
59     //========================================================================
60     // Fast specialization for rgba8
61     template<> struct color_interpolator<rgba8>
62     {
63     public:
64         typedef rgba8 color_type;
65 
66         color_interpolator(const color_type& c1,
67                            const color_type& c2,
68                            unsigned len) :
69             r(c1.r, c2.r, len),
70             g(c1.g, c2.g, len),
71             b(c1.b, c2.b, len),
72             a(c1.a, c2.a, len)
73         {}
74 
75         void operator ++ ()
76         {
77             ++r; ++g; ++b; ++a;
78         }
79 
80         color_type color() const
81         {
82             return color_type(r.y(), g.y(), b.y(), a.y());
83         }
84 
85     private:
86         agg::dda_line_interpolator<14> r, g, b, a;
87     };
88 
89     //========================================================================
90     // Fast specialization for gray8
91     template<> struct color_interpolator<gray8>
92     {
93     public:
94         typedef gray8 color_type;
95 
96         color_interpolator(const color_type& c1,
97                            const color_type& c2,
98                            unsigned len) :
99             v(c1.v, c2.v, len),
100             a(c1.a, c2.a, len)
101         {}
102 
103         void operator ++ ()
104         {
105             ++v; ++a;
106         }
107 
108         color_type color() const
109         {
110             return color_type(v.y(), a.y());
111         }
112 
113     private:
114         agg::dda_line_interpolator<14> v,a;
115     };
116 
117     //============================================================gradient_lut
118     template<class ColorInterpolator,
119              unsigned ColorLutSize=256> class gradient_lut
120     {
121     public:
122         typedef ColorInterpolator interpolator_type;
123         typedef typename interpolator_type::color_type color_type;
124         enum { color_lut_size = ColorLutSize };
125 
126         //--------------------------------------------------------------------
127         gradient_lut() : m_color_lut(color_lut_size) {}
128 
129         // Build Gradient Lut
130         // First, call remove_all(), then add_color() at least twice,
131         // then build_lut(). Argument "offset" in add_color must be
132         // in range [0...1] and defines a color stop as it is described
133         // in SVG specification, section Gradients and Patterns.
134         // The simplest linear gradient is:
135         //    gradient_lut.add_color(0.0, start_color);
136         //    gradient_lut.add_color(1.0, end_color);
137         //--------------------------------------------------------------------
138         void remove_all();
139         void add_color(double offset, const color_type& color);
140         void build_lut();
141 
142         // Size-index Interface. This class can be used directly as the
143         // ColorF in span_gradient. All it needs is two access methods
144         // size() and operator [].
145         //--------------------------------------------------------------------
146         static unsigned size()
147         {
148             return color_lut_size;
149         }
150         const color_type& operator [] (unsigned i) const
151         {
152             return m_color_lut[i];
153         }
154 
155     private:
156         //--------------------------------------------------------------------
157         struct color_point
158         {
159             double     offset;
160             color_type color;
161 
162             color_point() {}
163             color_point(double off, const color_type& c) :
164                 offset(off), color(c)
165             {
166                 if(offset < 0.0) offset = 0.0;
167                 if(offset > 1.0) offset = 1.0;
168             }
169         };
170         typedef agg::pod_bvector<color_point, 4> color_profile_type;
171         typedef agg::pod_array<color_type>       color_lut_type;
172 
173         static bool offset_less(const color_point& a, const color_point& b)
174         {
175             return a.offset < b.offset;
176         }
177         static bool offset_equal(const color_point& a, const color_point& b)
178         {
179             return a.offset == b.offset;
180         }
181 
182         //--------------------------------------------------------------------
183         color_profile_type  m_color_profile;
184         color_lut_type      m_color_lut;
185     };
186 
187 
188 
189     //------------------------------------------------------------------------
190     template<class T, unsigned S>
191     void gradient_lut<T,S>::remove_all()
192     {
193         m_color_profile.remove_all();
194     }
195 
196     //------------------------------------------------------------------------
197     template<class T, unsigned S>
198     void gradient_lut<T,S>::add_color(double offset, const color_type& color)
199     {
200         m_color_profile.add(color_point(offset, color));
201     }
202 
203     //------------------------------------------------------------------------
204     template<class T, unsigned S>
205     void gradient_lut<T,S>::build_lut()
206     {
207         quick_sort(m_color_profile, offset_less);
208         m_color_profile.cut_at(remove_duplicates(m_color_profile, offset_equal));
209         if(m_color_profile.size() >= 2)
210         {
211             unsigned i;
212             unsigned start = uround(m_color_profile[0].offset * color_lut_size);
213             unsigned end;
214             color_type c = m_color_profile[0].color;
215             for(i = 0; i < start; i++)
216             {
217                 m_color_lut[i] = c;
218             }
219             for(i = 1; i < m_color_profile.size(); i++)
220             {
221                 end  = uround(m_color_profile[i].offset * color_lut_size);
222                 interpolator_type ci(m_color_profile[i-1].color,
223                                      m_color_profile[i  ].color,
224                                      end - start + 1);
225                 while(start < end)
226                 {
227                     m_color_lut[start] = ci.color();
228                     ++ci;
229                     ++start;
230                 }
231             }
232             c = m_color_profile.last().color;
233             for(; end < m_color_lut.size(); end++)
234             {
235                 m_color_lut[end] = c;
236             }
237         }
238     }
239 }
240 
241 
242 
243 
244 #endif
245