@ -62,17 +62,6 @@ namespace ImageSharp.Drawing.Processors
minY = Math . Max ( 0 , minY ) ;
minY = Math . Max ( 0 , minY ) ;
maxY = Math . Min ( source . Height , maxY ) ;
maxY = Math . Min ( source . Height , maxY ) ;
// Reset offset if necessary.
if ( minX > 0 )
{
startX = 0 ;
}
if ( minY > 0 )
{
polyStartY = 0 ;
}
ArrayPool < Vector2 > arrayPool = ArrayPool < Vector2 > . Shared ;
ArrayPool < Vector2 > arrayPool = ArrayPool < Vector2 > . Shared ;
int maxIntersections = this . poly . MaxIntersections ;
int maxIntersections = this . poly . MaxIntersections ;
@ -80,18 +69,15 @@ namespace ImageSharp.Drawing.Processors
using ( PixelAccessor < TColor > sourcePixels = source . Lock ( ) )
using ( PixelAccessor < TColor > sourcePixels = source . Lock ( ) )
using ( IBrushApplicator < TColor > applicator = this . fillColor . CreateApplicator ( sourcePixels , rect ) )
using ( IBrushApplicator < TColor > applicator = this . fillColor . CreateApplicator ( sourcePixels , rect ) )
{
{
// we need to repeat this vertically to set anitialiasing vertically
// but we only have to get colors/fills for the external points nearest transitions in the X Pass ands only is anitialiasing is enabled
Parallel . For (
Parallel . For (
minY ,
minY ,
maxY ,
maxY ,
this . ParallelOptions ,
this . ParallelOptions ,
y = >
y = >
{
{
int offsetY = y - polyStartY ;
var buffer = arrayPool . Rent ( maxIntersections ) ;
var buffer = arrayPool . Rent ( maxIntersections ) ;
var left = new Vector2 ( startX , offsetY ) ;
var left = new Vector2 ( startX , y ) ;
var right = new Vector2 ( endX , offsetY ) ;
var right = new Vector2 ( endX , y ) ;
// foreach line we get all the points where this line crosses the polygon
// foreach line we get all the points where this line crosses the polygon
var pointsFound = this . poly . FindIntersections ( left , right , buffer , maxIntersections , 0 ) ;
var pointsFound = this . poly . FindIntersections ( left , right , buffer , maxIntersections , 0 ) ;
@ -103,11 +89,11 @@ namespace ImageSharp.Drawing.Processors
return ;
return ;
}
}
QuickSort ( buffer , 0 , pointsFound ) ;
QuickSortX ( buffer , 0 , pointsFound ) ;
int currentIntersection = 0 ;
int currentIntersection = 0 ;
float nextPoint = buffer [ 0 ] . X ;
float nextPoint = buffer [ 0 ] . X ;
float lastPoint = left . X ;
float lastPoint = float . MinValue ;
float targetPoint = nextPoint ;
float targetPoint = nextPoint ;
bool isInside = false ;
bool isInside = false ;
@ -116,12 +102,11 @@ namespace ImageSharp.Drawing.Processors
for ( int x = minX ; x < maxX ; x + + )
for ( int x = minX ; x < maxX ; x + + )
{
{
int offsetX = x - startX ;
currentPoint . X = x ;
currentPoint . X = offsetX ;
currentPoint . Y = y ;
currentPoint . Y = offsetY ;
if ( ! isInside )
if ( ! isInside )
{
{
if ( offsetX < ( nextPoint - DrawPadding ) & & offsetX > ( lastPoint + DrawPadding ) )
if ( x < ( nextPoint - DrawPadding ) & & x > ( lastPoint + DrawPadding ) )
{
{
if ( nextPoint = = right . X )
if ( nextPoint = = right . X )
{
{
@ -131,13 +116,13 @@ namespace ImageSharp.Drawing.Processors
}
}
// lets just jump forward
// lets just jump forward
x = ( int ) Math . Floor ( nextPoint ) + startX - DrawPadding ;
x = ( int ) Math . Floor ( nextPoint ) - DrawPadding ;
}
}
}
}
bool onCorner = false ;
bool onCorner = false ;
// there seems to be some issue with this switch.
// there seems to be some issue with this switch.
if ( offsetX > = nextPoint )
if ( x > = nextPoint )
{
{
currentIntersection + + ;
currentIntersection + + ;
lastPoint = nextPoint ;
lastPoint = nextPoint ;
@ -175,20 +160,20 @@ namespace ImageSharp.Drawing.Processors
if ( this . options . Antialias )
if ( this . options . Antialias )
{
{
float distance = float . MaxValue ;
float distance = float . MaxValue ;
if ( offsetX = = lastPoint | | offsetX = = nextPoint )
if ( x = = lastPoint | | x = = nextPoint )
{
{
// we are to far away from the line
// we are to far away from the line
distance = 0 ;
distance = 0 ;
}
}
else if ( nextPoint - AntialiasFactor < offsetX )
else if ( nextPoint - AntialiasFactor < x )
{
{
// we are near the left of the line
// we are near the left of the line
distance = nextPoint - offsetX ;
distance = nextPoint - x ;
}
}
else if ( lastPoint + AntialiasFactor > offsetX )
else if ( lastPoint + AntialiasFactor > x )
{
{
// we are near the right of the line
// we are near the right of the line
distance = offsetX - lastPoint ;
distance = x - lastPoint ;
}
}
else
else
{
{
@ -205,7 +190,7 @@ namespace ImageSharp.Drawing.Processors
if ( opacity > Constants . Epsilon )
if ( opacity > Constants . Epsilon )
{
{
Vector4 backgroundVector = sourcePixels [ offsetX , offsetY ] . ToVector4 ( ) ;
Vector4 backgroundVector = sourcePixels [ x , y ] . ToVector4 ( ) ;
Vector4 sourceVector = applicator . GetColor ( currentPoint ) . ToVector4 ( ) ;
Vector4 sourceVector = applicator . GetColor ( currentPoint ) . ToVector4 ( ) ;
Vector4 finalColor = Vector4BlendTransforms . PremultipliedLerp ( backgroundVector , sourceVector , opacity ) ;
Vector4 finalColor = Vector4BlendTransforms . PremultipliedLerp ( backgroundVector , sourceVector , opacity ) ;
@ -213,34 +198,233 @@ namespace ImageSharp.Drawing.Processors
TColor packed = default ( TColor ) ;
TColor packed = default ( TColor ) ;
packed . PackFromVector4 ( finalColor ) ;
packed . PackFromVector4 ( finalColor ) ;
sourcePixels [ offsetX , offsetY ] = packed ;
sourcePixels [ x , y ] = packed ;
}
}
}
}
arrayPool . Return ( buffer ) ;
arrayPool . Return ( buffer ) ;
} ) ;
} ) ;
if ( this . options . Antialias )
{
// we only need to do the X can for antialiasing purposes
Parallel . For (
minX ,
maxX ,
this . ParallelOptions ,
x = >
{
var buffer = arrayPool . Rent ( maxIntersections ) ;
var left = new Vector2 ( x , polyStartY ) ;
var right = new Vector2 ( x , polyEndY ) ;
// foreach line we get all the points where this line crosses the polygon
var pointsFound = this . poly . FindIntersections ( left , right , buffer , maxIntersections , 0 ) ;
if ( pointsFound = = 0 )
{
arrayPool . Return ( buffer ) ;
// nothign on this line skip
return ;
}
QuickSortY ( buffer , 0 , pointsFound ) ;
int currentIntersection = 0 ;
float nextPoint = buffer [ 0 ] . Y ;
float lastPoint = left . Y ;
float targetPoint = nextPoint ;
bool isInside = false ;
// every odd point is the start of a line
Vector2 currentPoint = default ( Vector2 ) ;
for ( int y = minY ; y < maxY ; y + + )
{
currentPoint . X = x ;
currentPoint . Y = y ;
if ( ! isInside )
{
if ( y < ( nextPoint - DrawPadding ) & & y > ( lastPoint + DrawPadding ) )
{
if ( nextPoint = = right . Y )
{
// we are in the ends run skip it
y = maxY ;
continue ;
}
// lets just jump forward
y = ( int ) Math . Floor ( nextPoint ) - DrawPadding ;
}
}
else
{
if ( y < nextPoint - DrawPadding )
{
if ( nextPoint = = right . Y )
{
// we are in the ends run skip it
y = maxY ;
continue ;
}
// lets just jump forward
y = ( int ) Math . Floor ( nextPoint ) ;
}
}
bool onCorner = false ;
if ( y > = nextPoint )
{
currentIntersection + + ;
lastPoint = nextPoint ;
if ( currentIntersection = = pointsFound )
{
nextPoint = right . Y ;
}
else
{
nextPoint = buffer [ currentIntersection ] . Y ;
// 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 . Y ;
}
else
{
nextPoint = buffer [ currentIntersection ] . Y ;
}
}
}
isInside ^ = true ;
}
float opacity = 1 ;
if ( ! isInside & & ! onCorner )
{
if ( this . options . Antialias )
{
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 ) ;
}
else
{
continue ;
}
}
// 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 . GetColor ( currentPoint ) . ToVector4 ( ) ;
Vector4 finalColor = Vector4BlendTransforms . PremultipliedLerp ( backgroundVector , sourceVector , opacity ) ;
finalColor . W = backgroundVector . W ;
TColor packed = default ( TColor ) ;
packed . PackFromVector4 ( finalColor ) ;
sourcePixels [ x , y ] = packed ;
}
}
arrayPool . Return ( buffer ) ;
} ) ;
}
}
}
private static void QuickSortX ( Vector2 [ ] data , int left , int right )
{
int i = left - 1 ;
int j = right ;
while ( true )
{
float x = data [ left ] . X ;
do
{
i + + ;
}
while ( data [ i ] . X < x ) ;
do
{
j - - ;
}
while ( data [ j ] . X > x ) ;
if ( i < j )
{
Vector2 tmp = data [ i ] ;
data [ i ] = data [ j ] ;
data [ j ] = tmp ;
}
else
{
if ( left < j )
{
QuickSortX ( data , left , j ) ;
}
if ( + + j < right )
{
QuickSortX ( data , j , right ) ;
}
return ;
}
}
}
}
}
private static void QuickSort ( Vector2 [ ] data , int left , int right )
private static void QuickSortY ( Vector2 [ ] data , int left , int right )
{
{
int i = left - 1 ;
int i = left - 1 ;
int j = right ;
int j = right ;
while ( true )
while ( true )
{
{
float d = data [ left ] . X ;
float d = data [ left ] . Y ;
do
do
{
{
i + + ;
i + + ;
}
}
while ( data [ i ] . X < d ) ;
while ( data [ i ] . Y < d ) ;
do
do
{
{
j - - ;
j - - ;
}
}
while ( data [ j ] . X > d ) ;
while ( data [ j ] . Y > d ) ;
if ( i < j )
if ( i < j )
{
{
@ -252,12 +436,12 @@ namespace ImageSharp.Drawing.Processors
{
{
if ( left < j )
if ( left < j )
{
{
QuickSort ( data , left , j ) ;
QuickSortY ( data , left , j ) ;
}
}
if ( + + j < right )
if ( + + j < right )
{
{
QuickSort ( data , j , right ) ;
QuickSortY ( data , j , right ) ;
}
}
return ;
return ;