104 lines
3.4 KiB
C++
104 lines
3.4 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;
|
|
constexpr static const density_t DENSITY_MAX = (1 << 3)-1;
|
|
constexpr static const material_t MATERIAL_MAX = (1 << 12)-1;
|
|
|
|
constexpr static const uint16_t DENSITY_MASK = 0b0111;
|
|
constexpr static const uint16_t MATERIAL_MASK = 0b0111'1111'1111'1000;
|
|
constexpr static const 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 ushort 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;
|
|
}
|
|
}
|
|
};
|
|
}
|