1 //----------------------------------------------------------------------------
2 // Anti-Grain Geometry - Version 2.4
3 // Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com)
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.
10 //----------------------------------------------------------------------------
11 // Contact: mcseem@antigrain.com
12 // mcseemagg@yahoo.com
13 // http://www.antigrain.com
14 //----------------------------------------------------------------------------
16 // Adaptation for high precision colors has been sponsored by
17 // Liberty Technology Systems, Inc., visit http://lib-sys.com
19 // Liberty Technology Systems, Inc. is the provider of
20 // PostScript and PDF technology for software developers.
22 //----------------------------------------------------------------------------
24 #ifndef AGG_SPAN_GOURAUD_GRAY_INCLUDED
25 #define AGG_SPAN_GOURAUD_GRAY_INCLUDED
27 #include "agg_basics.h"
28 #include "agg_color_gray.h"
29 #include "agg_dda_line.h"
30 #include "agg_span_gouraud.h"
35 //=======================================================span_gouraud_gray
36 template<class ColorT
> class span_gouraud_gray
: public span_gouraud
<ColorT
>
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
;
46 subpixel_scale
= 1 << subpixel_shift
50 //--------------------------------------------------------------------
53 void init(const coord_type
& c1
, const coord_type
& c2
)
58 double dy
= c2
.y
- c1
.y
;
59 m_1dy
= (fabs(dy
) < 1e-10) ? 1e10
: 1.0 / dy
;
62 m_dv
= c2
.color
.v
- m_v1
;
63 m_da
= c2
.color
.a
- m_a1
;
68 double k
= (y
- m_y1
) * m_1dy
;
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
);
91 //--------------------------------------------------------------------
92 span_gouraud_gray() {}
93 span_gouraud_gray(const color_type
& c1
,
100 base_type(c1
, c2
, c3
, x1
, y1
, x2
, y2
, x3
, y3
, d
)
103 //--------------------------------------------------------------------
107 base_type::arrange_vertices(coord
);
109 m_y2
= int(coord
[1].y
);
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;
115 m_c1
.init(coord
[0], coord
[2]);
116 m_c2
.init(coord
[0], coord
[1]);
117 m_c3
.init(coord
[1], coord
[2]);
120 //--------------------------------------------------------------------
121 void generate(color_type
* span
, int x
, int y
, unsigned len
)
124 const gray_calc
* pc1
= &m_c1
;
125 const gray_calc
* pc2
= &m_c2
;
129 // Bottom part of the triangle (first subtriangle)
130 //-------------------------
131 m_c2
.calc(y
+ m_c2
.m_1dy
);
135 // Upper part (second subtriangle)
136 //-------------------------
137 m_c3
.calc(y
- m_c3
.m_1dy
);
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
;
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;
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
);
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
164 //-------------------------
165 int start
= pc1
->m_x
- (x
<< subpixel_shift
);
171 enum lim_e
{ lim
= color_type::base_mask
};
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)
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
;
189 nlen
-= subpixel_scale
;
190 start
-= subpixel_scale
;
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)
202 span
->v
= (value_type
)v
.y();
203 span
->a
= (value_type
)a
.y();
206 nlen
-= subpixel_scale
;
211 // Ending part; checking for overflow.
212 // Typically it's 1-2 pixels, but may be more in some cases.
213 //-------------------------
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
;