1
0
Fork 0
Univerxel/src/core/world/Voxel.hpp

104 lines
3.3 KiB
C++

#pragma once
#include <robin_hood.h>
#include "../../core/world/materials.hpp"
#include <cassert>
namespace world {
/// Universe unit
struct Voxel {
/// Packed value
/// swap(1) + material(12) + density(3)
uint16_t value;
using material_t = uint_fast16_t;
using density_t = uint_fast8_t;
static constexpr density_t DENSITY_MAX = (1 << 3)-1;
static constexpr material_t MATERIAL_MAX = (1 << 12)-1;
static constexpr uint16_t DENSITY_MASK = 0b0111;
static constexpr uint16_t MATERIAL_MASK = 0b0111'1111'1111'1000;
static constexpr uint16_t SWAP_MASK = 0b1000'0000'0000'0000;
Voxel(uint16_t value = 0): value(value) { }
Voxel(material_t material, density_t density, bool swap = false) {
assert(density <= DENSITY_MAX);
assert(material <= MATERIAL_MAX);
value = (swap * SWAP_MASK) |
((material << 3) & MATERIAL_MASK) |
(density & DENSITY_MASK);
}
/// Material type
constexpr inline material_t material() const {
return (value & MATERIAL_MASK) >> 3;
}
/// Texture idx
constexpr inline uint16_t texture() const {
return materials::textures_map[material()];
}
/// Quantity of element
constexpr inline density_t density() const {
return value & DENSITY_MASK;
}
/// Quantity of element on [0, 1]
constexpr inline float density_ratio() const {
return density() * (1.f / world::Voxel::DENSITY_MAX);
}
/// Swap value
/// Use external metadata table
constexpr inline bool swap() const {
return (value & SWAP_MASK) != 0;
}
/// Is solid
constexpr inline bool is_solid() const {
return density() > 0 && materials::solidity[material()];
}
/// Is visible matter
constexpr inline bool is_visible() const {
return !materials::invisibility[material()];
}
/// Contains matter
constexpr inline bool is_material() const {
return density() > 0 && is_visible();
}
/// Is full
constexpr inline bool is_full() const {
return density() == DENSITY_MAX && !materials::transparency[material()];
}
/// Value after fill operation
inline Voxel const filled(Voxel in, float ratio) {
if (ratio >= 1)
return in;
const world::Voxel::density_t dst = in.density() * ratio;
if (!in.is_material())
return world::Voxel(material(), world::Voxel::DENSITY_MAX-dst, swap());
if (is_material() && density() > dst)
return Voxel(value);
return world::Voxel(in.material(), dst, in.swap());
}
};
/// Stock of material
struct Item {
/// Quantity of material
unsigned long long Count;
/// Material type
/// @see world::materials
Voxel::material_t Material;
};
/// List of materials
struct ItemList: robin_hood::unordered_map<Voxel::material_t, unsigned long long> {
void add(const std::optional<Item>& item) {
if(item) {
(*this)[item.value().Material] += item.value().Count;
}
}
};
}