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// class renderer_mclip
17//
18//----------------------------------------------------------------------------
19
20#ifndef AGG_RENDERER_MCLIP_INCLUDED
21#define AGG_RENDERER_MCLIP_INCLUDED
22
23#include "agg_basics.h"
24#include "agg_array.h"
25#include "agg_renderer_base.h"
26
27namespace agg
28{
29
30    //----------------------------------------------------------renderer_mclip
31    template<class PixelFormat> class renderer_mclip
32    {
33    public:
34        typedef PixelFormat pixfmt_type;
35        typedef typename pixfmt_type::color_type color_type;
36        typedef typename pixfmt_type::row_data row_data;
37        typedef renderer_base<pixfmt_type> base_ren_type;
38
39        //--------------------------------------------------------------------
40        renderer_mclip(pixfmt_type& pixf) :
41            m_ren(pixf),
42            m_curr_cb(0),
43            m_bounds(m_ren.xmin(), m_ren.ymin(), m_ren.xmax(), m_ren.ymax())
44        {}
45        void attach(pixfmt_type& pixf)
46        {
47            m_ren.attach(pixf);
48            reset_clipping(true);
49        }
50
51        //--------------------------------------------------------------------
52        const pixfmt_type& ren() const { return m_ren.ren();  }
53        pixfmt_type& ren() { return m_ren.ren();  }
54
55        //--------------------------------------------------------------------
56        unsigned width()  const { return m_ren.width();  }
57        unsigned height() const { return m_ren.height(); }
58
59        //--------------------------------------------------------------------
60        const rect_i& clip_box() const { return m_ren.clip_box(); }
61        int           xmin()     const { return m_ren.xmin(); }
62        int           ymin()     const { return m_ren.ymin(); }
63        int           xmax()     const { return m_ren.xmax(); }
64        int           ymax()     const { return m_ren.ymax(); }
65
66        //--------------------------------------------------------------------
67        const rect_i& bounding_clip_box() const { return m_bounds;    }
68        int           bounding_xmin()     const { return m_bounds.x1; }
69        int           bounding_ymin()     const { return m_bounds.y1; }
70        int           bounding_xmax()     const { return m_bounds.x2; }
71        int           bounding_ymax()     const { return m_bounds.y2; }
72
73        //--------------------------------------------------------------------
74        void first_clip_box()
75        {
76            m_curr_cb = 0;
77            if(m_clip.size())
78            {
79                const rect_i& cb = m_clip[0];
80                m_ren.clip_box_naked(cb.x1, cb.y1, cb.x2, cb.y2);
81            }
82        }
83
84        //--------------------------------------------------------------------
85        bool next_clip_box()
86        {
87            if(++m_curr_cb < m_clip.size())
88            {
89                const rect_i& cb = m_clip[m_curr_cb];
90                m_ren.clip_box_naked(cb.x1, cb.y1, cb.x2, cb.y2);
91                return true;
92            }
93            return false;
94        }
95
96        //--------------------------------------------------------------------
97        void reset_clipping(bool visibility)
98        {
99            m_ren.reset_clipping(visibility);
100            m_clip.remove_all();
101            m_curr_cb = 0;
102            m_bounds = m_ren.clip_box();
103        }
104
105        //--------------------------------------------------------------------
106        void add_clip_box(int x1, int y1, int x2, int y2)
107        {
108            rect_i cb(x1, y1, x2, y2);
109            cb.normalize();
110            if(cb.clip(rect_i(0, 0, width() - 1, height() - 1)))
111            {
112                m_clip.add(cb);
113                if(cb.x1 < m_bounds.x1) m_bounds.x1 = cb.x1;
114                if(cb.y1 < m_bounds.y1) m_bounds.y1 = cb.y1;
115                if(cb.x2 > m_bounds.x2) m_bounds.x2 = cb.x2;
116                if(cb.y2 > m_bounds.y2) m_bounds.y2 = cb.y2;
117            }
118        }
119
120        //--------------------------------------------------------------------
121        void clear(const color_type& c)
122        {
123            m_ren.clear(c);
124        }
125
126        //--------------------------------------------------------------------
127        void copy_pixel(int x, int y, const color_type& c)
128        {
129            first_clip_box();
130            do
131            {
132                if(m_ren.inbox(x, y))
133                {
134                    m_ren.ren().copy_pixel(x, y, c);
135                    break;
136                }
137            }
138            while(next_clip_box());
139        }
140
141        //--------------------------------------------------------------------
142        void blend_pixel(int x, int y, const color_type& c, cover_type cover)
143        {
144            first_clip_box();
145            do
146            {
147                if(m_ren.inbox(x, y))
148                {
149                    m_ren.ren().blend_pixel(x, y, c, cover);
150                    break;
151                }
152            }
153            while(next_clip_box());
154        }
155
156        //--------------------------------------------------------------------
157        color_type pixel(int x, int y) const
158        {
159            first_clip_box();
160            do
161            {
162                if(m_ren.inbox(x, y))
163                {
164                    return m_ren.ren().pixel(x, y);
165                }
166            }
167            while(next_clip_box());
168            return color_type::no_color();
169        }
170
171        //--------------------------------------------------------------------
172        void copy_hline(int x1, int y, int x2, const color_type& c)
173        {
174            first_clip_box();
175            do
176            {
177                m_ren.copy_hline(x1, y, x2, c);
178            }
179            while(next_clip_box());
180        }
181
182        //--------------------------------------------------------------------
183        void copy_vline(int x, int y1, int y2, const color_type& c)
184        {
185            first_clip_box();
186            do
187            {
188                m_ren.copy_vline(x, y1, y2, c);
189            }
190            while(next_clip_box());
191        }
192
193        //--------------------------------------------------------------------
194        void blend_hline(int x1, int y, int x2,
195                         const color_type& c, cover_type cover)
196        {
197            first_clip_box();
198            do
199            {
200                m_ren.blend_hline(x1, y, x2, c, cover);
201            }
202            while(next_clip_box());
203        }
204
205        //--------------------------------------------------------------------
206        void blend_vline(int x, int y1, int y2,
207                         const color_type& c, cover_type cover)
208        {
209            first_clip_box();
210            do
211            {
212                m_ren.blend_vline(x, y1, y2, c, cover);
213            }
214            while(next_clip_box());
215        }
216
217        //--------------------------------------------------------------------
218        void copy_bar(int x1, int y1, int x2, int y2, const color_type& c)
219        {
220            first_clip_box();
221            do
222            {
223                m_ren.copy_bar(x1, y1, x2, y2, c);
224            }
225            while(next_clip_box());
226        }
227
228        //--------------------------------------------------------------------
229        void blend_bar(int x1, int y1, int x2, int y2,
230                       const color_type& c, cover_type cover)
231        {
232            first_clip_box();
233            do
234            {
235                m_ren.blend_bar(x1, y1, x2, y2, c, cover);
236            }
237            while(next_clip_box());
238        }
239
240        //--------------------------------------------------------------------
241        void blend_solid_hspan(int x, int y, int len,
242                               const color_type& c, const cover_type* covers)
243        {
244            first_clip_box();
245            do
246            {
247                m_ren.blend_solid_hspan(x, y, len, c, covers);
248            }
249            while(next_clip_box());
250        }
251
252        //--------------------------------------------------------------------
253        void blend_solid_vspan(int x, int y, int len,
254                               const color_type& c, const cover_type* covers)
255        {
256            first_clip_box();
257            do
258            {
259                m_ren.blend_solid_vspan(x, y, len, c, covers);
260            }
261            while(next_clip_box());
262        }
263
264
265        //--------------------------------------------------------------------
266        void copy_color_hspan(int x, int y, int len, const color_type* colors)
267        {
268            first_clip_box();
269            do
270            {
271                m_ren.copy_color_hspan(x, y, len, colors);
272            }
273            while(next_clip_box());
274        }
275
276        //--------------------------------------------------------------------
277        void blend_color_hspan(int x, int y, int len,
278                               const color_type* colors,
279                               const cover_type* covers,
280                               cover_type cover = cover_full)
281        {
282            first_clip_box();
283            do
284            {
285                m_ren.blend_color_hspan(x, y, len, colors, covers, cover);
286            }
287            while(next_clip_box());
288        }
289
290        //--------------------------------------------------------------------
291        void blend_color_vspan(int x, int y, int len,
292                               const color_type* colors,
293                               const cover_type* covers,
294                               cover_type cover = cover_full)
295        {
296            first_clip_box();
297            do
298            {
299                m_ren.blend_color_vspan(x, y, len, colors, covers, cover);
300            }
301            while(next_clip_box());
302        }
303
304        //--------------------------------------------------------------------
305        void copy_from(const rendering_buffer& from,
306                       const rect_i* rc=0,
307                       int x_to=0,
308                       int y_to=0)
309        {
310            first_clip_box();
311            do
312            {
313                m_ren.copy_from(from, rc, x_to, y_to);
314            }
315            while(next_clip_box());
316        }
317
318        //--------------------------------------------------------------------
319        template<class SrcPixelFormatRenderer>
320        void blend_from(const SrcPixelFormatRenderer& src,
321                        const rect_i* rect_src_ptr = 0,
322                        int dx = 0,
323                        int dy = 0,
324                        cover_type cover = cover_full)
325        {
326            first_clip_box();
327            do
328            {
329                m_ren.blend_from(src, rect_src_ptr, dx, dy, cover);
330            }
331            while(next_clip_box());
332        }
333
334
335    private:
336        renderer_mclip(const renderer_mclip<PixelFormat>&);
337        const renderer_mclip<PixelFormat>&
338            operator = (const renderer_mclip<PixelFormat>&);
339
340        base_ren_type          m_ren;
341        pod_bvector<rect_i, 4> m_clip;
342        unsigned               m_curr_cb;
343        rect_i                 m_bounds;
344    };
345
346
347}
348
349#endif
350