WormCaveGenerator.cpp 9.3 KB

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