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#ifndef AGG_RENDERER_SCANLINE_INCLUDED
17#define AGG_RENDERER_SCANLINE_INCLUDED
18
19#include "agg_basics.h"
20#include "agg_renderer_base.h"
21
22namespace agg
23{
24
25    //================================================render_scanline_aa_solid
26    template<class Scanline, class BaseRenderer, class ColorT>
27    void render_scanline_aa_solid(const Scanline& sl,
28                                  BaseRenderer& ren,
29                                  const ColorT& color)
30    {
31        int y = sl.y();
32        unsigned num_spans = sl.num_spans();
33        typename Scanline::const_iterator span = sl.begin();
34
35        for(;;)
36        {
37            int x = span->x;
38            if(span->len > 0)
39            {
40                ren.blend_solid_hspan(x, y, (unsigned)span->len,
41                                      color,
42                                      span->covers);
43            }
44            else
45            {
46                ren.blend_hline(x, y, (unsigned)(x - span->len - 1),
47                                color,
48                                *(span->covers));
49            }
50            if(--num_spans == 0) break;
51            ++span;
52        }
53    }
54
55    //===============================================render_scanlines_aa_solid
56    template<class Rasterizer, class Scanline,
57             class BaseRenderer, class ColorT>
58    void render_scanlines_aa_solid(Rasterizer& ras, Scanline& sl,
59                                   BaseRenderer& ren, const ColorT& color)
60    {
61        if(ras.rewind_scanlines())
62        {
63            // Explicitly convert "color" to the BaseRenderer color type.
64            // For example, it can be called with color type "rgba", while
65            // "rgba8" is needed. Otherwise it will be implicitly
66            // converted in the loop many times.
67            //----------------------
68            typename BaseRenderer::color_type ren_color(color);
69
70            sl.reset(ras.min_x(), ras.max_x());
71            while(ras.sweep_scanline(sl))
72            {
73                //render_scanline_aa_solid(sl, ren, ren_color);
74
75                // This code is equivalent to the above call (copy/paste).
76                // It's just a "manual" optimization for old compilers,
77                // like Microsoft Visual C++ v6.0
78                //-------------------------------
79                int y = sl.y();
80                unsigned num_spans = sl.num_spans();
81                typename Scanline::const_iterator span = sl.begin();
82
83                for(;;)
84                {
85                    int x = span->x;
86                    if(span->len > 0)
87                    {
88                        ren.blend_solid_hspan(x, y, (unsigned)span->len,
89                                              ren_color,
90                                              span->covers);
91                    }
92                    else
93                    {
94                        ren.blend_hline(x, y, (unsigned)(x - span->len - 1),
95                                        ren_color,
96                                        *(span->covers));
97                    }
98                    if(--num_spans == 0) break;
99                    ++span;
100                }
101            }
102        }
103    }
104
105    //==============================================renderer_scanline_aa_solid
106    template<class BaseRenderer> class renderer_scanline_aa_solid
107    {
108    public:
109        typedef BaseRenderer base_ren_type;
110        typedef typename base_ren_type::color_type color_type;
111
112        //--------------------------------------------------------------------
113        renderer_scanline_aa_solid() : m_ren(0) {}
114        renderer_scanline_aa_solid(base_ren_type& ren) : m_ren(&ren) {}
115        void attach(base_ren_type& ren)
116        {
117            m_ren = &ren;
118        }
119
120        //--------------------------------------------------------------------
121        void color(const color_type& c) { m_color = c; }
122        const color_type& color() const { return m_color; }
123
124        //--------------------------------------------------------------------
125        void prepare() {}
126
127        //--------------------------------------------------------------------
128        template<class Scanline> void render(const Scanline& sl)
129        {
130            render_scanline_aa_solid(sl, *m_ren, m_color);
131        }
132
133    private:
134        base_ren_type* m_ren;
135        color_type m_color;
136    };
137
138
139
140
141
142
143
144
145
146
147
148
149
150    //======================================================render_scanline_aa
151    template<class Scanline, class BaseRenderer,
152             class SpanAllocator, class SpanGenerator>
153    void render_scanline_aa(const Scanline& sl, BaseRenderer& ren,
154                            SpanAllocator& alloc, SpanGenerator& span_gen)
155    {
156        int y = sl.y();
157
158        unsigned num_spans = sl.num_spans();
159        typename Scanline::const_iterator span = sl.begin();
160        for(;;)
161        {
162            int x = span->x;
163            int len = span->len;
164            const typename Scanline::cover_type* covers = span->covers;
165
166            if(len < 0) len = -len;
167            typename BaseRenderer::color_type* colors = alloc.allocate(len);
168            span_gen.generate(colors, x, y, len);
169            ren.blend_color_hspan(x, y, len, colors,
170                                  (span->len < 0) ? 0 : covers, *covers);
171
172            if(--num_spans == 0) break;
173            ++span;
174        }
175    }
176
177    //=====================================================render_scanlines_aa
178    template<class Rasterizer, class Scanline, class BaseRenderer,
179             class SpanAllocator, class SpanGenerator>
180    void render_scanlines_aa(Rasterizer& ras, Scanline& sl, BaseRenderer& ren,
181                             SpanAllocator& alloc, SpanGenerator& span_gen)
182    {
183        if(ras.rewind_scanlines())
184        {
185            sl.reset(ras.min_x(), ras.max_x());
186            span_gen.prepare();
187            while(ras.sweep_scanline(sl))
188            {
189                render_scanline_aa(sl, ren, alloc, span_gen);
190            }
191        }
192    }
193
194    //====================================================renderer_scanline_aa
195    template<class BaseRenderer, class SpanAllocator, class SpanGenerator>
196    class renderer_scanline_aa
197    {
198    public:
199        typedef BaseRenderer  base_ren_type;
200        typedef SpanAllocator alloc_type;
201        typedef SpanGenerator span_gen_type;
202
203        //--------------------------------------------------------------------
204        renderer_scanline_aa() : m_ren(0), m_alloc(0), m_span_gen(0) {}
205        renderer_scanline_aa(base_ren_type& ren,
206                             alloc_type& alloc,
207                             span_gen_type& span_gen) :
208            m_ren(&ren),
209            m_alloc(&alloc),
210            m_span_gen(&span_gen)
211        {}
212        void attach(base_ren_type& ren,
213                    alloc_type& alloc,
214                    span_gen_type& span_gen)
215        {
216            m_ren = &ren;
217            m_alloc = &alloc;
218            m_span_gen = &span_gen;
219        }
220
221        //--------------------------------------------------------------------
222        void prepare() { m_span_gen->prepare(); }
223
224        //--------------------------------------------------------------------
225        template<class Scanline> void render(const Scanline& sl)
226        {
227            render_scanline_aa(sl, *m_ren, *m_alloc, *m_span_gen);
228        }
229
230    private:
231        base_ren_type* m_ren;
232        alloc_type*    m_alloc;
233        span_gen_type* m_span_gen;
234    };
235
236
237
238
239
240
241    //===============================================render_scanline_bin_solid
242    template<class Scanline, class BaseRenderer, class ColorT>
243    void render_scanline_bin_solid(const Scanline& sl,
244                                   BaseRenderer& ren,
245                                   const ColorT& color)
246    {
247        unsigned num_spans = sl.num_spans();
248        typename Scanline::const_iterator span = sl.begin();
249        for(;;)
250        {
251            ren.blend_hline(span->x,
252                            sl.y(),
253                            span->x - 1 + ((span->len < 0) ?
254                                              -span->len :
255                                               span->len),
256                               color,
257                               cover_full);
258            if(--num_spans == 0) break;
259            ++span;
260        }
261    }
262
263    //==============================================render_scanlines_bin_solid
264    template<class Rasterizer, class Scanline,
265             class BaseRenderer, class ColorT>
266    void render_scanlines_bin_solid(Rasterizer& ras, Scanline& sl,
267                                    BaseRenderer& ren, const ColorT& color)
268    {
269        if(ras.rewind_scanlines())
270        {
271            // Explicitly convert "color" to the BaseRenderer color type.
272            // For example, it can be called with color type "rgba", while
273            // "rgba8" is needed. Otherwise it will be implicitly
274            // converted in the loop many times.
275            //----------------------
276            typename BaseRenderer::color_type ren_color(color);
277
278            sl.reset(ras.min_x(), ras.max_x());
279            while(ras.sweep_scanline(sl))
280            {
281                //render_scanline_bin_solid(sl, ren, ren_color);
282
283                // This code is equivalent to the above call (copy/paste).
284                // It's just a "manual" optimization for old compilers,
285                // like Microsoft Visual C++ v6.0
286                //-------------------------------
287                unsigned num_spans = sl.num_spans();
288                typename Scanline::const_iterator span = sl.begin();
289                for(;;)
290                {
291                    ren.blend_hline(span->x,
292                                    sl.y(),
293                                    span->x - 1 + ((span->len < 0) ?
294                                                      -span->len :
295                                                       span->len),
296                                       ren_color,
297                                       cover_full);
298                    if(--num_spans == 0) break;
299                    ++span;
300                }
301            }
302        }
303    }
304
305    //=============================================renderer_scanline_bin_solid
306    template<class BaseRenderer> class renderer_scanline_bin_solid
307    {
308    public:
309        typedef BaseRenderer base_ren_type;
310        typedef typename base_ren_type::color_type color_type;
311
312        //--------------------------------------------------------------------
313        renderer_scanline_bin_solid() : m_ren(0) {}
314        renderer_scanline_bin_solid(base_ren_type& ren) : m_ren(&ren) {}
315        void attach(base_ren_type& ren)
316        {
317            m_ren = &ren;
318        }
319
320        //--------------------------------------------------------------------
321        void color(const color_type& c) { m_color = c; }
322        const color_type& color() const { return m_color; }
323
324        //--------------------------------------------------------------------
325        void prepare() {}
326
327        //--------------------------------------------------------------------
328        template<class Scanline> void render(const Scanline& sl)
329        {
330            render_scanline_bin_solid(sl, *m_ren, m_color);
331        }
332
333    private:
334        base_ren_type* m_ren;
335        color_type m_color;
336    };
337
338
339
340
341
342
343
344
345    //======================================================render_scanline_bin
346    template<class Scanline, class BaseRenderer,
347             class SpanAllocator, class SpanGenerator>
348    void render_scanline_bin(const Scanline& sl, BaseRenderer& ren,
349                             SpanAllocator& alloc, SpanGenerator& span_gen)
350    {
351        int y = sl.y();
352
353        unsigned num_spans = sl.num_spans();
354        typename Scanline::const_iterator span = sl.begin();
355        for(;;)
356        {
357            int x = span->x;
358            int len = span->len;
359            if(len < 0) len = -len;
360            typename BaseRenderer::color_type* colors = alloc.allocate(len);
361            span_gen.generate(colors, x, y, len);
362            ren.blend_color_hspan(x, y, len, colors, 0, cover_full);
363            if(--num_spans == 0) break;
364            ++span;
365        }
366    }
367
368    //=====================================================render_scanlines_bin
369    template<class Rasterizer, class Scanline, class BaseRenderer,
370             class SpanAllocator, class SpanGenerator>
371    void render_scanlines_bin(Rasterizer& ras, Scanline& sl, BaseRenderer& ren,
372                              SpanAllocator& alloc, SpanGenerator& span_gen)
373    {
374        if(ras.rewind_scanlines())
375        {
376            sl.reset(ras.min_x(), ras.max_x());
377            span_gen.prepare();
378            while(ras.sweep_scanline(sl))
379            {
380                render_scanline_bin(sl, ren, alloc, span_gen);
381            }
382        }
383    }
384
385    //====================================================renderer_scanline_bin
386    template<class BaseRenderer, class SpanAllocator, class SpanGenerator>
387    class renderer_scanline_bin
388    {
389    public:
390        typedef BaseRenderer  base_ren_type;
391        typedef SpanAllocator alloc_type;
392        typedef SpanGenerator span_gen_type;
393
394        //--------------------------------------------------------------------
395        renderer_scanline_bin() : m_ren(0), m_alloc(0), m_span_gen(0) {}
396        renderer_scanline_bin(base_ren_type& ren,
397                              alloc_type& alloc,
398                              span_gen_type& span_gen) :
399            m_ren(&ren),
400            m_alloc(&alloc),
401            m_span_gen(&span_gen)
402        {}
403        void attach(base_ren_type& ren,
404                    alloc_type& alloc,
405                    span_gen_type& span_gen)
406        {
407            m_ren = &ren;
408            m_alloc = &alloc;
409            m_span_gen = &span_gen;
410        }
411
412        //--------------------------------------------------------------------
413        void prepare() { m_span_gen->prepare(); }
414
415        //--------------------------------------------------------------------
416        template<class Scanline> void render(const Scanline& sl)
417        {
418            render_scanline_bin(sl, *m_ren, *m_alloc, *m_span_gen);
419        }
420
421    private:
422        base_ren_type* m_ren;
423        alloc_type*    m_alloc;
424        span_gen_type* m_span_gen;
425    };
426
427
428
429
430
431
432
433
434
435
436    //========================================================render_scanlines
437    template<class Rasterizer, class Scanline, class Renderer>
438    void render_scanlines(Rasterizer& ras, Scanline& sl, Renderer& ren)
439    {
440        if(ras.rewind_scanlines())
441        {
442            sl.reset(ras.min_x(), ras.max_x());
443            ren.prepare();
444            while(ras.sweep_scanline(sl))
445            {
446                ren.render(sl);
447            }
448        }
449    }
450
451    //========================================================render_all_paths
452    template<class Rasterizer, class Scanline, class Renderer,
453             class VertexSource, class ColorStorage, class PathId>
454    void render_all_paths(Rasterizer& ras,
455                          Scanline& sl,
456                          Renderer& r,
457                          VertexSource& vs,
458                          const ColorStorage& as,
459                          const PathId& path_id,
460                          unsigned num_paths)
461    {
462        for(unsigned i = 0; i < num_paths; i++)
463        {
464            ras.reset();
465            ras.add_path(vs, path_id[i]);
466            r.color(as[i]);
467            render_scanlines(ras, sl, r);
468        }
469    }
470
471
472
473
474
475
476
477
478
479    //=============================================render_scanlines_compound
480    template<class Rasterizer,
481             class ScanlineAA,
482             class ScanlineBin,
483             class BaseRenderer,
484             class SpanAllocator,
485             class StyleHandler>
486    void render_scanlines_compound(Rasterizer& ras,
487                                   ScanlineAA& sl_aa,
488                                   ScanlineBin& sl_bin,
489                                   BaseRenderer& ren,
490                                   SpanAllocator& alloc,
491                                   StyleHandler& sh)
492    {
493        if(ras.rewind_scanlines())
494        {
495            int min_x = ras.min_x();
496            int len = ras.max_x() - min_x + 2;
497            sl_aa.reset(min_x, ras.max_x());
498
499            typedef typename BaseRenderer::color_type color_type;
500            color_type* color_span   = alloc.allocate(len * 2);
501            color_type* mix_buffer   = color_span + len;
502            cover_type* cover_buffer = ras.allocate_cover_buffer(len);
503            unsigned num_spans;
504
505            unsigned num_styles;
506            unsigned style;
507            bool     solid;
508            while((num_styles = ras.sweep_styles()) > 0)
509            {
510                typename ScanlineAA::const_iterator span_aa;
511                if(num_styles == 1)
512                {
513                    // Optimization for a single style. Happens often
514                    //-------------------------
515                    if(ras.sweep_scanline(sl_aa, 0))
516                    {
517                        style = ras.style(0);
518                        if(sh.is_solid(style))
519                        {
520                            // Just solid fill
521                            //-----------------------
522                            render_scanline_aa_solid(sl_aa, ren, sh.color(style));
523                        }
524                        else
525                        {
526                            // Arbitrary span generator
527                            //-----------------------
528                            span_aa   = sl_aa.begin();
529                            num_spans = sl_aa.num_spans();
530                            for(;;)
531                            {
532                                len = span_aa->len;
533                                sh.generate_span(color_span,
534                                                 span_aa->x,
535                                                 sl_aa.y(),
536                                                 len,
537                                                 style);
538
539                                ren.blend_color_hspan(span_aa->x,
540                                                      sl_aa.y(),
541                                                      span_aa->len,
542                                                      color_span,
543                                                      span_aa->covers);
544                                if(--num_spans == 0) break;
545                                ++span_aa;
546                            }
547                        }
548                    }
549                }
550                else
551                {
552                    int      sl_start = ras.scanline_start();
553                    unsigned sl_len   = ras.scanline_length();
554
555                    if(sl_len)
556                    {
557                        memset(mix_buffer + sl_start - min_x,
558                               0,
559                               sl_len * sizeof(color_type));
560
561                        memset(cover_buffer + sl_start - min_x,
562                               0,
563                               sl_len * sizeof(cover_type));
564
565                        int sl_y = 0x7FFFFFFF;
566                        unsigned i;
567                        for(i = 0; i < num_styles; i++)
568                        {
569                            style = ras.style(i);
570                            solid = sh.is_solid(style);
571
572                            if(ras.sweep_scanline(sl_aa, i))
573                            {
574                                unsigned    cover;
575                                color_type* colors;
576                                color_type* cspan;
577                                cover_type* src_covers;
578                                cover_type* dst_covers;
579                                span_aa   = sl_aa.begin();
580                                num_spans = sl_aa.num_spans();
581                                sl_y      = sl_aa.y();
582                                if(solid)
583                                {
584                                    // Just solid fill
585                                    //-----------------------
586                                    for(;;)
587                                    {
588                                        color_type c = sh.color(style);
589                                        len    = span_aa->len;
590                                        colors = mix_buffer + span_aa->x - min_x;
591                                        src_covers = span_aa->covers;
592                                        dst_covers = cover_buffer + span_aa->x - min_x;
593                                        do
594                                        {
595                                            cover = *src_covers;
596                                            if(*dst_covers + cover > cover_full)
597                                            {
598                                                cover = cover_full - *dst_covers;
599                                            }
600                                            if(cover)
601                                            {
602                                                colors->add(c, cover);
603                                                *dst_covers += cover;
604                                            }
605                                            ++colors;
606                                            ++src_covers;
607                                            ++dst_covers;
608                                        }
609                                        while(--len);
610                                        if(--num_spans == 0) break;
611                                        ++span_aa;
612                                    }
613                                }
614                                else
615                                {
616                                    // Arbitrary span generator
617                                    //-----------------------
618                                    for(;;)
619                                    {
620                                        len = span_aa->len;
621                                        colors = mix_buffer + span_aa->x - min_x;
622                                        cspan  = color_span;
623                                        sh.generate_span(cspan,
624                                                         span_aa->x,
625                                                         sl_aa.y(),
626                                                         len,
627                                                         style);
628                                        src_covers = span_aa->covers;
629                                        dst_covers = cover_buffer + span_aa->x - min_x;
630                                        do
631                                        {
632                                            cover = *src_covers;
633                                            if(*dst_covers + cover > cover_full)
634                                            {
635                                                cover = cover_full - *dst_covers;
636                                            }
637                                            if(cover)
638                                            {
639                                                colors->add(*cspan, cover);
640                                                *dst_covers += cover;
641                                            }
642                                            ++cspan;
643                                            ++colors;
644                                            ++src_covers;
645                                            ++dst_covers;
646                                        }
647                                        while(--len);
648                                        if(--num_spans == 0) break;
649                                        ++span_aa;
650                                    }
651                                }
652                            }
653                        }
654                        ren.blend_color_hspan(sl_start,
655                                              sl_y,
656                                              sl_len,
657                                              mix_buffer + sl_start - min_x,
658                                              0,
659                                              cover_full);
660                    } //if(sl_len)
661                } //if(num_styles == 1) ... else
662            } //while((num_styles = ras.sweep_styles()) > 0)
663        } //if(ras.rewind_scanlines())
664    }
665
666
667}
668
669#endif
670