/**
 * chunk_voxel_pos: u8 (contains u5: CHUNK_LENGTH)
 * chunk_voxel_idx: u16
 * chunk_pos: i56
 * region_chunk_pos: u8 (contains u5: REGION_LENGTH)
 * region_chunk_idx: u16
 * region_pos: i48 (NOTE: trimmed to i32)
 * voxel_pos: i64
 *
 * camera_offset: f32
 * camera_pos: region_pos + camera_offset
 *
 * known limits:
 * - noise: f32 2^24 spaghettification
 * - noise: i32 2^32 loop
 * - position: i32(chunk_pos)+u5(CHUNK_LENGTH) 2^36 no rendering (NOTE: only with chunk_pos as int)
 * - position: i32(region_pos)+u5(REGION_LENGTH)+u5(CHUNK_LENGTH) 2^42 loop
 */

#pragma once

#include <functional>
#include "../data/glm.hpp"
#include "../data/generational.hpp"

const auto CHUNK_LENGTH = glm::IDX_LENGTH;
const auto CHUNK_SIZE = CHUNK_LENGTH * CHUNK_LENGTH * CHUNK_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 = data::generational::id;
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 area_pos = glm::ifvec3;

using entity_id = data::generational::id;
using entity_instance_id = std::pair<entity_id, data::generational::id>;
static const auto PLAYER_ENTITY_ID = data::generational::id(0);

using camera_pos = glm::ifvec3;
