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_SCANLINE_BOOLEAN_ALGEBRA_INCLUDED
17#define AGG_SCANLINE_BOOLEAN_ALGEBRA_INCLUDED
18
19#include <stdlib.h>
20#include <math.h>
21#include "agg_basics.h"
22
23
24namespace agg
25{
26
27    //-----------------------------------------------sbool_combine_spans_bin
28    // Functor.
29    // Combine two binary encoded spans, i.e., when we don't have any
30    // anti-aliasing information, but only X and Length. The function
31    // is compatible with any type of scanlines.
32    //----------------
33    template<class Scanline1,
34             class Scanline2,
35             class Scanline>
36    struct sbool_combine_spans_bin
37    {
38        void operator () (const typename Scanline1::const_iterator&,
39                          const typename Scanline2::const_iterator&,
40                          int x, unsigned len,
41                          Scanline& sl) const
42        {
43            sl.add_span(x, len, cover_full);
44        }
45    };
46
47
48
49    //---------------------------------------------sbool_combine_spans_empty
50    // Functor.
51    // Combine two spans as empty ones. The functor does nothing
52    // and is used to XOR binary spans.
53    //----------------
54    template<class Scanline1,
55             class Scanline2,
56             class Scanline>
57    struct sbool_combine_spans_empty
58    {
59        void operator () (const typename Scanline1::const_iterator&,
60                          const typename Scanline2::const_iterator&,
61                          int, unsigned,
62                          Scanline&) const
63        {}
64    };
65
66
67
68    //--------------------------------------------------sbool_add_span_empty
69    // Functor.
70    // Add nothing. Used in conbine_shapes_sub
71    //----------------
72    template<class Scanline1,
73             class Scanline>
74    struct sbool_add_span_empty
75    {
76        void operator () (const typename Scanline1::const_iterator&,
77                          int, unsigned,
78                          Scanline&) const
79        {}
80    };
81
82
83    //----------------------------------------------------sbool_add_span_bin
84    // Functor.
85    // Add a binary span
86    //----------------
87    template<class Scanline1,
88             class Scanline>
89    struct sbool_add_span_bin
90    {
91        void operator () (const typename Scanline1::const_iterator&,
92                          int x, unsigned len,
93                          Scanline& sl) const
94        {
95            sl.add_span(x, len, cover_full);
96        }
97    };
98
99
100
101
102    //-----------------------------------------------------sbool_add_span_aa
103    // Functor.
104    // Add an anti-aliased span
105    // anti-aliasing information, but only X and Length. The function
106    // is compatible with any type of scanlines.
107    //----------------
108    template<class Scanline1,
109             class Scanline>
110    struct sbool_add_span_aa
111    {
112        void operator () (const typename Scanline1::const_iterator& span,
113                          int x, unsigned len,
114                          Scanline& sl) const
115        {
116            if(span->len < 0)
117            {
118                sl.add_span(x, len, *span->covers);
119            }
120            else
121            if(span->len > 0)
122            {
123                const typename Scanline1::cover_type* covers = span->covers;
124                if(span->x < x) covers += x - span->x;
125                sl.add_cells(x, len, covers);
126            }
127        }
128    };
129
130
131
132
133    //----------------------------------------------sbool_intersect_spans_aa
134    // Functor.
135    // Intersect two spans preserving the anti-aliasing information.
136    // The result is added to the "sl" scanline.
137    //------------------
138    template<class Scanline1,
139             class Scanline2,
140             class Scanline,
141             unsigned CoverShift = cover_shift>
142    struct sbool_intersect_spans_aa
143    {
144        enum cover_scale_e
145        {
146            cover_shift = CoverShift,
147            cover_size  = 1 << cover_shift,
148            cover_mask  = cover_size - 1,
149            cover_full  = cover_mask
150        };
151
152
153        void operator () (const typename Scanline1::const_iterator& span1,
154                          const typename Scanline2::const_iterator& span2,
155                          int x, unsigned len,
156                          Scanline& sl) const
157        {
158            unsigned cover;
159            const typename Scanline1::cover_type* covers1;
160            const typename Scanline2::cover_type* covers2;
161
162            // Calculate the operation code and choose the
163            // proper combination algorithm.
164            // 0 = Both spans are of AA type
165            // 1 = span1 is solid, span2 is AA
166            // 2 = span1 is AA, span2 is solid
167            // 3 = Both spans are of solid type
168            //-----------------
169            switch((span1->len < 0) | ((span2->len < 0) << 1))
170            {
171            case 0:      // Both are AA spans
172                covers1 = span1->covers;
173                covers2 = span2->covers;
174                if(span1->x < x) covers1 += x - span1->x;
175                if(span2->x < x) covers2 += x - span2->x;
176                do
177                {
178                    cover = *covers1++ * *covers2++;
179                    sl.add_cell(x++,
180                                (cover == cover_full * cover_full) ?
181                                cover_full :
182                                (cover >> cover_shift));
183                }
184                while(--len);
185                break;
186
187            case 1:      // span1 is solid, span2 is AA
188                covers2 = span2->covers;
189                if(span2->x < x) covers2 += x - span2->x;
190                if(*(span1->covers) == cover_full)
191                {
192                    sl.add_cells(x, len, covers2);
193                }
194                else
195                {
196                    do
197                    {
198                        cover = *(span1->covers) * *covers2++;
199                        sl.add_cell(x++,
200                                    (cover == cover_full * cover_full) ?
201                                    cover_full :
202                                    (cover >> cover_shift));
203                    }
204                    while(--len);
205                }
206                break;
207
208            case 2:      // span1 is AA, span2 is solid
209                covers1 = span1->covers;
210                if(span1->x < x) covers1 += x - span1->x;
211                if(*(span2->covers) == cover_full)
212                {
213                    sl.add_cells(x, len, covers1);
214                }
215                else
216                {
217                    do
218                    {
219                        cover = *covers1++ * *(span2->covers);
220                        sl.add_cell(x++,
221                                    (cover == cover_full * cover_full) ?
222                                    cover_full :
223                                    (cover >> cover_shift));
224                    }
225                    while(--len);
226                }
227                break;
228
229            case 3:      // Both are solid spans
230                cover = *(span1->covers) * *(span2->covers);
231                sl.add_span(x, len,
232                            (cover == cover_full * cover_full) ?
233                            cover_full :
234                            (cover >> cover_shift));
235                break;
236            }
237        }
238    };
239
240
241
242
243
244
245    //--------------------------------------------------sbool_unite_spans_aa
246    // Functor.
247    // Unite two spans preserving the anti-aliasing information.
248    // The result is added to the "sl" scanline.
249    //------------------
250    template<class Scanline1,
251             class Scanline2,
252             class Scanline,
253             unsigned CoverShift = cover_shift>
254    struct sbool_unite_spans_aa
255    {
256        enum cover_scale_e
257        {
258            cover_shift = CoverShift,
259            cover_size  = 1 << cover_shift,
260            cover_mask  = cover_size - 1,
261            cover_full  = cover_mask
262        };
263
264
265        void operator () (const typename Scanline1::const_iterator& span1,
266                          const typename Scanline2::const_iterator& span2,
267                          int x, unsigned len,
268                          Scanline& sl) const
269        {
270            unsigned cover;
271            const typename Scanline1::cover_type* covers1;
272            const typename Scanline2::cover_type* covers2;
273
274            // Calculate the operation code and choose the
275            // proper combination algorithm.
276            // 0 = Both spans are of AA type
277            // 1 = span1 is solid, span2 is AA
278            // 2 = span1 is AA, span2 is solid
279            // 3 = Both spans are of solid type
280            //-----------------
281            switch((span1->len < 0) | ((span2->len < 0) << 1))
282            {
283            case 0:      // Both are AA spans
284                covers1 = span1->covers;
285                covers2 = span2->covers;
286                if(span1->x < x) covers1 += x - span1->x;
287                if(span2->x < x) covers2 += x - span2->x;
288                do
289                {
290                    cover = cover_mask * cover_mask -
291                                (cover_mask - *covers1++) *
292                                (cover_mask - *covers2++);
293                    sl.add_cell(x++,
294                                (cover == cover_full * cover_full) ?
295                                cover_full :
296                                (cover >> cover_shift));
297                }
298                while(--len);
299                break;
300
301            case 1:      // span1 is solid, span2 is AA
302                covers2 = span2->covers;
303                if(span2->x < x) covers2 += x - span2->x;
304                if(*(span1->covers) == cover_full)
305                {
306                    sl.add_span(x, len, cover_full);
307                }
308                else
309                {
310                    do
311                    {
312                        cover = cover_mask * cover_mask -
313                                    (cover_mask - *(span1->covers)) *
314                                    (cover_mask - *covers2++);
315                        sl.add_cell(x++,
316                                    (cover == cover_full * cover_full) ?
317                                    cover_full :
318                                    (cover >> cover_shift));
319                    }
320                    while(--len);
321                }
322                break;
323
324            case 2:      // span1 is AA, span2 is solid
325                covers1 = span1->covers;
326                if(span1->x < x) covers1 += x - span1->x;
327                if(*(span2->covers) == cover_full)
328                {
329                    sl.add_span(x, len, cover_full);
330                }
331                else
332                {
333                    do
334                    {
335                        cover = cover_mask * cover_mask -
336                                    (cover_mask - *covers1++) *
337                                    (cover_mask - *(span2->covers));
338                        sl.add_cell(x++,
339                                    (cover == cover_full * cover_full) ?
340                                    cover_full :
341                                    (cover >> cover_shift));
342                    }
343                    while(--len);
344                }
345                break;
346
347            case 3:      // Both are solid spans
348                cover = cover_mask * cover_mask -
349                            (cover_mask - *(span1->covers)) *
350                            (cover_mask - *(span2->covers));
351                sl.add_span(x, len,
352                            (cover == cover_full * cover_full) ?
353                            cover_full :
354                            (cover >> cover_shift));
355                break;
356            }
357        }
358    };
359
360
361    //---------------------------------------------sbool_xor_formula_linear
362    template<unsigned CoverShift = cover_shift>
363    struct sbool_xor_formula_linear
364    {
365        enum cover_scale_e
366        {
367            cover_shift = CoverShift,
368            cover_size  = 1 << cover_shift,
369            cover_mask  = cover_size - 1
370        };
371
372        static AGG_INLINE unsigned calculate(unsigned a, unsigned b)
373        {
374            unsigned cover = a + b;
375            if(cover > cover_mask) cover = cover_mask + cover_mask - cover;
376            return cover;
377        }
378    };
379
380
381    //---------------------------------------------sbool_xor_formula_saddle
382    template<unsigned CoverShift = cover_shift>
383    struct sbool_xor_formula_saddle
384    {
385        enum cover_scale_e
386        {
387            cover_shift = CoverShift,
388            cover_size  = 1 << cover_shift,
389            cover_mask  = cover_size - 1
390        };
391
392        static AGG_INLINE unsigned calculate(unsigned a, unsigned b)
393        {
394            unsigned k = a * b;
395            if(k == cover_mask * cover_mask) return 0;
396
397            a = (cover_mask * cover_mask - (a << cover_shift) + k) >> cover_shift;
398            b = (cover_mask * cover_mask - (b << cover_shift) + k) >> cover_shift;
399            return cover_mask - ((a * b) >> cover_shift);
400        }
401    };
402
403
404    //-------------------------------------------sbool_xor_formula_abs_diff
405    struct sbool_xor_formula_abs_diff
406    {
407        static AGG_INLINE unsigned calculate(unsigned a, unsigned b)
408        {
409            return unsigned(abs(int(a) - int(b)));
410        }
411    };
412
413
414
415    //----------------------------------------------------sbool_xor_spans_aa
416    // Functor.
417    // XOR two spans preserving the anti-aliasing information.
418    // The result is added to the "sl" scanline.
419    //------------------
420    template<class Scanline1,
421             class Scanline2,
422             class Scanline,
423             class XorFormula,
424             unsigned CoverShift = cover_shift>
425    struct sbool_xor_spans_aa
426    {
427        enum cover_scale_e
428        {
429            cover_shift = CoverShift,
430            cover_size  = 1 << cover_shift,
431            cover_mask  = cover_size - 1,
432            cover_full  = cover_mask
433        };
434
435
436        void operator () (const typename Scanline1::const_iterator& span1,
437                          const typename Scanline2::const_iterator& span2,
438                          int x, unsigned len,
439                          Scanline& sl) const
440        {
441            unsigned cover;
442            const typename Scanline1::cover_type* covers1;
443            const typename Scanline2::cover_type* covers2;
444
445            // Calculate the operation code and choose the
446            // proper combination algorithm.
447            // 0 = Both spans are of AA type
448            // 1 = span1 is solid, span2 is AA
449            // 2 = span1 is AA, span2 is solid
450            // 3 = Both spans are of solid type
451            //-----------------
452            switch((span1->len < 0) | ((span2->len < 0) << 1))
453            {
454            case 0:      // Both are AA spans
455                covers1 = span1->covers;
456                covers2 = span2->covers;
457                if(span1->x < x) covers1 += x - span1->x;
458                if(span2->x < x) covers2 += x - span2->x;
459                do
460                {
461                    cover = XorFormula::calculate(*covers1++, *covers2++);
462                    if(cover) sl.add_cell(x, cover);
463                    ++x;
464                }
465                while(--len);
466                break;
467
468            case 1:      // span1 is solid, span2 is AA
469                covers2 = span2->covers;
470                if(span2->x < x) covers2 += x - span2->x;
471                do
472                {
473                    cover = XorFormula::calculate(*(span1->covers), *covers2++);
474                    if(cover) sl.add_cell(x, cover);
475                    ++x;
476                }
477                while(--len);
478                break;
479
480            case 2:      // span1 is AA, span2 is solid
481                covers1 = span1->covers;
482                if(span1->x < x) covers1 += x - span1->x;
483                do
484                {
485                    cover = XorFormula::calculate(*covers1++, *(span2->covers));
486                    if(cover) sl.add_cell(x, cover);
487                    ++x;
488                }
489                while(--len);
490                break;
491
492            case 3:      // Both are solid spans
493                cover = XorFormula::calculate(*(span1->covers), *(span2->covers));
494                if(cover) sl.add_span(x, len, cover);
495                break;
496
497            }
498        }
499    };
500
501
502
503
504
505    //-----------------------------------------------sbool_subtract_spans_aa
506    // Functor.
507    // Unite two spans preserving the anti-aliasing information.
508    // The result is added to the "sl" scanline.
509    //------------------
510    template<class Scanline1,
511             class Scanline2,
512             class Scanline,
513             unsigned CoverShift = cover_shift>
514    struct sbool_subtract_spans_aa
515    {
516        enum cover_scale_e
517        {
518            cover_shift = CoverShift,
519            cover_size  = 1 << cover_shift,
520            cover_mask  = cover_size - 1,
521            cover_full  = cover_mask
522        };
523
524
525        void operator () (const typename Scanline1::const_iterator& span1,
526                          const typename Scanline2::const_iterator& span2,
527                          int x, unsigned len,
528                          Scanline& sl) const
529        {
530            unsigned cover;
531            const typename Scanline1::cover_type* covers1;
532            const typename Scanline2::cover_type* covers2;
533
534            // Calculate the operation code and choose the
535            // proper combination algorithm.
536            // 0 = Both spans are of AA type
537            // 1 = span1 is solid, span2 is AA
538            // 2 = span1 is AA, span2 is solid
539            // 3 = Both spans are of solid type
540            //-----------------
541            switch((span1->len < 0) | ((span2->len < 0) << 1))
542            {
543            case 0:      // Both are AA spans
544                covers1 = span1->covers;
545                covers2 = span2->covers;
546                if(span1->x < x) covers1 += x - span1->x;
547                if(span2->x < x) covers2 += x - span2->x;
548                do
549                {
550                    cover = *covers1++ * (cover_mask - *covers2++);
551                    if(cover)
552                    {
553                        sl.add_cell(x,
554                                    (cover == cover_full * cover_full) ?
555                                    cover_full :
556                                    (cover >> cover_shift));
557                    }
558                    ++x;
559                }
560                while(--len);
561                break;
562
563            case 1:      // span1 is solid, span2 is AA
564                covers2 = span2->covers;
565                if(span2->x < x) covers2 += x - span2->x;
566                do
567                {
568                    cover = *(span1->covers) * (cover_mask - *covers2++);
569                    if(cover)
570                    {
571                        sl.add_cell(x,
572                                    (cover == cover_full * cover_full) ?
573                                    cover_full :
574                                    (cover >> cover_shift));
575                    }
576                    ++x;
577                }
578                while(--len);
579                break;
580
581            case 2:      // span1 is AA, span2 is solid
582                covers1 = span1->covers;
583                if(span1->x < x) covers1 += x - span1->x;
584                if(*(span2->covers) != cover_full)
585                {
586                    do
587                    {
588                        cover = *covers1++ * (cover_mask - *(span2->covers));
589                        if(cover)
590                        {
591                            sl.add_cell(x,
592                                        (cover == cover_full * cover_full) ?
593                                        cover_full :
594                                        (cover >> cover_shift));
595                        }
596                        ++x;
597                    }
598                    while(--len);
599                }
600                break;
601
602            case 3:      // Both are solid spans
603                cover = *(span1->covers) * (cover_mask - *(span2->covers));
604                if(cover)
605                {
606                    sl.add_span(x, len,
607                                (cover == cover_full * cover_full) ?
608                                cover_full :
609                                (cover >> cover_shift));
610                }
611                break;
612            }
613        }
614    };
615
616
617
618
619
620
621    //--------------------------------------------sbool_add_spans_and_render
622    template<class Scanline1,
623             class Scanline,
624             class Renderer,
625             class AddSpanFunctor>
626    void sbool_add_spans_and_render(const Scanline1& sl1,
627                                    Scanline& sl,
628                                    Renderer& ren,
629                                    AddSpanFunctor add_span)
630    {
631        sl.reset_spans();
632        typename Scanline1::const_iterator span = sl1.begin();
633        unsigned num_spans = sl1.num_spans();
634        for(;;)
635        {
636            add_span(span, span->x, abs((int)span->len), sl);
637            if(--num_spans == 0) break;
638            ++span;
639        }
640        sl.finalize(sl1.y());
641        ren.render(sl);
642    }
643
644
645
646
647
648
649
650    //---------------------------------------------sbool_intersect_scanlines
651    // Intersect two scanlines, "sl1" and "sl2" and generate a new "sl" one.
652    // The combine_spans functor can be of type sbool_combine_spans_bin or
653    // sbool_intersect_spans_aa. First is a general functor to combine
654    // two spans without Anti-Aliasing, the second preserves the AA
655    // information, but works slower
656    //
657    template<class Scanline1,
658             class Scanline2,
659             class Scanline,
660             class CombineSpansFunctor>
661    void sbool_intersect_scanlines(const Scanline1& sl1,
662                                   const Scanline2& sl2,
663                                   Scanline& sl,
664                                   CombineSpansFunctor combine_spans)
665    {
666        sl.reset_spans();
667
668        unsigned num1 = sl1.num_spans();
669        if(num1 == 0) return;
670
671        unsigned num2 = sl2.num_spans();
672        if(num2 == 0) return;
673
674        typename Scanline1::const_iterator span1 = sl1.begin();
675        typename Scanline2::const_iterator span2 = sl2.begin();
676
677        while(num1 && num2)
678        {
679            int xb1 = span1->x;
680            int xb2 = span2->x;
681            int xe1 = xb1 + abs((int)span1->len) - 1;
682            int xe2 = xb2 + abs((int)span2->len) - 1;
683
684            // Determine what spans we should advance in the next step
685            // The span with the least ending X should be advanced
686            // advance_both is just an optimization when we ending
687            // coordinates are the same and we can advance both
688            //--------------
689            bool advance_span1 = xe1 <  xe2;
690            bool advance_both  = xe1 == xe2;
691
692            // Find the intersection of the spans
693            // and check if they intersect
694            //--------------
695            if(xb1 < xb2) xb1 = xb2;
696            if(xe1 > xe2) xe1 = xe2;
697            if(xb1 <= xe1)
698            {
699                combine_spans(span1, span2, xb1, xe1 - xb1 + 1, sl);
700            }
701
702            // Advance the spans
703            //--------------
704            if(advance_both)
705            {
706                --num1;
707                --num2;
708                if(num1) ++span1;
709                if(num2) ++span2;
710            }
711            else
712            {
713                if(advance_span1)
714                {
715                    --num1;
716                    if(num1) ++span1;
717                }
718                else
719                {
720                    --num2;
721                    if(num2) ++span2;
722                }
723            }
724        }
725    }
726
727
728
729
730
731
732
733
734    //------------------------------------------------sbool_intersect_shapes
735    // Intersect the scanline shapes. Here the "Scanline Generator"
736    // abstraction is used. ScanlineGen1 and ScanlineGen2 are
737    // the generators, and can be of type rasterizer_scanline_aa<>.
738    // There function requires three scanline containers that can be of
739    // different types.
740    // "sl1" and "sl2" are used to retrieve scanlines from the generators,
741    // "sl" is ised as the resulting scanline to render it.
742    // The external "sl1" and "sl2" are used only for the sake of
743    // optimization and reusing of the scanline objects.
744    // the function calls sbool_intersect_scanlines with CombineSpansFunctor
745    // as the last argument. See sbool_intersect_scanlines for details.
746    //----------
747    template<class ScanlineGen1,
748             class ScanlineGen2,
749             class Scanline1,
750             class Scanline2,
751             class Scanline,
752             class Renderer,
753             class CombineSpansFunctor>
754    void sbool_intersect_shapes(ScanlineGen1& sg1, ScanlineGen2& sg2,
755                                Scanline1& sl1, Scanline2& sl2,
756                                Scanline& sl, Renderer& ren,
757                                CombineSpansFunctor combine_spans)
758    {
759        // Prepare the scanline generators.
760        // If anyone of them doesn't contain
761        // any scanlines, then return.
762        //-----------------
763        if(!sg1.rewind_scanlines()) return;
764        if(!sg2.rewind_scanlines()) return;
765
766        // Get the bounding boxes
767        //----------------
768        rect_i r1(sg1.min_x(), sg1.min_y(), sg1.max_x(), sg1.max_y());
769        rect_i r2(sg2.min_x(), sg2.min_y(), sg2.max_x(), sg2.max_y());
770
771        // Calculate the intersection of the bounding
772        // boxes and return if they don't intersect.
773        //-----------------
774        rect_i ir = intersect_rectangles(r1, r2);
775        if(!ir.is_valid()) return;
776
777        // Reset the scanlines and get two first ones
778        //-----------------
779        sl.reset(ir.x1, ir.x2);
780        sl1.reset(sg1.min_x(), sg1.max_x());
781        sl2.reset(sg2.min_x(), sg2.max_x());
782        if(!sg1.sweep_scanline(sl1)) return;
783        if(!sg2.sweep_scanline(sl2)) return;
784
785        ren.prepare();
786
787        // The main loop
788        // Here we synchronize the scanlines with
789        // the same Y coordinate, ignoring all other ones.
790        // Only scanlines having the same Y-coordinate
791        // are to be combined.
792        //-----------------
793        for(;;)
794        {
795            while(sl1.y() < sl2.y())
796            {
797                if(!sg1.sweep_scanline(sl1)) return;
798            }
799            while(sl2.y() < sl1.y())
800            {
801                if(!sg2.sweep_scanline(sl2)) return;
802            }
803
804            if(sl1.y() == sl2.y())
805            {
806                // The Y coordinates are the same.
807                // Combine the scanlines, render if they contain any spans,
808                // and advance both generators to the next scanlines
809                //----------------------
810                sbool_intersect_scanlines(sl1, sl2, sl, combine_spans);
811                if(sl.num_spans())
812                {
813                    sl.finalize(sl1.y());
814                    ren.render(sl);
815                }
816                if(!sg1.sweep_scanline(sl1)) return;
817                if(!sg2.sweep_scanline(sl2)) return;
818            }
819        }
820    }
821
822
823
824
825
826
827
828    //-------------------------------------------------sbool_unite_scanlines
829    // Unite two scanlines, "sl1" and "sl2" and generate a new "sl" one.
830    // The combine_spans functor can be of type sbool_combine_spans_bin or
831    // sbool_intersect_spans_aa. First is a general functor to combine
832    // two spans without Anti-Aliasing, the second preserves the AA
833    // information, but works slower
834    //
835    template<class Scanline1,
836             class Scanline2,
837             class Scanline,
838             class AddSpanFunctor1,
839             class AddSpanFunctor2,
840             class CombineSpansFunctor>
841    void sbool_unite_scanlines(const Scanline1& sl1,
842                               const Scanline2& sl2,
843                               Scanline& sl,
844                               AddSpanFunctor1 add_span1,
845                               AddSpanFunctor2 add_span2,
846                               CombineSpansFunctor combine_spans)
847    {
848        sl.reset_spans();
849
850        unsigned num1 = sl1.num_spans();
851        unsigned num2 = sl2.num_spans();
852
853        typename Scanline1::const_iterator span1;// = sl1.begin();
854        typename Scanline2::const_iterator span2;// = sl2.begin();
855
856        enum invalidation_e
857        {
858            invalid_b = 0xFFFFFFF,
859            invalid_e = invalid_b - 1
860        };
861
862        // Initialize the spans as invalid
863        //---------------
864        int xb1 = invalid_b;
865        int xb2 = invalid_b;
866        int xe1 = invalid_e;
867        int xe2 = invalid_e;
868
869        // Initialize span1 if there are spans
870        //---------------
871        if(num1)
872        {
873            span1 = sl1.begin();
874            xb1 = span1->x;
875            xe1 = xb1 + abs((int)span1->len) - 1;
876            --num1;
877        }
878
879        // Initialize span2 if there are spans
880        //---------------
881        if(num2)
882        {
883            span2 = sl2.begin();
884            xb2 = span2->x;
885            xe2 = xb2 + abs((int)span2->len) - 1;
886            --num2;
887        }
888
889
890        for(;;)
891        {
892            // Retrieve a new span1 if it's invalid
893            //----------------
894            if(num1 && xb1 > xe1)
895            {
896                --num1;
897                ++span1;
898                xb1 = span1->x;
899                xe1 = xb1 + abs((int)span1->len) - 1;
900            }
901
902            // Retrieve a new span2 if it's invalid
903            //----------------
904            if(num2 && xb2 > xe2)
905            {
906                --num2;
907                ++span2;
908                xb2 = span2->x;
909                xe2 = xb2 + abs((int)span2->len) - 1;
910            }
911
912            if(xb1 > xe1 && xb2 > xe2) break;
913
914            // Calculate the intersection
915            //----------------
916            int xb = xb1;
917            int xe = xe1;
918            if(xb < xb2) xb = xb2;
919            if(xe > xe2) xe = xe2;
920            int len = xe - xb + 1; // The length of the intersection
921            if(len > 0)
922            {
923                // The spans intersect,
924                // add the beginning of the span
925                //----------------
926                if(xb1 < xb2)
927                {
928                    add_span1(span1, xb1, xb2 - xb1, sl);
929                    xb1 = xb2;
930                }
931                else
932                if(xb2 < xb1)
933                {
934                    add_span2(span2, xb2, xb1 - xb2, sl);
935                    xb2 = xb1;
936                }
937
938                // Add the combination part of the spans
939                //----------------
940                combine_spans(span1, span2, xb, len, sl);
941
942
943                // Invalidate the fully processed span or both
944                //----------------
945                if(xe1 < xe2)
946                {
947                    // Invalidate span1 and eat
948                    // the processed part of span2
949                    //--------------
950                    xb1 = invalid_b;
951                    xe1 = invalid_e;
952                    xb2 += len;
953                }
954                else
955                if(xe2 < xe1)
956                {
957                    // Invalidate span2 and eat
958                    // the processed part of span1
959                    //--------------
960                    xb2 = invalid_b;
961                    xe2 = invalid_e;
962                    xb1 += len;
963                }
964                else
965                {
966                    xb1 = invalid_b;  // Invalidate both
967                    xb2 = invalid_b;
968                    xe1 = invalid_e;
969                    xe2 = invalid_e;
970                }
971            }
972            else
973            {
974                // The spans do not intersect
975                //--------------
976                if(xb1 < xb2)
977                {
978                    // Advance span1
979                    //---------------
980                    if(xb1 <= xe1)
981                    {
982                        add_span1(span1, xb1, xe1 - xb1 + 1, sl);
983                    }
984                    xb1 = invalid_b; // Invalidate
985                    xe1 = invalid_e;
986                }
987                else
988                {
989                    // Advance span2
990                    //---------------
991                    if(xb2 <= xe2)
992                    {
993                        add_span2(span2, xb2, xe2 - xb2 + 1, sl);
994                    }
995                    xb2 = invalid_b; // Invalidate
996                    xe2 = invalid_e;
997                }
998            }
999        }
1000    }
1001
1002
1003
1004
1005    //----------------------------------------------------sbool_unite_shapes
1006    // Unite the scanline shapes. Here the "Scanline Generator"
1007    // abstraction is used. ScanlineGen1 and ScanlineGen2 are
1008    // the generators, and can be of type rasterizer_scanline_aa<>.
1009    // There function requires three scanline containers that can be
1010    // of different type.
1011    // "sl1" and "sl2" are used to retrieve scanlines from the generators,
1012    // "sl" is ised as the resulting scanline to render it.
1013    // The external "sl1" and "sl2" are used only for the sake of
1014    // optimization and reusing of the scanline objects.
1015    // the function calls sbool_unite_scanlines with CombineSpansFunctor
1016    // as the last argument. See sbool_unite_scanlines for details.
1017    //----------
1018    template<class ScanlineGen1,
1019             class ScanlineGen2,
1020             class Scanline1,
1021             class Scanline2,
1022             class Scanline,
1023             class Renderer,
1024             class AddSpanFunctor1,
1025             class AddSpanFunctor2,
1026             class CombineSpansFunctor>
1027    void sbool_unite_shapes(ScanlineGen1& sg1, ScanlineGen2& sg2,
1028                            Scanline1& sl1, Scanline2& sl2,
1029                            Scanline& sl, Renderer& ren,
1030                            AddSpanFunctor1 add_span1,
1031                            AddSpanFunctor2 add_span2,
1032                            CombineSpansFunctor combine_spans)
1033    {
1034        // Prepare the scanline generators.
1035        // If anyone of them doesn't contain
1036        // any scanlines, then return.
1037        //-----------------
1038        bool flag1 = sg1.rewind_scanlines();
1039        bool flag2 = sg2.rewind_scanlines();
1040        if(!flag1 && !flag2) return;
1041
1042        // Get the bounding boxes
1043        //----------------
1044        rect_i r1(sg1.min_x(), sg1.min_y(), sg1.max_x(), sg1.max_y());
1045        rect_i r2(sg2.min_x(), sg2.min_y(), sg2.max_x(), sg2.max_y());
1046
1047        // Calculate the union of the bounding boxes
1048        //-----------------
1049        rect_i ur(1,1,0,0);
1050             if(flag1 && flag2) ur = unite_rectangles(r1, r2);
1051        else if(flag1)          ur = r1;
1052        else if(flag2)          ur = r2;
1053
1054        if(!ur.is_valid()) return;
1055
1056        ren.prepare();
1057
1058        // Reset the scanlines and get two first ones
1059        //-----------------
1060        sl.reset(ur.x1, ur.x2);
1061        if(flag1)
1062        {
1063            sl1.reset(sg1.min_x(), sg1.max_x());
1064            flag1 = sg1.sweep_scanline(sl1);
1065        }
1066
1067        if(flag2)
1068        {
1069            sl2.reset(sg2.min_x(), sg2.max_x());
1070            flag2 = sg2.sweep_scanline(sl2);
1071        }
1072
1073        // The main loop
1074        // Here we synchronize the scanlines with
1075        // the same Y coordinate.
1076        //-----------------
1077        while(flag1 || flag2)
1078        {
1079            if(flag1 && flag2)
1080            {
1081                if(sl1.y() == sl2.y())
1082                {
1083                    // The Y coordinates are the same.
1084                    // Combine the scanlines, render if they contain any spans,
1085                    // and advance both generators to the next scanlines
1086                    //----------------------
1087                    sbool_unite_scanlines(sl1, sl2, sl,
1088                                          add_span1, add_span2, combine_spans);
1089                    if(sl.num_spans())
1090                    {
1091                        sl.finalize(sl1.y());
1092                        ren.render(sl);
1093                    }
1094                    flag1 = sg1.sweep_scanline(sl1);
1095                    flag2 = sg2.sweep_scanline(sl2);
1096                }
1097                else
1098                {
1099                    if(sl1.y() < sl2.y())
1100                    {
1101                        sbool_add_spans_and_render(sl1, sl, ren, add_span1);
1102                        flag1 = sg1.sweep_scanline(sl1);
1103                    }
1104                    else
1105                    {
1106                        sbool_add_spans_and_render(sl2, sl, ren, add_span2);
1107                        flag2 = sg2.sweep_scanline(sl2);
1108                    }
1109                }
1110            }
1111            else
1112            {
1113                if(flag1)
1114                {
1115                    sbool_add_spans_and_render(sl1, sl, ren, add_span1);
1116                    flag1 = sg1.sweep_scanline(sl1);
1117                }
1118                if(flag2)
1119                {
1120                    sbool_add_spans_and_render(sl2, sl, ren, add_span2);
1121                    flag2 = sg2.sweep_scanline(sl2);
1122                }
1123            }
1124        }
1125    }
1126
1127
1128
1129
1130
1131
1132
1133
1134    //-------------------------------------------------sbool_subtract_shapes
1135    // Subtract the scanline shapes, "sg1-sg2". Here the "Scanline Generator"
1136    // abstraction is used. ScanlineGen1 and ScanlineGen2 are
1137    // the generators, and can be of type rasterizer_scanline_aa<>.
1138    // There function requires three scanline containers that can be of
1139    // different types.
1140    // "sl1" and "sl2" are used to retrieve scanlines from the generators,
1141    // "sl" is ised as the resulting scanline to render it.
1142    // The external "sl1" and "sl2" are used only for the sake of
1143    // optimization and reusing of the scanline objects.
1144    // the function calls sbool_intersect_scanlines with CombineSpansFunctor
1145    // as the last argument. See combine_scanlines_sub for details.
1146    //----------
1147    template<class ScanlineGen1,
1148             class ScanlineGen2,
1149             class Scanline1,
1150             class Scanline2,
1151             class Scanline,
1152             class Renderer,
1153             class AddSpanFunctor1,
1154             class CombineSpansFunctor>
1155    void sbool_subtract_shapes(ScanlineGen1& sg1, ScanlineGen2& sg2,
1156                               Scanline1& sl1, Scanline2& sl2,
1157                               Scanline& sl, Renderer& ren,
1158                               AddSpanFunctor1 add_span1,
1159                               CombineSpansFunctor combine_spans)
1160    {
1161        // Prepare the scanline generators.
1162        // Here "sg1" is master, "sg2" is slave.
1163        //-----------------
1164        if(!sg1.rewind_scanlines()) return;
1165        bool flag2 = sg2.rewind_scanlines();
1166
1167        // Get the bounding box
1168        //----------------
1169        rect_i r1(sg1.min_x(), sg1.min_y(), sg1.max_x(), sg1.max_y());
1170
1171        // Reset the scanlines and get two first ones
1172        //-----------------
1173        sl.reset(sg1.min_x(), sg1.max_x());
1174        sl1.reset(sg1.min_x(), sg1.max_x());
1175        sl2.reset(sg2.min_x(), sg2.max_x());
1176        if(!sg1.sweep_scanline(sl1)) return;
1177
1178        if(flag2) flag2 = sg2.sweep_scanline(sl2);
1179
1180        ren.prepare();
1181
1182        // A fake span2 processor
1183        sbool_add_span_empty<Scanline2, Scanline> add_span2;
1184
1185        // The main loop
1186        // Here we synchronize the scanlines with
1187        // the same Y coordinate, ignoring all other ones.
1188        // Only scanlines having the same Y-coordinate
1189        // are to be combined.
1190        //-----------------
1191        bool flag1 = true;
1192        do
1193        {
1194            // Synchronize "slave" with "master"
1195            //-----------------
1196            while(flag2 && sl2.y() < sl1.y())
1197            {
1198                flag2 = sg2.sweep_scanline(sl2);
1199            }
1200
1201
1202            if(flag2 && sl2.y() == sl1.y())
1203            {
1204                // The Y coordinates are the same.
1205                // Combine the scanlines and render if they contain any spans.
1206                //----------------------
1207                sbool_unite_scanlines(sl1, sl2, sl, add_span1, add_span2, combine_spans);
1208                if(sl.num_spans())
1209                {
1210                    sl.finalize(sl1.y());
1211                    ren.render(sl);
1212                }
1213            }
1214            else
1215            {
1216                sbool_add_spans_and_render(sl1, sl, ren, add_span1);
1217            }
1218
1219            // Advance the "master"
1220            flag1 = sg1.sweep_scanline(sl1);
1221        }
1222        while(flag1);
1223    }
1224
1225
1226
1227
1228
1229
1230
1231    //---------------------------------------------sbool_intersect_shapes_aa
1232    // Intersect two anti-aliased scanline shapes.
1233    // Here the "Scanline Generator" abstraction is used.
1234    // ScanlineGen1 and ScanlineGen2 are the generators, and can be of
1235    // type rasterizer_scanline_aa<>. There function requires three
1236    // scanline containers that can be of different types.
1237    // "sl1" and "sl2" are used to retrieve scanlines from the generators,
1238    // "sl" is ised as the resulting scanline to render it.
1239    // The external "sl1" and "sl2" are used only for the sake of
1240    // optimization and reusing of the scanline objects.
1241    //----------
1242    template<class ScanlineGen1,
1243             class ScanlineGen2,
1244             class Scanline1,
1245             class Scanline2,
1246             class Scanline,
1247             class Renderer>
1248    void sbool_intersect_shapes_aa(ScanlineGen1& sg1, ScanlineGen2& sg2,
1249                                   Scanline1& sl1, Scanline2& sl2,
1250                                   Scanline& sl, Renderer& ren)
1251    {
1252        sbool_intersect_spans_aa<Scanline1, Scanline2, Scanline> combine_functor;
1253        sbool_intersect_shapes(sg1, sg2, sl1, sl2, sl, ren, combine_functor);
1254    }
1255
1256
1257
1258
1259
1260    //--------------------------------------------sbool_intersect_shapes_bin
1261    // Intersect two binary scanline shapes (without anti-aliasing).
1262    // See intersect_shapes_aa for more comments
1263    //----------
1264    template<class ScanlineGen1,
1265             class ScanlineGen2,
1266             class Scanline1,
1267             class Scanline2,
1268             class Scanline,
1269             class Renderer>
1270    void sbool_intersect_shapes_bin(ScanlineGen1& sg1, ScanlineGen2& sg2,
1271                                    Scanline1& sl1, Scanline2& sl2,
1272                                    Scanline& sl, Renderer& ren)
1273    {
1274        sbool_combine_spans_bin<Scanline1, Scanline2, Scanline> combine_functor;
1275        sbool_intersect_shapes(sg1, sg2, sl1, sl2, sl, ren, combine_functor);
1276    }
1277
1278
1279
1280
1281
1282    //-------------------------------------------------sbool_unite_shapes_aa
1283    // Unite two anti-aliased scanline shapes
1284    // See intersect_shapes_aa for more comments
1285    //----------
1286    template<class ScanlineGen1,
1287             class ScanlineGen2,
1288             class Scanline1,
1289             class Scanline2,
1290             class Scanline,
1291             class Renderer>
1292    void sbool_unite_shapes_aa(ScanlineGen1& sg1, ScanlineGen2& sg2,
1293                               Scanline1& sl1, Scanline2& sl2,
1294                               Scanline& sl, Renderer& ren)
1295    {
1296        sbool_add_span_aa<Scanline1, Scanline> add_functor1;
1297        sbool_add_span_aa<Scanline2, Scanline> add_functor2;
1298        sbool_unite_spans_aa<Scanline1, Scanline2, Scanline> combine_functor;
1299        sbool_unite_shapes(sg1, sg2, sl1, sl2, sl, ren,
1300                           add_functor1, add_functor2, combine_functor);
1301    }
1302
1303
1304
1305
1306
1307    //------------------------------------------------sbool_unite_shapes_bin
1308    // Unite two binary scanline shapes (without anti-aliasing).
1309    // See intersect_shapes_aa for more comments
1310    //----------
1311    template<class ScanlineGen1,
1312             class ScanlineGen2,
1313             class Scanline1,
1314             class Scanline2,
1315             class Scanline,
1316             class Renderer>
1317    void sbool_unite_shapes_bin(ScanlineGen1& sg1, ScanlineGen2& sg2,
1318                                Scanline1& sl1, Scanline2& sl2,
1319                                Scanline& sl, Renderer& ren)
1320    {
1321        sbool_add_span_bin<Scanline1, Scanline> add_functor1;
1322        sbool_add_span_bin<Scanline2, Scanline> add_functor2;
1323        sbool_combine_spans_bin<Scanline1, Scanline2, Scanline> combine_functor;
1324        sbool_unite_shapes(sg1, sg2, sl1, sl2, sl, ren,
1325                           add_functor1, add_functor2, combine_functor);
1326    }
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336    //---------------------------------------------------sbool_xor_shapes_aa
1337    // Apply eXclusive OR to two anti-aliased scanline shapes. There's
1338    // a modified "Linear" XOR used instead of classical "Saddle" one.
1339    // The reason is to have the result absolutely conststent with what
1340    // the scanline rasterizer produces.
1341    // See intersect_shapes_aa for more comments
1342    //----------
1343    template<class ScanlineGen1,
1344             class ScanlineGen2,
1345             class Scanline1,
1346             class Scanline2,
1347             class Scanline,
1348             class Renderer>
1349    void sbool_xor_shapes_aa(ScanlineGen1& sg1, ScanlineGen2& sg2,
1350                             Scanline1& sl1, Scanline2& sl2,
1351                             Scanline& sl, Renderer& ren)
1352    {
1353        sbool_add_span_aa<Scanline1, Scanline> add_functor1;
1354        sbool_add_span_aa<Scanline2, Scanline> add_functor2;
1355        sbool_xor_spans_aa<Scanline1, Scanline2, Scanline,
1356                           sbool_xor_formula_linear<> > combine_functor;
1357        sbool_unite_shapes(sg1, sg2, sl1, sl2, sl, ren,
1358                           add_functor1, add_functor2, combine_functor);
1359    }
1360
1361
1362
1363    //------------------------------------------sbool_xor_shapes_saddle_aa
1364    // Apply eXclusive OR to two anti-aliased scanline shapes.
1365    // There's the classical "Saddle" used to calculate the
1366    // Anti-Aliasing values, that is:
1367    // a XOR b : 1-((1-a+a*b)*(1-b+a*b))
1368    // See intersect_shapes_aa for more comments
1369    //----------
1370    template<class ScanlineGen1,
1371             class ScanlineGen2,
1372             class Scanline1,
1373             class Scanline2,
1374             class Scanline,
1375             class Renderer>
1376    void sbool_xor_shapes_saddle_aa(ScanlineGen1& sg1, ScanlineGen2& sg2,
1377                                    Scanline1& sl1, Scanline2& sl2,
1378                                    Scanline& sl, Renderer& ren)
1379    {
1380        sbool_add_span_aa<Scanline1, Scanline> add_functor1;
1381        sbool_add_span_aa<Scanline2, Scanline> add_functor2;
1382        sbool_xor_spans_aa<Scanline1,
1383                           Scanline2,
1384                           Scanline,
1385                           sbool_xor_formula_saddle<> > combine_functor;
1386        sbool_unite_shapes(sg1, sg2, sl1, sl2, sl, ren,
1387                           add_functor1, add_functor2, combine_functor);
1388    }
1389
1390
1391    //--------------------------------------sbool_xor_shapes_abs_diff_aa
1392    // Apply eXclusive OR to two anti-aliased scanline shapes.
1393    // There's the absolute difference used to calculate
1394    // Anti-Aliasing values, that is:
1395    // a XOR b : abs(a-b)
1396    // See intersect_shapes_aa for more comments
1397    //----------
1398    template<class ScanlineGen1,
1399             class ScanlineGen2,
1400             class Scanline1,
1401             class Scanline2,
1402             class Scanline,
1403             class Renderer>
1404    void sbool_xor_shapes_abs_diff_aa(ScanlineGen1& sg1, ScanlineGen2& sg2,
1405                                      Scanline1& sl1, Scanline2& sl2,
1406                                      Scanline& sl, Renderer& ren)
1407    {
1408        sbool_add_span_aa<Scanline1, Scanline> add_functor1;
1409        sbool_add_span_aa<Scanline2, Scanline> add_functor2;
1410        sbool_xor_spans_aa<Scanline1,
1411                           Scanline2,
1412                           Scanline,
1413                           sbool_xor_formula_abs_diff> combine_functor;
1414        sbool_unite_shapes(sg1, sg2, sl1, sl2, sl, ren,
1415                           add_functor1, add_functor2, combine_functor);
1416    }
1417
1418
1419
1420    //--------------------------------------------------sbool_xor_shapes_bin
1421    // Apply eXclusive OR to two binary scanline shapes (without anti-aliasing).
1422    // See intersect_shapes_aa for more comments
1423    //----------
1424    template<class ScanlineGen1,
1425             class ScanlineGen2,
1426             class Scanline1,
1427             class Scanline2,
1428             class Scanline,
1429             class Renderer>
1430    void sbool_xor_shapes_bin(ScanlineGen1& sg1, ScanlineGen2& sg2,
1431                              Scanline1& sl1, Scanline2& sl2,
1432                              Scanline& sl, Renderer& ren)
1433    {
1434        sbool_add_span_bin<Scanline1, Scanline> add_functor1;
1435        sbool_add_span_bin<Scanline2, Scanline> add_functor2;
1436        sbool_combine_spans_empty<Scanline1, Scanline2, Scanline> combine_functor;
1437        sbool_unite_shapes(sg1, sg2, sl1, sl2, sl, ren,
1438                           add_functor1, add_functor2, combine_functor);
1439    }
1440
1441
1442
1443
1444
1445
1446    //----------------------------------------------sbool_subtract_shapes_aa
1447    // Subtract shapes "sg1-sg2" with anti-aliasing
1448    // See intersect_shapes_aa for more comments
1449    //----------
1450    template<class ScanlineGen1,
1451             class ScanlineGen2,
1452             class Scanline1,
1453             class Scanline2,
1454             class Scanline,
1455             class Renderer>
1456    void sbool_subtract_shapes_aa(ScanlineGen1& sg1, ScanlineGen2& sg2,
1457                                  Scanline1& sl1, Scanline2& sl2,
1458                                  Scanline& sl, Renderer& ren)
1459    {
1460        sbool_add_span_aa<Scanline1, Scanline> add_functor;
1461        sbool_subtract_spans_aa<Scanline1, Scanline2, Scanline> combine_functor;
1462        sbool_subtract_shapes(sg1, sg2, sl1, sl2, sl, ren,
1463                              add_functor, combine_functor);
1464    }
1465
1466
1467
1468
1469
1470    //---------------------------------------------sbool_subtract_shapes_bin
1471    // Subtract binary shapes "sg1-sg2" without anti-aliasing
1472    // See intersect_shapes_aa for more comments
1473    //----------
1474    template<class ScanlineGen1,
1475             class ScanlineGen2,
1476             class Scanline1,
1477             class Scanline2,
1478             class Scanline,
1479             class Renderer>
1480    void sbool_subtract_shapes_bin(ScanlineGen1& sg1, ScanlineGen2& sg2,
1481                                   Scanline1& sl1, Scanline2& sl2,
1482                                   Scanline& sl, Renderer& ren)
1483    {
1484        sbool_add_span_bin<Scanline1, Scanline> add_functor;
1485        sbool_combine_spans_empty<Scanline1, Scanline2, Scanline> combine_functor;
1486        sbool_subtract_shapes(sg1, sg2, sl1, sl2, sl, ren,
1487                              add_functor, combine_functor);
1488    }
1489
1490
1491
1492
1493
1494
1495    //------------------------------------------------------------sbool_op_e
1496    enum sbool_op_e
1497    {
1498        sbool_or,            //----sbool_or
1499        sbool_and,           //----sbool_and
1500        sbool_xor,           //----sbool_xor
1501        sbool_xor_saddle,    //----sbool_xor_saddle
1502        sbool_xor_abs_diff,  //----sbool_xor_abs_diff
1503        sbool_a_minus_b,     //----sbool_a_minus_b
1504        sbool_b_minus_a      //----sbool_b_minus_a
1505    };
1506
1507
1508
1509
1510
1511
1512    //----------------------------------------------sbool_combine_shapes_bin
1513    template<class ScanlineGen1,
1514             class ScanlineGen2,
1515             class Scanline1,
1516             class Scanline2,
1517             class Scanline,
1518             class Renderer>
1519    void sbool_combine_shapes_bin(sbool_op_e op,
1520                                  ScanlineGen1& sg1, ScanlineGen2& sg2,
1521                                  Scanline1& sl1, Scanline2& sl2,
1522                                  Scanline& sl, Renderer& ren)
1523    {
1524        switch(op)
1525        {
1526        case sbool_or          : sbool_unite_shapes_bin    (sg1, sg2, sl1, sl2, sl, ren); break;
1527        case sbool_and         : sbool_intersect_shapes_bin(sg1, sg2, sl1, sl2, sl, ren); break;
1528        case sbool_xor         :
1529        case sbool_xor_saddle  :
1530        case sbool_xor_abs_diff: sbool_xor_shapes_bin      (sg1, sg2, sl1, sl2, sl, ren); break;
1531        case sbool_a_minus_b   : sbool_subtract_shapes_bin (sg1, sg2, sl1, sl2, sl, ren); break;
1532        case sbool_b_minus_a   : sbool_subtract_shapes_bin (sg2, sg1, sl2, sl1, sl, ren); break;
1533        }
1534    }
1535
1536
1537
1538
1539    //-----------------------------------------------sbool_combine_shapes_aa
1540    template<class ScanlineGen1,
1541             class ScanlineGen2,
1542             class Scanline1,
1543             class Scanline2,
1544             class Scanline,
1545             class Renderer>
1546    void sbool_combine_shapes_aa(sbool_op_e op,
1547                                 ScanlineGen1& sg1, ScanlineGen2& sg2,
1548                                 Scanline1& sl1, Scanline2& sl2,
1549                                 Scanline& sl, Renderer& ren)
1550    {
1551        switch(op)
1552        {
1553        case sbool_or          : sbool_unite_shapes_aa       (sg1, sg2, sl1, sl2, sl, ren); break;
1554        case sbool_and         : sbool_intersect_shapes_aa   (sg1, sg2, sl1, sl2, sl, ren); break;
1555        case sbool_xor         : sbool_xor_shapes_aa         (sg1, sg2, sl1, sl2, sl, ren); break;
1556        case sbool_xor_saddle  : sbool_xor_shapes_saddle_aa  (sg1, sg2, sl1, sl2, sl, ren); break;
1557        case sbool_xor_abs_diff: sbool_xor_shapes_abs_diff_aa(sg1, sg2, sl1, sl2, sl, ren); break;
1558        case sbool_a_minus_b   : sbool_subtract_shapes_aa    (sg1, sg2, sl1, sl2, sl, ren); break;
1559        case sbool_b_minus_a   : sbool_subtract_shapes_aa    (sg2, sg1, sl2, sl1, sl, ren); break;
1560        }
1561    }
1562
1563}
1564
1565
1566#endif
1567
1568