#include "World.hpp" #include "../contouring/SurrondingFlatBox.hpp" #include "../render/buffer/ShortIndexedBuffer.hpp" #include World::World(const World::options& options) { setOptions(options); } World::~World() { } void World::update(const camera_pos& pos, World::report& rep) { const chunk_pos newPos = glm::divide(pos, chunk_voxel_pos(CHUNK_LENGTH)); const auto chunkChange = newPos != last_pos; last_pos = newPos; rmt_ScopedCPUSample(World, 0); // Update alive chunks { rmt_ScopedCPUSample(Update, 0); for(auto [chunkPos, chunk]: chunks) { const glm::ivec3 dist = last_pos - chunkPos; if (dist.x * dist.x + dist.y * dist.y + dist.z * dist.z > keepDistance * keepDistance && unloadQueue.push(chunkPos)) { //TODO: unloadCount++; continue; } if (chunk->update()) { // MAYBE: update joints //TODO: extract in contouring contouring::surrounding::chunks surrounding; surrounding[contouring::surrounding::CENTER] = chunk; bool all_found = true; for (size_t i = 0; all_found && i < contouring::surrounding::CENTER; i++) { const auto it = chunks.find(chunkPos + g_face_offsets[i]); if (it != chunks.end()) surrounding[i] = it->second; else all_found = false; } if(all_found) { rmt_ScopedCPUSample(Render, 0); if (chunk->buffer != NULL) delete chunk->buffer; std::vector vertices; { rmt_ScopedCPUSample(Contouring, 0); SurrondingFlatBox::render(surrounding, vertices); } ShortIndexedBuffer::Data data(vertices); // NOTE: indexing is really slow { rmt_ScopedCPUSample(Uploading, 0); chunk->buffer = new ShortIndexedBuffer(GL_TRIANGLES, data); } } } } } rep.chunk_unload.push(unloadQueue.size()); // Unload dead chunks { rmt_ScopedCPUSample(Unload, 0); for (size_t i = 0; i < 8 && !unloadQueue.empty(); i++) { chunks.extract(unloadQueue.pop()); //TODO: save to file } } // Find missing chunks (~240ms from max loadDistance) if(chunkChange) { rmt_ScopedCPUSample(ToLoad, 0); std::vector to_load; for (int x = -loadDistance; x <= loadDistance; x++) { for (int y = -loadDistance; y <= loadDistance; y++) { for (int z = -loadDistance; z <= loadDistance; z++) { if (x * x + y * y + z * z <= loadDistance * loadDistance) { const chunk_pos p = last_pos + glm::ivec3(x, y, z); if (chunks.find(p) == chunks.end()) { to_load.push_back(p); } } }}} std::sort(to_load.begin(), to_load.end(), [](const chunk_pos &a, const chunk_pos &b) { return glm::length2(a) < glm::length2(b); }); for(auto p: to_load) { loadQueue.push(p); } } rep.chunk_load.push(loadQueue.size()); // Load chunks { rmt_ScopedCPUSample(Load, 0); for (size_t i = 0; i < 8 && !loadQueue.empty(); i++) { const auto pos = loadQueue.pop(); const auto chunk = std::make_shared(pos, generator); chunks.insert({pos, chunk}); //trigger surronding render for (size_t i = 0; i < contouring::surrounding::CENTER; i++) { const auto it = chunks.find(pos + g_face_offsets[i]); if (it != chunks.end()) it->second->invalidate(); } } } rep.chunk_count.push(chunks.size()); } void World::setOptions(const World::options& options) { loadDistance = options.loadDistance; keepDistance = options.keepDistance; } void World::getModels(std::vector> &out, float scale) const { const auto scaling = glm::scale(glm::mat4(1), glm::vec3(scale)); for(const auto [pos, chunk]: chunks) { if(chunk->buffer != NULL) out.push_back({glm::translate(scaling, glm::vec3(pos) * glm::vec3(CHUNK_LENGTH)), chunk->buffer}); } } void World::getModels(std::vector> &out, float scale, const Frustum& frustum) const { const auto scaling = glm::scale(glm::mat4(1), glm::vec3(scale)); for(const auto [pos, chunk]: chunks) { if(chunk->buffer != NULL && frustum.contains(Box::fromMin(scale * glm::vec3(pos) * glm::vec3(CHUNK_LENGTH), scale * glm::vec3(CHUNK_LENGTH)))) out.push_back({glm::translate(scaling, glm::vec3(pos) * glm::vec3(CHUNK_LENGTH)), chunk->buffer}); } }