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
20namespace 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;
32        static AGG_INLINE int mul_div(double a, double b, double c)
33        {
34            return iround(a * b / c);
35        }
36        static int xi(int v) { return v; }
37        static int yi(int v) { return v; }
38        static int upscale(double v) { return iround(v * poly_subpixel_scale); }
39        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;
46        static AGG_INLINE int mul_div(double a, double b, double c)
47        {
48            return saturation<poly_max_coord>::iround(a * b / c);
49        }
50        static int xi(int v) { return v; }
51        static int yi(int v) { return v; }
52        static int upscale(double v)
53        {
54            return saturation<poly_max_coord>::iround(v * poly_subpixel_scale);
55        }
56        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;
63        static AGG_INLINE int mul_div(double a, double b, double c)
64        {
65            return iround(a * b / c);
66        }
67        static int xi(int v) { return v * 3; }
68        static int yi(int v) { return v; }
69        static int upscale(double v) { return iround(v * poly_subpixel_scale); }
70        static int downscale(int v)  { return v; }
71    };
72
73    //-----------------------------------------------------------ras_conv_dbl
74    struct ras_conv_dbl
75    {
76        typedef double coord_type;
77        static AGG_INLINE double mul_div(double a, double b, double c)
78        {
79            return a * b / c;
80        }
81        static int xi(double v) { return iround(v * poly_subpixel_scale); }
82        static int yi(double v) { return iround(v * poly_subpixel_scale); }
83        static double upscale(double v) { return v; }
84        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;
91        static AGG_INLINE double mul_div(double a, double b, double c)
92        {
93            return a * b / c;
94        }
95        static int xi(double v) { return iround(v * poly_subpixel_scale * 3); }
96        static int yi(double v) { return iround(v * poly_subpixel_scale); }
97        static double upscale(double v) { return v; }
98        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        //--------------------------------------------------------------------
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        //--------------------------------------------------------------------
123        void reset_clipping()
124        {
125            m_clipping = false;
126        }
127
128        //--------------------------------------------------------------------
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        //--------------------------------------------------------------------
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>
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>
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
317        rasterizer_sl_no_clip() : m_x1(0), m_y1(0) {}
318
319        void reset_clipping() {}
320        void clip_box(coord_type x1, coord_type y1, coord_type x2, coord_type y2) {}
321        void move_to(coord_type x1, coord_type y1) { m_x1 = x1; m_y1 = y1; }
322
323        template<class Rasterizer>
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