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