1 //----------------------------------------------------------------------------
2 // Anti-Grain Geometry - Version 2.4
3 // Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com)
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.
10 //----------------------------------------------------------------------------
11 // Contact: mcseem@antigrain.com
12 // mcseemagg@yahoo.com
13 // http://www.antigrain.com
14 //----------------------------------------------------------------------------
16 #ifndef AGG_SCANLINE_BOOLEAN_ALGEBRA_INCLUDED
17 #define AGG_SCANLINE_BOOLEAN_ALGEBRA_INCLUDED
21 #include "agg_basics.h"
27 //-----------------------------------------------sbool_combine_spans_bin
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.
33 template<class Scanline1
,
36 struct sbool_combine_spans_bin
38 void operator () (const typename
Scanline1::const_iterator
&,
39 const typename
Scanline2::const_iterator
&,
43 sl
.add_span(x
, len
, cover_full
);
49 //---------------------------------------------sbool_combine_spans_empty
51 // Combine two spans as empty ones. The functor does nothing
52 // and is used to XOR binary spans.
54 template<class Scanline1
,
57 struct sbool_combine_spans_empty
59 void operator () (const typename
Scanline1::const_iterator
&,
60 const typename
Scanline2::const_iterator
&,
68 //--------------------------------------------------sbool_add_span_empty
70 // Add nothing. Used in conbine_shapes_sub
72 template<class Scanline1
,
74 struct sbool_add_span_empty
76 void operator () (const typename
Scanline1::const_iterator
&,
83 //----------------------------------------------------sbool_add_span_bin
87 template<class Scanline1
,
89 struct sbool_add_span_bin
91 void operator () (const typename
Scanline1::const_iterator
&,
95 sl
.add_span(x
, len
, cover_full
);
102 //-----------------------------------------------------sbool_add_span_aa
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.
108 template<class Scanline1
,
110 struct sbool_add_span_aa
112 void operator () (const typename
Scanline1::const_iterator
& span
,
118 sl
.add_span(x
, len
, *span
->covers
);
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
);
133 //----------------------------------------------sbool_intersect_spans_aa
135 // Intersect two spans preserving the anti-aliasing information.
136 // The result is added to the "sl" scanline.
138 template<class Scanline1
,
141 unsigned CoverShift
= cover_shift
>
142 struct sbool_intersect_spans_aa
146 cover_shift
= CoverShift
,
147 cover_size
= 1 << cover_shift
,
148 cover_mask
= cover_size
- 1,
149 cover_full
= cover_mask
153 void operator () (const typename
Scanline1::const_iterator
& span1
,
154 const typename
Scanline2::const_iterator
& span2
,
159 const typename
Scanline1::cover_type
* covers1
;
160 const typename
Scanline2::cover_type
* covers2
;
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
169 switch((span1
->len
< 0) | ((span2
->len
< 0) << 1))
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
;
178 cover
= *covers1
++ * *covers2
++;
180 (cover
== cover_full
* cover_full
) ?
182 (cover
>> cover_shift
));
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
)
192 sl
.add_cells(x
, len
, covers2
);
198 cover
= *(span1
->covers
) * *covers2
++;
200 (cover
== cover_full
* cover_full
) ?
202 (cover
>> cover_shift
));
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
)
213 sl
.add_cells(x
, len
, covers1
);
219 cover
= *covers1
++ * *(span2
->covers
);
221 (cover
== cover_full
* cover_full
) ?
223 (cover
>> cover_shift
));
229 case 3: // Both are solid spans
230 cover
= *(span1
->covers
) * *(span2
->covers
);
232 (cover
== cover_full
* cover_full
) ?
234 (cover
>> cover_shift
));
245 //--------------------------------------------------sbool_unite_spans_aa
247 // Unite two spans preserving the anti-aliasing information.
248 // The result is added to the "sl" scanline.
250 template<class Scanline1
,
253 unsigned CoverShift
= cover_shift
>
254 struct sbool_unite_spans_aa
258 cover_shift
= CoverShift
,
259 cover_size
= 1 << cover_shift
,
260 cover_mask
= cover_size
- 1,
261 cover_full
= cover_mask
265 void operator () (const typename
Scanline1::const_iterator
& span1
,
266 const typename
Scanline2::const_iterator
& span2
,
271 const typename
Scanline1::cover_type
* covers1
;
272 const typename
Scanline2::cover_type
* covers2
;
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
281 switch((span1
->len
< 0) | ((span2
->len
< 0) << 1))
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
;
290 cover
= cover_mask
* cover_mask
-
291 (cover_mask
- *covers1
++) *
292 (cover_mask
- *covers2
++);
294 (cover
== cover_full
* cover_full
) ?
296 (cover
>> cover_shift
));
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
)
306 sl
.add_span(x
, len
, cover_full
);
312 cover
= cover_mask
* cover_mask
-
313 (cover_mask
- *(span1
->covers
)) *
314 (cover_mask
- *covers2
++);
316 (cover
== cover_full
* cover_full
) ?
318 (cover
>> cover_shift
));
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
)
329 sl
.add_span(x
, len
, cover_full
);
335 cover
= cover_mask
* cover_mask
-
336 (cover_mask
- *covers1
++) *
337 (cover_mask
- *(span2
->covers
));
339 (cover
== cover_full
* cover_full
) ?
341 (cover
>> cover_shift
));
347 case 3: // Both are solid spans
348 cover
= cover_mask
* cover_mask
-
349 (cover_mask
- *(span1
->covers
)) *
350 (cover_mask
- *(span2
->covers
));
352 (cover
== cover_full
* cover_full
) ?
354 (cover
>> cover_shift
));
361 //---------------------------------------------sbool_xor_formula_linear
362 template<unsigned CoverShift
= cover_shift
>
363 struct sbool_xor_formula_linear
367 cover_shift
= CoverShift
,
368 cover_size
= 1 << cover_shift
,
369 cover_mask
= cover_size
- 1
372 static AGG_INLINE
unsigned calculate(unsigned a
, unsigned b
)
374 unsigned cover
= a
+ b
;
375 if(cover
> cover_mask
) cover
= cover_mask
+ cover_mask
- cover
;
381 //---------------------------------------------sbool_xor_formula_saddle
382 template<unsigned CoverShift
= cover_shift
>
383 struct sbool_xor_formula_saddle
387 cover_shift
= CoverShift
,
388 cover_size
= 1 << cover_shift
,
389 cover_mask
= cover_size
- 1
392 static AGG_INLINE
unsigned calculate(unsigned a
, unsigned b
)
395 if(k
== cover_mask
* cover_mask
) return 0;
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
);
404 //-------------------------------------------sbool_xor_formula_abs_diff
405 struct sbool_xor_formula_abs_diff
407 static AGG_INLINE
unsigned calculate(unsigned a
, unsigned b
)
409 return unsigned(abs(int(a
) - int(b
)));
415 //----------------------------------------------------sbool_xor_spans_aa
417 // XOR two spans preserving the anti-aliasing information.
418 // The result is added to the "sl" scanline.
420 template<class Scanline1
,
424 unsigned CoverShift
= cover_shift
>
425 struct sbool_xor_spans_aa
429 cover_shift
= CoverShift
,
430 cover_size
= 1 << cover_shift
,
431 cover_mask
= cover_size
- 1,
432 cover_full
= cover_mask
436 void operator () (const typename
Scanline1::const_iterator
& span1
,
437 const typename
Scanline2::const_iterator
& span2
,
442 const typename
Scanline1::cover_type
* covers1
;
443 const typename
Scanline2::cover_type
* covers2
;
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
452 switch((span1
->len
< 0) | ((span2
->len
< 0) << 1))
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
;
461 cover
= XorFormula::calculate(*covers1
++, *covers2
++);
462 if(cover
) sl
.add_cell(x
, cover
);
468 case 1: // span1 is solid, span2 is AA
469 covers2
= span2
->covers
;
470 if(span2
->x
< x
) covers2
+= x
- span2
->x
;
473 cover
= XorFormula::calculate(*(span1
->covers
), *covers2
++);
474 if(cover
) sl
.add_cell(x
, cover
);
480 case 2: // span1 is AA, span2 is solid
481 covers1
= span1
->covers
;
482 if(span1
->x
< x
) covers1
+= x
- span1
->x
;
485 cover
= XorFormula::calculate(*covers1
++, *(span2
->covers
));
486 if(cover
) sl
.add_cell(x
, cover
);
492 case 3: // Both are solid spans
493 cover
= XorFormula::calculate(*(span1
->covers
), *(span2
->covers
));
494 if(cover
) sl
.add_span(x
, len
, cover
);
505 //-----------------------------------------------sbool_subtract_spans_aa
507 // Unite two spans preserving the anti-aliasing information.
508 // The result is added to the "sl" scanline.
510 template<class Scanline1
,
513 unsigned CoverShift
= cover_shift
>
514 struct sbool_subtract_spans_aa
518 cover_shift
= CoverShift
,
519 cover_size
= 1 << cover_shift
,
520 cover_mask
= cover_size
- 1,
521 cover_full
= cover_mask
525 void operator () (const typename
Scanline1::const_iterator
& span1
,
526 const typename
Scanline2::const_iterator
& span2
,
531 const typename
Scanline1::cover_type
* covers1
;
532 const typename
Scanline2::cover_type
* covers2
;
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
541 switch((span1
->len
< 0) | ((span2
->len
< 0) << 1))
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
;
550 cover
= *covers1
++ * (cover_mask
- *covers2
++);
554 (cover
== cover_full
* cover_full
) ?
556 (cover
>> cover_shift
));
563 case 1: // span1 is solid, span2 is AA
564 covers2
= span2
->covers
;
565 if(span2
->x
< x
) covers2
+= x
- span2
->x
;
568 cover
= *(span1
->covers
) * (cover_mask
- *covers2
++);
572 (cover
== cover_full
* cover_full
) ?
574 (cover
>> cover_shift
));
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
)
588 cover
= *covers1
++ * (cover_mask
- *(span2
->covers
));
592 (cover
== cover_full
* cover_full
) ?
594 (cover
>> cover_shift
));
602 case 3: // Both are solid spans
603 cover
= *(span1
->covers
) * (cover_mask
- *(span2
->covers
));
607 (cover
== cover_full
* cover_full
) ?
609 (cover
>> cover_shift
));
621 //--------------------------------------------sbool_add_spans_and_render
622 template<class Scanline1
,
625 class AddSpanFunctor
>
626 void sbool_add_spans_and_render(const Scanline1
& sl1
,
629 AddSpanFunctor add_span
)
632 typename
Scanline1::const_iterator span
= sl1
.begin();
633 unsigned num_spans
= sl1
.num_spans();
636 add_span(span
, span
->x
, abs((int)span
->len
), sl
);
637 if(--num_spans
== 0) break;
640 sl
.finalize(sl1
.y());
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
657 template<class Scanline1
,
660 class CombineSpansFunctor
>
661 void sbool_intersect_scanlines(const Scanline1
& sl1
,
662 const Scanline2
& sl2
,
664 CombineSpansFunctor combine_spans
)
668 unsigned num1
= sl1
.num_spans();
669 if(num1
== 0) return;
671 unsigned num2
= sl2
.num_spans();
672 if(num2
== 0) return;
674 typename
Scanline1::const_iterator span1
= sl1
.begin();
675 typename
Scanline2::const_iterator span2
= sl2
.begin();
681 int xe1
= xb1
+ abs((int)span1
->len
) - 1;
682 int xe2
= xb2
+ abs((int)span2
->len
) - 1;
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
689 bool advance_span1
= xe1
< xe2
;
690 bool advance_both
= xe1
== xe2
;
692 // Find the intersection of the spans
693 // and check if they intersect
695 if(xb1
< xb2
) xb1
= xb2
;
696 if(xe1
> xe2
) xe1
= xe2
;
699 combine_spans(span1
, span2
, xb1
, xe1
- xb1
+ 1, sl
);
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
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.
747 template<class ScanlineGen1
,
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
)
759 // Prepare the scanline generators.
760 // If anyone of them doesn't contain
761 // any scanlines, then return.
763 if(!sg1
.rewind_scanlines()) return;
764 if(!sg2
.rewind_scanlines()) return;
766 // Get the bounding boxes
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());
771 // Calculate the intersection of the bounding
772 // boxes and return if they don't intersect.
774 rect_i ir
= intersect_rectangles(r1
, r2
);
775 if(!ir
.is_valid()) return;
777 // Reset the scanlines and get two first ones
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;
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.
795 while(sl1
.y() < sl2
.y())
797 if(!sg1
.sweep_scanline(sl1
)) return;
799 while(sl2
.y() < sl1
.y())
801 if(!sg2
.sweep_scanline(sl2
)) return;
804 if(sl1
.y() == sl2
.y())
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
);
813 sl
.finalize(sl1
.y());
816 if(!sg1
.sweep_scanline(sl1
)) return;
817 if(!sg2
.sweep_scanline(sl2
)) return;
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
835 template<class Scanline1
,
838 class AddSpanFunctor1
,
839 class AddSpanFunctor2
,
840 class CombineSpansFunctor
>
841 void sbool_unite_scanlines(const Scanline1
& sl1
,
842 const Scanline2
& sl2
,
844 AddSpanFunctor1 add_span1
,
845 AddSpanFunctor2 add_span2
,
846 CombineSpansFunctor combine_spans
)
850 unsigned num1
= sl1
.num_spans();
851 unsigned num2
= sl2
.num_spans();
853 typename
Scanline1::const_iterator span1
;// = sl1.begin();
854 typename
Scanline2::const_iterator span2
;// = sl2.begin();
858 invalid_b
= 0xFFFFFFF,
859 invalid_e
= invalid_b
- 1
862 // Initialize the spans as invalid
869 // Initialize span1 if there are spans
875 xe1
= xb1
+ abs((int)span1
->len
) - 1;
879 // Initialize span2 if there are spans
885 xe2
= xb2
+ abs((int)span2
->len
) - 1;
892 // Retrieve a new span1 if it's invalid
894 if(num1
&& xb1
> xe1
)
899 xe1
= xb1
+ abs((int)span1
->len
) - 1;
902 // Retrieve a new span2 if it's invalid
904 if(num2
&& xb2
> xe2
)
909 xe2
= xb2
+ abs((int)span2
->len
) - 1;
912 if(xb1
> xe1
&& xb2
> xe2
) break;
914 // Calculate the intersection
918 if(xb
< xb2
) xb
= xb2
;
919 if(xe
> xe2
) xe
= xe2
;
920 int len
= xe
- xb
+ 1; // The length of the intersection
923 // The spans intersect,
924 // add the beginning of the span
928 add_span1(span1
, xb1
, xb2
- xb1
, sl
);
934 add_span2(span2
, xb2
, xb1
- xb2
, sl
);
938 // Add the combination part of the spans
940 combine_spans(span1
, span2
, xb
, len
, sl
);
943 // Invalidate the fully processed span or both
947 // Invalidate span1 and eat
948 // the processed part of span2
957 // Invalidate span2 and eat
958 // the processed part of span1
966 xb1
= invalid_b
; // Invalidate both
974 // The spans do not intersect
982 add_span1(span1
, xb1
, xe1
- xb1
+ 1, sl
);
984 xb1
= invalid_b
; // Invalidate
993 add_span2(span2
, xb2
, xe2
- xb2
+ 1, sl
);
995 xb2
= invalid_b
; // Invalidate
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.
1018 template<class ScanlineGen1
,
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
)
1034 // Prepare the scanline generators.
1035 // If anyone of them doesn't contain
1036 // any scanlines, then return.
1038 bool flag1
= sg1
.rewind_scanlines();
1039 bool flag2
= sg2
.rewind_scanlines();
1040 if(!flag1
&& !flag2
) return;
1042 // Get the bounding boxes
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());
1047 // Calculate the union of the bounding boxes
1050 if(flag1
&& flag2
) ur
= unite_rectangles(r1
, r2
);
1051 else if(flag1
) ur
= r1
;
1052 else if(flag2
) ur
= r2
;
1054 if(!ur
.is_valid()) return;
1058 // Reset the scanlines and get two first ones
1060 sl
.reset(ur
.x1
, ur
.x2
);
1063 sl1
.reset(sg1
.min_x(), sg1
.max_x());
1064 flag1
= sg1
.sweep_scanline(sl1
);
1069 sl2
.reset(sg2
.min_x(), sg2
.max_x());
1070 flag2
= sg2
.sweep_scanline(sl2
);
1074 // Here we synchronize the scanlines with
1075 // the same Y coordinate.
1077 while(flag1
|| flag2
)
1081 if(sl1
.y() == sl2
.y())
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
);
1091 sl
.finalize(sl1
.y());
1094 flag1
= sg1
.sweep_scanline(sl1
);
1095 flag2
= sg2
.sweep_scanline(sl2
);
1099 if(sl1
.y() < sl2
.y())
1101 sbool_add_spans_and_render(sl1
, sl
, ren
, add_span1
);
1102 flag1
= sg1
.sweep_scanline(sl1
);
1106 sbool_add_spans_and_render(sl2
, sl
, ren
, add_span2
);
1107 flag2
= sg2
.sweep_scanline(sl2
);
1115 sbool_add_spans_and_render(sl1
, sl
, ren
, add_span1
);
1116 flag1
= sg1
.sweep_scanline(sl1
);
1120 sbool_add_spans_and_render(sl2
, sl
, ren
, add_span2
);
1121 flag2
= sg2
.sweep_scanline(sl2
);
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
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.
1147 template<class ScanlineGen1
,
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
)
1161 // Prepare the scanline generators.
1162 // Here "sg1" is master, "sg2" is slave.
1164 if(!sg1
.rewind_scanlines()) return;
1165 bool flag2
= sg2
.rewind_scanlines();
1167 // Get the bounding box
1169 rect_i
r1(sg1
.min_x(), sg1
.min_y(), sg1
.max_x(), sg1
.max_y());
1171 // Reset the scanlines and get two first ones
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;
1178 if(flag2
) flag2
= sg2
.sweep_scanline(sl2
);
1182 // A fake span2 processor
1183 sbool_add_span_empty
<Scanline2
, Scanline
> add_span2
;
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.
1194 // Synchronize "slave" with "master"
1196 while(flag2
&& sl2
.y() < sl1
.y())
1198 flag2
= sg2
.sweep_scanline(sl2
);
1202 if(flag2
&& sl2
.y() == sl1
.y())
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
);
1210 sl
.finalize(sl1
.y());
1216 sbool_add_spans_and_render(sl1
, sl
, ren
, add_span1
);
1219 // Advance the "master"
1220 flag1
= sg1
.sweep_scanline(sl1
);
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.
1242 template<class ScanlineGen1
,
1248 void sbool_intersect_shapes_aa(ScanlineGen1
& sg1
, ScanlineGen2
& sg2
,
1249 Scanline1
& sl1
, Scanline2
& sl2
,
1250 Scanline
& sl
, Renderer
& ren
)
1252 sbool_intersect_spans_aa
<Scanline1
, Scanline2
, Scanline
> combine_functor
;
1253 sbool_intersect_shapes(sg1
, sg2
, sl1
, sl2
, sl
, ren
, combine_functor
);
1260 //--------------------------------------------sbool_intersect_shapes_bin
1261 // Intersect two binary scanline shapes (without anti-aliasing).
1262 // See intersect_shapes_aa for more comments
1264 template<class ScanlineGen1
,
1270 void sbool_intersect_shapes_bin(ScanlineGen1
& sg1
, ScanlineGen2
& sg2
,
1271 Scanline1
& sl1
, Scanline2
& sl2
,
1272 Scanline
& sl
, Renderer
& ren
)
1274 sbool_combine_spans_bin
<Scanline1
, Scanline2
, Scanline
> combine_functor
;
1275 sbool_intersect_shapes(sg1
, sg2
, sl1
, sl2
, sl
, ren
, combine_functor
);
1282 //-------------------------------------------------sbool_unite_shapes_aa
1283 // Unite two anti-aliased scanline shapes
1284 // See intersect_shapes_aa for more comments
1286 template<class ScanlineGen1
,
1292 void sbool_unite_shapes_aa(ScanlineGen1
& sg1
, ScanlineGen2
& sg2
,
1293 Scanline1
& sl1
, Scanline2
& sl2
,
1294 Scanline
& sl
, Renderer
& ren
)
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
);
1307 //------------------------------------------------sbool_unite_shapes_bin
1308 // Unite two binary scanline shapes (without anti-aliasing).
1309 // See intersect_shapes_aa for more comments
1311 template<class ScanlineGen1
,
1317 void sbool_unite_shapes_bin(ScanlineGen1
& sg1
, ScanlineGen2
& sg2
,
1318 Scanline1
& sl1
, Scanline2
& sl2
,
1319 Scanline
& sl
, Renderer
& ren
)
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
);
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
1343 template<class ScanlineGen1
,
1349 void sbool_xor_shapes_aa(ScanlineGen1
& sg1
, ScanlineGen2
& sg2
,
1350 Scanline1
& sl1
, Scanline2
& sl2
,
1351 Scanline
& sl
, Renderer
& ren
)
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
);
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
1370 template<class ScanlineGen1
,
1376 void sbool_xor_shapes_saddle_aa(ScanlineGen1
& sg1
, ScanlineGen2
& sg2
,
1377 Scanline1
& sl1
, Scanline2
& sl2
,
1378 Scanline
& sl
, Renderer
& ren
)
1380 sbool_add_span_aa
<Scanline1
, Scanline
> add_functor1
;
1381 sbool_add_span_aa
<Scanline2
, Scanline
> add_functor2
;
1382 sbool_xor_spans_aa
<Scanline1
,
1385 sbool_xor_formula_saddle
<> > combine_functor
;
1386 sbool_unite_shapes(sg1
, sg2
, sl1
, sl2
, sl
, ren
,
1387 add_functor1
, add_functor2
, combine_functor
);
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
1398 template<class ScanlineGen1
,
1404 void sbool_xor_shapes_abs_diff_aa(ScanlineGen1
& sg1
, ScanlineGen2
& sg2
,
1405 Scanline1
& sl1
, Scanline2
& sl2
,
1406 Scanline
& sl
, Renderer
& ren
)
1408 sbool_add_span_aa
<Scanline1
, Scanline
> add_functor1
;
1409 sbool_add_span_aa
<Scanline2
, Scanline
> add_functor2
;
1410 sbool_xor_spans_aa
<Scanline1
,
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
);
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
1424 template<class ScanlineGen1
,
1430 void sbool_xor_shapes_bin(ScanlineGen1
& sg1
, ScanlineGen2
& sg2
,
1431 Scanline1
& sl1
, Scanline2
& sl2
,
1432 Scanline
& sl
, Renderer
& ren
)
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
);
1446 //----------------------------------------------sbool_subtract_shapes_aa
1447 // Subtract shapes "sg1-sg2" with anti-aliasing
1448 // See intersect_shapes_aa for more comments
1450 template<class ScanlineGen1
,
1456 void sbool_subtract_shapes_aa(ScanlineGen1
& sg1
, ScanlineGen2
& sg2
,
1457 Scanline1
& sl1
, Scanline2
& sl2
,
1458 Scanline
& sl
, Renderer
& ren
)
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
);
1470 //---------------------------------------------sbool_subtract_shapes_bin
1471 // Subtract binary shapes "sg1-sg2" without anti-aliasing
1472 // See intersect_shapes_aa for more comments
1474 template<class ScanlineGen1
,
1480 void sbool_subtract_shapes_bin(ScanlineGen1
& sg1
, ScanlineGen2
& sg2
,
1481 Scanline1
& sl1
, Scanline2
& sl2
,
1482 Scanline
& sl
, Renderer
& ren
)
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
);
1495 //------------------------------------------------------------sbool_op_e
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
1512 //----------------------------------------------sbool_combine_shapes_bin
1513 template<class ScanlineGen1
,
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
)
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;
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;
1539 //-----------------------------------------------sbool_combine_shapes_aa
1540 template<class ScanlineGen1
,
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
)
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;