DimensionGenerator.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370
  1. #include "DimensionGenerator.h"
  2. #include <iostream>
  3. #include "Constants.h"
  4. #include "Game.h"
  5. #include "NoBlock.h"
  6. #include "Noise.h"
  7. #include "RandNoise.h"
  8. DimensionGenerator::DimensionGenerator(
  9. int dimensionId, CaveGenerator* caveGenerator)
  10. : ReferenceCounter(),
  11. dimensionId(dimensionId),
  12. minTemplateAffectedPosition(0, 0, 0),
  13. maxTemplateAffectedPosition(0, 0, 0),
  14. caveGenerator(caveGenerator)
  15. {
  16. StaticRegistry<DimensionGenerator>::INSTANCE.registerT(this, dimensionId);
  17. }
  18. DimensionGenerator::~DimensionGenerator() {}
  19. void DimensionGenerator::initialize(int seed)
  20. {
  21. this->seed = seed + dimensionId;
  22. caveGenerator->initialize(this->seed);
  23. for (auto biomGen : biomGenerators)
  24. {
  25. biomGen->setSeed(this->seed);
  26. }
  27. }
  28. BiomGenerator* DimensionGenerator::zBiomGenerator(int x, int y)
  29. {
  30. double noise = zBiomNoise()->getNoise((double)x, (double)y, 0.0);
  31. double border = 0;
  32. BiomGenerator* gen = 0;
  33. auto genI = biomGenerators.begin();
  34. auto distI = biomDistribution.begin();
  35. do
  36. {
  37. border += (double)distI++;
  38. gen = genI++;
  39. } while (border < noise && (bool)distI && (bool)genI);
  40. return gen;
  41. }
  42. void DimensionGenerator::registerBiom(
  43. BiomGenerator* generator, double possibility)
  44. {
  45. biomGenerators.add(generator);
  46. biomDistribution.add(possibility);
  47. for (auto t : generator->getTemplates())
  48. {
  49. minTemplateAffectedPosition.x
  50. = MIN(minTemplateAffectedPosition.x, t->getMinAffectedOffset().x);
  51. minTemplateAffectedPosition.y
  52. = MIN(minTemplateAffectedPosition.y, t->getMinAffectedOffset().y);
  53. minTemplateAffectedPosition.z
  54. = MIN(minTemplateAffectedPosition.z, t->getMinAffectedOffset().z);
  55. maxTemplateAffectedPosition.x
  56. = MAX(maxTemplateAffectedPosition.x, t->getMaxAffectedOffset().x);
  57. maxTemplateAffectedPosition.y
  58. = MAX(maxTemplateAffectedPosition.y, t->getMaxAffectedOffset().y);
  59. maxTemplateAffectedPosition.z
  60. = MAX(maxTemplateAffectedPosition.z, t->getMaxAffectedOffset().z);
  61. }
  62. generator->setSeed(seed);
  63. }
  64. Framework::RCArray<GeneratedStructure>*
  65. DimensionGenerator::getGeneratedStructoresForArea(
  66. Framework::Vec3<int> minPos, Framework::Vec3<int> maxPos)
  67. {
  68. Framework::RCArray<GeneratedStructure>* result
  69. = new Framework::RCArray<GeneratedStructure>();
  70. int minSearchX = minPos.x - maxTemplateAffectedPosition.x;
  71. int minSearchY = minPos.y - maxTemplateAffectedPosition.y;
  72. int minSearchZ = MAX(minPos.z - maxTemplateAffectedPosition.z, 0);
  73. int maxSearchX = maxPos.x - minTemplateAffectedPosition.x;
  74. int maxSearchY = maxPos.y - minTemplateAffectedPosition.y;
  75. int maxSearchZ
  76. = MIN(maxPos.z - minTemplateAffectedPosition.z, WORLD_HEIGHT - 1);
  77. Noise* structureNoise = zStructureNoise();
  78. for (int x = minSearchX; x <= maxSearchX; x++)
  79. {
  80. for (int y = minSearchY; y <= maxSearchY; y++)
  81. {
  82. BiomGenerator* biom = zBiomGenerator(x, y);
  83. int height = MIN_AIR_LEVEL
  84. + (int)(biom->zHeightMapNoise()->getNoise(
  85. (double)(x), (double)(y), 0.0)
  86. * (MAX_AIR_LEVEL - MIN_AIR_LEVEL));
  87. for (int z = minSearchZ; z <= maxSearchZ; z++)
  88. {
  89. if (z < height)
  90. {
  91. double rValue = structureNoise->getNoise(
  92. (double)x, (double)y, (double)z);
  93. double probSum = 0;
  94. for (auto t : biom->getTemplates())
  95. {
  96. if (t->isGenerationPossable(
  97. Framework::Vec3<int>(x, y, z), height - z))
  98. {
  99. if (rValue - probSum <= t->getPropability())
  100. {
  101. result->add(
  102. t->generateAt(Framework::Vec3<int>(x, y, z),
  103. structureNoise,
  104. dimensionId));
  105. break;
  106. }
  107. }
  108. probSum += t->getPropability();
  109. }
  110. }
  111. }
  112. }
  113. }
  114. return result;
  115. }
  116. Chunk* DimensionGenerator::generateChunk(int centerX, int centerY)
  117. {
  118. std::cout << "generating chunk " << centerX << ", " << centerY << "\n";
  119. double structureTime = 0;
  120. double caveTime = 0;
  121. double blockGenTime = 0;
  122. double biomTime = 0;
  123. double heightTime = 0;
  124. ZeitMesser zm;
  125. ZeitMesser zmGlobal;
  126. zm.messungStart();
  127. zmGlobal.messungStart();
  128. Framework::RCArray<GeneratedStructure>* structures
  129. = getGeneratedStructoresForArea(
  130. Framework::Vec3<int>(
  131. centerX - CHUNK_SIZE / 2, centerY - CHUNK_SIZE / 2, 0),
  132. Framework::Vec3<int>(centerX + CHUNK_SIZE / 2,
  133. centerY + CHUNK_SIZE / 2,
  134. WORLD_HEIGHT - 1));
  135. zm.messungEnde();
  136. structureTime += zm.getSekunden();
  137. zm.messungStart();
  138. CaveChunkGenerator* caveGen
  139. = caveGenerator->getGeneratorForChunk(centerX, centerY);
  140. zm.messungEnde();
  141. caveTime += zm.getSekunden();
  142. Chunk* chunk = new Chunk(Framework::Punkt(centerX, centerY), dimensionId);
  143. for (int x = -CHUNK_SIZE / 2; x < CHUNK_SIZE / 2; x++)
  144. {
  145. for (int y = -CHUNK_SIZE / 2; y < CHUNK_SIZE / 2; y++)
  146. {
  147. zm.messungStart();
  148. BiomGenerator* biom = zBiomGenerator(x + centerX, y + centerY);
  149. zm.messungEnde();
  150. biomTime += zm.getSekunden();
  151. // TODO: use Noise interpolator for height map between different
  152. // bioms
  153. zm.messungStart();
  154. int height
  155. = MIN_AIR_LEVEL
  156. + (int)(biom->zHeightMapNoise()->getNoise(
  157. (double)(x + centerX), (double)(y + centerY), 0.0)
  158. * (MAX_AIR_LEVEL - MIN_AIR_LEVEL));
  159. int maxSurfaceHeight
  160. = (int)(MAX_SURFACE_HEIGHT
  161. * (1.f
  162. - (float)(height - MIN_AIR_LEVEL)
  163. / (float)(MAX_AIR_LEVEL - MIN_AIR_LEVEL)));
  164. int actualSurfaceHeight
  165. = (int)((float)maxSurfaceHeight * (1.f - VARIABLE_SURFACE_PART)
  166. + ((float)maxSurfaceHeight * VARIABLE_SURFACE_PART
  167. * (float)biom->zHeightMapNoise()->getNoise(
  168. (double)(x + centerX),
  169. (double)(y + centerY),
  170. 10.0)));
  171. zm.messungEnde();
  172. heightTime += zm.getSekunden();
  173. for (int z = 0; z < WORLD_HEIGHT; z++)
  174. {
  175. Framework::Either<Block*, int> generated = BlockTypeEnum::AIR;
  176. bool structureAffected = 0;
  177. for (auto structure : *structures)
  178. {
  179. zm.messungStart();
  180. if (structure->isBlockAffected(
  181. Framework::Vec3<int>(x + centerX, y + centerY, z)))
  182. {
  183. generated = structure->generateBlockAt(
  184. Framework::Vec3<int>(x + centerX, y + centerY, z));
  185. structureAffected = 1;
  186. zm.messungEnde();
  187. structureTime += zm.getSekunden();
  188. break;
  189. }
  190. zm.messungEnde();
  191. structureTime += zm.getSekunden();
  192. }
  193. if (!structureAffected)
  194. {
  195. zm.messungStart();
  196. bool inCave
  197. = caveGen->isInCave(x + centerX, y + centerY, z);
  198. zm.messungEnde();
  199. caveTime += zm.getSekunden();
  200. zm.messungStart();
  201. if (inCave)
  202. generated = biom->generateCaveBlock(
  203. x + centerX, y + centerY, z);
  204. else if (z < height && z >= height - actualSurfaceHeight)
  205. generated = biom->generateSurfaceBlock(
  206. x + centerX, y + centerY, z);
  207. else if (z < height)
  208. generated = biom->generateBelowSurfaceBlock(
  209. x + centerX, y + centerY, z);
  210. else if (z >= height && z < WATER_LEVEL)
  211. {
  212. generated = biom->generateUnderWaterBlock(
  213. x + centerX, y + centerY, z, height, chunk);
  214. }
  215. else
  216. {
  217. generated = biom->generateAboveSurfaceBlock(
  218. x + centerX, y + centerY, z, height, chunk);
  219. }
  220. zm.messungEnde();
  221. blockGenTime += zm.getSekunden();
  222. }
  223. if (generated.isA())
  224. chunk->putBlockAt(
  225. Framework::Vec3<int>(
  226. x + CHUNK_SIZE / 2, y + CHUNK_SIZE / 2, z),
  227. generated);
  228. else
  229. chunk->putBlockTypeAt(
  230. Framework::Vec3<int>(
  231. x + CHUNK_SIZE / 2, y + CHUNK_SIZE / 2, z),
  232. generated);
  233. }
  234. }
  235. }
  236. caveGen->release();
  237. structures->release();
  238. zmGlobal.messungEnde();
  239. std::cout << "structureTime: " << structureTime << "\n";
  240. std::cout << "caveTime: " << caveTime << "\n";
  241. std::cout << "blockGenTime: " << blockGenTime << "\n";
  242. std::cout << "biomTime: " << biomTime << "\n";
  243. std::cout << "heightTime: " << heightTime << "\n";
  244. std::cout << "totalTime: " << zmGlobal.getSekunden() << "\n";
  245. return chunk;
  246. }
  247. Framework::Either<Block*, int> DimensionGenerator::generateBlock(
  248. Framework::Vec3<int> location)
  249. {
  250. Framework::RCArray<GeneratedStructure>* structures
  251. = getGeneratedStructoresForArea(location, location);
  252. BiomGenerator* biom = zBiomGenerator(location.x, location.y);
  253. // TODO: use Noise interpolator for height map between different bioms
  254. int height = MIN_AIR_LEVEL
  255. + (int)(biom->zHeightMapNoise()->getNoise(
  256. (double)(location.x), (double)(location.y), 0.0)
  257. * (MAX_AIR_LEVEL - MIN_AIR_LEVEL));
  258. int maxSurfaceHeight
  259. = (int)(MAX_SURFACE_HEIGHT
  260. * (1.f
  261. - (float)(height - MIN_AIR_LEVEL)
  262. / (float)(MAX_AIR_LEVEL - MIN_AIR_LEVEL)));
  263. int actualSurfaceHeight
  264. = (int)((float)maxSurfaceHeight * (1.f - VARIABLE_SURFACE_PART)
  265. + ((float)maxSurfaceHeight * VARIABLE_SURFACE_PART
  266. * (float)biom->zHeightMapNoise()->getNoise(
  267. (double)(location.x), (double)(location.y), 10.0)));
  268. for (auto structure : *structures)
  269. {
  270. if (structure->isBlockAffected(location))
  271. {
  272. auto generated = structure->generateBlockAt(location);
  273. structures->release();
  274. return generated;
  275. }
  276. }
  277. structures->release();
  278. if (location.z < height && location.z >= height - actualSurfaceHeight)
  279. return biom->generateSurfaceBlock(location.x, location.y, location.z);
  280. else if (location.z < height)
  281. return biom->generateBelowSurfaceBlock(
  282. location.x, location.y, location.z);
  283. else if (location.z >= height && location.z < WATER_LEVEL)
  284. {
  285. return biom->generateUnderWaterBlock(location.x,
  286. location.y,
  287. location.z,
  288. height,
  289. Game::INSTANCE->zDimension(getDimensionId())
  290. ->zChunk(
  291. Game::INSTANCE->getChunkCenter(location.x, location.y)));
  292. }
  293. if (location.z >= height)
  294. {
  295. return biom->generateAboveSurfaceBlock(location.x,
  296. location.x,
  297. location.z,
  298. height,
  299. Game::INSTANCE->zDimension(getDimensionId())
  300. ->zChunk(
  301. Game::INSTANCE->getChunkCenter(location.x, location.y)));
  302. }
  303. return BlockTypeEnum::AIR;
  304. }
  305. bool DimensionGenerator::spawnStructure(Framework::Vec3<int> location,
  306. std::function<bool(GenerationTemplate* tmpl)> filter)
  307. {
  308. BiomGenerator* biom = zBiomGenerator(location.x, location.y);
  309. for (auto t : biom->getTemplates())
  310. {
  311. if (filter(t))
  312. {
  313. RandNoise noise((int)time(0));
  314. GeneratedStructure* genStr
  315. = t->generateAt(location, &noise, dimensionId);
  316. if (genStr)
  317. {
  318. int minSearchX = location.x + t->getMinAffectedOffset().x;
  319. int minSearchY = location.y + t->getMinAffectedOffset().y;
  320. int minSearchZ
  321. = MAX(location.z + t->getMinAffectedOffset().z, 0);
  322. int maxSearchX = location.x + t->getMaxAffectedOffset().x;
  323. int maxSearchY = location.y + t->getMaxAffectedOffset().y;
  324. int maxSearchZ = MIN(
  325. location.z + t->getMaxAffectedOffset().z, WORLD_HEIGHT - 1);
  326. for (int x = minSearchX; x <= maxSearchX; x++)
  327. {
  328. for (int y = minSearchY; y <= maxSearchY; y++)
  329. {
  330. for (int z = minSearchZ; z <= maxSearchZ; z++)
  331. {
  332. if (genStr->isBlockAffected(
  333. Framework::Vec3<int>(x, y, z)))
  334. {
  335. auto gen = genStr->generateBlockAt(
  336. Framework::Vec3<int>(x, y, z));
  337. Game::INSTANCE->zDimension(dimensionId)
  338. ->placeBlock(
  339. Framework::Vec3<int>(x, y, z), gen);
  340. }
  341. }
  342. }
  343. }
  344. genStr->release();
  345. return 1;
  346. }
  347. }
  348. }
  349. return 0;
  350. }
  351. int DimensionGenerator::getDimensionId() const
  352. {
  353. return dimensionId;
  354. }