#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; keyPoints.add(lastPos); this->size.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 (keyPoints.getEintragAnzahl() < distant * 20) { Framework::Vec3 defaultDir(1.f, 0.f, 0.f); if (keyPoints.getEintragAnzahl() > 1) { defaultDir = keyPoints.get(keyPoints.getEintragAnzahl() - 1) - keyPoints.get(keyPoints.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; keyPoints.add(lastPos); float rad = (float)size->getNoise(lastPos.x, lastPos.y, lastPos.z) * (float)(maxRad - minRad) + (float)minRad; this->size.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)); } } Framework::Punkt NoiseWorm3D::getStartChunkCenter() { return startChunk; } void NoiseWorm3D::getPartAffectedByChunk( int x, int y, Framework::RCArray* zResult) { NoiseWorm3D* result = 0; 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) { auto pi = keyPoints.begin(); auto si = size.begin(); int newWormThreshold = 5; int outsideCounter = 0; while (pi && si) { if ((Framework::Vec2((float)x, (float)y) - Framework::Vec2(pi.val().x, pi.val().y)) .getLengthSq() < (si.val() + CHUNK_SIZE / 2) * (si.val() + CHUNK_SIZE / 2)) { outsideCounter = 0; if (result == 0) { result = new NoiseWorm3D(); result->minAffected.x = (int)(pi.val().x - si.val()); result->minAffected.y = (int)(pi.val().y - si.val()); result->minAffected.z = (int)(pi.val().z - si.val()); result->maxAffected.x = (int)(pi.val().x + si.val()); result->maxAffected.y = (int)(pi.val().y + si.val()); result->maxAffected.z = (int)(pi.val().z + si.val()); } else { result->minAffected.x = MIN( result->minAffected.x, (int)(pi.val().x - si.val())); result->minAffected.y = MIN( result->minAffected.y, (int)(pi.val().y - si.val())); result->minAffected.z = MIN( result->minAffected.z, (int)(pi.val().z - si.val())); result->maxAffected.x = MAX( result->maxAffected.x, (int)(pi.val().x + si.val())); result->maxAffected.y = MAX( result->maxAffected.y, (int)(pi.val().y + si.val())); result->maxAffected.z = MAX( result->maxAffected.z, (int)(pi.val().z + si.val())); } result->keyPoints.add(pi.val()); result->size.add(si.val()); } else { outsideCounter++; if (outsideCounter >= newWormThreshold) { if (result != 0) { zResult->add(result); result = 0; } outsideCounter = 0; } } ++pi; ++si; } } if (result) { 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) { auto pi = keyPoints.begin(); auto si = size.begin(); while (pi && si) { if (Framework::Vec3((float)x, (float)y, (float)z) .abstandSq(pi.val()) < si.val() * si.val()) return 1; ++pi; ++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; } } for (Framework::Punkt p : noWormChunks) { if (p.x == x && p.y == y) return 0; } float cNoise = (float)wormStartNoise->getNoise(x, y, 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(start.x, start.y, 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; } else { if (noWormChunks.getEintragAnzahl() > (maxDistant * 2) / CHUNK_SIZE * (maxDistant * 2) / CHUNK_SIZE * 3) noWormChunks.remove(0); noWormChunks.add(Framework::Punkt(x, y)); } 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); }