WormCaveGenerator.cpp 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272
  1. #include "WormCaveGenerator.h"
  2. #include "FastNoiseWrapper.h"
  3. #include "Game.h"
  4. #include "RandNoise.h"
  5. NoiseWorm3D::NoiseWorm3D()
  6. : ReferenceCounter()
  7. {}
  8. NoiseWorm3D::NoiseWorm3D(Noise* pitch,
  9. Noise* yaw,
  10. Noise* size,
  11. Framework::Vec3<int> startPos,
  12. int distant,
  13. int minRad,
  14. int maxRad)
  15. : ReferenceCounter(),
  16. startChunk(Game::INSTANCE->getChunkCenter(startPos.x, startPos.y))
  17. {
  18. Vec3<float> lastPos = (Vec3<float>)startPos;
  19. keyPoints.add(lastPos);
  20. this->size.add((float)minRad);
  21. minAffected.x = (int)lastPos.x - minRad;
  22. minAffected.y = (int)lastPos.y - minRad;
  23. minAffected.z = (int)lastPos.z - minRad;
  24. maxAffected.x = (int)lastPos.x + minRad;
  25. maxAffected.y = (int)lastPos.y + minRad;
  26. maxAffected.z = (int)lastPos.z + minRad;
  27. while (keyPoints.getEintragAnzahl() < distant * 20)
  28. {
  29. Vec3<float> defaultDir(1.f, 0.f, 0.f);
  30. if (keyPoints.getEintragAnzahl() > 1)
  31. {
  32. defaultDir = keyPoints.get(keyPoints.getEintragAnzahl() - 1)
  33. - keyPoints.get(keyPoints.getEintragAnzahl() - 2);
  34. }
  35. float n = (float)yaw->getNoise(lastPos.x, lastPos.y, lastPos.z);
  36. defaultDir.rotateZ((n - 0.5f) / 2.f);
  37. defaultDir.normalize();
  38. n = (float)pitch->getNoise(lastPos.x, lastPos.y, lastPos.z);
  39. defaultDir.z = ((float)n - 0.3f) * 2.f;
  40. lastPos = lastPos + defaultDir;
  41. if ((Vec2<float>(lastPos.x, lastPos.y)
  42. - (Vec2<float>((float)startPos.x, (float)startPos.y)))
  43. .getLengthSq()
  44. >= (float)(distant * distant))
  45. break;
  46. keyPoints.add(lastPos);
  47. float rad = (float)size->getNoise(lastPos.x, lastPos.y, lastPos.z)
  48. * (float)(maxRad - minRad)
  49. + (float)minRad;
  50. this->size.add(rad);
  51. minAffected.x = MIN(minAffected.x, (int)(lastPos.x - rad));
  52. minAffected.y = MIN(minAffected.y, (int)(lastPos.y - rad));
  53. minAffected.z = MIN(minAffected.z, (int)(lastPos.z - rad));
  54. maxAffected.x = MAX(maxAffected.x, (int)(lastPos.x + rad));
  55. maxAffected.y = MAX(maxAffected.y, (int)(lastPos.y + rad));
  56. maxAffected.z = MAX(maxAffected.z, (int)(lastPos.z + rad));
  57. }
  58. }
  59. Framework::Punkt NoiseWorm3D::getStartChunkCenter()
  60. {
  61. return startChunk;
  62. }
  63. void NoiseWorm3D::getPartAffectedByChunk(
  64. int x, int y, Framework::RCArray<NoiseWorm3D>* zResult)
  65. {
  66. NoiseWorm3D* result = 0;
  67. if (x - CHUNK_SIZE / 2 <= maxAffected.x
  68. && x + CHUNK_SIZE / 2 >= minAffected.x
  69. && y - CHUNK_SIZE / 2 <= maxAffected.y
  70. && y + CHUNK_SIZE / 2 >= minAffected.y)
  71. {
  72. auto pi = keyPoints.begin();
  73. auto si = size.begin();
  74. int newWormThreshold = 5;
  75. int outsideCounter = 0;
  76. while (pi && si)
  77. {
  78. if ((Vec2<float>((float)x, (float)y)
  79. - Vec2<float>(pi.val().x, pi.val().y))
  80. .getLengthSq()
  81. < (si.val() + CHUNK_SIZE / 2) * (si.val() + CHUNK_SIZE / 2))
  82. {
  83. outsideCounter = 0;
  84. if (result == 0)
  85. {
  86. result = new NoiseWorm3D();
  87. result->minAffected.x = (int)(pi.val().x - si.val());
  88. result->minAffected.y = (int)(pi.val().y - si.val());
  89. result->minAffected.z = (int)(pi.val().z - si.val());
  90. result->maxAffected.x = (int)(pi.val().x + si.val());
  91. result->maxAffected.y = (int)(pi.val().y + si.val());
  92. result->maxAffected.z = (int)(pi.val().z + si.val());
  93. }
  94. else
  95. {
  96. result->minAffected.x = MIN(
  97. result->minAffected.x, (int)(pi.val().x - si.val()));
  98. result->minAffected.y = MIN(
  99. result->minAffected.y, (int)(pi.val().y - si.val()));
  100. result->minAffected.z = MIN(
  101. result->minAffected.z, (int)(pi.val().z - si.val()));
  102. result->maxAffected.x = MAX(
  103. result->maxAffected.x, (int)(pi.val().x + si.val()));
  104. result->maxAffected.y = MAX(
  105. result->maxAffected.y, (int)(pi.val().y + si.val()));
  106. result->maxAffected.z = MAX(
  107. result->maxAffected.z, (int)(pi.val().z + si.val()));
  108. }
  109. result->keyPoints.add(pi.val());
  110. result->size.add(si.val());
  111. }
  112. else
  113. {
  114. outsideCounter++;
  115. if (outsideCounter >= newWormThreshold)
  116. {
  117. if (result != 0)
  118. {
  119. zResult->add(result);
  120. result = 0;
  121. }
  122. outsideCounter = 0;
  123. }
  124. }
  125. ++pi;
  126. ++si;
  127. }
  128. }
  129. if (result)
  130. {
  131. zResult->add(result);
  132. }
  133. }
  134. bool NoiseWorm3D::isInside(int x, int y, int z)
  135. {
  136. if (x >= minAffected.x && x <= maxAffected.x && y >= minAffected.y
  137. && y <= maxAffected.y && z >= minAffected.z && z <= maxAffected.z)
  138. {
  139. auto pi = keyPoints.begin();
  140. auto si = size.begin();
  141. while (pi && si)
  142. {
  143. if (Vec3<float>((float)x, (float)y, (float)z).abstandSq(pi.val())
  144. < si.val() * si.val())
  145. return 1;
  146. ++pi;
  147. ++si;
  148. }
  149. }
  150. return 0;
  151. }
  152. WormCaveChunkGenerator::WormCaveChunkGenerator(
  153. Framework::RCArray<NoiseWorm3D> worms)
  154. : CaveChunkGenerator(),
  155. worms(worms)
  156. {}
  157. bool WormCaveChunkGenerator::isInCave(int x, int y, int z)
  158. {
  159. for (NoiseWorm3D* w : worms)
  160. {
  161. if (w->isInside(x, y, z)) return 1;
  162. }
  163. return 0;
  164. }
  165. WormCaveGenerator::WormCaveGenerator(int minDistant,
  166. int maxDistant,
  167. int minRadius,
  168. int maxRadius,
  169. float cavePosibillityPerChunk,
  170. int seed)
  171. : CaveGenerator(seed),
  172. maxDistant(maxDistant),
  173. minDistant(minDistant),
  174. maxRadius(maxRadius),
  175. minRadius(minRadius),
  176. cavePosibillity(cavePosibillityPerChunk),
  177. wormStartNoise(new RandNoise(seed))
  178. {}
  179. WormCaveGenerator::~WormCaveGenerator()
  180. {
  181. wormStartNoise->release();
  182. }
  183. NoiseWorm3D* WormCaveGenerator::zWormOfChunk(int x, int y)
  184. {
  185. for (NoiseWorm3D* worm : cache)
  186. {
  187. if (worm->getStartChunkCenter().x == x
  188. && worm->getStartChunkCenter().y == y)
  189. {
  190. return worm;
  191. }
  192. }
  193. for (Punkt p : noWormChunks)
  194. {
  195. if (p.x == x && p.y == y) return 0;
  196. }
  197. float cNoise = (float)wormStartNoise->getNoise(x, y, 0);
  198. if (cNoise < cavePosibillity)
  199. {
  200. FastNoiseLite* noise = new FastNoiseLite(seed + x * y + y + x);
  201. noise->SetNoiseType(FastNoiseLite::NoiseType::NoiseType_Perlin);
  202. noise->SetFrequency(0.05f);
  203. FastNoiseWrapper* pitch
  204. = new FastNoiseWrapper(noise, seed + x * y + y + x);
  205. noise = new FastNoiseLite(seed + x * y + y + x);
  206. noise->SetNoiseType(FastNoiseLite::NoiseType::NoiseType_Perlin);
  207. noise->SetFrequency(0.005f);
  208. FastNoiseWrapper* yaw
  209. = new FastNoiseWrapper(noise, seed - x * y - y - x);
  210. Vec3<int> start(
  211. (int)(cNoise / cavePosibillity * CHUNK_SIZE) + x - CHUNK_SIZE / 2,
  212. (int)(cNoise / cavePosibillity * CHUNK_SIZE) + y - CHUNK_SIZE / 2,
  213. (int)(cNoise / cavePosibillity * 200));
  214. noise = new FastNoiseLite(
  215. seed + start.getLengthSq() + start.x + start.y + start.z);
  216. noise->SetNoiseType(FastNoiseLite::NoiseType::NoiseType_Perlin);
  217. noise->SetFrequency(0.005f);
  218. FastNoiseWrapper* size = new FastNoiseWrapper(
  219. noise, seed + start.getLengthSq() + start.x + start.y + start.z);
  220. NoiseWorm3D* worm = new NoiseWorm3D(pitch,
  221. yaw,
  222. size,
  223. start,
  224. (int)(wormStartNoise->getNoise(start.x, start.y, start.z)
  225. * (maxDistant - minDistant)
  226. + minDistant),
  227. minRadius,
  228. maxRadius);
  229. if (cache.getEintragAnzahl()
  230. > (maxDistant * 2) / CHUNK_SIZE * (maxDistant * 2) / CHUNK_SIZE * 3)
  231. cache.remove(0);
  232. cache.add(worm);
  233. return worm;
  234. }
  235. else
  236. {
  237. if (noWormChunks.getEintragAnzahl()
  238. > (maxDistant * 2) / CHUNK_SIZE * (maxDistant * 2) / CHUNK_SIZE * 3)
  239. noWormChunks.remove(0);
  240. noWormChunks.add(Punkt(x, y));
  241. }
  242. return 0;
  243. }
  244. CaveChunkGenerator* WormCaveGenerator::getGeneratorForChunk(int x, int y)
  245. {
  246. Framework::RCArray<NoiseWorm3D> affected;
  247. Punkt center = Game::getChunkCenter(x, y);
  248. int offset = (int)ceil((float)maxDistant / CHUNK_SIZE);
  249. for (int cx = -offset; cx <= offset; cx++)
  250. {
  251. for (int cy = -offset; cy <= offset; cy++)
  252. {
  253. NoiseWorm3D* worm = zWormOfChunk(
  254. center.x + cx * CHUNK_SIZE, center.y + cy * CHUNK_SIZE);
  255. if (worm)
  256. worm->getPartAffectedByChunk(x, y, &affected);
  257. }
  258. }
  259. return new WormCaveChunkGenerator(affected);
  260. }