/* Delauney --------- Uses Delauney triangulation of random points to generate the tileable texture. Author : Andreas Jonsson Created: July 23rd, 2005 Updated: July 28th, 2005 Texture Generator version 1.1.0 */ const int numPoints = 200; const int imageSize = 256; // Sort the points by x and y void sort(float[]@ points) { // A simple bubble sort since we won't handle a lot of points for( int a = 2; a < numPoints*2; a += 2 ) { for( int b = a; b > 0; b -= 2 ) { if( points[b] < points[b-2] ) { float swap = points[b]; points[b] = points[b-2]; points[b-2] = swap; swap = points[b+1]; points[b+1] = points[b-1]; points[b-1] = swap; } else break; } } } float abs(float val) { return val < 0 ? -val : val; } int findClosest(float[]@ points, float x, float y, float &out dist, int idx) { // Find the point closest in x, then look for points closer in y float d = abs(points[idx*2] - x); int max = numPoints; int min = 0; for(;;) { if( idx+1 < numPoints && abs(points[(idx+1)*2] - x) < d ) { idx += 1; min = idx; idx += (max-idx)/2; } else if( idx-1 >= 0 && abs(points[(idx-1)*2] - x) < d ) { idx -= 1; max = idx; idx -= (idx-min)/2; } else break; d = abs(points[idx*2] - x); if( idx == 0 || idx == numPoints-1 ) break; } // idx now holds the point closest in x // Find the closest point, including the distance in the y axis int bestIdx = idx; float bestDist = sqrt((points[idx*2] - x)*(points[idx*2] - x) + (points[idx*2+1] - y)*(points[idx*2+1] - y)); int idx2 = idx; for(;;) { if( idx2 >= numPoints ) idx2 -= numPoints; // Make the distances wrap around the texture float px = points[idx2*2]; if( px - x > imageSize/2 ) px -= imageSize; if( px - x < -imageSize/2 ) px += imageSize; if( abs(px - x) >= bestDist ) break; float py = points[idx2*2+1]; if( py - y > imageSize/2 ) py -= imageSize; if( py - y < -imageSize/2 ) py += imageSize; d = sqrt((px - x)*(px - x) + (py - y)*(py - y)); if( d < bestDist ) { bestIdx = idx2; bestDist = d; } idx2++; } idx2 = idx-1; for(;;) { if( idx2 < 0 ) idx2 += numPoints; // Make the distances wrap around the texture float px = points[idx2*2]; if( px - x > imageSize/2 ) px -= imageSize; if( px - x < -imageSize/2 ) px += imageSize; if( abs(px - x) >= bestDist ) break; float py = points[idx2*2+1]; if( py - y > imageSize/2 ) py -= imageSize; if( py - y < -imageSize/2 ) py += imageSize; d = sqrt((px - x)*(px - x) + (py - y)*(py - y)); if( d < bestDist ) { bestIdx = idx2; bestDist = d; } idx2--; } dist = bestDist; return bestIdx; } void main() { float[] points(numPoints*2); randomizer rnd; rnd.randomize(); for( int n = 0; n < numPoints*2; n++ ) points[n] = rnd.getNumber()*imageSize; sort(@points); image img(imageSize,imageSize); for( int n = 0; n < numPoints*2; n += 2 ) { img.Pixel(points[n],points[n+1]) = pixel(1.0f,1.0f,1.0f); } int idx = numPoints/2; for( int x = 0; x < imageSize; x++ ) { for( int y = 0; y < imageSize; y++ ) { float dist = 0; idx = findClosest(@points, x, y, dist, idx); img.Alpha(x,y) = dist; img.Red(x,y) = idx; } } detectEdges(@img); showDistances(@img); } void detectEdges(image@ img) { image edges(imageSize,imageSize); for( int y = 0; y < imageSize; y++ ) { for( int x = 0; x < imageSize; x++ ) { float c = 1; if( img.Red(x,y) != img.Red((x+1)%imageSize,y) ) c -= 0.25; if( img.Red(x,y) != img.Red(x,(y+1)%imageSize) ) c -= 0.25; if( img.Red(x,(y+1)%imageSize) != img.Red((x+1)%imageSize,(y+1)%imageSize) ) c -= 0.25; if( img.Red((x+1)%imageSize,y) != img.Red((x+1)%imageSize,(y+1)%imageSize) ) c -= 0.25; edges.Pixel(x,y) = pixel(c,c,c); } } edges.Show(); } void showDistances(image@ img) { float maxDist = 0; image dist(imageSize,imageSize); for( int y = 0; y < imageSize; y++ ) { for( int x = 0; x < imageSize; x++ ) { if( img.Alpha(x,y) > maxDist ) maxDist = img.Alpha(x,y); } } float distRecip = 1/maxDist; for( int y = 0; y < imageSize; y++ ) { for( int x = 0; x < imageSize; x++ ) { float d = distRecip * (maxDist - img.Alpha(x,y)); dist.Pixel(x,y) = pixel(d,d,d); } } dist.Show(); }