xref: /haiku/headers/libs/agg/agg_rasterizer_sl_clip.h (revision e39da397f5ff79f2db9f9a3ddf1852b6710578af)
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 #ifndef AGG_RASTERIZER_SL_CLIP_INCLUDED
16 #define AGG_RASTERIZER_SL_CLIP_INCLUDED
17 
18 #include "agg_clip_liang_barsky.h"
19 
20 namespace agg
21 {
22     //--------------------------------------------------------poly_max_coord_e
23     enum poly_max_coord_e
24     {
25         poly_max_coord = (1 << 30) - 1 //----poly_max_coord
26     };
27 
28     //------------------------------------------------------------ras_conv_int
29     struct ras_conv_int
30     {
31         typedef int coord_type;
mul_divras_conv_int32         static AGG_INLINE int mul_div(double a, double b, double c)
33         {
34             return iround(a * b / c);
35         }
xiras_conv_int36         static int xi(int v) { return v; }
yiras_conv_int37         static int yi(int v) { return v; }
upscaleras_conv_int38         static int upscale(double v) { return iround(v * poly_subpixel_scale); }
downscaleras_conv_int39         static int downscale(int v)  { return v; }
40     };
41 
42     //--------------------------------------------------------ras_conv_int_sat
43     struct ras_conv_int_sat
44     {
45         typedef int coord_type;
mul_divras_conv_int_sat46         static AGG_INLINE int mul_div(double a, double b, double c)
47         {
48             return saturation<poly_max_coord>::iround(a * b / c);
49         }
xiras_conv_int_sat50         static int xi(int v) { return v; }
yiras_conv_int_sat51         static int yi(int v) { return v; }
upscaleras_conv_int_sat52         static int upscale(double v)
53         {
54             return saturation<poly_max_coord>::iround(v * poly_subpixel_scale);
55         }
downscaleras_conv_int_sat56         static int downscale(int v) { return v; }
57     };
58 
59     //---------------------------------------------------------ras_conv_int_3x
60     struct ras_conv_int_3x
61     {
62         typedef int coord_type;
mul_divras_conv_int_3x63         static AGG_INLINE int mul_div(double a, double b, double c)
64         {
65             return iround(a * b / c);
66         }
xiras_conv_int_3x67         static int xi(int v) { return v * 3; }
yiras_conv_int_3x68         static int yi(int v) { return v; }
upscaleras_conv_int_3x69         static int upscale(double v) { return iround(v * poly_subpixel_scale); }
downscaleras_conv_int_3x70         static int downscale(int v)  { return v; }
71     };
72 
73     //-----------------------------------------------------------ras_conv_dbl
74     struct ras_conv_dbl
75     {
76         typedef double coord_type;
mul_divras_conv_dbl77         static AGG_INLINE double mul_div(double a, double b, double c)
78         {
79             return a * b / c;
80         }
xiras_conv_dbl81         static int xi(double v) { return iround(v * poly_subpixel_scale); }
yiras_conv_dbl82         static int yi(double v) { return iround(v * poly_subpixel_scale); }
upscaleras_conv_dbl83         static double upscale(double v) { return v; }
downscaleras_conv_dbl84         static double downscale(int v)  { return v / double(poly_subpixel_scale); }
85     };
86 
87     //--------------------------------------------------------ras_conv_dbl_3x
88     struct ras_conv_dbl_3x
89     {
90         typedef double coord_type;
mul_divras_conv_dbl_3x91         static AGG_INLINE double mul_div(double a, double b, double c)
92         {
93             return a * b / c;
94         }
xiras_conv_dbl_3x95         static int xi(double v) { return iround(v * poly_subpixel_scale * 3); }
yiras_conv_dbl_3x96         static int yi(double v) { return iround(v * poly_subpixel_scale); }
upscaleras_conv_dbl_3x97         static double upscale(double v) { return v; }
downscaleras_conv_dbl_3x98         static double downscale(int v)  { return v / double(poly_subpixel_scale); }
99     };
100 
101 
102 
103 
104 
105     //------------------------------------------------------rasterizer_sl_clip
106     template<class Conv> class rasterizer_sl_clip
107     {
108     public:
109         typedef Conv                      conv_type;
110         typedef typename Conv::coord_type coord_type;
111         typedef rect_base<coord_type>     rect_type;
112 
113         //--------------------------------------------------------------------
rasterizer_sl_clip()114         rasterizer_sl_clip() :
115             m_clip_box(0,0,0,0),
116             m_x1(0),
117             m_y1(0),
118             m_f1(0),
119             m_clipping(false)
120         {}
121 
122         //--------------------------------------------------------------------
reset_clipping()123         void reset_clipping()
124         {
125             m_clipping = false;
126         }
127 
128         //--------------------------------------------------------------------
clip_box(coord_type x1,coord_type y1,coord_type x2,coord_type y2)129         void clip_box(coord_type x1, coord_type y1, coord_type x2, coord_type y2)
130         {
131             m_clip_box = rect_type(x1, y1, x2, y2);
132             m_clip_box.normalize();
133             m_clipping = true;
134         }
135 
136         //--------------------------------------------------------------------
move_to(coord_type x1,coord_type y1)137         void move_to(coord_type x1, coord_type y1)
138         {
139             m_x1 = x1;
140             m_y1 = y1;
141             if(m_clipping) m_f1 = clipping_flags(x1, y1, m_clip_box);
142         }
143 
144     private:
145         //------------------------------------------------------------------------
146         template<class Rasterizer>
line_clip_y(Rasterizer & ras,coord_type x1,coord_type y1,coord_type x2,coord_type y2,unsigned f1,unsigned f2)147         AGG_INLINE void line_clip_y(Rasterizer& ras,
148                                     coord_type x1, coord_type y1,
149                                     coord_type x2, coord_type y2,
150                                     unsigned   f1, unsigned   f2) const
151         {
152             f1 &= 10;
153             f2 &= 10;
154             if((f1 | f2) == 0)
155             {
156                 // Fully visible
157                 ras.line(Conv::xi(x1), Conv::yi(y1), Conv::xi(x2), Conv::yi(y2));
158             }
159             else
160             {
161                 if(f1 == f2)
162                 {
163                     // Invisible by Y
164                     return;
165                 }
166 
167                 coord_type tx1 = x1;
168                 coord_type ty1 = y1;
169                 coord_type tx2 = x2;
170                 coord_type ty2 = y2;
171 
172                 if(f1 & 8) // y1 < clip.y1
173                 {
174                     tx1 = x1 + Conv::mul_div(m_clip_box.y1-y1, x2-x1, y2-y1);
175                     ty1 = m_clip_box.y1;
176                 }
177 
178                 if(f1 & 2) // y1 > clip.y2
179                 {
180                     tx1 = x1 + Conv::mul_div(m_clip_box.y2-y1, x2-x1, y2-y1);
181                     ty1 = m_clip_box.y2;
182                 }
183 
184                 if(f2 & 8) // y2 < clip.y1
185                 {
186                     tx2 = x1 + Conv::mul_div(m_clip_box.y1-y1, x2-x1, y2-y1);
187                     ty2 = m_clip_box.y1;
188                 }
189 
190                 if(f2 & 2) // y2 > clip.y2
191                 {
192                     tx2 = x1 + Conv::mul_div(m_clip_box.y2-y1, x2-x1, y2-y1);
193                     ty2 = m_clip_box.y2;
194                 }
195                 ras.line(Conv::xi(tx1), Conv::yi(ty1),
196                          Conv::xi(tx2), Conv::yi(ty2));
197             }
198         }
199 
200 
201     public:
202         //--------------------------------------------------------------------
203         template<class Rasterizer>
line_to(Rasterizer & ras,coord_type x2,coord_type y2)204         void line_to(Rasterizer& ras, coord_type x2, coord_type y2)
205         {
206             if(m_clipping)
207             {
208                 unsigned f2 = clipping_flags(x2, y2, m_clip_box);
209 
210                 if((m_f1 & 10) == (f2 & 10) && (m_f1 & 10) != 0)
211                 {
212                     // Invisible by Y
213                     m_x1 = x2;
214                     m_y1 = y2;
215                     m_f1 = f2;
216                     return;
217                 }
218 
219                 coord_type x1 = m_x1;
220                 coord_type y1 = m_y1;
221                 unsigned   f1 = m_f1;
222                 coord_type y3, y4;
223                 unsigned   f3, f4;
224 
225                 switch(((f1 & 5) << 1) | (f2 & 5))
226                 {
227                 case 0: // Visible by X
228                     line_clip_y(ras, x1, y1, x2, y2, f1, f2);
229                     break;
230 
231                 case 1: // x2 > clip.x2
232                     y3 = y1 + Conv::mul_div(m_clip_box.x2-x1, y2-y1, x2-x1);
233                     f3 = clipping_flags_y(y3, m_clip_box);
234                     line_clip_y(ras, x1, y1, m_clip_box.x2, y3, f1, f3);
235                     line_clip_y(ras, m_clip_box.x2, y3, m_clip_box.x2, y2, f3, f2);
236                     break;
237 
238                 case 2: // x1 > clip.x2
239                     y3 = y1 + Conv::mul_div(m_clip_box.x2-x1, y2-y1, x2-x1);
240                     f3 = clipping_flags_y(y3, m_clip_box);
241                     line_clip_y(ras, m_clip_box.x2, y1, m_clip_box.x2, y3, f1, f3);
242                     line_clip_y(ras, m_clip_box.x2, y3, x2, y2, f3, f2);
243                     break;
244 
245                 case 3: // x1 > clip.x2 && x2 > clip.x2
246                     line_clip_y(ras, m_clip_box.x2, y1, m_clip_box.x2, y2, f1, f2);
247                     break;
248 
249                 case 4: // x2 < clip.x1
250                     y3 = y1 + Conv::mul_div(m_clip_box.x1-x1, y2-y1, x2-x1);
251                     f3 = clipping_flags_y(y3, m_clip_box);
252                     line_clip_y(ras, x1, y1, m_clip_box.x1, y3, f1, f3);
253                     line_clip_y(ras, m_clip_box.x1, y3, m_clip_box.x1, y2, f3, f2);
254                     break;
255 
256                 case 6: // x1 > clip.x2 && x2 < clip.x1
257                     y3 = y1 + Conv::mul_div(m_clip_box.x2-x1, y2-y1, x2-x1);
258                     y4 = y1 + Conv::mul_div(m_clip_box.x1-x1, y2-y1, x2-x1);
259                     f3 = clipping_flags_y(y3, m_clip_box);
260                     f4 = clipping_flags_y(y4, m_clip_box);
261                     line_clip_y(ras, m_clip_box.x2, y1, m_clip_box.x2, y3, f1, f3);
262                     line_clip_y(ras, m_clip_box.x2, y3, m_clip_box.x1, y4, f3, f4);
263                     line_clip_y(ras, m_clip_box.x1, y4, m_clip_box.x1, y2, f4, f2);
264                     break;
265 
266                 case 8: // x1 < clip.x1
267                     y3 = y1 + Conv::mul_div(m_clip_box.x1-x1, y2-y1, x2-x1);
268                     f3 = clipping_flags_y(y3, m_clip_box);
269                     line_clip_y(ras, m_clip_box.x1, y1, m_clip_box.x1, y3, f1, f3);
270                     line_clip_y(ras, m_clip_box.x1, y3, x2, y2, f3, f2);
271                     break;
272 
273                 case 9:  // x1 < clip.x1 && x2 > clip.x2
274                     y3 = y1 + Conv::mul_div(m_clip_box.x1-x1, y2-y1, x2-x1);
275                     y4 = y1 + Conv::mul_div(m_clip_box.x2-x1, y2-y1, x2-x1);
276                     f3 = clipping_flags_y(y3, m_clip_box);
277                     f4 = clipping_flags_y(y4, m_clip_box);
278                     line_clip_y(ras, m_clip_box.x1, y1, m_clip_box.x1, y3, f1, f3);
279                     line_clip_y(ras, m_clip_box.x1, y3, m_clip_box.x2, y4, f3, f4);
280                     line_clip_y(ras, m_clip_box.x2, y4, m_clip_box.x2, y2, f4, f2);
281                     break;
282 
283                 case 12: // x1 < clip.x1 && x2 < clip.x1
284                     line_clip_y(ras, m_clip_box.x1, y1, m_clip_box.x1, y2, f1, f2);
285                     break;
286                 }
287                 m_f1 = f2;
288             }
289             else
290             {
291                 ras.line(Conv::xi(m_x1), Conv::yi(m_y1),
292                          Conv::xi(x2),   Conv::yi(y2));
293             }
294             m_x1 = x2;
295             m_y1 = y2;
296         }
297 
298 
299     private:
300         rect_type        m_clip_box;
301         coord_type       m_x1;
302         coord_type       m_y1;
303         unsigned         m_f1;
304         bool             m_clipping;
305     };
306 
307 
308 
309 
310     //---------------------------------------------------rasterizer_sl_no_clip
311     class rasterizer_sl_no_clip
312     {
313     public:
314         typedef ras_conv_int conv_type;
315         typedef int          coord_type;
316 
rasterizer_sl_no_clip()317         rasterizer_sl_no_clip() : m_x1(0), m_y1(0) {}
318 
reset_clipping()319         void reset_clipping() {}
clip_box(coord_type x1,coord_type y1,coord_type x2,coord_type y2)320         void clip_box(coord_type x1, coord_type y1, coord_type x2, coord_type y2) {}
move_to(coord_type x1,coord_type y1)321         void move_to(coord_type x1, coord_type y1) { m_x1 = x1; m_y1 = y1; }
322 
323         template<class Rasterizer>
line_to(Rasterizer & ras,coord_type x2,coord_type y2)324         void line_to(Rasterizer& ras, coord_type x2, coord_type y2)
325         {
326             ras.line(m_x1, m_y1, x2, y2);
327             m_x1 = x2;
328             m_y1 = y2;
329         }
330 
331     private:
332         int m_x1, m_y1;
333     };
334 
335 
336     //                                         -----rasterizer_sl_clip_int
337     //                                         -----rasterizer_sl_clip_int_sat
338     //                                         -----rasterizer_sl_clip_int_3x
339     //                                         -----rasterizer_sl_clip_dbl
340     //                                         -----rasterizer_sl_clip_dbl_3x
341     //------------------------------------------------------------------------
342     typedef rasterizer_sl_clip<ras_conv_int>     rasterizer_sl_clip_int;
343     typedef rasterizer_sl_clip<ras_conv_int_sat> rasterizer_sl_clip_int_sat;
344     typedef rasterizer_sl_clip<ras_conv_int_3x>  rasterizer_sl_clip_int_3x;
345     typedef rasterizer_sl_clip<ras_conv_dbl>     rasterizer_sl_clip_dbl;
346     typedef rasterizer_sl_clip<ras_conv_dbl_3x>  rasterizer_sl_clip_dbl_3x;
347 
348 
349 }
350 
351 #endif
352