001    package railo.runtime.img.math;
002    
003    import java.util.Random;
004    
005    /**
006     * Sparse Convolution Noise. This is computationally very expensive, but worth it.
007     */
008    public class SCNoise implements Function1D, Function2D, Function3D {
009    
010            private static Random randomGenerator = new Random();
011            
012            public float evaluate(float x) {
013                    return evaluate(x, .1f);
014            }
015            
016            public float evaluate(float x, float y) {
017                    int i, j,  h, n;
018                    int ix, iy;
019                    float sum = 0;
020                    float fx, fy, dx, dy, distsq;
021    
022                    if (impulseTab == null)
023                            impulseTab = impulseTabInit(665);
024    
025                    ix = floor(x); fx = x - ix;
026                    iy = floor(y); fy = y - iy;
027                    
028                    /* Perform the sparse convolution. */
029                    int m = 2;
030                    for (i = -m; i <= m; i++) {
031                      for (j = -m; j <= m; j++) {
032                            /* Compute voxel hash code. */
033                            h = perm[(ix+i + perm[(iy+j)&TABMASK])&TABMASK];
034                            
035                            for (n = NIMPULSES; n > 0; n--, h = (h+1) & TABMASK) {
036                                    /* Convolve filter and impulse. */
037                                    int h4 = h*4;
038                                    dx = fx - (i + impulseTab[h4++]);
039                                    dy = fy - (j + impulseTab[h4++]);
040                                    distsq = dx*dx + dy*dy;
041                                    sum += catrom2(distsq) * impulseTab[h4];
042                            }
043                      }
044                    }
045    
046                    return sum / NIMPULSES;
047            }
048            
049            public float evaluate(float x, float y, float z) {
050                    int i, j, k, h, n;
051                    int ix, iy, iz;
052                    float sum = 0;
053                    float fx, fy, fz, dx, dy, dz, distsq;
054    
055                    if (impulseTab == null)
056                            impulseTab = impulseTabInit(665);
057    
058                    ix = floor(x); fx = x - ix;
059                    iy = floor(y); fy = y - iy;
060                    iz = floor(z); fz = z - iz;
061                    
062                    /* Perform the sparse convolution. */
063                    int m = 2;
064                    for (i = -m; i <= m; i++) {
065                      for (j = -m; j <= m; j++) {
066                            for (k = -m; k <= m; k++) {
067                                    /* Compute voxel hash code. */
068                                    h = perm[(ix+i + perm[(iy+j + perm[(iz+k)&TABMASK])&TABMASK])&TABMASK];
069                                    
070                                    for (n = NIMPULSES; n > 0; n--, h = (h+1) & TABMASK) {
071                                            /* Convolve filter and impulse. */
072                                            int h4 = h*4;
073                                            dx = fx - (i + impulseTab[h4++]);
074                                            dy = fy - (j + impulseTab[h4++]);
075                                            dz = fz - (k + impulseTab[h4++]);
076                                            distsq = dx*dx + dy*dy + dz*dz;
077                                            sum += catrom2(distsq) * impulseTab[h4];
078                                    }
079                            }
080                      }
081                    }
082    
083                    return sum / NIMPULSES;
084            }
085            
086            public short[] perm = {
087                            225,155,210,108,175,199,221,144,203,116, 70,213, 69,158, 33,252,
088                              5, 82,173,133,222,139,174, 27,  9, 71, 90,246, 75,130, 91,191,
089                            169,138,  2,151,194,235, 81,  7, 25,113,228,159,205,253,134,142,
090                            248, 65,224,217, 22,121,229, 63, 89,103, 96,104,156, 17,201,129,
091                             36,  8,165,110,237,117,231, 56,132,211,152, 20,181,111,239,218,
092                            170,163, 51,172,157, 47, 80,212,176,250, 87, 49, 99,242,136,189,
093                            162,115, 44, 43,124, 94,150, 16,141,247, 32, 10,198,223,255, 72,
094                             53,131, 84, 57,220,197, 58, 50,208, 11,241, 28,  3,192, 62,202,
095                             18,215,153, 24, 76, 41, 15,179, 39, 46, 55,  6,128,167, 23,188,
096                            106, 34,187,140,164, 73,112,182,244,195,227, 13, 35, 77,196,185,
097                             26,200,226,119, 31,123,168,125,249, 68,183,230,177,135,160,180,
098                             12,  1,243,148,102,166, 38,238,251, 37,240,126, 64, 74,161, 40,
099                            184,149,171,178,101, 66, 29, 59,146, 61,254,107, 42, 86,154,  4,
100                            236,232,120, 21,233,209, 45, 98,193,114, 78, 19,206, 14,118,127,
101                             48, 79,147, 85, 30,207,219, 54, 88,234,190,122, 95, 67,143,109,
102                            137,214,145, 93, 92,100,245,  0,216,186, 60, 83,105, 97,204, 52
103            };
104    
105            private final static int TABSIZE = 256;
106            private final static int TABMASK = (TABSIZE-1);
107            private final static int NIMPULSES = 3;
108    
109            private static float[] impulseTab;
110    
111            public static int floor(float x) {
112                    int ix = (int)x;
113                    if (x < 0 && x != ix)
114                            return ix-1;
115                    return ix;
116            }
117    
118            private final static int SAMPRATE = 100;  /* table entries per unit distance */
119            private final static int NENTRIES = (4*SAMPRATE+1);
120            private static float[] table;
121    
122            public float catrom2(float d) {
123                    float x;
124                    int i;
125    
126                    if (d >= 4)
127                            return 0;
128    
129                    if (table == null) {
130                            table = new float[NENTRIES];
131                            for (i = 0; i < NENTRIES; i++) {
132                                    x = i/(float)SAMPRATE;
133                                    x = (float)Math.sqrt(x);
134                                    if (x < 1)
135                                            table[i] = 0.5f * (2+x*x*(-5+x*3));
136                                    else
137                                            table[i] = 0.5f * (4+x*(-8+x*(5-x)));
138                            }
139                    }
140    
141                    d = d*SAMPRATE + 0.5f;
142                    i = floor(d);
143                    if (i >= NENTRIES)
144                            return 0;
145                    return table[i];
146            }
147    
148            static float[] impulseTabInit(int seed) {
149                    float[] impulseTab = new float[TABSIZE*4];
150    
151                    randomGenerator = new Random(seed); /* Set random number generator seed. */
152                    for (int i = 0; i < TABSIZE; i++) {
153                            impulseTab[i++] = randomGenerator.nextFloat();
154                            impulseTab[i++] = randomGenerator.nextFloat();
155                            impulseTab[i++] = randomGenerator.nextFloat();
156                            impulseTab[i++] = 1.0f - 2.0f*randomGenerator.nextFloat();
157                    }
158                    
159                    return impulseTab;
160            }
161            
162    }