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 }