mg_ore.cpp 12 KB

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