#include "WormCaveGenerator.h" #include "Constants.h" #include "FastNoiseWrapper.h" #include "Game.h" #include "RandNoise.h" NoiseWorm3D::NoiseWorm3D() : ReferenceCounter() {} NoiseWorm3D::NoiseWorm3D(Noise* pitch, Noise* yaw, Noise* size, Framework::Vec3 startPos, int distant, int minRad, int maxRad) : ReferenceCounter(), startChunk(Game::INSTANCE->getChunkCenter(startPos.x, startPos.y)) { Framework::Vec3 lastPos = (Framework::Vec3)startPos; Framework::Array> tmpPointList; Framework::Array tmpSizeList; tmpPointList.add(lastPos); tmpSizeList.add((float)minRad); minAffected.x = (int)lastPos.x - minRad; minAffected.y = (int)lastPos.y - minRad; minAffected.z = (int)lastPos.z - minRad; maxAffected.x = (int)lastPos.x + minRad; maxAffected.y = (int)lastPos.y + minRad; maxAffected.z = (int)lastPos.z + minRad; while (tmpSizeList.getEintragAnzahl() < distant * 20) { Framework::Vec3 defaultDir(1.f, 0.f, 0.f); if (tmpPointList.getEintragAnzahl() > 1) { defaultDir = tmpPointList.get(tmpPointList.getEintragAnzahl() - 1) - tmpPointList.get(tmpPointList.getEintragAnzahl() - 2); } float n = (float)yaw->getNoise(lastPos.x, lastPos.y, lastPos.z); defaultDir.rotateZ((n - 0.5f) / 2.f); defaultDir.normalize(); n = (float)pitch->getNoise(lastPos.x, lastPos.y, lastPos.z); defaultDir.z = ((float)n - 0.3f) * 2.f; lastPos = lastPos + defaultDir; if ((Framework::Vec2(lastPos.x, lastPos.y) - (Framework::Vec2( (float)startPos.x, (float)startPos.y))) .getLengthSq() >= (float)(distant * distant)) break; tmpPointList.add(lastPos); float rad = (float)size->getNoise(lastPos.x, lastPos.y, lastPos.z) * (float)(maxRad - minRad) + (float)minRad; tmpSizeList.add(rad); minAffected.x = MIN(minAffected.x, (int)(lastPos.x - rad)); minAffected.y = MIN(minAffected.y, (int)(lastPos.y - rad)); minAffected.z = MIN(minAffected.z, (int)(lastPos.z - rad)); maxAffected.x = MAX(maxAffected.x, (int)(lastPos.x + rad)); maxAffected.y = MAX(maxAffected.y, (int)(lastPos.y + rad)); maxAffected.z = MAX(maxAffected.z, (int)(lastPos.z + rad)); } keyPoints = new float[3 * tmpPointList.getEintragAnzahl()]; keyPointSize = new float[tmpPointList.getEintragAnzahl()]; float* keyPointsP = keyPoints; float* keyPointSizeP = keyPointSize; auto pi = tmpPointList.begin(); auto si = tmpSizeList.begin(); while (pi) { *(keyPointsP++) = pi.val().x; *(keyPointsP++) = pi.val().y; *(keyPointsP++) = pi.val().z; *(keyPointSizeP++) = si.val(); ++pi; ++si; } } NoiseWorm3D::~NoiseWorm3D() { delete[] keyPoints; delete[] keyPointSize; } const Framework::Punkt& NoiseWorm3D::getStartChunkCenter() { return startChunk; } void NoiseWorm3D::getPartAffectedByChunk( int x, int y, Framework::RCArray* zResult) { NoiseWorm3D* result = 0; Framework::Array> tmpPointList; Framework::Array tmpSizeList; if (x - CHUNK_SIZE / 2 <= maxAffected.x && x + CHUNK_SIZE / 2 >= minAffected.x && y - CHUNK_SIZE / 2 <= maxAffected.y && y + CHUNK_SIZE / 2 >= minAffected.y) { float* pi = keyPoints; float* si = keyPointSize; int newWormThreshold = 5; int outsideCounter = 0; for (int i = 0; i < keyPointCount; i++) { if ((Framework::Vec2((float)x, (float)y) - Framework::Vec2(*pi, *(pi + 1))) .getLengthSq() < (*si + CHUNK_SIZE / 2) * (*si + CHUNK_SIZE / 2)) { outsideCounter = 0; if (result == 0) { result = new NoiseWorm3D(); result->minAffected.x = (int)(*pi - *si); result->minAffected.y = (int)(*(pi + 1) - *si); result->minAffected.z = (int)(*(pi + 2) - *si); result->maxAffected.x = (int)(*pi + *si); result->maxAffected.y = (int)(*(pi + 1) + *si); result->maxAffected.z = (int)(*(pi + 2) + *si); } else { result->minAffected.x = MIN(result->minAffected.x, (int)(*pi - *si)); result->minAffected.y = MIN(result->minAffected.y, (int)(*(pi + 1) - *si)); result->minAffected.z = MIN(result->minAffected.z, (int)(*(pi + 2) - *si)); result->maxAffected.x = MAX(result->maxAffected.x, (int)(*pi + *si)); result->maxAffected.y = MAX(result->maxAffected.y, (int)(*(pi + 1) + *si)); result->maxAffected.z = MAX(result->maxAffected.z, (int)(*(pi + 2) + *si)); } tmpPointList.add({*pi, *(pi + 1), *(pi + 2)}); tmpSizeList.add(*si); } else { outsideCounter++; if (outsideCounter >= newWormThreshold) { if (result != 0) { result->keyPoints = new float[tmpPointList.getEintragAnzahl() * 3]; result->keyPointSize = new float[tmpPointList.getEintragAnzahl()]; float* rkeyPointsP = result->keyPoints; float* rkeyPointSizeP = result->keyPointSize; auto rpi = tmpPointList.begin(); auto rsi = tmpSizeList.begin(); while (rpi) { *(rkeyPointsP++) = rpi.val().x; *(rkeyPointsP++) = rpi.val().y; *(rkeyPointsP++) = rpi.val().z; *(rkeyPointSizeP++) = rsi.val(); ++rpi; ++rsi; } tmpPointList.leeren(); tmpSizeList.leeren(); zResult->add(result); result = 0; } outsideCounter = 0; } } pi += 3; ++si; } } if (result) { result->keyPoints = new float[tmpPointList.getEintragAnzahl() * 3]; result->keyPointSize = new float[tmpPointList.getEintragAnzahl()]; float* rkeyPointsP = result->keyPoints; float* rkeyPointSizeP = result->keyPointSize; auto rpi = tmpPointList.begin(); auto rsi = tmpSizeList.begin(); while (rpi) { *(rkeyPointsP++) = rpi.val().x; *(rkeyPointsP++) = rpi.val().y; *(rkeyPointsP++) = rpi.val().z; *(rkeyPointSizeP++) = rsi.val(); ++rpi; ++rsi; } zResult->add(result); } } bool NoiseWorm3D::isInside(int x, int y, int z) { if (x >= minAffected.x && x <= maxAffected.x && y >= minAffected.y && y <= maxAffected.y && z >= minAffected.z && z <= maxAffected.z) { float* pi = keyPoints; float* si = keyPointSize; while (pi && si) { if (Framework::Vec3((float)x, (float)y, (float)z) .abstandSq({*pi, *(pi + 1), *(pi + 2)}) < *si * *si) return 1; pi += 3; ++si; } } return 0; } WormCaveChunkGenerator::WormCaveChunkGenerator( Framework::RCArray worms) : CaveChunkGenerator(), worms(worms) {} bool WormCaveChunkGenerator::isInCave(int x, int y, int z) { for (NoiseWorm3D* w : worms) { if (w->isInside(x, y, z)) return 1; } return 0; } WormCaveGenerator::WormCaveGenerator(int minDistant, int maxDistant, int minRadius, int maxRadius, float cavePosibillityPerChunk, int seed) : CaveGenerator(seed), maxDistant(maxDistant), minDistant(minDistant), maxRadius(maxRadius), minRadius(minRadius), cavePosibillity(cavePosibillityPerChunk), wormStartNoise(new RandNoise(seed)) {} WormCaveGenerator::~WormCaveGenerator() { wormStartNoise->release(); } NoiseWorm3D* WormCaveGenerator::zWormOfChunk(int x, int y) { for (NoiseWorm3D* worm : cache) { if (worm->getStartChunkCenter().x == x && worm->getStartChunkCenter().y == y) { return worm; } } float cNoise = (float)wormStartNoise->getNoise((double)x, (double)y, (double)0); if (cNoise < cavePosibillity) { FastNoiseLite* noise = new FastNoiseLite(seed + x * y + y + x); noise->SetNoiseType(FastNoiseLite::NoiseType::NoiseType_Perlin); noise->SetFrequency(0.05f); FastNoiseWrapper* pitch = new FastNoiseWrapper(noise, seed + x * y + y + x); noise = new FastNoiseLite(seed + x * y + y + x); noise->SetNoiseType(FastNoiseLite::NoiseType::NoiseType_Perlin); noise->SetFrequency(0.005f); FastNoiseWrapper* yaw = new FastNoiseWrapper(noise, seed - x * y - y - x); Framework::Vec3 start( (int)(cNoise / cavePosibillity * CHUNK_SIZE) + x - CHUNK_SIZE / 2, (int)(cNoise / cavePosibillity * CHUNK_SIZE) + y - CHUNK_SIZE / 2, (int)(cNoise / cavePosibillity * 200)); noise = new FastNoiseLite( seed + start.getLengthSq() + start.x + start.y + start.z); noise->SetNoiseType(FastNoiseLite::NoiseType::NoiseType_Perlin); noise->SetFrequency(0.005f); FastNoiseWrapper* size = new FastNoiseWrapper( noise, seed + start.getLengthSq() + start.x + start.y + start.z); NoiseWorm3D* worm = new NoiseWorm3D(pitch, yaw, size, start, (int)(wormStartNoise->getNoise( (double)start.x, (double)start.y, (double)start.z) * (maxDistant - minDistant) + minDistant), minRadius, maxRadius); if (cache.getEintragAnzahl() > (maxDistant * 2) / CHUNK_SIZE * (maxDistant * 2) / CHUNK_SIZE * 3) cache.remove(0); cache.add(worm); return worm; } return 0; } CaveChunkGenerator* WormCaveGenerator::getGeneratorForChunk(int x, int y) { Framework::RCArray affected; Framework::Punkt center = Game::getChunkCenter(x, y); int offset = (int)ceil((float)maxDistant / CHUNK_SIZE); for (int cx = -offset; cx <= offset; cx++) { for (int cy = -offset; cy <= offset; cy++) { NoiseWorm3D* worm = zWormOfChunk( center.x + cx * CHUNK_SIZE, center.y + cy * CHUNK_SIZE); if (worm) worm->getPartAffectedByChunk(x, y, &affected); } } return new WormCaveChunkGenerator(affected); }