|
|
@ -21,27 +21,187 @@ |
|
|
|
#define ANTKEEPER_GEOM_MORTON_HPP
|
|
|
|
|
|
|
|
#include <array>
|
|
|
|
#include <cstdint>
|
|
|
|
#include <cstdlib>
|
|
|
|
|
|
|
|
namespace geom { |
|
|
|
|
|
|
|
/// Morton location code encoding and decoding functions.
|
|
|
|
namespace morton { |
|
|
|
|
|
|
|
/// Encodes 2D coordinates as a 32-bit Morton location code.
|
|
|
|
std::uint32_t encode_2d(std::uint32_t x, std::uint32_t y); |
|
|
|
/**
|
|
|
|
* Encodes 2D coordinates as a Morton location code. |
|
|
|
* |
|
|
|
* @param[in] x X-coordinate to encode. |
|
|
|
* @param[in] y Y-coordinate to encode. |
|
|
|
* @return Morton location code. |
|
|
|
*/ |
|
|
|
template <typename T> |
|
|
|
T encode(T x, T y); |
|
|
|
|
|
|
|
/**
|
|
|
|
* Encodes 3D coordinates as a Morton location code. |
|
|
|
* |
|
|
|
* @param[in] x X-coordinate to encode. |
|
|
|
* @param[in] y Y-coordinate to encode. |
|
|
|
* @param[in] z Z-coordinate to encode. |
|
|
|
* @return Morton location code. |
|
|
|
*/ |
|
|
|
template <typename T> |
|
|
|
T encode(T x, T y, T z); |
|
|
|
|
|
|
|
/**
|
|
|
|
* Decodes 2D coordinates from a Morton location code. |
|
|
|
* |
|
|
|
* @param[in] code Morton location code to decode. |
|
|
|
* @param[out] x Decoded x-coordinate. |
|
|
|
* @param[out] y Decoded y-coordinate. |
|
|
|
*/ |
|
|
|
template <typename T> |
|
|
|
void decode(T code, T& x, T& y); |
|
|
|
|
|
|
|
/**
|
|
|
|
* Decodes 3D coordinates from a Morton location code. |
|
|
|
* |
|
|
|
* @param[in] code Morton location code to decode. |
|
|
|
* @param[out] x Decoded x-coordinate. |
|
|
|
* @param[out] y Decoded y-coordinate. |
|
|
|
* @param[out] z Decoded z-coordinate. |
|
|
|
*/ |
|
|
|
template <typename T> |
|
|
|
void decode(T code, T& x, T& y, T& z); |
|
|
|
|
|
|
|
/// Encodes 3D coordinates as a 32-bit Morton location code.
|
|
|
|
std::uint32_t encode_3d(std::uint32_t x, std::uint32_t y, std::uint32_t z); |
|
|
|
template <typename T> |
|
|
|
T encode(T x, T y) |
|
|
|
{ |
|
|
|
auto expand = [](T x) -> T |
|
|
|
{ |
|
|
|
x &= (1 << (sizeof(T) << 2)) - 1; |
|
|
|
|
|
|
|
if constexpr(sizeof(T) >= 8) |
|
|
|
x = (x ^ (x << 16)) & T(0x0000ffff0000ffff); |
|
|
|
if constexpr(sizeof(T) >= 4) |
|
|
|
x = (x ^ (x << 8)) & T(0x00ff00ff00ff00ff); |
|
|
|
if constexpr(sizeof(T) >= 2) |
|
|
|
x = (x ^ (x << 4)) & T(0x0f0f0f0f0f0f0f0f); |
|
|
|
|
|
|
|
x = (x ^ (x << 2)) & T(0x3333333333333333); |
|
|
|
x = (x ^ (x << 1)) & T(0x5555555555555555); |
|
|
|
|
|
|
|
return x; |
|
|
|
}; |
|
|
|
|
|
|
|
return expand(x) | (expand(y) << 1); |
|
|
|
} |
|
|
|
|
|
|
|
/// Decodes X and Y coordinates from a 32-bit Morton location code.
|
|
|
|
std::array<uint32_t, 2> decode_2d(std::uint32_t code); |
|
|
|
template <typename T> |
|
|
|
T encode(T x, T y, T z) |
|
|
|
{ |
|
|
|
auto expand = [](T x) -> T |
|
|
|
{ |
|
|
|
if constexpr(sizeof(T) == 1) |
|
|
|
{ |
|
|
|
x &= 0x3; |
|
|
|
x = (x | x << 2) & 0x9; |
|
|
|
} |
|
|
|
else if constexpr(sizeof(T) == 2) |
|
|
|
{ |
|
|
|
x &= 0x001f; |
|
|
|
x = (x | x << 8) & 0x100f; |
|
|
|
x = (x | x << 4) & 0x10c3; |
|
|
|
x = (x | x << 2) & 0x1249; |
|
|
|
} |
|
|
|
else if constexpr(sizeof(T) == 4) |
|
|
|
{ |
|
|
|
x &= 0x00003ff; |
|
|
|
x = (x | x << 16) & 0x30000ff; |
|
|
|
x = (x | x << 8) & 0x300f00f; |
|
|
|
x = (x | x << 4) & 0x30c30c3; |
|
|
|
x = (x | x << 2) & 0x9249249; |
|
|
|
} |
|
|
|
else if constexpr(sizeof(T) == 8) |
|
|
|
{ |
|
|
|
x &= 0x00000000001fffff; |
|
|
|
x = (x | x << 32) & 0x001f00000000ffff; |
|
|
|
x = (x | x << 16) & 0x001f0000ff0000ff; |
|
|
|
x = (x | x << 8) & 0x100f00f00f00f00f; |
|
|
|
x = (x | x << 4) & 0x10c30c30c30c30c3; |
|
|
|
x = (x | x << 2) & 0x1249249249249249; |
|
|
|
} |
|
|
|
|
|
|
|
/// Decodes X, Y, and Z coordinates from a 32-bit Morton location code.
|
|
|
|
std::array<uint32_t, 3> decode_3d(std::uint32_t code); |
|
|
|
return x; |
|
|
|
}; |
|
|
|
|
|
|
|
return expand(x) | (expand(y) << 1) | (expand(z) << 2); |
|
|
|
} |
|
|
|
|
|
|
|
template <typename T> |
|
|
|
void decode(T code, T& x, T& y) |
|
|
|
{ |
|
|
|
auto compress = [](T x) -> T |
|
|
|
{ |
|
|
|
x &= T(0x5555555555555555); |
|
|
|
|
|
|
|
x = (x ^ (x >> 1)) & T(0x3333333333333333); |
|
|
|
x = (x ^ (x >> 2)) & T(0x0f0f0f0f0f0f0f0f); |
|
|
|
|
|
|
|
if constexpr(sizeof(T) >= 2) |
|
|
|
x = (x ^ (x >> 4)) & T(0x00ff00ff00ff00ff); |
|
|
|
if constexpr(sizeof(T) >= 4) |
|
|
|
x = (x ^ (x >> 8)) & T(0x0000ffff0000ffff); |
|
|
|
if constexpr(sizeof(T) >= 8) |
|
|
|
x = (x ^ (x >> 16)) & T(0x00000000ffffffff); |
|
|
|
|
|
|
|
return x; |
|
|
|
}; |
|
|
|
|
|
|
|
x = compress(code); |
|
|
|
y = compress(code >> 1); |
|
|
|
} |
|
|
|
|
|
|
|
template <typename T> |
|
|
|
void decode(T code, T& x, T& y, T& z) |
|
|
|
{ |
|
|
|
auto compress = [](T x) -> T |
|
|
|
{ |
|
|
|
if constexpr(sizeof(T) == 1) |
|
|
|
{ |
|
|
|
x &= 0x9; |
|
|
|
x = (x ^ x >> 2) & 0x3; |
|
|
|
} |
|
|
|
else if constexpr(sizeof(T) == 2) |
|
|
|
{ |
|
|
|
x &= 0x1249; |
|
|
|
x = (x ^ x >> 2) & 0x10c3; |
|
|
|
x = (x ^ x >> 4) & 0x100f; |
|
|
|
x = (x ^ x >> 8) & 0x001f; |
|
|
|
} |
|
|
|
else if constexpr(sizeof(T) == 4) |
|
|
|
{ |
|
|
|
x &= 0x9249249; |
|
|
|
x = (x ^ x >> 2) & 0x30c30c3; |
|
|
|
x = (x ^ x >> 4) & 0x300f00f; |
|
|
|
x = (x ^ x >> 8) & 0x30000ff; |
|
|
|
x = (x ^ x >> 16) & 0x00003ff; |
|
|
|
} |
|
|
|
else if constexpr(sizeof(T) == 8) |
|
|
|
{ |
|
|
|
x &= 0x1249249249249249; |
|
|
|
x = (x ^ x >> 2) & 0x10c30c30c30c30c3; |
|
|
|
x = (x ^ x >> 4) & 0x100f00f00f00f00f; |
|
|
|
x = (x ^ x >> 8) & 0x001f0000ff0000ff; |
|
|
|
x = (x ^ x >> 16) & 0x001f00000000ffff; |
|
|
|
x = (x ^ x >> 32) & 0x00000000001fffff; |
|
|
|
} |
|
|
|
|
|
|
|
return x; |
|
|
|
}; |
|
|
|
|
|
|
|
x = compress(code); |
|
|
|
y = compress(code >> 1); |
|
|
|
z = compress(code >> 2); |
|
|
|
} |
|
|
|
|
|
|
|
} // namespace morton
|
|
|
|
} // namespace geom
|
|
|
|
|
|
|
|
#endif // ANTKEEPER_GEOM_MORTON_HPP
|
|
|
|
|