/// <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;
			*/
			
		}
示例#2
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;
             */
        }