/// <summary>Slices off anything below the given line.</summary> public override void SliceBottom(float sliceLine, VectorPath path) { float previous = Previous.Y; float current = Y; // Both below? if (previous < sliceLine && current < sliceLine) { // Both below. path.RemoveVisually(this); return; } else if (previous >= sliceLine && current >= sliceLine) { // Do nothing. return; } // Split where the slice line is. VectorPoint newPoint = Split((sliceLine - previous) / (current - previous), path); // Delete the segment to the left/right. if (current < sliceLine) { // Delete this -> newPoint path.RemoveVisually(newPoint); } else { // Delete previous -> this path.RemoveVisually(this); } }
public override VectorPoint Split(float t,VectorPath path){ // Create the next one: StraightLinePoint point=new StraightLinePoint(X,Y); // Get previous: float previousX=Previous.X; float previousY=Previous.Y; // Get deltas: float dx=X-previousX; float dy=Y-previousY; float nX=previousX + (t*dx); float nY=previousY + (t*dy); X=nX; Y=nY; path.PathNodeCount++; // Insert after this: if(Next==null){ path.LatestPathNode=point; }else{ point.Next=Next; Next.Previous=point; } point.Previous=this; Next=point; return point; }
public override void RecalculateBounds(VectorPath path) { // Take control point into account too: if (Control2X < path.MinX) { path.MinX = Control2X; } if (Control2Y < path.MinY) { path.MinY = Control2Y; } // Width/height are used as max to save some memory: if (Control2X > path.Width) { path.Width = Control2X; } if (Control2Y > path.Height) { path.Height = Control2Y; } base.RecalculateBounds(path); }
/// <summary>Replaces this point with another.</summary> public void ReplaceWith(VectorPoint replacement, VectorPath path) { if (replacement == null) { return; } // Update next/prev: replacement.Next = Next; replacement.Previous = Previous; replacement.IsClose = IsClose; if (Next == null) { path.LatestPathNode = replacement; } else { Next.Previous = replacement; } if (Previous == null) { path.FirstPathNode = replacement; } else { Previous.Next = replacement; } }
public override void RecalculateBounds(VectorPath path) { // Take control point into account too: if (CenterX < path.MinX) { path.MinX = CenterX; } if (CenterY < path.MinY) { path.MinY = CenterY; } // Width/height are used as max to save some memory: if (CenterX > path.Width) { path.Width = CenterX; } if (CenterY > path.Height) { path.Height = CenterY; } // Proportion of the overall length (0-1): float lengthPortion = SweepAngle / 2f * (float)Math.PI; // Approximate ellipse length: float h = (float)(Math.Pow((RadiusX - RadiusY), 2f) / Math.Pow((RadiusX + RadiusY), 2f)); Length = lengthPortion * (((float)Math.PI * (RadiusX + RadiusY)) * (1f + ((3f * h) / (10f + (float)Math.Sqrt(4f - (3f * h)))))); base.RecalculateBounds(path); }
public override void RecalculateBounds(VectorPath path){ // Take control point into account too: if(CircleCenterX<path.MinX){ path.MinX=CircleCenterX; } if(CircleCenterY<path.MinY){ path.MinY=CircleCenterY; } // Width/height are used as max to save some memory: if(CircleCenterX>path.Width){ path.Width=CircleCenterX; } if(CircleCenterY>path.Height){ path.Height=CircleCenterY; } // How much must we rotate through overall? float angleToRotateThrough=EndAngle-StartAngle; // How long is the arc? // First, what portion of a full circle is it: float circlePortion=angleToRotateThrough/((float)Math.PI*2f); // Next, what's the circumference of that circle // (and the above portion of it, thus the length of the arc): Length=2f*(float)Math.PI*Radius * circlePortion; base.RecalculateBounds(path); }
public override void ExtrudeAndSample(VectorPath path, float extrudeBy, PointReceiverStepped sampler) { // Cache radius: float radius = Radius; // Extrude: Radius += extrudeBy; // Clamp: if (Radius < 0f) { Radius = 0f; } // Rebound: RecalculateBounds(path); if (sampler.IncludeFirstNode) { sampler.AddPoint(Previous.X, Previous.Y, 0f); } // Sample now: ComputeLinePoints(sampler); // Restore: Radius = radius; }
public override void RecalculateBounds(VectorPath path){ // Take control point into account too: if(Control1X<path.MinX){ path.MinX=Control1X; } if(Control1Y<path.MinY){ path.MinY=Control1Y; } // Width/height are used as max to save some memory: if(Control1X>path.Width){ path.Width=Control1X; } if(Control1Y>path.Height){ path.Height=Control1Y; } // Start figuring out the length.. float vaX=Previous.X-(2f*Control1X)+X; float vaY=Previous.Y-(2f*Control1Y)+Y; float vbX=(2f*Control1X) - (2f*Previous.X); float vbY=(2f*Control1Y) - (2f*Previous.Y); float a=4f*((vaX*vaX) + (vaY*vaY)); float b=4f*((vaX*vbX) + (vaY*vbY)); float c=(vbX*vbX) + (vbY*vbY); float rootABC = 2f*(float)Math.Sqrt(a+b+c); float rootA = (float)Math.Sqrt(a); float aRootA = 2f*a*rootA; if(aRootA==0f){ Length=0f; }else{ float rootC = 2f*(float)Math.Sqrt(c); float bA = b/rootA; Length=( aRootA * rootABC + rootA*b*(rootABC-rootC) + (4f*c*a - b*b)*(float)Math.Log( (2f*rootA+bA+rootABC) / (bA+rootC) ) ) / (4f*aRootA); } base.RecalculateBounds(path); }
public override void ExtrudeAndSample(VectorPath path, float extrudeBy, PointReceiverStepped sampler) { // First, cache all the points: float prevX = Previous.X; float prevY = Previous.Y; float c1x = Control1X; float c1y = Control1Y; float c2x = Control2X; float c2y = Control2Y; float x = X; float y = Y; // Get the normals and extrude along them. float normalX; float normalY; // First point: StartNormal(out normalX, out normalY); Previous.X += normalX * extrudeBy; Previous.Y += normalY * extrudeBy; // First control: NormalAt(0.3333f, out normalX, out normalY); Control1X += normalX * extrudeBy; Control1Y += normalY * extrudeBy; // Second control: NormalAt(0.6666f, out normalX, out normalY); Control2X += normalX * extrudeBy; Control2Y += normalY * extrudeBy; // Last point: EndNormal(out normalX, out normalY); X += normalX * extrudeBy; Y += normalY * extrudeBy; // Rebound: RecalculateBounds(path); if (sampler.IncludeFirstNode) { sampler.AddPoint(Previous.X, Previous.Y, 0f); } // Sample now: ComputeLinePoints(sampler); // Restore all the points: Previous.X = prevX; Previous.Y = prevY; Control1X = c1x; Control1Y = c1y; Control2X = c2x; Control2Y = c2y; X = x; Y = y; }
public override VectorPoint DeleteControl(int id, VectorPath path) { // Create: VectorPoint pt = new StraightLinePoint(X, Y); // Remove this and add in it's place: ReplaceWith(pt, path); return(pt); }
/// <summary>Copies this path.</summary> public VectorPath CopyPath() { // Create: VectorPath path = new VectorPath(); // Copy into it: CopyInto(path); return(path); }
/// <summary>Simplifies this path now using the given midpoint of the line.</summary> internal void SimplifyNow(VectorPath path) { // Split down the middle, then do it again on those two sublines. Split(0.5f, path); // Split 2nd half: Next.Split(0.5f, path); // Split 1st half (this object again): Split(0.5f, path); }
public override void RecalculateBounds(VectorPath path) { // Get deltas: float dx = X - Previous.X; float dy = Y - Previous.Y; // Length: Length = (float)Math.Sqrt((dx * dx) + (dy * dy)); base.RecalculateBounds(path); }
public override void RecalculateBounds(VectorPath path){ // Get deltas: float dx=X-Previous.X; float dy=Y-Previous.Y; // Length: Length=(float)Math.Sqrt((dx*dx)+(dy*dy)); base.RecalculateBounds(path); }
/// <summary>Copies a section of this path. /// Note that if p2 is before p1, it will safely loop over a closed node. /// </summary> public VectorPath CopySection(VectorPoint p1, float c1, VectorPoint p2, float c2) { // Split the line p1 at c1. // Split the line p2 at c2. // The section between these two nodes is the part we want. // Create the path: VectorPath path = new VectorPath(); if (p1 == null) { p1 = FirstPathNode; c1 = 0f; } // Add the first node: path.AddPathNode(p1.PointAt(c1, true)); VectorPoint current = p1.Next; while (current != p2 && current != null) { if (current == p1) { // This occurs when p1 and p2 are not in the same shape. throw new Exception("Section start and end are not from the same path."); } // Add a copy: path.AddPathNode(current.Copy()); // Go to next: current = current.Next; if (current == null && p2 != null) { // Need to loop back around unless p2 is null. // Notice that we actively skip the moveTo itself as // current is in the same location. current = path.FirstPathNode.Next; } } if (current == p2 && p2 != null) { // Add it: path.AddPathNode(p2.PointAt(c2, false)); } return(path); }
public override VectorPoint Split(float t,VectorPath path){ float invert=1f-t; float p0x=Previous.X; float p0y=Previous.Y; float p1x=Control1X; float p1y=Control1Y; float p2x=X; float p2y=Y; // The new points: float p3x=p0x * invert + p1x * t; float p3y=p0y * invert + p1y * t; float p4x=p1x * invert + p2x * t; float p4y=p1y * invert + p2y * t; float p5x=p3x * invert + p4x * t; float p5y=p3y * invert + p4y * t; // This curve will become the new 1st half: Control1X=p3x; Control1Y=p3y; X=p5x; Y=p5y; path.PathNodeCount++; // Create the next one: QuadLinePoint point=new QuadLinePoint(p2x,p2y); point.Control1X=p4x; point.Control1Y=p4y; // Insert after this: if(Next==null){ path.LatestPathNode=point; }else{ point.Next=Next; Next.Previous=point; } point.Previous=this; Next=point; return point; }
public override VectorPoint AddControl(float x, float y, VectorPath path, out int id) { id = 0; // Just split the line: // Get the "progress" of x/y along the line: float C = X - Previous.X; float D = Y - Previous.Y; float len_sq = C * C + D * D; float t = ProgressAlongFast(x, y, C, D, len_sq); return(Split(t, path)); }
public override VectorPoint AddControl(float x, float y, VectorPath path, out int id) { // Create: QuadLinePoint pt = new QuadLinePoint(X, Y); pt.Control1X = x; pt.Control1Y = y; // Remove this and add pt in it's place: ReplaceWith(pt, path); id = 1; return(pt); }
public override VectorPoint Split(float t, VectorPath path) { // Create the next one: StraightLinePoint point = new StraightLinePoint(X, Y); // Get previous: float previousX = Previous.X; float previousY = Previous.Y; // Get deltas: float dx = X - previousX; float dy = Y - previousY; float nX = previousX + (t * dx); float nY = previousY + (t * dy); X = nX; Y = nY; path.PathNodeCount++; // Insert after this: if (Next == null) { path.LatestPathNode = point; } else { point.Next = Next; Next.Previous = point; } // Update lengths: point.Length = (1f - t) * Length; Length = t * Length; point.Previous = this; Next = point; if (IsClose) { IsClose = false; point.IsClose = true; path.CloseNode.ClosePoint = point; } return(point); }
public override void RecalculateBounds(VectorPath path) { // Take control point into account too: if (Control2X < path.MinX) { path.MinX = Control2X; } if (Control2Y < path.MinY) { path.MinY = Control2Y; } // Width/height are used as max to save some memory: if (Control2X > path.Width) { path.Width = Control2X; } if (Control2Y > path.Height) { path.Height = Control2Y; } // Start figuring out the length (very approximate).. float dx = Previous.X - Control1X; float dy = Previous.Y - Control1Y; double len = Math.Sqrt(dx * dx + dy * dy); dx = Control2X - Control1X; dy = Control2Y - Control1Y; len += Math.Sqrt(dx * dx + dy * dy); dx = X - Control2X; dy = Y - Control2Y; len += Math.Sqrt(dx * dx + dy * dy); Length = (float)len; BaseBounds(path); }
public override VectorPoint AddControl(float x, float y, VectorPath path, out int id) { // Create: CurveLinePoint pt = new CurveLinePoint(X, Y); // Get the "progress" of x/y along the line, vs control point progress. float C = X - Previous.X; float D = Y - Previous.Y; float len_sq = C * C + D * D; float newProg = ProgressAlongFast(x, y, C, D, len_sq); float p1Prog = ProgressAlongFast(Control1X, Control1Y, C, D, len_sq); // Should this new control be control point #1? bool first = (newProg < p1Prog); if (first) { // Pt 1: pt.Control1X = x; pt.Control1Y = y; pt.Control2X = Control1X; pt.Control2Y = Control1Y; id = 1; } else { // Pt 2: pt.Control1X = Control1X; pt.Control1Y = Control1Y; pt.Control2X = x; pt.Control2Y = y; id = 2; } // Remove this and add in it's place: ReplaceWith(pt, path); return(pt); }
public override VectorPath GetPath(RenderableData context, CssProperty property) { if (CachedPath_ == null) { CachedPath_ = new VectorPath(); // Create the curve now: CachedPath_.CurveTo( this[0].GetDecimal(context, property), this[1].GetDecimal(context, property), this[2].GetDecimal(context, property), this[3].GetDecimal(context, property), 1f, 1f ); } return(CachedPath_); }
/// <summary>Copies this vector path into the given one.</summary> public void CopyInto(VectorPath path) { VectorPoint point = FirstPathNode; while (point != null) { VectorPoint copiedPoint = point.Copy(); path.AddPathNode(copiedPoint); // Copy close status: if (point.IsClose) { copiedPoint.IsClose = true; path.CloseNode.ClosePoint = copiedPoint; } point = point.Next; } }
/// <summary>Adds the given path onto the end of this one.</summary> public void Append(VectorPath path) { if (LatestPathNode == null) { // This path just becomes the same as the given one: FirstPathNode = path.FirstPathNode; LatestPathNode = path.LatestPathNode; PathNodeCount = path.PathNodeCount; CloseNode = path.CloseNode; } else { // Add the first node: AddPathNode(path.FirstPathNode); LatestPathNode = path.LatestPathNode; // -1 because Add already added the first node. PathNodeCount += path.PathNodeCount - 1; CloseNode = path.CloseNode; } }
public override void RecalculateBounds(VectorPath path){ // Take control point into account too: if(Control2X<path.MinX){ path.MinX=Control2X; } if(Control2Y<path.MinY){ path.MinY=Control2Y; } // Width/height are used as max to save some memory: if(Control2X>path.Width){ path.Width=Control2X; } if(Control2Y>path.Height){ path.Height=Control2Y; } base.RecalculateBounds(path); }
public override VectorPoint DeleteControl(int id, VectorPath path) { // Create: QuadLinePoint pt = new QuadLinePoint(X, Y); if (id == 1) { // Deleting control point 1. pt.Control1X = Control2X; pt.Control1Y = Control2Y; } else { // Deleting control point 2. pt.Control1X = Control1X; pt.Control1Y = Control1Y; } // Remove this and add in it's place: ReplaceWith(pt, path); return(pt); }
/// <summary>Recalculates the minimum values and width/height of this path, taking curves into account.</summary> public virtual void RecalculateBounds(VectorPath path) { if (X < path.MinX) { path.MinX = X; } if (Y < path.MinY) { path.MinY = Y; } // Width/height are used as max to save some memory: if (X > path.Width) { path.Width = X; } if (Y > path.Height) { path.Height = Y; } }
public override void RecalculateBounds(VectorPath path) { // Take control point into account too: if (CircleCenterX < path.MinX) { path.MinX = CircleCenterX; } if (CircleCenterY < path.MinY) { path.MinY = CircleCenterY; } // Width/height are used as max to save some memory: if (CircleCenterX > path.Width) { path.Width = CircleCenterX; } if (CircleCenterY > path.Height) { path.Height = CircleCenterY; } // How much must we rotate through overall? float angleToRotateThrough = EndAngle - StartAngle; // How long is the arc? // First, what portion of a full circle is it: float circlePortion = angleToRotateThrough / ((float)Math.PI * 2f); // Next, what's the circumference of that circle // (and the above portion of it, thus the length of the arc): Length = 2f * (float)Math.PI * Radius * circlePortion; base.RecalculateBounds(path); }
public override VectorPoint Split(float t, VectorPath path) { // Create the next one: StraightLinePoint point = new StraightLinePoint(X, Y); // Get previous: float previousX = Previous.X; float previousY = Previous.Y; // Get deltas: float dx = X - previousX; float dy = Y - previousY; float nX = previousX + (t * dx); float nY = previousY + (t * dy); X = nX; Y = nY; path.PathNodeCount++; // Insert after this: if (Next == null) { path.LatestPathNode = point; } else { point.Next = Next; Next.Previous = point; } point.Previous = this; Next = point; return(point); }
public override void ExtrudeAndSample(VectorPath path, float extrudeBy, PointReceiverStepped sampler) { // First, cache all the points: float prevX = Previous.X; float prevY = Previous.Y; float x = X; float y = Y; // Get the normal and extrude along it. float normalX; float normalY; StartNormal(out normalX, out normalY); Previous.X += normalX * extrudeBy; Previous.Y += normalY * extrudeBy; X += normalX * extrudeBy; Y += normalY * extrudeBy; // Rebound: RecalculateBounds(path); if (sampler.IncludeFirstNode) { sampler.AddPoint(Previous.X, Previous.Y, 0f); } // Sample now: ComputeLinePoints(sampler); // Restore all the points: Previous.X = prevX; Previous.Y = prevY; X = x; Y = y; }
/// <summary>Requests to draw the given path at the given atlas location.</summary> public static void RequestDraw(AtlasLocation location, VectorPath path, float offsetX, float offsetY, float drawHeight) { DrawingTexture drawing = new DrawingTexture(); drawing.Location = location; drawing.Path = path; drawing.OffsetX = offsetX; drawing.OffsetY = offsetY; if (Camera == null) { Camera = new TextureCamera(CPUCopyMode); // Apply scale: Scale = drawHeight * Camera.WorldPerPixel.x; } if (Camera.IsDrawing || !Camera.TryFit(drawing)) { // Add to global pending queue: drawing.NextDrawing = Pending; Pending = drawing; } }
public override void RecalculateBounds(VectorPath path) { // Take control point into account too: if (Control1X < path.MinX) { path.MinX = Control1X; } if (Control1Y < path.MinY) { path.MinY = Control1Y; } // Width/height are used as max to save some memory: if (Control1X > path.Width) { path.Width = Control1X; } if (Control1Y > path.Height) { path.Height = Control1Y; } /* * // Start figuring out the length.. * float vaX=Previous.X-(2f*Control1X)+X; * float vaY=Previous.Y-(2f*Control1Y)+Y; * * float vbX=(2f*Control1X) - (2f*Previous.X); * float vbY=(2f*Control1Y) - (2f*Previous.Y); * * float a=4f*((vaX*vaX) + (vaY*vaY)); * * float b=4f*((vaX*vbX) + (vaY*vbY)); * * float c=(vbX*vbX) + (vbY*vbY); * * float rootABC = 2f*(float)Math.Sqrt(a+b+c); * float rootA = (float)Math.Sqrt(a); * float aRootA = 2f*a*rootA; * * if(aRootA==0f){ * * Length=0f; * * }else{ * * float rootC = 2f*(float)Math.Sqrt(c); * float bA = b/rootA; * * Length=( * aRootA * rootABC + rootA*b*(rootABC-rootC) + (4f*c*a - b*b)*(float)Math.Log( * (2f*rootA+bA+rootABC) / (bA+rootC) * ) * ) / (4f*aRootA); * * } */ // Start figuring out the length (very approximate).. float dx = Previous.X - Control1X; float dy = Previous.Y - Control1Y; double len = Math.Sqrt(dx * dx + dy * dy); dx = X - Control1X; dy = Y - Control1Y; len += Math.Sqrt(dx * dx + dy * dy); Length = (float)len; base.RecalculateBounds(path); }
//--------------------------------------
public void BaseBounds(VectorPath path) { base.RecalculateBounds(path); }
/// <summary>Rasterises a generic vector.</summary> public bool Rasterise(VectorPath glyph,Color32[] atlasPixels,int atlasWidth,int baseIndex,int width,int height,float hOffset,float vOffset,Color32 fill,bool clear){ if(glyph.FirstPathNode==null){ return false; } if(RequiresStart){ // Start now: Start(); } PreviousY=-1; // Offset the rasteriser: VerticalOffset=vOffset; HorizontalOffset=hOffset; if(Blurred){ // Add some space for the blur: width+=BlurSpread; height+=BlurSpread; } if(clear){ int atlasIndex=baseIndex; for(int i=0;i<height;i++){ // Clear the row: Array.Clear(atlasPixels,atlasIndex,width); atlasIndex+=atlasWidth; } } if(Blurred){ if( width > (DistanceCacheWidth * BlurSpread) ){ // Resize time! DistanceCacheWidth = ((width-1)/BlurSpread)+1; // Rebuild: CreateDistanceCache(); }else if(height > (DistanceCacheHeight * BlurSpread)){ // Resize time! DistanceCacheHeight = ((height-1)/BlurSpread)+1; // Rebuild: CreateDistanceCache(); }else{ // Clear the cache: ClearDistanceCache(); } } if(ScanLineBuffer==null || ScanLineBuffer.Length<=height){ // Create the shared buffer: ScanLineBuffer=new ScannerScanLine[height+1]; } // Clear the buffer: for(int i=0;i<=height;i++){ // Grab the line: ScannerScanLine line=ScanLineBuffer[i]; if(line==null){ // Create it now: ScanLineBuffer[i]=new ScannerScanLine(this); continue; } // Empty the line (into the pool): line.Clear(); } // For each line in the glyph, resolve it into a series of points. // Each one is at most one pixel away from the previous point. // Get the next point (exists due to check above): VectorPoint point=glyph.FirstPathNode; while(point!=null){ // Compute the points along the line which are fairly dense and regularly spaced (when possible): point.ComputeLinePoints(this); if((point.IsClose || point.Next==null) && LineChangeY!=-1 && MoveToY==-1){ // Test if we need to add our special point: if(LineChangeWentUp!=WentUp){ if(LineChangeY>=0 && LineChangeY<ScanLineBuffer.Length){ AddPixel(LineChangeX,LineChangeY); } } // Clear Y: LineChangeY=-1; } // Go to the next one: point=point.Next; } int blurOffset=HalfBlurSpread; // For each scan line, skipping the ones we know won't contain anything at this point: int verticalMax=height-blurOffset; // Stop only one blurspread from the end - we know there's nothing beyond that. int lineMax=width-blurOffset; // The current pixel index - offset over the blur spread: int pixelIndex=baseIndex + (atlasWidth * blurOffset); if(Blurred){ // SDF mode for(int i=blurOffset;i<verticalMax;i++){ // Grab the line: ScannerScanLine line=ScanLineBuffer[i]; if(line.First==null){ // Advance to the next line: pixelIndex+=atlasWidth; continue; } // Grab the first pixel (each one represents an intersect): ScannerPixel inwardPixel=line.First; while(inwardPixel!=null){ // Grab the next one: ScannerPixel outwardPixel=inwardPixel.Next; if(outwardPixel==null){ break; } // Index of the last pixel (exclusive): int max=outwardPixel.PixelIndex; if(max>lineMax){ // Clip it: max=lineMax; } // The section from inwardPixel to outwardPixel is filled. for(int p=inwardPixel.PixelIndex;p<max;p++){ // Fill: atlasPixels[pixelIndex+p]=fill; } if(outwardPixel==null){ // No more pairs: break; } // Go to the next intersect: inwardPixel=outwardPixel.Next; } // Advance to the next line: pixelIndex+=atlasWidth; } // "blur" time! int cacheSquareIndex=0; int blurSpread=BlurSpread; int atlasSize=atlasPixels.Length; // For each distance cache square.. for(int dY=0;dY<DistanceCacheHeight;dY++){ for(int dX=0;dX<DistanceCacheWidth;dX++){ // Get the square: DistanceCacheSquare currentSquare=DistanceCache[cacheSquareIndex]; pixelIndex=baseIndex+(currentSquare.PixelIndexY * atlasWidth)+currentSquare.PixelIndexX; if(currentSquare.InRange){ // Get the FX/FY: float squareFX=currentSquare.XOffset; float fY=currentSquare.YOffset; float fX=squareFX; // Grab the squares search set: DistanceCacheSquare[] toSearch=currentSquare.SearchSet; // How many? int searchCount=toSearch.Length; // Reset pixel index: pixelIndex=baseIndex+(currentSquare.PixelIndexY * atlasWidth)+currentSquare.PixelIndexX; // For each pixel in this square.. for(int y=0;y<blurSpread;y++){ if(pixelIndex>=atlasSize){ break; } for(int x=0;x<blurSpread;x++){ // Where's the pixel? int fullIndex=pixelIndex+x; if(fullIndex>=atlasSize){ break; } // Must be black otherwise we'll ignore it. if(atlasPixels[fullIndex].r!=0){ // It has colour. Skip. // Move float x along: fX++; continue; } // Start doing distance tests - look in all the nearest squares: float bestDistance=float.MaxValue; for(int i=0;i<searchCount;i++){ DistanceCacheSquare square=toSearch[i]; if(square.Count==0){ // Ignore empty square. continue; } // Temp grab the point set: List<DistanceCachePoint> points=square.Points; // How many points? int pointCount=points.Count; // For each node in the square, find the (relative) nearest. for(int p=0;p<pointCount;p++){ // Get the point: DistanceCachePoint cachePoint=points[p]; // Distance check: float deltaX=cachePoint.X - fX; float deltaY=cachePoint.Y - fY; // Full distance: float distance=(deltaX * deltaX) + (deltaY * deltaY); if(distance<bestDistance){ // Closest distance found: bestDistance=distance; } } } // Result value: byte distancePixel; if(bestDistance>MaxDistanceSquared){ // The pixel should be black: distancePixel=0; }else{ // Map the distance to an accurate distance, and put it in range: distancePixel=(byte)(255f-(Math.Sqrt(bestDistance) * DistanceAdjuster)); } // Write the result: atlasPixels[fullIndex]=new Color32(fill.r,fill.g,fill.b,distancePixel); // Move float x along: fX++; } // Move float y along: fY++; fX=squareFX; // Move pixel index up a row: pixelIndex+=atlasWidth; } } cacheSquareIndex++; } } }else{ // Got alpha? bool fillAlpha=(fill.a!=255 && !clear); // "Invert" fill alpha: int alphaInvert=255-fill.a; int fillRA=fill.r * fill.a; int fillGA=fill.g * fill.a; int fillBA=fill.b * fill.a; for(int i=blurOffset;i<verticalMax;i++){ // Grab the line: ScannerScanLine line=ScanLineBuffer[i]; if(line.First==null){ // Advance to the next line: pixelIndex+=atlasWidth; continue; } // Grab the first pixel (each one represents an intersect): ScannerPixel inwardPixel=line.First; while(inwardPixel!=null){ // Grab the next one: ScannerPixel outwardPixel=inwardPixel.Next; if(outwardPixel==null){ break; } // Index of the last pixel (exclusive): int max=outwardPixel.PixelIndex; if(max>lineMax){ // Clip it: max=lineMax; } // The section from inwardPixel to outwardPixel is filled. if(fillAlpha){ for(int p=inwardPixel.PixelIndex;p<max;p++){ // Get the index: int index=pixelIndex+p; // Grab the colour: Color32 colour=atlasPixels[index]; // Alpha blend: int dstA=(colour.a * alphaInvert) / 255; int cA=fill.a + dstA; colour.a=(byte)cA; colour.r=(byte) ((fillRA + colour.r * dstA)/cA); colour.g=(byte) ((fillGA + colour.g * dstA)/cA); colour.b=(byte) ((fillBA + colour.b * dstA)/cA); // Fill: atlasPixels[index]=colour; } }else{ for(int p=inwardPixel.PixelIndex;p<max;p++){ // Fill: atlasPixels[pixelIndex+p]=fill; } } if(outwardPixel==null){ // No more pairs: break; } // Go to the next intersect: inwardPixel=outwardPixel.Next; } // Advance to the next line: pixelIndex+=atlasWidth; } } return true; /* // Create the output. SubScanPixel[][] intersects=new SubScanPixel[height][]; for(int i=0;i<height;i++){ // Flatten the scan line into the pixel buffer: intersects[i]=ScanLineBuffer[i].Flatten(); } // Finally create the raster: RasterGlyph raster=new RasterGlyph(); // Apply intersects: raster.Intersects=intersects; // Apply width: raster.Width=width; return raster; */ }
public CurveSampler(VectorPath path) { Path = path; }