xref: /haiku/headers/libs/agg/agg_renderer_scanline.h (revision 1705656eac83cd8b65c2ee895888cd529c62c04c)
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 
22 namespace agg
23 {
24 
25     //================================================render_scanline_aa_solid
26     template<class Scanline, class BaseRenderer, class ColorT>
render_scanline_aa_solid(const Scanline & sl,BaseRenderer & ren,const ColorT & color)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>
render_scanlines_aa_solid(Rasterizer & ras,Scanline & sl,BaseRenderer & ren,const ColorT & color)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         //--------------------------------------------------------------------
renderer_scanline_aa_solid()113         renderer_scanline_aa_solid() : m_ren(0) {}
renderer_scanline_aa_solid(base_ren_type & ren)114         renderer_scanline_aa_solid(base_ren_type& ren) : m_ren(&ren) {}
attach(base_ren_type & ren)115         void attach(base_ren_type& ren)
116         {
117             m_ren = &ren;
118         }
119 
120         //--------------------------------------------------------------------
color(const color_type & c)121         void color(const color_type& c) { m_color = c; }
color()122         const color_type& color() const { return m_color; }
123 
124         //--------------------------------------------------------------------
prepare()125         void prepare() {}
126 
127         //--------------------------------------------------------------------
render(const Scanline & sl)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>
render_scanline_aa(const Scanline & sl,BaseRenderer & ren,SpanAllocator & alloc,SpanGenerator & span_gen)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>
render_scanlines_aa(Rasterizer & ras,Scanline & sl,BaseRenderer & ren,SpanAllocator & alloc,SpanGenerator & span_gen)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         //--------------------------------------------------------------------
renderer_scanline_aa()204         renderer_scanline_aa() : m_ren(0), m_alloc(0), m_span_gen(0) {}
renderer_scanline_aa(base_ren_type & ren,alloc_type & alloc,span_gen_type & span_gen)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         {}
attach(base_ren_type & ren,alloc_type & alloc,span_gen_type & span_gen)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         //--------------------------------------------------------------------
prepare()222         void prepare() { m_span_gen->prepare(); }
223 
224         //--------------------------------------------------------------------
render(const Scanline & sl)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>
render_scanline_bin_solid(const Scanline & sl,BaseRenderer & ren,const ColorT & color)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>
render_scanlines_bin_solid(Rasterizer & ras,Scanline & sl,BaseRenderer & ren,const ColorT & color)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         //--------------------------------------------------------------------
renderer_scanline_bin_solid()313         renderer_scanline_bin_solid() : m_ren(0) {}
renderer_scanline_bin_solid(base_ren_type & ren)314         renderer_scanline_bin_solid(base_ren_type& ren) : m_ren(&ren) {}
attach(base_ren_type & ren)315         void attach(base_ren_type& ren)
316         {
317             m_ren = &ren;
318         }
319 
320         //--------------------------------------------------------------------
color(const color_type & c)321         void color(const color_type& c) { m_color = c; }
color()322         const color_type& color() const { return m_color; }
323 
324         //--------------------------------------------------------------------
prepare()325         void prepare() {}
326 
327         //--------------------------------------------------------------------
render(const Scanline & sl)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>
render_scanline_bin(const Scanline & sl,BaseRenderer & ren,SpanAllocator & alloc,SpanGenerator & span_gen)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>
render_scanlines_bin(Rasterizer & ras,Scanline & sl,BaseRenderer & ren,SpanAllocator & alloc,SpanGenerator & span_gen)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         //--------------------------------------------------------------------
renderer_scanline_bin()395         renderer_scanline_bin() : m_ren(0), m_alloc(0), m_span_gen(0) {}
renderer_scanline_bin(base_ren_type & ren,alloc_type & alloc,span_gen_type & span_gen)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         {}
attach(base_ren_type & ren,alloc_type & alloc,span_gen_type & span_gen)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         //--------------------------------------------------------------------
prepare()413         void prepare() { m_span_gen->prepare(); }
414 
415         //--------------------------------------------------------------------
render(const Scanline & sl)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>
render_scanlines(Rasterizer & ras,Scanline & sl,Renderer & ren)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>
render_all_paths(Rasterizer & ras,Scanline & sl,Renderer & r,VertexSource & vs,const ColorStorage & as,const PathId & path_id,unsigned num_paths)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>
render_scanlines_compound(Rasterizer & ras,ScanlineAA & sl_aa,ScanlineBin & sl_bin,BaseRenderer & ren,SpanAllocator & alloc,StyleHandler & sh)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((void*)(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