Toast Engine
Loading...
Searching...
No Matches
brick.hpp
Go to the documentation of this file.
1
6
7#pragma once
8#include "voxel_constants.hpp"
9
10#include <array>
11#include <bit>
12#include <cassert>
13#include <cstdint>
14
15namespace voxel {
16
19 std::array<uint64_t, k_brick_dim> slices {};
20
21 [[nodiscard]]
22 constexpr auto operator[](uint32_t z) noexcept -> uint64_t& {
23 assert(z < k_brick_dim);
24 return slices[z];
25 }
26
27 [[nodiscard]]
28 constexpr auto operator[](uint32_t z) const noexcept -> const uint64_t& {
29 assert(z < k_brick_dim);
30 return slices[z];
31 }
32
33 [[nodiscard]]
34 constexpr auto operator==(const BrickOccupancy&) const noexcept -> bool = default;
35};
36
37inline constexpr BrickOccupancy k_empty_brick {};
38
39inline constexpr BrickOccupancy k_full_brick {
40 {~0ull, ~0ull, ~0ull, ~0ull, ~0ull, ~0ull, ~0ull, ~0ull}
41};
42
43inline constexpr uint64_t k_column_x_min = 0x0101010101010101ull;
44
45inline constexpr uint64_t k_column_x_max = 0x8080808080808080ull;
46
47inline constexpr uint64_t k_row_y_min = 0x00000000000000FFull;
48
49inline constexpr uint64_t k_row_y_max = 0xFF00000000000000ull;
50
51[[nodiscard]]
52constexpr auto localIndex(const uint32_t x, const uint32_t y, const uint32_t z) noexcept -> uint32_t {
53 assert(x < k_brick_dim && y < k_brick_dim && z < k_brick_dim);
54 return x + (y * k_brick_dim) + (z * k_brick_dim * k_brick_dim);
55}
56
57struct BrickCoord {
58 uint32_t x = 0;
59 uint32_t y = 0;
60 uint32_t z = 0;
61
62 [[nodiscard]]
63 constexpr auto operator==(const BrickCoord&) const noexcept -> bool = default;
64};
65
66[[nodiscard]]
67constexpr auto localFromIndex(uint32_t index) noexcept -> BrickCoord {
68 assert(index < k_brick_voxel_count);
69 return BrickCoord {index & 7u, (index >> 3u) & 7u, index >> 6u};
70}
71
72[[nodiscard]]
73constexpr auto sliceBit(uint32_t x, uint32_t y) noexcept -> uint32_t {
74 assert(x < k_brick_dim && y < k_brick_dim);
75 return (y * k_brick_dim) + x;
76}
77
78[[nodiscard]]
79constexpr auto isSolid(const BrickOccupancy& brick, uint32_t x, uint32_t y, uint32_t z) noexcept -> bool {
80 assert(z < k_brick_dim);
81 return ((brick[z] >> sliceBit(x, y)) & 1ull) != 0ull;
82}
83
84[[nodiscard]]
85constexpr auto isSolid(const BrickOccupancy& brick, uint32_t local_index) noexcept -> bool {
86 const BrickCoord c = localFromIndex(local_index);
87 return isSolid(brick, c.x, c.y, c.z);
88}
89
90constexpr void setSolid(BrickOccupancy& brick, uint32_t x, uint32_t y, uint32_t z, bool solid) noexcept {
91 assert(z < k_brick_dim);
92 const uint64_t bit = 1ull << sliceBit(x, y);
93 if (solid) {
94 brick[z] |= bit;
95 } else {
96 brick[z] &= ~bit;
97 }
98}
99
100constexpr void setSolid(BrickOccupancy& brick, uint32_t local_index, bool solid) noexcept {
101 const BrickCoord c = localFromIndex(local_index);
102 setSolid(brick, c.x, c.y, c.z, solid);
103}
104
105[[nodiscard]]
106constexpr auto isEmpty(const BrickOccupancy& brick) noexcept -> bool {
107 for (uint64_t slice : brick.slices) {
108 if (slice != 0ull) {
109 return false;
110 }
111 }
112 return true;
113}
114
115[[nodiscard]]
116constexpr auto isFull(const BrickOccupancy& brick) noexcept -> bool {
117 for (uint64_t slice : brick.slices) {
118 if (slice != ~0ull) {
119 return false;
120 }
121 }
122 return true;
123}
124
125[[nodiscard]]
126constexpr auto popCount(const BrickOccupancy& brick) noexcept -> uint32_t {
127 uint32_t total = 0;
128 for (uint64_t slice : brick.slices) {
129 total += static_cast<uint32_t>(std::popcount(slice));
130 }
131 return total;
132}
133
135 BrickCoord min;
136 BrickCoord max;
137};
138
140[[nodiscard]]
141constexpr auto occupiedExtent(const BrickOccupancy& brick) noexcept -> BrickExtent {
142 uint64_t merged = 0;
143 uint32_t z_min = k_brick_dim;
144 uint32_t z_max = 0;
145 for (uint32_t z = 0; z < k_brick_dim; ++z) {
146 if (brick[z] != 0ull) {
147 merged |= brick[z];
148 z_min = z < z_min ? z : z_min;
149 z_max = z;
150 }
151 }
152
153 uint32_t columns = 0;
154 uint32_t y_min = k_brick_dim;
155 uint32_t y_max = 0;
156 for (uint32_t y = 0; y < k_brick_dim; ++y) {
157 const auto row = static_cast<uint32_t>((merged >> (y * k_brick_dim)) & 0xFFull);
158 if (row != 0u) {
159 columns |= row;
160 y_min = y < y_min ? y : y_min;
161 y_max = y;
162 }
163 }
164
165 return {
166 .min = { static_cast<uint32_t>(std::countr_zero(columns)), y_min, z_min},
167 .max = {31u - static_cast<uint32_t>(std::countl_zero(columns)), y_max, z_max},
168 };
169}
170
171[[nodiscard]]
172constexpr auto operator&(const BrickOccupancy& a, const BrickOccupancy& b) noexcept -> BrickOccupancy {
173 BrickOccupancy out {};
174 for (uint32_t z = 0; z < k_brick_dim; ++z) {
175 out[z] = a[z] & b[z];
176 }
177 return out;
178}
179
180[[nodiscard]]
181constexpr auto operator|(const BrickOccupancy& a, const BrickOccupancy& b) noexcept -> BrickOccupancy {
182 BrickOccupancy out {};
183 for (uint32_t z = 0; z < k_brick_dim; ++z) {
184 out[z] = a[z] | b[z];
185 }
186 return out;
187}
188
189[[nodiscard]]
190constexpr auto operator~(const BrickOccupancy& a) noexcept -> BrickOccupancy {
191 BrickOccupancy out {};
192 for (uint32_t z = 0; z < k_brick_dim; ++z) {
193 out[z] = ~a[z];
194 }
195 return out;
196}
197
198[[nodiscard]]
199constexpr auto neighboursNegX(const BrickOccupancy& brick, const BrickOccupancy* adjacent = nullptr) noexcept -> BrickOccupancy {
200 BrickOccupancy out {};
201 for (uint32_t z = 0; z < k_brick_dim; ++z) {
202 out[z] = (brick[z] & ~k_column_x_max) << 1;
203 if (adjacent != nullptr) {
204 out[z] |= ((*adjacent)[z] >> 7) & k_column_x_min;
205 }
206 }
207 return out;
208}
209
210[[nodiscard]]
211constexpr auto neighboursPosX(const BrickOccupancy& brick, const BrickOccupancy* adjacent = nullptr) noexcept -> BrickOccupancy {
212 BrickOccupancy out {};
213 for (uint32_t z = 0; z < k_brick_dim; ++z) {
214 out[z] = (brick[z] & ~k_column_x_min) >> 1;
215 if (adjacent != nullptr) {
216 out[z] |= ((*adjacent)[z] << 7) & k_column_x_max;
217 }
218 }
219 return out;
220}
221
222[[nodiscard]]
223constexpr auto neighboursNegY(const BrickOccupancy& brick, const BrickOccupancy* adjacent = nullptr) noexcept -> BrickOccupancy {
224 BrickOccupancy out {};
225 for (uint32_t z = 0; z < k_brick_dim; ++z) {
226 out[z] = brick[z] << k_brick_dim;
227 if (adjacent != nullptr) {
228 out[z] |= (*adjacent)[z] >> 56;
229 }
230 }
231 return out;
232}
233
234[[nodiscard]]
235constexpr auto neighboursPosY(const BrickOccupancy& brick, const BrickOccupancy* adjacent = nullptr) noexcept -> BrickOccupancy {
236 BrickOccupancy out {};
237 for (uint32_t z = 0; z < k_brick_dim; ++z) {
238 out[z] = brick[z] >> k_brick_dim;
239 if (adjacent != nullptr) {
240 out[z] |= (*adjacent)[z] << 56;
241 }
242 }
243 return out;
244}
245
246[[nodiscard]]
247constexpr auto neighboursNegZ(const BrickOccupancy& brick, const BrickOccupancy* adjacent = nullptr) noexcept -> BrickOccupancy {
248 BrickOccupancy out {};
249 out[0] = adjacent != nullptr ? (*adjacent)[k_brick_dim - 1] : 0ull;
250 for (uint32_t z = 1; z < k_brick_dim; ++z) {
251 out[z] = brick[z - 1];
252 }
253 return out;
254}
255
256[[nodiscard]]
257constexpr auto neighboursPosZ(const BrickOccupancy& brick, const BrickOccupancy* adjacent = nullptr) noexcept -> BrickOccupancy {
258 BrickOccupancy out {};
259 for (uint32_t z = 0; z + 1 < k_brick_dim; ++z) {
260 out[z] = brick[z + 1];
261 }
262 out[k_brick_dim - 1] = adjacent != nullptr ? (*adjacent)[0] : 0ull;
263 return out;
264}
265
267 const BrickOccupancy* neg_x = nullptr;
268 const BrickOccupancy* pos_x = nullptr;
269 const BrickOccupancy* neg_y = nullptr;
270 const BrickOccupancy* pos_y = nullptr;
271 const BrickOccupancy* neg_z = nullptr;
272 const BrickOccupancy* pos_z = nullptr;
273};
274
275[[nodiscard]]
276constexpr auto interior(const BrickOccupancy& brick, const BrickNeighbourhood& neighbours = {}) noexcept -> BrickOccupancy {
277 return brick & neighboursNegX(brick, neighbours.neg_x) & neighboursPosX(brick, neighbours.pos_x) &
278 neighboursNegY(brick, neighbours.neg_y) & neighboursPosY(brick, neighbours.pos_y) &
279 neighboursNegZ(brick, neighbours.neg_z) & neighboursPosZ(brick, neighbours.pos_z);
280}
281
282[[nodiscard]]
283constexpr auto surfaceShell(const BrickOccupancy& brick, const BrickNeighbourhood& neighbours = {}) noexcept -> BrickOccupancy {
284 return brick & ~interior(brick, neighbours);
285}
286
287[[nodiscard]]
288constexpr auto dilate(const BrickOccupancy& brick) noexcept -> BrickOccupancy {
289 return brick | neighboursNegX(brick) | neighboursPosX(brick) | neighboursNegY(brick) | neighboursPosY(brick) |
290 neighboursNegZ(brick) | neighboursPosZ(brick);
291}
292
294[[nodiscard]]
295constexpr auto faceNegX(const BrickOccupancy& brick) noexcept -> uint64_t {
296 uint64_t out = 0;
297 for (uint32_t z = 0; z < k_brick_dim; ++z) {
298 for (uint32_t y = 0; y < k_brick_dim; ++y) {
299 if (((brick[z] >> sliceBit(0, y)) & 1ull) != 0ull) {
300 out |= 1ull << ((z * k_brick_dim) + y);
301 }
302 }
303 }
304 return out;
305}
306
308[[nodiscard]]
309constexpr auto facePosX(const BrickOccupancy& brick) noexcept -> uint64_t {
310 uint64_t out = 0;
311 for (uint32_t z = 0; z < k_brick_dim; ++z) {
312 for (uint32_t y = 0; y < k_brick_dim; ++y) {
313 if (((brick[z] >> sliceBit(k_brick_dim - 1, y)) & 1ull) != 0ull) {
314 out |= 1ull << ((z * k_brick_dim) + y);
315 }
316 }
317 }
318 return out;
319}
320
322[[nodiscard]]
323constexpr auto faceNegY(const BrickOccupancy& brick) noexcept -> uint64_t {
324 uint64_t out = 0;
325 for (uint32_t z = 0; z < k_brick_dim; ++z) {
326 out |= (brick[z] & k_row_y_min) << (z * k_brick_dim);
327 }
328 return out;
329}
330
332[[nodiscard]]
333constexpr auto facePosY(const BrickOccupancy& brick) noexcept -> uint64_t {
334 uint64_t out = 0;
335 for (uint32_t z = 0; z < k_brick_dim; ++z) {
336 out |= (brick[z] >> 56) << (z * k_brick_dim);
337 }
338 return out;
339}
340
342[[nodiscard]]
343constexpr auto faceNegZ(const BrickOccupancy& brick) noexcept -> uint64_t {
344 return brick[0];
345}
346
348[[nodiscard]]
349constexpr auto facePosZ(const BrickOccupancy& brick) noexcept -> uint64_t {
350 return brick[k_brick_dim - 1];
351}
352
354 uint64_t neg_x = 0;
355 uint64_t pos_x = 0;
356 uint64_t neg_y = 0;
357 uint64_t pos_y = 0;
358 uint64_t neg_z = 0;
359 uint64_t pos_z = 0;
360
361 [[nodiscard]]
362 constexpr auto operator==(const BrickFaces&) const noexcept -> bool = default;
363};
364
365[[nodiscard]]
366constexpr auto computeFaces(const BrickOccupancy& brick) noexcept -> BrickFaces {
367 return BrickFaces {faceNegX(brick), facePosX(brick), faceNegY(brick), facePosY(brick), faceNegZ(brick), facePosZ(brick)};
368}
369
370[[nodiscard]]
371constexpr auto facesConnect(uint64_t face_a, uint64_t face_b) noexcept -> bool {
372 return (face_a & face_b) != 0ull;
373}
374
375}
constexpr auto faceNegX(const BrickOccupancy &brick) noexcept -> uint64_t
x == 0 plane with bit z * 8 + y
Definition brick.hpp:295
constexpr auto occupiedExtent(const BrickOccupancy &brick) noexcept -> BrickExtent
Brick must not be empty.
Definition brick.hpp:141
constexpr auto facePosX(const BrickOccupancy &brick) noexcept -> uint64_t
x == 7 plane with bit z * 8 + y
Definition brick.hpp:309
constexpr auto facePosZ(const BrickOccupancy &brick) noexcept -> uint64_t
z == 7 plane with bit y * 8 + x
Definition brick.hpp:349
constexpr auto faceNegY(const BrickOccupancy &brick) noexcept -> uint64_t
y == 0 plane with bit z * 8 + x
Definition brick.hpp:323
constexpr auto facePosY(const BrickOccupancy &brick) noexcept -> uint64_t
y == 7 plane with bit z * 8 + x
Definition brick.hpp:333
constexpr auto faceNegZ(const BrickOccupancy &brick) noexcept -> uint64_t
z == 0 plane with bit y * 8 + x
Definition brick.hpp:343
Definition brick.hpp:57
Definition brick.hpp:134
Definition brick.hpp:353
Definition brick.hpp:266
One 64-bit word per z-slice with bit y * 8 + x.
Definition brick.hpp:18