update dev300-m58
[ooovba.git] / agg / inc / agg_scanline_boolean_algebra.h
blobc606fa2d0d52eeed24d74f123b82e4995baeecae
1 //----------------------------------------------------------------------------
2 // Anti-Grain Geometry - Version 2.3
3 // Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com)
4 //
5 // Permission to copy, use, modify, sell and distribute this software
6 // is granted provided this copyright notice appears in all copies.
7 // This software is provided "as is" without express or implied
8 // warranty, and with no claim as to its suitability for any purpose.
9 //
10 //----------------------------------------------------------------------------
11 // Contact: mcseem@antigrain.com
12 // mcseemagg@yahoo.com
13 // http://www.antigrain.com
14 //----------------------------------------------------------------------------
16 #ifndef AGG_SCANLINE_BOOLEAN_ALGEBRA_INCLUDED
17 #define AGG_SCANLINE_BOOLEAN_ALGEBRA_INCLUDED
19 #include <stdlib.h>
20 #include <math.h>
21 #include "agg_basics.h"
24 namespace agg
27 //-----------------------------------------------sbool_combine_spans_bin
28 // Functor.
29 // Combine two binary encoded spans, i.e., when we don't have any
30 // anti-aliasing information, but only X and Length. The function
31 // is compatible with any type of scanlines.
32 //----------------
33 template<class Scanline1,
34 class Scanline2,
35 class Scanline>
36 struct sbool_combine_spans_bin
38 void operator () (const typename Scanline1::const_iterator&,
39 const typename Scanline2::const_iterator&,
40 int x, unsigned len,
41 Scanline& sl) const
43 sl.add_span(x, len, cover_full);
49 //---------------------------------------------sbool_combine_spans_empty
50 // Functor.
51 // Combine two spans as empty ones. The functor does nothing
52 // and is used to XOR binary spans.
53 //----------------
54 template<class Scanline1,
55 class Scanline2,
56 class Scanline>
57 struct sbool_combine_spans_empty
59 void operator () (const typename Scanline1::const_iterator&,
60 const typename Scanline2::const_iterator&,
61 int, unsigned,
62 Scanline&) const
68 //--------------------------------------------------sbool_add_span_empty
69 // Functor.
70 // Add nothing. Used in conbine_shapes_sub
71 //----------------
72 template<class Scanline1,
73 class Scanline>
74 struct sbool_add_span_empty
76 void operator () (const typename Scanline1::const_iterator&,
77 int, unsigned,
78 Scanline&) const
83 //----------------------------------------------------sbool_add_span_bin
84 // Functor.
85 // Add a binary span
86 //----------------
87 template<class Scanline1,
88 class Scanline>
89 struct sbool_add_span_bin
91 void operator () (const typename Scanline1::const_iterator&,
92 int x, unsigned len,
93 Scanline& sl) const
95 sl.add_span(x, len, cover_full);
102 //-----------------------------------------------------sbool_add_span_aa
103 // Functor.
104 // Add an anti-aliased span
105 // anti-aliasing information, but only X and Length. The function
106 // is compatible with any type of scanlines.
107 //----------------
108 template<class Scanline1,
109 class Scanline>
110 struct sbool_add_span_aa
112 void operator () (const typename Scanline1::const_iterator& span,
113 int x, unsigned len,
114 Scanline& sl) const
116 if(span->len < 0)
118 sl.add_span(x, len, *span->covers);
120 else
121 if(span->len > 0)
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
134 // Functor.
135 // Intersect two spans preserving the anti-aliasing information.
136 // The result is added to the "sl" scanline.
137 //------------------
138 template<class Scanline1,
139 class Scanline2,
140 class Scanline,
141 unsigned CoverShift = cover_shift>
142 struct sbool_intersect_spans_aa
144 enum
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,
155 int x, unsigned len,
156 Scanline& sl) const
158 unsigned cover;
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
168 //-----------------
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++;
179 sl.add_cell(x++,
180 (cover == cover_full * cover_full) ?
181 cover_full :
182 (cover >> cover_shift));
184 while(--len);
185 break;
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);
194 else
198 cover = *(span1->covers) * *covers2++;
199 sl.add_cell(x++,
200 (cover == cover_full * cover_full) ?
201 cover_full :
202 (cover >> cover_shift));
204 while(--len);
206 break;
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);
215 else
219 cover = *covers1++ * *(span2->covers);
220 sl.add_cell(x++,
221 (cover == cover_full * cover_full) ?
222 cover_full :
223 (cover >> cover_shift));
225 while(--len);
227 break;
229 case 3: // Both are solid spans
230 cover = *(span1->covers) * *(span2->covers);
231 sl.add_span(x, len,
232 (cover == cover_full * cover_full) ?
233 cover_full :
234 (cover >> cover_shift));
235 break;
245 //--------------------------------------------------sbool_unite_spans_aa
246 // Functor.
247 // Unite two spans preserving the anti-aliasing information.
248 // The result is added to the "sl" scanline.
249 //------------------
250 template<class Scanline1,
251 class Scanline2,
252 class Scanline,
253 unsigned CoverShift = cover_shift>
254 struct sbool_unite_spans_aa
256 enum
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,
267 int x, unsigned len,
268 Scanline& sl) const
270 unsigned cover;
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
280 //-----------------
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++);
293 sl.add_cell(x++,
294 (cover == cover_full * cover_full) ?
295 cover_full :
296 (cover >> cover_shift));
298 while(--len);
299 break;
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);
308 else
312 cover = cover_mask * cover_mask -
313 (cover_mask - *(span1->covers)) *
314 (cover_mask - *covers2++);
315 sl.add_cell(x++,
316 (cover == cover_full * cover_full) ?
317 cover_full :
318 (cover >> cover_shift));
320 while(--len);
322 break;
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);
331 else
335 cover = cover_mask * cover_mask -
336 (cover_mask - *covers1++) *
337 (cover_mask - *(span2->covers));
338 sl.add_cell(x++,
339 (cover == cover_full * cover_full) ?
340 cover_full :
341 (cover >> cover_shift));
343 while(--len);
345 break;
347 case 3: // Both are solid spans
348 cover = cover_mask * cover_mask -
349 (cover_mask - *(span1->covers)) *
350 (cover_mask - *(span2->covers));
351 sl.add_span(x, len,
352 (cover == cover_full * cover_full) ?
353 cover_full :
354 (cover >> cover_shift));
355 break;
361 //---------------------------------------------sbool_xor_formula_linear
362 template<unsigned CoverShift = cover_shift>
363 struct sbool_xor_formula_linear
365 enum
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;
376 return cover;
381 //---------------------------------------------sbool_xor_formula_saddle
382 template<unsigned CoverShift = cover_shift>
383 struct sbool_xor_formula_saddle
385 enum
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)
394 unsigned k = a * 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
416 // Functor.
417 // XOR two spans preserving the anti-aliasing information.
418 // The result is added to the "sl" scanline.
419 //------------------
420 template<class Scanline1,
421 class Scanline2,
422 class Scanline,
423 class XorFormula,
424 unsigned CoverShift = cover_shift>
425 struct sbool_xor_spans_aa
427 enum
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,
438 int x, unsigned len,
439 Scanline& sl) const
441 unsigned cover;
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
451 //-----------------
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);
463 ++x;
465 while(--len);
466 break;
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);
475 ++x;
477 while(--len);
478 break;
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);
487 ++x;
489 while(--len);
490 break;
492 case 3: // Both are solid spans
493 cover = XorFormula::calculate(*(span1->covers), *(span2->covers));
494 if(cover) sl.add_span(x, len, cover);
495 break;
505 //-----------------------------------------------sbool_subtract_spans_aa
506 // Functor.
507 // Unite two spans preserving the anti-aliasing information.
508 // The result is added to the "sl" scanline.
509 //------------------
510 template<class Scanline1,
511 class Scanline2,
512 class Scanline,
513 unsigned CoverShift = cover_shift>
514 struct sbool_subtract_spans_aa
516 enum
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,
527 int x, unsigned len,
528 Scanline& sl) const
530 unsigned cover;
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
540 //-----------------
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++);
551 if(cover)
553 sl.add_cell(x,
554 (cover == cover_full * cover_full) ?
555 cover_full :
556 (cover >> cover_shift));
558 ++x;
560 while(--len);
561 break;
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++);
569 if(cover)
571 sl.add_cell(x,
572 (cover == cover_full * cover_full) ?
573 cover_full :
574 (cover >> cover_shift));
576 ++x;
578 while(--len);
579 break;
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));
589 if(cover)
591 sl.add_cell(x,
592 (cover == cover_full * cover_full) ?
593 cover_full :
594 (cover >> cover_shift));
596 ++x;
598 while(--len);
600 break;
602 case 3: // Both are solid spans
603 cover = *(span1->covers) * (cover_mask - *(span2->covers));
604 if(cover)
606 sl.add_span(x, len,
607 (cover == cover_full * cover_full) ?
608 cover_full :
609 (cover >> cover_shift));
611 break;
621 //--------------------------------------------sbool_add_spans_and_render
622 template<class Scanline1,
623 class Scanline,
624 class Renderer,
625 class AddSpanFunctor>
626 void sbool_add_spans_and_render(const Scanline1& sl1,
627 Scanline& sl,
628 Renderer& ren,
629 AddSpanFunctor add_span)
631 sl.reset_spans();
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);
637 ++span;
639 while(--num_spans);
640 sl.finalize(sl1.y());
641 ren.render(sl);
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,
658 class Scanline2,
659 class Scanline,
660 class CombineSpansFunctor>
661 void sbool_intersect_scanlines(const Scanline1& sl1,
662 const Scanline2& sl2,
663 Scanline& sl,
664 CombineSpansFunctor combine_spans)
666 sl.reset_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();
677 while(num1 && num2)
679 int xb1 = span1->x;
680 int xb2 = span2->x;
681 int xe1 = xb1 + abs((int)span1->len) - 1;
682 int xe2 = xb2 + abs((int)span2->len) - 1;
684 // Determine what spans we should advance in the next step
685 // The span with the least ending X should be advanced
686 // advance_both is just an optimization when we ending
687 // coordinates are the same and we can advance both
688 //--------------
689 bool advance_span1 = xe1 < xe2;
690 bool advance_both = xe1 == xe2;
692 // Find the intersection of the spans
693 // and check if they intersect
694 //--------------
695 if(xb1 < xb2) xb1 = xb2;
696 if(xe1 > xe2) xe1 = xe2;
697 if(xb1 <= xe1)
699 combine_spans(span1, span2, xb1, xe1 - xb1 + 1, sl);
702 // Advance the spans
703 //--------------
704 if(advance_both)
706 --num1;
707 --num2;
708 ++span1;
709 ++span2;
711 else
713 if(advance_span1)
715 --num1;
716 ++span1;
718 else
720 --num2;
721 ++span2;
734 //------------------------------------------------sbool_intersect_shapes
735 // Intersect the scanline shapes. Here the "Scanline Generator"
736 // abstraction is used. ScanlineGen1 and ScanlineGen2 are
737 // the generators, and can be of type rasterizer_scanline_aa<>.
738 // There function requires three scanline containers that can be of
739 // different types.
740 // "sl1" and "sl2" are used to retrieve scanlines from the generators,
741 // "sl" is ised as the resulting scanline to render it.
742 // The external "sl1" and "sl2" are used only for the sake of
743 // optimization and reusing of the scanline objects.
744 // the function calls sbool_intersect_scanlines with CombineSpansFunctor
745 // as the last argument. See sbool_intersect_scanlines for details.
746 //----------
747 template<class ScanlineGen1,
748 class ScanlineGen2,
749 class Scanline1,
750 class Scanline2,
751 class Scanline,
752 class Renderer,
753 class CombineSpansFunctor>
754 void sbool_intersect_shapes(ScanlineGen1& sg1, ScanlineGen2& sg2,
755 Scanline1& sl1, Scanline2& sl2,
756 Scanline& sl, Renderer& ren,
757 CombineSpansFunctor combine_spans)
759 // Prepare the scanline generators.
760 // If anyone of them doesn't contain
761 // any scanlines, then return.
762 //-----------------
763 if(!sg1.rewind_scanlines()) return;
764 if(!sg2.rewind_scanlines()) return;
766 // Get the bounding boxes
767 //----------------
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.
773 //-----------------
774 rect ir = intersect_rectangles(r1, r2);
775 if(!ir.is_valid()) return;
777 // Reset the scanlines and get two first ones
778 //-----------------
779 sl.reset(ir.x1, ir.x2);
780 sl1.reset(sg1.min_x(), sg1.max_x());
781 sl2.reset(sg2.min_x(), sg2.max_x());
782 if(!sg1.sweep_scanline(sl1)) return;
783 if(!sg2.sweep_scanline(sl2)) return;
785 ren.prepare(unsigned(ir.x2 - ir.x1 + 2));
787 // The main loop
788 // Here we synchronize the scanlines with
789 // the same Y coordinate, ignoring all other ones.
790 // Only scanlines having the same Y-coordinate
791 // are to be combined.
792 //-----------------
793 for(;;)
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);
811 if(sl.num_spans())
813 sl.finalize(sl1.y());
814 ren.render(sl);
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,
836 class Scanline2,
837 class Scanline,
838 class AddSpanFunctor1,
839 class AddSpanFunctor2,
840 class CombineSpansFunctor>
841 void sbool_unite_scanlines(const Scanline1& sl1,
842 const Scanline2& sl2,
843 Scanline& sl,
844 AddSpanFunctor1 add_span1,
845 AddSpanFunctor2 add_span2,
846 CombineSpansFunctor combine_spans)
848 sl.reset_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
859 //---------------
860 int xb1 = invalid_b;
861 int xb2 = invalid_b;
862 int xe1 = invalid_e;
863 int xe2 = invalid_e;
865 // Initialize span1 if there are spans
866 //---------------
867 if(num1)
869 span1 = sl1.begin();
870 xb1 = span1->x;
871 xe1 = xb1 + abs((int)span1->len) - 1;
872 --num1;
875 // Initialize span2 if there are spans
876 //---------------
877 if(num2)
879 span2 = sl2.begin();
880 xb2 = span2->x;
881 xe2 = xb2 + abs((int)span2->len) - 1;
882 --num2;
886 for(;;)
888 // Retrieve a new span1 if it's invalid
889 //----------------
890 if(num1 && xb1 > xe1)
892 --num1;
893 ++span1;
894 xb1 = span1->x;
895 xe1 = xb1 + abs((int)span1->len) - 1;
898 // Retrieve a new span2 if it's invalid
899 //----------------
900 if(num2 && xb2 > xe2)
902 --num2;
903 ++span2;
904 xb2 = span2->x;
905 xe2 = xb2 + abs((int)span2->len) - 1;
908 if(xb1 > xe1 && xb2 > xe2) break;
910 // Calculate the intersection
911 //----------------
912 int xb = xb1;
913 int xe = xe1;
914 if(xb < xb2) xb = xb2;
915 if(xe > xe2) xe = xe2;
916 int len = xe - xb + 1; // The length of the intersection
917 if(len > 0)
919 // The spans intersect,
920 // add the beginning of the span
921 //----------------
922 if(xb1 < xb2)
924 add_span1(span1, xb1, xb2 - xb1, sl);
925 xb1 = xb2;
927 else
928 if(xb2 < xb1)
930 add_span2(span2, xb2, xb1 - xb2, sl);
931 xb2 = xb1;
934 // Add the combination part of the spans
935 //----------------
936 combine_spans(span1, span2, xb, len, sl);
939 // Invalidate the fully processed span or both
940 //----------------
941 if(xe1 < xe2)
943 // Invalidate span1 and eat
944 // the processed part of span2
945 //--------------
946 xb1 = invalid_b;
947 xe1 = invalid_e;
948 xb2 += len;
950 else
951 if(xe2 < xe1)
953 // Invalidate span2 and eat
954 // the processed part of span1
955 //--------------
956 xb2 = invalid_b;
957 xe2 = invalid_e;
958 xb1 += len;
960 else
962 xb1 = invalid_b; // Invalidate both
963 xb2 = invalid_b;
964 xe1 = invalid_e;
965 xe2 = invalid_e;
968 else
970 // The spans do not intersect
971 //--------------
972 if(xb1 < xb2)
974 // Advance span1
975 //---------------
976 if(xb1 <= xe1)
978 add_span1(span1, xb1, xe1 - xb1 + 1, sl);
980 xb1 = invalid_b; // Invalidate
981 xe1 = invalid_e;
983 else
985 // Advance span2
986 //---------------
987 if(xb2 <= xe2)
989 add_span2(span2, xb2, xe2 - xb2 + 1, sl);
991 xb2 = invalid_b; // Invalidate
992 xe2 = invalid_e;
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.
1013 //----------
1014 template<class ScanlineGen1,
1015 class ScanlineGen2,
1016 class Scanline1,
1017 class Scanline2,
1018 class Scanline,
1019 class Renderer,
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.
1033 //-----------------
1034 bool flag1 = sg1.rewind_scanlines();
1035 bool flag2 = sg2.rewind_scanlines();
1036 if(!flag1 && !flag2) return;
1038 // Get the bounding boxes
1039 //----------------
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
1044 //-----------------
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
1051 //-----------------
1052 sl.reset(ur.x1, ur.x2);
1053 if(flag1)
1055 sl1.reset(sg1.min_x(), sg1.max_x());
1056 flag1 = sg1.sweep_scanline(sl1);
1059 if(flag2)
1061 sl2.reset(sg2.min_x(), sg2.max_x());
1062 flag2 = sg2.sweep_scanline(sl2);
1065 // The main loop
1066 // Here we synchronize the scanlines with
1067 // the same Y coordinate.
1068 //-----------------
1069 while(flag1 || flag2)
1071 if(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);
1081 if(sl.num_spans())
1083 sl.finalize(sl1.y());
1084 ren.render(sl);
1086 flag1 = sg1.sweep_scanline(sl1);
1087 flag2 = sg2.sweep_scanline(sl2);
1089 else
1091 if(sl1.y() < sl2.y())
1093 sbool_add_spans_and_render(sl1, sl, ren, add_span1);
1094 flag1 = sg1.sweep_scanline(sl1);
1096 else
1098 sbool_add_spans_and_render(sl2, sl, ren, add_span2);
1099 flag2 = sg2.sweep_scanline(sl2);
1103 else
1105 if(flag1)
1107 sbool_add_spans_and_render(sl1, sl, ren, add_span1);
1108 flag1 = sg1.sweep_scanline(sl1);
1110 if(flag2)
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
1131 // different types.
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.
1138 //----------
1139 template<class ScanlineGen1,
1140 class ScanlineGen2,
1141 class Scanline1,
1142 class Scanline2,
1143 class Scanline,
1144 class Renderer,
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.
1155 //-----------------
1156 if(!sg1.rewind_scanlines()) return;
1157 bool flag2 = sg2.rewind_scanlines();
1159 // Get the bounding box
1160 //----------------
1161 rect r1(sg1.min_x(), sg1.min_y(), sg1.max_x(), sg1.max_y());
1163 // Reset the scanlines and get two first ones
1164 //-----------------
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;
1177 // The main loop
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.
1182 //-----------------
1183 bool flag1 = true;
1186 // Synchronize "slave" with "master"
1187 //-----------------
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);
1200 if(sl.num_spans())
1202 sl.finalize(sl1.y());
1203 ren.render(sl);
1206 else
1208 sbool_add_spans_and_render(sl1, sl, ren, add_span1);
1211 // Advance the "master"
1212 flag1 = sg1.sweep_scanline(sl1);
1214 while(flag1);
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.
1233 //----------
1234 template<class ScanlineGen1,
1235 class ScanlineGen2,
1236 class Scanline1,
1237 class Scanline2,
1238 class Scanline,
1239 class Renderer>
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
1255 //----------
1256 template<class ScanlineGen1,
1257 class ScanlineGen2,
1258 class Scanline1,
1259 class Scanline2,
1260 class Scanline,
1261 class Renderer>
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
1277 //----------
1278 template<class ScanlineGen1,
1279 class ScanlineGen2,
1280 class Scanline1,
1281 class Scanline2,
1282 class Scanline,
1283 class Renderer>
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
1302 //----------
1303 template<class ScanlineGen1,
1304 class ScanlineGen2,
1305 class Scanline1,
1306 class Scanline2,
1307 class Scanline,
1308 class Renderer>
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
1334 //----------
1335 template<class ScanlineGen1,
1336 class ScanlineGen2,
1337 class Scanline1,
1338 class Scanline2,
1339 class Scanline,
1340 class Renderer>
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
1361 //----------
1362 template<class ScanlineGen1,
1363 class ScanlineGen2,
1364 class Scanline1,
1365 class Scanline2,
1366 class Scanline,
1367 class Renderer>
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,
1375 Scanline2,
1376 Scanline,
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
1389 //----------
1390 template<class ScanlineGen1,
1391 class ScanlineGen2,
1392 class Scanline1,
1393 class Scanline2,
1394 class Scanline,
1395 class Renderer>
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,
1403 Scanline2,
1404 Scanline,
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
1415 //----------
1416 template<class ScanlineGen1,
1417 class ScanlineGen2,
1418 class Scanline1,
1419 class Scanline2,
1420 class Scanline,
1421 class Renderer>
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
1441 //----------
1442 template<class ScanlineGen1,
1443 class ScanlineGen2,
1444 class Scanline1,
1445 class Scanline2,
1446 class Scanline,
1447 class Renderer>
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
1465 //----------
1466 template<class ScanlineGen1,
1467 class ScanlineGen2,
1468 class Scanline1,
1469 class Scanline2,
1470 class Scanline,
1471 class Renderer>
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
1488 enum 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,
1506 class ScanlineGen2,
1507 class Scanline1,
1508 class Scanline2,
1509 class Scanline,
1510 class Renderer>
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)
1516 switch(op)
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;
1520 case sbool_xor :
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,
1533 class ScanlineGen2,
1534 class Scanline1,
1535 class Scanline2,
1536 class Scanline,
1537 class Renderer>
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)
1543 switch(op)
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;
1558 #endif