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        void fill(const color_type& c)
138        {
139            unsigned y;
140            if(width())
141            {
142                for(y = 0; y < height(); y++)
143                {
144                    m_ren->blend_hline(0, y, width(), c, cover_mask);
145                }
146            }
147        }
148
149        //--------------------------------------------------------------------
150        void copy_pixel(int x, int y, const color_type& c)
151        {
152            if(inbox(x, y))
153            {
154                m_ren->copy_pixel(x, y, c);
155            }
156        }
157
158        //--------------------------------------------------------------------
159        void blend_pixel(int x, int y, const color_type& c, cover_type cover)
160        {
161            if(inbox(x, y))
162            {
163                m_ren->blend_pixel(x, y, c, cover);
164            }
165        }
166
167        //--------------------------------------------------------------------
168        color_type pixel(int x, int y) const
169        {
170            return inbox(x, y) ?
171                   m_ren->pixel(x, y) :
172                   color_type::no_color();
173        }
174
175        //--------------------------------------------------------------------
176        void copy_hline(int x1, int y, int x2, const color_type& c)
177        {
178            if(x1 > x2) { int t = x2; x2 = x1; x1 = t; }
179            if(y  > ymax()) return;
180            if(y  < ymin()) return;
181            if(x1 > xmax()) return;
182            if(x2 < xmin()) return;
183
184            if(x1 < xmin()) x1 = xmin();
185            if(x2 > xmax()) x2 = xmax();
186
187            m_ren->copy_hline(x1, y, x2 - x1 + 1, c);
188        }
189
190        //--------------------------------------------------------------------
191        void copy_vline(int x, int y1, int y2, const color_type& c)
192        {
193            if(y1 > y2) { int t = y2; y2 = y1; y1 = t; }
194            if(x  > xmax()) return;
195            if(x  < xmin()) return;
196            if(y1 > ymax()) return;
197            if(y2 < ymin()) return;
198
199            if(y1 < ymin()) y1 = ymin();
200            if(y2 > ymax()) y2 = ymax();
201
202            m_ren->copy_vline(x, y1, y2 - y1 + 1, c);
203        }
204
205        //--------------------------------------------------------------------
206        void blend_hline(int x1, int y, int x2,
207                         const color_type& c, cover_type cover)
208        {
209            if(x1 > x2) { int t = x2; x2 = x1; x1 = t; }
210            if(y  > ymax()) return;
211            if(y  < ymin()) return;
212            if(x1 > xmax()) return;
213            if(x2 < xmin()) return;
214
215            if(x1 < xmin()) x1 = xmin();
216            if(x2 > xmax()) x2 = xmax();
217
218            m_ren->blend_hline(x1, y, x2 - x1 + 1, c, cover);
219        }
220
221
222        //--------------------------------------------------------------------
223        void blend_vline(int x, int y1, int y2,
224                         const color_type& c, cover_type cover)
225        {
226            if(y1 > y2) { int t = y2; y2 = y1; y1 = t; }
227            if(x  > xmax()) return;
228            if(x  < xmin()) return;
229            if(y1 > ymax()) return;
230            if(y2 < ymin()) return;
231
232            if(y1 < ymin()) y1 = ymin();
233            if(y2 > ymax()) y2 = ymax();
234
235            m_ren->blend_vline(x, y1, y2 - y1 + 1, c, cover);
236        }
237
238
239        //--------------------------------------------------------------------
240        void copy_bar(int x1, int y1, int x2, int y2, const color_type& c)
241        {
242            rect_i rc(x1, y1, x2, y2);
243            rc.normalize();
244            if(rc.clip(clip_box()))
245            {
246                int y;
247                for(y = rc.y1; y <= rc.y2; y++)
248                {
249                    m_ren->copy_hline(rc.x1, y, unsigned(rc.x2 - rc.x1 + 1), c);
250                }
251            }
252        }
253
254        //--------------------------------------------------------------------
255        void blend_bar(int x1, int y1, int x2, int y2,
256                       const color_type& c, cover_type cover)
257        {
258            rect_i rc(x1, y1, x2, y2);
259            rc.normalize();
260            if(rc.clip(clip_box()))
261            {
262                int y;
263                for(y = rc.y1; y <= rc.y2; y++)
264                {
265                    m_ren->blend_hline(rc.x1,
266                                       y,
267                                       unsigned(rc.x2 - rc.x1 + 1),
268                                       c,
269                                       cover);
270                }
271            }
272        }
273
274        //--------------------------------------------------------------------
275        void blend_solid_hspan(int x, int y, int len,
276                               const color_type& c,
277                               const cover_type* covers)
278        {
279            if(y > ymax()) return;
280            if(y < ymin()) return;
281
282            if(x < xmin())
283            {
284                len -= xmin() - x;
285                if(len <= 0) return;
286                covers += xmin() - x;
287                x = xmin();
288            }
289            if(x + len > xmax())
290            {
291                len = xmax() - x + 1;
292                if(len <= 0) return;
293            }
294            m_ren->blend_solid_hspan(x, y, len, c, covers);
295        }
296
297		//--------------------------------------------------------------------
298        void blend_solid_hspan_subpix(int x, int y, int len,
299                                      const color_type& c,
300                                      const cover_type* covers)
301        {
302            if(y > ymax()) return;
303            if(y < ymin()) return;
304
305            if(x < xmin())
306            {
307                len -= 3 * (xmin() - x);
308                if(len <= 0) return;
309                covers += 3 * (xmin() - x);
310                x = xmin();
311            }
312            if(x + len / 3 > xmax())
313            {
314                len = 3 * (xmax() - x + 1);
315                if(len <= 0) return;
316            }
317            m_ren->blend_solid_hspan_subpix(x, y, len, c, covers);
318        }
319
320        //--------------------------------------------------------------------
321        void blend_solid_vspan(int x, int y, int len,
322                               const color_type& c,
323                               const cover_type* covers)
324        {
325            if(x > xmax()) return;
326            if(x < xmin()) return;
327
328            if(y < ymin())
329            {
330                len -= ymin() - y;
331                if(len <= 0) return;
332                covers += ymin() - y;
333                y = ymin();
334            }
335            if(y + len > ymax())
336            {
337                len = ymax() - y + 1;
338                if(len <= 0) return;
339            }
340            m_ren->blend_solid_vspan(x, y, len, c, covers);
341        }
342
343
344        //--------------------------------------------------------------------
345        void copy_color_hspan(int x, int y, int len, const color_type* colors)
346        {
347            if(y > ymax()) return;
348            if(y < ymin()) return;
349
350            if(x < xmin())
351            {
352                int d = xmin() - x;
353                len -= d;
354                if(len <= 0) return;
355                colors += d;
356                x = xmin();
357            }
358            if(x + len > xmax())
359            {
360                len = xmax() - x + 1;
361                if(len <= 0) return;
362            }
363            m_ren->copy_color_hspan(x, y, len, colors);
364        }
365
366
367        //--------------------------------------------------------------------
368        void copy_color_vspan(int x, int y, int len, const color_type* colors)
369        {
370            if(x > xmax()) return;
371            if(x < xmin()) return;
372
373            if(y < ymin())
374            {
375                int d = ymin() - y;
376                len -= d;
377                if(len <= 0) return;
378                colors += d;
379                y = ymin();
380            }
381            if(y + len > ymax())
382            {
383                len = ymax() - y + 1;
384                if(len <= 0) return;
385            }
386            m_ren->copy_color_vspan(x, y, len, colors);
387        }
388
389
390        //--------------------------------------------------------------------
391        void blend_color_hspan(int x, int y, int len,
392                               const color_type* colors,
393                               const cover_type* covers,
394                               cover_type cover = agg::cover_full)
395        {
396            if(y > ymax()) return;
397            if(y < ymin()) return;
398
399            if(x < xmin())
400            {
401                int d = xmin() - x;
402                len -= d;
403                if(len <= 0) return;
404                if(covers) covers += d;
405                colors += d;
406                x = xmin();
407            }
408            if(x + len > xmax())
409            {
410                len = xmax() - x + 1;
411                if(len <= 0) return;
412            }
413            m_ren->blend_color_hspan(x, y, len, colors, covers, cover);
414        }
415
416        //--------------------------------------------------------------------
417        void blend_color_vspan(int x, int y, int len,
418                               const color_type* colors,
419                               const cover_type* covers,
420                               cover_type cover = agg::cover_full)
421        {
422            if(x > xmax()) return;
423            if(x < xmin()) return;
424
425            if(y < ymin())
426            {
427                int d = ymin() - y;
428                len -= d;
429                if(len <= 0) return;
430                if(covers) covers += d;
431                colors += d;
432                y = ymin();
433            }
434            if(y + len > ymax())
435            {
436                len = ymax() - y + 1;
437                if(len <= 0) return;
438            }
439            m_ren->blend_color_vspan(x, y, len, colors, covers, cover);
440        }
441
442        //--------------------------------------------------------------------
443        rect_i clip_rect_area(rect_i& dst, rect_i& src, int wsrc, int hsrc) const
444        {
445            rect_i rc(0,0,0,0);
446            rect_i cb = clip_box();
447            ++cb.x2;
448            ++cb.y2;
449
450            if(src.x1 < 0)
451            {
452                dst.x1 -= src.x1;
453                src.x1 = 0;
454            }
455            if(src.y1 < 0)
456            {
457                dst.y1 -= src.y1;
458                src.y1 = 0;
459            }
460
461            if(src.x2 > wsrc) src.x2 = wsrc;
462            if(src.y2 > hsrc) src.y2 = hsrc;
463
464            if(dst.x1 < cb.x1)
465            {
466                src.x1 += cb.x1 - dst.x1;
467                dst.x1 = cb.x1;
468            }
469            if(dst.y1 < cb.y1)
470            {
471                src.y1 += cb.y1 - dst.y1;
472                dst.y1 = cb.y1;
473            }
474
475            if(dst.x2 > cb.x2) dst.x2 = cb.x2;
476            if(dst.y2 > cb.y2) dst.y2 = cb.y2;
477
478            rc.x2 = dst.x2 - dst.x1;
479            rc.y2 = dst.y2 - dst.y1;
480
481            if(rc.x2 > src.x2 - src.x1) rc.x2 = src.x2 - src.x1;
482            if(rc.y2 > src.y2 - src.y1) rc.y2 = src.y2 - src.y1;
483            return rc;
484        }
485
486        //--------------------------------------------------------------------
487        template<class RenBuf>
488        void copy_from(const RenBuf& src,
489                       const rect_i* rect_src_ptr = 0,
490                       int dx = 0,
491                       int dy = 0)
492        {
493            rect_i rsrc(0, 0, src.width(), src.height());
494            if(rect_src_ptr)
495            {
496                rsrc.x1 = rect_src_ptr->x1;
497                rsrc.y1 = rect_src_ptr->y1;
498                rsrc.x2 = rect_src_ptr->x2 + 1;
499                rsrc.y2 = rect_src_ptr->y2 + 1;
500            }
501
502            // Version with xdst, ydst (absolute positioning)
503            //rect_i rdst(xdst, ydst, xdst + rsrc.x2 - rsrc.x1, ydst + rsrc.y2 - rsrc.y1);
504
505            // Version with dx, dy (relative positioning)
506            rect_i rdst(rsrc.x1 + dx, rsrc.y1 + dy, rsrc.x2 + dx, rsrc.y2 + dy);
507
508            rect_i rc = clip_rect_area(rdst, rsrc, src.width(), src.height());
509
510            if(rc.x2 > 0)
511            {
512                int incy = 1;
513                if(rdst.y1 > rsrc.y1)
514                {
515                    rsrc.y1 += rc.y2 - 1;
516                    rdst.y1 += rc.y2 - 1;
517                    incy = -1;
518                }
519                while(rc.y2 > 0)
520                {
521                    m_ren->copy_from(src,
522                                     rdst.x1, rdst.y1,
523                                     rsrc.x1, rsrc.y1,
524                                     rc.x2);
525                    rdst.y1 += incy;
526                    rsrc.y1 += incy;
527                    --rc.y2;
528                }
529            }
530        }
531
532        //--------------------------------------------------------------------
533        template<class SrcPixelFormatRenderer>
534        void blend_from(const SrcPixelFormatRenderer& src,
535                        const rect_i* rect_src_ptr = 0,
536                        int dx = 0,
537                        int dy = 0,
538                        cover_type cover = agg::cover_full)
539        {
540            rect_i rsrc(0, 0, src.width(), src.height());
541            if(rect_src_ptr)
542            {
543                rsrc.x1 = rect_src_ptr->x1;
544                rsrc.y1 = rect_src_ptr->y1;
545                rsrc.x2 = rect_src_ptr->x2 + 1;
546                rsrc.y2 = rect_src_ptr->y2 + 1;
547            }
548
549            // Version with xdst, ydst (absolute positioning)
550            //rect_i rdst(xdst, ydst, xdst + rsrc.x2 - rsrc.x1, ydst + rsrc.y2 - rsrc.y1);
551
552            // Version with dx, dy (relative positioning)
553            rect_i rdst(rsrc.x1 + dx, rsrc.y1 + dy, rsrc.x2 + dx, rsrc.y2 + dy);
554            rect_i rc = clip_rect_area(rdst, rsrc, src.width(), src.height());
555
556            if(rc.x2 > 0)
557            {
558                int incy = 1;
559                if(rdst.y1 > rsrc.y1)
560                {
561                    rsrc.y1 += rc.y2 - 1;
562                    rdst.y1 += rc.y2 - 1;
563                    incy = -1;
564                }
565                while(rc.y2 > 0)
566                {
567                    typename SrcPixelFormatRenderer::row_data rw = src.row(rsrc.y1);
568                    if(rw.ptr)
569                    {
570                        int x1src = rsrc.x1;
571                        int x1dst = rdst.x1;
572                        int len   = rc.x2;
573                        if(rw.x1 > x1src)
574                        {
575                            x1dst += rw.x1 - x1src;
576                            len   -= rw.x1 - x1src;
577                            x1src  = rw.x1;
578                        }
579                        if(len > 0)
580                        {
581                            if(x1src + len-1 > rw.x2)
582                            {
583                                len -= x1src + len - rw.x2 - 1;
584                            }
585                            if(len > 0)
586                            {
587                                m_ren->blend_from(src,
588                                                  x1dst, rdst.y1,
589                                                  x1src, rsrc.y1,
590                                                  len,
591                                                  cover);
592                            }
593                        }
594                    }
595                    rdst.y1 += incy;
596                    rsrc.y1 += incy;
597                    --rc.y2;
598                }
599            }
600        }
601
602    private:
603        pixfmt_type* m_ren;
604        rect_i       m_clip_box;
605    };
606
607
608}
609
610#endif
611