#include "generator.h" #include "../../../ext.h" #include "voxel.h" #include #include #include #include #include #include #include #include namespace { bool SWIZZLE_OPTIMIZATION = false; ext::TerrainVoxel::light_t AMBIENT_LIGHT = 0x6666; //{std::numeric_limits::max(), std::numeric_limits::max(), std::numeric_limits::max()}; struct COLOR { uint r : 4; uint g : 4; uint b : 4; uint a : 4; }; COLOR uint16ToColor( uint16_t color ) { COLOR result; memcpy( &result, &color, sizeof color ); return result; } uint16_t colorToUint16( COLOR color ) { uint16_t result; memcpy( &result, &color, sizeof color ); return result; } bool inBounds( int x, int y, int z, const pod::Vector3ui& size ) { return (x >= 0 && x < size.x && y >= 0 && y < size.y && z >= 0 && z < size.z); } } ext::TerrainGenerator::Swizzle ext::TerrainGenerator::DEFAULT_SWIZZLE = Swizzle::YZX; uf::PerlinNoise ext::TerrainGenerator::noise; void ext::TerrainGenerator::initialize( const pod::Vector3ui& size, uint modulus ){ this->m_size = size; this->m_modulus = modulus; } void ext::TerrainGenerator::destroy(){ /* if ( !this->m_voxels.id.raw ) return; for ( uint x = 0; x < this->m_size.x; ++x ) { for ( uint y = 0; y < this->m_size.y; ++y ) delete[] this->m_voxels.id.raw[x][y]; delete[] this->m_voxels.id.raw[x]; } delete[] this->m_voxels.id.raw; this->m_voxels.id.raw = NULL; */ // this->m_voxels.id.raw.clear(); // this->m_voxels.lighting.raw.clear(); } void ext::TerrainGenerator::generate( ext::Region& region ){ // if ( !this->m_voxels.id.raw.empty() || !this->m_voxels.id.rle.empty() ) return; this->destroy(); uint half_x = this->m_size.x / 2; uint half_y = this->m_size.y / 2; uint half_z = this->m_size.z / 2; const pod::Transform<>& transform = region.getComponent>(); const pod::Vector3i location = { transform.position.x / this->m_size.x, transform.position.y / this->m_size.y, transform.position.z / this->m_size.z, }; this->m_location = location; this->m_terrain = ®ion.getParent(); /* COLOR ambientLight = uint16ToColor(AMBIENT_LIGHT); { uf::Serializer& tMetadata = region.getComponent(); ambientLight.r *= tMetadata["region"]["light"]["ambient"][0].asFloat(); ambientLight.g *= tMetadata["region"]["light"]["ambient"][1].asFloat(); ambientLight.b *= tMetadata["region"]["light"]["ambient"][2].asFloat(); } */ std::string base = region.getParent().getComponent()["_config"]["hash"].asString(); std::string filename = "./data/save/" + base + "/regions/" + std::to_string(location.x) + "." + std::to_string(location.y) + "." + std::to_string(location.z) + ".json"; // old region, load save if ( uf::string::exists( filename ) ) { uf::Serializer save; save.readFromFile(filename); // ID if ( save["voxels"]["id"]["base64"].isString() ) { std::string base64 = save["voxels"]["id"]["base64"].asString(); auto raw = uf::base64::decode( base64 ); if ( save["voxels"]["id"]["rle"].asBool() ) { // [uint8_t]*4 -> [uint16_t, uint16_t] this->m_voxels.id.rle.resize( raw.size() / ( sizeof(pod::RLE::length_t) + sizeof(pod::RLE::value_t) ) ); memcpy( &this->m_voxels.id.rle[0], &raw[0], raw.size() ); // normal voxel load or something } else { } this->m_voxels.id.swizzle = (TerrainGenerator::Swizzle) save["voxels"]["id"]["swizzle"].asUInt64(); this->unwrapVoxel(); } // Lighting if ( save["voxels"]["lighting"]["base64"].isString() ) { std::string base64 = save["voxels"]["lighting"]["base64"].asString(); auto raw = uf::base64::decode( base64 ); if ( save["voxels"]["lighting"]["rle"].asBool() ) { // [uint8_t]*4 -> [uint8_t, uint8_t] this->m_voxels.lighting.rle.resize( raw.size() / ( sizeof(pod::RLE::length_t) + sizeof(pod::RLE::value_t) ) ); memcpy( &this->m_voxels.lighting.rle[0], &raw[0], raw.size() ); // normal voxel load or something } else { } this->m_voxels.lighting.swizzle = (TerrainGenerator::Swizzle) save["voxels"]["lighting"]["swizzle"].asUInt64(); this->unwrapLight(); } // load failed / new region } // maze /* { ext::Maze& maze = this->m_terrain->getComponent(); int ROW = this->m_location.z + (maze.WIDTH / 2) - 1; int COL = this->m_location.x + (maze.LENGTH / 2) - 1; auto value = maze( ROW, COL, 0 ); bool east = value & ext::Maze::EAST; // ROW + 1 < maze.WIDTH ? maze( ROW + 1, COL, 1 ) : 0; bool west = value & ext::Maze::WEST; // ROW - 1 > 0 ? maze( ROW - 1, COL, 1 ) : 0; bool north = value & ext::Maze::NORTH; // COL + 1 < maze.LENGTH ? maze( ROW, COL + 1, 1 ) : 0; bool south = value & ext::Maze::SOUTH; // COL - 1 > 0 ? maze( ROW, COL - 1, 1 ) : 0; std::cout << ROW << ", " << COL << " = " << value << "\t" << east << " " << west << " " << north << " " << south << std::endl; } */ if ( this->m_voxels.id.rle.empty() ) { double maxValue = 0.0; double base = 0; ext::TerrainVoxel::uid_t raw_id[this->m_size.x][this->m_size.y][this->m_size.z]; ext::TerrainVoxel::light_t raw_lighting[this->m_size.x][this->m_size.y][this->m_size.z]; double raw_noise[this->m_size.x][this->m_size.y][this->m_size.z]; for ( uint y = 0; y < this->m_size.y; ++y ) for ( uint z = 0; z < this->m_size.z; ++z ) for ( uint x = 0; x < this->m_size.x; ++x ) { pod::Vector3d position = { transform.position.x - half_x, transform.position.y - half_y, transform.position.z - half_z }; position.x += (double) x / (double) this->m_size.x; position.y += (double) y / (double) this->m_size.y; position.z += (double) z / (double) this->m_size.z; raw_noise[x][y][z] = ext::TerrainGenerator::noise.sample( position ); maxValue = std::max( maxValue, raw_noise[x][y][z] ); } for ( uint y = 0; y < this->m_size.y; ++y ) for ( uint z = 0; z < this->m_size.z; ++z ) for ( uint x = 0; x < this->m_size.x; ++x ) base += raw_noise[x][y][z] / maxValue; base /= this->m_size.x * this->m_size.y * this->m_size.z; uint partitions = this->m_modulus; struct { ext::TerrainVoxel::uid_t floor = ext::TerrainVoxelFloor().uid(); ext::TerrainVoxel::uid_t wall = ext::TerrainVoxelWall().uid(); ext::TerrainVoxel::uid_t ceiling = ext::TerrainVoxelCeiling().uid(); ext::TerrainVoxel::uid_t stair = ext::TerrainVoxelStair().uid(); ext::TerrainVoxel::uid_t pillar = ext::TerrainVoxelPillar().uid(); ext::TerrainVoxel::uid_t lava = ext::TerrainVoxelLava().uid(); } atlas; this->m_voxels.id.raw.reserve( this->m_size.x * this->m_size.y * this->m_size.z ); this->m_voxels.lighting.raw.reserve( this->m_size.x * this->m_size.y * this->m_size.z ); ext::Maze& maze = this->m_terrain->getComponent(); int LABYRINTH = ext::Maze::FLOOR | ext::Maze::CEIL; { int ROW = this->m_location.z + (maze.WIDTH / 2) - 1; int COL = this->m_location.x + (maze.LENGTH / 2) - 1; if ( ROW >= 0 && ROW < maze.WIDTH && COL >= 0 && COL < maze.LENGTH ) LABYRINTH = maze( ROW, COL, 0 ); } std::size_t i = 0; for ( uint y = 0; y < this->m_size.y; ++y ) { for ( uint z = 0; z < this->m_size.z; ++z ) { for ( uint x = 0; x < this->m_size.x; ++x ) { ext::TerrainVoxel::uid_t voxel = 0; double e = raw_noise[x][y][z] / maxValue; // generate walls if wall exists in maze // if ( (x) % (this->m_size.x / partitions) == 0 ) voxel = atlas.wall; // if ( (z) % (this->m_size.z / partitions) == 0 ) voxel = atlas.wall; /* if ( (x + 1) % (this->m_size.x / partitions) == 0 ) voxel = atlas.wall; if ( (z + 1) % (this->m_size.z / partitions) == 0 ) voxel = atlas.wall; if ( y > 0 && y < this->m_size.y - 1 ) { if ( x % (this->m_size.x / partitions) >= 3 && x % (this->m_size.x / partitions) <= partitions - 4 ) voxel = 0; if ( z % (this->m_size.z / partitions) >= 3 && z % (this->m_size.z / partitions) <= partitions - 4 ) voxel = 0; } */ if ( y <= 1 ) voxel = atlas.floor; if ( y == this->m_size.y - 1 ) voxel = atlas.ceiling; if ( uf::vector::sum(location) != 0 ) { if ( e < 0.5 ) voxel = y == 0 ? atlas.lava : 0; // if ( raw_noise[x][1][z] / maxValue < 0.2 || raw_noise[x][2][z] / maxValue > 0.8 ) voxel = atlas.stair; if ( raw_noise[x][1][z] < 0.2 || raw_noise[x][2][z] > 0.8 ) voxel = atlas.stair; } else { // if ( x == half_x && y == 4 && z == half_z ) voxel = atlas.lava; } auto light = ext::TerrainVoxel::atlas(voxel).light(); if ( LABYRINTH & ext::Maze::EAST ) if ( x == 0 ) voxel = atlas.wall; if ( LABYRINTH & ext::Maze::WEST ) if ( x == this->m_size.x - 1 ) voxel = atlas.wall; if ( LABYRINTH & ext::Maze::NORTH ) if ( z == 0 ) voxel = atlas.wall; if ( LABYRINTH & ext::Maze::SOUTH ) if ( z == this->m_size.z - 1 ) voxel = atlas.wall; // if ( LABYRINTH & ext::Maze::FLOOR ) if ( y == 0 ) voxel = atlas.floor; // if ( LABYRINTH & ext::Maze::CEIL ) if ( y == this->m_size.y - 1 ) voxel = atlas.ceiling; if ( light < AMBIENT_LIGHT ) light = AMBIENT_LIGHT; raw_id[x][y][z] = voxel; raw_lighting[x][y][z] = light; // write to raw buffers this->m_voxels.id.raw.push_back(voxel); this->m_voxels.lighting.raw.push_back(light); } } } uf::Serializer serializer; // redundant but sure serializer["location"][0] = location.x; serializer["location"][1] = location.y; serializer["location"][2] = location.z; this->writeToFile(); } this->destroy(); } void ext::TerrainGenerator::writeToFile() { this->wrapVoxel(); this->wrapLight(); uf::Serializer serializer; std::string base = this->m_terrain ? this->m_terrain->getComponent()["_config"]["hash"].asString() : "UNKNOWN"; std::string filename = "./data/save/" + base + "/regions/" + std::to_string(this->m_location.x) + "." + std::to_string(this->m_location.y) + "." + std::to_string(this->m_location.z) + ".json"; { // encode as base64, json safe serializer["voxels"]["id"]["base64"] = uf::base64::encode( this->m_voxels.id.rle ); // hash of raw data for data integrity serializer["voxels"]["id"]["hash"] = uf::string::sha256( uf::base64::decode(serializer["voxels"]["id"]["rle"]["base64"].asString()) ); serializer["voxels"]["id"]["rle"] = true; serializer["voxels"]["id"]["swizzle"] = this->m_voxels.id.swizzle; } { // encode as base64, json safe serializer["voxels"]["lighting"]["base64"] = uf::base64::encode( this->m_voxels.lighting.rle ); // hash of raw data for data integrity serializer["voxels"]["lighting"]["hash"] = uf::string::sha256( uf::base64::decode(serializer["voxels"]["lighting"]["rle"]["base64"].asString()) ); serializer["voxels"]["lighting"]["rle"] = true; serializer["voxels"]["lighting"]["swizzle"] = this->m_voxels.lighting.swizzle; } serializer.writeToFile(filename); this->destroy(); } std::vector ext::TerrainGenerator::getRawVoxels() { return this->m_voxels.id.raw; } const pod::RLE::string_t& ext::TerrainGenerator::getVoxels() const { return this->m_voxels.id.rle; } ext::TerrainVoxel::uid_t ext::TerrainGenerator::getVoxel( int x, int y, int z ) const { // check oob if ( !inBounds( x, y, z, this->m_size ) ) { if ( !this->m_terrain ) return 0; const ext::Terrain& terrain = *((const ext::Terrain*)this->m_terrain); pod::Vector3i location = this->m_location; while ( !inBounds( x, y, z, this->m_size ) ) { if ( x < 0 ) { x += this->m_size.x; --location.x; } else if ( x >= this->m_size.x ) { x -= this->m_size.x; ++location.x; } if ( y < 0 ) { y += this->m_size.y; --location.y; } else if ( y >= this->m_size.y ) { y -= this->m_size.y; ++location.y; } if ( z < 0 ) { z += this->m_size.z; --location.z; } else if ( z >= this->m_size.z ) { z -= this->m_size.z; ++location.z; } } ext::Region* region = terrain.at( location ); if ( !region ) return 0; return region->getComponent().getVoxel( x, y, z ); /* while ( x < 0 ) { --location.x; x += this->m_size.x; } while ( x >= this->m_size.x - 1 ) { ++location.x; x -= this->m_size.x; } while ( y < 0 ) { --location.y; y += this->m_size.y; } while ( y >= this->m_size.y - 1 ) { ++location.y; y -= this->m_size.y; } while ( z < 0 ) { --location.z; z += this->m_size.z; } while ( z >= this->m_size.z - 1 ) { ++location.z; z -= this->m_size.z; } ext::Region* region = terrain.at( location ); if ( !region ) return 0; return region->getComponent().getVoxel( x, y, z ); */ } // if ( this->m_voxels.id.raw ) return this->m_voxels.id.raw[x][y][z]; if ( !this->m_voxels.id.raw.empty() ) { std::size_t i = this->wrapPosition( x, y, z, this->m_voxels.id.swizzle ); return this->m_voxels.id.raw[i]; } std::size_t i = 0; for ( auto& _ : this->m_voxels.id.rle ) { for ( std::size_t __ = 0; __ < _.length; ++__ ) { auto v = this->unwrapIndex( i++, this->m_voxels.id.swizzle ); if ( v.x == x && v.y == y && v.z == z ) return _.value; } } return 0; } ext::TerrainVoxel::uid_t ext::TerrainGenerator::getVoxel( const pod::Vector3i& location ) const { return this->getVoxel( location.x, location.y, location.z ); } ext::TerrainVoxel::light_t ext::TerrainGenerator::getLight( int x, int y, int z ) const { // check oob if ( !inBounds( x, y, z, this->m_size ) ) { if ( !this->m_terrain ) { // std::cout << "Invalid call @ getLight( " << x << ", " << y << ", " << z << " ) " << std::endl; return 0x0000; } const ext::Terrain& terrain = *((const ext::Terrain*)this->m_terrain); pod::Vector3i location = this->m_location; while ( !inBounds( x, y, z, this->m_size ) ) { if ( x < 0 ) { x += this->m_size.x; --location.x; } else if ( x >= this->m_size.x ) { x -= this->m_size.x; ++location.x; } if ( y < 0 ) { y += this->m_size.y; --location.y; } else if ( y >= this->m_size.y ) { y -= this->m_size.y; ++location.y; } if ( z < 0 ) { z += this->m_size.z; --location.z; } else if ( z >= this->m_size.z ) { z -= this->m_size.z; ++location.z; } } /* while ( x < 0 ) { --location.x; x += this->m_size.x; } while ( x >= this->m_size.x - 1 ) { ++location.x; x -= this->m_size.x - 1; } while ( y < 0 ) { --location.y; y += this->m_size.y; } while ( y >= this->m_size.y - 1 ) { ++location.y; y -= this->m_size.y - 1; } while ( z < 0 ) { --location.z; z += this->m_size.z; } while ( z >= this->m_size.z - 1 ) { ++location.z; z -= this->m_size.z - 1; } */ ext::Region* region = terrain.at( location ); if ( !region ) { // std::cout << "Out of bounds Region("<< location.x << ", " << location.y << ", " << location.z <<") @ getLight( " << x << ", " << y << ", " << z << " ) " << std::endl; return 0xFFFF; } return region->getComponent().getLight( x, y, z ); } /* if ( !this->m_voxels.lighting.raw.empty() ) { std::size_t i = this->wrapPosition( x, y, z, this->m_voxels.lighting.swizzle ); return this->m_voxels.lighting.raw[i]; } */ std::size_t i = 0; for ( auto& _ : this->m_voxels.lighting.rle ) { for ( std::size_t __ = 0; __ < _.length; ++__ ) { auto v = this->unwrapIndex( i++, this->m_voxels.lighting.swizzle ); if ( v.x == x && v.y == y && v.z == z ) { return _.value; } } } return 0x0000; } ext::TerrainVoxel::light_t ext::TerrainGenerator::getLight( const pod::Vector3i& location ) const { return this->getLight( location.x, location.y, location.z ); } pod::Vector3ui ext::TerrainGenerator::unwrapIndex( std::size_t i, Swizzle swizzle ) const { // ordered from first to change to last to change /* result.x = i % this->m_size.x; result.y = ( i / this->m_size.x ) % this->m_size.y; result.z = i / ( this->m_size.x * this->m_size.y ); */ pod::Vector3ui size; switch ( swizzle ) { case Swizzle::YZX: size = { this->m_size.x, this->m_size.z, this->m_size.y, }; return { i % size.x, i / ( size.x * size.y ), ( i / size.x ) % size.y, }; break; case Swizzle::ZXY: size = { this->m_size.y, this->m_size.x, this->m_size.z, }; return { ( i / size.x ) % size.y, i % size.x, i / ( size.x * size.y ), }; break; case Swizzle::XYZ: default: size = { this->m_size.z, this->m_size.y, this->m_size.x, }; return { ( i / size.x ) % size.y, i / ( size.x * size.y ), i % size.x, }; break; } } // (y, z, x) -> (x, y, z) std::size_t ext::TerrainGenerator::wrapPosition( uint x, uint y, uint z, Swizzle swizzle ) const { // ordered from first to change to last to change pod::Vector3ui input; pod::Vector3ui size; switch ( swizzle ) { case Swizzle::YZX: input = { x, z, y, }; size = { this->m_size.x, this->m_size.z, this->m_size.y, }; break; case Swizzle::ZXY: input = { y, x, z, }; size = { this->m_size.y, this->m_size.x, this->m_size.z, }; break; case Swizzle::XYZ: input = { z, y, x, }; size = { this->m_size.z, this->m_size.y, this->m_size.x, }; break; } return size.y * size.x * input.z + size.x * input.y + input.x; // return size.z * size.x * input.y + size.x * input.z + input.x; // return (x * this->m_size.y * this->m_size.z) + (z * this->m_size.y) + y; } std::size_t ext::TerrainGenerator::wrapPosition( const pod::Vector3ui& position, Swizzle swizzle ) const { return this->wrapPosition( position.x, position.y, position.z, swizzle ); } void ext::TerrainGenerator::wrapVoxel() { if ( this->m_voxels.id.raw.empty() ) return; this->m_voxels.id.rle.clear(); ext::TerrainVoxel::uid_t raw_id[this->m_size.x][this->m_size.y][this->m_size.z]; this->m_voxels.id.swizzle = ext::TerrainGenerator::DEFAULT_SWIZZLE; for ( std::size_t i = 0; i < this->m_size.x * this->m_size.y * this->m_size.z; ++i ) { auto position = this->unwrapIndex( i, this->m_voxels.id.swizzle ); raw_id[position.x][position.y][position.z] = this->m_voxels.id.raw[i]; } std::vector buffer; buffer.reserve( this->m_size.x * this->m_size.y * this->m_size.z ); // use YZX if ( SWIZZLE_OPTIMIZATION ) { pod::RLE::string_t xyz, yzx, zxy; { for ( uint x = 0; x < this->m_size.x; x++ ) for ( uint y = 0; y < this->m_size.y; y++ ) for ( uint z = 0; z < this->m_size.z; z++ ) buffer.push_back( raw_id[x][y][z] ); xyz = uf::rle::encode( buffer ); } buffer.clear(); buffer.reserve( this->m_size.x * this->m_size.y * this->m_size.z ); { for ( uint y = 0; y < this->m_size.y; y++ ) for ( uint z = 0; z < this->m_size.z; z++ ) for ( uint x = 0; x < this->m_size.x; x++ ) buffer.push_back( raw_id[x][y][z] ); yzx = uf::rle::encode( buffer ); } buffer.clear(); buffer.reserve( this->m_size.x * this->m_size.y * this->m_size.z ); { for ( uint z = 0; z < this->m_size.z; z++ ) for ( uint x = 0; x < this->m_size.x; x++ ) for ( uint y = 0; y < this->m_size.y; y++ ) buffer.push_back( raw_id[x][y][z] ); zxy = uf::rle::encode( buffer ); } // xyz if ( xyz.size() <= yzx.size() && xyz.size() <= zxy.size() ) { this->m_voxels.id.swizzle = Swizzle::XYZ; this->m_voxels.id.rle = xyz; // yzx } else if ( yzx.size() <= xyz.size() && yzx.size() <= zxy.size() ) { this->m_voxels.id.swizzle = Swizzle::YZX; this->m_voxels.id.rle = yzx; } else if ( zxy.size() <= xyz.size() && zxy.size() <= yzx.size() ) { this->m_voxels.id.swizzle = Swizzle::ZXY; this->m_voxels.id.rle = zxy; } else { this->m_voxels.id.swizzle = Swizzle::YZX; this->m_voxels.id.rle = yzx; } } else { for ( uint y = 0; y < this->m_size.y; y++ ) for ( uint z = 0; z < this->m_size.z; z++ ) for ( uint x = 0; x < this->m_size.x; x++ ) buffer.push_back( raw_id[x][y][z] ); this->m_voxels.id.swizzle = Swizzle::YZX; this->m_voxels.id.rle = uf::rle::encode( buffer ); } } void ext::TerrainGenerator::wrapLight() { if ( this->m_voxels.lighting.raw.empty() ) return; this->m_voxels.lighting.rle.clear(); ext::TerrainVoxel::light_t raw_lighting[this->m_size.x][this->m_size.y][this->m_size.z]; this->m_voxels.lighting.swizzle = ext::TerrainGenerator::DEFAULT_SWIZZLE; for ( std::size_t i = 0; i < this->m_size.x * this->m_size.y * this->m_size.z; ++i ) { auto position = this->unwrapIndex( i, this->m_voxels.lighting.swizzle ); raw_lighting[position.x][position.y][position.z] = this->m_voxels.lighting.raw[i]; } std::vector buffer; buffer.reserve( this->m_size.x * this->m_size.y * this->m_size.z ); // use YZX if ( SWIZZLE_OPTIMIZATION ) { pod::RLE::string_t xyz, yzx, zxy; { for ( uint x = 0; x < this->m_size.x; x++ ) for ( uint y = 0; y < this->m_size.y; y++ ) for ( uint z = 0; z < this->m_size.z; z++ ) buffer.push_back( raw_lighting[x][y][z] ); xyz = uf::rle::encode( buffer ); } buffer.clear(); buffer.reserve( this->m_size.x * this->m_size.y * this->m_size.z ); { for ( uint y = 0; y < this->m_size.y; y++ ) for ( uint z = 0; z < this->m_size.z; z++ ) for ( uint x = 0; x < this->m_size.x; x++ ) buffer.push_back( raw_lighting[x][y][z] ); yzx = uf::rle::encode( buffer ); } buffer.clear(); buffer.reserve( this->m_size.x * this->m_size.y * this->m_size.z ); { for ( uint z = 0; z < this->m_size.z; z++ ) for ( uint x = 0; x < this->m_size.x; x++ ) for ( uint y = 0; y < this->m_size.y; y++ ) buffer.push_back( raw_lighting[x][y][z] ); zxy = uf::rle::encode( buffer ); } // xyz if ( xyz.size() <= yzx.size() && xyz.size() <= zxy.size() ) { this->m_voxels.lighting.swizzle = Swizzle::XYZ; this->m_voxels.lighting.rle = xyz; // yzx } else if ( yzx.size() <= xyz.size() && yzx.size() <= zxy.size() ) { this->m_voxels.lighting.swizzle = Swizzle::YZX; this->m_voxels.lighting.rle = yzx; } else if ( zxy.size() <= xyz.size() && zxy.size() <= yzx.size() ) { this->m_voxels.lighting.swizzle = Swizzle::ZXY; this->m_voxels.lighting.rle = zxy; } else { this->m_voxels.lighting.swizzle = Swizzle::YZX; this->m_voxels.lighting.rle = yzx; } } else { for ( uint y = 0; y < this->m_size.y; y++ ) for ( uint z = 0; z < this->m_size.z; z++ ) for ( uint x = 0; x < this->m_size.x; x++ ) buffer.push_back( raw_lighting[x][y][z] ); this->m_voxels.lighting.swizzle = Swizzle::YZX; this->m_voxels.lighting.rle = uf::rle::encode( buffer ); } } void ext::TerrainGenerator::unwrapVoxel() { ext::TerrainVoxel::uid_t raw_id[this->m_size.x][this->m_size.y][this->m_size.z]; this->m_voxels.id.raw.clear(); this->m_voxels.id.raw.reserve(this->m_size.x * this->m_size.y * this->m_size.z); std::size_t i = 0; for ( auto& _ : this->m_voxels.id.rle ) { for ( std::size_t __ = 0; __ < _.length; ++__ ) { auto v = this->unwrapIndex( i++, this->m_voxels.id.swizzle ); raw_id[v.x][v.y][v.z] = _.value; } } for ( uint y = 0; y < this->m_size.y; y++ ) for ( uint z = 0; z < this->m_size.z; z++ ) for ( uint x = 0; x < this->m_size.x; x++ ) this->m_voxels.id.raw.push_back( raw_id[x][y][z] ); } void ext::TerrainGenerator::unwrapLight() { ext::TerrainVoxel::light_t raw_lighting[this->m_size.x][this->m_size.y][this->m_size.z]; this->m_voxels.lighting.raw.clear(); this->m_voxels.lighting.raw.reserve(this->m_size.x * this->m_size.y * this->m_size.z); std::size_t i = 0; for ( auto& _ : this->m_voxels.lighting.rle ) { for ( std::size_t __ = 0; __ < _.length; ++__ ) { auto v = this->unwrapIndex( i++, this->m_voxels.lighting.swizzle ); raw_lighting[v.x][v.y][v.z] = _.value; } } for ( uint y = 0; y < this->m_size.y; y++ ) for ( uint z = 0; z < this->m_size.z; z++ ) for ( uint x = 0; x < this->m_size.x; x++ ) this->m_voxels.lighting.raw.push_back( raw_lighting[x][y][z] ); } void ext::TerrainGenerator::setVoxel( int x, int y, int z, const ext::TerrainVoxel::uid_t& voxel, bool update ){ // check oob if ( !inBounds( x, y, z, this->m_size ) ) { if ( !this->m_terrain ) return; const ext::Terrain& terrain = *((const ext::Terrain*)this->m_terrain); pod::Vector3i location = this->m_location; while ( !inBounds( x, y, z, this->m_size ) ) { if ( x < 0 ) { x += this->m_size.x; --location.x; } else if ( x >= this->m_size.x ) { x -= this->m_size.x; ++location.x; } if ( y < 0 ) { y += this->m_size.y; --location.y; } else if ( y >= this->m_size.y ) { y -= this->m_size.y; ++location.y; } if ( z < 0 ) { z += this->m_size.z; --location.z; } else if ( z >= this->m_size.z ) { z -= this->m_size.z; ++location.z; } } /* while ( x < 0 ) { --location.x; x += this->m_size.x; } while ( x >= this->m_size.x - 1 ) { ++location.x; x -= this->m_size.x - 1; } while ( y < 0 ) { --location.y; y += this->m_size.y; } while ( y >= this->m_size.y - 1 ) { ++location.y; y -= this->m_size.y - 1; } while ( z < 0 ) { --location.z; z += this->m_size.z; } while ( z >= this->m_size.z - 1 ) { ++location.z; z -= this->m_size.z - 1; } */ ext::Region* region = terrain.at( location ); if ( !region ) return; region->getComponent().setVoxel( x, y, z, voxel, update ); return; } // set modified if ( this->m_terrain ) { const ext::Terrain& terrain = *((const ext::Terrain*)this->m_terrain); ext::Region* region = terrain.at( this->m_location ); if ( region ) region->getComponent()["region"]["modified"] = true; } std::size_t i = this->wrapPosition(x, y, z, this->m_voxels.id.swizzle); this->m_voxels.id.raw[i] = voxel; this->wrapVoxel(); } void ext::TerrainGenerator::setVoxel( const pod::Vector3i& location, const ext::TerrainVoxel::uid_t& light, bool update ){ return this->setVoxel( location.x, location.y, location.z, light, update ); } void ext::TerrainGenerator::setLight( int x, int y, int z, const ext::TerrainVoxel::light_t& light, bool update ){ // check oob if ( !inBounds( x, y, z, this->m_size ) ) { if ( !this->m_terrain ) return; const ext::Terrain& terrain = *((const ext::Terrain*)this->m_terrain); pod::Vector3i location = this->m_location; while ( !inBounds( x, y, z, this->m_size ) ) { if ( x < 0 ) { x += this->m_size.x; --location.x; } else if ( x >= this->m_size.x ) { x -= this->m_size.x; ++location.x; } if ( y < 0 ) { y += this->m_size.y; --location.y; } else if ( y >= this->m_size.y ) { y -= this->m_size.y; ++location.y; } if ( z < 0 ) { z += this->m_size.z; --location.z; } else if ( z >= this->m_size.z ) { z -= this->m_size.z; ++location.z; } } /* while ( x < 0 ) { --location.x; x += this->m_size.x; } while ( x >= this->m_size.x - 1 ) { ++location.x; x -= this->m_size.x - 1; } while ( y < 0 ) { --location.y; y += this->m_size.y; } while ( y >= this->m_size.y - 1 ) { ++location.y; y -= this->m_size.y - 1; } while ( z < 0 ) { --location.z; z += this->m_size.z; } while ( z >= this->m_size.z - 1 ) { ++location.z; z -= this->m_size.z - 1; } */ ext::Region* region = terrain.at( location ); if ( !region ) { // std::cout << "Out of bounds Region("<< location.x << ", " << location.y << ", " << location.z <<") @ setLight( " << x << ", " << y << ", " << z << " ) " << std::endl; return; } region->getComponent().setLight( x, y, z, light, update ); return; } // set modified if ( this->m_terrain ) { const ext::Terrain& terrain = *((const ext::Terrain*)this->m_terrain); ext::Region* region = terrain.at( this->m_location ); if ( region ) region->getComponent()["region"]["modified"] = true; } std::size_t i = this->wrapPosition(x, y, z, this->m_voxels.lighting.swizzle); // std::cout << "Set Voxel( " << x << ", " << y << ", " << z << ") ("<< i <<") to level " << light << std::endl; this->m_voxels.lighting.raw[i] = light; this->wrapLight(); } void ext::TerrainGenerator::setLight( const pod::Vector3i& location, const ext::TerrainVoxel::light_t& light, bool update ){ return this->setLight( location.x, location.y, location.z, light, update ); } void ext::TerrainGenerator::light( int x, int y, int z, const ext::TerrainVoxel::light_t& targetLight ){ // reset any existing lighting data /* for ( uint i = 0; i < this->m_size.x * this->m_size.y * this->m_size.z; ++i ) { auto v = this->unwrapIndex( i, this->m_voxels.id.swizzle ); this->setLight(v.x, v.y, v.z, 0x90FF ); } this->writeToFile(); return; */ this->setLight( x, y, z, targetLight ); int lightingMode = 3; // REDGREEENBLUE if ( lightingMode == 1 ) { uint8_t steps = 1; struct bfsNode { pod::Vector3i position; ext::Region* region; }; std::queue bfs; const ext::Terrain& terrain = *((const ext::Terrain*)this->m_terrain); { bfsNode root; root.position = pod::Vector3i{x, y, z}, root.region = terrain.at( this->m_location ); bfs.emplace(root); } size_t i = 0; while ( !bfs.empty() ) { bfsNode node = bfs.front(); bfs.pop(); std::cout << "Calls: " << (++i) << " | Nodes: " << bfs.size() << std::endl; if ( !node.region ) continue; auto& self = node.region->getComponent(); ext::TerrainVoxel voxel = ext::TerrainVoxel::atlas( self.getVoxel( node.position ) ); // ext::TerrainVoxel::light_t light = (self.getLight( node.position ) >> 12) & 0xF; struct LIGHT { ext::TerrainVoxel::light_t r, g, b; } light; light.r = (self.getLight( node.position ) >> 12) & 0xF; light.g = (self.getLight( node.position ) >> 8) & 0xF; light.b = (self.getLight( node.position ) >> 4) & 0xF; std::vector positions = { node.position + pod::Vector3i{-1, 0, 0 }, node.position + pod::Vector3i{ 1, 0, 0 }, node.position + pod::Vector3i{ 0,-1, 0 }, node.position + pod::Vector3i{ 0, 1, 0 }, node.position + pod::Vector3i{ 0, 0,-1 }, node.position + pod::Vector3i{ 0, 0, 1 }, }; for ( auto& position : positions ) { { pod::Vector3i location = self.m_location; if ( position.x < 0 ) { position.x += self.m_size.x; --location.x; } else if ( position.x >= self.m_size.x ) { position.x -= self.m_size.x; ++location.x; } if ( position.y < 0 ) { position.y += self.m_size.y; --location.y; } else if ( position.y >= self.m_size.y ) { position.y -= self.m_size.y; ++location.y; } if ( position.z < 0 ) { position.z += self.m_size.z; --location.z; } else if ( position.z >= self.m_size.z ) { position.z -= self.m_size.z; ++location.z; } /* while ( position.x < 0 ) { --location.x; position.x += self.m_size.x; } while ( position.x >= self.m_size.x - 1 ) { ++location.x; position.x -= self.m_size.x; } while ( position.y < 0 ) { --location.y; position.y += self.m_size.y; } while ( position.y >= self.m_size.y - 1 ) { ++location.y; position.y -= self.m_size.y; } while ( position.z < 0 ) { --location.z; position.z += self.m_size.z; } while ( position.z >= self.m_size.z - 1 ) { ++location.z; position.z -= self.m_size.z; } */ node.region = terrain.at( location ); } if ( !node.region ) continue; auto& selfGenerator = node.region->getComponent(); struct { ext::TerrainVoxel voxel; ext::TerrainVoxel::light_t light; } neighbor; neighbor.voxel = ext::TerrainVoxel::atlas( selfGenerator.getVoxel( position ) ); neighbor.light = selfGenerator.getLight( position ); // ext::TerrainVoxel::light_t targetLight = (neighbor.light >> 12) & 0xF; LIGHT targetLight; targetLight.r = (neighbor.light >> 12) & 0xF; targetLight.g = (neighbor.light >> 8) & 0xF; targetLight.b = (neighbor.light >> 4) & 0xF; if ( neighbor.voxel.opaque() ) continue; if ( targetLight.r + (2 * steps) <= light.r ) { selfGenerator.setLight( position, (neighbor.light & 0x0FFF ) | ((light.r - (1 * steps)) << 12), false ); node.position = position; bfs.emplace( node ); } if ( targetLight.g + (2 * steps) <= light.g ) { selfGenerator.setLight( position, (neighbor.light & 0xF0FF ) | ((light.g - (1 * steps)) << 8), false ); node.position = position; bfs.emplace( node ); } if ( targetLight.b + (2 * steps) <= light.b ) { selfGenerator.setLight( position, (neighbor.light & 0xFF0F ) | ((light.b - (1 * steps)) << 4), false ); node.position = position; bfs.emplace( node ); } } } } // REDGREENBLUE if ( lightingMode == 2 ) { uint8_t steps = 1; std::queue bfs; bfs.emplace( pod::Vector3i{x, y, z}); while ( !bfs.empty() ) { pod::Vector3i node = bfs.front(); bfs.pop(); ext::TerrainVoxel voxel = ext::TerrainVoxel::atlas( this->getVoxel( node ) ); struct LIGHT { ext::TerrainVoxel::light_t r, g, b; } light; light.r = (this->getLight( node ) >> 12) & 0xF; light.g = (this->getLight( node ) >> 8) & 0xF; light.b = (this->getLight( node ) >> 4) & 0xF; std::vector positions = { node + pod::Vector3i{-1, 0, 0 }, node + pod::Vector3i{ 1, 0, 0 }, node + pod::Vector3i{ 0,-1, 0 }, node + pod::Vector3i{ 0, 1, 0 }, node + pod::Vector3i{ 0, 0,-1 }, node + pod::Vector3i{ 0, 0, 1 }, }; for ( auto& position : positions ) { struct { ext::TerrainVoxel voxel; ext::TerrainVoxel::light_t light; } neighbor; neighbor.voxel = ext::TerrainVoxel::atlas( this->getVoxel( position ) ); neighbor.light = this->getLight( position ); // ext::TerrainVoxel::light_t targetLight = (neighbor.light >> 12) & 0xF; LIGHT targetLight; targetLight.r = (neighbor.light >> 12) & 0xF; targetLight.g = (neighbor.light >> 8) & 0xF; targetLight.b = (neighbor.light >> 4) & 0xF; if ( neighbor.voxel.opaque() ) continue; if ( targetLight.r + (2 * steps) <= light.r ) { this->setLight( position, (neighbor.light & 0x0FFF ) | ((light.r - (1 * steps)) << 12), false ); bfs.emplace( position ); } if ( targetLight.g + (2 * steps) <= light.g ) { this->setLight( position, (neighbor.light & 0xF0FF ) | ((light.g - (1 * steps)) << 8), false ); bfs.emplace( position ); } if ( targetLight.b + (2 * steps) <= light.b ) { this->setLight( position, (neighbor.light & 0xFF0F ) | ((light.b - (1 * steps)) << 4), false ); bfs.emplace( position ); } } } } // RED if ( lightingMode == 3 ) { uint8_t steps = 1; std::queue bfs; bfs.emplace( pod::Vector3i{x, y, z}); while ( !bfs.empty() ) { pod::Vector3i node = bfs.front(); bfs.pop(); ext::TerrainVoxel voxel = ext::TerrainVoxel::atlas( this->getVoxel( node ) ); ext::TerrainVoxel::light_t light = (this->getLight( node ) >> 12) & 0xF; std::vector positions = { node + pod::Vector3i{-1, 0, 0 }, node + pod::Vector3i{ 1, 0, 0 }, node + pod::Vector3i{ 0,-1, 0 }, node + pod::Vector3i{ 0, 1, 0 }, node + pod::Vector3i{ 0, 0,-1 }, node + pod::Vector3i{ 0, 0, 1 }, }; for ( auto& position : positions ) { struct { ext::TerrainVoxel voxel; ext::TerrainVoxel::light_t light; } neighbor; neighbor.voxel = ext::TerrainVoxel::atlas( this->getVoxel( position ) ); neighbor.light = this->getLight( position ); ext::TerrainVoxel::light_t targetLight = (neighbor.light >> 12) & 0xF; if ( neighbor.voxel.opaque() ) continue; if ( targetLight + (2 * steps) <= light ) { this->setLight( position, (neighbor.light & 0x0FFF ) | ((light - (1 * steps)) << 12), false ); bfs.emplace( position ); } } } } // GREEN if ( lightingMode == 3 ) { uint8_t steps = 1; std::queue bfs; bfs.emplace( pod::Vector3i{x, y, z}); while ( !bfs.empty() ) { pod::Vector3i node = bfs.front(); bfs.pop(); ext::TerrainVoxel voxel = ext::TerrainVoxel::atlas( this->getVoxel( node ) ); ext::TerrainVoxel::light_t light = (this->getLight( node ) >> 8) & 0xF; std::vector positions = { node + pod::Vector3i{-1, 0, 0 }, node + pod::Vector3i{ 1, 0, 0 }, node + pod::Vector3i{ 0,-1, 0 }, node + pod::Vector3i{ 0, 1, 0 }, node + pod::Vector3i{ 0, 0,-1 }, node + pod::Vector3i{ 0, 0, 1 }, }; for ( auto& position : positions ) { struct { ext::TerrainVoxel voxel; ext::TerrainVoxel::light_t light; } neighbor; neighbor.voxel = ext::TerrainVoxel::atlas( this->getVoxel( position ) ); neighbor.light = this->getLight( position ); ext::TerrainVoxel::light_t targetLight = (neighbor.light >> 8) & 0xF; if ( neighbor.voxel.opaque() ) continue; if ( targetLight + (2 * steps) <= light ) { this->setLight( position, (neighbor.light & 0xF0FF ) | ((light - (1 * steps)) << 8), false ); bfs.emplace( position ); } } } } // BLUE if ( lightingMode == 3 ) { uint8_t steps = 1; std::queue bfs; bfs.emplace( pod::Vector3i{x, y, z}); while ( !bfs.empty() ) { pod::Vector3i node = bfs.front(); bfs.pop(); ext::TerrainVoxel voxel = ext::TerrainVoxel::atlas( this->getVoxel( node ) ); ext::TerrainVoxel::light_t light = (this->getLight( node ) >> 4) & 0xF; std::vector positions = { node + pod::Vector3i{-1, 0, 0 }, node + pod::Vector3i{ 1, 0, 0 }, node + pod::Vector3i{ 0,-1, 0 }, node + pod::Vector3i{ 0, 1, 0 }, node + pod::Vector3i{ 0, 0,-1 }, node + pod::Vector3i{ 0, 0, 1 }, }; for ( auto& position : positions ) { struct { ext::TerrainVoxel voxel; ext::TerrainVoxel::light_t light; } neighbor; neighbor.voxel = ext::TerrainVoxel::atlas( this->getVoxel( position ) ); neighbor.light = this->getLight( position ); ext::TerrainVoxel::light_t targetLight = (neighbor.light >> 4) & 0xF; if ( neighbor.voxel.opaque() ) continue; if ( targetLight + (2 * steps) <= light ) { this->setLight( position, (neighbor.light & 0xFF0F ) | ((light - (1 * steps)) << 4), false ); bfs.emplace( position ); } } } } // this->writeToFile(); } void ext::TerrainGenerator::light( const pod::Vector3i& location, const ext::TerrainVoxel::light_t& targetLight ){ return this->light( location.x, location.y, location.z, targetLight ); } void ext::TerrainGenerator::updateLight(){ // this->unwrapLight(); // set lights to original values /* std::size_t i = 0; std::cout << "Updating lights for " << this->m_location.x << ", " << this->m_location.y << ", " << this->m_location.z << std::endl; for ( auto& _ : this->m_voxels.id.rle ) { for ( std::size_t __ = 0; __ < _.length; ++__ ) { ext::TerrainVoxel voxel = ext::TerrainVoxel::atlas( _.value ); auto v = this->unwrapIndex( i++, this->m_voxels.id.swizzle ); // this->setLight(v.x, v.y, v.z, voxel.light() ); this->m_voxels.lighting.raw[i] = AMBIENT_LIGHT; } } //this->wrapLight(); */ // set lights std::size_t i = 0; for ( auto& _ : this->m_voxels.id.rle ) { for ( std::size_t __ = 0; __ < _.length; ++__ ) { ext::TerrainVoxel voxel = ext::TerrainVoxel::atlas( _.value ); auto v = this->unwrapIndex( i++, this->m_voxels.id.swizzle ); if ( voxel.light() == 0x0000 ) continue; this->light(v.x, v.y, v.z, voxel.light() ); } } // this->wrapLight(); // this->writeToFile(); } void ext::TerrainGenerator::rasterize( std::vector& vertices, const ext::Region& region ){ if ( this->m_voxels.id.rle.empty() ) return; this->writeToFile(); struct { struct { float x, y, z; } position; struct { float u, v, x, y; } uv; } offset; const ext::Terrain& terrain = region.getParent(); const pod::Transform<>& transform = region.getComponent>(); const pod::Vector3i location = { transform.position.x / this->m_size.x, transform.position.y / this->m_size.y, transform.position.z / this->m_size.z, }; struct { ext::Region* right = NULL; ext::Region* left = NULL; ext::Region* top = NULL; ext::Region* bottom = NULL; ext::Region* front = NULL; ext::Region* back = NULL; } regions; regions.right = terrain.at( { location.x + 1, location.y, location.z } ); regions.left = terrain.at( { location.x - 1, location.y, location.z } ); regions.top = terrain.at( { location.x, location.y + 1, location.z } ); regions.bottom = terrain.at( { location.x, location.y - 1, location.z } ); regions.front = terrain.at( { location.x, location.y, location.z + 1 } ); regions.back = terrain.at( { location.x, location.y, location.z - 1 } ); ext::TerrainVoxel::light_t ambientLight = AMBIENT_LIGHT; { const uf::Serializer& tMetadata = region.getComponent(); COLOR color = uint16ToColor( ambientLight ); color.r *= tMetadata["region"]["light"]["ambient"][0].asFloat(); color.g *= tMetadata["region"]["light"]["ambient"][1].asFloat(); color.b *= tMetadata["region"]["light"]["ambient"][2].asFloat(); ambientLight = colorToUint16( color ); } #define TERRAIN_SHOULD_RENDER_FACE(SIDE)\ should.SIDE = !neighbor.SIDE.opaque();\ if ( should.SIDE ) {\ for ( uint i = 0; i < model.position.SIDE.size() / 3; ++i ) {\ ext::TerrainGenerator::mesh_t::vertex_t vertex;\ {\ pod::Vector3f& p = vertex.position;\ p.x = model.position.SIDE[i*3+0]; p.y = model.position.SIDE[i*3+1]; p.z = model.position.SIDE[i*3+2];\ p.x += offset.position.x; p.y += offset.position.y; p.z += offset.position.z;\ }\ {\ pod::Vector2f& p = vertex.uv;\ p.x = model.uv.SIDE[i*2+0]; p.y = model.uv.SIDE[i*2+1];\ p.x *= offset.uv.x; p.y *= offset.uv.y;\ p.x += offset.uv.u; p.y += offset.uv.v;\ }\ {\ pod::Vector3f& p = vertex.normal;\ p.x = model.normal.SIDE[i*3+0]; p.y = model.normal.SIDE[i*3+1]; p.z = model.normal.SIDE[i*3+2];\ }\ {\ pod::Vector4t& p = vertex.color;\ ext::TerrainVoxel::light_t l = light.SIDE;\ p[0] = (l >> 12) & 0xF;\ p[1] = (l >> 8) & 0xF;\ p[2] = (l >> 4) & 0xF;\ p[3] = (l ) & 0xF;\ p[0] = (p[0] << 4) | p[0];\ p[1] = (p[1] << 4) | p[1];\ p[2] = (p[2] << 4) | p[2];\ p[3] = (p[3] << 4) | p[3];\ }\ vertices.push_back(vertex);\ }\ } /* for ( uint y = 0; y < this->m_size.y; ++y ) { for ( uint z = 0; z < this->m_size.z; ++z ) { for ( uint x = 0; x < this->m_size.x; ++x ) { ext::TerrainVoxel voxel = ext::TerrainVoxel::atlas( this->getVoxel( x, y, z ) ); */ std::size_t i = 0; for ( auto& _ : this->m_voxels.id.rle ) { for ( std::size_t __ = 0; __ < _.length; ++__ ) { { int x = 0, y = 0, z = 0; { auto v = this->unwrapIndex( i++, this->m_voxels.id.swizzle ); x = v.x; y = v.y; z = v.z; } ext::TerrainVoxel voxel = ext::TerrainVoxel::atlas( _.value ); offset.position.x = x - (this->m_size.x / 2.0f); offset.position.y = y - (this->m_size.y / 2.0f); offset.position.z = z - (this->m_size.z / 2.0f); const ext::TerrainVoxel::Model& model = voxel.model(); // clear block, don't render if ( !voxel.opaque() ) continue; offset.position.x += transform.position.x; offset.position.y += transform.position.y; offset.position.z += transform.position.z; offset.uv.x = 1.0f / ext::TerrainVoxel::size().x; offset.uv.y = 1.0f / ext::TerrainVoxel::size().y; offset.uv.u = voxel.uv().x * offset.uv.x; offset.uv.v = (ext::TerrainVoxel::size().y - 1 - voxel.uv().y) * offset.uv.y; struct { bool top = true, bottom = true, left = true, right = true, front = true, back = true; } should; struct { ext::TerrainVoxel top = ext::TerrainVoxel::atlas(0), bottom = ext::TerrainVoxel::atlas(0), left = ext::TerrainVoxel::atlas(0), right = ext::TerrainVoxel::atlas(0), front = ext::TerrainVoxel::atlas(0), back = ext::TerrainVoxel::atlas(0); } neighbor; struct { ext::TerrainVoxel::light_t top = 0xffff, bottom = 0xfff, left = 0xffff, right = 0xffff, front = 0xffff, back = 0xffff; } light; /* if ( x > 0 ) neighbor.left = ext::TerrainVoxel::atlas(this->getVoxel(x-1,y,z)); else if ( regions.left != NULL ) neighbor.left = ext::TerrainVoxel::atlas(regions.left->getComponent().getVoxel(this->m_size.x-1,y,z)); if ( x + 1 < this->m_size.x ) neighbor.right = ext::TerrainVoxel::atlas(this->getVoxel(x+1,y,z)); else if ( regions.right != NULL ) neighbor.right = ext::TerrainVoxel::atlas(regions.right->getComponent().getVoxel(0,y,z)); if ( y > 0 ) neighbor.bottom = ext::TerrainVoxel::atlas(this->getVoxel(x,y-1,z)); else if ( regions.bottom != NULL ) neighbor.bottom = ext::TerrainVoxel::atlas(regions.bottom->getComponent().getVoxel(x,this->m_size.y-1,z)); if ( y + 1 < this->m_size.y ) neighbor.top = ext::TerrainVoxel::atlas(this->getVoxel(x,y+1,z)); else if ( regions.top != NULL ) neighbor.top = ext::TerrainVoxel::atlas(regions.top->getComponent().getVoxel(x,0,z)); if ( z > 0 ) neighbor.back = ext::TerrainVoxel::atlas(this->getVoxel(x,y,z-1)); else if ( regions.back != NULL ) neighbor.back = ext::TerrainVoxel::atlas(regions.back->getComponent().getVoxel(x,y,this->m_size.z-1)); if ( z + 1 < this->m_size.z ) neighbor.front = ext::TerrainVoxel::atlas(this->getVoxel(x,y,z+1)); else if ( regions.front != NULL ) neighbor.front = ext::TerrainVoxel::atlas(regions.front->getComponent().getVoxel(x,y,0)); */ neighbor.left = ext::TerrainVoxel::atlas(this->getVoxel(x-1,y,z)); light.left = this->getLight(x-1,y,z); neighbor.bottom = ext::TerrainVoxel::atlas(this->getVoxel(x,y-1,z)); light.bottom = this->getLight(x,y-1,z); neighbor.back = ext::TerrainVoxel::atlas(this->getVoxel(x,y,z-1)); light.back = this->getLight(x,y,z-1); neighbor.right = ext::TerrainVoxel::atlas(this->getVoxel(x+1,y,z)); light.right = this->getLight(x+1,y,z); neighbor.top = ext::TerrainVoxel::atlas(this->getVoxel(x,y+1,z)); light.top = this->getLight(x,y+1,z); neighbor.front = ext::TerrainVoxel::atlas(this->getVoxel(x,y,z+1)); light.front = this->getLight(x,y,z+1); TERRAIN_SHOULD_RENDER_FACE(right) TERRAIN_SHOULD_RENDER_FACE(left) TERRAIN_SHOULD_RENDER_FACE(top) TERRAIN_SHOULD_RENDER_FACE(bottom) TERRAIN_SHOULD_RENDER_FACE(front) TERRAIN_SHOULD_RENDER_FACE(back) /* should.right = !neighbor.right.opaque(); should.left = !neighbor.left.opaque(); should.top = !neighbor.top.opaque(); should.bottom = !neighbor.bottom.opaque(); should.front = !neighbor.front.opaque(); should.back = !neighbor.back.opaque(); if ( should.right ) { for ( uint i = 0; i < model.position.right.size() / 3; ++i ) { ext::TerrainGenerator::mesh_t::vertex_t vertex; { pod::Vector3f& p = vertex.position; p.x = model.position.right[i*3+0]; p.y = model.position.right[i*3+1]; p.z = model.position.right[i*3+2]; p.x += offset.position.x; p.y += offset.position.y; p.z += offset.position.z; } { pod::Vector2f& p = vertex.uv; p.x = model.uv.right[i*2+0]; p.y = model.uv.right[i*2+1]; p.x *= offset.uv.x; p.y *= offset.uv.y; p.x += offset.uv.u; p.y += offset.uv.v; } { pod::Vector3f& p = vertex.normal; p.x = model.normal.right[i*3+0]; p.y = model.normal.right[i*3+1]; p.z = model.normal.right[i*3+2]; } { pod::Vector4t& p = vertex.color; ext::TerrainVoxel::light_t l = light.right; p[0] = (l >> 12) & 0xF; // A/R p[1] = (l >> 8) & 0xF; // B/G p[2] = (l >> 4) & 0xF; // G/B p[3] = (l ) & 0xF; // R/A p[0] = (p[0] << 4) | p[0]; p[1] = (p[1] << 4) | p[1]; p[2] = (p[2] << 4) | p[2]; p[3] = (p[3] << 4) | p[3]; } vertices.push_back(vertex); } } if ( should.left ) { for ( uint i = 0; i < model.position.left.size() / 3; ++i ) { ext::TerrainGenerator::mesh_t::vertex_t vertex; { pod::Vector3f& p = vertex.position; p.x = model.position.left[i*3+0]; p.y = model.position.left[i*3+1]; p.z = model.position.left[i*3+2]; p.x += offset.position.x; p.y += offset.position.y; p.z += offset.position.z; } { pod::Vector2f& p = vertex.uv; p.x = model.uv.left[i*2+0]; p.y = model.uv.left[i*2+1]; p.x *= offset.uv.x; p.y *= offset.uv.y; p.x += offset.uv.u; p.y += offset.uv.v; } { pod::Vector3f& p = vertex.normal; p.x = model.normal.left[i*3+0]; p.y = model.normal.left[i*3+1]; p.z = model.normal.left[i*3+2]; } { pod::Vector4t& p = vertex.color; ext::TerrainVoxel::light_t l = light.left; p[0] = (l >> 12) & 0xF; // A/R p[1] = (l >> 8) & 0xF; // B/G p[2] = (l >> 4) & 0xF; // G/B p[3] = (l ) & 0xF; // R/A p[0] = (p[0] << 4) | p[0]; p[1] = (p[1] << 4) | p[1]; p[2] = (p[2] << 4) | p[2]; p[3] = (p[3] << 4) | p[3]; // if ( p[0] > 0 ) std::cout << "LIGHT: " << std::hex << *((uint32_t*) &p[0]) << std::endl; // else std::cout << "BLACK: " << std::hex << (uint32_t) light.left << std::endl; } vertices.push_back(vertex); } } if ( should.top ) { for ( uint i = 0; i < model.position.top.size() / 3; ++i ) { ext::TerrainGenerator::mesh_t::vertex_t vertex; { pod::Vector3f& p = vertex.position; p.x = model.position.top[i*3+0]; p.y = model.position.top[i*3+1]; p.z = model.position.top[i*3+2]; p.x += offset.position.x; p.y += offset.position.y; p.z += offset.position.z; } { pod::Vector2f& p = vertex.uv; p.x = model.uv.top[i*2+0]; p.y = model.uv.top[i*2+1]; p.x *= offset.uv.x; p.y *= offset.uv.y; p.x += offset.uv.u; p.y += offset.uv.v; } { pod::Vector3f& p = vertex.normal; p.x = model.normal.top[i*3+0]; p.y = model.normal.top[i*3+1]; p.z = model.normal.top[i*3+2]; } { pod::Vector4t& p = vertex.color; ext::TerrainVoxel::light_t l = light.top; p[0] = (l >> 12) & 0xF; // A/R p[1] = (l >> 8) & 0xF; // B/G p[2] = (l >> 4) & 0xF; // G/B p[3] = (l ) & 0xF; // R/A p[0] = (p[0] << 4) | p[0]; p[1] = (p[1] << 4) | p[1]; p[2] = (p[2] << 4) | p[2]; p[3] = (p[3] << 4) | p[3]; // if ( p[0] > 0 ) std::cout << "LIGHT: " << std::hex << *((uint32_t*) &p[0]) << std::endl; // else std::cout << "BLACK: " << std::hex << (uint32_t) light.top << std::endl; } vertices.push_back(vertex); } } if ( should.bottom ) { for ( uint i = 0; i < model.position.bottom.size() / 3; ++i ) { ext::TerrainGenerator::mesh_t::vertex_t vertex; { pod::Vector3f& p = vertex.position; p.x = model.position.bottom[i*3+0]; p.y = model.position.bottom[i*3+1]; p.z = model.position.bottom[i*3+2]; p.x += offset.position.x; p.y += offset.position.y; p.z += offset.position.z; } { pod::Vector2f& p = vertex.uv; p.x = model.uv.bottom[i*2+0]; p.y = model.uv.bottom[i*2+1]; p.x *= offset.uv.x; p.y *= offset.uv.y; p.x += offset.uv.u; p.y += offset.uv.v; } { pod::Vector3f& p = vertex.normal; p.x = model.normal.bottom[i*3+0]; p.y = model.normal.bottom[i*3+1]; p.z = model.normal.bottom[i*3+2]; } { pod::Vector4t& p = vertex.color; ext::TerrainVoxel::light_t l = light.bottom; p[0] = (l >> 12) & 0xF; // A/R p[1] = (l >> 8) & 0xF; // B/G p[2] = (l >> 4) & 0xF; // G/B p[3] = (l ) & 0xF; // R/A p[0] = (p[0] << 4) | p[0]; p[1] = (p[1] << 4) | p[1]; p[2] = (p[2] << 4) | p[2]; p[3] = (p[3] << 4) | p[3]; // if ( p[0] > 0 ) std::cout << "LIGHT: " << std::hex << *((uint32_t*) &p[0]) << std::endl; // else std::cout << "BLACK: " << std::hex << (uint32_t) light.bottom << std::endl; } vertices.push_back(vertex); } } if ( should.front ) { for ( uint i = 0; i < model.position.front.size() / 3; ++i ) { ext::TerrainGenerator::mesh_t::vertex_t vertex; { pod::Vector3f& p = vertex.position; p.x = model.position.front[i*3+0]; p.y = model.position.front[i*3+1]; p.z = model.position.front[i*3+2]; p.x += offset.position.x; p.y += offset.position.y; p.z += offset.position.z; } { pod::Vector2f& p = vertex.uv; p.x = model.uv.front[i*2+0]; p.y = model.uv.front[i*2+1]; p.x *= offset.uv.x; p.y *= offset.uv.y; p.x += offset.uv.u; p.y += offset.uv.v; } { pod::Vector3f& p = vertex.normal; p.x = model.normal.front[i*3+0]; p.y = model.normal.front[i*3+1]; p.z = model.normal.front[i*3+2]; } { pod::Vector4t& p = vertex.color; ext::TerrainVoxel::light_t l = light.front; p[0] = (l >> 12) & 0xF; // A/R p[1] = (l >> 8) & 0xF; // B/G p[2] = (l >> 4) & 0xF; // G/B p[3] = (l ) & 0xF; // R/A p[0] = (p[0] << 4) | p[0]; p[1] = (p[1] << 4) | p[1]; p[2] = (p[2] << 4) | p[2]; p[3] = (p[3] << 4) | p[3]; // if ( p[0] > 0 ) std::cout << "LIGHT: " << std::hex << *((uint32_t*) &p[0]) << std::endl; // else std::cout << "BLACK: " << std::hex << (uint32_t) light.front << std::endl; } vertices.push_back(vertex); } } if ( should.back ) { for ( uint i = 0; i < model.position.back.size() / 3; ++i ) { ext::TerrainGenerator::mesh_t::vertex_t vertex; { pod::Vector3f& p = vertex.position; p.x = model.position.back[i*3+0]; p.y = model.position.back[i*3+1]; p.z = model.position.back[i*3+2]; p.x += offset.position.x; p.y += offset.position.y; p.z += offset.position.z; } { pod::Vector2f& p = vertex.uv; p.x = model.uv.back[i*2+0]; p.y = model.uv.back[i*2+1]; p.x *= offset.uv.x; p.y *= offset.uv.y; p.x += offset.uv.u; p.y += offset.uv.v; } { pod::Vector3f& p = vertex.normal; p.x = model.normal.back[i*3+0]; p.y = model.normal.back[i*3+1]; p.z = model.normal.back[i*3+2]; } { pod::Vector4t& p = vertex.color; ext::TerrainVoxel::light_t l = light.back; p[0] = (l >> 12) & 0xF; // A/R p[1] = (l >> 8) & 0xF; // B/G p[2] = (l >> 4) & 0xF; // G/B p[3] = (l ) & 0xF; // R/A p[0] = (p[0] << 4) | p[0]; p[1] = (p[1] << 4) | p[1]; p[2] = (p[2] << 4) | p[2]; p[3] = (p[3] << 4) | p[3]; // if ( p[0] > 0 ) std::cout << "LIGHT: " << std::hex << *((uint32_t*) &p[0]) << std::endl; // else std::cout << "BLACK: " << std::hex << (uint32_t) light.back << std::endl; } vertices.push_back(vertex); } } */ } } } } void ext::TerrainGenerator::vectorize( std::vector& buffer, const ext::Region& region ) { struct { pod::Vector3f position; struct { float u, v, x, y; } uv; } offset; const ext::Terrain& terrain = region.getParent(); const pod::Transform<>& transform = region.getComponent>(); const pod::Vector3i location = { transform.position.x / this->m_size.x, transform.position.y / this->m_size.y, transform.position.z / this->m_size.z, }; struct { ext::Region* right = NULL; ext::Region* left = NULL; ext::Region* top = NULL; ext::Region* bottom = NULL; ext::Region* front = NULL; ext::Region* back = NULL; } regions; regions.right = terrain.at( { location.x + 1, location.y, location.z } ); regions.left = terrain.at( { location.x - 1, location.y, location.z } ); regions.top = terrain.at( { location.x, location.y + 1, location.z } ); regions.bottom = terrain.at( { location.x, location.y - 1, location.z } ); regions.front = terrain.at( { location.x, location.y, location.z + 1 } ); regions.back = terrain.at( { location.x, location.y, location.z - 1 } ); /* for ( uint x = 0; x < this->m_size.x; ++x ) { for ( uint y = 0; y < this->m_size.y; ++y ) { for ( uint z = 0; z < this->m_size.z; ++z ) { ext::TerrainVoxel voxel = ext::TerrainVoxel::atlas(this->m_voxels.id.raw[x][y][z]); */ std::size_t i = 0; for ( auto& _ : this->m_voxels.id.rle ) { for ( std::size_t __ = 0; __ < _.length; ++__ ) { { std::size_t x = 0, y = 0, z = 0; { auto v = this->unwrapIndex( i++, this->m_voxels.id.swizzle ); x = v.x; y = v.y; z = v.z; } ext::TerrainVoxel voxel = ext::TerrainVoxel::atlas( _.value ); offset.position.x = x - (this->m_size.x / 2.0f); offset.position.y = y - (this->m_size.y / 2.0f); offset.position.z = z - (this->m_size.z / 2.0f); const ext::TerrainVoxel::Model& model = voxel.model(); if ( !voxel.opaque() ) continue; struct { bool top = true, bottom = true, left = true, right = true, front = true, back = true; } should; struct { ext::TerrainVoxel top = ext::TerrainVoxel::atlas(0), bottom = ext::TerrainVoxel::atlas(0), left = ext::TerrainVoxel::atlas(0), right = ext::TerrainVoxel::atlas(0), front = ext::TerrainVoxel::atlas(0), back = ext::TerrainVoxel::atlas(0); } neighbor; if ( x > 0 ) neighbor.left = ext::TerrainVoxel::atlas(this->getVoxel(x-1,y,z)); else if ( regions.left != NULL ) { const ext::Region& left = *regions.left; const ext::TerrainGenerator& t = left.getComponent(); neighbor.left = ext::TerrainVoxel::atlas(t.getVoxel(t.m_size.x-1,y,z)); } if ( y > 0 ) neighbor.bottom = ext::TerrainVoxel::atlas(this->getVoxel(x,y-1,z)); else if ( regions.bottom != NULL ) { const ext::Region& bottom = *regions.bottom; const ext::TerrainGenerator& t = bottom.getComponent(); neighbor.bottom =ext::TerrainVoxel::atlas( t.getVoxel(x,t.m_size.y-1,z)); } if ( z > 0 ) neighbor.back = ext::TerrainVoxel::atlas(this->getVoxel(x,y,z-1)); else if ( regions.back != NULL ) { const ext::Region& back = *regions.back; const ext::TerrainGenerator& t = back.getComponent(); neighbor.back = ext::TerrainVoxel::atlas(t.getVoxel(x,y,t.m_size.z-1)); } if ( x + 1 < this->m_size.x ) neighbor.right = ext::TerrainVoxel::atlas(this->getVoxel(x+1,y,z)); else if ( regions.right != NULL ) { const ext::Region& right = *regions.right; const ext::TerrainGenerator& t = right.getComponent(); neighbor.right = ext::TerrainVoxel::atlas(t.getVoxel(0,y,z)); } if ( y + 1 < this->m_size.y ) neighbor.top = ext::TerrainVoxel::atlas(this->getVoxel(x,y+1,z)); else if ( regions.top != NULL ) { const ext::Region& top = *regions.top; const ext::TerrainGenerator& t = top.getComponent(); neighbor.top = ext::TerrainVoxel::atlas(t.getVoxel(x,0,z)); } if ( z + 1 < this->m_size.z ) neighbor.front = ext::TerrainVoxel::atlas(this->getVoxel(x,y,z+1)); else if ( regions.front != NULL ) { const ext::Region& front = *regions.front; const ext::TerrainGenerator& t = front.getComponent(); neighbor.front = ext::TerrainVoxel::atlas(t.getVoxel(x,y,0)); } should.right = !neighbor.right.opaque(); should.left = !neighbor.left.opaque(); should.top = !neighbor.top.opaque(); should.bottom = !neighbor.bottom.opaque(); should.front = !neighbor.front.opaque(); should.back = !neighbor.back.opaque(); // occluded if ( !should.right && !should.left && !should.top && !should.bottom && !should.front && !should.back ) continue; if ( !voxel.opaque() ) continue; ext::vulkan::ComputeGraphic::Cube cube; pod::Vector3f location = offset.position + transform.position; cube.position.x = location.x; cube.position.y = location.y; cube.position.z = location.z; cube.position.z *= -1; cube.position.w = 0.5f; cube.type = voxel.opaque() ? pod::Primitive::CUBE : pod::Primitive::EMPTY; buffer.push_back(cube); } } } }