parent
f75afb5e1e
commit
5c6ccd48e5
15
TODO.md
15
TODO.md
|
@ -4,10 +4,9 @@
|
|||
- [x] Generate noise
|
||||
- [x] Density
|
||||
- [x] Robin hood map
|
||||
- [ ] In memory RLE
|
||||
- [ ] Octree world
|
||||
- [ ] Remove density
|
||||
- [x] Serialize
|
||||
- [ ] Variable length encoding
|
||||
- [x] Group files
|
||||
- [x] Zstd + custom grouping
|
||||
- [~] Find best region size
|
||||
|
@ -15,13 +14,15 @@
|
|||
- [x] Low memory: Keep only ifstream
|
||||
- [x] High memory: Save multiple
|
||||
- [x] Unload unused
|
||||
- [ ] In memory RLE
|
||||
- [x] Edition
|
||||
- [ ] Entity
|
||||
- [ ] Planet
|
||||
- [ ] CubicSphere
|
||||
- [ ] Healpix
|
||||
- [ ] Galaxy
|
||||
- [ ] Area
|
||||
- [ ] Offset
|
||||
- [ ] Rotation
|
||||
- [ ] Planet
|
||||
- [ ] CubicSphere
|
||||
- [ ] Healpix
|
||||
- [ ] Galaxy
|
||||
- [ ] Biomes
|
||||
- https://imgur.com/kM8b5Zq
|
||||
- https://imgur.com/a/bh2iy
|
||||
|
|
|
@ -15,13 +15,13 @@ namespace contouring {
|
|||
|
||||
/// Each frame ping.
|
||||
/// Mostly used for cleanup and to flush buffers data using main thread
|
||||
virtual void update(const voxel_pos &pos) = 0;
|
||||
virtual void update(const voxel_pos &pos, const world::area_map &areas) = 0;
|
||||
|
||||
/// Chunk data change
|
||||
virtual void onUpdate(const chunk_pos &pos, const world::chunk_map &data, geometry::Faces neighbors) = 0;
|
||||
virtual void onUpdate(const area_<chunk_pos> &pos, const world::ChunkContainer &data, geometry::Faces neighbors) = 0;
|
||||
/// Chunk existante ping
|
||||
/// @note notify for chunks entering view while moving
|
||||
virtual void onNotify(const chunk_pos &pos, const world::chunk_map &data) = 0;
|
||||
virtual void onNotify(const area_<chunk_pos> &pos, const world::ChunkContainer &data) = 0;
|
||||
/// Display ImGui config
|
||||
virtual void onGui() = 0;
|
||||
/// Get options
|
||||
|
|
|
@ -5,17 +5,30 @@
|
|||
#include "../world/Chunk.hpp"
|
||||
|
||||
namespace contouring {
|
||||
void AbstractFlat::update(const voxel_pos& pos) {
|
||||
center = glm::divide(pos, chunk_voxel_pos(CHUNK_LENGTH));
|
||||
auto it = buffers.begin();
|
||||
while (it != buffers.end()) { // Remove out of range buffers
|
||||
if (inKeepRange(it->first)) {
|
||||
it++;
|
||||
} else {
|
||||
if(it->second != NULL)
|
||||
delete it->second;
|
||||
void AbstractFlat::update(const voxel_pos& pos, const world::area_map& areas) {
|
||||
center = glm::divide(pos);
|
||||
auto it_a = buffers.begin();
|
||||
while (it_a != buffers.end()) { // Remove out of range buffers
|
||||
if (const auto area = areas.find(it_a->first); area != areas.end()) {
|
||||
//Update
|
||||
auto it = it_a->second.begin();
|
||||
while(it != it_a->second.end()) {
|
||||
if (inKeepRange(it->first /*TODO: + area.second->getPosition() */)) {
|
||||
++it;
|
||||
} else {
|
||||
if(it->second != NULL)
|
||||
delete it->second;
|
||||
|
||||
it = buffers.erase(it);
|
||||
it = it_a->second.erase(it);
|
||||
}
|
||||
}
|
||||
++it_a;
|
||||
} else {
|
||||
for(auto& buffer: it_a->second) {
|
||||
if(buffer.second != NULL)
|
||||
delete buffer.second;
|
||||
}
|
||||
it_a = buffers.erase(it_a);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -41,10 +54,11 @@ namespace contouring {
|
|||
|
||||
void AbstractFlat::getModels(std::vector<std::pair<glm::mat4, buffer::Abstract *const>> &out, const std::optional<geometry::Frustum> &frustum, const glm::llvec3& offset, int density) {
|
||||
const auto scaling = glm::scale(glm::mat4(1), glm::vec3(1.f / density));
|
||||
for (const auto [pos, buffer] : buffers) {
|
||||
const glm::vec3 fPos = glm::vec3(glm::llvec3(pos) * glm::llvec3(CHUNK_LENGTH) - offset * glm::llvec3(density)) / glm::vec3(density);
|
||||
for (const auto [_, bfs] : buffers) {
|
||||
for (const auto [pos, buffer] : bfs) {
|
||||
const glm::vec3 fPos = glm::vec3(glm::multiply(pos /*TODO: + area.position*/) - offset * glm::llvec3(density)) / glm::vec3(density);
|
||||
if (buffer != NULL && (!frustum.has_value() || frustum.value().contains(geometry::Box::fromMin(fPos, glm::vec3(CHUNK_LENGTH / (float)density)))))
|
||||
out.emplace_back(glm::translate(scaling, fPos * (float)density), buffer);
|
||||
}
|
||||
}}
|
||||
}
|
||||
}
|
|
@ -11,7 +11,7 @@ namespace contouring {
|
|||
virtual ~AbstractFlat() {}
|
||||
|
||||
/// Each frame ping. Used to clear out of range
|
||||
void update(const voxel_pos &) override;
|
||||
void update(const voxel_pos &, const world::area_map &areas) override;
|
||||
|
||||
/// Display ImGui config
|
||||
void onGui() override;
|
||||
|
@ -30,7 +30,8 @@ namespace contouring {
|
|||
return glm::length2(center - point) <= keepDistance * keepDistance;
|
||||
}
|
||||
|
||||
robin_hood::unordered_map<chunk_pos, buffer::Abstract *> buffers;
|
||||
//MAYBE: store position copy
|
||||
robin_hood::unordered_flat_map<area_id, robin_hood::unordered_flat_map<chunk_pos, buffer::Abstract *>> buffers;
|
||||
chunk_pos center = chunk_pos(INT_MAX);
|
||||
|
||||
int loadDistance = 3;
|
||||
|
|
|
@ -9,9 +9,9 @@ namespace contouring {
|
|||
Dummy(): Abstract() { }
|
||||
virtual ~Dummy() { }
|
||||
|
||||
void update(const voxel_pos &) override { }
|
||||
void onUpdate(const chunk_pos &, const world::chunk_map &, geometry::Faces) override {}
|
||||
void onNotify(const chunk_pos &, const world::chunk_map &) override { }
|
||||
void update(const voxel_pos &, const world::area_map &) override {}
|
||||
void onUpdate(const area_<chunk_pos> &, const world::ChunkContainer &, geometry::Faces) override {}
|
||||
void onNotify(const area_<chunk_pos> &, const world::ChunkContainer &) override {}
|
||||
void onGui() override { }
|
||||
std::string getOptions() override { return ""; }
|
||||
void getModels(std::vector<std::pair<glm::mat4, buffer::Abstract *const>> &, const std::optional<geometry::Frustum>&, const glm::llvec3&, int) override { }
|
||||
|
|
|
@ -16,7 +16,7 @@ namespace contouring {
|
|||
for (size_t i = 1; i <= 2; i++) {
|
||||
workers.emplace_back([&] {
|
||||
while (running) {
|
||||
std::pair<chunk_pos, surrounding::corners> ctx;
|
||||
std::pair<area_<chunk_pos>, surrounding::corners> ctx;
|
||||
loadQueue.wait();
|
||||
if (loadQueue.pop(ctx)) {
|
||||
rmt_ScopedCPUSample(ProcessContouring, 0);
|
||||
|
@ -49,51 +49,52 @@ namespace contouring {
|
|||
return ss.str();
|
||||
}
|
||||
|
||||
void FlatDualMC::enqueue(const chunk_pos &pos, const world::chunk_map &data) {
|
||||
void FlatDualMC::enqueue(const area_<chunk_pos> &pos, const world::ChunkContainer &data) {
|
||||
rmt_ScopedCPUSample(EnqueueContouring, RMTSF_Aggregate);
|
||||
const auto dist2 = glm::length2(pos - center);
|
||||
const auto dist2 = glm::length2(center - pos.second); //TODO: - area.pos
|
||||
if (dist2 <= loadDistance * loadDistance) {
|
||||
surrounding::corners surrounding;
|
||||
if(surrounding::load(surrounding, pos, data)) {
|
||||
if(surrounding::load(surrounding, pos.second, data)) {
|
||||
loadQueue.push(pos, surrounding, -dist2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void FlatDualMC::onUpdate(const chunk_pos &pos, const world::chunk_map &data, geometry::Faces neighbors) {
|
||||
void FlatDualMC::onUpdate(const area_<chunk_pos> &pos, const world::ChunkContainer &data, geometry::Faces neighbors) {
|
||||
enqueue(pos, data);
|
||||
if (neighbors && (geometry::Faces::Left | geometry::Faces::Down | geometry::Faces::Backward)) {
|
||||
for (size_t i = 1; i < 8; i++) {
|
||||
enqueue(pos - surrounding::g_corner_offsets[i], data);
|
||||
enqueue(std::make_pair(pos.first, pos.second - surrounding::g_corner_offsets[i]), data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void FlatDualMC::onNotify(const chunk_pos &pos, const world::chunk_map &data) {
|
||||
if (buffers.find(pos) == buffers.end()) {
|
||||
void FlatDualMC::onNotify(const area_<chunk_pos> &pos, const world::ChunkContainer &data) {
|
||||
const auto it = buffers.find(pos.first);
|
||||
if(it == buffers.end() || it->second.find(pos.second) == it->second.end()) {
|
||||
enqueue(pos, data);
|
||||
}
|
||||
}
|
||||
|
||||
void FlatDualMC::update(const voxel_pos& pos) {
|
||||
AbstractFlat::update(pos);
|
||||
std::pair<chunk_pos, buffer::ShortIndexed::Data> out;
|
||||
void FlatDualMC::update(const voxel_pos& pos, const world::area_map& areas) {
|
||||
AbstractFlat::update(pos, areas);
|
||||
std::pair<area_<chunk_pos>, buffer::ShortIndexed::Data> out;
|
||||
reports.load.push(loadQueue.size());
|
||||
//MAYBE: clear out of range loadQueue.trim(keepDistance * keepDistance)
|
||||
reports.loaded.push(loadedQueue.size());
|
||||
while(loadedQueue.pop(out)) {
|
||||
const auto buffer = new buffer::ShortIndexed(GL_TRIANGLES, out.second);
|
||||
const auto it = buffers.find(out.first);
|
||||
if (it != buffers.end()) {
|
||||
auto& bfs = buffers[out.first.first];
|
||||
if (const auto it = bfs.find(out.first.second); it != bfs.end()) {
|
||||
if(it->second != NULL)
|
||||
delete it->second;
|
||||
|
||||
it->second = buffer;
|
||||
} else {
|
||||
buffers.emplace(out.first, buffer);
|
||||
bfs.emplace(out.first.second, buffer);
|
||||
}
|
||||
}
|
||||
reports.count.push(buffers.size());
|
||||
reports.count.push(buffers.size()); //FIXME: get from AbstractFlat
|
||||
}
|
||||
|
||||
void FlatDualMC::onGui() {
|
||||
|
@ -116,7 +117,7 @@ namespace contouring {
|
|||
for (int y = 0; y < SIZE; y++) {
|
||||
for (int x = 0; x < SIZE; x++) {
|
||||
const auto &chunk = surrounding[(z >= CHUNK_LENGTH) + (y >= CHUNK_LENGTH)*2 + (x >= CHUNK_LENGTH)*4];
|
||||
const auto &voxel = chunk->getAt(chunk_voxel_pos(x % CHUNK_LENGTH, y % CHUNK_LENGTH, z % CHUNK_LENGTH));
|
||||
const auto &voxel = chunk->get(glm::toIdx(x % CHUNK_LENGTH, y % CHUNK_LENGTH, z % CHUNK_LENGTH));
|
||||
grid.emplace_back(voxel.density() * 1.f / world::Voxel::DENSITY_MAX, voxel.material());
|
||||
}}}
|
||||
}
|
||||
|
|
|
@ -19,21 +19,21 @@ namespace contouring {
|
|||
FlatDualMC(const std::string&);
|
||||
virtual ~FlatDualMC();
|
||||
|
||||
void update(const voxel_pos&) override;
|
||||
void update(const voxel_pos&, const world::area_map&) override;
|
||||
|
||||
void onGui() override;
|
||||
|
||||
std::string getOptions() override;
|
||||
|
||||
/// Chunk data change
|
||||
void onUpdate(const chunk_pos &, const world::chunk_map &, geometry::Faces) override;
|
||||
void onUpdate(const area_<chunk_pos> &, const world::ChunkContainer &, geometry::Faces) override;
|
||||
/// Chunk existante ping
|
||||
/// @note notify for chunks entering view while moving
|
||||
void onNotify(const chunk_pos &, const world::chunk_map &) override;
|
||||
void onNotify(const area_<chunk_pos> &, const world::ChunkContainer &) override;
|
||||
|
||||
protected:
|
||||
safe_priority_queue_map<chunk_pos, surrounding::corners, int> loadQueue;
|
||||
safe_queue<std::pair<chunk_pos, buffer::ShortIndexed::Data>> loadedQueue;
|
||||
safe_priority_queue_map<area_<chunk_pos>, surrounding::corners, int, area_hash> loadQueue;
|
||||
safe_queue<std::pair<area_<chunk_pos>, buffer::ShortIndexed::Data>> loadedQueue;
|
||||
|
||||
struct report {
|
||||
circular_buffer<float> count = circular_buffer<float>(REPORT_BUFFER_SIZE, 0); // MAYBE: store int
|
||||
|
@ -44,7 +44,7 @@ namespace contouring {
|
|||
bool running = true;
|
||||
std::vector<std::thread> workers;
|
||||
|
||||
void enqueue(const chunk_pos &, const world::chunk_map &);
|
||||
void enqueue(const area_<chunk_pos> &, const world::ChunkContainer &);
|
||||
|
||||
float iso = .1f;
|
||||
bool manifold = true;
|
||||
|
|
|
@ -11,7 +11,7 @@ namespace contouring {
|
|||
for (size_t i = 1; i <= 4; i++) {
|
||||
workers.emplace_back([&] {
|
||||
while (running) {
|
||||
std::pair<chunk_pos, surrounding::faces> ctx;
|
||||
std::pair<area_<chunk_pos>, surrounding::faces> ctx;
|
||||
loadQueue.wait();
|
||||
if (loadQueue.pop(ctx)) {
|
||||
rmt_ScopedCPUSample(ProcessContouring, 0);
|
||||
|
@ -36,63 +36,64 @@ namespace contouring {
|
|||
}
|
||||
}
|
||||
|
||||
void FlatSurroundingBox::enqueue(const chunk_pos &pos, const world::chunk_map &data) {
|
||||
void FlatSurroundingBox::enqueue(const area_<chunk_pos> &pos, const world::ChunkContainer &data) {
|
||||
rmt_ScopedCPUSample(EnqueueContouring, RMTSF_Aggregate);
|
||||
const auto dist2 = glm::length2(pos - center);
|
||||
const auto dist2 = glm::length2(center - pos.second /*TODO: - area.pos */);
|
||||
if (dist2 <= loadDistance * loadDistance) {
|
||||
surrounding::faces surrounding;
|
||||
if(surrounding::load(surrounding, pos, data)) {
|
||||
if(surrounding::load(surrounding, pos.second, data)) {
|
||||
loadQueue.push(pos, surrounding, -dist2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void FlatSurroundingBox::onUpdate(const chunk_pos &pos, const world::chunk_map &data, Faces neighbors) {
|
||||
void FlatSurroundingBox::onUpdate(const area_<chunk_pos> &pos, const world::ChunkContainer &data, Faces neighbors) {
|
||||
enqueue(pos, data);
|
||||
if (neighbors && Faces::Right)
|
||||
enqueue(pos + g_face_offsets[static_cast<int>(Face::Right)], data);
|
||||
enqueue(std::make_pair(pos.first, pos.second + g_face_offsets[static_cast<int>(Face::Right)]), data);
|
||||
|
||||
if (neighbors && Faces::Left)
|
||||
enqueue(pos + g_face_offsets[static_cast<int>(Face::Left)], data);
|
||||
enqueue(std::make_pair(pos.first, pos.second + g_face_offsets[static_cast<int>(Face::Left)]), data);
|
||||
|
||||
if (neighbors && Faces::Up)
|
||||
enqueue(pos + g_face_offsets[static_cast<int>(Face::Up)], data);
|
||||
enqueue(std::make_pair(pos.first, pos.second + g_face_offsets[static_cast<int>(Face::Up)]), data);
|
||||
|
||||
if (neighbors && Faces::Down)
|
||||
enqueue(pos + g_face_offsets[static_cast<int>(Face::Down)], data);
|
||||
enqueue(std::make_pair(pos.first, pos.second + g_face_offsets[static_cast<int>(Face::Down)]), data);
|
||||
|
||||
if (neighbors && Faces::Forward)
|
||||
enqueue(pos + g_face_offsets[static_cast<int>(Face::Forward)], data);
|
||||
enqueue(std::make_pair(pos.first, pos.second + g_face_offsets[static_cast<int>(Face::Forward)]), data);
|
||||
|
||||
if (neighbors && Faces::Backward)
|
||||
enqueue(pos + g_face_offsets[static_cast<int>(Face::Backward)], data);
|
||||
enqueue(std::make_pair(pos.first, pos.second + g_face_offsets[static_cast<int>(Face::Backward)]), data);
|
||||
}
|
||||
|
||||
void FlatSurroundingBox::onNotify(const chunk_pos &pos, const world::chunk_map &data) {
|
||||
if (buffers.find(pos) == buffers.end()) {
|
||||
void FlatSurroundingBox::onNotify(const area_<chunk_pos> &pos, const world::ChunkContainer &data) {
|
||||
const auto it = buffers.find(pos.first);
|
||||
if(it == buffers.end() || it->second.find(pos.second) == it->second.end()) {
|
||||
enqueue(pos, data);
|
||||
}
|
||||
}
|
||||
|
||||
void FlatSurroundingBox::update(const voxel_pos& pos) {
|
||||
AbstractFlat::update(pos);
|
||||
std::pair<chunk_pos, buffer::ShortIndexed::Data> out;
|
||||
void FlatSurroundingBox::update(const voxel_pos& pos, const world::area_map& areas) {
|
||||
AbstractFlat::update(pos, areas);
|
||||
std::pair<area_<chunk_pos>, buffer::ShortIndexed::Data> out;
|
||||
reports.load.push(loadQueue.size());
|
||||
//MAYBE: clear out of range loadQueue.trim(keepDistance * keepDistance)
|
||||
reports.loaded.push(loadedQueue.size());
|
||||
while(loadedQueue.pop(out)) {
|
||||
const auto buffer = new buffer::ShortIndexed(GL_TRIANGLES, out.second);
|
||||
const auto it = buffers.find(out.first);
|
||||
if (it != buffers.end()) {
|
||||
auto& bfs = buffers[out.first.first];
|
||||
if (const auto it = bfs.find(out.first.second); it != bfs.end()) {
|
||||
if(it->second != NULL)
|
||||
delete it->second;
|
||||
|
||||
it->second = buffer;
|
||||
} else {
|
||||
buffers.emplace(out.first, buffer);
|
||||
bfs.emplace(out.first.second, buffer);
|
||||
}
|
||||
}
|
||||
reports.count.push(buffers.size());
|
||||
reports.count.push(buffers.size()); //FIXME: get from AbstractFlat
|
||||
}
|
||||
|
||||
void FlatSurroundingBox::onGui() {
|
||||
|
@ -110,7 +111,7 @@ namespace contouring {
|
|||
void FlatSurroundingBox::render(const surrounding::faces &surrounding, std::vector<buffer::VertexData> &vertices) {
|
||||
const auto center = surrounding[surrounding::CENTER];
|
||||
vertices.clear();
|
||||
for (ushort i = 0; i < CHUNK_SIZE; i++) {
|
||||
for (ushort i = 0; i < world::CHUNK_SIZE; i++) {
|
||||
if (center->get(i).density() > 0) {
|
||||
Faces faces = center->get(i).density() < world::Voxel::DENSITY_MAX ? Faces::All :
|
||||
(isTransparent(surrounding, surrounding::getNeighborIdx(i, Face::Right)) & Faces::Right) |
|
||||
|
@ -119,7 +120,7 @@ namespace contouring {
|
|||
(isTransparent(surrounding, surrounding::getNeighborIdx(i, Face::Down)) & Faces::Down) |
|
||||
(isTransparent(surrounding, surrounding::getNeighborIdx(i, Face::Forward)) & Faces::Forward) |
|
||||
(isTransparent(surrounding, surrounding::getNeighborIdx(i, Face::Backward)) & Faces::Backward);
|
||||
box::addCube(vertices, world::Chunk::getPosition(i), center->get(i).material(), faces, glm::vec3(center->get(i).density() * 1.f / world::Voxel::DENSITY_MAX));
|
||||
box::addCube(vertices, glm::fromIdx(i), center->get(i).material(), faces, glm::vec3(center->get(i).density() * 1.f / world::Voxel::DENSITY_MAX));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,19 +19,19 @@ namespace contouring {
|
|||
FlatSurroundingBox(const std::string&);
|
||||
virtual ~FlatSurroundingBox();
|
||||
|
||||
void update(const voxel_pos&) override;
|
||||
void update(const voxel_pos&, const world::area_map&) override;
|
||||
|
||||
void onGui() override;
|
||||
|
||||
/// Chunk data change
|
||||
void onUpdate(const chunk_pos &, const world::chunk_map &, geometry::Faces) override;
|
||||
void onUpdate(const area_<chunk_pos> &, const world::ChunkContainer &, geometry::Faces) override;
|
||||
/// Chunk existante ping
|
||||
/// @note notify for chunks entering view while moving
|
||||
void onNotify(const chunk_pos &, const world::chunk_map &) override;
|
||||
void onNotify(const area_<chunk_pos> &, const world::ChunkContainer &) override;
|
||||
|
||||
protected:
|
||||
safe_priority_queue_map<chunk_pos, surrounding::faces, int> loadQueue;
|
||||
safe_queue<std::pair<chunk_pos, buffer::ShortIndexed::Data>> loadedQueue;
|
||||
safe_priority_queue_map<area_<chunk_pos>, surrounding::faces, int, area_hash> loadQueue;
|
||||
safe_queue<std::pair<area_<chunk_pos>, buffer::ShortIndexed::Data>> loadedQueue;
|
||||
|
||||
struct report {
|
||||
circular_buffer<float> count = circular_buffer<float>(REPORT_BUFFER_SIZE, 0); // MAYBE: store int
|
||||
|
@ -42,7 +42,7 @@ namespace contouring {
|
|||
bool running = true;
|
||||
std::vector<std::thread> workers;
|
||||
|
||||
void enqueue(const chunk_pos &, const world::chunk_map &);
|
||||
void enqueue(const area_<chunk_pos> &, const world::ChunkContainer &);
|
||||
|
||||
private:
|
||||
static inline bool isTransparent(const surrounding::faces &surrounding, const std::pair<ushort, ushort> &idx);
|
||||
|
|
|
@ -1,72 +1,79 @@
|
|||
#include "surrounding.hpp"
|
||||
|
||||
#include "../world/Chunk.hpp"
|
||||
#include "../world/Area.hpp"
|
||||
#include "../data/math.hpp"
|
||||
|
||||
using namespace geometry;
|
||||
namespace contouring::surrounding {
|
||||
bool load(faces &out, const chunk_pos &chunkPos, const world::chunk_map &chunks) {
|
||||
bool load(faces &out, const chunk_pos &chunkPos, const world::ChunkContainer &chunks) {
|
||||
{
|
||||
const auto it = chunks.find(chunkPos);
|
||||
if (it == chunks.end())
|
||||
const auto chunk = chunks.findInRange(chunkPos);
|
||||
if (!chunk.has_value())
|
||||
return false;
|
||||
|
||||
out[CENTER] = it->second;
|
||||
out[CENTER] = chunk.value();
|
||||
}
|
||||
for (size_t i = 0; i < CENTER; i++) {
|
||||
const auto it = chunks.find(chunkPos + g_face_offsets[i]);
|
||||
if (it == chunks.end())
|
||||
const auto chunk = chunks.findOrEmpty(chunkPos + g_face_offsets[i]);
|
||||
if (!chunk.has_value())
|
||||
return false;
|
||||
|
||||
out[i] = it->second;
|
||||
out[i] = chunk.value();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
std::pair<ushort, ushort> getNeighborIdx(ushort idx, Face face) {
|
||||
std::pair<glm::idx, glm::idx> getNeighborIdx(glm::idx idx, Face face) {
|
||||
switch (face) {
|
||||
case Face::Forward:
|
||||
if (idx % CHUNK_LENGTH >= CHUNK_LENGTH - 1)
|
||||
return {static_cast<int>(Face::Forward), idx - (CHUNK_LENGTH - 1)};
|
||||
if (idx % glm::IDX_LENGTH >= glm::IDX_LENGTH - 1)
|
||||
return {static_cast<int>(Face::Forward), idx - (glm::IDX_LENGTH - 1)};
|
||||
return {CENTER, idx + 1};
|
||||
|
||||
case Face::Backward:
|
||||
if (idx % CHUNK_LENGTH <= 0)
|
||||
return {static_cast<int>(Face::Backward), idx + (CHUNK_LENGTH - 1)};
|
||||
if (idx % glm::IDX_LENGTH <= 0)
|
||||
return {static_cast<int>(Face::Backward), idx + (glm::IDX_LENGTH - 1)};
|
||||
return {CENTER, idx - 1};
|
||||
|
||||
case Face::Up:
|
||||
if ((idx / CHUNK_LENGTH) % CHUNK_LENGTH >= CHUNK_LENGTH - 1)
|
||||
return {static_cast<int>(Face::Up), idx - (CHUNK_LENGTH2 - CHUNK_LENGTH)};
|
||||
return {CENTER, idx + CHUNK_LENGTH};
|
||||
if ((idx / glm::IDX_LENGTH) % glm::IDX_LENGTH >= glm::IDX_LENGTH - 1)
|
||||
return {static_cast<int>(Face::Up), idx - (glm::IDX_LENGTH2 - glm::IDX_LENGTH)};
|
||||
return {CENTER, idx + glm::IDX_LENGTH};
|
||||
|
||||
case Face::Down:
|
||||
if ((idx / CHUNK_LENGTH) % CHUNK_LENGTH <= 0)
|
||||
return {static_cast<int>(Face::Down), idx + (CHUNK_LENGTH2 - CHUNK_LENGTH)};
|
||||
return {CENTER, idx - CHUNK_LENGTH};
|
||||
if ((idx / glm::IDX_LENGTH) % glm::IDX_LENGTH <= 0)
|
||||
return {static_cast<int>(Face::Down), idx + (glm::IDX_LENGTH2 - glm::IDX_LENGTH)};
|
||||
return {CENTER, idx - glm::IDX_LENGTH};
|
||||
|
||||
case Face::Right:
|
||||
if (idx / CHUNK_LENGTH2 >= CHUNK_LENGTH - 1)
|
||||
return {static_cast<int>(Face::Right), idx - (CHUNK_SIZE - CHUNK_LENGTH2)};
|
||||
return {CENTER, idx + CHUNK_LENGTH2};
|
||||
if (idx / glm::IDX_LENGTH2 >= glm::IDX_LENGTH - 1)
|
||||
return {static_cast<int>(Face::Right), idx - (glm::IDX_SIZE - glm::IDX_LENGTH2)};
|
||||
return {CENTER, idx + glm::IDX_LENGTH2};
|
||||
|
||||
case Face::Left:
|
||||
if (idx / CHUNK_LENGTH2 <= 0)
|
||||
return {static_cast<int>(Face::Left), idx + (CHUNK_SIZE - CHUNK_LENGTH2)};
|
||||
return {CENTER, idx - CHUNK_LENGTH2};
|
||||
if (idx / glm::IDX_LENGTH2 <= 0)
|
||||
return {static_cast<int>(Face::Left), idx + (glm::IDX_SIZE - glm::IDX_LENGTH2)};
|
||||
return {CENTER, idx - glm::IDX_LENGTH2};
|
||||
|
||||
default:
|
||||
return {CENTER, idx};
|
||||
}
|
||||
}
|
||||
|
||||
bool load(corners &out, const chunk_pos &chunkPos, const world::chunk_map &chunks) {
|
||||
for (size_t i = 0; i < 8; i++) {
|
||||
const auto it = chunks.find(chunkPos + g_corner_offsets[i]);
|
||||
if (it == chunks.end())
|
||||
bool load(corners &out, const chunk_pos &chunkPos, const world::ChunkContainer &chunks) {
|
||||
{
|
||||
const auto chunk = chunks.findInRange(chunkPos);
|
||||
if(!chunk.has_value())
|
||||
return false;
|
||||
|
||||
out[i] = it->second;
|
||||
out[0] = chunk.value();
|
||||
}
|
||||
for (size_t i = 1; i < 8; i++) {
|
||||
const auto chunk = chunks.findOrEmpty(chunkPos + g_corner_offsets[i]);
|
||||
if (!chunk.has_value())
|
||||
return false;
|
||||
|
||||
out[i] = chunk.value();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -10,7 +10,7 @@ namespace contouring::surrounding {
|
|||
const auto CENTER = 6;
|
||||
typedef std::array<std::shared_ptr<const world::Chunk>, CENTER+1> faces;
|
||||
|
||||
bool load(faces &out, const chunk_pos &chunkPos, const world::chunk_map &chunks);
|
||||
bool load(faces &out, const chunk_pos &chunkPos, const world::ChunkContainer &chunks);
|
||||
|
||||
std::pair<ushort, ushort> getNeighborIdx(ushort idx, geometry::Face face);
|
||||
|
||||
|
@ -26,5 +26,5 @@ namespace contouring::surrounding {
|
|||
chunk_pos(1, 1, 1),
|
||||
};
|
||||
|
||||
bool load(corners &out, const chunk_pos &chunkPos, const world::chunk_map &chunks);
|
||||
bool load(corners &out, const chunk_pos &chunkPos, const world::ChunkContainer &chunks);
|
||||
}
|
||||
|
|
|
@ -11,7 +11,7 @@ namespace geometry {
|
|||
};
|
||||
|
||||
Box(glm::vec3 min, glm::vec3 max): Min(min), Max(max) {
|
||||
assert(("Min > Max", max.x >= min.x && max.y >= min.y && max.z >= min.z));
|
||||
assert((max.x >= min.x && max.y >= min.y && max.z >= min.z) && "Min > Max");
|
||||
}
|
||||
inline static Box fromCenter(glm::vec3 center, float radius) { return Box(center - radius, center + radius); }
|
||||
inline static Box fromMin(glm::vec3 min, glm::vec3 size) { return Box(min, min + size); }
|
||||
|
|
|
@ -7,4 +7,9 @@ namespace glm {
|
|||
typedef vec<3, long> lvec3;
|
||||
typedef vec<3, ushort> usvec3;
|
||||
typedef vec<3, unsigned char> ucvec3;
|
||||
|
||||
const auto IDX_LENGTH = 32;
|
||||
const auto IDX_LENGTH2 = IDX_LENGTH * IDX_LENGTH;
|
||||
const auto IDX_SIZE = IDX_LENGTH2 * IDX_LENGTH;
|
||||
using idx = glm::u16;
|
||||
}
|
||||
|
|
|
@ -20,16 +20,32 @@ namespace glm {
|
|||
constexpr long inline div(long long value, uint m) {
|
||||
return value < 0 ? ((value+1) / (long long)m) - 1 : value / (long long)m;
|
||||
}
|
||||
constexpr ucvec3 inline modulo(const llvec3& value, const ucvec3& m) {
|
||||
constexpr ucvec3 inline modulo(const llvec3& value, const ucvec3& m = ucvec3(IDX_LENGTH)) {
|
||||
return ucvec3(rem(value.x, m.x), rem(value.y, m.y), rem(value.z, m.z));
|
||||
}
|
||||
constexpr lvec3 inline divide(const llvec3 &value, const ucvec3 &m) {
|
||||
return lvec3(div(value.x, m.x), div(value.y, m.y), div(value.z, m.z));
|
||||
}
|
||||
constexpr lvec3 inline divide(const llvec3 &value, const uvec3 &m) {
|
||||
return lvec3(div(value.x, m.x), div(value.y, m.y), div(value.z, m.z));
|
||||
}
|
||||
constexpr std::pair<lvec3, ucvec3> inline split(const llvec3 &value, const ucvec3 &m) {
|
||||
constexpr lvec3 inline divide(const llvec3 &value, const ucvec3 &m = ucvec3(IDX_LENGTH)) {
|
||||
return lvec3(div(value.x, m.x), div(value.y, m.y), div(value.z, m.z));
|
||||
}
|
||||
constexpr llvec3 inline multiply(const lvec3 &value, const ucvec3 &m = ucvec3(IDX_LENGTH)) {
|
||||
return llvec3(value) * llvec3(m);
|
||||
}
|
||||
constexpr std::pair<lvec3, ucvec3> inline split(const llvec3 &value, const ucvec3 &m = ucvec3(IDX_LENGTH)) {
|
||||
return {divide(value, m), modulo(value, m)};
|
||||
}
|
||||
constexpr ucvec3 inline fromIdx(idx idx) {
|
||||
assert(idx < IDX_SIZE);
|
||||
return ucvec3(idx / IDX_LENGTH2, (idx / IDX_LENGTH) % IDX_LENGTH, idx % IDX_LENGTH);
|
||||
}
|
||||
constexpr idx inline toIdx(glm::u8 x, glm::u8 y, glm::u8 z) {
|
||||
return (x * IDX_LENGTH + y) * IDX_LENGTH + z;
|
||||
}
|
||||
constexpr idx inline toIdx(ucvec3 pos) {
|
||||
return toIdx(pos.x, pos.y, pos.z);
|
||||
}
|
||||
constexpr std::pair<lvec3, idx> inline splitIdx(const llvec3 &value, const ucvec3 &m = ucvec3(IDX_LENGTH)) {
|
||||
return {divide(value, m), toIdx(rem(value.x, m.x), rem(value.y, m.y), rem(value.z, m.z))};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
|
||||
namespace data {
|
||||
/// Thread safe queue with unique keys updating priority and value
|
||||
template <class K, class V, class W>
|
||||
template <class K, class V, class W, class hash = robin_hood::hash<K>>
|
||||
class safe_priority_queue_map {
|
||||
private:
|
||||
static bool cmpByWeight(const std::pair<K, W> &a, const std::pair<K, W> &b) {
|
||||
|
@ -18,7 +18,7 @@ namespace data {
|
|||
}
|
||||
|
||||
std::vector<std::pair<K, W>> heap;
|
||||
robin_hood::unordered_map<K, V> map;
|
||||
robin_hood::unordered_map<K, V, hash> map;
|
||||
std::mutex mutex;
|
||||
std::condition_variable cv;
|
||||
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
#include <queue>
|
||||
#include <mutex>
|
||||
#include <condition_variable>
|
||||
#include <robin_hood.h>
|
||||
|
||||
namespace data {
|
||||
/// Thread safe queue
|
||||
|
|
|
@ -7,11 +7,11 @@
|
|||
|
||||
namespace data {
|
||||
/// Thread safe queue discarding duplicate values
|
||||
template <class T>
|
||||
template <class T, class hash = robin_hood::hash<T>>
|
||||
class safe_unique_queue {
|
||||
private:
|
||||
std::queue<T> queue;
|
||||
robin_hood::unordered_flat_set<T> set;
|
||||
robin_hood::unordered_flat_set<T, hash> set;
|
||||
std::mutex mutex;
|
||||
std::condition_variable cv;
|
||||
|
||||
|
|
|
@ -74,10 +74,10 @@ int main(int /*unused*/, char */*unused*/[]){
|
|||
glm::vec4(1, 1, 1, 1), glm::vec4(1, 1, 1, 1),
|
||||
});
|
||||
|
||||
#if RMT_ENABLED
|
||||
Remotery *rmt;
|
||||
rmt_CreateGlobalInstance(&rmt);
|
||||
rmt_BindOpenGL();
|
||||
#if RMT_ENABLED
|
||||
LOG("Profiling !");
|
||||
#endif
|
||||
|
||||
|
@ -171,7 +171,7 @@ int main(int /*unused*/, char */*unused*/[]){
|
|||
if(state.look_at.has_value()) {
|
||||
lookProgram->useIt();
|
||||
lookProgram->start(renderer);
|
||||
const auto model = glm::scale(glm::translate(glm::scale(glm::mat4(1), 1.f / glm::vec3(options.voxel_density)), glm::vec3(state.look_at.value().first - offset * glm::llvec3(options.voxel_density)) - glm::vec3(.5 + options.tool.radius)), glm::vec3(1 + options.tool.radius * 2));
|
||||
const auto model = glm::scale(glm::translate(glm::scale(glm::mat4(1), 1.f / glm::vec3(options.voxel_density)), glm::vec3(state.look_at.value().first.second - offset * glm::llvec3(options.voxel_density)) - glm::vec3(.5 + options.tool.radius)), glm::vec3(1 + options.tool.radius * 2));
|
||||
lookBuffer.draw(lookProgram->setup(renderer, model));
|
||||
}
|
||||
renderer->postProcess();
|
||||
|
|
|
@ -166,8 +166,8 @@ UI::Actions UI::draw(options &options, state &state, const reports &reports, GLu
|
|||
if (options.editor_show) {
|
||||
ImGui::Begin("Editor", &options.editor_show, ImGuiWindowFlags_AlwaysAutoResize);
|
||||
if (state.look_at.has_value()) {
|
||||
ImGui::Text("Look at: (%lld, %lld, %lld) (%s, %.1f)", state.look_at.value().first.x, state.look_at.value().first.y, state.look_at.value().first.z, world::materials::textures[state.look_at.value().second.material()].c_str(), state.look_at.value().second.density() * 1. / world::Voxel::DENSITY_MAX);
|
||||
ImGui::Text("(%.3f, %.3f, %.3f)", state.look_at.value().first.x * 1. / options.voxel_density, state.look_at.value().first.y * 1. / options.voxel_density, state.look_at.value().first.z * 1. / options.voxel_density);
|
||||
ImGui::Text("Look at: (%ld: %lld, %lld, %lld) (%s, %.1f)", state.look_at.value().first.first, state.look_at.value().first.second.x, state.look_at.value().first.second.y, state.look_at.value().first.second.z, world::materials::textures[state.look_at.value().second.material()].c_str(), state.look_at.value().second.density() * 1. / world::Voxel::DENSITY_MAX);
|
||||
ImGui::Text("(%.3f, %.3f, %.3f)", state.look_at.value().first.second.x * 1. / options.voxel_density, state.look_at.value().first.second.y * 1. / options.voxel_density, state.look_at.value().first.second.z * 1. / options.voxel_density);
|
||||
} else {
|
||||
ImGui::Text("Look at: none");
|
||||
}
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
#define MIN_WIDTH 854
|
||||
#define MIN_HEIGHT 480
|
||||
|
||||
void framebuffer_size_callback(GLFWwindow *window, int width, int height) {
|
||||
void framebuffer_size_callback(GLFWwindow *, int width, int height) {
|
||||
glViewport(0, 0, width, height);
|
||||
}
|
||||
|
||||
|
|
|
@ -181,7 +181,7 @@ struct options {
|
|||
struct state {
|
||||
bool capture_mouse = true;
|
||||
camera_pos position = camera_pos(voxel_pos(0), 1);
|
||||
std::optional<std::pair<voxel_pos, world::Voxel>> look_at = {};
|
||||
std::optional<std::pair<area_<voxel_pos>, world::Voxel>> look_at = {};
|
||||
|
||||
std::shared_ptr<contouring::Abstract> contouring;
|
||||
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
#include "Area.hpp"
|
||||
|
||||
#include "Chunk.hpp"
|
||||
|
||||
using namespace world;
|
||||
|
||||
std::optional<std::shared_ptr<Chunk>> ChunkContainer::findInRange(const chunk_pos &pos) const {
|
||||
const auto it = find(pos);
|
||||
return it != end() ? std::make_optional(it->second) : std::nullopt;
|
||||
}
|
||||
std::optional<std::shared_ptr<const Chunk>> ChunkContainer::findOrEmpty(const chunk_pos &pos) const {
|
||||
return inRange(pos) ? findInRange(pos) : std::make_optional(world::EMPTY_CHUNK);
|
||||
}
|
||||
|
||||
std::shared_ptr<Region> Area::getRegion(const std::string& folderPath, const area_<region_pos>& pos) {
|
||||
{ // Found
|
||||
const auto shared = regions.lock_shared();
|
||||
const auto it = shared->find(pos.second);
|
||||
if(it != shared->end())
|
||||
return it->second;
|
||||
}
|
||||
// Reading
|
||||
const auto reg = std::make_shared<Region>(folderPath, pos);
|
||||
const auto unique = regions.lock();
|
||||
return unique->insert({pos.second, reg}).first->second;
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
#pragma once
|
||||
|
||||
#include "forward.h"
|
||||
#include <shared_mutex_guarded.h>
|
||||
using namespace libguarded;
|
||||
#include "region/index.hpp"
|
||||
#include "Generator.hpp"
|
||||
|
||||
namespace world {
|
||||
/// Chunk map with restricted access
|
||||
struct ChunkContainer: robin_hood::unordered_map<chunk_pos, std::shared_ptr<Chunk>> {
|
||||
private:
|
||||
int radius;
|
||||
|
||||
public:
|
||||
ChunkContainer(int radius): radius(radius) {
|
||||
assert(radius < (1 << 22) / CHUNK_LENGTH);
|
||||
}
|
||||
inline bool inRange(const chunk_pos& pos) const {
|
||||
return glm::abs(pos.x) < radius && glm::abs(pos.y) < radius && glm::abs(pos.z) < radius;
|
||||
}
|
||||
std::optional<std::shared_ptr<Chunk>> findInRange(const chunk_pos &pos) const;
|
||||
std::optional<std::shared_ptr<const Chunk>> findOrEmpty(const chunk_pos &pos) const;
|
||||
};
|
||||
|
||||
/// Area (aka big group of chunks)
|
||||
struct Area {
|
||||
public:
|
||||
using regions_t = robin_hood::unordered_map<region_pos, std::shared_ptr<Region>>;
|
||||
|
||||
/// radius: size in chunk (length = radius * 2 + 1)
|
||||
Area(int radius, int seed = 42): chunks(radius), generator(seed) { }
|
||||
|
||||
inline const ChunkContainer &getChunks() const { return chunks; }
|
||||
inline ChunkContainer &setChunks() { return chunks; }
|
||||
std::shared_ptr<Region> getRegion(const std::string& folderPath, const area_<region_pos> &);
|
||||
shared_guarded<regions_t>::handle getRegions() { return regions.lock(); }
|
||||
inline Generator &getGenerator() { return generator; }
|
||||
|
||||
private:
|
||||
//TODO: position rotation
|
||||
ChunkContainer chunks;
|
||||
shared_guarded<regions_t> regions;
|
||||
|
||||
Generator generator;
|
||||
};
|
||||
}
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
#include "materials.hpp"
|
||||
#include <algorithm>
|
||||
#include "../data/math.hpp"
|
||||
|
||||
using namespace world;
|
||||
|
||||
|
@ -20,6 +21,7 @@ Chunk::Chunk(const chunk_pos& pos, Generator& rnd) {
|
|||
rnd.free(densitySet);
|
||||
rnd.free(materialSet);
|
||||
}
|
||||
#include <iostream>
|
||||
Chunk::Chunk(std::istream& str, bool rle) {
|
||||
if(rle) {
|
||||
ushort i = 0;
|
||||
|
@ -34,7 +36,7 @@ Chunk::Chunk(std::istream& str, bool rle) {
|
|||
i++;
|
||||
}
|
||||
}
|
||||
assert(("Mismatch data length", i == CHUNK_SIZE-1));
|
||||
assert(i == CHUNK_SIZE && "Mismatch data length");
|
||||
} else {
|
||||
for(auto& voxel: voxels) {
|
||||
str.read(reinterpret_cast<char *>(&voxel), sizeof(voxel));
|
||||
|
@ -49,7 +51,7 @@ void Chunk::write(std::ostream& str, bool rle) const {
|
|||
ushort counter = 1;
|
||||
Voxel current = *it;
|
||||
while(true) {
|
||||
it++;
|
||||
++it;
|
||||
const auto end = (it == voxels.end());
|
||||
if(end || current.value != it->value) {
|
||||
str.write(reinterpret_cast<char *>(&counter), sizeof(counter));
|
||||
|
@ -90,37 +92,37 @@ void Chunk::set(ushort idx, const Voxel& val) {
|
|||
((!getNeighborIdx(idx, Face::Backward).has_value()) & Faces::Backward));
|
||||
}
|
||||
|
||||
std::optional<ushort> Chunk::getNeighborIdx(ushort idx, Face dir) {
|
||||
std::optional<chunk_voxel_idx> Chunk::getNeighborIdx(chunk_voxel_idx idx, Face dir) {
|
||||
switch (dir) {
|
||||
case Face::Forward:
|
||||
if (idx % CHUNK_LENGTH >= CHUNK_LENGTH - 1)
|
||||
if (idx % glm::IDX_LENGTH >= glm::IDX_LENGTH - 1)
|
||||
return {};
|
||||
return idx + 1;
|
||||
|
||||
case Face::Backward:
|
||||
if (idx % CHUNK_LENGTH <= 0)
|
||||
if (idx % glm::IDX_LENGTH <= 0)
|
||||
return {};
|
||||
return idx - 1;
|
||||
|
||||
case Face::Up:
|
||||
if ((idx / CHUNK_LENGTH) % CHUNK_LENGTH >= CHUNK_LENGTH - 1)
|
||||
if ((idx / glm::IDX_LENGTH) % glm::IDX_LENGTH >= glm::IDX_LENGTH - 1)
|
||||
return {};
|
||||
return idx + CHUNK_LENGTH;
|
||||
return idx + glm::IDX_LENGTH;
|
||||
|
||||
case Face::Down:
|
||||
if ((idx / CHUNK_LENGTH) % CHUNK_LENGTH <= 0)
|
||||
if ((idx / glm::IDX_LENGTH) % glm::IDX_LENGTH <= 0)
|
||||
return {};
|
||||
return idx - CHUNK_LENGTH;
|
||||
return idx - glm::IDX_LENGTH;
|
||||
|
||||
case Face::Right:
|
||||
if (idx / CHUNK_LENGTH2 >= CHUNK_LENGTH - 1)
|
||||
if (idx / glm::IDX_LENGTH2 >= glm::IDX_LENGTH - 1)
|
||||
return {};
|
||||
return idx + CHUNK_LENGTH2;
|
||||
return idx + glm::IDX_LENGTH2;
|
||||
|
||||
case Face::Left:
|
||||
if (idx / CHUNK_LENGTH2 <= 0)
|
||||
if (idx / glm::IDX_LENGTH2 <= 0)
|
||||
return {};
|
||||
return idx - CHUNK_LENGTH2;
|
||||
return idx - glm::IDX_LENGTH2;
|
||||
|
||||
default:
|
||||
return {};
|
||||
|
|
|
@ -1,20 +1,23 @@
|
|||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <sstream>
|
||||
#include "Generator.hpp"
|
||||
#include "Voxel.hpp"
|
||||
#include "../data/geometry/Faces.hpp"
|
||||
#include <sstream>
|
||||
#include "../data/math.hpp"
|
||||
|
||||
/// Chunk length
|
||||
#define CHUNK_LENGTH2 (CHUNK_LENGTH * CHUNK_LENGTH)
|
||||
#define CHUNK_SIZE (CHUNK_LENGTH2 * CHUNK_LENGTH)
|
||||
|
||||
namespace world {
|
||||
const auto CHUNK_LENGTH2 = CHUNK_LENGTH * CHUNK_LENGTH;
|
||||
const auto CHUNK_SIZE = CHUNK_LENGTH2 * CHUNK_LENGTH;
|
||||
|
||||
constexpr auto RLE = true; //NOTE: only 2.7% gain after zstd
|
||||
using namespace geometry;
|
||||
/// World part as linear 3d voxel array
|
||||
class Chunk {
|
||||
public:
|
||||
Chunk() {}
|
||||
Chunk(const chunk_pos& pos, Generator& rnd);
|
||||
Chunk(std::istream& str, bool rle = RLE);
|
||||
~Chunk();
|
||||
|
@ -30,41 +33,31 @@ namespace world {
|
|||
modified = true;
|
||||
}
|
||||
// Get voxel from index
|
||||
inline const Voxel& get(ushort idx) const {
|
||||
inline const Voxel& get(chunk_voxel_idx idx) const {
|
||||
return voxels[idx];
|
||||
}
|
||||
// Get voxel from position
|
||||
inline const Voxel& getAt(const chunk_voxel_pos& pos) const {
|
||||
return get(getIdx(pos));
|
||||
return get(glm::toIdx(pos));
|
||||
}
|
||||
// Set voxel from index
|
||||
void set(ushort idx, const Voxel& val);
|
||||
void set(chunk_voxel_idx idx, const Voxel& val);
|
||||
// Set voxel from position
|
||||
void setAt(const chunk_voxel_pos& pos, const Voxel& val) {
|
||||
set(getIdx(pos), val);
|
||||
set(glm::toIdx(pos), val);
|
||||
}
|
||||
// Break voxel
|
||||
Item breakAt(const chunk_voxel_pos& pos, const Voxel& val) {
|
||||
const auto idx = getIdx(pos);
|
||||
std::optional<Item> replace(chunk_voxel_idx idx, const Voxel& val) {
|
||||
const auto res = voxels[idx];
|
||||
set(idx, val);
|
||||
return Item{res.density(), res.material()};
|
||||
return {Item{res.density(), res.material()}}; //TODO: materials break table
|
||||
}
|
||||
// Is player modified
|
||||
inline bool isModified() const { return modified; }
|
||||
// Write to file.
|
||||
void write(std::ostream& str, bool rle = RLE) const;
|
||||
|
||||
static inline chunk_voxel_pos getPosition(ushort idx) {
|
||||
return chunk_voxel_pos(idx / CHUNK_LENGTH2, (idx / CHUNK_LENGTH) % CHUNK_LENGTH, idx % CHUNK_LENGTH);
|
||||
}
|
||||
static inline ushort getIdx(chunk_voxel_pos pos) {
|
||||
return getIdx(pos.x, pos.y, pos.z);
|
||||
}
|
||||
static inline ushort getIdx(uint x, uint y, uint z) {
|
||||
return (x * CHUNK_LENGTH + y) * CHUNK_LENGTH + z;
|
||||
}
|
||||
static std::optional<ushort> getNeighborIdx(ushort idx, Face dir);
|
||||
static std::optional<chunk_voxel_idx> getNeighborIdx(chunk_voxel_idx idx, Face dir);
|
||||
|
||||
private:
|
||||
/// Chunk data
|
||||
|
@ -76,4 +69,7 @@ namespace world {
|
|||
/// Modified by player
|
||||
bool modified = false;
|
||||
};
|
||||
|
||||
/// Chunk full of air
|
||||
static const std::shared_ptr<const Chunk> EMPTY_CHUNK = std::make_shared<Chunk>();
|
||||
}
|
||||
|
|
|
@ -8,7 +8,9 @@
|
|||
|
||||
using namespace world;
|
||||
|
||||
Universe::Universe(const Universe::options &options): generator(42), dicts("content/zstd.dict"), contouring(std::make_shared<contouring::Dummy>()) {
|
||||
const auto MAIN_AREA = 1;
|
||||
|
||||
Universe::Universe(const Universe::options &options): dicts("content/zstd.dict"), contouring(std::make_shared<contouring::Dummy>()) {
|
||||
setOptions(options);
|
||||
folderPath = options.folderPath;
|
||||
struct vec_istream: std::streambuf {
|
||||
|
@ -17,30 +19,33 @@ Universe::Universe(const Universe::options &options): generator(42), dicts("cont
|
|||
}
|
||||
};
|
||||
running = true;
|
||||
|
||||
std::filesystem::create_directories(folderPath);
|
||||
areas.emplace(MAIN_AREA, std::make_shared<Area>(1 << 2));
|
||||
areas.emplace(2, std::make_shared<Area>(1 << 2, 43));
|
||||
|
||||
// Load workers
|
||||
for (size_t i = 0; i < 4; i++) {
|
||||
loadWorkers.emplace_back([&] {
|
||||
const auto ctx = dicts.make_reader();
|
||||
while (running) {
|
||||
chunk_pos pos;
|
||||
std::pair<area_<chunk_pos>, std::shared_ptr<Area>> task;
|
||||
loadQueue.wait();
|
||||
if (loadQueue.pop(pos)) {
|
||||
if (loadQueue.pop(task)) {
|
||||
//MAYBE: loadQueue.take to avoid duplicated work on fast move
|
||||
rmt_ScopedCPUSample(ProcessLoad, 0);
|
||||
const region_pos rPos = glm::divide(pos, region_chunk_pos(REGION_LENGTH));
|
||||
const region_chunk_pos cPos = glm::modulo(pos, region_chunk_pos(REGION_LENGTH));
|
||||
const auto reg = getRegion(rPos);
|
||||
const auto &pos = task.first;
|
||||
const auto rcPos = glm::split(pos.second);
|
||||
const auto reg = task.second->getRegion(folderPath, std::make_pair(pos.first, rcPos.first));
|
||||
Region::data data;
|
||||
if(reg->read(cPos, ctx, data)) {
|
||||
if(reg->read(rcPos.second, ctx, data)) {
|
||||
rmt_ScopedCPUSample(ProcessRead, 0);
|
||||
vec_istream idata(data);
|
||||
std::istream iss(&idata);
|
||||
loadedQueue.push({pos, std::make_shared<Chunk>(iss)});
|
||||
} else {
|
||||
rmt_ScopedCPUSample(ProcessGenerate, 0);
|
||||
loadedQueue.push({pos, std::make_shared<Chunk>(pos, generator)});
|
||||
loadedQueue.push({pos, std::make_shared<Chunk>(pos.second, task.second->getGenerator())});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -52,17 +57,16 @@ Universe::Universe(const Universe::options &options): generator(42), dicts("cont
|
|||
saveWorkers.emplace_back([&] {
|
||||
const auto ctx = dicts.make_writer();
|
||||
while (running) {
|
||||
robin_hood::pair<chunk_pos, std::shared_ptr<Chunk>> task;
|
||||
save_task_t task;
|
||||
saveQueue.wait();
|
||||
if (saveQueue.pop(task) && task.second->isModified()) {
|
||||
if (saveQueue.pop(task) && task.second.second->isModified()) {
|
||||
//MAYBE: queue.take to avoid concurent write or duplicated work on fast move
|
||||
rmt_ScopedCPUSample(ProcessSave, 0);
|
||||
std::ostringstream out;
|
||||
task.second->write(out);
|
||||
const region_pos rPos = glm::divide(task.first, region_chunk_pos(REGION_LENGTH));
|
||||
const region_chunk_pos cPos = glm::modulo(task.first, region_chunk_pos(REGION_LENGTH));
|
||||
const auto reg = getRegion(rPos);
|
||||
reg->write(cPos, ctx, out.str());
|
||||
task.second.second->write(out);
|
||||
const auto rcPos = glm::split(task.second.first);
|
||||
const auto reg = task.first.second->getRegion(folderPath, std::make_pair(task.first.first, rcPos.first));
|
||||
reg->write(rcPos.second, ctx, out.str());
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -72,8 +76,9 @@ Universe::~Universe() {
|
|||
contouring = NULL;
|
||||
|
||||
// Save all
|
||||
for(auto& pair: chunks) {
|
||||
saveQueue.push(pair);
|
||||
for(auto& area: areas) {
|
||||
for(auto& chunk: area.second->getChunks())
|
||||
saveQueue.emplace(area, chunk);
|
||||
}
|
||||
if (auto size = saveQueue.size(); size > 0) {
|
||||
std::cout << std::endl;
|
||||
|
@ -99,88 +104,103 @@ Universe::~Universe() {
|
|||
}
|
||||
}
|
||||
|
||||
std::shared_ptr<Region> Universe::getRegion(const region_pos& pos) {
|
||||
{ // Found
|
||||
const auto shared = regions.lock_shared();
|
||||
const auto it = shared->find(pos);
|
||||
if(it != shared->end())
|
||||
return it->second;
|
||||
}
|
||||
// Reading
|
||||
const auto reg = std::make_shared<Region>(folderPath, pos);
|
||||
const auto unique = regions.lock();
|
||||
return unique->insert({pos, reg}).first->second;
|
||||
}
|
||||
|
||||
void Universe::update(const voxel_pos& pos, Universe::report& rep) {
|
||||
const chunk_pos newPos = glm::divide(pos, chunk_voxel_pos(CHUNK_LENGTH));
|
||||
const chunk_pos newPos = glm::divide(pos);
|
||||
const auto chunkChange = last_pos != newPos;
|
||||
last_pos = newPos;
|
||||
rmt_ScopedCPUSample(Universe, 0);
|
||||
|
||||
// Update alive chunks
|
||||
// Update alive areas
|
||||
{
|
||||
rmt_ScopedCPUSample(Update, 0);
|
||||
auto it = chunks.begin();
|
||||
while (it != chunks.end()) {
|
||||
if (glm::length2(last_pos - it->first) > keepDistance * keepDistance) {
|
||||
saveQueue.push(*it);
|
||||
it = chunks.erase(it);
|
||||
size_t chunk_count = 0;
|
||||
auto it = areas.begin();
|
||||
while (it != areas.end()) {
|
||||
auto diff = last_pos /*TODO: - it->second.position*/;
|
||||
auto &chunks = it->second->setChunks();
|
||||
if (glm::length2(diff) /*TODO: - it->second.radius * radius * CHUNK_SIZE * CHUNK_SIZE */ > keepDistance * keepDistance) {
|
||||
auto it_c = chunks.begin();
|
||||
while(it_c != chunks.end()) {
|
||||
saveQueue.emplace(*it, *it_c);
|
||||
it_c = chunks.erase(it_c);
|
||||
}
|
||||
it = areas.erase(it);
|
||||
} else {
|
||||
if (const auto neighbors = it->second->update()) {
|
||||
contouring->onUpdate(it->first, chunks, neighbors.value()); //TODO: get update update_type(simple(pos), complex)
|
||||
} else if (chunkChange) {
|
||||
contouring->onNotify(it->first, chunks);
|
||||
auto it_c = chunks.begin();
|
||||
while(it_c != chunks.end()) { // Update alive chunks
|
||||
if (glm::length2(diff - it_c->first) > keepDistance * keepDistance) {
|
||||
saveQueue.emplace(*it, *it_c);
|
||||
it_c = chunks.erase(it_c);
|
||||
}else {
|
||||
const auto acPos = std::make_pair(it->first, it_c->first);
|
||||
if (const auto neighbors = it_c->second->update()) {
|
||||
contouring->onUpdate(acPos, chunks, neighbors.value()); //TODO: it->second.position
|
||||
} else if (chunkChange) {
|
||||
contouring->onNotify(acPos, chunks); //TODO: it->second.position
|
||||
}
|
||||
++it_c;
|
||||
chunk_count++;
|
||||
}
|
||||
}
|
||||
++it;
|
||||
}
|
||||
}
|
||||
rep.chunk_count.push(chunk_count);
|
||||
}
|
||||
rep.chunk_unload.push(saveQueue.size());
|
||||
{
|
||||
rmt_ScopedCPUSample(Contouring, 0);
|
||||
contouring->update(pos);
|
||||
contouring->update(pos, areas);
|
||||
//MAYBE: if(chunkChange) contouring->notify(chunks);
|
||||
}
|
||||
|
||||
// Find missing chunks
|
||||
if(chunkChange) {
|
||||
rmt_ScopedCPUSample(ToLoad, 0);
|
||||
//NOTE: need dist so no easy sphere fill
|
||||
for (int x = -loadDistance; x <= loadDistance; x++) {
|
||||
for (int y = -loadDistance; y <= loadDistance; y++) {
|
||||
for (int z = -loadDistance; z <= loadDistance; z++) {
|
||||
const auto dist2 = x * x + y * y + z * z;
|
||||
if (dist2 <= loadDistance * loadDistance) {
|
||||
const auto p = last_pos + chunk_pos(x, y, z);
|
||||
if (chunks.find(p) == chunks.end()) {
|
||||
loadQueue.push(p, -dist2);
|
||||
//TODO: for(auto& far: far_areas)
|
||||
|
||||
for(auto& area: areas) {
|
||||
//NOTE: need dist so no easy sphere fill
|
||||
auto& chunks = area.second->getChunks();
|
||||
for (int x = -loadDistance; x <= loadDistance; x++) {
|
||||
for (int y = -loadDistance; y <= loadDistance; y++) {
|
||||
for (int z = -loadDistance; z <= loadDistance; z++) {
|
||||
const auto dist2 = x * x + y * y + z * z;
|
||||
if (dist2 <= loadDistance * loadDistance) {
|
||||
const auto p = last_pos + chunk_pos(x, y, z) /*TODO: + area.second->getPosition() */;
|
||||
if (chunks.inRange(p) && chunks.find(p) == chunks.end()) {
|
||||
loadQueue.push(std::make_pair(area.first, p), area.second, -dist2);
|
||||
}
|
||||
}
|
||||
}
|
||||
}}}
|
||||
}}}
|
||||
}
|
||||
}
|
||||
|
||||
rep.chunk_load.push(loadQueue.size());
|
||||
// Loaded chunks
|
||||
// Store loaded chunks
|
||||
{
|
||||
rmt_ScopedCPUSample(Load, 0);
|
||||
robin_hood::pair<chunk_pos, std::shared_ptr<Chunk>> loaded;
|
||||
robin_hood::pair<area_<chunk_pos>, std::shared_ptr<Chunk>> loaded;
|
||||
while (loadedQueue.pop(loaded)) {
|
||||
chunks.insert(loaded);
|
||||
contouring->onUpdate(loaded.first, chunks, Faces::All);
|
||||
if (const auto it = areas.find(loaded.first.first); it != areas.end()) {
|
||||
auto &chunks = it->second->setChunks();
|
||||
chunks.emplace(loaded.first.second, loaded.second);
|
||||
contouring->onUpdate(loaded.first, chunks, Faces::All);
|
||||
}
|
||||
}
|
||||
}
|
||||
rep.chunk_count.push(chunks.size());
|
||||
|
||||
if(!rep.chunk_load.current() && !rep.chunk_unload.current()) {
|
||||
rmt_ScopedCPUSample(Region, 0);
|
||||
const auto unique = regions.lock(); // MAYBE: shared then unique
|
||||
rep.region_count.push(unique->size());
|
||||
const auto me = glm::divide(last_pos, glm::uvec3(REGION_LENGTH));
|
||||
for (auto it = unique->begin(); it != unique->end(); it++) {
|
||||
if (glm::length2(glm::lvec3(it->first) - me) > keepDistance) { //FIXME: probably a limit
|
||||
unique->erase(it);
|
||||
break; //NOTE: save one max per frame
|
||||
for(auto& area: areas) {
|
||||
const auto unique = area.second->getRegions(); // MAYBE: shared then unique
|
||||
rep.region_count.push(unique->size());
|
||||
const auto me = glm::divide(last_pos /*TODO: + position*/);
|
||||
for (auto it = unique->begin(); it != unique->end(); ++it) {
|
||||
if (glm::length2(glm::lvec3(it->first) - me) > keepDistance) { //FIXME: keepDistance^1 may suck with high values
|
||||
unique->erase(it);
|
||||
break; //NOTE: save one max per frame
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -195,43 +215,63 @@ void Universe::setContouring(const std::shared_ptr<contouring::Abstract>& ct) {
|
|||
last_pos = chunk_pos(INT_MAX); // trigger chunkChange on next update
|
||||
}
|
||||
|
||||
std::optional<std::pair<voxel_pos, Voxel>> Universe::raycast(const Ray &ray) const {
|
||||
std::optional<std::pair<area_<voxel_pos>, Voxel>> Universe::raycast(const Ray &ray) const {
|
||||
std::vector<voxel_pos> points;
|
||||
ray.grid(points);
|
||||
std::shared_ptr<Chunk> chunk = NULL;
|
||||
chunk_pos chunk_vec(INT_MAX);
|
||||
for(auto point: points) {
|
||||
const chunk_pos pos = glm::divide(point, glm::uvec3(CHUNK_LENGTH));
|
||||
if(pos != chunk_vec) {
|
||||
if(const auto& newChunk = at(pos)) {
|
||||
chunk = newChunk.value();
|
||||
chunk_vec = pos;
|
||||
std::optional<std::pair<area_<voxel_pos>, Voxel>> target = std::nullopt;
|
||||
size_t dist = points.size();
|
||||
for(auto& area: areas) {
|
||||
//TODO: if ray.insert(area.getIBox())
|
||||
const auto &chunks = area.second->getChunks();
|
||||
std::shared_ptr<Chunk> chunk = NULL;
|
||||
chunk_pos chunk_vec(INT_MAX);
|
||||
for (size_t i = 0; i < dist; i++) {
|
||||
const auto pos = points[i] /*TODO: + area.position*/;
|
||||
const chunk_pos cPos = glm::divide(pos);
|
||||
if(cPos != chunk_vec) {
|
||||
if (const auto it = chunks.find(cPos); it != chunks.end()) {
|
||||
chunk = it->second;
|
||||
chunk_vec = cPos;
|
||||
} else {
|
||||
chunk = NULL;
|
||||
}
|
||||
}
|
||||
if(chunk != NULL) {
|
||||
const auto voxel = chunk->getAt(glm::modulo(pos));
|
||||
if(voxel.density() > 0) {
|
||||
target = {{{area.first, pos}, voxel}};
|
||||
dist = i;
|
||||
i = points.size();
|
||||
}
|
||||
}
|
||||
}
|
||||
if(chunk != NULL) {
|
||||
const auto voxel = chunk->getAt(glm::modulo(point, glm::uvec3(CHUNK_LENGTH)));
|
||||
if(voxel.density() > 0)
|
||||
return {{point, voxel}};
|
||||
}
|
||||
}
|
||||
return target;
|
||||
}
|
||||
|
||||
std::optional<Item> Universe::set(const area_<voxel_pos>& pos, const Voxel& val) {
|
||||
if(const auto it = areas.find(pos.first); it != areas.end()) {
|
||||
auto &chunks = it->second->setChunks();
|
||||
const auto split = glm::splitIdx(pos.second);
|
||||
if(chunks.inRange(split.first))
|
||||
if(const auto chunk = chunks.findInRange(split.first))
|
||||
return {chunk.value()->replace(split.second, val)};
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
std::optional<Item> Universe::set(const voxel_pos& pos, const Voxel& val) {
|
||||
const auto chunkPos = glm::divide(pos, glm::uvec3(CHUNK_LENGTH));
|
||||
if(const auto& chunk = at(chunkPos)) {
|
||||
return {chunk.value()->breakAt(glm::modulo(pos, glm::uvec3(CHUNK_LENGTH)), val)};
|
||||
} else {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
ItemList Universe::setCube(const voxel_pos& pos, const Voxel& val, int radius) {
|
||||
ItemList Universe::setCube(const area_<voxel_pos>& pos, const Voxel& val, int radius) {
|
||||
ItemList list;
|
||||
for (int z = -radius; z <= radius; z++) {
|
||||
for (int y = -radius; y <= radius; y++) {
|
||||
for (int x = -radius; x <= radius; x++) {
|
||||
//TODO: list.pop(val)
|
||||
list.add(set(pos + glm::llvec3(x, y, z), val));
|
||||
}}}
|
||||
if(const auto it = areas.find(pos.first); it != areas.end()) {
|
||||
auto& chunks = it->second->setChunks();
|
||||
for (int z = -radius; z <= radius; z++) {
|
||||
for (int y = -radius; y <= radius; y++) {
|
||||
for (int x = -radius; x <= radius; x++) {
|
||||
//TODO: list.pop(val)
|
||||
const auto split = glm::splitIdx(pos.second + voxel_pos(x, y, z));
|
||||
if(chunks.inRange(split.first))
|
||||
if(const auto chunk = it->second->setChunks().findInRange(split.first))
|
||||
list.add(chunk.value()->replace(split.second, val));
|
||||
}}}
|
||||
}
|
||||
return list;
|
||||
}
|
|
@ -2,17 +2,14 @@
|
|||
|
||||
#include <string>
|
||||
#include <thread>
|
||||
#include <shared_mutex_guarded.h>
|
||||
using namespace libguarded;
|
||||
#include "../data/math.hpp"
|
||||
#include "../data/safe_queue.hpp"
|
||||
#include "../data/safe_priority_queue.hpp"
|
||||
#include "../data/circular_buffer.hpp"
|
||||
#include "../data/geometry/Ray.hpp"
|
||||
#include "forward.h"
|
||||
#include "Area.hpp"
|
||||
#include "Voxel.hpp"
|
||||
#include "region/index.hpp"
|
||||
#include "Generator.hpp"
|
||||
|
||||
#define REPORT_BUFFER_SIZE 128
|
||||
|
||||
|
@ -57,11 +54,12 @@ namespace world {
|
|||
|
||||
/// Get nearest voxel colliding ray
|
||||
/// @note ray in world scale
|
||||
std::optional<std::pair<voxel_pos, Voxel>> raycast(const geometry::Ray &ray) const;
|
||||
std::optional<std::pair<area_<voxel_pos>, Voxel>> raycast(const geometry::Ray &ray) const;
|
||||
/// Set voxel at pos
|
||||
std::optional<Item> set(const voxel_pos &pos, const Voxel &val);
|
||||
std::optional<Item> set(const area_<voxel_pos> &pos, const Voxel &val);
|
||||
/// Set cube of voxel with pos as center
|
||||
ItemList setCube(const voxel_pos &pos, const Voxel &val, int radius);
|
||||
/// MAYBE: allow set multi area
|
||||
ItemList setCube(const area_<voxel_pos> &pos, const Voxel &val, int radius);
|
||||
|
||||
/// Change contouring worker
|
||||
void setContouring(const std::shared_ptr<contouring::Abstract>& ct);
|
||||
|
@ -73,33 +71,26 @@ namespace world {
|
|||
private:
|
||||
chunk_pos last_pos = chunk_pos(INT_MAX);
|
||||
|
||||
/// Data
|
||||
chunk_map chunks;
|
||||
/// Alive areas containing chunks
|
||||
area_map areas;
|
||||
using area_it_t = robin_hood::pair<area_id, std::shared_ptr<Area>>;
|
||||
|
||||
std::optional<std::shared_ptr<Chunk>> at(const chunk_pos& pos) const {
|
||||
const auto it = chunks.find(pos);
|
||||
if(it == chunks.end())
|
||||
return {};
|
||||
return {it->second};
|
||||
}
|
||||
|
||||
Generator generator;
|
||||
//TODO: far_areas: <pos, {id, size, seed}>
|
||||
|
||||
bool running = true;
|
||||
std::vector<std::thread> loadWorkers;
|
||||
safe_priority_queue<chunk_pos, int> loadQueue;
|
||||
safe_queue<robin_hood::pair<chunk_pos, std::shared_ptr<Chunk>>> loadedQueue;
|
||||
safe_priority_queue_map<area_<chunk_pos>, std::shared_ptr<Area>, int, area_hash> loadQueue;
|
||||
safe_queue<robin_hood::pair<area_<chunk_pos>, std::shared_ptr<Chunk>>> loadedQueue;
|
||||
|
||||
std::vector<std::thread> saveWorkers;
|
||||
safe_queue<robin_hood::pair<chunk_pos, std::shared_ptr<Chunk>>> saveQueue; //NOTE: consider const Chunk
|
||||
using save_task_t = std::pair<area_it_t, robin_hood::pair<chunk_pos, std::shared_ptr<Chunk>>>;
|
||||
data::safe_queue<save_task_t> saveQueue; //NOTE: consider const Area and Chunk
|
||||
|
||||
int loadDistance;
|
||||
int keepDistance;
|
||||
std::string folderPath;
|
||||
|
||||
shared_guarded<robin_hood::unordered_map<region_pos, std::shared_ptr<Region>>> regions;
|
||||
dict_set dicts;
|
||||
std::shared_ptr<Region> getRegion(const region_pos &);
|
||||
|
||||
/// Contouring worker
|
||||
std::shared_ptr<contouring::Abstract> contouring;
|
||||
|
|
|
@ -1,9 +1,12 @@
|
|||
#pragma once
|
||||
|
||||
#include "../data/safe_queue.hpp"
|
||||
#include <robin_hood.h>
|
||||
#include "position.h"
|
||||
|
||||
namespace world {
|
||||
class Chunk;
|
||||
typedef robin_hood::unordered_map<chunk_pos, std::shared_ptr<Chunk>> chunk_map;
|
||||
class Area;
|
||||
using area_map = robin_hood::unordered_map<area_id, std::shared_ptr<Area>>;
|
||||
class ChunkContainer;
|
||||
}
|
|
@ -1,7 +1,9 @@
|
|||
/**
|
||||
* chunk_voxel_pos: u8 (contains CHUNK_LENGTH)
|
||||
* chunk_voxel_pos: u8 (contains u5: CHUNK_LENGTH)
|
||||
* chunk_voxel_idx: u16
|
||||
* chunk_pos: i56
|
||||
* region_chunk_pos: u8 (contains REGION_LENGTH)
|
||||
* region_chunk_pos: u8 (contains u5: REGION_LENGTH)
|
||||
* region_chunk_idx: u16
|
||||
* region_pos: i48 (NOTE: trimmed to i32)
|
||||
* voxel_pos: i64
|
||||
*
|
||||
|
@ -17,16 +19,33 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <functional>
|
||||
#include "../data/glm.hpp"
|
||||
|
||||
const auto CHUNK_LENGTH = 32;
|
||||
const auto REGION_LENGTH = 32;
|
||||
const auto CHUNK_LENGTH = glm::IDX_LENGTH;
|
||||
const auto REGION_LENGTH = glm::IDX_LENGTH;
|
||||
|
||||
using voxel_pos = glm::llvec3;
|
||||
using chunk_pos = glm::lvec3;
|
||||
using chunk_voxel_pos = glm::ucvec3;
|
||||
using chunk_voxel_idx = glm::u16;
|
||||
using region_pos = glm::ivec3;
|
||||
using region_chunk_pos = glm::ucvec3;
|
||||
using region_chunk_idx = glm::u16;
|
||||
|
||||
using area_id = uint64_t;
|
||||
template <class pos>
|
||||
using area_ = std::pair<area_id, pos>;
|
||||
struct area_hash {
|
||||
template <typename pos>
|
||||
std::size_t operator()(area_<pos> const& a) const noexcept {
|
||||
std::size_t h1 = std::hash<area_id>{}(a.first);
|
||||
std::size_t h2 = std::hash<pos>{}(a.second);
|
||||
return h1 ^ (h2 << 1);
|
||||
}
|
||||
};
|
||||
using entity_id = uint64_t;
|
||||
|
||||
struct camera_pos {
|
||||
using raw_t = region_pos;
|
||||
using offset_t = glm::vec3;
|
||||
|
|
|
@ -6,9 +6,9 @@ using namespace world;
|
|||
|
||||
#define REMOVE_CORRUPTED 1
|
||||
|
||||
FileRegion::FileRegion(const std::string &folderPath, const region_pos &pos) {
|
||||
path = folderPath + '/' + std::to_string(pos.x) + '.' +
|
||||
std::to_string(pos.y) + '.' + std::to_string(pos.z) + ".map";
|
||||
FileRegion::FileRegion(const std::string &folderPath, const area_<region_pos> &pos) {
|
||||
path = folderPath + '/' + std::to_string(pos.first) + '.' + std::to_string(pos.second.x) + '.' +
|
||||
std::to_string(pos.second.y) + '.' + std::to_string(pos.second.z) + ".map";
|
||||
|
||||
load();
|
||||
}
|
||||
|
|
|
@ -11,7 +11,7 @@ namespace world {
|
|||
///Group of chunks saved as a single file only pointer
|
||||
class FileRegion {
|
||||
public:
|
||||
FileRegion(const std::string& folderPath, const region_pos &pos);
|
||||
FileRegion(const std::string& folderPath, const area_<region_pos> &pos);
|
||||
~FileRegion();
|
||||
|
||||
typedef std::vector<char> data;
|
||||
|
|
|
@ -5,9 +5,9 @@ using namespace world;
|
|||
#define REMOVE_CORRUPTED 1
|
||||
#define LAZYNESS 8
|
||||
|
||||
MemoryRegion::MemoryRegion(const std::string &folderPath, const region_pos &pos) {
|
||||
path = folderPath + '/' + std::to_string(pos.x) + '.' +
|
||||
std::to_string(pos.y) + '.' + std::to_string(pos.z) + ".map";
|
||||
MemoryRegion::MemoryRegion(const std::string &folderPath, const area_<region_pos> &pos) {
|
||||
path = folderPath + '/' + std::to_string(pos.first) + '.' + std::to_string(pos.second.x) + '.' +
|
||||
std::to_string(pos.second.y) + '.' + std::to_string(pos.second.z) + ".map";
|
||||
|
||||
load();
|
||||
}
|
||||
|
|
|
@ -12,7 +12,7 @@ namespace world {
|
|||
///Group of chunks saved as a single file in memory
|
||||
class MemoryRegion {
|
||||
public:
|
||||
MemoryRegion(const std::string& folderPath, const region_pos &pos);
|
||||
MemoryRegion(const std::string& folderPath, const area_<region_pos> &pos);
|
||||
~MemoryRegion();
|
||||
|
||||
typedef std::vector<char> data;
|
||||
|
|
Loading…
Reference in New Issue