WormCaveGenerator.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324
  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. Framework::Array<Framework::Vec3<float>> tmpPointList;
  21. Framework::Array<float> tmpSizeList;
  22. tmpPointList.add(lastPos);
  23. tmpSizeList.add((float)minRad);
  24. minAffected.x = (int)lastPos.x - minRad;
  25. minAffected.y = (int)lastPos.y - minRad;
  26. minAffected.z = (int)lastPos.z - minRad;
  27. maxAffected.x = (int)lastPos.x + minRad;
  28. maxAffected.y = (int)lastPos.y + minRad;
  29. maxAffected.z = (int)lastPos.z + minRad;
  30. while (tmpSizeList.getEintragAnzahl() < distant * 20)
  31. {
  32. Framework::Vec3<float> defaultDir(1.f, 0.f, 0.f);
  33. if (tmpPointList.getEintragAnzahl() > 1)
  34. {
  35. defaultDir = tmpPointList.get(tmpPointList.getEintragAnzahl() - 1)
  36. - tmpPointList.get(tmpPointList.getEintragAnzahl() - 2);
  37. }
  38. float n = (float)yaw->getNoise(lastPos.x, lastPos.y, lastPos.z);
  39. defaultDir.rotateZ((n - 0.5f) / 2.f);
  40. defaultDir.normalize();
  41. n = (float)pitch->getNoise(lastPos.x, lastPos.y, lastPos.z);
  42. defaultDir.z = ((float)n - 0.3f) * 2.f;
  43. lastPos = lastPos + defaultDir;
  44. if ((Framework::Vec2<float>(lastPos.x, lastPos.y)
  45. - (Framework::Vec2<float>(
  46. (float)startPos.x, (float)startPos.y)))
  47. .getLengthSq()
  48. >= (float)(distant * distant))
  49. break;
  50. tmpPointList.add(lastPos);
  51. float rad = (float)size->getNoise(lastPos.x, lastPos.y, lastPos.z)
  52. * (float)(maxRad - minRad)
  53. + (float)minRad;
  54. tmpSizeList.add(rad);
  55. minAffected.x = MIN(minAffected.x, (int)(lastPos.x - rad));
  56. minAffected.y = MIN(minAffected.y, (int)(lastPos.y - rad));
  57. minAffected.z = MIN(minAffected.z, (int)(lastPos.z - rad));
  58. maxAffected.x = MAX(maxAffected.x, (int)(lastPos.x + rad));
  59. maxAffected.y = MAX(maxAffected.y, (int)(lastPos.y + rad));
  60. maxAffected.z = MAX(maxAffected.z, (int)(lastPos.z + rad));
  61. }
  62. keyPoints = new float[3 * tmpPointList.getEintragAnzahl()];
  63. keyPointSize = new float[tmpPointList.getEintragAnzahl()];
  64. float* keyPointsP = keyPoints;
  65. float* keyPointSizeP = keyPointSize;
  66. auto pi = tmpPointList.begin();
  67. auto si = tmpSizeList.begin();
  68. while (pi)
  69. {
  70. *(keyPointsP++) = pi.val().x;
  71. *(keyPointsP++) = pi.val().y;
  72. *(keyPointsP++) = pi.val().z;
  73. *(keyPointSizeP++) = si.val();
  74. ++pi;
  75. ++si;
  76. }
  77. }
  78. NoiseWorm3D::~NoiseWorm3D()
  79. {
  80. delete[] keyPoints;
  81. delete[] keyPointSize;
  82. }
  83. const Framework::Punkt& NoiseWorm3D::getStartChunkCenter()
  84. {
  85. return startChunk;
  86. }
  87. void NoiseWorm3D::getPartAffectedByChunk(
  88. int x, int y, Framework::RCArray<NoiseWorm3D>* zResult)
  89. {
  90. NoiseWorm3D* result = 0;
  91. Framework::Array<Framework::Vec3<float>> tmpPointList;
  92. Framework::Array<float> tmpSizeList;
  93. if (x - CHUNK_SIZE / 2 <= maxAffected.x
  94. && x + CHUNK_SIZE / 2 >= minAffected.x
  95. && y - CHUNK_SIZE / 2 <= maxAffected.y
  96. && y + CHUNK_SIZE / 2 >= minAffected.y)
  97. {
  98. float* pi = keyPoints;
  99. float* si = keyPointSize;
  100. int newWormThreshold = 5;
  101. int outsideCounter = 0;
  102. for (int i = 0; i < keyPointCount; i++)
  103. {
  104. if ((Framework::Vec2<float>((float)x, (float)y)
  105. - Framework::Vec2<float>(*pi, *(pi + 1)))
  106. .getLengthSq()
  107. < (*si + CHUNK_SIZE / 2) * (*si + CHUNK_SIZE / 2))
  108. {
  109. outsideCounter = 0;
  110. if (result == 0)
  111. {
  112. result = new NoiseWorm3D();
  113. result->minAffected.x = (int)(*pi - *si);
  114. result->minAffected.y = (int)(*(pi + 1) - *si);
  115. result->minAffected.z = (int)(*(pi + 2) - *si);
  116. result->maxAffected.x = (int)(*pi + *si);
  117. result->maxAffected.y = (int)(*(pi + 1) + *si);
  118. result->maxAffected.z = (int)(*(pi + 2) + *si);
  119. }
  120. else
  121. {
  122. result->minAffected.x
  123. = MIN(result->minAffected.x, (int)(*pi - *si));
  124. result->minAffected.y
  125. = MIN(result->minAffected.y, (int)(*(pi + 1) - *si));
  126. result->minAffected.z
  127. = MIN(result->minAffected.z, (int)(*(pi + 2) - *si));
  128. result->maxAffected.x
  129. = MAX(result->maxAffected.x, (int)(*pi + *si));
  130. result->maxAffected.y
  131. = MAX(result->maxAffected.y, (int)(*(pi + 1) + *si));
  132. result->maxAffected.z
  133. = MAX(result->maxAffected.z, (int)(*(pi + 2) + *si));
  134. }
  135. tmpPointList.add({*pi, *(pi + 1), *(pi + 2)});
  136. tmpSizeList.add(*si);
  137. }
  138. else
  139. {
  140. outsideCounter++;
  141. if (outsideCounter >= newWormThreshold)
  142. {
  143. if (result != 0)
  144. {
  145. result->keyPoints
  146. = new float[tmpPointList.getEintragAnzahl() * 3];
  147. result->keyPointSize
  148. = new float[tmpPointList.getEintragAnzahl()];
  149. float* rkeyPointsP = result->keyPoints;
  150. float* rkeyPointSizeP = result->keyPointSize;
  151. auto rpi = tmpPointList.begin();
  152. auto rsi = tmpSizeList.begin();
  153. while (rpi)
  154. {
  155. *(rkeyPointsP++) = rpi.val().x;
  156. *(rkeyPointsP++) = rpi.val().y;
  157. *(rkeyPointsP++) = rpi.val().z;
  158. *(rkeyPointSizeP++) = rsi.val();
  159. ++rpi;
  160. ++rsi;
  161. }
  162. tmpPointList.leeren();
  163. tmpSizeList.leeren();
  164. zResult->add(result);
  165. result = 0;
  166. }
  167. outsideCounter = 0;
  168. }
  169. }
  170. pi += 3;
  171. ++si;
  172. }
  173. }
  174. if (result)
  175. {
  176. result->keyPoints = new float[tmpPointList.getEintragAnzahl() * 3];
  177. result->keyPointSize = new float[tmpPointList.getEintragAnzahl()];
  178. float* rkeyPointsP = result->keyPoints;
  179. float* rkeyPointSizeP = result->keyPointSize;
  180. auto rpi = tmpPointList.begin();
  181. auto rsi = tmpSizeList.begin();
  182. while (rpi)
  183. {
  184. *(rkeyPointsP++) = rpi.val().x;
  185. *(rkeyPointsP++) = rpi.val().y;
  186. *(rkeyPointsP++) = rpi.val().z;
  187. *(rkeyPointSizeP++) = rsi.val();
  188. ++rpi;
  189. ++rsi;
  190. }
  191. zResult->add(result);
  192. }
  193. }
  194. bool NoiseWorm3D::isInside(int x, int y, int z)
  195. {
  196. if (x >= minAffected.x && x <= maxAffected.x && y >= minAffected.y
  197. && y <= maxAffected.y && z >= minAffected.z && z <= maxAffected.z)
  198. {
  199. float* pi = keyPoints;
  200. float* si = keyPointSize;
  201. while (pi && si)
  202. {
  203. if (Framework::Vec3<float>((float)x, (float)y, (float)z)
  204. .abstandSq({*pi, *(pi + 1), *(pi + 2)})
  205. < *si * *si)
  206. return 1;
  207. pi += 3;
  208. ++si;
  209. }
  210. }
  211. return 0;
  212. }
  213. WormCaveChunkGenerator::WormCaveChunkGenerator(
  214. Framework::RCArray<NoiseWorm3D> worms)
  215. : CaveChunkGenerator(),
  216. worms(worms)
  217. {}
  218. bool WormCaveChunkGenerator::isInCave(int x, int y, int z)
  219. {
  220. for (NoiseWorm3D* w : worms)
  221. {
  222. if (w->isInside(x, y, z)) return 1;
  223. }
  224. return 0;
  225. }
  226. WormCaveGenerator::WormCaveGenerator(int minDistant,
  227. int maxDistant,
  228. int minRadius,
  229. int maxRadius,
  230. float cavePosibillityPerChunk,
  231. int seed)
  232. : CaveGenerator(seed),
  233. maxDistant(maxDistant),
  234. minDistant(minDistant),
  235. maxRadius(maxRadius),
  236. minRadius(minRadius),
  237. cavePosibillity(cavePosibillityPerChunk),
  238. wormStartNoise(new RandNoise(seed))
  239. {}
  240. WormCaveGenerator::~WormCaveGenerator()
  241. {
  242. wormStartNoise->release();
  243. }
  244. NoiseWorm3D* WormCaveGenerator::zWormOfChunk(int x, int y)
  245. {
  246. for (NoiseWorm3D* worm : cache)
  247. {
  248. if (worm->getStartChunkCenter().x == x
  249. && worm->getStartChunkCenter().y == y)
  250. {
  251. return worm;
  252. }
  253. }
  254. float cNoise
  255. = (float)wormStartNoise->getNoise((double)x, (double)y, (double)0);
  256. if (cNoise < cavePosibillity)
  257. {
  258. FastNoiseLite* noise = new FastNoiseLite(seed + x * y + y + x);
  259. noise->SetNoiseType(FastNoiseLite::NoiseType::NoiseType_Perlin);
  260. noise->SetFrequency(0.05f);
  261. FastNoiseWrapper* pitch
  262. = new FastNoiseWrapper(noise, seed + x * y + y + x);
  263. noise = new FastNoiseLite(seed + x * y + y + x);
  264. noise->SetNoiseType(FastNoiseLite::NoiseType::NoiseType_Perlin);
  265. noise->SetFrequency(0.005f);
  266. FastNoiseWrapper* yaw
  267. = new FastNoiseWrapper(noise, seed - x * y - y - x);
  268. Framework::Vec3<int> start(
  269. (int)(cNoise / cavePosibillity * CHUNK_SIZE) + x - CHUNK_SIZE / 2,
  270. (int)(cNoise / cavePosibillity * CHUNK_SIZE) + y - CHUNK_SIZE / 2,
  271. (int)(cNoise / cavePosibillity * 200));
  272. noise = new FastNoiseLite(
  273. seed + start.getLengthSq() + start.x + start.y + start.z);
  274. noise->SetNoiseType(FastNoiseLite::NoiseType::NoiseType_Perlin);
  275. noise->SetFrequency(0.005f);
  276. FastNoiseWrapper* size = new FastNoiseWrapper(
  277. noise, seed + start.getLengthSq() + start.x + start.y + start.z);
  278. NoiseWorm3D* worm = new NoiseWorm3D(pitch,
  279. yaw,
  280. size,
  281. start,
  282. (int)(wormStartNoise->getNoise(
  283. (double)start.x, (double)start.y, (double)start.z)
  284. * (maxDistant - minDistant)
  285. + minDistant),
  286. minRadius,
  287. maxRadius);
  288. if (cache.getEintragAnzahl()
  289. > (maxDistant * 2) / CHUNK_SIZE * (maxDistant * 2) / CHUNK_SIZE * 3)
  290. cache.remove(0);
  291. cache.add(worm);
  292. return worm;
  293. }
  294. return 0;
  295. }
  296. CaveChunkGenerator* WormCaveGenerator::getGeneratorForChunk(int x, int y)
  297. {
  298. Framework::RCArray<NoiseWorm3D> affected;
  299. Framework::Punkt center = Game::getChunkCenter(x, y);
  300. int offset = (int)ceil((float)maxDistant / CHUNK_SIZE);
  301. for (int cx = -offset; cx <= offset; cx++)
  302. {
  303. for (int cy = -offset; cy <= offset; cy++)
  304. {
  305. NoiseWorm3D* worm = zWormOfChunk(
  306. center.x + cx * CHUNK_SIZE, center.y + cy * CHUNK_SIZE);
  307. if (worm) worm->getPartAffectedByChunk(x, y, &affected);
  308. }
  309. }
  310. return new WormCaveChunkGenerator(affected);
  311. }