#include "Chunk.hpp" #include "materials.hpp" #include #include "../data/math.hpp" using namespace world; constexpr auto DENSITY = 0.f; constexpr auto GRANULARITY = 30.f; constexpr auto HEIGHT = 2; 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++) { const auto height = std::max(0l, pos.y * CHUNK_LENGTH + glm::fromIdx(i).y); const auto density = std::clamp((densitySet[i] + DENSITY) * GRANULARITY - height / HEIGHT, 0.f, 1.f) * Voxel::DENSITY_MAX; const auto material = 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) voxels[i] = Voxel(material, density); } rnd.free(densitySet); rnd.free(materialSet); } #include Chunk::Chunk(std::istream& str, bool rle) { if(rle) { ushort i = 0; while(!str.eof()) { ushort count; Voxel voxel; str.read(reinterpret_cast(&count), sizeof(count)); str.read(reinterpret_cast(&voxel), sizeof(voxel)); str.peek(); for (; count > 0; count--) { voxels[i] = voxel; i++; } } assert(i == CHUNK_SIZE && "Mismatch data length"); } else { for(auto& voxel: voxels) { str.read(reinterpret_cast(&voxel), sizeof(voxel)); } } } Chunk::~Chunk() { } void Chunk::write(std::ostream& str, bool rle) const { if (rle) { const auto *it = voxels.begin(); ushort counter = 1; Voxel current = *it; while(true) { ++it; const auto end = (it == voxels.end()); if(end || current.value != it->value) { str.write(reinterpret_cast(&counter), sizeof(counter)); str.write(reinterpret_cast(¤t), sizeof(current)); if(end) break; current = *it; counter = 1; } else { counter++; } } } else { for(auto current: voxels) { str.write(reinterpret_cast(¤t), sizeof(current)); } } } 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(chunk_voxel_idx idx, Face dir) { switch (dir) { case Face::Forward: if (idx % glm::IDX_LENGTH >= glm::IDX_LENGTH - 1) return {}; return idx + 1; case Face::Backward: if (idx % glm::IDX_LENGTH <= 0) return {}; return idx - 1; case Face::Up: if ((idx / glm::IDX_LENGTH) % glm::IDX_LENGTH >= glm::IDX_LENGTH - 1) return {}; return idx + glm::IDX_LENGTH; case Face::Down: if ((idx / glm::IDX_LENGTH) % glm::IDX_LENGTH <= 0) return {}; return idx - glm::IDX_LENGTH; case Face::Right: if (idx / glm::IDX_LENGTH2 >= glm::IDX_LENGTH - 1) return {}; return idx + glm::IDX_LENGTH2; case Face::Left: if (idx / glm::IDX_LENGTH2 <= 0) return {}; return idx - glm::IDX_LENGTH2; default: return {}; } }