/* * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ #pragma once #include "Math.hpp" #include #include #include #include #include #include namespace OpenVulkano::Math { /** * A templated vector implementation that allows for a lower resolution of the y axis. * * @tparam T backing datatype * @tparam REDUCE_Y_RESOLUTION if the y resolution should be reduced * @tparam ASSERT_INPUT_VALUES if input values should be validated before they are used * @tparam BITS_PER_COMPONENT how many bits each component should use. -1 for automatic sizing */ template && std::is_integral_v>> class DenseVector3i { typedef DenseVector3i DenseVec3; static constexpr int GetBitCount() { if (BITS_PER_COMPONENT > 0) return BITS_PER_COMPONENT; if constexpr (std::is_same_v) { return REDUCE_Y_RESOLUTION ? 3 : 2; } if constexpr (std::is_same_v) { return REDUCE_Y_RESOLUTION ? 6 : 5; } if constexpr (std::is_same_v) { return REDUCE_Y_RESOLUTION ? 11 : 10; } return REDUCE_Y_RESOLUTION ? 22 : 21; } static constexpr int GetBitCountY() { if (BITS_PER_COMPONENT > 0) return BITS_PER_COMPONENT; if (!REDUCE_Y_RESOLUTION) return GetBitCount(); return sizeof(T) * 8 - GetBitCount() * 2; } static constexpr int BITS = GetBitCount(); static constexpr int BITS_Y = GetBitCountY(); static constexpr T BITMASK = (1 << BITS) - 1; static constexpr int MAX_VALUE = (1 << (BITS - 1)) - 1; static constexpr int MAX_VALUE_Y = (1 << (BITS_Y - 1)) - 1; static constexpr int MIN_VALUE = -MAX_VALUE - 1; static constexpr int MIN_VALUE_Y = -MAX_VALUE_Y - 1; static constexpr void AssertValue(int value, int maxValue = MAX_VALUE, int minValue = MIN_VALUE) { if (!ASSERT_INPUT_VALUES) return; if (value > maxValue || value < minValue) throw std::range_error("Value to big for DenseVector"); } T data = 0; public: DenseVector3i() = default; constexpr explicit DenseVector3i(const Math::Vector3i& vec3) : DenseVector3i(vec3.x, vec3.y, vec3.z) {} constexpr explicit DenseVector3i(const Math::Vector3i_SIMD& vec3) : DenseVector3i(vec3.x, vec3.y, vec3.z) {} constexpr DenseVector3i(T x, T y, T z) : data((x & BITMASK) | ((y & BITMASK) << (2 * BITS)) | ((z & BITMASK) << BITS)) { AssertValue(x); AssertValue(y, MAX_VALUE_Y, MIN_VALUE_Y); AssertValue(z); } constexpr T Data() const { return data; } [[nodiscard]] constexpr int X() const { T v = data & BITMASK; if (v > MAX_VALUE) v |= ~BITMASK; return v; } [[nodiscard]] constexpr int Y() const { T v = (data >> (2 * BITS)) & BITMASK; if (v > MAX_VALUE_Y) v |= ~BITMASK; return v; } [[nodiscard]] constexpr int Z() const { T v = (data >> BITS) & BITMASK; if (v > MAX_VALUE) v |= ~BITMASK; return v; } void SetX(int x) { AssertValue(x); data = (data & !BITMASK) | (x & BITMASK); } void SetY(int y) { AssertValue(y, MAX_VALUE_Y, MIN_VALUE_Y); data = (data & !(BITMASK << (2 * BITS))) | ((y & BITMASK) << (2 * BITS)); } void SetZ(int z) { AssertValue(z); data = (data & !(BITMASK << BITS)) | ((z & BITMASK) << BITS); } [[nodiscard]] std::string ToString(const std::string& separator) const { return std::to_string(X()) + separator + std::to_string(Y()) + separator + std::to_string(Z()); } [[nodiscard]] std::string ToString() const { return fmt::format("{},{},{}", X(), Y(), Z()); } //[[nodiscard]] constexpr operator T() const { return data; } [[nodiscard]] constexpr bool operator <(DenseVec3 rhs) const { return data < rhs.data; } [[nodiscard]] bool operator>(DenseVec3 rhs) const { return rhs < *this; } [[nodiscard]] bool operator>=(DenseVec3 rhs) const { return !(*this < rhs); } [[nodiscard]] bool operator<=(DenseVec3 rhs) const { return !(rhs < *this); } [[nodiscard]] constexpr bool operator ==(DenseVec3 rhs) const { return data == rhs.data; } [[nodiscard]] constexpr bool operator !=(DenseVec3 rhs) const { return data != rhs.data; } [[nodiscard]] explicit constexpr operator Math::Vector3i() const { return { X(), Y(), Z() }; } [[nodiscard]] explicit constexpr operator Math::Vector3i_SIMD() const { return { X(), Y(), Z() }; } }; }