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