00001 import java.util.*;
00002
00004
00015 public final class PerlinTerrainGenerator implements TerrainGenerator
00016 {
00017 private final int width;
00018 private final int height;
00019 private final int roughness;
00020 private final long seed;
00021
00022 public PerlinTerrainGenerator(final int width, final int height, final int roughness)
00023 {
00024 this(width, height, roughness, System.currentTimeMillis());
00025 }
00026
00027 public PerlinTerrainGenerator(final int width, final int height, final int roughness, final long seed)
00028 {
00029 this.width = width;
00030 this.height = height;
00031 this.roughness = roughness;
00032 this.seed = seed;
00033 }
00034
00035 public byte[][] getTerrain()
00036 {
00037 double [][] tempResult = new double[width][height];
00038 for(int scale = roughness; scale < 8; ++scale)
00039 {
00040 int [][] intermediate = generateOneOctave(width, height, seed + scale, 256 >> scale);
00041 for(int x = 0; x < width; ++x)
00042 for(int y = 0; y < height; ++y)
00043 tempResult[x][y] += ((double)intermediate[x][y]) / (2 << (scale - roughness));
00044 }
00045
00046 byte [][] result = new byte[width][height];
00047 for(int x = 0; x < width; ++x)
00048 for(int y = 0; y < height; ++y)
00049 result[x][y] = (byte)((int)tempResult[x][y]);
00050 return result;
00051 }
00052
00053 private int[][] generateOneOctave(final int width, final int height, final long seed, final double scale)
00054 {
00055 final ArrayList<ArrayList<Double>> G = new ArrayList<ArrayList<Double>>();
00056 final Random r = new Random(seed);
00057
00058 while(G.size() < 256)
00059 {
00060 while(true)
00061 {
00062 final double first = r.nextDouble() * 2 - 1;
00063 final double second = r.nextDouble() * 2 - 1;
00064
00065 final double length = Math.sqrt(first * first + second * second);
00066 if(length < 1.0)
00067 {
00068 final ArrayList<Double> newElem = new ArrayList<Double>();
00069 newElem.add(first / length);
00070 newElem.add(second / length);
00071 G.add(newElem);
00072 break;
00073 }
00074 }
00075 }
00076
00077 final int[] P = new int[256];
00078 for(int i = 0; i < P.length; i++)
00079 {
00080 P[i] = i;
00081 }
00082
00083 for(int i = P.length - 1; i > 0; i--)
00084 {
00085 final int index = r.nextInt(i);
00086 final int temp = P[index];
00087 P[index] = P[i];
00088 P[i] = temp;
00089 }
00090
00091 final int[][] result = new int[width][height];
00092 for(int x = 0; x < width; ++x)
00093 {
00094 for(int y = 0; y < height; ++y)
00095 {
00096 result[x][y] = (int) ((noise(x / scale, y / scale, P, G) + 1) * 128);
00097 }
00098 }
00099
00100 return result;
00101 }
00102
00103 private double drop(final double a)
00104 {
00105 final double b = Math.abs(a);
00106 return 1.0 - b * b * b * (b * (b * 6 - 15) + 10);
00107 }
00108
00109 private double Q(final double u, final double v)
00110 {
00111 return drop(u) * drop(v);
00112 }
00113
00114 private double dotProduct(final ArrayList<Double> b, final double[] a)
00115 {
00116 return a[0] * b.get(0) + a[1] * b.get(1);
00117 }
00118
00119 private double noise(final double x, final double y, final int[] P, final ArrayList<ArrayList<Double>> G)
00120 {
00121 final double[] cell = new double[] {Math.floor(x), Math.floor(y)};
00122
00123 double sum = 0.0;
00124 for(int r = 0; r <= 1; ++r)
00125 {
00126 for(int s = 0; s <= 1; ++s)
00127 {
00128 final double i = cell[0] + r;
00129 final double j = cell[1] + s;
00130
00131 final double[] uv = new double[] {x - i, y - j};
00132
00133 int index = P[(int) i];
00134 index = P[(index + (int) j) % P.length];
00135 final ArrayList<Double> grad = G.get(index % G.size());
00136 sum += Q(uv[0], uv[1]) * dotProduct(grad, uv);
00137 }
00138 }
00139
00140 return Math.max(Math.min(sum, 1.0), -1.0);
00141 }
00142 }