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_base
17//
18//----------------------------------------------------------------------------
19
20#ifndef AGG_RENDERER_BASE_INCLUDED
21#define AGG_RENDERER_BASE_INCLUDED
22
23#include "agg_basics.h"
24#include "agg_rendering_buffer.h"
25
26namespace agg
27{
28
29    //-----------------------------------------------------------renderer_base
30    template<class PixelFormat> class renderer_base
31    {
32    public:
33        typedef PixelFormat pixfmt_type;
34        typedef typename pixfmt_type::color_type color_type;
35        typedef typename pixfmt_type::row_data row_data;
36
37        //--------------------------------------------------------------------
38        renderer_base() : m_ren(0), m_clip_box(1, 1, 0, 0) {}
39        renderer_base(pixfmt_type& ren) :
40            m_ren(&ren),
41            m_clip_box(0, 0, ren.width() - 1, ren.height() - 1)
42        {}
43        void attach(pixfmt_type& ren)
44        {
45            m_ren = &ren;
46            m_clip_box = rect_i(0, 0, ren.width() - 1, ren.height() - 1);
47        }
48
49        //--------------------------------------------------------------------
50        const pixfmt_type& ren() const { return *m_ren;  }
51        pixfmt_type& ren() { return *m_ren;  }
52
53        //--------------------------------------------------------------------
54        unsigned width()  const { return m_ren->width();  }
55        unsigned height() const { return m_ren->height(); }
56
57        //--------------------------------------------------------------------
58        bool clip_box(int x1, int y1, int x2, int y2)
59        {
60            rect_i cb(x1, y1, x2, y2);
61            cb.normalize();
62            if(cb.clip(rect_i(0, 0, width() - 1, height() - 1)))
63            {
64                m_clip_box = cb;
65                return true;
66            }
67            m_clip_box.x1 = 1;
68            m_clip_box.y1 = 1;
69            m_clip_box.x2 = 0;
70            m_clip_box.y2 = 0;
71            return false;
72        }
73
74        //--------------------------------------------------------------------
75        void reset_clipping(bool visibility)
76        {
77            if(visibility)
78            {
79                m_clip_box.x1 = 0;
80                m_clip_box.y1 = 0;
81                m_clip_box.x2 = width() - 1;
82                m_clip_box.y2 = height() - 1;
83            }
84            else
85            {
86                m_clip_box.x1 = 1;
87                m_clip_box.y1 = 1;
88                m_clip_box.x2 = 0;
89                m_clip_box.y2 = 0;
90            }
91        }
92
93        //--------------------------------------------------------------------
94        void clip_box_naked(int x1, int y1, int x2, int y2)
95        {
96            m_clip_box.x1 = x1;
97            m_clip_box.y1 = y1;
98            m_clip_box.x2 = x2;
99            m_clip_box.y2 = y2;
100        }
101
102        //--------------------------------------------------------------------
103        bool inbox(int x, int y) const
104        {
105            return x >= m_clip_box.x1 && y >= m_clip_box.y1 &&
106                   x <= m_clip_box.x2 && y <= m_clip_box.y2;
107        }
108
109        //--------------------------------------------------------------------
110        const rect_i& clip_box() const { return m_clip_box;    }
111        int           xmin()     const { return m_clip_box.x1; }
112        int           ymin()     const { return m_clip_box.y1; }
113        int           xmax()     const { return m_clip_box.x2; }
114        int           ymax()     const { return m_clip_box.y2; }
115
116        //--------------------------------------------------------------------
117        const rect_i& bounding_clip_box() const { return m_clip_box;    }
118        int           bounding_xmin()     const { return m_clip_box.x1; }
119        int           bounding_ymin()     const { return m_clip_box.y1; }
120        int           bounding_xmax()     const { return m_clip_box.x2; }
121        int           bounding_ymax()     const { return m_clip_box.y2; }
122
123        //--------------------------------------------------------------------
124        void clear(const color_type& c)
125        {
126            unsigned y;
127            if(width())
128            {
129                for(y = 0; y < height(); y++)
130                {
131                    m_ren->copy_hline(0, y, width(), c);
132                }
133            }
134        }
135
136
137        //--------------------------------------------------------------------
138        void copy_pixel(int x, int y, const color_type& c)
139        {
140            if(inbox(x, y))
141            {
142                m_ren->copy_pixel(x, y, c);
143            }
144        }
145
146        //--------------------------------------------------------------------
147        void blend_pixel(int x, int y, const color_type& c, cover_type cover)
148        {
149            if(inbox(x, y))
150            {
151                m_ren->blend_pixel(x, y, c, cover);
152            }
153        }
154
155        //--------------------------------------------------------------------
156        color_type pixel(int x, int y) const
157        {
158            return inbox(x, y) ?
159                   m_ren->pixel(x, y) :
160                   color_type::no_color();
161        }
162
163        //--------------------------------------------------------------------
164        void copy_hline(int x1, int y, int x2, const color_type& c)
165        {
166            if(x1 > x2) { int t = x2; x2 = x1; x1 = t; }
167            if(y  > ymax()) return;
168            if(y  < ymin()) return;
169            if(x1 > xmax()) return;
170            if(x2 < xmin()) return;
171
172            if(x1 < xmin()) x1 = xmin();
173            if(x2 > xmax()) x2 = xmax();
174
175            m_ren->copy_hline(x1, y, x2 - x1 + 1, c);
176        }
177
178        //--------------------------------------------------------------------
179        void copy_vline(int x, int y1, int y2, const color_type& c)
180        {
181            if(y1 > y2) { int t = y2; y2 = y1; y1 = t; }
182            if(x  > xmax()) return;
183            if(x  < xmin()) return;
184            if(y1 > ymax()) return;
185            if(y2 < ymin()) return;
186
187            if(y1 < ymin()) y1 = ymin();
188            if(y2 > ymax()) y2 = ymax();
189
190            m_ren->copy_vline(x, y1, y2 - y1 + 1, c);
191        }
192
193        //--------------------------------------------------------------------
194        void blend_hline(int x1, int y, int x2,
195                         const color_type& c, cover_type cover)
196        {
197            if(x1 > x2) { int t = x2; x2 = x1; x1 = t; }
198            if(y  > ymax()) return;
199            if(y  < ymin()) return;
200            if(x1 > xmax()) return;
201            if(x2 < xmin()) return;
202
203            if(x1 < xmin()) x1 = xmin();
204            if(x2 > xmax()) x2 = xmax();
205
206            m_ren->blend_hline(x1, y, x2 - x1 + 1, c, cover);
207        }
208
209
210        //--------------------------------------------------------------------
211        void blend_vline(int x, int y1, int y2,
212                         const color_type& c, cover_type cover)
213        {
214            if(y1 > y2) { int t = y2; y2 = y1; y1 = t; }
215            if(x  > xmax()) return;
216            if(x  < xmin()) return;
217            if(y1 > ymax()) return;
218            if(y2 < ymin()) return;
219
220            if(y1 < ymin()) y1 = ymin();
221            if(y2 > ymax()) y2 = ymax();
222
223            m_ren->blend_vline(x, y1, y2 - y1 + 1, c, cover);
224        }
225
226
227        //--------------------------------------------------------------------
228        void copy_bar(int x1, int y1, int x2, int y2, const color_type& c)
229        {
230            rect_i rc(x1, y1, x2, y2);
231            rc.normalize();
232            if(rc.clip(clip_box()))
233            {
234                int y;
235                for(y = rc.y1; y <= rc.y2; y++)
236                {
237                    m_ren->copy_hline(rc.x1, y, unsigned(rc.x2 - rc.x1 + 1), c);
238                }
239            }
240        }
241
242        //--------------------------------------------------------------------
243        void blend_bar(int x1, int y1, int x2, int y2,
244                       const color_type& c, cover_type cover)
245        {
246            rect_i rc(x1, y1, x2, y2);
247            rc.normalize();
248            if(rc.clip(clip_box()))
249            {
250                int y;
251                for(y = rc.y1; y <= rc.y2; y++)
252                {
253                    m_ren->blend_hline(rc.x1,
254                                       y,
255                                       unsigned(rc.x2 - rc.x1 + 1),
256                                       c,
257                                       cover);
258                }
259            }
260        }
261
262        //--------------------------------------------------------------------
263        void blend_solid_hspan(int x, int y, int len,
264                               const color_type& c,
265                               const cover_type* covers)
266        {
267            if(y > ymax()) return;
268            if(y < ymin()) return;
269
270            if(x < xmin())
271            {
272                len -= xmin() - x;
273                if(len <= 0) return;
274                covers += xmin() - x;
275                x = xmin();
276            }
277            if(x + len > xmax())
278            {
279                len = xmax() - x + 1;
280                if(len <= 0) return;
281            }
282            m_ren->blend_solid_hspan(x, y, len, c, covers);
283        }
284
285		//--------------------------------------------------------------------
286        void blend_solid_hspan_subpix(int x, int y, int len,
287                                      const color_type& c,
288                                      const cover_type* covers)
289        {
290            if(y > ymax()) return;
291            if(y < ymin()) return;
292
293            if(x < xmin())
294            {
295                len -= 3 * (xmin() - x);
296                if(len <= 0) return;
297                covers += 3 * (xmin() - x);
298                x = xmin();
299            }
300            if(x + len / 3 > xmax())
301            {
302                len = 3 * (xmax() - x + 1);
303                if(len <= 0) return;
304            }
305            m_ren->blend_solid_hspan_subpix(x, y, len, c, covers);
306        }
307
308        //--------------------------------------------------------------------
309        void blend_solid_vspan(int x, int y, int len,
310                               const color_type& c,
311                               const cover_type* covers)
312        {
313            if(x > xmax()) return;
314            if(x < xmin()) return;
315
316            if(y < ymin())
317            {
318                len -= ymin() - y;
319                if(len <= 0) return;
320                covers += ymin() - y;
321                y = ymin();
322            }
323            if(y + len > ymax())
324            {
325                len = ymax() - y + 1;
326                if(len <= 0) return;
327            }
328            m_ren->blend_solid_vspan(x, y, len, c, covers);
329        }
330
331
332        //--------------------------------------------------------------------
333        void copy_color_hspan(int x, int y, int len, const color_type* colors)
334        {
335            if(y > ymax()) return;
336            if(y < ymin()) return;
337
338            if(x < xmin())
339            {
340                int d = xmin() - x;
341                len -= d;
342                if(len <= 0) return;
343                colors += d;
344                x = xmin();
345            }
346            if(x + len > xmax())
347            {
348                len = xmax() - x + 1;
349                if(len <= 0) return;
350            }
351            m_ren->copy_color_hspan(x, y, len, colors);
352        }
353
354
355        //--------------------------------------------------------------------
356        void copy_color_vspan(int x, int y, int len, const color_type* colors)
357        {
358            if(x > xmax()) return;
359            if(x < xmin()) return;
360
361            if(y < ymin())
362            {
363                int d = ymin() - y;
364                len -= d;
365                if(len <= 0) return;
366                colors += d;
367                y = ymin();
368            }
369            if(y + len > ymax())
370            {
371                len = ymax() - y + 1;
372                if(len <= 0) return;
373            }
374            m_ren->copy_color_vspan(x, y, len, colors);
375        }
376
377
378        //--------------------------------------------------------------------
379        void blend_color_hspan(int x, int y, int len,
380                               const color_type* colors,
381                               const cover_type* covers,
382                               cover_type cover = agg::cover_full)
383        {
384            if(y > ymax()) return;
385            if(y < ymin()) return;
386
387            if(x < xmin())
388            {
389                int d = xmin() - x;
390                len -= d;
391                if(len <= 0) return;
392                if(covers) covers += d;
393                colors += d;
394                x = xmin();
395            }
396            if(x + len > xmax())
397            {
398                len = xmax() - x + 1;
399                if(len <= 0) return;
400            }
401            m_ren->blend_color_hspan(x, y, len, colors, covers, cover);
402        }
403
404        //--------------------------------------------------------------------
405        void blend_color_vspan(int x, int y, int len,
406                               const color_type* colors,
407                               const cover_type* covers,
408                               cover_type cover = agg::cover_full)
409        {
410            if(x > xmax()) return;
411            if(x < xmin()) return;
412
413            if(y < ymin())
414            {
415                int d = ymin() - y;
416                len -= d;
417                if(len <= 0) return;
418                if(covers) covers += d;
419                colors += d;
420                y = ymin();
421            }
422            if(y + len > ymax())
423            {
424                len = ymax() - y + 1;
425                if(len <= 0) return;
426            }
427            m_ren->blend_color_vspan(x, y, len, colors, covers, cover);
428        }
429
430        //--------------------------------------------------------------------
431        rect_i clip_rect_area(rect_i& dst, rect_i& src, int wsrc, int hsrc) const
432        {
433            rect_i rc(0,0,0,0);
434            rect_i cb = clip_box();
435            ++cb.x2;
436            ++cb.y2;
437
438            if(src.x1 < 0)
439            {
440                dst.x1 -= src.x1;
441                src.x1 = 0;
442            }
443            if(src.y1 < 0)
444            {
445                dst.y1 -= src.y1;
446                src.y1 = 0;
447            }
448
449            if(src.x2 > wsrc) src.x2 = wsrc;
450            if(src.y2 > hsrc) src.y2 = hsrc;
451
452            if(dst.x1 < cb.x1)
453            {
454                src.x1 += cb.x1 - dst.x1;
455                dst.x1 = cb.x1;
456            }
457            if(dst.y1 < cb.y1)
458            {
459                src.y1 += cb.y1 - dst.y1;
460                dst.y1 = cb.y1;
461            }
462
463            if(dst.x2 > cb.x2) dst.x2 = cb.x2;
464            if(dst.y2 > cb.y2) dst.y2 = cb.y2;
465
466            rc.x2 = dst.x2 - dst.x1;
467            rc.y2 = dst.y2 - dst.y1;
468
469            if(rc.x2 > src.x2 - src.x1) rc.x2 = src.x2 - src.x1;
470            if(rc.y2 > src.y2 - src.y1) rc.y2 = src.y2 - src.y1;
471            return rc;
472        }
473
474        //--------------------------------------------------------------------
475        template<class RenBuf>
476        void copy_from(const RenBuf& src,
477                       const rect_i* rect_src_ptr = 0,
478                       int dx = 0,
479                       int dy = 0)
480        {
481            rect_i rsrc(0, 0, src.width(), src.height());
482            if(rect_src_ptr)
483            {
484                rsrc.x1 = rect_src_ptr->x1;
485                rsrc.y1 = rect_src_ptr->y1;
486                rsrc.x2 = rect_src_ptr->x2 + 1;
487                rsrc.y2 = rect_src_ptr->y2 + 1;
488            }
489
490            // Version with xdst, ydst (absolute positioning)
491            //rect_i rdst(xdst, ydst, xdst + rsrc.x2 - rsrc.x1, ydst + rsrc.y2 - rsrc.y1);
492
493            // Version with dx, dy (relative positioning)
494            rect_i rdst(rsrc.x1 + dx, rsrc.y1 + dy, rsrc.x2 + dx, rsrc.y2 + dy);
495
496            rect_i rc = clip_rect_area(rdst, rsrc, src.width(), src.height());
497
498            if(rc.x2 > 0)
499            {
500                int incy = 1;
501                if(rdst.y1 > rsrc.y1)
502                {
503                    rsrc.y1 += rc.y2 - 1;
504                    rdst.y1 += rc.y2 - 1;
505                    incy = -1;
506                }
507                while(rc.y2 > 0)
508                {
509                    m_ren->copy_from(src,
510                                     rdst.x1, rdst.y1,
511                                     rsrc.x1, rsrc.y1,
512                                     rc.x2);
513                    rdst.y1 += incy;
514                    rsrc.y1 += incy;
515                    --rc.y2;
516                }
517            }
518        }
519
520        //--------------------------------------------------------------------
521        template<class SrcPixelFormatRenderer>
522        void blend_from(const SrcPixelFormatRenderer& src,
523                        const rect_i* rect_src_ptr = 0,
524                        int dx = 0,
525                        int dy = 0,
526                        cover_type cover = agg::cover_full)
527        {
528            rect_i rsrc(0, 0, src.width(), src.height());
529            if(rect_src_ptr)
530            {
531                rsrc.x1 = rect_src_ptr->x1;
532                rsrc.y1 = rect_src_ptr->y1;
533                rsrc.x2 = rect_src_ptr->x2 + 1;
534                rsrc.y2 = rect_src_ptr->y2 + 1;
535            }
536
537            // Version with xdst, ydst (absolute positioning)
538            //rect_i rdst(xdst, ydst, xdst + rsrc.x2 - rsrc.x1, ydst + rsrc.y2 - rsrc.y1);
539
540            // Version with dx, dy (relative positioning)
541            rect_i rdst(rsrc.x1 + dx, rsrc.y1 + dy, rsrc.x2 + dx, rsrc.y2 + dy);
542            rect_i rc = clip_rect_area(rdst, rsrc, src.width(), src.height());
543
544            if(rc.x2 > 0)
545            {
546                int incy = 1;
547                if(rdst.y1 > rsrc.y1)
548                {
549                    rsrc.y1 += rc.y2 - 1;
550                    rdst.y1 += rc.y2 - 1;
551                    incy = -1;
552                }
553                while(rc.y2 > 0)
554                {
555                    typename SrcPixelFormatRenderer::row_data rw = src.row(rsrc.y1);
556                    if(rw.ptr)
557                    {
558                        int x1src = rsrc.x1;
559                        int x1dst = rdst.x1;
560                        int len   = rc.x2;
561                        if(rw.x1 > x1src)
562                        {
563                            x1dst += rw.x1 - x1src;
564                            len   -= rw.x1 - x1src;
565                            x1src  = rw.x1;
566                        }
567                        if(len > 0)
568                        {
569                            if(x1src + len-1 > rw.x2)
570                            {
571                                len -= x1src + len - rw.x2 - 1;
572                            }
573                            if(len > 0)
574                            {
575                                m_ren->blend_from(src,
576                                                  x1dst, rdst.y1,
577                                                  x1src, rsrc.y1,
578                                                  len,
579                                                  cover);
580                            }
581                        }
582                    }
583                    rdst.y1 += incy;
584                    rsrc.y1 += incy;
585                    --rc.y2;
586                }
587            }
588        }
589
590    private:
591        pixfmt_type* m_ren;
592        rect_i       m_clip_box;
593    };
594
595
596}
597
598#endif
599