@ -57,315 +57,116 @@ namespace ImageSharp.Drawing.Processors
/// <inheritdoc/>
protected override void OnApply ( ImageBase < TColor > source , Rectangle sourceRectangle )
{
Rectangle rect = this . Region . Bounds ;
int polyStartY = sourceRectangle . Y - DrawPadding ;
int polyEndY = sourceRectangle . Bottom + DrawPadding ;
int startX = sourceRectangle . X - DrawPadding ;
int endX = sourceRectangle . Right + DrawPadding ;
int minX = Math . Max ( sourceRectangle . Left , startX ) ;
int maxX = Math . Min ( sourceRectangle . Right - 1 , endX ) ;
int minY = Math . Max ( sourceRectangle . Top , polyStartY ) ;
int maxY = Math . Min ( sourceRectangle . Bottom - 1 , polyEndY ) ;
Region region = this . Region ;
Rectangle rect = region . Bounds ;
// Align start/end positions.
minX = Math . Max ( 0 , minX ) ;
maxX = Math . Min ( source . Width , maxX ) ;
minY = Math . Max ( 0 , minY ) ;
maxY = Math . Min ( source . Height , maxY ) ;
int minX = Math . Max ( 0 , rect . Left ) ;
int maxX = Math . Min ( source . Width , rect . Right ) ;
int minY = Math . Max ( 0 , rect . Top ) ;
int maxY = Math . Min ( source . Height , rect . Bottom ) ;
ArrayPool < float > arrayPool = ArrayPool < float > . Shared ;
int maxIntersections = this . Region . MaxIntersections ;
int maxIntersections = region . MaxIntersections ;
float subpixelCount = 4 ;
if ( this . Options . Antialias )
{
subpixelCount = this . Options . AntialiasSubpixelDepth ;
if ( subpixelCount < 4 )
{
subpixelCount = 4 ;
}
}
using ( PixelAccessor < TColor > sourcePixels = source . Lock ( ) )
using ( BrushApplicator < TColor > applicator = this . Brush . CreateApplicator ( sourcePixels , rect ) )
{
Parallel . For (
minY ,
maxY ,
this . ParallelOptions ,
( int y ) = >
float [ ] buffer = arrayPool . Rent ( maxIntersections ) ;
int scanlineWidth = maxX - minX ;
float [ ] scanline = ArrayPool < float > . Shared . Rent ( scanlineWidth ) ;
try
{
float [ ] buffer = arrayPool . Rent ( maxIntersections ) ;
try
bool scanlineDirty = true ;
for ( var y = minY ; y < maxY ; y + + )
{
float right = endX ;
// foreach line we get all the points where this line crosses the polygon
int pointsFound = this . Region . ScanY ( y , buffer , maxIntersections , 0 ) ;
if ( pointsFound = = 0 )
{
// nothing on this line skip
return ;
}
QuickSort ( buffer , pointsFound ) ;
int currentIntersection = 0 ;
float nextPoint = buffer [ 0 ] ;
float lastPoint = float . MinValue ;
bool isInside = false ;
for ( int x = minX ; x < maxX ; x + + )
if ( scanlineDirty )
{
if ( ! isInside )
{
if ( x < ( nextPoint - DrawPadding ) & & x > ( lastPoint + DrawPadding ) )
{
if ( nextPoint = = right )
{
// we are in the ends run skip it
x = maxX ;
continue ;
}
// lets just jump forward
x = ( int ) Math . Floor ( nextPoint ) - DrawPadding ;
}
}
bool onCorner = false ;
// there seems to be some issue with this switch.
if ( x > = nextPoint )
// clear the buffer
for ( int x = 0 ; x < scanlineWidth ; x + + )
{
currentIntersection + + ;
lastPoint = nextPoint ;
if ( currentIntersection = = pointsFound )
{
nextPoint = right ;
}
else
{
nextPoint = buffer [ currentIntersection ] ;
// double point from a corner flip the bit back and move on again
if ( nextPoint = = lastPoint )
{
onCorner = true ;
isInside ^ = true ;
currentIntersection + + ;
if ( currentIntersection = = pointsFound )
{
nextPoint = right ;
}
else
{
nextPoint = buffer [ currentIntersection ] ;
}
}
}
isInside ^ = true ;
}
float opacity = 1 ;
if ( ! isInside & & ! onCorner )
{
if ( this . Options . Antialias )
{
float distance = float . MaxValue ;
if ( x = = lastPoint | | x = = nextPoint )
{
// we are to far away from the line
distance = 0 ;
}
else if ( nextPoint - AntialiasFactor < x )
{
// we are near the left of the line
distance = nextPoint - x ;
}
else if ( lastPoint + AntialiasFactor > x )
{
// we are near the right of the line
distance = x - lastPoint ;
}
else
{
// we are to far away from the line
continue ;
}
opacity = 1 - ( distance / AntialiasFactor ) ;
}
else
{
continue ;
}
scanline [ x ] = 0 ;
}
if ( opacity > Constants . Epsilon )
{
Vector4 backgroundVector = sourcePixels [ x , y ] . ToVector4 ( ) ;
Vector4 sourceVector = applicator [ x , y ] . ToVector4 ( ) ;
Vector4 finalColor = Vector4BlendTransforms . PremultipliedLerp ( backgroundVector , sourceVector , opacity ) ;
TColor packed = default ( TColor ) ;
packed . PackFromVector4 ( finalColor ) ;
sourcePixels [ x , y ] = packed ;
}
scanlineDirty = false ;
}
}
finally
{
arrayPool . Return ( buffer ) ;
}
} ) ;
if ( this . Options . Antialias )
{
// we only need to do the X can for antialiasing purposes
Parallel . For (
minX ,
maxX ,
this . ParallelOptions ,
( int x ) = >
{
float [ ] buffer = arrayPool . Rent ( maxIntersections ) ;
try
float subpixelFraction = 1f / subpixelCount ;
float subpixelFractionPoint = subpixelFraction / subpixelCount ;
for ( float subPixel = ( float ) y ; subPixel < y + 1 ; subPixel + = subpixelFraction )
{
float left = polyStartY ;
float right = polyEndY ;
// foreach line we get all the points where this line crosses the polygon
int pointsFound = this . Region . ScanX ( x , buffer , maxIntersections , 0 ) ;
int pointsFound = region . ScanY ( subPixel , buffer , maxIntersections , 0 ) ;
if ( pointsFound = = 0 )
{
// nothig n on this line skip
return ;
// nothing on this line skip
continue ;
}
QuickSort ( buffer , pointsFound ) ;
int currentIntersection = 0 ;
float nextPoint = buffer [ 0 ] ;
float lastPoint = left ;
bool isInside = false ;
for ( int y = minY ; y < maxY ; y + + )
for ( int point = 0 ; point < pointsFound ; point + = 2 )
{
if ( ! isInside )
{
if ( y < ( nextPoint - DrawPadding ) & & y > ( lastPoint + DrawPadding ) )
{
if ( nextPoint = = right )
{
// we are in the ends run skip it
y = maxY ;
continue ;
}
// points will be paired up
float scanStart = buffer [ point ] - minX ;
float scanEnd = buffer [ point + 1 ] - minX ;
int startX = ( int ) Math . Floor ( scanStart ) ;
int endX = ( int ) Math . Floor ( scanEnd ) ;
// lets just jump forward
y = ( int ) Math . Floor ( nextPoint ) - DrawPadding ;
}
}
else
for ( float x = scanStart ; x < startX + 1 ; x + = subpixelFraction )
{
if ( y < nextPoint - DrawPadding )
{
if ( nextPoint = = right )
{
// we are in the ends run skip it
y = maxY ;
continue ;
}
// lets just jump forward
y = ( int ) Math . Floor ( nextPoint ) ;
}
scanline [ startX ] + = subpixelFractionPoint ;
scanlineDirty = true ;
}
bool onCorner = false ;
if ( y > = nextPoint )
for ( float x = endX ; x < scanEnd ; x + = subpixelFraction )
{
currentIntersection + + ;
lastPoint = nextPoint ;
if ( currentIntersection = = pointsFound )
{
nextPoint = right ;
}
else
{
nextPoint = buffer [ currentIntersection ] ;
// double point from a corner flip the bit back and move on again
if ( nextPoint = = lastPoint )
{
onCorner = true ;
isInside ^ = true ;
currentIntersection + + ;
if ( currentIntersection = = pointsFound )
{
nextPoint = right ;
}
else
{
nextPoint = buffer [ currentIntersection ] ;
}
}
}
scanline [ endX ] + = subpixelFractionPoint ;
scanlineDirty = true ;
}
isInside ^ = true ;
for ( int x = startX + 1 ; x < endX ; x + + )
{
scanline [ x ] + = subpixelFraction ;
scanlineDirty = true ;
}
}
}
float opacity = 1 ;
if ( ! isInside & & ! onCorner )
if ( scanlineDirty )
{
if ( ! this . Options . Antialias )
{
for ( int x = 0 ; x < scanlineWidth ; x + + )
{
if ( this . Options . Antialias )
if ( scanline [ x ] > 0.5 )
{
float distance = float . MaxValue ;
if ( y = = lastPoint | | y = = nextPoint )
{
// we are to far away from the line
distance = 0 ;
}
else if ( nextPoint - AntialiasFactor < y )
{
// we are near the left of the line
distance = nextPoint - y ;
}
else if ( lastPoint + AntialiasFactor > y )
{
// we are near the right of the line
distance = y - lastPoint ;
}
else
{
// we are to far away from the line
continue ;
}
opacity = 1 - ( distance / AntialiasFactor ) ;
scanline [ x ] = 1 ;
}
else
{
continue ;
scanline [ x ] = 0 ;
}
}
// don't set full opactiy color as it will have been gotten by the first scan
if ( opacity > Constants . Epsilon & & opacity < 1 )
{
Vector4 backgroundVector = sourcePixels [ x , y ] . ToVector4 ( ) ;
Vector4 sourceVector = applicator [ x , y ] . ToVector4 ( ) ;
Vector4 finalColor = Vector4BlendTransforms . PremultipliedLerp ( backgroundVector , sourceVector , opacity ) ;
finalColor . W = backgroundVector . W ;
TColor packed = default ( TColor ) ;
packed . PackFromVector4 ( finalColor ) ;
sourcePixels [ x , y ] = packed ;
}
}
applicator . Apply ( scanline , scanlineWidth , 0 , minX , y ) ;
}
finally
{
arrayPool . Return ( buffer ) ;
}
} ) ;
}
}
finally
{
arrayPool . Return ( buffer ) ;
ArrayPool < float > . Shared . Return ( scanline ) ;
}
}
}