1 //----------------------------------------------------------------------------
2 // Anti-Grain Geometry - Version 2.3
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
Scanline::const_iterator span
= sl1
.begin();
633 unsigned num_spans
= sl1
.num_spans();
636 add_span(span
, span
->x
, abs((int)span
->len
), sl
);
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
Scanline::const_iterator span1
= sl1
.begin();
675 typename
Scanline::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
r1(sg1
.min_x(), sg1
.min_y(), sg1
.max_x(), sg1
.max_y());
769 rect
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 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;
785 ren
.prepare(unsigned(ir
.x2
- ir
.x1
+ 2));
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
Scanline::const_iterator span1
;
854 typename
Scanline::const_iterator span2
;
856 enum { invalid_b
= 0xFFFFFFF, invalid_e
= invalid_b
- 1 };
858 // Initialize the spans as invalid
865 // Initialize span1 if there are spans
871 xe1
= xb1
+ abs((int)span1
->len
) - 1;
875 // Initialize span2 if there are spans
881 xe2
= xb2
+ abs((int)span2
->len
) - 1;
888 // Retrieve a new span1 if it's invalid
890 if(num1
&& xb1
> xe1
)
895 xe1
= xb1
+ abs((int)span1
->len
) - 1;
898 // Retrieve a new span2 if it's invalid
900 if(num2
&& xb2
> xe2
)
905 xe2
= xb2
+ abs((int)span2
->len
) - 1;
908 if(xb1
> xe1
&& xb2
> xe2
) break;
910 // Calculate the intersection
914 if(xb
< xb2
) xb
= xb2
;
915 if(xe
> xe2
) xe
= xe2
;
916 int len
= xe
- xb
+ 1; // The length of the intersection
919 // The spans intersect,
920 // add the beginning of the span
924 add_span1(span1
, xb1
, xb2
- xb1
, sl
);
930 add_span2(span2
, xb2
, xb1
- xb2
, sl
);
934 // Add the combination part of the spans
936 combine_spans(span1
, span2
, xb
, len
, sl
);
939 // Invalidate the fully processed span or both
943 // Invalidate span1 and eat
944 // the processed part of span2
953 // Invalidate span2 and eat
954 // the processed part of span1
962 xb1
= invalid_b
; // Invalidate both
970 // The spans do not intersect
978 add_span1(span1
, xb1
, xe1
- xb1
+ 1, sl
);
980 xb1
= invalid_b
; // Invalidate
989 add_span2(span2
, xb2
, xe2
- xb2
+ 1, sl
);
991 xb2
= invalid_b
; // Invalidate
1001 //----------------------------------------------------sbool_unite_shapes
1002 // Unite the scanline shapes. Here the "Scanline Generator"
1003 // abstraction is used. ScanlineGen1 and ScanlineGen2 are
1004 // the generators, and can be of type rasterizer_scanline_aa<>.
1005 // There function requires three scanline containers that can be
1006 // of different type.
1007 // "sl1" and "sl2" are used to retrieve scanlines from the generators,
1008 // "sl" is ised as the resulting scanline to render it.
1009 // The external "sl1" and "sl2" are used only for the sake of
1010 // optimization and reusing of the scanline objects.
1011 // the function calls sbool_unite_scanlines with CombineSpansFunctor
1012 // as the last argument. See sbool_unite_scanlines for details.
1014 template<class ScanlineGen1
,
1020 class AddSpanFunctor1
,
1021 class AddSpanFunctor2
,
1022 class CombineSpansFunctor
>
1023 void sbool_unite_shapes(ScanlineGen1
& sg1
, ScanlineGen2
& sg2
,
1024 Scanline1
& sl1
, Scanline2
& sl2
,
1025 Scanline
& sl
, Renderer
& ren
,
1026 AddSpanFunctor1 add_span1
,
1027 AddSpanFunctor2 add_span2
,
1028 CombineSpansFunctor combine_spans
)
1030 // Prepare the scanline generators.
1031 // If anyone of them doesn't contain
1032 // any scanlines, then return.
1034 bool flag1
= sg1
.rewind_scanlines();
1035 bool flag2
= sg2
.rewind_scanlines();
1036 if(!flag1
&& !flag2
) return;
1038 // Get the bounding boxes
1040 rect
r1(sg1
.min_x(), sg1
.min_y(), sg1
.max_x(), sg1
.max_y());
1041 rect
r2(sg2
.min_x(), sg2
.min_y(), sg2
.max_x(), sg2
.max_y());
1043 // Calculate the union of the bounding boxes
1045 rect ur
= unite_rectangles(r1
, r2
);
1046 if(!ur
.is_valid()) return;
1048 ren
.prepare(unsigned(ur
.x2
- ur
.x2
+ 2));
1050 // Reset the scanlines and get two first ones
1052 sl
.reset(ur
.x1
, ur
.x2
);
1055 sl1
.reset(sg1
.min_x(), sg1
.max_x());
1056 flag1
= sg1
.sweep_scanline(sl1
);
1061 sl2
.reset(sg2
.min_x(), sg2
.max_x());
1062 flag2
= sg2
.sweep_scanline(sl2
);
1066 // Here we synchronize the scanlines with
1067 // the same Y coordinate.
1069 while(flag1
|| flag2
)
1073 if(sl1
.y() == sl2
.y())
1075 // The Y coordinates are the same.
1076 // Combine the scanlines, render if they contain any spans,
1077 // and advance both generators to the next scanlines
1078 //----------------------
1079 sbool_unite_scanlines(sl1
, sl2
, sl
,
1080 add_span1
, add_span2
, combine_spans
);
1083 sl
.finalize(sl1
.y());
1086 flag1
= sg1
.sweep_scanline(sl1
);
1087 flag2
= sg2
.sweep_scanline(sl2
);
1091 if(sl1
.y() < sl2
.y())
1093 sbool_add_spans_and_render(sl1
, sl
, ren
, add_span1
);
1094 flag1
= sg1
.sweep_scanline(sl1
);
1098 sbool_add_spans_and_render(sl2
, sl
, ren
, add_span2
);
1099 flag2
= sg2
.sweep_scanline(sl2
);
1107 sbool_add_spans_and_render(sl1
, sl
, ren
, add_span1
);
1108 flag1
= sg1
.sweep_scanline(sl1
);
1112 sbool_add_spans_and_render(sl2
, sl
, ren
, add_span2
);
1113 flag2
= sg2
.sweep_scanline(sl2
);
1126 //-------------------------------------------------sbool_subtract_shapes
1127 // Subtract the scanline shapes, "sg1-sg2". Here the "Scanline Generator"
1128 // abstraction is used. ScanlineGen1 and ScanlineGen2 are
1129 // the generators, and can be of type rasterizer_scanline_aa<>.
1130 // There function requires three scanline containers that can be of
1132 // "sl1" and "sl2" are used to retrieve scanlines from the generators,
1133 // "sl" is ised as the resulting scanline to render it.
1134 // The external "sl1" and "sl2" are used only for the sake of
1135 // optimization and reusing of the scanline objects.
1136 // the function calls sbool_intersect_scanlines with CombineSpansFunctor
1137 // as the last argument. See combine_scanlines_sub for details.
1139 template<class ScanlineGen1
,
1145 class AddSpanFunctor1
,
1146 class CombineSpansFunctor
>
1147 void sbool_subtract_shapes(ScanlineGen1
& sg1
, ScanlineGen2
& sg2
,
1148 Scanline1
& sl1
, Scanline2
& sl2
,
1149 Scanline
& sl
, Renderer
& ren
,
1150 AddSpanFunctor1 add_span1
,
1151 CombineSpansFunctor combine_spans
)
1153 // Prepare the scanline generators.
1154 // Here "sg1" is master, "sg2" is slave.
1156 if(!sg1
.rewind_scanlines()) return;
1157 bool flag2
= sg2
.rewind_scanlines();
1159 // Get the bounding box
1161 rect
r1(sg1
.min_x(), sg1
.min_y(), sg1
.max_x(), sg1
.max_y());
1163 // Reset the scanlines and get two first ones
1165 sl
.reset(sg1
.min_x(), sg1
.max_x());
1166 sl1
.reset(sg1
.min_x(), sg1
.max_x());
1167 sl2
.reset(sg2
.min_x(), sg2
.max_x());
1168 if(!sg1
.sweep_scanline(sl1
)) return;
1170 if(flag2
) flag2
= sg2
.sweep_scanline(sl2
);
1172 ren
.prepare(unsigned(sg1
.max_x() - sg1
.min_x() + 2));
1174 // A fake span2 processor
1175 sbool_add_span_empty
<Scanline1
, Scanline
> add_span2
;
1178 // Here we synchronize the scanlines with
1179 // the same Y coordinate, ignoring all other ones.
1180 // Only scanlines having the same Y-coordinate
1181 // are to be combined.
1186 // Synchronize "slave" with "master"
1188 while(flag2
&& sl2
.y() < sl1
.y())
1190 flag2
= sg2
.sweep_scanline(sl2
);
1194 if(flag2
&& sl2
.y() == sl1
.y())
1196 // The Y coordinates are the same.
1197 // Combine the scanlines and render if they contain any spans.
1198 //----------------------
1199 sbool_unite_scanlines(sl1
, sl2
, sl
, add_span1
, add_span2
, combine_spans
);
1202 sl
.finalize(sl1
.y());
1208 sbool_add_spans_and_render(sl1
, sl
, ren
, add_span1
);
1211 // Advance the "master"
1212 flag1
= sg1
.sweep_scanline(sl1
);
1223 //---------------------------------------------sbool_intersect_shapes_aa
1224 // Intersect two anti-aliased scanline shapes.
1225 // Here the "Scanline Generator" abstraction is used.
1226 // ScanlineGen1 and ScanlineGen2 are the generators, and can be of
1227 // type rasterizer_scanline_aa<>. There function requires three
1228 // scanline containers that can be of different types.
1229 // "sl1" and "sl2" are used to retrieve scanlines from the generators,
1230 // "sl" is ised as the resulting scanline to render it.
1231 // The external "sl1" and "sl2" are used only for the sake of
1232 // optimization and reusing of the scanline objects.
1234 template<class ScanlineGen1
,
1240 void sbool_intersect_shapes_aa(ScanlineGen1
& sg1
, ScanlineGen2
& sg2
,
1241 Scanline1
& sl1
, Scanline2
& sl2
,
1242 Scanline
& sl
, Renderer
& ren
)
1244 sbool_intersect_spans_aa
<Scanline1
, Scanline2
, Scanline
> combine_functor
;
1245 sbool_intersect_shapes(sg1
, sg2
, sl1
, sl2
, sl
, ren
, combine_functor
);
1252 //--------------------------------------------sbool_intersect_shapes_bin
1253 // Intersect two binary scanline shapes (without anti-aliasing).
1254 // See intersect_shapes_aa for more comments
1256 template<class ScanlineGen1
,
1262 void sbool_intersect_shapes_bin(ScanlineGen1
& sg1
, ScanlineGen2
& sg2
,
1263 Scanline1
& sl1
, Scanline2
& sl2
,
1264 Scanline
& sl
, Renderer
& ren
)
1266 sbool_combine_spans_bin
<Scanline1
, Scanline2
, Scanline
> combine_functor
;
1267 sbool_intersect_shapes(sg1
, sg2
, sl1
, sl2
, sl
, ren
, combine_functor
);
1274 //-------------------------------------------------sbool_unite_shapes_aa
1275 // Unite two anti-aliased scanline shapes
1276 // See intersect_shapes_aa for more comments
1278 template<class ScanlineGen1
,
1284 void sbool_unite_shapes_aa(ScanlineGen1
& sg1
, ScanlineGen2
& sg2
,
1285 Scanline1
& sl1
, Scanline2
& sl2
,
1286 Scanline
& sl
, Renderer
& ren
)
1288 sbool_add_span_aa
<Scanline1
, Scanline
> add_functor1
;
1289 sbool_add_span_aa
<Scanline2
, Scanline
> add_functor2
;
1290 sbool_unite_spans_aa
<Scanline1
, Scanline2
, Scanline
> combine_functor
;
1291 sbool_unite_shapes(sg1
, sg2
, sl1
, sl2
, sl
, ren
,
1292 add_functor1
, add_functor2
, combine_functor
);
1299 //------------------------------------------------sbool_unite_shapes_bin
1300 // Unite two binary scanline shapes (without anti-aliasing).
1301 // See intersect_shapes_aa for more comments
1303 template<class ScanlineGen1
,
1309 void sbool_unite_shapes_bin(ScanlineGen1
& sg1
, ScanlineGen2
& sg2
,
1310 Scanline1
& sl1
, Scanline2
& sl2
,
1311 Scanline
& sl
, Renderer
& ren
)
1313 sbool_add_span_bin
<Scanline1
, Scanline
> add_functor1
;
1314 sbool_add_span_bin
<Scanline2
, Scanline
> add_functor2
;
1315 sbool_combine_spans_bin
<Scanline1
, Scanline2
, Scanline
> combine_functor
;
1316 sbool_unite_shapes(sg1
, sg2
, sl1
, sl2
, sl
, ren
,
1317 add_functor1
, add_functor2
, combine_functor
);
1328 //---------------------------------------------------sbool_xor_shapes_aa
1329 // Apply eXclusive OR to two anti-aliased scanline shapes. There's
1330 // a modified "Linear" XOR used instead of classical "Saddle" one.
1331 // The reason is to have the result absolutely conststent with what
1332 // the scanline rasterizer produces.
1333 // See intersect_shapes_aa for more comments
1335 template<class ScanlineGen1
,
1341 void sbool_xor_shapes_aa(ScanlineGen1
& sg1
, ScanlineGen2
& sg2
,
1342 Scanline1
& sl1
, Scanline2
& sl2
,
1343 Scanline
& sl
, Renderer
& ren
)
1345 sbool_add_span_aa
<Scanline1
, Scanline
> add_functor1
;
1346 sbool_add_span_aa
<Scanline2
, Scanline
> add_functor2
;
1347 sbool_xor_spans_aa
<Scanline1
, Scanline2
, Scanline
,
1348 sbool_xor_formula_linear
<> > combine_functor
;
1349 sbool_unite_shapes(sg1
, sg2
, sl1
, sl2
, sl
, ren
,
1350 add_functor1
, add_functor2
, combine_functor
);
1355 //------------------------------------------sbool_xor_shapes_saddle_aa
1356 // Apply eXclusive OR to two anti-aliased scanline shapes.
1357 // There's the classical "Saddle" used to calculate the
1358 // Anti-Aliasing values, that is:
1359 // a XOR b : 1-((1-a+a*b)*(1-b+a*b))
1360 // See intersect_shapes_aa for more comments
1362 template<class ScanlineGen1
,
1368 void sbool_xor_shapes_saddle_aa(ScanlineGen1
& sg1
, ScanlineGen2
& sg2
,
1369 Scanline1
& sl1
, Scanline2
& sl2
,
1370 Scanline
& sl
, Renderer
& ren
)
1372 sbool_add_span_aa
<Scanline1
, Scanline
> add_functor1
;
1373 sbool_add_span_aa
<Scanline2
, Scanline
> add_functor2
;
1374 sbool_xor_spans_aa
<Scanline1
,
1377 sbool_xor_formula_saddle
<> > combine_functor
;
1378 sbool_unite_shapes(sg1
, sg2
, sl1
, sl2
, sl
, ren
,
1379 add_functor1
, add_functor2
, combine_functor
);
1383 //--------------------------------------sbool_xor_shapes_abs_diff_aa
1384 // Apply eXclusive OR to two anti-aliased scanline shapes.
1385 // There's the absolute difference used to calculate
1386 // Anti-Aliasing values, that is:
1387 // a XOR b : abs(a-b)
1388 // See intersect_shapes_aa for more comments
1390 template<class ScanlineGen1
,
1396 void sbool_xor_shapes_abs_diff_aa(ScanlineGen1
& sg1
, ScanlineGen2
& sg2
,
1397 Scanline1
& sl1
, Scanline2
& sl2
,
1398 Scanline
& sl
, Renderer
& ren
)
1400 sbool_add_span_aa
<Scanline1
, Scanline
> add_functor1
;
1401 sbool_add_span_aa
<Scanline2
, Scanline
> add_functor2
;
1402 sbool_xor_spans_aa
<Scanline1
,
1405 sbool_xor_formula_abs_diff
> combine_functor
;
1406 sbool_unite_shapes(sg1
, sg2
, sl1
, sl2
, sl
, ren
,
1407 add_functor1
, add_functor2
, combine_functor
);
1412 //--------------------------------------------------sbool_xor_shapes_bin
1413 // Apply eXclusive OR to two binary scanline shapes (without anti-aliasing).
1414 // See intersect_shapes_aa for more comments
1416 template<class ScanlineGen1
,
1422 void sbool_xor_shapes_bin(ScanlineGen1
& sg1
, ScanlineGen2
& sg2
,
1423 Scanline1
& sl1
, Scanline2
& sl2
,
1424 Scanline
& sl
, Renderer
& ren
)
1426 sbool_add_span_bin
<Scanline1
, Scanline
> add_functor1
;
1427 sbool_add_span_bin
<Scanline2
, Scanline
> add_functor2
;
1428 sbool_combine_spans_empty
<Scanline1
, Scanline2
, Scanline
> combine_functor
;
1429 sbool_unite_shapes(sg1
, sg2
, sl1
, sl2
, sl
, ren
,
1430 add_functor1
, add_functor2
, combine_functor
);
1438 //----------------------------------------------sbool_subtract_shapes_aa
1439 // Subtract shapes "sg1-sg2" with anti-aliasing
1440 // See intersect_shapes_aa for more comments
1442 template<class ScanlineGen1
,
1448 void sbool_subtract_shapes_aa(ScanlineGen1
& sg1
, ScanlineGen2
& sg2
,
1449 Scanline1
& sl1
, Scanline2
& sl2
,
1450 Scanline
& sl
, Renderer
& ren
)
1452 sbool_add_span_aa
<Scanline1
, Scanline
> add_functor
;
1453 sbool_subtract_spans_aa
<Scanline1
, Scanline2
, Scanline
> combine_functor
;
1454 sbool_subtract_shapes(sg1
, sg2
, sl1
, sl2
, sl
, ren
,
1455 add_functor
, combine_functor
);
1462 //---------------------------------------------sbool_subtract_shapes_bin
1463 // Subtract binary shapes "sg1-sg2" without anti-aliasing
1464 // See intersect_shapes_aa for more comments
1466 template<class ScanlineGen1
,
1472 void sbool_subtract_shapes_bin(ScanlineGen1
& sg1
, ScanlineGen2
& sg2
,
1473 Scanline1
& sl1
, Scanline2
& sl2
,
1474 Scanline
& sl
, Renderer
& ren
)
1476 sbool_add_span_bin
<Scanline1
, Scanline
> add_functor
;
1477 sbool_combine_spans_empty
<Scanline1
, Scanline2
, Scanline
> combine_functor
;
1478 sbool_subtract_shapes(sg1
, sg2
, sl1
, sl2
, sl
, ren
,
1479 add_functor
, combine_functor
);
1487 //------------------------------------------------------------sbool_op_e
1490 sbool_or
, //----sbool_or
1491 sbool_and
, //----sbool_and
1492 sbool_xor
, //----sbool_xor
1493 sbool_xor_saddle
, //----sbool_xor_saddle
1494 sbool_xor_abs_diff
, //----sbool_xor_abs_diff
1495 sbool_a_minus_b
, //----sbool_a_minus_b
1496 sbool_b_minus_a
//----sbool_b_minus_a
1504 //----------------------------------------------sbool_combine_shapes_bin
1505 template<class ScanlineGen1
,
1511 void sbool_combine_shapes_bin(sbool_op_e op
,
1512 ScanlineGen1
& sg1
, ScanlineGen2
& sg2
,
1513 Scanline1
& sl1
, Scanline2
& sl2
,
1514 Scanline
& sl
, Renderer
& ren
)
1518 case sbool_or
: sbool_unite_shapes_bin (sg1
, sg2
, sl1
, sl2
, sl
, ren
); break;
1519 case sbool_and
: sbool_intersect_shapes_bin(sg1
, sg2
, sl1
, sl2
, sl
, ren
); break;
1521 case sbool_xor_saddle
:
1522 case sbool_xor_abs_diff
: sbool_xor_shapes_bin (sg1
, sg2
, sl1
, sl2
, sl
, ren
); break;
1523 case sbool_a_minus_b
: sbool_subtract_shapes_bin (sg1
, sg2
, sl1
, sl2
, sl
, ren
); break;
1524 case sbool_b_minus_a
: sbool_subtract_shapes_bin (sg2
, sg1
, sl2
, sl1
, sl
, ren
); break;
1531 //-----------------------------------------------sbool_combine_shapes_aa
1532 template<class ScanlineGen1
,
1538 void sbool_combine_shapes_aa(sbool_op_e op
,
1539 ScanlineGen1
& sg1
, ScanlineGen2
& sg2
,
1540 Scanline1
& sl1
, Scanline2
& sl2
,
1541 Scanline
& sl
, Renderer
& ren
)
1545 case sbool_or
: sbool_unite_shapes_aa (sg1
, sg2
, sl1
, sl2
, sl
, ren
); break;
1546 case sbool_and
: sbool_intersect_shapes_aa (sg1
, sg2
, sl1
, sl2
, sl
, ren
); break;
1547 case sbool_xor
: sbool_xor_shapes_aa (sg1
, sg2
, sl1
, sl2
, sl
, ren
); break;
1548 case sbool_xor_saddle
: sbool_xor_shapes_saddle_aa (sg1
, sg2
, sl1
, sl2
, sl
, ren
); break;
1549 case sbool_xor_abs_diff
: sbool_xor_shapes_abs_diff_aa(sg1
, sg2
, sl1
, sl2
, sl
, ren
); break;
1550 case sbool_a_minus_b
: sbool_subtract_shapes_aa (sg1
, sg2
, sl1
, sl2
, sl
, ren
); break;
1551 case sbool_b_minus_a
: sbool_subtract_shapes_aa (sg2
, sg1
, sl2
, sl1
, sl
, ren
); break;