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