#include "Chunk.hpp" #include "materials.hpp" #include using namespace world; constexpr auto DENSITY = 0.f; constexpr auto GRANULARITY = 30.f; constexpr auto RLE = true; Chunk::Chunk(const chunk_pos& pos, Generator& rnd) { const auto [densitySet, materialSet] = rnd.getChunk(pos, CHUNK_LENGTH); for (size_t i = 0; i < CHUNK_SIZE; i++) { voxels[i].Density = std::clamp((densitySet[i] + DENSITY) * GRANULARITY, 0.f, 1.f) * UCHAR_MAX; voxels[i].Material = voxels[i].Density > 0 ? 1 + std::clamp(static_cast(std::lrint((materialSet[i] + 1) / 2 * (materials::count - 2))), 0, materials::count - 2) : 0; //NOTE: map (approx -1, 1) to (1, mat_max) } FastNoiseSIMD::FreeNoiseSet(densitySet); FastNoiseSIMD::FreeNoiseSet(materialSet); } Chunk::Chunk(std::istream& str) { if constexpr (RLE) { ushort i = 0; while(!str.eof()) { ushort count; Voxel voxel; str.read(reinterpret_cast(&count), sizeof(count)); str.read(reinterpret_cast(&voxel.Density), sizeof(Voxel::Density)); str.read(reinterpret_cast(&voxel.Material), sizeof(Voxel::Material)); str.peek(); for (; count > 0; count--) { voxels[i] = voxel; i++; } } assert(("Mismatch data length", i == CHUNK_SIZE-1)); } else { for(auto& voxel: voxels) { str.read(reinterpret_cast(&voxel.Density), sizeof(Voxel::Density)); str.read(reinterpret_cast(&voxel.Material), sizeof(Voxel::Material)); } } } Chunk::~Chunk() { } void Chunk::write(std::ostream& str) const { if constexpr (RLE) { const auto *it = voxels.begin(); ushort counter = 1; Voxel current = *it; while(true) { it++; const auto end = (it == voxels.end()); if(end || current.Density != it->Density || current.Material != it->Material) { str.write(reinterpret_cast(&counter), sizeof(counter)); str.write(reinterpret_cast(¤t.Density), sizeof(current.Density)); str.write(reinterpret_cast(¤t.Material), sizeof(current.Material)); if(end) break; current = *it; counter = 1; } else { counter++; } } } else { for(auto current: voxels) { str.write(reinterpret_cast(¤t.Density), sizeof(current.Density)); str.write(reinterpret_cast(¤t.Material), sizeof(current.Material)); } } } std::optional Chunk::update() { if(upToDate) { return {}; } else { upToDate = true; return {toUpdate}; } } void Chunk::set(ushort idx, const Voxel& val) { voxels[idx] = val; invalidate( ((!getNeighborIdx(idx, Face::Up).has_value()) & Faces::Up) | ((!getNeighborIdx(idx, Face::Down).has_value()) & Faces::Down) | ((!getNeighborIdx(idx, Face::Left).has_value()) & Faces::Left) | ((!getNeighborIdx(idx, Face::Right).has_value()) & Faces::Right) | ((!getNeighborIdx(idx, Face::Forward).has_value()) & Faces::Forward) | ((!getNeighborIdx(idx, Face::Backward).has_value()) & Faces::Backward)); } std::optional Chunk::getNeighborIdx(ushort idx, Face dir) { switch (dir) { case Face::Forward: if (idx % CHUNK_LENGTH >= CHUNK_LENGTH - 1) return {}; return idx + 1; case Face::Backward: if (idx % CHUNK_LENGTH <= 0) return {}; return idx - 1; case Face::Up: if ((idx / CHUNK_LENGTH) % CHUNK_LENGTH >= CHUNK_LENGTH - 1) return {}; return idx + CHUNK_LENGTH; case Face::Down: if ((idx / CHUNK_LENGTH) % CHUNK_LENGTH <= 0) return {}; return idx - CHUNK_LENGTH; case Face::Right: if (idx / CHUNK_LENGTH2 >= CHUNK_LENGTH - 1) return {}; return idx + CHUNK_LENGTH2; case Face::Left: if (idx / CHUNK_LENGTH2 <= 0) return {}; return idx - CHUNK_LENGTH2; default: return {}; } }