1 module dminer.core.terrain; 2 3 import dminer.core.minetypes; 4 import dlangui.core.logger; 5 6 7 struct TerrainGen { 8 private int dx; 9 private int dy; 10 private int xpow; 11 private int ypow; 12 private short[] data; 13 private Random rnd; 14 private void diamond(int x, int y, int size, int offset) { 15 int avg = (get(x, y - size) + get(x + size, y) + get(x, y + size) + get(x - size, y)) >> 2; 16 set(x, y, avg + offset); 17 } 18 private void square(int x, int y, int size, int offset) { 19 int avg = (get(x - size, y - size) + get(x + size, y - size) + get(x - size, y + size) + get(x - size, y - size)) >> 2; 20 set(x, y, avg + offset); 21 } 22 23 this(int xbits, int zbits) { 24 xpow = xbits; 25 ypow = zbits; 26 dx = (1 << xpow) + 1; 27 dy = (1 << ypow) + 1; 28 data = new short[dx * dy]; 29 } 30 ~this() { 31 } 32 void filter(int range) { 33 short[] tmp = new short[dx * dy]; 34 int div = (range * 2 + 1) * (range * 2 + 1); 35 for (int y = 0; y < dy; y++) { 36 for (int x = 0; x < dx; x++) { 37 int s = 0; 38 for (int yy = -range; yy <= range; yy++) { 39 for (int xx = -range; xx <= range; xx++) { 40 s += get(x + xx, y + yy); 41 } 42 } 43 s /= div; 44 tmp[(y << ypow) + y + x] = cast(short)s; 45 } 46 } 47 int sz = dx * dy; 48 data[0 .. sz] = tmp[0 .. sz]; 49 } 50 51 void generate(int seed, short[] initData, int stepBits) { 52 Log.d("TerrainGen.generate(initData.length=", initData.length, " stepBits=", stepBits, ")"); 53 rnd.setSeed(seed); 54 int step = 1 << stepBits; 55 int index = 0; 56 for (int y = 0; y <= dy; y += step) { 57 for (int x = 0; x <= dx; x += step) { 58 set(x, y, initData[index++]); 59 } 60 } 61 Log.f("last index = ", index); 62 int half = step >> 1; 63 while (half > 0) { 64 Log.f("halfstep=", half); 65 int scale = step; 66 for (int y = half; y < dy; y += step) { 67 for (int x = half; x < dx; x++) { 68 square(x, y, half, rnd.nextInt(scale * 2) - scale); 69 } 70 } 71 for (int y = 0; y <= dy; y += half) { 72 for (int x = (y + half) % step; x <= dx; x += step) { 73 diamond(x, y, half, rnd.nextInt(scale * 2) - scale); 74 } 75 } 76 step >>= 1; 77 half >>= 1; 78 } 79 } 80 void generateWithScale(int seed, short[] initData, int stepBits, TerrainGen scaleMap) { 81 Log.d("TerrainGen.generateWithScale(initData.length=", initData.length, " stepBits=", stepBits, ")"); 82 rnd.setSeed(seed); 83 int step = 1 << stepBits; 84 int index = 0; 85 for (int y = 0; y <= dy; y += step) { 86 for (int x = 0; x <= dx; x += step) { 87 set(x, y, initData[index++]); 88 } 89 } 90 Log.f("last index = ", index); 91 int half = step >> 1; 92 while (half > 0) { 93 Log.f("halfstep=", half); 94 for (int y = half; y < dy; y += step) { 95 for (int x = half; x < dx; x++) { 96 int scale = (scaleMap.get(x, y) * step) >> 8; 97 scale = rnd.nextInt(scale * 2) - scale; 98 if (step < 4) 99 scale = 0; 100 square(x, y, half, scale); 101 } 102 } 103 for (int y = 0; y <= dy; y += half) { 104 for (int x = (y + half) % step; x <= dx; x += step) { 105 int scale = (scaleMap.get(x, y) * step) >> 8; 106 scale = rnd.nextInt(scale * 2) - scale; 107 if (step < 4) 108 scale = 0; 109 diamond(x, y, half, scale); 110 } 111 } 112 step >>= 1; 113 half >>= 1; 114 } 115 } 116 @property int width() { 117 return dx - 1; 118 } 119 @property int height() { 120 return dy - 1; 121 } 122 int get(int x, int y) { 123 if (x < 0 || y < 0 || x >= dx || y >= dy) 124 return 0; 125 return data[(y << ypow) + y + x]; 126 } 127 int getHeightDiff(int x, int y) { 128 import std.algorithm; 129 int h0 = get(x, y); 130 int h1 = get(x+1, y)-h0; 131 int h2 = get(x-1, y)-h0; 132 int h3 = get(x, y+1)-h0; 133 int h4 = get(x, y-1)-h0; 134 int mindh = min(h1, h2, h3, h4); 135 int maxdh = max(h1, h2, h3, h4); 136 return max(-mindh, maxdh); 137 } 138 void set(int x, int y, int value) { 139 if (x < 0 || y < 0 || x >= dx || y >= dy) 140 return; 141 if (value < -32767) 142 value = -32767; 143 if (value > 32767) 144 value = 32767; 145 data[(y << ypow) + y + x] = cast(short)value; 146 } 147 /// ensure that data is in range [minvalue, maxvalue] 148 void limit(int minvalue, int maxvalue) { 149 // find actual min/max 150 int minv, maxv; 151 minv = maxv = get(0, 0); 152 for (int y = 0; y <= dy; y++) { 153 for (int x = 0; x <= dx; x++) { 154 int v = get(x, y); 155 if (minv > v) 156 minv = v; 157 if (maxv < v) 158 maxv = v; 159 } 160 } 161 int mul = (maxvalue - minvalue); 162 int div = (maxv - minv); 163 if (div > 0) { 164 for (int y = 0; y <= dy; y++) { 165 for (int x = 0; x <= dx; x++) { 166 set(x, y, minvalue + (get(x, y) - minv) * mul / div); 167 } 168 } 169 } 170 } 171 } 172 173