001    package org.bukkit.util.noise;
002    
003    import java.util.Random;
004    import org.bukkit.World;
005    
006    /**
007     * Generates noise using the "classic" perlin generator
008     *
009     * @see SimplexNoiseGenerator "Improved" and faster version with slighly
010     *     different results
011     */
012    public class PerlinNoiseGenerator extends NoiseGenerator {
013        protected static final int grad3[][] = {{1, 1, 0}, {-1, 1, 0}, {1, -1, 0}, {-1, -1, 0},
014            {1, 0, 1}, {-1, 0, 1}, {1, 0, -1}, {-1, 0, -1},
015            {0, 1, 1}, {0, -1, 1}, {0, 1, -1}, {0, -1, -1}};
016        private static final PerlinNoiseGenerator instance = new PerlinNoiseGenerator();
017    
018        protected PerlinNoiseGenerator() {
019            int p[] = {151, 160, 137, 91, 90, 15, 131, 13, 201,
020                95, 96, 53, 194, 233, 7, 225, 140, 36, 103, 30, 69, 142, 8, 99, 37,
021                240, 21, 10, 23, 190, 6, 148, 247, 120, 234, 75, 0, 26, 197, 62,
022                94, 252, 219, 203, 117, 35, 11, 32, 57, 177, 33, 88, 237, 149, 56,
023                87, 174, 20, 125, 136, 171, 168, 68, 175, 74, 165, 71, 134, 139,
024                48, 27, 166, 77, 146, 158, 231, 83, 111, 229, 122, 60, 211, 133,
025                230, 220, 105, 92, 41, 55, 46, 245, 40, 244, 102, 143, 54, 65, 25,
026                63, 161, 1, 216, 80, 73, 209, 76, 132, 187, 208, 89, 18, 169, 200,
027                196, 135, 130, 116, 188, 159, 86, 164, 100, 109, 198, 173, 186, 3,
028                64, 52, 217, 226, 250, 124, 123, 5, 202, 38, 147, 118, 126, 255,
029                82, 85, 212, 207, 206, 59, 227, 47, 16, 58, 17, 182, 189, 28, 42,
030                223, 183, 170, 213, 119, 248, 152, 2, 44, 154, 163, 70, 221, 153,
031                101, 155, 167, 43, 172, 9, 129, 22, 39, 253, 19, 98, 108, 110, 79,
032                113, 224, 232, 178, 185, 112, 104, 218, 246, 97, 228, 251, 34, 242,
033                193, 238, 210, 144, 12, 191, 179, 162, 241, 81, 51, 145, 235, 249,
034                14, 239, 107, 49, 192, 214, 31, 181, 199, 106, 157, 184, 84, 204,
035                176, 115, 121, 50, 45, 127, 4, 150, 254, 138, 236, 205, 93, 222,
036                114, 67, 29, 24, 72, 243, 141, 128, 195, 78, 66, 215, 61, 156, 180};
037    
038            for (int i = 0; i < 512; i++) {
039                perm[i] = p[i & 255];
040            }
041        }
042    
043        /**
044         * Creates a seeded perlin noise generator for the given world
045         *
046         * @param world World to construct this generator for
047         */
048        public PerlinNoiseGenerator(World world) {
049            this(new Random(world.getSeed()));
050        }
051    
052        /**
053         * Creates a seeded perlin noise generator for the given seed
054         *
055         * @param seed Seed to construct this generator for
056         */
057        public PerlinNoiseGenerator(long seed) {
058            this(new Random(seed));
059        }
060    
061        /**
062         * Creates a seeded perlin noise generator with the given Random
063         *
064         * @param rand Random to construct with
065         */
066        public PerlinNoiseGenerator(Random rand) {
067            offsetX = rand.nextDouble() * 256;
068            offsetY = rand.nextDouble() * 256;
069            offsetZ = rand.nextDouble() * 256;
070    
071            for (int i = 0; i < 256; i++) {
072                perm[i] = rand.nextInt(256);
073            }
074    
075            for (int i = 0; i < 256; i++) {
076                int pos = rand.nextInt(256 - i) + i;
077                int old = perm[i];
078    
079                perm[i] = perm[pos];
080                perm[pos] = old;
081                perm[i + 256] = perm[i];
082            }
083        }
084    
085        /**
086         * Computes and returns the 1D unseeded perlin noise for the given
087         * coordinates in 1D space
088         *
089         * @param x X coordinate
090         * @return Noise at given location, from range -1 to 1
091         */
092        public static double getNoise(double x) {
093            return instance.noise(x);
094        }
095    
096        /**
097         * Computes and returns the 2D unseeded perlin noise for the given
098         * coordinates in 2D space
099         *
100         * @param x X coordinate
101         * @param y Y coordinate
102         * @return Noise at given location, from range -1 to 1
103         */
104        public static double getNoise(double x, double y) {
105            return instance.noise(x, y);
106        }
107    
108        /**
109         * Computes and returns the 3D unseeded perlin noise for the given
110         * coordinates in 3D space
111         *
112         * @param x X coordinate
113         * @param y Y coordinate
114         * @param z Z coordinate
115         * @return Noise at given location, from range -1 to 1
116         */
117        public static double getNoise(double x, double y, double z) {
118            return instance.noise(x, y, z);
119        }
120    
121        /**
122         * Gets the singleton unseeded instance of this generator
123         *
124         * @return Singleton
125         */
126        public static PerlinNoiseGenerator getInstance() {
127            return instance;
128        }
129    
130        @Override
131        public double noise(double x, double y, double z) {
132            x += offsetX;
133            y += offsetY;
134            z += offsetZ;
135    
136            int floorX = floor(x);
137            int floorY = floor(y);
138            int floorZ = floor(z);
139    
140            // Find unit cube containing the point
141            int X = floorX & 255;
142            int Y = floorY & 255;
143            int Z = floorZ & 255;
144    
145            // Get relative xyz coordinates of the point within the cube
146            x -= floorX;
147            y -= floorY;
148            z -= floorZ;
149    
150            // Compute fade curves for xyz
151            double fX = fade(x);
152            double fY = fade(y);
153            double fZ = fade(z);
154    
155            // Hash coordinates of the cube corners
156            int A = perm[X] + Y;
157            int AA = perm[A] + Z;
158            int AB = perm[A + 1] + Z;
159            int B = perm[X + 1] + Y;
160            int BA = perm[B] + Z;
161            int BB = perm[B + 1] + Z;
162    
163            return lerp(fZ, lerp(fY, lerp(fX, grad(perm[AA], x, y, z),
164                            grad(perm[BA], x - 1, y, z)),
165                        lerp(fX, grad(perm[AB], x, y - 1, z),
166                            grad(perm[BB], x - 1, y - 1, z))),
167                    lerp(fY, lerp(fX, grad(perm[AA + 1], x, y, z - 1),
168                            grad(perm[BA + 1], x - 1, y, z - 1)),
169                        lerp(fX, grad(perm[AB + 1], x, y - 1, z - 1),
170                            grad(perm[BB + 1], x - 1, y - 1, z - 1))));
171        }
172    
173        /**
174         * Generates noise for the 1D coordinates using the specified number of
175         * octaves and parameters
176         *
177         * @param x X-coordinate
178         * @param octaves Number of octaves to use
179         * @param frequency How much to alter the frequency by each octave
180         * @param amplitude How much to alter the amplitude by each octave
181         * @return Resulting noise
182         */
183        public static double getNoise(double x, int octaves, double frequency, double amplitude) {
184            return instance.noise(x, octaves, frequency, amplitude);
185        }
186    
187        /**
188         * Generates noise for the 2D coordinates using the specified number of
189         * octaves and parameters
190         *
191         * @param x X-coordinate
192         * @param y Y-coordinate
193         * @param octaves Number of octaves to use
194         * @param frequency How much to alter the frequency by each octave
195         * @param amplitude How much to alter the amplitude by each octave
196         * @return Resulting noise
197         */
198        public static double getNoise(double x, double y, int octaves, double frequency, double amplitude) {
199            return instance.noise(x, y, octaves, frequency, amplitude);
200        }
201    
202        /**
203         * Generates noise for the 3D coordinates using the specified number of
204         * octaves and parameters
205         *
206         * @param x X-coordinate
207         * @param y Y-coordinate
208         * @param z Z-coordinate
209         * @param octaves Number of octaves to use
210         * @param frequency How much to alter the frequency by each octave
211         * @param amplitude How much to alter the amplitude by each octave
212         * @return Resulting noise
213         */
214        public static double getNoise(double x, double y, double z, int octaves, double frequency, double amplitude) {
215            return instance.noise(x, y, z, octaves, frequency, amplitude);
216        }
217    }