24 std::array<uint8_t, 3> source {0, 1, 2};
25 std::array<bool, 3> flip {
false,
false,
false};
31 constexpr auto isMirror()
const noexcept ->
bool {
34 for (
int i = 0; i < 3; ++i) {
35 for (
int j = i + 1; j < 3; ++j) {
36 inversions += source[i] > source[j] ? 1 : 0;
39 const int negated =
static_cast<int>(flip[0]) +
static_cast<int>(flip[1]) +
static_cast<int>(flip[2]);
40 return (inversions + negated) % 2 != 0;
45inline auto allLatticeOrientations() -> std::array<LatticeOrientation, 48> {
46 constexpr std::array<std::array<uint8_t, 3>, 6> permutations {
47 {{0, 1, 2}, {0, 2, 1}, {1, 0, 2}, {1, 2, 0}, {2, 0, 1}, {2, 1, 0}}
50 std::array<LatticeOrientation, 48> out {};
52 for (
const std::array<uint8_t, 3>& permutation : permutations) {
53 for (uint32_t signs = 0; signs < 8; ++signs) {
55 orientation.source = permutation;
56 orientation.flip = {(signs & 1u) != 0, (signs & 2u) != 0, (signs & 4u) != 0};
57 out[next++] = orientation;
65 glm::mat3 matrix(0.0f);
66 for (
int row = 0; row < 3; ++row) {
67 matrix[orientation.source[row]][row] = orientation.flip[row] ? -1.0f : 1.0f;
75 glm::ivec3 offset {0};
85 for (
int axis = 0; axis < 3; ++axis) {
86 const int32_t along = voxel[placement.orientation.source[axis]];
87 out[axis] = placement.offset[axis] + (placement.orientation.flip[axis] ? -along - 1 : along);
94inline auto placementFromTransform(
const glm::mat4& transform,
float voxel_size = k_voxel_size,
float tolerance = 1e-4f)
95 -> std::optional<LatticePlacement> {
97 std::array<bool, 3> used {
false,
false,
false};
99 for (
int row = 0; row < 3; ++row) {
101 for (
int column = 0; column < 3; ++column) {
102 const float value = transform[column][row];
103 if (std::abs(std::abs(value) - 1.0f) <= tolerance) {
108 out.orientation.flip[row] = value < 0.0f;
109 }
else if (std::abs(value) > tolerance) {
113 if (found == -1 || used[found]) {
117 out.orientation.source[row] =
static_cast<uint8_t
>(found);
120 if (std::abs(transform[0][3]) > tolerance || std::abs(transform[1][3]) > tolerance || std::abs(transform[2][3]) > tolerance ||
121 std::abs(transform[3][3] - 1.0f) > tolerance) {
125 const float slack = 0.001f / voxel_size;
126 for (
int axis = 0; axis < 3; ++axis) {
127 const float voxels = transform[3][axis] / voxel_size;
128 const float nearest = std::round(voxels);
129 if (std::abs(voxels - nearest) > slack) {
132 out.offset[axis] =
static_cast<int32_t
>(nearest);
143 for (uint32_t i = 0; i < k_palette_size; ++i) {
144 table[i] =
static_cast<uint8_t
>(i);
152 std::vector<uint8_t> unmatched;
158 for (uint32_t i = 1; i < k_palette_size; ++i) {
164 bool matched =
false;
165 if (entry.
emissive == 0 || piece.max_emissive == master.max_emissive) {
166 for (uint32_t j = 1; j < k_palette_size; ++j) {
167 if (master.entries[j] == entry) {
168 out.table[i] =
static_cast<uint8_t
>(j);
175 out.unmatched.push_back(
static_cast<uint8_t
>(i));
182 uint32_t voxels_written = 0;
184 uint32_t voxels_clipped = 0;
189 bool pool_exhausted =
false;
Definition voxel_volume.hpp:21
auto placementFromTransform(const glm::mat4 &transform, float voxel_size=k_voxel_size, float tolerance=1e-4f) -> std::optional< LatticePlacement >
Matrix entries within tolerance of 0 or +/-1 and translation within a millimetre of a voxel boundary.
Definition stamp.hpp:94
auto placeVoxel(const LatticePlacement &placement, glm::ivec3 voxel) noexcept -> glm::ivec3
A flipped axis lands cell [v, v + 1] on [-v - 1, -v] hence the -1.
Definition stamp.hpp:83
std::array< uint8_t, k_palette_size > PaletteRemapTable
Index 0 always maps to 0.
Definition stamp.hpp:138
Output axis i reads input axis source[i] negated when flip[i].
Definition stamp.hpp:23
16 bytes and the offsets are a shader contract
Definition palette.hpp:26
uint8_t emissive
Scaled by Palette::max_emissive.
Definition palette.hpp:39
Entry 0 is the empty voxel and must stay all zero.
Definition palette.hpp:59
uint32_t voxels_unmapped
Skipped since stamping them as empty would erase the target.
Definition stamp.hpp:187