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