from Rasterizer.hpp:58
class Rasterizer
{
public:
enum
{
POLY_BASE_SHIFT = 5,
POLY_BASE_SIZE = 1 << POLY_BASE_SHIFT,
POLY_BASE_MASK = POLY_BASE_SIZE - 1
};
enum
{
AA_SHIFT = 8,
AA_NUM = 1 << AA_SHIFT,
AA_MASK = AA_NUM - 1,
AA_2NUM = AA_NUM * 2,
AA_2MASK = AA_2NUM - 1
};
enum FillingRule
{
FILL_NON_ZERO,
FILL_EVEN_ODD
};
Rasterizer()
: fillingRule(FILL_NON_ZERO)
{
}
void reset()
{
outline.reset();
}
void setFillingRule(FillingRule fillingRule)
{
this->fillingRule = fillingRule;
}
void moveTo(int x, int y)
{
#ifndef SIMULATOR
if (!outline.wasOutlineTooComplex())
#endif
{
outline.moveTo(x, y);
}
}
void lineTo(int x, int y)
{
#ifndef SIMULATOR
if (!outline.wasOutlineTooComplex())
#endif
{
outline.lineTo(x, y);
}
}
unsigned calculateAlpha(int area) const
{
int cover = area >> (Rasterizer::POLY_BASE_SHIFT * 2 + 1 - AA_SHIFT);
if (cover < 0)
{
cover = -cover;
}
if (fillingRule == FILL_EVEN_ODD)
{
cover &= AA_2MASK;
if (cover > AA_NUM)
{
cover = AA_2NUM - cover;
}
}
if (cover > AA_MASK)
{
cover = AA_MASK;
}
return cover;
}
template <class Renderer>
bool render(Renderer& r)
{
const Cell* cells = outline.getCells();
unsigned numCells = outline.getNumCells();
if (numCells == 0)
{
return true;
}
if (outline.wasOutlineTooComplex())
{
return false;
}
int x, y;
int cover;
int alpha;
int area;
scanline.reset();
cover = 0;
const Cell* curCell = cells++;
numCells--;
for (;;)
{
const Cell* startCell = curCell;
int coord = curCell->packedCoord();
x = curCell->x;
y = curCell->y;
area = startCell->area;
cover += startCell->cover;
while (numCells-- > 0)
{
curCell = cells++;
if (curCell->packedCoord() != coord)
{
break;
}
area += curCell->area;
cover += curCell->cover;
}
if (area)
{
alpha = calculateAlpha((cover << (Rasterizer::POLY_BASE_SHIFT + 1)) - area);
if (alpha)
{
if (scanline.isReady(y))
{
r.render(scanline);
scanline.resetSpans();
}
scanline.addCell(x, y, alpha);
}
x++;
}
if (numCells == unsigned(-1))
{
break;
}
if (curCell->x > x)
{
alpha = calculateAlpha(cover << (Rasterizer::POLY_BASE_SHIFT + 1));
if (alpha)
{
if (scanline.isReady(y))
{
r.render(scanline);
scanline.resetSpans();
}
scanline.addSpan(x, y, curCell->x - x, alpha);
}
}
}
if (scanline.getNumSpans())
{
r.render(scanline);
}
return true;
}
void setMaxRenderY(int y)
{
outline.setMaxRenderY(y);
}
bool wasOutlineTooComplex()
{
return outline.wasOutlineTooComplex();
}
private:
Rasterizer(const Rasterizer&);
const Rasterizer& operator=(const Rasterizer&);
Outline outline;
Scanline scanline;
FillingRule fillingRule;
};