Anti-Grain Geometry - AGG (libagg)
2.5
|
00001 //---------------------------------------------------------------------------- 00002 // Anti-Grain Geometry (AGG) - Version 2.5 00003 // A high quality rendering engine for C++ 00004 // Copyright (C) 2002-2006 Maxim Shemanarev 00005 // Contact: mcseem@antigrain.com 00006 // mcseemagg@yahoo.com 00007 // http://antigrain.com 00008 // 00009 // AGG is free software; you can redistribute it and/or 00010 // modify it under the terms of the GNU General Public License 00011 // as published by the Free Software Foundation; either version 2 00012 // of the License, or (at your option) any later version. 00013 // 00014 // AGG is distributed in the hope that it will be useful, 00015 // but WITHOUT ANY WARRANTY; without even the implied warranty of 00016 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00017 // GNU General Public License for more details. 00018 // 00019 // You should have received a copy of the GNU General Public License 00020 // along with AGG; if not, write to the Free Software 00021 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 00022 // MA 02110-1301, USA. 00023 //---------------------------------------------------------------------------- 00024 00025 #ifndef AGG_SPAN_GRADIENT_INCLUDED 00026 #define AGG_SPAN_GRADIENT_INCLUDED 00027 00028 #include <math.h> 00029 #include <stdlib.h> 00030 #include <string.h> 00031 #include "agg_basics.h" 00032 #include "agg_math.h" 00033 #include "agg_array.h" 00034 00035 00036 namespace agg 00037 { 00038 00039 enum gradient_subpixel_scale_e 00040 { 00041 gradient_subpixel_shift = 4, //-----gradient_subpixel_shift 00042 gradient_subpixel_scale = 1 << gradient_subpixel_shift, //-----gradient_subpixel_scale 00043 gradient_subpixel_mask = gradient_subpixel_scale - 1 //-----gradient_subpixel_mask 00044 }; 00045 00046 00047 00048 //==========================================================span_gradient 00049 template<class ColorT, 00050 class Interpolator, 00051 class GradientF, 00052 class ColorF> 00053 class span_gradient 00054 { 00055 public: 00056 typedef Interpolator interpolator_type; 00057 typedef ColorT color_type; 00058 00059 enum downscale_shift_e 00060 { 00061 downscale_shift = interpolator_type::subpixel_shift - 00062 gradient_subpixel_shift 00063 }; 00064 00065 //-------------------------------------------------------------------- 00066 span_gradient() {} 00067 00068 //-------------------------------------------------------------------- 00069 span_gradient(interpolator_type& inter, 00070 const GradientF& gradient_function, 00071 const ColorF& color_function, 00072 double d1, double d2) : 00073 m_interpolator(&inter), 00074 m_gradient_function(&gradient_function), 00075 m_color_function(&color_function), 00076 m_d1(iround(d1 * gradient_subpixel_scale)), 00077 m_d2(iround(d2 * gradient_subpixel_scale)) 00078 {} 00079 00080 //-------------------------------------------------------------------- 00081 interpolator_type& interpolator() { return *m_interpolator; } 00082 const GradientF& gradient_function() const { return *m_gradient_function; } 00083 const ColorF& color_function() const { return *m_color_function; } 00084 double d1() const { return double(m_d1) / gradient_subpixel_scale; } 00085 double d2() const { return double(m_d2) / gradient_subpixel_scale; } 00086 00087 //-------------------------------------------------------------------- 00088 void interpolator(interpolator_type& i) { m_interpolator = &i; } 00089 void gradient_function(const GradientF& gf) { m_gradient_function = &gf; } 00090 void color_function(const ColorF& cf) { m_color_function = &cf; } 00091 void d1(double v) { m_d1 = iround(v * gradient_subpixel_scale); } 00092 void d2(double v) { m_d2 = iround(v * gradient_subpixel_scale); } 00093 00094 //-------------------------------------------------------------------- 00095 void prepare() {} 00096 00097 //-------------------------------------------------------------------- 00098 void generate(color_type* span, int x, int y, unsigned len) 00099 { 00100 int dd = m_d2 - m_d1; 00101 if(dd < 1) dd = 1; 00102 m_interpolator->begin(x+0.5, y+0.5, len); 00103 do 00104 { 00105 m_interpolator->coordinates(&x, &y); 00106 int d = m_gradient_function->calculate(x >> downscale_shift, 00107 y >> downscale_shift, m_d2); 00108 d = ((d - m_d1) * (int)m_color_function->size()) / dd; 00109 if(d < 0) d = 0; 00110 if(d >= (int)m_color_function->size()) d = m_color_function->size() - 1; 00111 *span++ = (*m_color_function)[d]; 00112 ++(*m_interpolator); 00113 } 00114 while(--len); 00115 } 00116 00117 private: 00118 interpolator_type* m_interpolator; 00119 const GradientF* m_gradient_function; 00120 const ColorF* m_color_function; 00121 int m_d1; 00122 int m_d2; 00123 }; 00124 00125 00126 00127 00128 //=====================================================gradient_linear_color 00129 template<class ColorT> 00130 struct gradient_linear_color 00131 { 00132 typedef ColorT color_type; 00133 00134 gradient_linear_color() {} 00135 gradient_linear_color(const color_type& c1, const color_type& c2, 00136 unsigned size = 256) : 00137 m_c1(c1), m_c2(c2), m_size(size) {} 00138 00139 unsigned size() const { return m_size; } 00140 color_type operator [] (unsigned v) const 00141 { 00142 return m_c1.gradient(m_c2, double(v) / double(m_size - 1)); 00143 } 00144 00145 void colors(const color_type& c1, const color_type& c2, unsigned size = 256) 00146 { 00147 m_c1 = c1; 00148 m_c2 = c2; 00149 m_size = size; 00150 } 00151 00152 color_type m_c1; 00153 color_type m_c2; 00154 unsigned m_size; 00155 }; 00156 00157 00158 00159 00160 00161 00162 //==========================================================gradient_circle 00163 class gradient_circle 00164 { 00165 // Actually the same as radial. Just for compatibility 00166 public: 00167 static AGG_INLINE int calculate(int x, int y, int) 00168 { 00169 return int(fast_sqrt(x*x + y*y)); 00170 } 00171 }; 00172 00173 00174 //==========================================================gradient_radial 00175 class gradient_radial 00176 { 00177 public: 00178 static AGG_INLINE int calculate(int x, int y, int) 00179 { 00180 return int(fast_sqrt(x*x + y*y)); 00181 } 00182 }; 00183 00184 //========================================================gradient_radial_d 00185 class gradient_radial_d 00186 { 00187 public: 00188 static AGG_INLINE int calculate(int x, int y, int) 00189 { 00190 return uround(sqrt(double(x)*double(x) + double(y)*double(y))); 00191 } 00192 }; 00193 00194 //====================================================gradient_radial_focus 00195 class gradient_radial_focus 00196 { 00197 public: 00198 //--------------------------------------------------------------------- 00199 gradient_radial_focus() : 00200 m_r(100 * gradient_subpixel_scale), 00201 m_fx(0), 00202 m_fy(0) 00203 { 00204 update_values(); 00205 } 00206 00207 //--------------------------------------------------------------------- 00208 gradient_radial_focus(double r, double fx, double fy) : 00209 m_r (iround(r * gradient_subpixel_scale)), 00210 m_fx(iround(fx * gradient_subpixel_scale)), 00211 m_fy(iround(fy * gradient_subpixel_scale)) 00212 { 00213 update_values(); 00214 } 00215 00216 //--------------------------------------------------------------------- 00217 void init(double r, double fx, double fy) 00218 { 00219 m_r = iround(r * gradient_subpixel_scale); 00220 m_fx = iround(fx * gradient_subpixel_scale); 00221 m_fy = iround(fy * gradient_subpixel_scale); 00222 update_values(); 00223 } 00224 00225 //--------------------------------------------------------------------- 00226 double radius() const { return double(m_r) / gradient_subpixel_scale; } 00227 double focus_x() const { return double(m_fx) / gradient_subpixel_scale; } 00228 double focus_y() const { return double(m_fy) / gradient_subpixel_scale; } 00229 00230 //--------------------------------------------------------------------- 00231 int calculate(int x, int y, int) const 00232 { 00233 double dx = x - m_fx; 00234 double dy = y - m_fy; 00235 double d2 = dx * m_fy - dy * m_fx; 00236 double d3 = m_r2 * (dx * dx + dy * dy) - d2 * d2; 00237 return iround((dx * m_fx + dy * m_fy + sqrt(fabs(d3))) * m_mul); 00238 } 00239 00240 private: 00241 //--------------------------------------------------------------------- 00242 void update_values() 00243 { 00244 // Calculate the invariant values. In case the focal center 00245 // lies exactly on the gradient circle the divisor degenerates 00246 // into zero. In this case we just move the focal center by 00247 // one subpixel unit possibly in the direction to the origin (0,0) 00248 // and calculate the values again. 00249 //------------------------- 00250 m_r2 = double(m_r) * double(m_r); 00251 m_fx2 = double(m_fx) * double(m_fx); 00252 m_fy2 = double(m_fy) * double(m_fy); 00253 double d = (m_r2 - (m_fx2 + m_fy2)); 00254 if(d == 0) 00255 { 00256 if(m_fx) { if(m_fx < 0) ++m_fx; else --m_fx; } 00257 if(m_fy) { if(m_fy < 0) ++m_fy; else --m_fy; } 00258 m_fx2 = double(m_fx) * double(m_fx); 00259 m_fy2 = double(m_fy) * double(m_fy); 00260 d = (m_r2 - (m_fx2 + m_fy2)); 00261 } 00262 m_mul = m_r / d; 00263 } 00264 00265 int m_r; 00266 int m_fx; 00267 int m_fy; 00268 double m_r2; 00269 double m_fx2; 00270 double m_fy2; 00271 double m_mul; 00272 }; 00273 00274 00275 //==============================================================gradient_x 00276 class gradient_x 00277 { 00278 public: 00279 static int calculate(int x, int, int) { return x; } 00280 }; 00281 00282 00283 //==============================================================gradient_y 00284 class gradient_y 00285 { 00286 public: 00287 static int calculate(int, int y, int) { return y; } 00288 }; 00289 00290 //========================================================gradient_diamond 00291 class gradient_diamond 00292 { 00293 public: 00294 static AGG_INLINE int calculate(int x, int y, int) 00295 { 00296 int ax = abs(x); 00297 int ay = abs(y); 00298 return ax > ay ? ax : ay; 00299 } 00300 }; 00301 00302 //=============================================================gradient_xy 00303 class gradient_xy 00304 { 00305 public: 00306 static AGG_INLINE int calculate(int x, int y, int d) 00307 { 00308 return abs(x) * abs(y) / d; 00309 } 00310 }; 00311 00312 //========================================================gradient_sqrt_xy 00313 class gradient_sqrt_xy 00314 { 00315 public: 00316 static AGG_INLINE int calculate(int x, int y, int) 00317 { 00318 return fast_sqrt(abs(x) * abs(y)); 00319 } 00320 }; 00321 00322 //==========================================================gradient_conic 00323 class gradient_conic 00324 { 00325 public: 00326 static AGG_INLINE int calculate(int x, int y, int d) 00327 { 00328 return uround(fabs(atan2(double(y), double(x))) * double(d) / pi); 00329 } 00330 }; 00331 00332 //=================================================gradient_repeat_adaptor 00333 template<class GradientF> class gradient_repeat_adaptor 00334 { 00335 public: 00336 gradient_repeat_adaptor(const GradientF& gradient) : 00337 m_gradient(&gradient) {} 00338 00339 AGG_INLINE int calculate(int x, int y, int d) const 00340 { 00341 int ret = m_gradient->calculate(x, y, d) % d; 00342 if(ret < 0) ret += d; 00343 return ret; 00344 } 00345 00346 private: 00347 const GradientF* m_gradient; 00348 }; 00349 00350 //================================================gradient_reflect_adaptor 00351 template<class GradientF> class gradient_reflect_adaptor 00352 { 00353 public: 00354 gradient_reflect_adaptor(const GradientF& gradient) : 00355 m_gradient(&gradient) {} 00356 00357 AGG_INLINE int calculate(int x, int y, int d) const 00358 { 00359 int d2 = d << 1; 00360 int ret = m_gradient->calculate(x, y, d) % d2; 00361 if(ret < 0) ret += d2; 00362 if(ret >= d) ret = d2 - ret; 00363 return ret; 00364 } 00365 00366 private: 00367 const GradientF* m_gradient; 00368 }; 00369 00370 00371 } 00372 00373 #endif