1
0
Fork 0
Univerxel/src/world/Chunk.cpp

133 lines
4.0 KiB
C++
Raw Normal View History

2020-07-10 17:49:16 +00:00
#include "Chunk.hpp"
#include "materials.hpp"
2020-07-31 17:09:44 +00:00
#include <algorithm>
2020-07-10 17:49:16 +00:00
2020-07-25 16:45:03 +00:00
using namespace world;
2020-07-31 23:17:09 +00:00
constexpr auto DENSITY = 0.f;
constexpr auto GRANULARITY = 30.f;
constexpr auto RLE = true;
2020-07-10 17:49:16 +00:00
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;
2020-07-25 14:29:05 +00:00
voxels[i].Material = voxels[i].Density > 0 ? 1 + std::clamp(static_cast<int>(std::lrint((materialSet[i] + 1) / 2 * (materials::count - 2))),
0, materials::count - 2) : 0; //NOTE: map (approx -1, 1) to (1, mat_max)
2020-07-10 17:49:16 +00:00
}
2020-08-01 21:31:01 +00:00
rnd.free(densitySet);
rnd.free(materialSet);
2020-07-10 17:49:16 +00:00
}
2020-07-30 16:35:13 +00:00
Chunk::Chunk(std::istream& str) {
2020-07-31 23:17:09 +00:00
if constexpr (RLE) {
2020-07-26 20:53:14 +00:00
ushort i = 0;
while(!str.eof()) {
ushort count;
Voxel voxel;
str.read(reinterpret_cast<char *>(&count), sizeof(count));
str.read(reinterpret_cast<char *>(&voxel.Density), sizeof(Voxel::Density));
str.read(reinterpret_cast<char *>(&voxel.Material), sizeof(Voxel::Material));
str.peek();
for (; count > 0; count--) {
voxels[i] = voxel;
i++;
}
}
2020-07-31 17:09:44 +00:00
assert(("Mismatch data length", i == CHUNK_SIZE-1));
2020-07-31 23:17:09 +00:00
} else {
2020-07-30 16:35:13 +00:00
for(auto& voxel: voxels) {
str.read(reinterpret_cast<char *>(&voxel.Density), sizeof(Voxel::Density));
str.read(reinterpret_cast<char *>(&voxel.Material), sizeof(Voxel::Material));
}
2020-07-31 23:17:09 +00:00
}
2020-07-26 20:53:14 +00:00
}
2020-07-10 17:49:16 +00:00
Chunk::~Chunk() { }
2020-07-30 16:35:13 +00:00
void Chunk::write(std::ostream& str) const {
2020-07-31 23:17:09 +00:00
if constexpr (RLE) {
const auto *it = voxels.begin();
2020-07-26 20:53:14 +00:00
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<char *>(&counter), sizeof(counter));
str.write(reinterpret_cast<char *>(&current.Density), sizeof(current.Density));
str.write(reinterpret_cast<char *>(&current.Material), sizeof(current.Material));
if(end)
break;
current = *it;
counter = 1;
} else {
counter++;
}
}
2020-07-31 23:17:09 +00:00
} else {
2020-07-30 16:35:13 +00:00
for(auto current: voxels) {
str.write(reinterpret_cast<char *>(&current.Density), sizeof(current.Density));
str.write(reinterpret_cast<char *>(&current.Material), sizeof(current.Material));
}
2020-07-31 23:17:09 +00:00
}
2020-07-26 20:53:14 +00:00
}
2020-07-25 14:29:05 +00:00
std::optional<Faces> Chunk::update() {
2020-07-10 17:49:16 +00:00
if(upToDate) {
2020-07-25 14:29:05 +00:00
return {};
2020-07-10 17:49:16 +00:00
} else {
upToDate = true;
2020-07-25 14:29:05 +00:00
return {toUpdate};
2020-07-10 17:49:16 +00:00
}
}
2020-07-25 16:45:03 +00:00
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));
}
2020-07-31 23:17:09 +00:00
std::optional<ushort> Chunk::getNeighborIdx(ushort idx, Face dir) {
switch (dir) {
2020-07-10 17:49:16 +00:00
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 {};
}
}