package railo.runtime.img.math; import java.util.Random; /** * Sparse Convolution Noise. This is computationally very expensive, but worth it. */ public class SCNoise implements Function1D, Function2D, Function3D { private static Random randomGenerator = new Random(); public float evaluate(float x) { return evaluate(x, .1f); } public float evaluate(float x, float y) { int i, j, h, n; int ix, iy; float sum = 0; float fx, fy, dx, dy, distsq; if (impulseTab == null) impulseTab = impulseTabInit(665); ix = floor(x); fx = x - ix; iy = floor(y); fy = y - iy; /* Perform the sparse convolution. */ int m = 2; for (i = -m; i <= m; i++) { for (j = -m; j <= m; j++) { /* Compute voxel hash code. */ h = perm[(ix+i + perm[(iy+j)&TABMASK])&TABMASK]; for (n = NIMPULSES; n > 0; n--, h = (h+1) & TABMASK) { /* Convolve filter and impulse. */ int h4 = h*4; dx = fx - (i + impulseTab[h4++]); dy = fy - (j + impulseTab[h4++]); distsq = dx*dx + dy*dy; sum += catrom2(distsq) * impulseTab[h4]; } } } return sum / NIMPULSES; } public float evaluate(float x, float y, float z) { int i, j, k, h, n; int ix, iy, iz; float sum = 0; float fx, fy, fz, dx, dy, dz, distsq; if (impulseTab == null) impulseTab = impulseTabInit(665); ix = floor(x); fx = x - ix; iy = floor(y); fy = y - iy; iz = floor(z); fz = z - iz; /* Perform the sparse convolution. */ int m = 2; for (i = -m; i <= m; i++) { for (j = -m; j <= m; j++) { for (k = -m; k <= m; k++) { /* Compute voxel hash code. */ h = perm[(ix+i + perm[(iy+j + perm[(iz+k)&TABMASK])&TABMASK])&TABMASK]; for (n = NIMPULSES; n > 0; n--, h = (h+1) & TABMASK) { /* Convolve filter and impulse. */ int h4 = h*4; dx = fx - (i + impulseTab[h4++]); dy = fy - (j + impulseTab[h4++]); dz = fz - (k + impulseTab[h4++]); distsq = dx*dx + dy*dy + dz*dz; sum += catrom2(distsq) * impulseTab[h4]; } } } } return sum / NIMPULSES; } public short[] perm = { 225,155,210,108,175,199,221,144,203,116, 70,213, 69,158, 33,252, 5, 82,173,133,222,139,174, 27, 9, 71, 90,246, 75,130, 91,191, 169,138, 2,151,194,235, 81, 7, 25,113,228,159,205,253,134,142, 248, 65,224,217, 22,121,229, 63, 89,103, 96,104,156, 17,201,129, 36, 8,165,110,237,117,231, 56,132,211,152, 20,181,111,239,218, 170,163, 51,172,157, 47, 80,212,176,250, 87, 49, 99,242,136,189, 162,115, 44, 43,124, 94,150, 16,141,247, 32, 10,198,223,255, 72, 53,131, 84, 57,220,197, 58, 50,208, 11,241, 28, 3,192, 62,202, 18,215,153, 24, 76, 41, 15,179, 39, 46, 55, 6,128,167, 23,188, 106, 34,187,140,164, 73,112,182,244,195,227, 13, 35, 77,196,185, 26,200,226,119, 31,123,168,125,249, 68,183,230,177,135,160,180, 12, 1,243,148,102,166, 38,238,251, 37,240,126, 64, 74,161, 40, 184,149,171,178,101, 66, 29, 59,146, 61,254,107, 42, 86,154, 4, 236,232,120, 21,233,209, 45, 98,193,114, 78, 19,206, 14,118,127, 48, 79,147, 85, 30,207,219, 54, 88,234,190,122, 95, 67,143,109, 137,214,145, 93, 92,100,245, 0,216,186, 60, 83,105, 97,204, 52 }; private final static int TABSIZE = 256; private final static int TABMASK = (TABSIZE-1); private final static int NIMPULSES = 3; private static float[] impulseTab; public static int floor(float x) { int ix = (int)x; if (x < 0 && x != ix) return ix-1; return ix; } private final static int SAMPRATE = 100; /* table entries per unit distance */ private final static int NENTRIES = (4*SAMPRATE+1); private static float[] table; public float catrom2(float d) { float x; int i; if (d >= 4) return 0; if (table == null) { table = new float[NENTRIES]; for (i = 0; i < NENTRIES; i++) { x = i/(float)SAMPRATE; x = (float)Math.sqrt(x); if (x < 1) table[i] = 0.5f * (2+x*x*(-5+x*3)); else table[i] = 0.5f * (4+x*(-8+x*(5-x))); } } d = d*SAMPRATE + 0.5f; i = floor(d); if (i >= NENTRIES) return 0; return table[i]; } static float[] impulseTabInit(int seed) { float[] impulseTab = new float[TABSIZE*4]; randomGenerator = new Random(seed); /* Set random number generator seed. */ for (int i = 0; i < TABSIZE; i++) { impulseTab[i++] = randomGenerator.nextFloat(); impulseTab[i++] = randomGenerator.nextFloat(); impulseTab[i++] = randomGenerator.nextFloat(); impulseTab[i++] = 1.0f - 2.0f*randomGenerator.nextFloat(); } return impulseTab; } }