]> git.lizzy.rs Git - minetest.git/blob - src/mg_ore.cpp
Snake case for screen options in minetest.conf (#5792)
[minetest.git] / src / mg_ore.cpp
1 /*
2 Minetest
3 Copyright (C) 2014-2016 kwolekr, Ryan Kwolek <kwolekr@minetest.net>
4 Copyright (C) 2015-2017 paramat
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU Lesser General Public License as published by
8 the Free Software Foundation; either version 2.1 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 GNU Lesser General Public License for more details.
15
16 You should have received a copy of the GNU Lesser General Public License along
17 with this program; if not, write to the Free Software Foundation, Inc.,
18 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 */
20
21 #include "mg_ore.h"
22 #include "mapgen.h"
23 #include "noise.h"
24 #include "map.h"
25 #include "log.h"
26 #include <algorithm>
27
28
29 FlagDesc flagdesc_ore[] = {
30         {"absheight",                 OREFLAG_ABSHEIGHT},
31         {"puff_cliffs",               OREFLAG_PUFF_CLIFFS},
32         {"puff_additive_composition", OREFLAG_PUFF_ADDITIVE},
33         {NULL,                        0}
34 };
35
36
37 ///////////////////////////////////////////////////////////////////////////////
38
39
40 OreManager::OreManager(IGameDef *gamedef) :
41         ObjDefManager(gamedef, OBJDEF_ORE)
42 {
43 }
44
45
46 size_t OreManager::placeAllOres(Mapgen *mg, u32 blockseed, v3s16 nmin, v3s16 nmax)
47 {
48         size_t nplaced = 0;
49
50         for (size_t i = 0; i != m_objects.size(); i++) {
51                 Ore *ore = (Ore *)m_objects[i];
52                 if (!ore)
53                         continue;
54
55                 nplaced += ore->placeOre(mg, blockseed, nmin, nmax);
56                 blockseed++;
57         }
58
59         return nplaced;
60 }
61
62
63 void OreManager::clear()
64 {
65         for (size_t i = 0; i < m_objects.size(); i++) {
66                 Ore *ore = (Ore *)m_objects[i];
67                 delete ore;
68         }
69         m_objects.clear();
70 }
71
72
73 ///////////////////////////////////////////////////////////////////////////////
74
75
76 Ore::Ore()
77 {
78         flags = 0;
79         noise = NULL;
80 }
81
82
83 Ore::~Ore()
84 {
85         delete noise;
86 }
87
88
89 void Ore::resolveNodeNames()
90 {
91         getIdFromNrBacklog(&c_ore, "", CONTENT_AIR);
92         getIdsFromNrBacklog(&c_wherein);
93 }
94
95
96 size_t Ore::placeOre(Mapgen *mg, u32 blockseed, v3s16 nmin, v3s16 nmax)
97 {
98         int in_range = 0;
99
100         in_range |= (nmin.Y <= y_max && nmax.Y >= y_min);
101         if (flags & OREFLAG_ABSHEIGHT)
102                 in_range |= (nmin.Y >= -y_max && nmax.Y <= -y_min) << 1;
103         if (!in_range)
104                 return 0;
105
106         int actual_ymin, actual_ymax;
107         if (in_range & ORE_RANGE_MIRROR) {
108                 actual_ymin = MYMAX(nmin.Y, -y_max);
109                 actual_ymax = MYMIN(nmax.Y, -y_min);
110         } else {
111                 actual_ymin = MYMAX(nmin.Y, y_min);
112                 actual_ymax = MYMIN(nmax.Y, y_max);
113         }
114         if (clust_size >= actual_ymax - actual_ymin + 1)
115                 return 0;
116
117         nmin.Y = actual_ymin;
118         nmax.Y = actual_ymax;
119         generate(mg->vm, mg->seed, blockseed, nmin, nmax, mg->biomemap);
120
121         return 1;
122 }
123
124
125 ///////////////////////////////////////////////////////////////////////////////
126
127
128 void OreScatter::generate(MMVManip *vm, int mapseed, u32 blockseed,
129         v3s16 nmin, v3s16 nmax, u8 *biomemap)
130 {
131         PcgRandom pr(blockseed);
132         MapNode n_ore(c_ore, 0, ore_param2);
133
134         u32 sizex  = (nmax.X - nmin.X + 1);
135         u32 volume = (nmax.X - nmin.X + 1) *
136                                  (nmax.Y - nmin.Y + 1) *
137                                  (nmax.Z - nmin.Z + 1);
138         u32 csize     = clust_size;
139         u32 cvolume    = csize * csize * csize;
140         u32 nclusters = volume / clust_scarcity;
141
142         for (u32 i = 0; i != nclusters; i++) {
143                 int x0 = pr.range(nmin.X, nmax.X - csize + 1);
144                 int y0 = pr.range(nmin.Y, nmax.Y - csize + 1);
145                 int z0 = pr.range(nmin.Z, nmax.Z - csize + 1);
146
147                 if ((flags & OREFLAG_USE_NOISE) &&
148                         (NoisePerlin3D(&np, x0, y0, z0, mapseed) < nthresh))
149                         continue;
150
151                 if (biomemap && !biomes.empty()) {
152                         u32 index = sizex * (z0 - nmin.Z) + (x0 - nmin.X);
153                         UNORDERED_SET<u8>::iterator it = biomes.find(biomemap[index]);
154                         if (it == biomes.end())
155                                 continue;
156                 }
157
158                 for (u32 z1 = 0; z1 != csize; z1++)
159                 for (u32 y1 = 0; y1 != csize; y1++)
160                 for (u32 x1 = 0; x1 != csize; x1++) {
161                         if (pr.range(1, cvolume) > clust_num_ores)
162                                 continue;
163
164                         u32 i = vm->m_area.index(x0 + x1, y0 + y1, z0 + z1);
165                         if (!CONTAINS(c_wherein, vm->m_data[i].getContent()))
166                                 continue;
167
168                         vm->m_data[i] = n_ore;
169                 }
170         }
171 }
172
173
174 ///////////////////////////////////////////////////////////////////////////////
175
176
177 void OreSheet::generate(MMVManip *vm, int mapseed, u32 blockseed,
178         v3s16 nmin, v3s16 nmax, u8 *biomemap)
179 {
180         PcgRandom pr(blockseed + 4234);
181         MapNode n_ore(c_ore, 0, ore_param2);
182
183         u16 max_height = column_height_max;
184         int y_start_min = nmin.Y + max_height;
185         int y_start_max = nmax.Y - max_height;
186
187         int y_start = y_start_min < y_start_max ?
188                 pr.range(y_start_min, y_start_max) :
189                 (y_start_min + y_start_max) / 2;
190
191         if (!noise) {
192                 int sx = nmax.X - nmin.X + 1;
193                 int sz = nmax.Z - nmin.Z + 1;
194                 noise = new Noise(&np, 0, sx, sz);
195         }
196         noise->seed = mapseed + y_start;
197         noise->perlinMap2D(nmin.X, nmin.Z);
198
199         size_t index = 0;
200         for (int z = nmin.Z; z <= nmax.Z; z++)
201         for (int x = nmin.X; x <= nmax.X; x++, index++) {
202                 float noiseval = noise->result[index];
203                 if (noiseval < nthresh)
204                         continue;
205
206                 if (biomemap && !biomes.empty()) {
207                         UNORDERED_SET<u8>::iterator it = biomes.find(biomemap[index]);
208                         if (it == biomes.end())
209                                 continue;
210                 }
211
212                 u16 height = pr.range(column_height_min, column_height_max);
213                 int ymidpoint = y_start + noiseval;
214                 int y0 = MYMAX(nmin.Y, ymidpoint - height * (1 - column_midpoint_factor));
215                 int y1 = MYMIN(nmax.Y, y0 + height - 1);
216
217                 for (int y = y0; y <= y1; y++) {
218                         u32 i = vm->m_area.index(x, y, z);
219                         if (!vm->m_area.contains(i))
220                                 continue;
221                         if (!CONTAINS(c_wherein, vm->m_data[i].getContent()))
222                                 continue;
223
224                         vm->m_data[i] = n_ore;
225                 }
226         }
227 }
228
229
230 ///////////////////////////////////////////////////////////////////////////////
231
232 OrePuff::OrePuff() :
233         Ore()
234 {
235         noise_puff_top    = NULL;
236         noise_puff_bottom = NULL;
237 }
238
239
240 OrePuff::~OrePuff()
241 {
242         delete noise_puff_top;
243         delete noise_puff_bottom;
244 }
245
246
247 void OrePuff::generate(MMVManip *vm, int mapseed, u32 blockseed,
248         v3s16 nmin, v3s16 nmax, u8 *biomemap)
249 {
250         PcgRandom pr(blockseed + 4234);
251         MapNode n_ore(c_ore, 0, ore_param2);
252
253         int y_start = pr.range(nmin.Y, nmax.Y);
254
255         if (!noise) {
256                 int sx = nmax.X - nmin.X + 1;
257                 int sz = nmax.Z - nmin.Z + 1;
258                 noise = new Noise(&np, 0, sx, sz);
259                 noise_puff_top = new Noise(&np_puff_top, 0, sx, sz);
260                 noise_puff_bottom = new Noise(&np_puff_bottom, 0, sx, sz);
261         }
262
263         noise->seed = mapseed + y_start;
264         noise->perlinMap2D(nmin.X, nmin.Z);
265         bool noise_generated = false;
266
267         size_t index = 0;
268         for (int z = nmin.Z; z <= nmax.Z; z++)
269         for (int x = nmin.X; x <= nmax.X; x++, index++) {
270                 float noiseval = noise->result[index];
271                 if (noiseval < nthresh)
272                         continue;
273
274                 if (biomemap && !biomes.empty()) {
275                         UNORDERED_SET<u8>::iterator it = biomes.find(biomemap[index]);
276                         if (it == biomes.end())
277                                 continue;
278                 }
279
280                 if (!noise_generated) {
281                         noise_generated = true;
282                         noise_puff_top->perlinMap2D(nmin.X, nmin.Z);
283                         noise_puff_bottom->perlinMap2D(nmin.X, nmin.Z);
284                 }
285
286                 float ntop    = noise_puff_top->result[index];
287                 float nbottom = noise_puff_bottom->result[index];
288
289                 if (!(flags & OREFLAG_PUFF_CLIFFS)) {
290                         float ndiff = noiseval - nthresh;
291                         if (ndiff < 1.0f) {
292                                 ntop *= ndiff;
293                                 nbottom *= ndiff;
294                         }
295                 }
296
297                 int ymid = y_start;
298                 int y0 = ymid - nbottom;
299                 int y1 = ymid + ntop;
300
301                 if ((flags & OREFLAG_PUFF_ADDITIVE) && (y0 > y1))
302                         SWAP(int, y0, y1);
303
304                 for (int y = y0; y <= y1; y++) {
305                         u32 i = vm->m_area.index(x, y, z);
306                         if (!vm->m_area.contains(i))
307                                 continue;
308                         if (!CONTAINS(c_wherein, vm->m_data[i].getContent()))
309                                 continue;
310
311                         vm->m_data[i] = n_ore;
312                 }
313         }
314 }
315
316
317 ///////////////////////////////////////////////////////////////////////////////
318
319
320 void OreBlob::generate(MMVManip *vm, int mapseed, u32 blockseed,
321         v3s16 nmin, v3s16 nmax, u8 *biomemap)
322 {
323         PcgRandom pr(blockseed + 2404);
324         MapNode n_ore(c_ore, 0, ore_param2);
325
326         u32 sizex  = (nmax.X - nmin.X + 1);
327         u32 volume = (nmax.X - nmin.X + 1) *
328                                  (nmax.Y - nmin.Y + 1) *
329                                  (nmax.Z - nmin.Z + 1);
330         u32 csize  = clust_size;
331         u32 nblobs = volume / clust_scarcity;
332
333         if (!noise)
334                 noise = new Noise(&np, mapseed, csize, csize, csize);
335
336         for (u32 i = 0; i != nblobs; i++) {
337                 int x0 = pr.range(nmin.X, nmax.X - csize + 1);
338                 int y0 = pr.range(nmin.Y, nmax.Y - csize + 1);
339                 int z0 = pr.range(nmin.Z, nmax.Z - csize + 1);
340
341                 if (biomemap && !biomes.empty()) {
342                         u32 bmapidx = sizex * (z0 - nmin.Z) + (x0 - nmin.X);
343                         UNORDERED_SET<u8>::iterator it = biomes.find(biomemap[bmapidx]);
344                         if (it == biomes.end())
345                                 continue;
346                 }
347
348                 bool noise_generated = false;
349                 noise->seed = blockseed + i;
350
351                 size_t index = 0;
352                 for (u32 z1 = 0; z1 != csize; z1++)
353                 for (u32 y1 = 0; y1 != csize; y1++)
354                 for (u32 x1 = 0; x1 != csize; x1++, index++) {
355                         u32 i = vm->m_area.index(x0 + x1, y0 + y1, z0 + z1);
356                         if (!CONTAINS(c_wherein, vm->m_data[i].getContent()))
357                                 continue;
358
359                         // Lazily generate noise only if there's a chance of ore being placed
360                         // This simple optimization makes calls 6x faster on average
361                         if (!noise_generated) {
362                                 noise_generated = true;
363                                 noise->perlinMap3D(x0, y0, z0);
364                         }
365
366                         float noiseval = noise->result[index];
367
368                         float xdist = (s32)x1 - (s32)csize / 2;
369                         float ydist = (s32)y1 - (s32)csize / 2;
370                         float zdist = (s32)z1 - (s32)csize / 2;
371
372                         noiseval -= (sqrt(xdist * xdist + ydist * ydist + zdist * zdist) / csize);
373
374                         if (noiseval < nthresh)
375                                 continue;
376
377                         vm->m_data[i] = n_ore;
378                 }
379         }
380 }
381
382
383 ///////////////////////////////////////////////////////////////////////////////
384
385 OreVein::OreVein() :
386         Ore()
387 {
388         noise2 = NULL;
389 }
390
391
392 OreVein::~OreVein()
393 {
394         delete noise2;
395 }
396
397
398 void OreVein::generate(MMVManip *vm, int mapseed, u32 blockseed,
399         v3s16 nmin, v3s16 nmax, u8 *biomemap)
400 {
401         PcgRandom pr(blockseed + 520);
402         MapNode n_ore(c_ore, 0, ore_param2);
403
404         u32 sizex = (nmax.X - nmin.X + 1);
405
406         if (!noise) {
407                 int sx = nmax.X - nmin.X + 1;
408                 int sy = nmax.Y - nmin.Y + 1;
409                 int sz = nmax.Z - nmin.Z + 1;
410                 noise  = new Noise(&np, mapseed, sx, sy, sz);
411                 noise2 = new Noise(&np, mapseed + 436, sx, sy, sz);
412         }
413         bool noise_generated = false;
414
415         size_t index = 0;
416         for (int z = nmin.Z; z <= nmax.Z; z++)
417         for (int y = nmin.Y; y <= nmax.Y; y++)
418         for (int x = nmin.X; x <= nmax.X; x++, index++) {
419                 u32 i = vm->m_area.index(x, y, z);
420                 if (!vm->m_area.contains(i))
421                         continue;
422                 if (!CONTAINS(c_wherein, vm->m_data[i].getContent()))
423                         continue;
424
425                 if (biomemap && !biomes.empty()) {
426                         u32 bmapidx = sizex * (z - nmin.Z) + (x - nmin.X);
427                         UNORDERED_SET<u8>::iterator it = biomes.find(biomemap[bmapidx]);
428                         if (it == biomes.end())
429                                 continue;
430                 }
431
432                 // Same lazy generation optimization as in OreBlob
433                 if (!noise_generated) {
434                         noise_generated = true;
435                         noise->perlinMap3D(nmin.X, nmin.Y, nmin.Z);
436                         noise2->perlinMap3D(nmin.X, nmin.Y, nmin.Z);
437                 }
438
439                 // randval ranges from -1..1
440                 float randval   = (float)pr.next() / (pr.RANDOM_RANGE / 2) - 1.f;
441                 float noiseval  = contour(noise->result[index]);
442                 float noiseval2 = contour(noise2->result[index]);
443                 if (noiseval * noiseval2 + randval * random_factor < nthresh)
444                         continue;
445
446                 vm->m_data[i] = n_ore;
447         }
448 }