public void CreateDistanceCache() { // Create the caches: DistanceCache = new DistanceCacheSquare[DistanceCacheWidth * DistanceCacheHeight]; // The cell square index: int index = 0; // For each cell.. for (int y = 0; y < DistanceCacheHeight; y++) { for (int x = 0; x < DistanceCacheWidth; x++) { // Create it: DistanceCache[index] = new DistanceCacheSquare(x, y, index); index++; } } index = 0; // For each cell.. for (int y = 0; y < DistanceCacheHeight; y++) { for (int x = 0; x < DistanceCacheWidth; x++) { // Set it up (done like this as it accesses other squares in cache): DistanceCache[index].Setup(this); index++; } } }
public void CreateDistanceCache(){ // Create the caches: DistanceCache=new DistanceCacheSquare[DistanceCacheWidth * DistanceCacheHeight]; // The cell square index: int index=0; // For each cell.. for(int y=0;y<DistanceCacheHeight;y++){ for(int x=0;x<DistanceCacheWidth;x++){ // Create it: DistanceCache[index]=new DistanceCacheSquare(x,y,index); index++; } } index=0; // For each cell.. for(int y=0;y<DistanceCacheHeight;y++){ for(int x=0;x<DistanceCacheWidth;x++){ // Set it up (done like this as it accesses other squares in cache): DistanceCache[index].Setup(this); index++; } } }
/// <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; */ }