kernel DistanceFieldGenerator < namespace : "www.zspline.net"; vendor : "Zoltan Erdokovy"; version : 2; description : "Distance field generator"; > { input image4 Image; output pixel4 ActPixel; parameter int Iterations < minValue: 2; maxValue: 256; defaultValue: 8; >; parameter int SelectionPreview < minValue : 0; maxValue : 1; defaultValue : 1; parameterType : "enum"; enumValues : "OFF|ON"; >; parameter int4 Selection < //stepInterval: 64; // Doesn't seem to work, so we multiply the values by 64 later on. // Step size is important when processing an image piece by piece: // we don't want to process already done areas. Discrete steps make // this easier. minValue: int4(0,0,0,0); maxValue: int4(64,64,64,64); // Since it will be multiplied by 64 the max image size is 4096. defaultValue: int4(0,0,16,16); // Translates to 0,0,1024,1024. >; parameter int Mode < minValue : 0; maxValue : 2; defaultValue : 0; parameterType : "enum"; enumValues : "Normal|Inside|RedToGreen"; >; /*void DrawPixel(float2 InCoord, float2 InLocation, float3 InColor, float InThreshold) { if ((abs(InCoord.x - InLocation.x) 0.5) rounded = 1.0; return rounded; } float ProcessPixel(float2 InCoord, pixel4 InPixel, float2 InLocation, float InStoredDistance) { pixel4 OtherPixel; float Distance = 0.0; float TempDistance = 0.0; OtherPixel = sampleNearest(Image, InLocation); Distance = distance(InCoord, InLocation); TempDistance = InStoredDistance; if (Mode == 2) // If its RedToGreen mode... { if ((Round(OtherPixel.g) == 1.0) && (Distance < InStoredDistance)) TempDistance = Distance; } else // If its Normal or Inside mode... { // Black input pixel means outer distance check. if (Round(InPixel.r) == 0.0) { if ((Round(OtherPixel.r) == 1.0) && (Distance < InStoredDistance)) TempDistance = Distance; } // White or red input pixel means inner distance check. else if ((Round(OtherPixel.r) == 0.0) && (Distance < InStoredDistance)) TempDistance = Distance; } return TempDistance; } void evaluatePixel() { float StoredDistance = float(Iterations); float2 Coord = float2(0.0,0.0); float Radius; float f; float ddF_x; float ddF_y; float x; float y; Coord = outCoord(); ActPixel = sampleNearest(Image,Coord); // We only process pixels in the current selection. if ((Coord.x >= float(Selection.r*64)) && (Coord.y >= float(Selection.g*64)) && (Coord.x <= float(Selection.b*64)) && (Coord.y <= float(Selection.a*64))) { if (SelectionPreview == 1) // If Selection Preview is enabled then we don't compute stuff only show selection rectangle. { ActPixel.rgba = float4(Round(ActPixel.r),0.0,((1.0-Round(ActPixel.r))/4.0),1.0); } else if ((Mode == 0) ^^ ((Mode > 0) && (Round(ActPixel.r) == 1.0))) // The condition for processing a pixel. { { for (Radius=1.0; Radius < float(Iterations); Radius++) // Start to check around the current pixel in an ever growing circle. { f = 1.0 - Radius; ddF_x = 1.0; ddF_y = -2.0 * Radius; x = 0.0; y = Radius; StoredDistance = ProcessPixel(Coord,ActPixel,float2(Coord.x,Coord.y+Radius),StoredDistance); StoredDistance = ProcessPixel(Coord,ActPixel,float2(Coord.x,Coord.y-Radius),StoredDistance); StoredDistance = ProcessPixel(Coord,ActPixel,float2(Coord.x+Radius,Coord.y),StoredDistance); StoredDistance = ProcessPixel(Coord,ActPixel,float2(Coord.x-Radius,Coord.y),StoredDistance); while(x < y) { // ddF_x == 2 * x + 1; // ddF_y == -2 * y; // f == x*x + y*y - radius*radius + 2*x - y + 1; if(f >= 0.0) { y--; ddF_y += 2.0; f += ddF_y; } x++; ddF_x += 2.0; f += ddF_x; StoredDistance = ProcessPixel(Coord,ActPixel,float2(Coord.x+x,Coord.y+y),StoredDistance); StoredDistance = ProcessPixel(Coord,ActPixel,float2(Coord.x-x,Coord.y+y),StoredDistance); StoredDistance = ProcessPixel(Coord,ActPixel,float2(Coord.x+x,Coord.y-y),StoredDistance); StoredDistance = ProcessPixel(Coord,ActPixel,float2(Coord.x-x,Coord.y-y),StoredDistance); StoredDistance = ProcessPixel(Coord,ActPixel,float2(Coord.x+y,Coord.y+x),StoredDistance); StoredDistance = ProcessPixel(Coord,ActPixel,float2(Coord.x-y,Coord.y+x),StoredDistance); StoredDistance = ProcessPixel(Coord,ActPixel,float2(Coord.x+y,Coord.y-x),StoredDistance); StoredDistance = ProcessPixel(Coord,ActPixel,float2(Coord.x-y,Coord.y-x),StoredDistance); } if (StoredDistance < float(Iterations)) break; // When and if we found a pixel of interest then we won't // search any further away from the pixel. } if (Round(ActPixel.r) == 0.0) // If black pixel... { StoredDistance = (float(Iterations)-StoredDistance)/float(Iterations)/2.0; ActPixel.rgb = float3(StoredDistance); } else // If white pixel... { if (Mode > 0) { ActPixel.rgb = float3((StoredDistance/float(Iterations))+(1.0/float(Iterations))); } else { // | Set range to 0..1 | Shift down a bit to get 0.5 at the low end.| StoredDistance = (((float(Iterations)-StoredDistance)/float(Iterations)+(1.0/float(Iterations)))/2.0); ActPixel.rgb = float3(1.0-StoredDistance); } } } } } } }