From d261feab3a4357617a36e0356db767c1cfc78a86 Mon Sep 17 00:00:00 2001 From: "C. J. Howard" Date: Thu, 14 Jan 2021 23:42:06 +0800 Subject: [PATCH] Revise Morton location code functions to be templated, closes #7 --- CMakeLists.txt | 1 + src/game/states/play-state.cpp | 1 + src/geom/mesh-accelerator.cpp | 5 +- src/geom/morton.cpp | 86 ---------------- src/geom/morton.hpp | 180 +++++++++++++++++++++++++++++++-- src/utility/bit-math.hpp | 4 +- 6 files changed, 177 insertions(+), 100 deletions(-) delete mode 100644 src/geom/morton.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index d4aa351..bc40e61 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -14,6 +14,7 @@ find_package(SDL2 REQUIRED COMPONENTS SDL2::SDL2-static SDL2::SDL2main CONFIG) find_package(OpenAL REQUIRED CONFIG) find_library(physfs REQUIRED NAMES physfs-static PATHS "${CMAKE_PREFIX_PATH}/lib") + # Determine dependencies set(STATIC_LIBS dr_wav diff --git a/src/game/states/play-state.cpp b/src/game/states/play-state.cpp index 8a9b72a..fd30565 100644 --- a/src/game/states/play-state.cpp +++ b/src/game/states/play-state.cpp @@ -458,6 +458,7 @@ void play_state_enter(game_context* ctx) std::cout << "similarity62: " << genetics::protein::similarity(protein_b.begin(), protein_b.end(), protein_c.begin(), genetics::matrix::blosum62) << std::endl; std::cout << "similarity80: " << genetics::protein::similarity(protein_b.begin(), protein_b.end(), protein_c.begin(), genetics::matrix::blosum80) << std::endl; + } void play_state_exit(game_context* ctx) diff --git a/src/geom/mesh-accelerator.cpp b/src/geom/mesh-accelerator.cpp index cd7a295..197000d 100644 --- a/src/geom/mesh-accelerator.cpp +++ b/src/geom/mesh-accelerator.cpp @@ -141,7 +141,8 @@ void mesh_accelerator::query_nearest_recursive(float& nearest_t, geom::mesh::fac aabb mesh_accelerator::get_node_bounds(octree32::node_type node) const { // Decode Morton location of node - auto [x, y, z] = morton::decode_3d(octree32::location(node)); + std::uint32_t x, y, z; + morton::decode(octree32::location(node), x, y, z); float3 node_location = float3{static_cast(x), static_cast(y), static_cast(z)}; // Get node dimensions at node depth @@ -167,7 +168,7 @@ octree32::node_type mesh_accelerator::find_node(const float3& point) const transformed_point = transformed_point / node_dimensions[octree32::max_depth]; // Encode transformed point as a Morton location code - std::uint32_t location = morton::encode_3d( + std::uint32_t location = morton::encode( static_cast(transformed_point.x), static_cast(transformed_point.y), static_cast(transformed_point.z)); diff --git a/src/geom/morton.cpp b/src/geom/morton.cpp deleted file mode 100644 index 4273f4b..0000000 --- a/src/geom/morton.cpp +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Copyright (C) 2021 Christopher J. Howard - * - * This file is part of Antkeeper source code. - * - * Antkeeper source code is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Antkeeper source code 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Antkeeper source code. If not, see . - */ - -#include "morton.hpp" - -namespace geom { -namespace morton { - -std::uint32_t encode_2d(std::uint32_t x, std::uint32_t y) -{ - auto interleave = [](std::uint32_t x) -> std::uint32_t - { - x &= 0x0000ffff; - x = (x ^ (x << 8)) & 0x00ff00ff; - x = (x ^ (x << 4)) & 0x0f0f0f0f; - x = (x ^ (x << 2)) & 0x33333333; - x = (x ^ (x << 1)) & 0x55555555; - return x; - }; - - return (interleave(y) << 1) + interleave(x); -} - -std::uint32_t encode_3d(std::uint32_t x, std::uint32_t y, std::uint32_t z) -{ - auto interleave = [](std::uint32_t x) -> std::uint32_t - { - x &= 0x000003ff; - x = (x ^ (x << 16)) & 0xff0000ff; - x = (x ^ (x << 8)) & 0x0300f00f; - x = (x ^ (x << 4)) & 0x030c30c3; - x = (x ^ (x << 2)) & 0x09249249; - return x; - }; - - return interleave(x) | (interleave(y) << 1) | (interleave(z) << 2); -} - -std::array decode_2d(std::uint32_t code) -{ - auto unravel = [](std::uint32_t x) -> std::uint32_t - { - x &= 0x55555555; - x = (x ^ (x >> 1)) & 0x33333333; - x = (x ^ (x >> 2)) & 0x0f0f0f0f; - x = (x ^ (x >> 4)) & 0x00ff00ff; - x = (x ^ (x >> 8)) & 0x0000ffff; - return x; - }; - - return {unravel(code >> 0), unravel(code >> 1)}; -} - -std::array decode_3d(std::uint32_t code) -{ - auto unravel = [](std::uint32_t x) -> std::uint32_t - { - x &= 0x09249249; - x = (x ^ (x >> 2)) & 0x030c30c3; - x = (x ^ (x >> 4)) & 0x0300f00f; - x = (x ^ (x >> 8)) & 0xff0000ff; - x = (x ^ (x >> 16)) & 0x000003ff; - return x; - }; - - return {unravel(code >> 0), unravel(code >> 1), unravel(code >> 2)}; -} - -} // namespace morton -} // namespace geom diff --git a/src/geom/morton.hpp b/src/geom/morton.hpp index afbcae6..02f5f6d 100644 --- a/src/geom/morton.hpp +++ b/src/geom/morton.hpp @@ -21,27 +21,187 @@ #define ANTKEEPER_GEOM_MORTON_HPP #include -#include +#include 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 +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 +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 +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 +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 +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 decode_2d(std::uint32_t code); +template +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 decode_3d(std::uint32_t code); + return x; + }; + + return expand(x) | (expand(y) << 1) | (expand(z) << 2); +} + +template +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 +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 - diff --git a/src/utility/bit-math.hpp b/src/utility/bit-math.hpp index 29f1f8b..3166345 100644 --- a/src/utility/bit-math.hpp +++ b/src/utility/bit-math.hpp @@ -20,8 +20,8 @@ #ifndef ANTKEEPER_BIT_MATH_HPP #define ANTKEEPER_BIT_MATH_HPP -namespace bit -{ +/// Bitwise math +namespace bit { /** * Compresses the even bits of a value into the lower half, then clears the upper half.