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