/**
*
* Copyright (c) 2014, the Railo Company Ltd. All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*
**/
package lucee.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();
@Override
public float evaluate(float x) {
return evaluate(x, .1f);
}
@Override
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;
}
@Override
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;
}
}