mapgen_fractal.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448
  1. /*
  2. Minetest
  3. Copyright (C) 2015-2019 paramat
  4. Copyright (C) 2015-2016 kwolekr, Ryan Kwolek
  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 "mapgen.h"
  18. #include <cmath>
  19. #include "voxel.h"
  20. #include "noise.h"
  21. #include "mapblock.h"
  22. #include "mapnode.h"
  23. #include "map.h"
  24. #include "nodedef.h"
  25. #include "voxelalgorithms.h"
  26. //#include "profiler.h" // For TimeTaker
  27. #include "settings.h" // For g_settings
  28. #include "emerge.h"
  29. #include "dungeongen.h"
  30. #include "cavegen.h"
  31. #include "mg_biome.h"
  32. #include "mg_ore.h"
  33. #include "mg_decoration.h"
  34. #include "mapgen_fractal.h"
  35. FlagDesc flagdesc_mapgen_fractal[] = {
  36. {"terrain", MGFRACTAL_TERRAIN},
  37. {NULL, 0}
  38. };
  39. ///////////////////////////////////////////////////////////////////////////////////////
  40. MapgenFractal::MapgenFractal(MapgenFractalParams *params, EmergeParams *emerge)
  41. : MapgenBasic(MAPGEN_FRACTAL, params, emerge)
  42. {
  43. spflags = params->spflags;
  44. cave_width = params->cave_width;
  45. large_cave_depth = params->large_cave_depth;
  46. small_cave_num_min = params->small_cave_num_min;
  47. small_cave_num_max = params->small_cave_num_max;
  48. large_cave_num_min = params->large_cave_num_min;
  49. large_cave_num_max = params->large_cave_num_max;
  50. large_cave_flooded = params->large_cave_flooded;
  51. dungeon_ymin = params->dungeon_ymin;
  52. dungeon_ymax = params->dungeon_ymax;
  53. fractal = params->fractal;
  54. iterations = params->iterations;
  55. scale = params->scale;
  56. offset = params->offset;
  57. slice_w = params->slice_w;
  58. julia_x = params->julia_x;
  59. julia_y = params->julia_y;
  60. julia_z = params->julia_z;
  61. julia_w = params->julia_w;
  62. //// 2D noise
  63. if (spflags & MGFRACTAL_TERRAIN)
  64. noise_seabed = new Noise(&params->np_seabed, seed, csize.X, csize.Z);
  65. noise_filler_depth = new Noise(&params->np_filler_depth, seed, csize.X, csize.Z);
  66. //// 3D noise
  67. MapgenBasic::np_dungeons = params->np_dungeons;
  68. // Overgeneration to node_min.Y - 1
  69. MapgenBasic::np_cave1 = params->np_cave1;
  70. MapgenBasic::np_cave2 = params->np_cave2;
  71. formula = fractal / 2 + fractal % 2;
  72. julia = fractal % 2 == 0;
  73. }
  74. MapgenFractal::~MapgenFractal()
  75. {
  76. delete noise_seabed;
  77. delete noise_filler_depth;
  78. }
  79. MapgenFractalParams::MapgenFractalParams():
  80. np_seabed (-14, 9, v3f(600, 600, 600), 41900, 5, 0.6, 2.0),
  81. np_filler_depth (0, 1.2, v3f(150, 150, 150), 261, 3, 0.7, 2.0),
  82. np_cave1 (0, 12, v3f(61, 61, 61), 52534, 3, 0.5, 2.0),
  83. np_cave2 (0, 12, v3f(67, 67, 67), 10325, 3, 0.5, 2.0),
  84. np_dungeons (0.9, 0.5, v3f(500, 500, 500), 0, 2, 0.8, 2.0)
  85. {
  86. }
  87. void MapgenFractalParams::readParams(const Settings *settings)
  88. {
  89. settings->getFlagStrNoEx("mgfractal_spflags", spflags, flagdesc_mapgen_fractal);
  90. settings->getFloatNoEx("mgfractal_cave_width", cave_width);
  91. settings->getS16NoEx("mgfractal_large_cave_depth", large_cave_depth);
  92. settings->getU16NoEx("mgfractal_small_cave_num_min", small_cave_num_min);
  93. settings->getU16NoEx("mgfractal_small_cave_num_max", small_cave_num_max);
  94. settings->getU16NoEx("mgfractal_large_cave_num_min", large_cave_num_min);
  95. settings->getU16NoEx("mgfractal_large_cave_num_max", large_cave_num_max);
  96. settings->getFloatNoEx("mgfractal_large_cave_flooded", large_cave_flooded);
  97. settings->getS16NoEx("mgfractal_dungeon_ymin", dungeon_ymin);
  98. settings->getS16NoEx("mgfractal_dungeon_ymax", dungeon_ymax);
  99. settings->getU16NoEx("mgfractal_fractal", fractal);
  100. settings->getU16NoEx("mgfractal_iterations", iterations);
  101. settings->getV3FNoEx("mgfractal_scale", scale);
  102. settings->getV3FNoEx("mgfractal_offset", offset);
  103. settings->getFloatNoEx("mgfractal_slice_w", slice_w);
  104. settings->getFloatNoEx("mgfractal_julia_x", julia_x);
  105. settings->getFloatNoEx("mgfractal_julia_y", julia_y);
  106. settings->getFloatNoEx("mgfractal_julia_z", julia_z);
  107. settings->getFloatNoEx("mgfractal_julia_w", julia_w);
  108. settings->getNoiseParams("mgfractal_np_seabed", np_seabed);
  109. settings->getNoiseParams("mgfractal_np_filler_depth", np_filler_depth);
  110. settings->getNoiseParams("mgfractal_np_cave1", np_cave1);
  111. settings->getNoiseParams("mgfractal_np_cave2", np_cave2);
  112. settings->getNoiseParams("mgfractal_np_dungeons", np_dungeons);
  113. iterations = std::max<u16>(iterations, 1);
  114. }
  115. void MapgenFractalParams::writeParams(Settings *settings) const
  116. {
  117. settings->setFlagStr("mgfractal_spflags", spflags, flagdesc_mapgen_fractal);
  118. settings->setFloat("mgfractal_cave_width", cave_width);
  119. settings->setS16("mgfractal_large_cave_depth", large_cave_depth);
  120. settings->setU16("mgfractal_small_cave_num_min", small_cave_num_min);
  121. settings->setU16("mgfractal_small_cave_num_max", small_cave_num_max);
  122. settings->setU16("mgfractal_large_cave_num_min", large_cave_num_min);
  123. settings->setU16("mgfractal_large_cave_num_max", large_cave_num_max);
  124. settings->setFloat("mgfractal_large_cave_flooded", large_cave_flooded);
  125. settings->setS16("mgfractal_dungeon_ymin", dungeon_ymin);
  126. settings->setS16("mgfractal_dungeon_ymax", dungeon_ymax);
  127. settings->setU16("mgfractal_fractal", fractal);
  128. settings->setU16("mgfractal_iterations", iterations);
  129. settings->setV3F("mgfractal_scale", scale);
  130. settings->setV3F("mgfractal_offset", offset);
  131. settings->setFloat("mgfractal_slice_w", slice_w);
  132. settings->setFloat("mgfractal_julia_x", julia_x);
  133. settings->setFloat("mgfractal_julia_y", julia_y);
  134. settings->setFloat("mgfractal_julia_z", julia_z);
  135. settings->setFloat("mgfractal_julia_w", julia_w);
  136. settings->setNoiseParams("mgfractal_np_seabed", np_seabed);
  137. settings->setNoiseParams("mgfractal_np_filler_depth", np_filler_depth);
  138. settings->setNoiseParams("mgfractal_np_cave1", np_cave1);
  139. settings->setNoiseParams("mgfractal_np_cave2", np_cave2);
  140. settings->setNoiseParams("mgfractal_np_dungeons", np_dungeons);
  141. }
  142. void MapgenFractalParams::setDefaultSettings(Settings *settings)
  143. {
  144. settings->setDefault("mgfractal_spflags", flagdesc_mapgen_fractal,
  145. MGFRACTAL_TERRAIN);
  146. }
  147. /////////////////////////////////////////////////////////////////
  148. int MapgenFractal::getSpawnLevelAtPoint(v2s16 p)
  149. {
  150. bool solid_below = false; // Fractal node is present below to spawn on
  151. u8 air_count = 0; // Consecutive air nodes above a fractal node
  152. s16 search_start = 0; // No terrain search start
  153. // If terrain present, don't start search below terrain or water level
  154. if (noise_seabed) {
  155. s16 seabed_level = NoisePerlin2D(&noise_seabed->np, p.X, p.Y, seed);
  156. search_start = MYMAX(search_start, MYMAX(seabed_level, water_level));
  157. }
  158. for (s16 y = search_start; y <= search_start + 4096; y++) {
  159. if (getFractalAtPoint(p.X, y, p.Y)) {
  160. // Fractal node
  161. solid_below = true;
  162. air_count = 0;
  163. } else if (solid_below) {
  164. // Air above fractal node
  165. air_count++;
  166. // 3 and -2 to account for biome dust nodes
  167. if (air_count == 3)
  168. return y - 2;
  169. }
  170. }
  171. return MAX_MAP_GENERATION_LIMIT; // Unsuitable spawn point
  172. }
  173. void MapgenFractal::makeChunk(BlockMakeData *data)
  174. {
  175. // Pre-conditions
  176. assert(data->vmanip);
  177. assert(data->nodedef);
  178. //TimeTaker t("makeChunk");
  179. this->generating = true;
  180. this->vm = data->vmanip;
  181. this->ndef = data->nodedef;
  182. v3s16 blockpos_min = data->blockpos_min;
  183. v3s16 blockpos_max = data->blockpos_max;
  184. node_min = blockpos_min * MAP_BLOCKSIZE;
  185. node_max = (blockpos_max + v3s16(1, 1, 1)) * MAP_BLOCKSIZE - v3s16(1, 1, 1);
  186. full_node_min = (blockpos_min - 1) * MAP_BLOCKSIZE;
  187. full_node_max = (blockpos_max + 2) * MAP_BLOCKSIZE - v3s16(1, 1, 1);
  188. blockseed = getBlockSeed2(full_node_min, seed);
  189. // Generate fractal and optional terrain
  190. s16 stone_surface_max_y = generateTerrain();
  191. // Create heightmap
  192. updateHeightmap(node_min, node_max);
  193. // Init biome generator, place biome-specific nodes, and build biomemap
  194. if (flags & MG_BIOMES) {
  195. biomegen->calcBiomeNoise(node_min);
  196. generateBiomes();
  197. }
  198. // Generate tunnels and randomwalk caves
  199. if (flags & MG_CAVES) {
  200. generateCavesNoiseIntersection(stone_surface_max_y);
  201. generateCavesRandomWalk(stone_surface_max_y, large_cave_depth);
  202. }
  203. // Generate the registered ores
  204. if (flags & MG_ORES)
  205. m_emerge->oremgr->placeAllOres(this, blockseed, node_min, node_max);
  206. // Generate dungeons
  207. if (flags & MG_DUNGEONS)
  208. generateDungeons(stone_surface_max_y);
  209. // Generate the registered decorations
  210. if (flags & MG_DECORATIONS)
  211. m_emerge->decomgr->placeAllDecos(this, blockseed, node_min, node_max);
  212. // Sprinkle some dust on top after everything else was generated
  213. if (flags & MG_BIOMES)
  214. dustTopNodes();
  215. // Update liquids
  216. if (spflags & MGFRACTAL_TERRAIN)
  217. updateLiquid(&data->transforming_liquid, full_node_min, full_node_max);
  218. // Calculate lighting
  219. if (flags & MG_LIGHT)
  220. calcLighting(node_min - v3s16(0, 1, 0), node_max + v3s16(0, 1, 0),
  221. full_node_min, full_node_max);
  222. this->generating = false;
  223. //printf("makeChunk: %lums\n", t.stop());
  224. }
  225. bool MapgenFractal::getFractalAtPoint(s16 x, s16 y, s16 z)
  226. {
  227. float cx, cy, cz, cw, ox, oy, oz, ow;
  228. if (julia) { // Julia set
  229. cx = julia_x;
  230. cy = julia_y;
  231. cz = julia_z;
  232. cw = julia_w;
  233. ox = (float)x / scale.X - offset.X;
  234. oy = (float)y / scale.Y - offset.Y;
  235. oz = (float)z / scale.Z - offset.Z;
  236. ow = slice_w;
  237. } else { // Mandelbrot set
  238. cx = (float)x / scale.X - offset.X;
  239. cy = (float)y / scale.Y - offset.Y;
  240. cz = (float)z / scale.Z - offset.Z;
  241. cw = slice_w;
  242. ox = 0.0f;
  243. oy = 0.0f;
  244. oz = 0.0f;
  245. ow = 0.0f;
  246. }
  247. float nx = 0.0f;
  248. float ny = 0.0f;
  249. float nz = 0.0f;
  250. float nw = 0.0f;
  251. for (u16 iter = 0; iter < iterations; iter++) {
  252. switch (formula) {
  253. default:
  254. case 1: // 4D "Roundy"
  255. nx = ox * ox - oy * oy - oz * oz - ow * ow + cx;
  256. ny = 2.0f * (ox * oy + oz * ow) + cy;
  257. nz = 2.0f * (ox * oz + oy * ow) + cz;
  258. nw = 2.0f * (ox * ow + oy * oz) + cw;
  259. break;
  260. case 2: // 4D "Squarry"
  261. nx = ox * ox - oy * oy - oz * oz - ow * ow + cx;
  262. ny = 2.0f * (ox * oy + oz * ow) + cy;
  263. nz = 2.0f * (ox * oz + oy * ow) + cz;
  264. nw = 2.0f * (ox * ow - oy * oz) + cw;
  265. break;
  266. case 3: // 4D "Mandy Cousin"
  267. nx = ox * ox - oy * oy - oz * oz + ow * ow + cx;
  268. ny = 2.0f * (ox * oy + oz * ow) + cy;
  269. nz = 2.0f * (ox * oz + oy * ow) + cz;
  270. nw = 2.0f * (ox * ow + oy * oz) + cw;
  271. break;
  272. case 4: // 4D "Variation"
  273. nx = ox * ox - oy * oy - oz * oz - ow * ow + cx;
  274. ny = 2.0f * (ox * oy + oz * ow) + cy;
  275. nz = 2.0f * (ox * oz - oy * ow) + cz;
  276. nw = 2.0f * (ox * ow + oy * oz) + cw;
  277. break;
  278. case 5: // 3D "Mandelbrot/Mandelbar"
  279. nx = ox * ox - oy * oy - oz * oz + cx;
  280. ny = 2.0f * ox * oy + cy;
  281. nz = -2.0f * ox * oz + cz;
  282. break;
  283. case 6: // 3D "Christmas Tree"
  284. // Altering the formula here is necessary to avoid division by zero
  285. if (std::fabs(oz) < 0.000000001f) {
  286. nx = ox * ox - oy * oy - oz * oz + cx;
  287. ny = 2.0f * oy * ox + cy;
  288. nz = 4.0f * oz * ox + cz;
  289. } else {
  290. float a = (2.0f * ox) / (std::sqrt(oy * oy + oz * oz));
  291. nx = ox * ox - oy * oy - oz * oz + cx;
  292. ny = a * (oy * oy - oz * oz) + cy;
  293. nz = a * 2.0f * oy * oz + cz;
  294. }
  295. break;
  296. case 7: // 3D "Mandelbulb"
  297. if (std::fabs(oy) < 0.000000001f) {
  298. nx = ox * ox - oz * oz + cx;
  299. ny = cy;
  300. nz = -2.0f * oz * std::sqrt(ox * ox) + cz;
  301. } else {
  302. float a = 1.0f - (oz * oz) / (ox * ox + oy * oy);
  303. nx = (ox * ox - oy * oy) * a + cx;
  304. ny = 2.0f * ox * oy * a + cy;
  305. nz = -2.0f * oz * std::sqrt(ox * ox + oy * oy) + cz;
  306. }
  307. break;
  308. case 8: // 3D "Cosine Mandelbulb"
  309. if (std::fabs(oy) < 0.000000001f) {
  310. nx = 2.0f * ox * oz + cx;
  311. ny = 4.0f * oy * oz + cy;
  312. nz = oz * oz - ox * ox - oy * oy + cz;
  313. } else {
  314. float a = (2.0f * oz) / std::sqrt(ox * ox + oy * oy);
  315. nx = (ox * ox - oy * oy) * a + cx;
  316. ny = 2.0f * ox * oy * a + cy;
  317. nz = oz * oz - ox * ox - oy * oy + cz;
  318. }
  319. break;
  320. case 9: // 4D "Mandelbulb"
  321. float rxy = std::sqrt(ox * ox + oy * oy);
  322. float rxyz = std::sqrt(ox * ox + oy * oy + oz * oz);
  323. if (std::fabs(ow) < 0.000000001f && std::fabs(oz) < 0.000000001f) {
  324. nx = (ox * ox - oy * oy) + cx;
  325. ny = 2.0f * ox * oy + cy;
  326. nz = -2.0f * rxy * oz + cz;
  327. nw = 2.0f * rxyz * ow + cw;
  328. } else {
  329. float a = 1.0f - (ow * ow) / (rxyz * rxyz);
  330. float b = a * (1.0f - (oz * oz) / (rxy * rxy));
  331. nx = (ox * ox - oy * oy) * b + cx;
  332. ny = 2.0f * ox * oy * b + cy;
  333. nz = -2.0f * rxy * oz * a + cz;
  334. nw = 2.0f * rxyz * ow + cw;
  335. }
  336. break;
  337. }
  338. if (nx * nx + ny * ny + nz * nz + nw * nw > 4.0f)
  339. return false;
  340. ox = nx;
  341. oy = ny;
  342. oz = nz;
  343. ow = nw;
  344. }
  345. return true;
  346. }
  347. s16 MapgenFractal::generateTerrain()
  348. {
  349. MapNode n_air(CONTENT_AIR);
  350. MapNode n_stone(c_stone);
  351. MapNode n_water(c_water_source);
  352. s16 stone_surface_max_y = -MAX_MAP_GENERATION_LIMIT;
  353. u32 index2d = 0;
  354. if (noise_seabed)
  355. noise_seabed->perlinMap2D(node_min.X, node_min.Z);
  356. for (s16 z = node_min.Z; z <= node_max.Z; z++) {
  357. for (s16 y = node_min.Y - 1; y <= node_max.Y + 1; y++) {
  358. u32 vi = vm->m_area.index(node_min.X, y, z);
  359. for (s16 x = node_min.X; x <= node_max.X; x++, vi++, index2d++) {
  360. if (vm->m_data[vi].getContent() != CONTENT_IGNORE)
  361. continue;
  362. s16 seabed_height = -MAX_MAP_GENERATION_LIMIT;
  363. if (noise_seabed)
  364. seabed_height = noise_seabed->result[index2d];
  365. if (((spflags & MGFRACTAL_TERRAIN) && y <= seabed_height) ||
  366. getFractalAtPoint(x, y, z)) {
  367. vm->m_data[vi] = n_stone;
  368. if (y > stone_surface_max_y)
  369. stone_surface_max_y = y;
  370. } else if ((spflags & MGFRACTAL_TERRAIN) && y <= water_level) {
  371. vm->m_data[vi] = n_water;
  372. } else {
  373. vm->m_data[vi] = n_air;
  374. }
  375. }
  376. index2d -= ystride;
  377. }
  378. index2d += ystride;
  379. }
  380. return stone_surface_max_y;
  381. }