rsys

Basic data structures and low-level features
git clone git://git.meso-star.fr/rsys.git
Log | Files | Refs | README | LICENSE

commit 765d4712d38454484fc1c49f71928d5cd34e994b
parent fcef40d165201c431679cf739fe8d38586bc35e9
Author: vaplv <vaplv@free.fr>
Date:   Mon, 11 Jan 2021 12:20:42 +0100

Add and test the 3D morton encoding/decoding

Diffstat:
Mcmake/CMakeLists.txt | 1+
Asrc/morton.h | 65+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/rsys.h | 5+++++
Asrc/test_morton.c | 83+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 154 insertions(+), 0 deletions(-)

diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt @@ -230,6 +230,7 @@ if(NOT NO_TEST) new_test(test_math ${MATH_LIB}) new_test(test_mem_allocator rsys) new_test(test_misc) + new_test(test_morton) new_test(test_quaternion rsys) new_test(test_ref) new_test(test_signal rsys) diff --git a/src/morton.h b/src/morton.h @@ -0,0 +1,65 @@ +/* Copyright (C) 2013-2020 Vincent Forest (vaplv@free.fr) + * + * The RSys library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The RSys library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with the RSys library. If not, see <http://www.gnu.org/licenses/>. */ + +#ifndef MORTON_H +#define MORTON_H + +#include "rsys.h" + +static INLINE uint64_t +morton3D_encode_u21(const uint32_t u21) +{ + uint64_t u64 = u21 & ((1<<21) - 1); + ASSERT(u21 <= ((1 << 21) - 1)); + u64 = (u64 | (u64 << 32)) & 0xFFFF00000000FFFF; + u64 = (u64 | (u64 << 16)) & 0x00FF0000FF0000FF; + u64 = (u64 | (u64 << 8)) & 0xF00F00F00F00F00F; + u64 = (u64 | (u64 << 4)) & 0x30C30C30C30C30C3; + u64 = (u64 | (u64 << 2)) & 0x9249249249249249; + return u64; +} + +static INLINE uint32_t +morton3D_decode_u21(const uint64_t u64) +{ + uint64_t tmp = (u64 & 0x9249249249249249); + tmp = (tmp | (tmp >> 2)) & 0x30C30C30C30C30C3; + tmp = (tmp | (tmp >> 4)) & 0xF00F00F00F00F00F; + tmp = (tmp | (tmp >> 8)) & 0x00FF0000FF0000FF; + tmp = (tmp | (tmp >> 16)) & 0xFFFF00000000FFFF; + tmp = (tmp | (tmp >> 32)) & 0x00000000FFFFFFFF; + ASSERT(tmp <= ((1<<21)-1)); + return (uint32_t)tmp; +} + +static INLINE uint64_t +morton_xyz_encode_u21(const uint32_t xyz[3]) +{ + return (morton3D_encode_u21(xyz[0]) << 2) + | (morton3D_encode_u21(xyz[1]) << 1) + | (morton3D_encode_u21(xyz[2]) << 0); +} + +static INLINE void +morton_xyz_decode_u21(const uint64_t code, uint32_t xyz[3]) +{ + ASSERT(xyz && code < ((1ull << 63)-1)); + xyz[0] = (uint32_t)morton3D_decode_u21(code >> 2); + xyz[1] = (uint32_t)morton3D_decode_u21(code >> 1); + xyz[2] = (uint32_t)morton3D_decode_u21(code >> 0); +} + +#endif /* MORTON_H */ + diff --git a/src/rsys.h b/src/rsys.h @@ -366,6 +366,11 @@ typedef int res_T; #endif #define BIT(Num) (1 << (Num)) +#define BIT_I32(Num) ((int32_t)1 << (Num)) +#define BIT_I64(Num) ((int64_t)1 << (Num)) +#define BIT_U32(Num) ((uint32_t)1 << (Num)) +#define BIT_U64(Num) ((uint64_t)1 << (Num)) + #define CONCAT__(A, B) A ## B #define CONCAT(A, B) CONCAT__(A, B) #define SPLIT2(A) (A)[0], (A)[1] diff --git a/src/test_morton.c b/src/test_morton.c @@ -0,0 +1,83 @@ +/* Copyright (C) 2013-2020 Vincent Forest (vaplv@free.fr) + * + * The RSys library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The RSys library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with the RSys library. If not, see <http://www.gnu.org/licenses/>. */ + +#include "math.h" +#include "morton.h" + +#include <stdlib.h> + +static INLINE uint32_t +rand_u21() +{ + return (uint32_t)(rand() & (BIT(21)-1)); +} + +static INLINE uint64_t +encode_u21(uint32_t u21) +{ + uint64_t mcode = 0; + uint32_t i; + for(i = (uint32_t)round_up_pow2(u21); i != 0; i >>= 1) { + if(i <= u21) { + mcode |= morton3D_encode_u21(i); + u21 -= i; + } + } + return mcode; +} + +int +main(int argc, char** argv) +{ + int bit = 0; + int i = 0; + (void)argc, (void)argv; + + FOR_EACH(bit, 0, 21) { + CHK(morton3D_encode_u21(BIT_U32(bit)) == BIT_U64(3*bit)); + CHK(morton3D_decode_u21(BIT_U64(3*bit)) == BIT_U32(bit)); + } + + FOR_EACH(i, 0, 10000) { + const uint32_t u21 = rand_u21(); + const uint64_t u64 = morton3D_encode_u21(u21); + CHK(u64 == encode_u21(u21)); + CHK(u21 == morton3D_decode_u21(u64)); + } + + FOR_EACH(i, 0, 10000) { + uint32_t xyz[3]; + uint32_t xyz2[3]; + uint64_t xyz_mcode[3]; + uint64_t mcode; + + xyz[0] = rand_u21(); + xyz[1] = rand_u21(); + xyz[2] = rand_u21(); + mcode = morton_xyz_encode_u21(xyz); + + xyz_mcode[0] = morton3D_encode_u21(xyz[0]); + xyz_mcode[1] = morton3D_encode_u21(xyz[1]); + xyz_mcode[2] = morton3D_encode_u21(xyz[2]); + CHK(mcode == ((xyz_mcode[0]<<2) | (xyz_mcode[1]<<1) | (xyz_mcode[2]<<0))); + + morton_xyz_decode_u21(mcode, xyz2); + CHK(xyz[0] = xyz2[0]); + CHK(xyz[1] = xyz2[1]); + CHK(xyz[2] = xyz2[2]); + } + + return 0; +}