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 #ifndef AGG_SPAN_GOURAUD_GRAY_INCLUDED 25 #define AGG_SPAN_GOURAUD_GRAY_INCLUDED 26 27 #include "agg_basics.h" 28 #include "agg_color_gray.h" 29 #include "agg_dda_line.h" 30 #include "agg_span_gouraud.h" 31 32 namespace agg 33 { 34 35 //=======================================================span_gouraud_gray 36 template<class ColorT> class span_gouraud_gray : public span_gouraud<ColorT> 37 { 38 public: 39 typedef ColorT color_type; 40 typedef typename color_type::value_type value_type; 41 typedef span_gouraud<color_type> base_type; 42 typedef typename base_type::coord_type coord_type; 43 enum subpixel_scale_e 44 { 45 subpixel_shift = 4, 46 subpixel_scale = 1 << subpixel_shift 47 }; 48 49 private: 50 //-------------------------------------------------------------------- 51 struct gray_calc 52 { 53 void init(const coord_type& c1, const coord_type& c2) 54 { 55 m_x1 = c1.x - 0.5; 56 m_y1 = c1.y - 0.5; 57 m_dx = c2.x - c1.x; 58 double dy = c2.y - c1.y; 59 m_1dy = (fabs(dy) < 1e-10) ? 1e10 : 1.0 / dy; 60 m_v1 = c1.color.v; 61 m_a1 = c1.color.a; 62 m_dv = c2.color.v - m_v1; 63 m_da = c2.color.a - m_a1; 64 } 65 66 void calc(double y) 67 { 68 double k = (y - m_y1) * m_1dy; 69 if(k < 0.0) k = 0.0; 70 if(k > 1.0) k = 1.0; 71 m_v = m_v1 + iround(m_dv * k); 72 m_a = m_a1 + iround(m_da * k); 73 m_x = iround((m_x1 + m_dx * k) * subpixel_scale); 74 } 75 76 double m_x1; 77 double m_y1; 78 double m_dx; 79 double m_1dy; 80 int m_v1; 81 int m_a1; 82 int m_dv; 83 int m_da; 84 int m_v; 85 int m_a; 86 int m_x; 87 }; 88 89 90 public: 91 //-------------------------------------------------------------------- 92 span_gouraud_gray() {} 93 span_gouraud_gray(const color_type& c1, 94 const color_type& c2, 95 const color_type& c3, 96 double x1, double y1, 97 double x2, double y2, 98 double x3, double y3, 99 double d = 0) : 100 base_type(c1, c2, c3, x1, y1, x2, y2, x3, y3, d) 101 {} 102 103 //-------------------------------------------------------------------- 104 void prepare() 105 { 106 coord_type coord[3]; 107 base_type::arrange_vertices(coord); 108 109 m_y2 = int(coord[1].y); 110 111 m_swap = cross_product(coord[0].x, coord[0].y, 112 coord[2].x, coord[2].y, 113 coord[1].x, coord[1].y) < 0.0; 114 115 m_c1.init(coord[0], coord[2]); 116 m_c2.init(coord[0], coord[1]); 117 m_c3.init(coord[1], coord[2]); 118 } 119 120 //-------------------------------------------------------------------- 121 void generate(color_type* span, int x, int y, unsigned len) 122 { 123 m_c1.calc(y); 124 const gray_calc* pc1 = &m_c1; 125 const gray_calc* pc2 = &m_c2; 126 127 if(y < m_y2) 128 { 129 // Bottom part of the triangle (first subtriangle) 130 //------------------------- 131 m_c2.calc(y + m_c2.m_1dy); 132 } 133 else 134 { 135 // Upper part (second subtriangle) 136 //------------------------- 137 m_c3.calc(y - m_c3.m_1dy); 138 pc2 = &m_c3; 139 } 140 141 if(m_swap) 142 { 143 // It means that the triangle is oriented clockwise, 144 // so that we need to swap the controlling structures 145 //------------------------- 146 const gray_calc* t = pc2; 147 pc2 = pc1; 148 pc1 = t; 149 } 150 151 // Get the horizontal length with subpixel accuracy 152 // and protect it from division by zero 153 //------------------------- 154 int nlen = abs(pc2->m_x - pc1->m_x); 155 if(nlen <= 0) nlen = 1; 156 157 dda_line_interpolator<14> v(pc1->m_v, pc2->m_v, nlen); 158 dda_line_interpolator<14> a(pc1->m_a, pc2->m_a, nlen); 159 160 // Calculate the starting point of the gradient with subpixel 161 // accuracy and correct (roll back) the interpolators. 162 // This operation will also clip the beginning of the span 163 // if necessary. 164 //------------------------- 165 int start = pc1->m_x - (x << subpixel_shift); 166 v -= start; 167 a -= start; 168 nlen += start; 169 170 int vv, va; 171 enum lim_e { lim = color_type::base_mask }; 172 173 // Beginning part of the span. Since we rolled back the 174 // interpolators, the color values may have overflow. 175 // So that, we render the beginning part with checking 176 // for overflow. It lasts until "start" is positive; 177 // typically it's 1-2 pixels, but may be more in some cases. 178 //------------------------- 179 while(len && start > 0) 180 { 181 vv = v.y(); 182 va = a.y(); 183 if(vv < 0) vv = 0; if(vv > lim) vv = lim; 184 if(va < 0) va = 0; if(va > lim) va = lim; 185 span->v = (value_type)vv; 186 span->a = (value_type)va; 187 v += subpixel_scale; 188 a += subpixel_scale; 189 nlen -= subpixel_scale; 190 start -= subpixel_scale; 191 ++span; 192 --len; 193 } 194 195 // Middle part, no checking for overflow. 196 // Actual spans can be longer than the calculated length 197 // because of anti-aliasing, thus, the interpolators can 198 // overflow. But while "nlen" is positive we are safe. 199 //------------------------- 200 while(len && nlen > 0) 201 { 202 span->v = (value_type)v.y(); 203 span->a = (value_type)a.y(); 204 v += subpixel_scale; 205 a += subpixel_scale; 206 nlen -= subpixel_scale; 207 ++span; 208 --len; 209 } 210 211 // Ending part; checking for overflow. 212 // Typically it's 1-2 pixels, but may be more in some cases. 213 //------------------------- 214 while(len) 215 { 216 vv = v.y(); 217 va = a.y(); 218 if(vv < 0) vv = 0; if(vv > lim) vv = lim; 219 if(va < 0) va = 0; if(va > lim) va = lim; 220 span->v = (value_type)vv; 221 span->a = (value_type)va; 222 v += subpixel_scale; 223 a += subpixel_scale; 224 ++span; 225 --len; 226 } 227 } 228 229 230 private: 231 bool m_swap; 232 int m_y2; 233 gray_calc m_c1; 234 gray_calc m_c2; 235 gray_calc m_c3; 236 }; 237 238 239 } 240 241 #endif 242