示例#1
0
        /// <summary>Clears this scan line.</summary>
        public void Clear()
        {
            if (First == null)
            {
                return;
            }

            if (Scanner.PooledPixels < Scanner.MaxPoolCount)
            {
                // We're ok to add to the pool.
                // This will likely go over max, but that's fine - these things are tiny.

                Scanner.PooledPixels += Count;
                Last.Next             = Scanner.FirstPooled;
                Scanner.FirstPooled   = First;
            }

            First = null;
            Last  = null;
            Count = 0;
        }
		/// <summary>Clears this scan line.</summary>
		public void Clear(){
			
			if(First==null){
				return;
			}
			
			if(Scanner.PooledPixels<Scanner.MaxPoolCount){
				
				// We're ok to add to the pool.
				// This will likely go over max, but that's fine - these things are tiny.
				
				Scanner.PooledPixels+=Count;
				Last.Next=Scanner.FirstPooled;
				Scanner.FirstPooled=First;
			
			}
			
			First=null;
			Last=null;
			Count=0;
			
		}
示例#3
0
        /// <summary>Adds a given pixel to the scanline buffer.</summary>
        private void AddPixel(float x, int y)
        {
            ScannerPixel pixel;

            if (FirstPooled == null)
            {
                pixel = new ScannerPixel();
            }
            else
            {
                pixel       = FirstPooled;
                FirstPooled = pixel.Next;
                pixel.Next  = null;
                PooledPixels--;
            }

            // Set it up:
            pixel.X = x + HalfBlurSpread;

            // Add it:
            ScanLineBuffer[y].Add(pixel);
        }
示例#4
0
        /// <summary>Flattens this scan lines data into our base set of pixels.</summary>
        public SubScanPixel[] Flatten()
        {
            // Create the set:
            SubScanPixel[] set = new SubScanPixel[Count];

            // Copy each:
            ScannerPixel current = First;

            int index = 0;

            while (current != null)
            {
                // Create and add in our pixel:
                set[index] = new SubScanPixel((ushort)current.X, current.Fill);

                // Increase the index:
                index++;

                // Hop to the next one:
                current = current.Next;
            }

            return(set);
        }
示例#5
0
        /// <summary>Adds the given intersect pixel to this scan line.</summary>
        public void Add(ScannerPixel pixel)
        {
            // Clear prev/next:
            pixel.Previous = null;
            pixel.Next     = null;

            // Increase the count:
            Count++;

            if (First == null)
            {
                // One and only:
                First = Last = pixel;

                return;
            }

            if (pixel.X > Last.X)
            {
                // It's the furthest over. Stick it on the end:

                pixel.Previous = Last;
                Last           = Last.Next = pixel;
            }
            else
            {
                // Find the place it needs to go between:
                ScannerPixel current = Last;

                while (current != null)
                {
                    if (pixel.X <= current.X)
                    {
                        if (current.Previous != null)
                        {
                            if (pixel.X <= current.Previous.X)
                            {
                                current = current.Previous;
                                continue;
                            }

                            // Ensure next is connected too.
                            pixel.Previous = current.Previous;

                            pixel.Previous.Next = pixel;
                        }
                        else
                        {
                            // It goes at the start:
                            First = pixel;
                        }

                        // It goes before current.
                        pixel.Next = current;

                        current.Previous = pixel;

                        return;
                    }

                    current = current.Previous;
                }
            }
        }
		/// <summary>Adds a given pixel to the scanline buffer.</summary>
		private void AddPixel(float x,int y){
	
			ScannerPixel pixel;
			
			if(FirstPooled==null){
				pixel=new ScannerPixel();
			}else{
				pixel=FirstPooled;
				FirstPooled=pixel.Next;
				pixel.Next=null;
				PooledPixels--;
			}
			
			// Set it up:
			pixel.X=x + HalfBlurSpread;
			
			// Add it:
			ScanLineBuffer[y].Add(pixel);
			
		}
		/// <summary>Adds the given intersect pixel to this scan line.</summary>
		public void Add(ScannerPixel pixel){
			
			// Clear prev/next:
			pixel.Previous=null;
			pixel.Next=null;
			
			// Increase the count:
			Count++;
			
			if(First==null){
				
				// One and only:
				First=Last=pixel;
				
				return;
			}
			
			if(pixel.X>Last.X){
				
				// It's the furthest over. Stick it on the end:
				
				pixel.Previous=Last;
				Last=Last.Next=pixel;
			
			}else{
				
				// Find the place it needs to go between:
				ScannerPixel current=Last;
				
				while(current!=null){
					
					if(pixel.X<=current.X){
						
						if(current.Previous!=null){
							
							if(pixel.X<=current.Previous.X){
								
								current=current.Previous;
								continue;
								
							}
							
							// Ensure next is connected too.
							pixel.Previous=current.Previous;
							
							pixel.Previous.Next=pixel;
							
						}else{
							
							// It goes at the start:
							First=pixel;
							
						}
						
						// It goes before current.
						pixel.Next=current;
						
						current.Previous=pixel;
						
						return;
						
					}
					
					current=current.Previous;
				}
				
			}
			
		}
示例#8
0
        /// <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;
             */
        }