1525 lines
51 KiB
C
1525 lines
51 KiB
C
|
//----------------------------------------------------------------------------
|
||
|
// Anti-Grain Geometry - Version 2.2
|
||
|
// Copyright (C) 2002-2004 Maxim Shemanarev (http://www.antigrain.com)
|
||
|
//
|
||
|
// Permission to copy, use, modify, sell and distribute this software
|
||
|
// is granted provided this copyright notice appears in all copies.
|
||
|
// This software is provided "as is" without express or implied
|
||
|
// warranty, and with no claim as to its suitability for any purpose.
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
// Contact: mcseem@antigrain.com
|
||
|
// mcseemagg@yahoo.com
|
||
|
// http://www.antigrain.com
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
#ifndef AGG_SCANLINE_BOOLEAN_ALGEBRA_INCLUDED
|
||
|
#define AGG_SCANLINE_BOOLEAN_ALGEBRA_INCLUDED
|
||
|
|
||
|
#include <stdlib.h>
|
||
|
#include <math.h>
|
||
|
#include "agg_basics.h"
|
||
|
|
||
|
|
||
|
namespace agg
|
||
|
{
|
||
|
|
||
|
//-----------------------------------------------sbool_combine_spans_bin
|
||
|
// Functor.
|
||
|
// Combine two binary encoded spans, i.e., when we don't have any
|
||
|
// anti-aliasing information, but only X and Length. The function
|
||
|
// is compatible with any type of scanlines.
|
||
|
//----------------
|
||
|
template<class Scanline1,
|
||
|
class Scanline2,
|
||
|
class Scanline>
|
||
|
struct sbool_combine_spans_bin
|
||
|
{
|
||
|
void operator () (const typename Scanline1::const_iterator&,
|
||
|
const typename Scanline2::const_iterator&,
|
||
|
int x, unsigned len,
|
||
|
Scanline& sl) const
|
||
|
{
|
||
|
sl.add_span(x, len, cover_full);
|
||
|
}
|
||
|
};
|
||
|
|
||
|
|
||
|
|
||
|
//---------------------------------------------sbool_combine_spans_empty
|
||
|
// Functor.
|
||
|
// Combine two spans as empty ones. The functor does nothing
|
||
|
// and is used to XOR binary spans.
|
||
|
//----------------
|
||
|
template<class Scanline1,
|
||
|
class Scanline2,
|
||
|
class Scanline>
|
||
|
struct sbool_combine_spans_empty
|
||
|
{
|
||
|
void operator () (const typename Scanline1::const_iterator&,
|
||
|
const typename Scanline2::const_iterator&,
|
||
|
int, unsigned,
|
||
|
Scanline&) const
|
||
|
{}
|
||
|
};
|
||
|
|
||
|
|
||
|
|
||
|
//--------------------------------------------------sbool_add_span_empty
|
||
|
// Functor.
|
||
|
// Add nothing. Used in conbine_shapes_sub
|
||
|
//----------------
|
||
|
template<class Scanline1,
|
||
|
class Scanline>
|
||
|
struct sbool_add_span_empty
|
||
|
{
|
||
|
void operator () (const typename Scanline1::const_iterator&,
|
||
|
int, unsigned,
|
||
|
Scanline&) const
|
||
|
{}
|
||
|
};
|
||
|
|
||
|
|
||
|
//----------------------------------------------------sbool_add_span_bin
|
||
|
// Functor.
|
||
|
// Add a binary span
|
||
|
//----------------
|
||
|
template<class Scanline1,
|
||
|
class Scanline>
|
||
|
struct sbool_add_span_bin
|
||
|
{
|
||
|
void operator () (const typename Scanline1::const_iterator&,
|
||
|
int x, unsigned len,
|
||
|
Scanline& sl) const
|
||
|
{
|
||
|
sl.add_span(x, len, cover_full);
|
||
|
}
|
||
|
};
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
//-----------------------------------------------------sbool_add_span_aa
|
||
|
// Functor.
|
||
|
// Add an anti-aliased span
|
||
|
// anti-aliasing information, but only X and Length. The function
|
||
|
// is compatible with any type of scanlines.
|
||
|
//----------------
|
||
|
template<class Scanline1,
|
||
|
class Scanline>
|
||
|
struct sbool_add_span_aa
|
||
|
{
|
||
|
void operator () (const typename Scanline1::const_iterator& span,
|
||
|
int x, unsigned len,
|
||
|
Scanline& sl) const
|
||
|
{
|
||
|
if(span->len < 0)
|
||
|
{
|
||
|
sl.add_span(x, len, *span->covers);
|
||
|
}
|
||
|
else
|
||
|
if(span->len > 0)
|
||
|
{
|
||
|
const typename Scanline1::cover_type* covers = span->covers;
|
||
|
if(span->x < x) covers += x - span->x;
|
||
|
sl.add_cells(x, len, covers);
|
||
|
}
|
||
|
}
|
||
|
};
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
//----------------------------------------------sbool_intersect_spans_aa
|
||
|
// Functor.
|
||
|
// Intersect two spans preserving the anti-aliasing information.
|
||
|
// The result is added to the "sl" scanline.
|
||
|
//------------------
|
||
|
template<class Scanline1,
|
||
|
class Scanline2,
|
||
|
class Scanline,
|
||
|
unsigned CoverShift = cover_shift>
|
||
|
struct sbool_intersect_spans_aa
|
||
|
{
|
||
|
enum
|
||
|
{
|
||
|
cover_shift = CoverShift,
|
||
|
cover_size = 1 << cover_shift,
|
||
|
cover_mask = cover_size - 1,
|
||
|
cover_full = cover_mask
|
||
|
};
|
||
|
|
||
|
|
||
|
void operator () (const typename Scanline1::const_iterator& span1,
|
||
|
const typename Scanline2::const_iterator& span2,
|
||
|
int x, unsigned len,
|
||
|
Scanline& sl) const
|
||
|
{
|
||
|
unsigned cover;
|
||
|
const typename Scanline1::cover_type* covers1;
|
||
|
const typename Scanline2::cover_type* covers2;
|
||
|
|
||
|
// Calculate the operation code and choose the
|
||
|
// proper combination algorithm.
|
||
|
// 0 = Both spans are of AA type
|
||
|
// 1 = span1 is solid, span2 is AA
|
||
|
// 2 = span1 is AA, span2 is solid
|
||
|
// 3 = Both spans are of solid type
|
||
|
//-----------------
|
||
|
switch((span1->len < 0) | ((span2->len < 0) << 1))
|
||
|
{
|
||
|
case 0: // Both are AA spans
|
||
|
covers1 = span1->covers;
|
||
|
covers2 = span2->covers;
|
||
|
if(span1->x < x) covers1 += x - span1->x;
|
||
|
if(span2->x < x) covers2 += x - span2->x;
|
||
|
do
|
||
|
{
|
||
|
cover = *covers1++ * *covers2++;
|
||
|
sl.add_cell(x++,
|
||
|
(cover == cover_full * cover_full) ?
|
||
|
cover_full :
|
||
|
(cover >> cover_shift));
|
||
|
}
|
||
|
while(--len);
|
||
|
break;
|
||
|
|
||
|
case 1: // span1 is solid, span2 is AA
|
||
|
covers2 = span2->covers;
|
||
|
if(span2->x < x) covers2 += x - span2->x;
|
||
|
if(*(span1->covers) == cover_full)
|
||
|
{
|
||
|
sl.add_cells(x, len, covers2);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
do
|
||
|
{
|
||
|
cover = *(span1->covers) * *covers2++;
|
||
|
sl.add_cell(x++,
|
||
|
(cover == cover_full * cover_full) ?
|
||
|
cover_full :
|
||
|
(cover >> cover_shift));
|
||
|
}
|
||
|
while(--len);
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case 2: // span1 is AA, span2 is solid
|
||
|
covers1 = span1->covers;
|
||
|
if(span1->x < x) covers1 += x - span1->x;
|
||
|
if(*(span2->covers) == cover_full)
|
||
|
{
|
||
|
sl.add_cells(x, len, covers1);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
do
|
||
|
{
|
||
|
cover = *covers1++ * *(span2->covers);
|
||
|
sl.add_cell(x++,
|
||
|
(cover == cover_full * cover_full) ?
|
||
|
cover_full :
|
||
|
(cover >> cover_shift));
|
||
|
}
|
||
|
while(--len);
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case 3: // Both are solid spans
|
||
|
cover = *(span1->covers) * *(span2->covers);
|
||
|
sl.add_span(x, len,
|
||
|
(cover == cover_full * cover_full) ?
|
||
|
cover_full :
|
||
|
(cover >> cover_shift));
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
};
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
//--------------------------------------------------sbool_unite_spans_aa
|
||
|
// Functor.
|
||
|
// Unite two spans preserving the anti-aliasing information.
|
||
|
// The result is added to the "sl" scanline.
|
||
|
//------------------
|
||
|
template<class Scanline1,
|
||
|
class Scanline2,
|
||
|
class Scanline,
|
||
|
unsigned CoverShift = cover_shift>
|
||
|
struct sbool_unite_spans_aa
|
||
|
{
|
||
|
enum
|
||
|
{
|
||
|
cover_shift = CoverShift,
|
||
|
cover_size = 1 << cover_shift,
|
||
|
cover_mask = cover_size - 1,
|
||
|
cover_full = cover_mask
|
||
|
};
|
||
|
|
||
|
|
||
|
void operator () (const typename Scanline1::const_iterator& span1,
|
||
|
const typename Scanline2::const_iterator& span2,
|
||
|
int x, unsigned len,
|
||
|
Scanline& sl) const
|
||
|
{
|
||
|
unsigned cover;
|
||
|
const typename Scanline1::cover_type* covers1;
|
||
|
const typename Scanline2::cover_type* covers2;
|
||
|
|
||
|
// Calculate the operation code and choose the
|
||
|
// proper combination algorithm.
|
||
|
// 0 = Both spans are of AA type
|
||
|
// 1 = span1 is solid, span2 is AA
|
||
|
// 2 = span1 is AA, span2 is solid
|
||
|
// 3 = Both spans are of solid type
|
||
|
//-----------------
|
||
|
switch((span1->len < 0) | ((span2->len < 0) << 1))
|
||
|
{
|
||
|
case 0: // Both are AA spans
|
||
|
covers1 = span1->covers;
|
||
|
covers2 = span2->covers;
|
||
|
if(span1->x < x) covers1 += x - span1->x;
|
||
|
if(span2->x < x) covers2 += x - span2->x;
|
||
|
do
|
||
|
{
|
||
|
cover = cover_mask * cover_mask -
|
||
|
(cover_mask - *covers1++) *
|
||
|
(cover_mask - *covers2++);
|
||
|
sl.add_cell(x++,
|
||
|
(cover == cover_full * cover_full) ?
|
||
|
cover_full :
|
||
|
(cover >> cover_shift));
|
||
|
}
|
||
|
while(--len);
|
||
|
break;
|
||
|
|
||
|
case 1: // span1 is solid, span2 is AA
|
||
|
covers2 = span2->covers;
|
||
|
if(span2->x < x) covers2 += x - span2->x;
|
||
|
if(*(span1->covers) == cover_full)
|
||
|
{
|
||
|
sl.add_span(x, len, cover_full);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
do
|
||
|
{
|
||
|
cover = cover_mask * cover_mask -
|
||
|
(cover_mask - *(span1->covers)) *
|
||
|
(cover_mask - *covers2++);
|
||
|
sl.add_cell(x++,
|
||
|
(cover == cover_full * cover_full) ?
|
||
|
cover_full :
|
||
|
(cover >> cover_shift));
|
||
|
}
|
||
|
while(--len);
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case 2: // span1 is AA, span2 is solid
|
||
|
covers1 = span1->covers;
|
||
|
if(span1->x < x) covers1 += x - span1->x;
|
||
|
if(*(span2->covers) == cover_full)
|
||
|
{
|
||
|
sl.add_span(x, len, cover_full);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
do
|
||
|
{
|
||
|
cover = cover_mask * cover_mask -
|
||
|
(cover_mask - *covers1++) *
|
||
|
(cover_mask - *(span2->covers));
|
||
|
sl.add_cell(x++,
|
||
|
(cover == cover_full * cover_full) ?
|
||
|
cover_full :
|
||
|
(cover >> cover_shift));
|
||
|
}
|
||
|
while(--len);
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case 3: // Both are solid spans
|
||
|
cover = cover_mask * cover_mask -
|
||
|
(cover_mask - *(span1->covers)) *
|
||
|
(cover_mask - *(span2->covers));
|
||
|
sl.add_span(x, len,
|
||
|
(cover == cover_full * cover_full) ?
|
||
|
cover_full :
|
||
|
(cover >> cover_shift));
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
};
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
//---------------------------------------------sbool_xor_formula_saddle
|
||
|
template<unsigned CoverShift = cover_shift>
|
||
|
struct sbool_xor_formula_saddle
|
||
|
{
|
||
|
enum
|
||
|
{
|
||
|
cover_shift = CoverShift,
|
||
|
cover_size = 1 << cover_shift,
|
||
|
cover_mask = cover_size - 1
|
||
|
};
|
||
|
|
||
|
static unsigned calculate(unsigned a, unsigned b)
|
||
|
{
|
||
|
unsigned k = a * b;
|
||
|
if(k == cover_mask * cover_mask) return 0;
|
||
|
|
||
|
a = (cover_mask * cover_mask - (a << cover_shift) + k) >> cover_shift;
|
||
|
b = (cover_mask * cover_mask - (b << cover_shift) + k) >> cover_shift;
|
||
|
return cover_mask - ((a * b) >> cover_shift);
|
||
|
}
|
||
|
};
|
||
|
|
||
|
|
||
|
|
||
|
//--------------------------------------------sbool_xor_formula_linear
|
||
|
template<unsigned CoverShift = cover_shift>
|
||
|
struct sbool_xor_formula_linear
|
||
|
{
|
||
|
enum
|
||
|
{
|
||
|
cover_shift = CoverShift,
|
||
|
cover_size = 1 << cover_shift,
|
||
|
cover_mask = cover_size - 1
|
||
|
};
|
||
|
|
||
|
static unsigned calculate(unsigned a, unsigned b)
|
||
|
{
|
||
|
unsigned cover = a + b;
|
||
|
if(cover > cover_mask) cover = cover_mask + cover_mask - cover;
|
||
|
return cover;
|
||
|
}
|
||
|
};
|
||
|
|
||
|
|
||
|
|
||
|
//----------------------------------------------------sbool_xor_spans_aa
|
||
|
// Functor.
|
||
|
// XOR two spans preserving the anti-aliasing information.
|
||
|
// The result is added to the "sl" scanline.
|
||
|
//------------------
|
||
|
template<class Scanline1,
|
||
|
class Scanline2,
|
||
|
class Scanline,
|
||
|
class XorFormula,
|
||
|
unsigned CoverShift = cover_shift>
|
||
|
struct sbool_xor_spans_aa
|
||
|
{
|
||
|
enum
|
||
|
{
|
||
|
cover_shift = CoverShift,
|
||
|
cover_size = 1 << cover_shift,
|
||
|
cover_mask = cover_size - 1,
|
||
|
cover_full = cover_mask
|
||
|
};
|
||
|
|
||
|
|
||
|
void operator () (const typename Scanline1::const_iterator& span1,
|
||
|
const typename Scanline2::const_iterator& span2,
|
||
|
int x, unsigned len,
|
||
|
Scanline& sl) const
|
||
|
{
|
||
|
unsigned cover;
|
||
|
const typename Scanline1::cover_type* covers1;
|
||
|
const typename Scanline2::cover_type* covers2;
|
||
|
|
||
|
// Calculate the operation code and choose the
|
||
|
// proper combination algorithm.
|
||
|
// 0 = Both spans are of AA type
|
||
|
// 1 = span1 is solid, span2 is AA
|
||
|
// 2 = span1 is AA, span2 is solid
|
||
|
// 3 = Both spans are of solid type
|
||
|
//-----------------
|
||
|
switch((span1->len < 0) | ((span2->len < 0) << 1))
|
||
|
{
|
||
|
case 0: // Both are AA spans
|
||
|
covers1 = span1->covers;
|
||
|
covers2 = span2->covers;
|
||
|
if(span1->x < x) covers1 += x - span1->x;
|
||
|
if(span2->x < x) covers2 += x - span2->x;
|
||
|
do
|
||
|
{
|
||
|
cover = XorFormula::calculate(*covers1++, *covers2++);
|
||
|
if(cover) sl.add_cell(x, cover);
|
||
|
++x;
|
||
|
}
|
||
|
while(--len);
|
||
|
break;
|
||
|
|
||
|
case 1: // span1 is solid, span2 is AA
|
||
|
covers2 = span2->covers;
|
||
|
if(span2->x < x) covers2 += x - span2->x;
|
||
|
do
|
||
|
{
|
||
|
cover = XorFormula::calculate(*(span1->covers), *covers2++);
|
||
|
if(cover) sl.add_cell(x, cover);
|
||
|
++x;
|
||
|
}
|
||
|
while(--len);
|
||
|
break;
|
||
|
|
||
|
case 2: // span1 is AA, span2 is solid
|
||
|
covers1 = span1->covers;
|
||
|
if(span1->x < x) covers1 += x - span1->x;
|
||
|
do
|
||
|
{
|
||
|
cover = XorFormula::calculate(*covers1++, *(span2->covers));
|
||
|
if(cover) sl.add_cell(x, cover);
|
||
|
++x;
|
||
|
}
|
||
|
while(--len);
|
||
|
break;
|
||
|
|
||
|
case 3: // Both are solid spans
|
||
|
cover = XorFormula::calculate(*(span1->covers), *(span2->covers));
|
||
|
if(cover) sl.add_span(x, len, cover);
|
||
|
break;
|
||
|
|
||
|
}
|
||
|
}
|
||
|
};
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
//-----------------------------------------------sbool_subtract_spans_aa
|
||
|
// Functor.
|
||
|
// Unite two spans preserving the anti-aliasing information.
|
||
|
// The result is added to the "sl" scanline.
|
||
|
//------------------
|
||
|
template<class Scanline1,
|
||
|
class Scanline2,
|
||
|
class Scanline,
|
||
|
unsigned CoverShift = cover_shift>
|
||
|
struct sbool_subtract_spans_aa
|
||
|
{
|
||
|
enum
|
||
|
{
|
||
|
cover_shift = CoverShift,
|
||
|
cover_size = 1 << cover_shift,
|
||
|
cover_mask = cover_size - 1,
|
||
|
cover_full = cover_mask
|
||
|
};
|
||
|
|
||
|
|
||
|
void operator () (const typename Scanline1::const_iterator& span1,
|
||
|
const typename Scanline2::const_iterator& span2,
|
||
|
int x, unsigned len,
|
||
|
Scanline& sl) const
|
||
|
{
|
||
|
unsigned cover;
|
||
|
const typename Scanline1::cover_type* covers1;
|
||
|
const typename Scanline2::cover_type* covers2;
|
||
|
|
||
|
// Calculate the operation code and choose the
|
||
|
// proper combination algorithm.
|
||
|
// 0 = Both spans are of AA type
|
||
|
// 1 = span1 is solid, span2 is AA
|
||
|
// 2 = span1 is AA, span2 is solid
|
||
|
// 3 = Both spans are of solid type
|
||
|
//-----------------
|
||
|
switch((span1->len < 0) | ((span2->len < 0) << 1))
|
||
|
{
|
||
|
case 0: // Both are AA spans
|
||
|
covers1 = span1->covers;
|
||
|
covers2 = span2->covers;
|
||
|
if(span1->x < x) covers1 += x - span1->x;
|
||
|
if(span2->x < x) covers2 += x - span2->x;
|
||
|
do
|
||
|
{
|
||
|
cover = *covers1++ * (cover_mask - *covers2++);
|
||
|
if(cover)
|
||
|
{
|
||
|
sl.add_cell(x,
|
||
|
(cover == cover_full * cover_full) ?
|
||
|
cover_full :
|
||
|
(cover >> cover_shift));
|
||
|
}
|
||
|
++x;
|
||
|
}
|
||
|
while(--len);
|
||
|
break;
|
||
|
|
||
|
case 1: // span1 is solid, span2 is AA
|
||
|
covers2 = span2->covers;
|
||
|
if(span2->x < x) covers2 += x - span2->x;
|
||
|
do
|
||
|
{
|
||
|
cover = *(span1->covers) * (cover_mask - *covers2++);
|
||
|
if(cover)
|
||
|
{
|
||
|
sl.add_cell(x,
|
||
|
(cover == cover_full * cover_full) ?
|
||
|
cover_full :
|
||
|
(cover >> cover_shift));
|
||
|
}
|
||
|
++x;
|
||
|
}
|
||
|
while(--len);
|
||
|
break;
|
||
|
|
||
|
case 2: // span1 is AA, span2 is solid
|
||
|
covers1 = span1->covers;
|
||
|
if(span1->x < x) covers1 += x - span1->x;
|
||
|
if(*(span2->covers) != cover_full)
|
||
|
{
|
||
|
do
|
||
|
{
|
||
|
cover = *covers1++ * (cover_mask - *(span2->covers));
|
||
|
if(cover)
|
||
|
{
|
||
|
sl.add_cell(x,
|
||
|
(cover == cover_full * cover_full) ?
|
||
|
cover_full :
|
||
|
(cover >> cover_shift));
|
||
|
}
|
||
|
++x;
|
||
|
}
|
||
|
while(--len);
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case 3: // Both are solid spans
|
||
|
cover = *(span1->covers) * (cover_mask - *(span2->covers));
|
||
|
if(cover)
|
||
|
{
|
||
|
sl.add_span(x, len,
|
||
|
(cover == cover_full * cover_full) ?
|
||
|
cover_full :
|
||
|
(cover >> cover_shift));
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
};
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
//--------------------------------------------sbool_add_spans_and_render
|
||
|
template<class Scanline1,
|
||
|
class Scanline,
|
||
|
class Renderer,
|
||
|
class AddSpanFunctor>
|
||
|
void sbool_add_spans_and_render(const Scanline1& sl1,
|
||
|
Scanline& sl,
|
||
|
Renderer& ren,
|
||
|
AddSpanFunctor add_span)
|
||
|
{
|
||
|
sl.reset_spans();
|
||
|
typename Scanline::const_iterator span = sl1.begin();
|
||
|
unsigned num_spans = sl1.num_spans();
|
||
|
do
|
||
|
{
|
||
|
add_span(span, span->x, abs((int)span->len), sl);
|
||
|
++span;
|
||
|
}
|
||
|
while(--num_spans);
|
||
|
sl.finalize(sl1.y());
|
||
|
ren.render(sl);
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
//---------------------------------------------sbool_intersect_scanlines
|
||
|
// Intersect two scanlines, "sl1" and "sl2" and generate a new "sl" one.
|
||
|
// The combine_spans functor can be of type sbool_combine_spans_bin or
|
||
|
// sbool_intersect_spans_aa. First is a general functor to combine
|
||
|
// two spans without Anti-Aliasing, the second preserves the AA
|
||
|
// information, but works slower
|
||
|
//
|
||
|
template<class Scanline1,
|
||
|
class Scanline2,
|
||
|
class Scanline,
|
||
|
class CombineSpansFunctor>
|
||
|
void sbool_intersect_scanlines(const Scanline1& sl1,
|
||
|
const Scanline2& sl2,
|
||
|
Scanline& sl,
|
||
|
CombineSpansFunctor combine_spans)
|
||
|
{
|
||
|
sl.reset_spans();
|
||
|
|
||
|
unsigned num1 = sl1.num_spans();
|
||
|
if(num1 == 0) return;
|
||
|
|
||
|
unsigned num2 = sl2.num_spans();
|
||
|
if(num2 == 0) return;
|
||
|
|
||
|
typename Scanline::const_iterator span1 = sl1.begin();
|
||
|
typename Scanline::const_iterator span2 = sl2.begin();
|
||
|
|
||
|
while(num1 && num2)
|
||
|
{
|
||
|
int xb1 = span1->x;
|
||
|
int xb2 = span2->x;
|
||
|
int xe1 = xb1 + abs((int)span1->len) - 1;
|
||
|
int xe2 = xb2 + abs((int)span2->len) - 1;
|
||
|
|
||
|
// Determine what spans we should advance in the next step
|
||
|
// The span with the least ending X should be advanced
|
||
|
// advance_both is just an optimization when we ending
|
||
|
// coordinates are the same and we can advance both
|
||
|
//--------------
|
||
|
bool advance_span1 = xe1 < xe2;
|
||
|
bool advance_both = xe1 == xe2;
|
||
|
|
||
|
// Find the intersection of the spans
|
||
|
// and check if they intersect
|
||
|
//--------------
|
||
|
if(xb1 < xb2) xb1 = xb2;
|
||
|
if(xe1 > xe2) xe1 = xe2;
|
||
|
if(xb1 <= xe1)
|
||
|
{
|
||
|
combine_spans(span1, span2, xb1, xe1 - xb1 + 1, sl);
|
||
|
}
|
||
|
|
||
|
// Advance the spans
|
||
|
//--------------
|
||
|
if(advance_both)
|
||
|
{
|
||
|
--num1;
|
||
|
--num2;
|
||
|
++span1;
|
||
|
++span2;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if(advance_span1)
|
||
|
{
|
||
|
--num1;
|
||
|
++span1;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
--num2;
|
||
|
++span2;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
//------------------------------------------------sbool_intersect_shapes
|
||
|
// Intersect the scanline shapes. Here the "Scanline Generator"
|
||
|
// abstraction is used. ScanlineGen1 and ScanlineGen2 are
|
||
|
// the generators, and can be of type rasterizer_scanline_aa<>.
|
||
|
// There function requires three scanline containers that can be of
|
||
|
// different types.
|
||
|
// "sl1" and "sl2" are used to retrieve scanlines from the generators,
|
||
|
// "sl" is ised as the resulting scanline to render it.
|
||
|
// The external "sl1" and "sl2" are used only for the sake of
|
||
|
// optimization and reusing of the scanline objects.
|
||
|
// the function calls sbool_intersect_scanlines with CombineSpansFunctor
|
||
|
// as the last argument. See sbool_intersect_scanlines for details.
|
||
|
//----------
|
||
|
template<class ScanlineGen1,
|
||
|
class ScanlineGen2,
|
||
|
class Scanline1,
|
||
|
class Scanline2,
|
||
|
class Scanline,
|
||
|
class Renderer,
|
||
|
class CombineSpansFunctor>
|
||
|
void sbool_intersect_shapes(ScanlineGen1& sg1, ScanlineGen2& sg2,
|
||
|
Scanline1& sl1, Scanline2& sl2,
|
||
|
Scanline& sl, Renderer& ren,
|
||
|
CombineSpansFunctor combine_spans)
|
||
|
{
|
||
|
// Prepare the scanline generators.
|
||
|
// If anyone of them doesn't contain
|
||
|
// any scanlines, then return.
|
||
|
//-----------------
|
||
|
if(!sg1.rewind_scanlines()) return;
|
||
|
if(!sg2.rewind_scanlines()) return;
|
||
|
|
||
|
// Get the bounding boxes
|
||
|
//----------------
|
||
|
rect r1(sg1.min_x(), sg1.min_y(), sg1.max_x(), sg1.max_y());
|
||
|
rect r2(sg2.min_x(), sg2.min_y(), sg2.max_x(), sg2.max_y());
|
||
|
|
||
|
// Calculate the intersection of the bounding
|
||
|
// boxes and return if they don't intersect.
|
||
|
//-----------------
|
||
|
rect ir = intersect_rectangles(r1, r2);
|
||
|
if(!ir.is_valid()) return;
|
||
|
|
||
|
// Reset the scanlines and get two first ones
|
||
|
//-----------------
|
||
|
sl.reset(ir.x1, ir.x2);
|
||
|
sl1.reset(sg1.min_x(), sg1.max_x());
|
||
|
sl2.reset(sg2.min_x(), sg2.max_x());
|
||
|
if(!sg1.sweep_scanline(sl1)) return;
|
||
|
if(!sg2.sweep_scanline(sl2)) return;
|
||
|
|
||
|
ren.prepare(unsigned(ir.x2 - ir.x1 + 2));
|
||
|
|
||
|
// The main loop
|
||
|
// Here we synchronize the scanlines with
|
||
|
// the same Y coordinate, ignoring all other ones.
|
||
|
// Only scanlines having the same Y-coordinate
|
||
|
// are to be combined.
|
||
|
//-----------------
|
||
|
for(;;)
|
||
|
{
|
||
|
while(sl1.y() < sl2.y())
|
||
|
{
|
||
|
if(!sg1.sweep_scanline(sl1)) return;
|
||
|
}
|
||
|
while(sl2.y() < sl1.y())
|
||
|
{
|
||
|
if(!sg2.sweep_scanline(sl2)) return;
|
||
|
}
|
||
|
|
||
|
if(sl1.y() == sl2.y())
|
||
|
{
|
||
|
// The Y coordinates are the same.
|
||
|
// Combine the scanlines, render if they contain any spans,
|
||
|
// and advance both generators to the next scanlines
|
||
|
//----------------------
|
||
|
sbool_intersect_scanlines(sl1, sl2, sl, combine_spans);
|
||
|
if(sl.num_spans())
|
||
|
{
|
||
|
sl.finalize(sl1.y());
|
||
|
ren.render(sl);
|
||
|
}
|
||
|
if(!sg1.sweep_scanline(sl1)) return;
|
||
|
if(!sg2.sweep_scanline(sl2)) return;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
//-------------------------------------------------sbool_unite_scanlines
|
||
|
// Unite two scanlines, "sl1" and "sl2" and generate a new "sl" one.
|
||
|
// The combine_spans functor can be of type sbool_combine_spans_bin or
|
||
|
// sbool_intersect_spans_aa. First is a general functor to combine
|
||
|
// two spans without Anti-Aliasing, the second preserves the AA
|
||
|
// information, but works slower
|
||
|
//
|
||
|
template<class Scanline1,
|
||
|
class Scanline2,
|
||
|
class Scanline,
|
||
|
class AddSpanFunctor1,
|
||
|
class AddSpanFunctor2,
|
||
|
class CombineSpansFunctor>
|
||
|
void sbool_unite_scanlines(const Scanline1& sl1,
|
||
|
const Scanline2& sl2,
|
||
|
Scanline& sl,
|
||
|
AddSpanFunctor1 add_span1,
|
||
|
AddSpanFunctor2 add_span2,
|
||
|
CombineSpansFunctor combine_spans)
|
||
|
{
|
||
|
sl.reset_spans();
|
||
|
|
||
|
unsigned num1 = sl1.num_spans();
|
||
|
unsigned num2 = sl2.num_spans();
|
||
|
|
||
|
typename Scanline::const_iterator span1;
|
||
|
typename Scanline::const_iterator span2;
|
||
|
|
||
|
enum { invalid_b = 0x7FFFFFFF, invalid_e = invalid_b - 1 };
|
||
|
|
||
|
// Initialize the spans as invalid
|
||
|
//---------------
|
||
|
int xb1 = invalid_b;
|
||
|
int xb2 = invalid_b;
|
||
|
int xe1 = invalid_e;
|
||
|
int xe2 = invalid_e;
|
||
|
|
||
|
// Initialize span1 if there are spans
|
||
|
//---------------
|
||
|
if(num1)
|
||
|
{
|
||
|
span1 = sl1.begin();
|
||
|
xb1 = span1->x;
|
||
|
xe1 = xb1 + abs((int)span1->len) - 1;
|
||
|
--num1;
|
||
|
}
|
||
|
|
||
|
// Initialize span2 if there are spans
|
||
|
//---------------
|
||
|
if(num2)
|
||
|
{
|
||
|
span2 = sl2.begin();
|
||
|
xb2 = span2->x;
|
||
|
xe2 = xb2 + abs((int)span2->len) - 1;
|
||
|
--num2;
|
||
|
}
|
||
|
|
||
|
|
||
|
for(;;)
|
||
|
{
|
||
|
// Retrieve a new span1 if it's invalid
|
||
|
//----------------
|
||
|
if(num1 && xb1 > xe1)
|
||
|
{
|
||
|
--num1;
|
||
|
++span1;
|
||
|
xb1 = span1->x;
|
||
|
xe1 = xb1 + abs((int)span1->len) - 1;
|
||
|
}
|
||
|
|
||
|
// Retrieve a new span2 if it's invalid
|
||
|
//----------------
|
||
|
if(num2 && xb2 > xe2)
|
||
|
{
|
||
|
--num2;
|
||
|
++span2;
|
||
|
xb2 = span2->x;
|
||
|
xe2 = xb2 + abs((int)span2->len) - 1;
|
||
|
}
|
||
|
|
||
|
if(xb1 > xe1 && xb2 > xe2) break;
|
||
|
|
||
|
// Calculate the intersection
|
||
|
//----------------
|
||
|
int xb = xb1;
|
||
|
int xe = xe1;
|
||
|
if(xb < xb2) xb = xb2;
|
||
|
if(xe > xe2) xe = xe2;
|
||
|
int len = xe - xb + 1; // The length of the intersection
|
||
|
if(len > 0)
|
||
|
{
|
||
|
// The spans intersect,
|
||
|
// add the beginning of the span
|
||
|
//----------------
|
||
|
if(xb1 < xb2)
|
||
|
{
|
||
|
add_span1(span1, xb1, xb2 - xb1, sl);
|
||
|
xb1 = xb2;
|
||
|
}
|
||
|
else
|
||
|
if(xb2 < xb1)
|
||
|
{
|
||
|
add_span2(span2, xb2, xb1 - xb2, sl);
|
||
|
xb2 = xb1;
|
||
|
}
|
||
|
|
||
|
// Add the combination part of the spans
|
||
|
//----------------
|
||
|
combine_spans(span1, span2, xb, len, sl);
|
||
|
|
||
|
|
||
|
// Invalidate the fully processed span or both
|
||
|
//----------------
|
||
|
if(xe1 < xe2)
|
||
|
{
|
||
|
// Invalidate span1 and eat
|
||
|
// the processed part of span2
|
||
|
//--------------
|
||
|
xb1 = invalid_b;
|
||
|
xe1 = invalid_e;
|
||
|
xb2 += len;
|
||
|
}
|
||
|
else
|
||
|
if(xe2 < xe1)
|
||
|
{
|
||
|
// Invalidate span2 and eat
|
||
|
// the processed part of span1
|
||
|
//--------------
|
||
|
xb2 = invalid_b;
|
||
|
xe2 = invalid_e;
|
||
|
xb1 += len;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
xb1 = invalid_b; // Invalidate both
|
||
|
xb2 = invalid_b;
|
||
|
xe1 = invalid_e;
|
||
|
xe2 = invalid_e;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// The spans do not intersect
|
||
|
//--------------
|
||
|
if(xb1 < xb2)
|
||
|
{
|
||
|
// Advance span1
|
||
|
//---------------
|
||
|
if(xb1 <= xe1)
|
||
|
{
|
||
|
add_span1(span1, xb1, xe1 - xb1 + 1, sl);
|
||
|
}
|
||
|
xb1 = invalid_b; // Invalidate
|
||
|
xe1 = invalid_e;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// Advance span2
|
||
|
//---------------
|
||
|
if(xb2 <= xe2)
|
||
|
{
|
||
|
add_span2(span2, xb2, xe2 - xb2 + 1, sl);
|
||
|
}
|
||
|
xb2 = invalid_b; // Invalidate
|
||
|
xe2 = invalid_e;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
//----------------------------------------------------sbool_unite_shapes
|
||
|
// Unite the scanline shapes. Here the "Scanline Generator"
|
||
|
// abstraction is used. ScanlineGen1 and ScanlineGen2 are
|
||
|
// the generators, and can be of type rasterizer_scanline_aa<>.
|
||
|
// There function requires three scanline containers that can be
|
||
|
// of different type.
|
||
|
// "sl1" and "sl2" are used to retrieve scanlines from the generators,
|
||
|
// "sl" is ised as the resulting scanline to render it.
|
||
|
// The external "sl1" and "sl2" are used only for the sake of
|
||
|
// optimization and reusing of the scanline objects.
|
||
|
// the function calls sbool_unite_scanlines with CombineSpansFunctor
|
||
|
// as the last argument. See sbool_unite_scanlines for details.
|
||
|
//----------
|
||
|
template<class ScanlineGen1,
|
||
|
class ScanlineGen2,
|
||
|
class Scanline1,
|
||
|
class Scanline2,
|
||
|
class Scanline,
|
||
|
class Renderer,
|
||
|
class AddSpanFunctor1,
|
||
|
class AddSpanFunctor2,
|
||
|
class CombineSpansFunctor>
|
||
|
void sbool_unite_shapes(ScanlineGen1& sg1, ScanlineGen2& sg2,
|
||
|
Scanline1& sl1, Scanline2& sl2,
|
||
|
Scanline& sl, Renderer& ren,
|
||
|
AddSpanFunctor1 add_span1,
|
||
|
AddSpanFunctor2 add_span2,
|
||
|
CombineSpansFunctor combine_spans)
|
||
|
{
|
||
|
// Prepare the scanline generators.
|
||
|
// If anyone of them doesn't contain
|
||
|
// any scanlines, then return.
|
||
|
//-----------------
|
||
|
bool flag1 = sg1.rewind_scanlines();
|
||
|
bool flag2 = sg2.rewind_scanlines();
|
||
|
if(!flag1 && !flag2) return;
|
||
|
|
||
|
// Get the bounding boxes
|
||
|
//----------------
|
||
|
rect r1(sg1.min_x(), sg1.min_y(), sg1.max_x(), sg1.max_y());
|
||
|
rect r2(sg2.min_x(), sg2.min_y(), sg2.max_x(), sg2.max_y());
|
||
|
|
||
|
// Calculate the union of the bounding boxes
|
||
|
//-----------------
|
||
|
rect ur = unite_rectangles(r1, r2);
|
||
|
if(!ur.is_valid()) return;
|
||
|
|
||
|
ren.prepare(unsigned(ur.x2 - ur.x2 + 2));
|
||
|
|
||
|
// Reset the scanlines and get two first ones
|
||
|
//-----------------
|
||
|
sl.reset(ur.x1, ur.x2);
|
||
|
if(flag1)
|
||
|
{
|
||
|
sl1.reset(sg1.min_x(), sg1.max_x());
|
||
|
flag1 = sg1.sweep_scanline(sl1);
|
||
|
}
|
||
|
|
||
|
if(flag2)
|
||
|
{
|
||
|
sl2.reset(sg2.min_x(), sg2.max_x());
|
||
|
flag2 = sg2.sweep_scanline(sl2);
|
||
|
}
|
||
|
|
||
|
// The main loop
|
||
|
// Here we synchronize the scanlines with
|
||
|
// the same Y coordinate.
|
||
|
//-----------------
|
||
|
while(flag1 || flag2)
|
||
|
{
|
||
|
if(flag1 && flag2)
|
||
|
{
|
||
|
if(sl1.y() == sl2.y())
|
||
|
{
|
||
|
// The Y coordinates are the same.
|
||
|
// Combine the scanlines, render if they contain any spans,
|
||
|
// and advance both generators to the next scanlines
|
||
|
//----------------------
|
||
|
sbool_unite_scanlines(sl1, sl2, sl,
|
||
|
add_span1, add_span2, combine_spans);
|
||
|
if(sl.num_spans())
|
||
|
{
|
||
|
sl.finalize(sl1.y());
|
||
|
ren.render(sl);
|
||
|
}
|
||
|
flag1 = sg1.sweep_scanline(sl1);
|
||
|
flag2 = sg2.sweep_scanline(sl2);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if(sl1.y() < sl2.y())
|
||
|
{
|
||
|
sbool_add_spans_and_render(sl1, sl, ren, add_span1);
|
||
|
flag1 = sg1.sweep_scanline(sl1);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
sbool_add_spans_and_render(sl2, sl, ren, add_span2);
|
||
|
flag2 = sg2.sweep_scanline(sl2);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if(flag1)
|
||
|
{
|
||
|
sbool_add_spans_and_render(sl1, sl, ren, add_span1);
|
||
|
flag1 = sg1.sweep_scanline(sl1);
|
||
|
}
|
||
|
if(flag2)
|
||
|
{
|
||
|
sbool_add_spans_and_render(sl2, sl, ren, add_span2);
|
||
|
flag2 = sg2.sweep_scanline(sl2);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
//-------------------------------------------------sbool_subtract_shapes
|
||
|
// Subtract the scanline shapes, "sg1-sg2". Here the "Scanline Generator"
|
||
|
// abstraction is used. ScanlineGen1 and ScanlineGen2 are
|
||
|
// the generators, and can be of type rasterizer_scanline_aa<>.
|
||
|
// There function requires three scanline containers that can be of
|
||
|
// different types.
|
||
|
// "sl1" and "sl2" are used to retrieve scanlines from the generators,
|
||
|
// "sl" is ised as the resulting scanline to render it.
|
||
|
// The external "sl1" and "sl2" are used only for the sake of
|
||
|
// optimization and reusing of the scanline objects.
|
||
|
// the function calls sbool_intersect_scanlines with CombineSpansFunctor
|
||
|
// as the last argument. See combine_scanlines_sub for details.
|
||
|
//----------
|
||
|
template<class ScanlineGen1,
|
||
|
class ScanlineGen2,
|
||
|
class Scanline1,
|
||
|
class Scanline2,
|
||
|
class Scanline,
|
||
|
class Renderer,
|
||
|
class AddSpanFunctor1,
|
||
|
class CombineSpansFunctor>
|
||
|
void sbool_subtract_shapes(ScanlineGen1& sg1, ScanlineGen2& sg2,
|
||
|
Scanline1& sl1, Scanline2& sl2,
|
||
|
Scanline& sl, Renderer& ren,
|
||
|
AddSpanFunctor1 add_span1,
|
||
|
CombineSpansFunctor combine_spans)
|
||
|
{
|
||
|
// Prepare the scanline generators.
|
||
|
// Here "sg1" is master, "sg2" is slave.
|
||
|
//-----------------
|
||
|
if(!sg1.rewind_scanlines()) return;
|
||
|
bool flag2 = sg2.rewind_scanlines();
|
||
|
|
||
|
// Get the bounding box
|
||
|
//----------------
|
||
|
rect r1(sg1.min_x(), sg1.min_y(), sg1.max_x(), sg1.max_y());
|
||
|
|
||
|
// Reset the scanlines and get two first ones
|
||
|
//-----------------
|
||
|
sl.reset(sg1.min_x(), sg1.max_x());
|
||
|
sl1.reset(sg1.min_x(), sg1.max_x());
|
||
|
sl2.reset(sg2.min_x(), sg2.max_x());
|
||
|
if(!sg1.sweep_scanline(sl1)) return;
|
||
|
|
||
|
if(flag2) flag2 = sg2.sweep_scanline(sl2);
|
||
|
|
||
|
ren.prepare(unsigned(sg1.max_x() - sg1.min_x() + 2));
|
||
|
|
||
|
// A fake span2 processor
|
||
|
sbool_add_span_empty<Scanline1, Scanline> add_span2;
|
||
|
|
||
|
// The main loop
|
||
|
// Here we synchronize the scanlines with
|
||
|
// the same Y coordinate, ignoring all other ones.
|
||
|
// Only scanlines having the same Y-coordinate
|
||
|
// are to be combined.
|
||
|
//-----------------
|
||
|
bool flag1 = true;
|
||
|
do
|
||
|
{
|
||
|
// Synchronize "slave" with "master"
|
||
|
//-----------------
|
||
|
while(flag2 && sl2.y() < sl1.y())
|
||
|
{
|
||
|
flag2 = sg2.sweep_scanline(sl2);
|
||
|
}
|
||
|
|
||
|
|
||
|
if(flag2 && sl2.y() == sl1.y())
|
||
|
{
|
||
|
// The Y coordinates are the same.
|
||
|
// Combine the scanlines and render if they contain any spans.
|
||
|
//----------------------
|
||
|
sbool_unite_scanlines(sl1, sl2, sl, add_span1, add_span2, combine_spans);
|
||
|
if(sl.num_spans())
|
||
|
{
|
||
|
sl.finalize(sl1.y());
|
||
|
ren.render(sl);
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
sbool_add_spans_and_render(sl1, sl, ren, add_span1);
|
||
|
}
|
||
|
|
||
|
// Advance the "master"
|
||
|
flag1 = sg1.sweep_scanline(sl1);
|
||
|
}
|
||
|
while(flag1);
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
//---------------------------------------------sbool_intersect_shapes_aa
|
||
|
// Intersect two anti-aliased scanline shapes.
|
||
|
// Here the "Scanline Generator" abstraction is used.
|
||
|
// ScanlineGen1 and ScanlineGen2 are the generators, and can be of
|
||
|
// type rasterizer_scanline_aa<>. There function requires three
|
||
|
// scanline containers that can be of different types.
|
||
|
// "sl1" and "sl2" are used to retrieve scanlines from the generators,
|
||
|
// "sl" is ised as the resulting scanline to render it.
|
||
|
// The external "sl1" and "sl2" are used only for the sake of
|
||
|
// optimization and reusing of the scanline objects.
|
||
|
//----------
|
||
|
template<class ScanlineGen1,
|
||
|
class ScanlineGen2,
|
||
|
class Scanline1,
|
||
|
class Scanline2,
|
||
|
class Scanline,
|
||
|
class Renderer>
|
||
|
void sbool_intersect_shapes_aa(ScanlineGen1& sg1, ScanlineGen2& sg2,
|
||
|
Scanline1& sl1, Scanline2& sl2,
|
||
|
Scanline& sl, Renderer& ren)
|
||
|
{
|
||
|
sbool_intersect_spans_aa<Scanline1, Scanline2, Scanline> combine_functor;
|
||
|
sbool_intersect_shapes(sg1, sg2, sl1, sl2, sl, ren, combine_functor);
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
//--------------------------------------------sbool_intersect_shapes_bin
|
||
|
// Intersect two binary scanline shapes (without anti-aliasing).
|
||
|
// See intersect_shapes_aa for more comments
|
||
|
//----------
|
||
|
template<class ScanlineGen1,
|
||
|
class ScanlineGen2,
|
||
|
class Scanline1,
|
||
|
class Scanline2,
|
||
|
class Scanline,
|
||
|
class Renderer>
|
||
|
void sbool_intersect_shapes_bin(ScanlineGen1& sg1, ScanlineGen2& sg2,
|
||
|
Scanline1& sl1, Scanline2& sl2,
|
||
|
Scanline& sl, Renderer& ren)
|
||
|
{
|
||
|
sbool_combine_spans_bin<Scanline1, Scanline2, Scanline> combine_functor;
|
||
|
sbool_intersect_shapes(sg1, sg2, sl1, sl2, sl, ren, combine_functor);
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
//-------------------------------------------------sbool_unite_shapes_aa
|
||
|
// Unite two anti-aliased scanline shapes
|
||
|
// See intersect_shapes_aa for more comments
|
||
|
//----------
|
||
|
template<class ScanlineGen1,
|
||
|
class ScanlineGen2,
|
||
|
class Scanline1,
|
||
|
class Scanline2,
|
||
|
class Scanline,
|
||
|
class Renderer>
|
||
|
void sbool_unite_shapes_aa(ScanlineGen1& sg1, ScanlineGen2& sg2,
|
||
|
Scanline1& sl1, Scanline2& sl2,
|
||
|
Scanline& sl, Renderer& ren)
|
||
|
{
|
||
|
sbool_add_span_aa<Scanline1, Scanline> add_functor1;
|
||
|
sbool_add_span_aa<Scanline2, Scanline> add_functor2;
|
||
|
sbool_unite_spans_aa<Scanline1, Scanline2, Scanline> combine_functor;
|
||
|
sbool_unite_shapes(sg1, sg2, sl1, sl2, sl, ren,
|
||
|
add_functor1, add_functor2, combine_functor);
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
//------------------------------------------------sbool_unite_shapes_bin
|
||
|
// Unite two binary scanline shapes (without anti-aliasing).
|
||
|
// See intersect_shapes_aa for more comments
|
||
|
//----------
|
||
|
template<class ScanlineGen1,
|
||
|
class ScanlineGen2,
|
||
|
class Scanline1,
|
||
|
class Scanline2,
|
||
|
class Scanline,
|
||
|
class Renderer>
|
||
|
void sbool_unite_shapes_bin(ScanlineGen1& sg1, ScanlineGen2& sg2,
|
||
|
Scanline1& sl1, Scanline2& sl2,
|
||
|
Scanline& sl, Renderer& ren)
|
||
|
{
|
||
|
sbool_add_span_bin<Scanline1, Scanline> add_functor1;
|
||
|
sbool_add_span_bin<Scanline2, Scanline> add_functor2;
|
||
|
sbool_combine_spans_bin<Scanline1, Scanline2, Scanline> combine_functor;
|
||
|
sbool_unite_shapes(sg1, sg2, sl1, sl2, sl, ren,
|
||
|
add_functor1, add_functor2, combine_functor);
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
//---------------------------------------------------sbool_xor_shapes_aa
|
||
|
// Apply eXclusive OR to two anti-aliased scanline shapes. There's
|
||
|
// a modified "Linear" XOR used instead of classical "Saddle" one.
|
||
|
// The reason is to have the result absolutely conststent with what
|
||
|
// the scanline rasterizer produces.
|
||
|
// See intersect_shapes_aa for more comments
|
||
|
//----------
|
||
|
template<class ScanlineGen1,
|
||
|
class ScanlineGen2,
|
||
|
class Scanline1,
|
||
|
class Scanline2,
|
||
|
class Scanline,
|
||
|
class Renderer>
|
||
|
void sbool_xor_shapes_aa(ScanlineGen1& sg1, ScanlineGen2& sg2,
|
||
|
Scanline1& sl1, Scanline2& sl2,
|
||
|
Scanline& sl, Renderer& ren)
|
||
|
{
|
||
|
sbool_add_span_aa<Scanline1, Scanline> add_functor1;
|
||
|
sbool_add_span_aa<Scanline2, Scanline> add_functor2;
|
||
|
sbool_xor_spans_aa<Scanline1, Scanline2, Scanline,
|
||
|
sbool_xor_formula_linear<> > combine_functor;
|
||
|
sbool_unite_shapes(sg1, sg2, sl1, sl2, sl, ren,
|
||
|
add_functor1, add_functor2, combine_functor);
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
//------------------------------------------sbool_xor_shapes_saddle_aa
|
||
|
// Apply eXclusive OR to two anti-aliased scanline shapes.
|
||
|
// There's the classical "Saddle" used to calculate the
|
||
|
// Anti-Aliasing values, that is:
|
||
|
// a XOR b : 1-((1-a+a*b)*(1-b+a*b))
|
||
|
// See intersect_shapes_aa for more comments
|
||
|
//----------
|
||
|
template<class ScanlineGen1,
|
||
|
class ScanlineGen2,
|
||
|
class Scanline1,
|
||
|
class Scanline2,
|
||
|
class Scanline,
|
||
|
class Renderer>
|
||
|
void sbool_xor_shapes_saddle_aa(ScanlineGen1& sg1, ScanlineGen2& sg2,
|
||
|
Scanline1& sl1, Scanline2& sl2,
|
||
|
Scanline& sl, Renderer& ren)
|
||
|
{
|
||
|
sbool_add_span_aa<Scanline1, Scanline> add_functor1;
|
||
|
sbool_add_span_aa<Scanline2, Scanline> add_functor2;
|
||
|
sbool_xor_spans_aa<Scanline1,
|
||
|
Scanline2,
|
||
|
Scanline,
|
||
|
sbool_xor_formula_saddle<> > combine_functor;
|
||
|
sbool_unite_shapes(sg1, sg2, sl1, sl2, sl, ren,
|
||
|
add_functor1, add_functor2, combine_functor);
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
//--------------------------------------------------sbool_xor_shapes_bin
|
||
|
// Apply eXclusive OR to two binary scanline shapes (without anti-aliasing).
|
||
|
// See intersect_shapes_aa for more comments
|
||
|
//----------
|
||
|
template<class ScanlineGen1,
|
||
|
class ScanlineGen2,
|
||
|
class Scanline1,
|
||
|
class Scanline2,
|
||
|
class Scanline,
|
||
|
class Renderer>
|
||
|
void sbool_xor_shapes_bin(ScanlineGen1& sg1, ScanlineGen2& sg2,
|
||
|
Scanline1& sl1, Scanline2& sl2,
|
||
|
Scanline& sl, Renderer& ren)
|
||
|
{
|
||
|
sbool_add_span_bin<Scanline1, Scanline> add_functor1;
|
||
|
sbool_add_span_bin<Scanline2, Scanline> add_functor2;
|
||
|
sbool_combine_spans_empty<Scanline1, Scanline2, Scanline> combine_functor;
|
||
|
sbool_unite_shapes(sg1, sg2, sl1, sl2, sl, ren,
|
||
|
add_functor1, add_functor2, combine_functor);
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
//----------------------------------------------sbool_subtract_shapes_aa
|
||
|
// Subtract shapes "sg1-sg2" with anti-aliasing
|
||
|
// See intersect_shapes_aa for more comments
|
||
|
//----------
|
||
|
template<class ScanlineGen1,
|
||
|
class ScanlineGen2,
|
||
|
class Scanline1,
|
||
|
class Scanline2,
|
||
|
class Scanline,
|
||
|
class Renderer>
|
||
|
void sbool_subtract_shapes_aa(ScanlineGen1& sg1, ScanlineGen2& sg2,
|
||
|
Scanline1& sl1, Scanline2& sl2,
|
||
|
Scanline& sl, Renderer& ren)
|
||
|
{
|
||
|
sbool_add_span_aa<Scanline1, Scanline> add_functor;
|
||
|
sbool_subtract_spans_aa<Scanline1, Scanline2, Scanline> combine_functor;
|
||
|
sbool_subtract_shapes(sg1, sg2, sl1, sl2, sl, ren,
|
||
|
add_functor, combine_functor);
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
//---------------------------------------------sbool_subtract_shapes_bin
|
||
|
// Subtract binary shapes "sg1-sg2" without anti-aliasing
|
||
|
// See intersect_shapes_aa for more comments
|
||
|
//----------
|
||
|
template<class ScanlineGen1,
|
||
|
class ScanlineGen2,
|
||
|
class Scanline1,
|
||
|
class Scanline2,
|
||
|
class Scanline,
|
||
|
class Renderer>
|
||
|
void sbool_subtract_shapes_bin(ScanlineGen1& sg1, ScanlineGen2& sg2,
|
||
|
Scanline1& sl1, Scanline2& sl2,
|
||
|
Scanline& sl, Renderer& ren)
|
||
|
{
|
||
|
sbool_add_span_bin<Scanline1, Scanline> add_functor;
|
||
|
sbool_combine_spans_empty<Scanline1, Scanline2, Scanline> combine_functor;
|
||
|
sbool_subtract_shapes(sg1, sg2, sl1, sl2, sl, ren,
|
||
|
add_functor, combine_functor);
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
//------------------------------------------------------------sbool_op_e
|
||
|
enum sbool_op_e
|
||
|
{
|
||
|
sbool_or, //----sbool_or
|
||
|
sbool_and, //----sbool_and
|
||
|
sbool_xor, //----sbool_xor
|
||
|
sbool_xor_saddle, //----sbool_xor_saddle
|
||
|
sbool_a_minus_b, //----sbool_a_minus_b
|
||
|
sbool_b_minus_a //----sbool_b_minus_a
|
||
|
};
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
//----------------------------------------------sbool_combine_shapes_bin
|
||
|
template<class ScanlineGen1,
|
||
|
class ScanlineGen2,
|
||
|
class Scanline1,
|
||
|
class Scanline2,
|
||
|
class Scanline,
|
||
|
class Renderer>
|
||
|
void sbool_combine_shapes_bin(sbool_op_e op,
|
||
|
ScanlineGen1& sg1, ScanlineGen2& sg2,
|
||
|
Scanline1& sl1, Scanline2& sl2,
|
||
|
Scanline& sl, Renderer& ren)
|
||
|
{
|
||
|
switch(op)
|
||
|
{
|
||
|
case sbool_or : sbool_unite_shapes_bin (sg1, sg2, sl1, sl2, sl, ren); break;
|
||
|
case sbool_and : sbool_intersect_shapes_bin(sg1, sg2, sl1, sl2, sl, ren); break;
|
||
|
case sbool_xor :
|
||
|
case sbool_xor_saddle: sbool_xor_shapes_bin (sg1, sg2, sl1, sl2, sl, ren); break;
|
||
|
case sbool_a_minus_b : sbool_subtract_shapes_bin (sg1, sg2, sl1, sl2, sl, ren); break;
|
||
|
case sbool_b_minus_a : sbool_subtract_shapes_bin (sg2, sg1, sl2, sl1, sl, ren); break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
//-----------------------------------------------sbool_combine_shapes_aa
|
||
|
template<class ScanlineGen1,
|
||
|
class ScanlineGen2,
|
||
|
class Scanline1,
|
||
|
class Scanline2,
|
||
|
class Scanline,
|
||
|
class Renderer>
|
||
|
void sbool_combine_shapes_aa(sbool_op_e op,
|
||
|
ScanlineGen1& sg1, ScanlineGen2& sg2,
|
||
|
Scanline1& sl1, Scanline2& sl2,
|
||
|
Scanline& sl, Renderer& ren)
|
||
|
{
|
||
|
switch(op)
|
||
|
{
|
||
|
case sbool_or : sbool_unite_shapes_aa (sg1, sg2, sl1, sl2, sl, ren); break;
|
||
|
case sbool_and : sbool_intersect_shapes_aa (sg1, sg2, sl1, sl2, sl, ren); break;
|
||
|
case sbool_xor : sbool_xor_shapes_aa (sg1, sg2, sl1, sl2, sl, ren); break;
|
||
|
case sbool_xor_saddle: sbool_xor_shapes_saddle_aa(sg1, sg2, sl1, sl2, sl, ren); break;
|
||
|
case sbool_a_minus_b : sbool_subtract_shapes_aa (sg1, sg2, sl1, sl2, sl, ren); break;
|
||
|
case sbool_b_minus_a : sbool_subtract_shapes_aa (sg2, sg1, sl2, sl1, sl, ren); break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
#endif
|
||
|
|