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