#include "DimensionGenerator.h" #include "Constants.h" #include "Noise.h" #include "NoBlock.h" #include DimensionGenerator::DimensionGenerator( int dimensionId ) : ReferenceCounter(), dimensionId( dimensionId ), minTemplateAffectedPosition( 0, 0, 0 ), maxTemplateAffectedPosition( 0, 0, 0 ) { StaticRegistry::INSTANCE.registerT( this, dimensionId ); } DimensionGenerator::~DimensionGenerator() {} BiomGenerator* DimensionGenerator::zBiomGenerator( int seed, int x, int y ) { double noise = zBiomNoise( seed )->getNoise( (double)x, (double)y, 0.0 ); double border = 0; BiomGenerator* gen = 0; auto genI = biomGenerators.begin(); auto distI = biomDistribution.begin(); do { border += (double)distI++; gen = genI++; } while( border < noise && (bool)distI && (bool)genI ); return gen; } void DimensionGenerator::registerBiom( BiomGenerator* generator, double possibility ) { biomGenerators.add( generator ); biomDistribution.add( possibility ); for( auto t : generator->getTemplates() ) { minTemplateAffectedPosition.x = MIN( minTemplateAffectedPosition.x, t->getMinAffectedOffset().x ); minTemplateAffectedPosition.y = MIN( minTemplateAffectedPosition.y, t->getMinAffectedOffset().y ); minTemplateAffectedPosition.z = MIN( minTemplateAffectedPosition.z, t->getMinAffectedOffset().z ); maxTemplateAffectedPosition.x = MAX( maxTemplateAffectedPosition.x, t->getMaxAffectedOffset().x ); maxTemplateAffectedPosition.y = MAX( maxTemplateAffectedPosition.y, t->getMaxAffectedOffset().y ); maxTemplateAffectedPosition.z = MAX( maxTemplateAffectedPosition.z, t->getMaxAffectedOffset().z ); } } Framework::RCArray* DimensionGenerator::getGeneratedStructoresForArea( int seed, Framework::Vec3 minPos, Framework::Vec3 maxPos ) { Framework::RCArray* result = new Framework::RCArray(); int minSearchX = minPos.x - maxTemplateAffectedPosition.x; int minSearchY = minPos.y - maxTemplateAffectedPosition.y; int minSearchZ = MAX( minPos.z - maxTemplateAffectedPosition.z, 0 ); int maxSearchX = maxPos.x - minTemplateAffectedPosition.x; int maxSearchY = maxPos.y - minTemplateAffectedPosition.y; int maxSearchZ = MIN( maxPos.z - minTemplateAffectedPosition.z, WORLD_HEIGHT - 1 ); Noise* structureNoise = zStructureNoise( seed + dimensionId ); for( int x = minSearchX; x <= maxSearchX; x++ ) { for( int y = minSearchY; y <= maxSearchY; y++ ) { BiomGenerator* biom = zBiomGenerator( seed + dimensionId, x, y ); int height = MIN_AIR_LEVEL + (int)(biom->zHeightMapNoise( seed + dimensionId )->getNoise( (double)(x), (double)(y), 0.0 ) * (MAX_AIR_LEVEL - MIN_AIR_LEVEL)); for( int z = minSearchZ; z <= maxSearchZ; z++ ) { if( z < height ) { double rValue = structureNoise->getNoise( (double)x, (double)y, (double)z ); double probSum = 0; for( auto t : biom->getTemplates() ) { if( t->isGenerationPossable( Framework::Vec3( x, y, z ), height - z ) ) { if( rValue - probSum <= t->getPropability() ) { result->add( t->generateAt( Framework::Vec3( x, y, z ), structureNoise ) ); break; } } probSum += t->getPropability(); } } } } } return result; } Chunk* DimensionGenerator::generateChunk( int seed, int centerX, int centerY ) { Framework::RCArray* structures = getGeneratedStructoresForArea( seed, Framework::Vec3( centerX - CHUNK_SIZE / 2, centerY - CHUNK_SIZE / 2, 0 ), Framework::Vec3( centerX + CHUNK_SIZE / 2, centerY + CHUNK_SIZE / 2, WORLD_HEIGHT - 1 ) ); std::cout << "generating chunk " << centerX << ", " << centerY << "\n"; Chunk* chunk = new Chunk( Framework::Punkt( centerX, centerY ), dimensionId ); for( int x = -CHUNK_SIZE / 2; x < CHUNK_SIZE / 2; x++ ) { for( int y = -CHUNK_SIZE / 2; y < CHUNK_SIZE / 2; y++ ) { BiomGenerator* biom = zBiomGenerator( seed + dimensionId, x + centerX, y + centerY ); // TODO: use Noise interpolator for height map between different bioms int height = MIN_AIR_LEVEL + (int)(biom->zHeightMapNoise( seed + dimensionId )->getNoise( (double)(x + centerX), (double)(y + centerY), 0.0 ) * (MAX_AIR_LEVEL - MIN_AIR_LEVEL)); int maxSurfaceHeight = (int)(MAX_SURFACE_HEIGHT * (1.f - (float)(height - MIN_AIR_LEVEL) / (float)(MAX_AIR_LEVEL - MIN_AIR_LEVEL))); int actualSurfaceHeight = (int)((float)maxSurfaceHeight * (1.f - VARIABLE_SURFACE_PART) + ((float)maxSurfaceHeight * VARIABLE_SURFACE_PART * (float)biom->zHeightMapNoise( seed + dimensionId )->getNoise( (double)(x + centerX), (double)(y + centerY), 10.0 ))); for( int z = 0; z < WORLD_HEIGHT; z++ ) { Framework::Either generated = AirBlockBlockType::ID; bool structureAffected = 0; for( auto structure : *structures ) { if( structure->isBlockAffected( Framework::Vec3( x + centerX, y + centerY, z ) ) ) { generated = structure->generateBlockAt( Framework::Vec3( x + centerX, y + centerY, z ) ); structureAffected = 1; break; } } if( !structureAffected ) { if( z < height && z >= height - actualSurfaceHeight ) generated = biom->generateSurfaceBlock( x + centerX, y + centerY, z ); else if( z < height ) generated = biom->generateBelowSurfaceBlock( x + centerX, y + centerY, z ); } if( generated.isA() ) chunk->putBlockAt( Framework::Vec3( x + CHUNK_SIZE / 2, y + CHUNK_SIZE / 2, z ), generated ); else chunk->putBlockTypeAt( Framework::Vec3( x + CHUNK_SIZE / 2, y + CHUNK_SIZE / 2, z ), generated ); } } } structures->release(); return chunk; } Framework::Either DimensionGenerator::generateBlock( int seed, Framework::Vec3 location ) { Framework::RCArray* structures = getGeneratedStructoresForArea( seed, location, location ); BiomGenerator* biom = zBiomGenerator( seed + dimensionId, location.x, location.y ); // TODO: use Noise interpolator for height map between different bioms int height = MIN_AIR_LEVEL + (int)(biom->zHeightMapNoise( seed + dimensionId )->getNoise( (double)(location.x), (double)(location.y), 0.0 ) * (MAX_AIR_LEVEL - MIN_AIR_LEVEL)); int maxSurfaceHeight = (int)(MAX_SURFACE_HEIGHT * (1.f - (float)(height - MIN_AIR_LEVEL) / (float)(MAX_AIR_LEVEL - MIN_AIR_LEVEL))); int actualSurfaceHeight = (int)((float)maxSurfaceHeight * (1.f - VARIABLE_SURFACE_PART) + ((float)maxSurfaceHeight * VARIABLE_SURFACE_PART * (float)biom->zHeightMapNoise( seed + dimensionId )->getNoise( (double)(location.x), (double)(location.y), 10.0 ))); for( auto structure : *structures ) { if( structure->isBlockAffected( location ) ) { auto generated = structure->generateBlockAt( location ); structures->release(); return generated; } } structures->release(); if( location.z < height && location.z >= height - actualSurfaceHeight ) return biom->generateSurfaceBlock( location.x, location.y, location.z ); else if( location.z < height ) return biom->generateBelowSurfaceBlock( location.x, location.y, location.z ); return AirBlockBlockType::ID; } int DimensionGenerator::getDimensionId() const { return dimensionId; }