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