#include "World.hpp" namespace MC::World { std::vector World::get_visible_chunks(Vector<3> position) { auto visible_chunks = get_visible_chunk_indices(position); auto difference = visible_chunks; for (auto index : m_visible_chunks) { difference.erase(index); } if (!difference.empty()) { for (auto new_index: difference) { auto& data = get_or_generate(new_index); if (!data.mesh.has_value()) { auto mesh = data.chunk->mesh(); data.mesh = GFX::Binder::load(mesh); } } m_visible_chunks = visible_chunks; } std::vector chunks{}; chunks.reserve(visible_chunks.size()); for (auto index : visible_chunks) { chunks.push_back(get_or_generate(index)); } return chunks; } std::unordered_set World::get_visible_chunk_indices(Vector<3> position) const { int32_t center_x = std::round(position.x() / CHUNK_WIDTH); int32_t center_y = std::round(position.z() / CHUNK_HEIGHT); auto upper_x_bound = center_x + m_view_distance_radius; auto lower_x_bound = center_x - m_view_distance_radius; auto upper_y_bound = center_y + m_view_distance_radius; auto lower_y_bound = center_y - m_view_distance_radius; std::unordered_set indices{}; indices.reserve(m_view_distance_radius * m_view_distance_radius * 4); for (int32_t x = lower_x_bound; x < upper_x_bound; x++) { for (int32_t y = lower_y_bound; y < upper_y_bound; y++) { indices.emplace(x, y); } } return indices; } World::ChunkData& World::get_or_generate(ChunkIndex index) { auto entry = m_chunks.find(index); if (entry == m_chunks.end()) { auto chunk = m_generator.generate(index.x, index.y); ChunkData data{index, std::make_shared(chunk)}; m_chunks.insert({index, data}); return m_chunks.at(index); } return entry->second; } }