Browse Source

Add structured binding support to math::matrix. Replace math::vector floating point static asserts with floating point concepts

master
C. J. Howard 2 years ago
parent
commit
32c53d7106
3 changed files with 392 additions and 272 deletions
  1. +40
    -55
      src/game/system/terrain.cpp
  2. +265
    -131
      src/math/matrix.hpp
  3. +87
    -86
      src/math/vector.hpp

+ 40
- 55
src/game/system/terrain.cpp View File

@ -84,54 +84,32 @@ void terrain::update(double t, double dt)
const scene::camera& cam = *camera.object; const scene::camera& cam = *camera.object;
// for (int i = 0; i < 8; ++i)
// std::cout << "corner " << i << ": " << cam.get_view_frustum().get_corners()[i] << std::endl;
geom::primitive::ray<float, 3> rays[8];
rays[0] = cam.pick({-1, -1});
rays[1] = cam.pick({-1, 1});
rays[2] = cam.pick({ 1, 1});
rays[3] = cam.pick({ 1, -1});
float3 ntl = rays[0].origin;
float3 nbl = rays[1].origin;
float3 nbr = rays[2].origin;
float3 ntr = rays[3].origin;
// Determine camera node location
const auto [x, y, z] = cam.get_translation();
float3 ftl = rays[0].origin + rays[0].direction * (cam.get_clip_far() - cam.get_clip_near());
float3 fbl = rays[1].origin + rays[1].direction * (cam.get_clip_far() - cam.get_clip_near());
float3 fbr = rays[2].origin + rays[2].direction * (cam.get_clip_far() - cam.get_clip_near());
float3 ftr = rays[3].origin + rays[3].direction * (cam.get_clip_far() - cam.get_clip_near());
quadtree_node_type node_x = static_cast<quadtree_node_type>((x / patch_side_length) + quadtree.resolution / 4);
quadtree_node_type node_y = static_cast<quadtree_node_type>((z / patch_side_length) + quadtree.resolution / 4);
quadtree_node_type node_location = geom::morton::encode<quadtree_node_type>(node_x, node_y);
quadtree.insert(quadtree.node(quadtree.max_depth, node_location));
// for (int i = 0; i < 8; ++i)
// std::cout << "ray or " << i << ": " << rays[i].origin << std::endl;
balance_quadtree();
geom::convex_hull<float> hull(6);
hull.planes[0] = geom::plane<float>(ftl, fbl, nbl);
hull.planes[1] = geom::plane<float>(ntr, nbr, fbr);
hull.planes[2] = geom::plane<float>(fbl, fbr, nbr);
hull.planes[3] = geom::plane<float>(ftl, ntl, ntr);
hull.planes[4] = geom::plane<float>(ntl, nbl, nbr);
hull.planes[5] = geom::plane<float>(ftr, fbr, fbl);
geom::sphere<float> sphere;
sphere.center = cam.get_translation();
//sphere.radius = patch_side_length;
sphere.radius = 1.0f;
// Determine camera position node
auto translation = cam.get_translation();
//visit_quadtree(cam.get_view_frustum().get_bounds(), quadtree_type::root);
visit_quadtree(sphere, quadtree_type::root);
for (const quadtree_node_type& node: quadtree)
{
if (!quadtree.is_leaf(node))
continue;
if (patches.find(node) == patches.end())
{
patch* node_patch = generate_patch(node);
patches[node] = node_patch;
scene_collection->add_object(node_patch->model_instance);
}
}
} }
); );
balance_quadtree();
//std::cout << "qsize: " << quadtree.size() << std::endl; //std::cout << "qsize: " << quadtree.size() << std::endl;
std::size_t qvis = 0; std::size_t qvis = 0;
@ -337,23 +315,30 @@ void terrain::balance_quadtree()
quadtree_node_type x, y; quadtree_node_type x, y;
geom::morton::decode(location, x, y); geom::morton::decode(location, x, y);
--depth;
if (x < quadtree.resolution - 1)
{
if (y < quadtree.resolution - 1)
nodes.insert(quadtree.node(depth, geom::morton::encode<quadtree_node_type>(x + 1, y + 1)));
if (y > 0)
nodes.insert(quadtree.node(depth, geom::morton::encode<quadtree_node_type>(x + 1, y - 1)));
}
// TODO!!!!
// DONT USE quadtree.resolution, use a depth-specific resolution
if (x > 0)
if (!quadtree.is_leaf(node))
{ {
if (y < quadtree.resolution - 1)
nodes.insert(quadtree.node(depth, geom::morton::encode<quadtree_node_type>(x - 1, y + 1)));
if (y > 0)
nodes.insert(quadtree.node(depth, geom::morton::encode<quadtree_node_type>(x - 1, y - 1)));
if (x < (quadtree.resolution / 4) - 1)
{
if (y < (quadtree.resolution / 4) - 1)
nodes.insert(quadtree.node(depth, geom::morton::encode<quadtree_node_type>(x + 1, y + 1)));
if (y > 0)
nodes.insert(quadtree.node(depth, geom::morton::encode<quadtree_node_type>(x + 1, y - 1)));
}
if (x > 0)
{
if (y < (quadtree.resolution / 4) - 1)
nodes.insert(quadtree.node(depth, geom::morton::encode<quadtree_node_type>(x - 1, y + 1)));
if (y > 0)
nodes.insert(quadtree.node(depth, geom::morton::encode<quadtree_node_type>(x - 1, y - 1)));
}
} }
} }
for (const auto& node: nodes) for (const auto& node: nodes)

+ 265
- 131
src/math/matrix.hpp View File

@ -33,7 +33,7 @@ namespace math {
/** /**
* *n* by *m* column-major matrix. * *n* by *m* column-major matrix.
* *
* @tparam T Matrix element data type.
* @tparam T Element type.
* @tparam N Number of columns. * @tparam N Number of columns.
* @tparam M Number of rows. * @tparam M Number of rows.
* *
@ -63,6 +63,58 @@ struct matrix
/// Array of matrix column vectors. /// Array of matrix column vectors.
column_vector_type columns[column_count]; column_vector_type columns[column_count];
/// @name Conversion
/// @{
/// @private
template <class U, std::size_t... I>
constexpr inline matrix<U, N, M> type_cast(std::index_sequence<I...>) const noexcept
{
return {vector<U, M>(columns[I])...};
}
/**
* Type-casts the elements of this matrix using `static_cast`.
*
* @tparam U Target element type.
*
* @return Matrix containing the type-casted elements.
*/
template <class U>
constexpr inline explicit operator matrix<U, N, M>() const noexcept
{
return type_cast<U>(std::make_index_sequence<N>{});
}
/// @private
template <std::size_t P, std::size_t O, std::size_t... I>
constexpr inline matrix<T, P, O> size_cast(std::index_sequence<I...>) const noexcept
{
if constexpr (O == M)
return {((I < N) ? columns[I] : matrix<T, P, O>::identity()[I]) ...};
else
return {((I < N) ? vector<T, O>(columns[I]) : matrix<T, P, O>::identity()[I]) ...};
}
/**
* Size-casts this matrix to a matrix with different dimensions. Casting to greater dimensions causes new elements to be set to identity matrix elements.
*
* @tparam P Target number of columns.
* @tparam O Target number of rows.
*
* @return *p* by *o* matrix.
*/
template <std::size_t P, std::size_t O>
constexpr inline explicit operator matrix<T, P, O>() const noexcept
{
return size_cast<P, O>(std::make_index_sequence<P>{});
}
/// @}
/// @name Column access
/// @{
/** /**
* Returns a reference to the column vector at a given index. * Returns a reference to the column vector at a given index.
* *
@ -90,25 +142,9 @@ struct matrix
/// @} /// @}
/** /**
* Returns a reference to the element at a given column-major index.
*
* @param i Column-major index of a matrix element.
*
* @return Reference to the element at column-major index @p i.
* Returns a reference to the first column vector.
*/ */
/// @{ /// @{
constexpr inline T& element(std::size_t i) noexcept
{
return columns[i / row_count][i % row_count];
}
constexpr inline const T& element(std::size_t i) const noexcept
{
return columns[i / row_count][i % row_count];
}
/// @}
/// Returns a reference to the first column vector.
/// @{
constexpr inline column_vector_type& front() noexcept constexpr inline column_vector_type& front() noexcept
{ {
return columns[0]; return columns[0];
@ -119,7 +155,9 @@ struct matrix
} }
/// @} /// @}
/// Returns a reference to the last column vector.
/**
* Returns a reference to the last column vector.
*/
/// @{ /// @{
constexpr inline column_vector_type& back() noexcept constexpr inline column_vector_type& back() noexcept
{ {
@ -131,6 +169,29 @@ struct matrix
} }
/// @} /// @}
/// @}
/// @name Element access
/// @{
/**
* Returns a reference to the element at a given column-major index.
*
* @param i Column-major index of a matrix element.
*
* @return Reference to the element at column-major index @p i.
*/
/// @{
constexpr inline T& element(std::size_t i) noexcept
{
return columns[i / row_count][i % row_count];
}
constexpr inline const T& element(std::size_t i) const noexcept
{
return columns[i / row_count][i % row_count];
}
/// @}
/** /**
* Returns a pointer to the first element. * Returns a pointer to the first element.
* *
@ -147,7 +208,14 @@ struct matrix
}; };
/// @} /// @}
/// Returns an iterator to the first column vector.
/// @}
/// @name Iterators
/// @{
/**
* Returns an iterator to the first column vector.
*/
/// @{ /// @{
constexpr inline column_vector_type* begin() noexcept constexpr inline column_vector_type* begin() noexcept
{ {
@ -163,7 +231,9 @@ struct matrix
} }
/// @} /// @}
/// Returns an iterator to the column vector following the last column vector.
/**
* Returns an iterator to the column vector following the last column vector.
*/
/// @{ /// @{
constexpr inline column_vector_type* end() noexcept constexpr inline column_vector_type* end() noexcept
{ {
@ -179,7 +249,9 @@ struct matrix
} }
/// @} /// @}
/// Returns a reverse iterator to the first column vector of the reversed matrix.
/**
* Returns a reverse iterator to the first column vector of the reversed matrix.
*/
/// @{ /// @{
constexpr inline std::reverse_iterator<column_vector_type*> rbegin() noexcept constexpr inline std::reverse_iterator<column_vector_type*> rbegin() noexcept
{ {
@ -195,7 +267,9 @@ struct matrix
} }
/// @} /// @}
/// Returns a reverse iterator to the column vector following the last column vector of the reversed matrix.
/**
* Returns a reverse iterator to the column vector following the last column vector of the reversed matrix.
*/
/// @{ /// @{
constexpr inline std::reverse_iterator<column_vector_type*> rend() noexcept constexpr inline std::reverse_iterator<column_vector_type*> rend() noexcept
{ {
@ -211,57 +285,27 @@ struct matrix
} }
/// @} /// @}
/// Returns the number of elements in the matrix.
constexpr inline std::size_t size() const noexcept
{
return element_count;
};
/// @}
/// @private
template <class U, std::size_t... I>
constexpr inline matrix<U, N, M> type_cast(std::index_sequence<I...>) const noexcept
{
return {vector<U, M>(columns[I])...};
}
/// @name Capacity
/// @{
/** /**
* Type-casts the elements of this matrix using `static_cast`.
*
* @tparam U Target element type.
*
* @return Matrix containing the type-casted elements.
* Returns the number of elements in the matrix.
*/ */
template <class U>
constexpr inline explicit operator matrix<U, N, M>() const noexcept
constexpr inline std::size_t size() const noexcept
{ {
return type_cast<U>(std::make_index_sequence<N>{});
}
return element_count;
};
/// @private
template <std::size_t P, std::size_t O, std::size_t... I>
constexpr inline matrix<T, P, O> size_cast(std::index_sequence<I...>) const noexcept
{
if constexpr (O == M)
return {((I < N) ? columns[I] : matrix<T, P, O>::identity()[I]) ...};
else
return {((I < N) ? vector<T, O>(columns[I]) : matrix<T, P, O>::identity()[I]) ...};
}
/// @}
/// @name Constants
/// @{
/** /**
* Size-casts this matrix to a matrix with different dimensions. Casting to greater dimensions causes new elements to be set to identity matrix elements.
*
* @tparam P Target number of columns.
* @tparam O Target number of rows.
*
* @return *p* by *o* matrix.
* Returns a zero matrix, where every element is equal to zero.
*/ */
template <std::size_t P, std::size_t O>
constexpr inline explicit operator matrix<T, P, O>() const noexcept
{
return size_cast<P, O>(std::make_index_sequence<P>{});
}
/// Returns a zero matrix, where every element is equal to zero.
static constexpr matrix zero() noexcept static constexpr matrix zero() noexcept
{ {
return {}; return {};
@ -277,7 +321,9 @@ struct matrix
return {(I ? column_vector_type::one() : column_vector_type::one()) ...}; return {(I ? column_vector_type::one() : column_vector_type::one()) ...};
} }
/// Returns a matrix of ones, where every element is equal to one.
/**
* Returns a matrix of ones, where every element is equal to one.
*/
static constexpr matrix one() noexcept static constexpr matrix one() noexcept
{ {
return one(std::make_index_sequence<column_count>{}); return one(std::make_index_sequence<column_count>{});
@ -297,11 +343,15 @@ struct matrix
return {identity_column(I, std::make_index_sequence<row_count>{}) ...}; return {identity_column(I, std::make_index_sequence<row_count>{}) ...};
} }
/// Returns an identity matrix, with ones on the main diagonal and zeros elsewhere.
/**
* Returns an identity matrix, with ones on the main diagonal and zeros elsewhere.
*/
static constexpr matrix identity() noexcept static constexpr matrix identity() noexcept
{ {
return identity(std::make_index_sequence<column_count>{}); return identity(std::make_index_sequence<column_count>{});
} }
/// @}
}; };
/// 2x2 matrix. /// 2x2 matrix.
@ -362,18 +412,6 @@ constexpr matrix add(const matrix& a, T b) noexcept;
template <class T, std::size_t N> template <class T, std::size_t N>
constexpr T determinant(const matrix<T, N, N>& m) noexcept; constexpr T determinant(const matrix<T, N, N>& m) noexcept;
/**
* Calculates the inverse of a square matrix.
*
* @param m Square matrix.
*
* @return Inverse of matrix @p m.
*
* @warning Currently only implemented for 2x2, 3x3, and 4x4 matrices.
*/
template <class T, std::size_t N>
constexpr matrix<T, N, N> inverse(const matrix<T, N, N>& m) noexcept;
/** /**
* Performs a component-wise multiplication of two matrices. * Performs a component-wise multiplication of two matrices.
* *
@ -418,6 +456,41 @@ constexpr matrix div(const matrix& a, T b) noexcept;
template <class T, std::size_t N, std::size_t M> template <class T, std::size_t N, std::size_t M>
constexpr matrix<T, N, M> div(T a, const matrix<T, N, M>& b) noexcept; constexpr matrix<T, N, M> div(T a, const matrix<T, N, M>& b) noexcept;
/**
* Extracts the Ith column from a matrix.
*
* @tparam I Index of a column.
* @tparam T Element type.
* @tparam N Number of columns.
* @tparam M Number of rows.
*
* @param m Matrix from which to extract a column.
*
* @return Reference to the Ith column of @p m.
*/
/// @{
template<std::size_t I, class T, std::size_t N, std::size_t M>
constexpr typename matrix<T, N, M>::column_vector_type& get(math::matrix<T, N, M>& m) noexcept;
template<std::size_t I, class T, std::size_t N, std::size_t M>
constexpr typename matrix<T, N, M>::column_vector_type&& get(math::matrix<T, N, M>&& m) noexcept;
template<std::size_t I, class T, std::size_t N, std::size_t M>
constexpr const typename matrix<T, N, M>::column_vector_type& get(const math::matrix<T, N, M>& m) noexcept;
template<std::size_t I, class T, std::size_t N, std::size_t M>
constexpr const typename matrix<T, N, M>::column_vector_type&& get(const math::matrix<T, N, M>&& m) noexcept;
/// @}
/**
* Calculates the inverse of a square matrix.
*
* @param m Square matrix.
*
* @return Inverse of matrix @p m.
*
* @warning Currently only implemented for 2x2, 3x3, and 4x4 matrices.
*/
template <class T, std::size_t N>
constexpr matrix<T, N, N> inverse(const matrix<T, N, N>& m) noexcept;
/** /**
* Creates a viewing transformation matrix. * Creates a viewing transformation matrix.
* *
@ -659,6 +732,86 @@ constexpr T determinant(const matrix& m) noexcept
m[0][1] * m[1][0] * m[2][2] * m[3][3] + m[0][0] * m[1][1] * m[2][2] * m[3][3]; m[0][1] * m[1][0] * m[2][2] * m[3][3] + m[0][0] * m[1][1] * m[2][2] * m[3][3];
} }
/// @private
template <class T, std::size_t N, std::size_t M, std::size_t... I>
constexpr inline matrix<T, N, M> componentwise_mul(const matrix<T, N, M>& a, const matrix<T, N, M>& b, std::index_sequence<I...>) noexcept
{
return {(a[I] * b[I]) ...};
}
template <class T, std::size_t N, std::size_t M>
constexpr matrix<T, N, M> componentwise_mul(const matrix<T, N, M>& a, const matrix<T, N, M>& b) noexcept
{
return componentwise_mul(a, b, std::make_index_sequence<N>{});
}
/// @private
template <class T, std::size_t N, std::size_t M, std::size_t... I>
constexpr inline matrix<T, N, M> div(const matrix<T, N, M>& a, const matrix<T, N, M>& b, std::index_sequence<I...>) noexcept
{
return {(a[I] / b[I]) ...};
}
template <class T, std::size_t N, std::size_t M>
constexpr matrix<T, N, M> div(const matrix<T, N, M>& a, const matrix<T, N, M>& b) noexcept
{
return div(a, b, std::make_index_sequence<N>{});
}
/// @private
template <class T, std::size_t N, std::size_t M, std::size_t... I>
constexpr inline matrix<T, N, M> div(const matrix<T, N, M>& a, T b, std::index_sequence<I...>) noexcept
{
return {(a[I] / b) ...};
}
template <class T, std::size_t N, std::size_t M>
constexpr matrix<T, N, M> div(const matrix<T, N, M>& a, T b) noexcept
{
return div(a, b, std::make_index_sequence<N>{});
}
/// @private
template <class T, std::size_t N, std::size_t M, std::size_t... I>
constexpr inline matrix<T, N, M> div(T a, const matrix<T, N, M>& b, std::index_sequence<I...>) noexcept
{
return {(a / b[I]) ...};
}
template <class T, std::size_t N, std::size_t M>
constexpr matrix<T, N, M> div(T a, const matrix<T, N, M>& b) noexcept
{
return div(a, b, std::make_index_sequence<N>{});
}
template<std::size_t I, class T, std::size_t N, std::size_t M>
constexpr inline typename matrix<T, N, M>::column_vector_type& get(math::matrix<T, N, M>& m) noexcept
{
static_assert(I < N);
return m.columns[I];
}
template<std::size_t I, class T, std::size_t N, std::size_t M>
constexpr inline typename matrix<T, N, M>::column_vector_type&& get(math::matrix<T, N, M>&& m) noexcept
{
static_assert(I < N);
return std::move(m.columns[I]);
}
template<std::size_t I, class T, std::size_t N, std::size_t M>
constexpr inline const typename matrix<T, N, M>::column_vector_type& get(const math::matrix<T, N, M>& m) noexcept
{
static_assert(I < N);
return m.columns[I];
}
template<std::size_t I, class T, std::size_t N, std::size_t M>
constexpr inline const typename matrix<T, N, M>::column_vector_type&& get(const math::matrix<T, N, M>&& m) noexcept
{
static_assert(I < N);
return std::move(m.columns[I]);
}
template <class T> template <class T>
constexpr matrix<T, 2, 2> inverse(const matrix<T, 2, 2>& m) noexcept constexpr matrix<T, 2, 2> inverse(const matrix<T, 2, 2>& m) noexcept
{ {
@ -723,58 +876,6 @@ constexpr matrix inverse(const matrix& m) noexcept
}; };
} }
/// @private
template <class T, std::size_t N, std::size_t M, std::size_t... I>
constexpr inline matrix<T, N, M> componentwise_mul(const matrix<T, N, M>& a, const matrix<T, N, M>& b, std::index_sequence<I...>) noexcept
{
return {(a[I] * b[I]) ...};
}
template <class T, std::size_t N, std::size_t M>
constexpr matrix<T, N, M> componentwise_mul(const matrix<T, N, M>& a, const matrix<T, N, M>& b) noexcept
{
return componentwise_mul(a, b, std::make_index_sequence<N>{});
}
/// @private
template <class T, std::size_t N, std::size_t M, std::size_t... I>
constexpr inline matrix<T, N, M> div(const matrix<T, N, M>& a, const matrix<T, N, M>& b, std::index_sequence<I...>) noexcept
{
return {(a[I] / b[I]) ...};
}
template <class T, std::size_t N, std::size_t M>
constexpr matrix<T, N, M> div(const matrix<T, N, M>& a, const matrix<T, N, M>& b) noexcept
{
return div(a, b, std::make_index_sequence<N>{});
}
/// @private
template <class T, std::size_t N, std::size_t M, std::size_t... I>
constexpr inline matrix<T, N, M> div(const matrix<T, N, M>& a, T b, std::index_sequence<I...>) noexcept
{
return {(a[I] / b) ...};
}
template <class T, std::size_t N, std::size_t M>
constexpr matrix<T, N, M> div(const matrix<T, N, M>& a, T b) noexcept
{
return div(a, b, std::make_index_sequence<N>{});
}
/// @private
template <class T, std::size_t N, std::size_t M, std::size_t... I>
constexpr inline matrix<T, N, M> div(T a, const matrix<T, N, M>& b, std::index_sequence<I...>) noexcept
{
return {(a / b[I]) ...};
}
template <class T, std::size_t N, std::size_t M>
constexpr matrix<T, N, M> div(T a, const matrix<T, N, M>& b) noexcept
{
return div(a, b, std::make_index_sequence<N>{});
}
template <class T> template <class T>
constexpr matrix<T, 4, 4> look_at(const vector<T, 3>& position, const vector<T, 3>& target, vector<T, 3> up) constexpr matrix<T, 4, 4> look_at(const vector<T, 3>& position, const vector<T, 3>& target, vector<T, 3> up)
{ {
@ -1238,4 +1339,37 @@ std::istream& operator>>(std::istream& is, matrix& m)
using namespace math::operators; using namespace math::operators;
// Structured binding support
namespace std
{
/**
* Provides access to the number of columns in a math::matrix as a compile-time constant expression.
*
* @tparam T Element type.
* @tparam N Number of columns.
* @tparam M Number of rows.
*/
template<class T, std::size_t N, std::size_t M>
struct tuple_size<math::matrix<T, N, M>>
{
/// Number of columns in the matrix.
static constexpr std::size_t value = math::matrix<T, N, M>::column_count;
};
/**
* Provides compile-time indexed access to the type of the columns in a math::matrix using a tuple-like interface.
*
* @tparam I Index of a column.
* @tparam T Element type.
* @tparam N Number of columns.
* @tparam M Number of rows.
*/
template<std::size_t I, class T, std::size_t N, std::size_t M>
struct tuple_element<I, math::matrix<T, N, M>>
{
/// Type of columns in the matrix.
using type = math::matrix<T, N, M>::column_vector_type;
};
}
#endif // ANTKEEPER_MATH_MATRIX_HPP #endif // ANTKEEPER_MATH_MATRIX_HPP

+ 87
- 86
src/math/vector.hpp View File

@ -23,6 +23,7 @@
#include <algorithm> #include <algorithm>
#include <cstddef> #include <cstddef>
#include <cmath> #include <cmath>
#include <concepts>
#include <istream> #include <istream>
#include <iterator> #include <iterator>
#include <ostream> #include <ostream>
@ -49,6 +50,51 @@ struct vector
/// Array of vector elements. /// Array of vector elements.
element_type elements[N]; element_type elements[N];
/// @name Conversion
/// @{
/// @private
template <class U, std::size_t... I>
constexpr inline vector<U, N> type_cast(std::index_sequence<I...>) const noexcept
{
return {static_cast<U>(elements[I])...};
}
/**
* Type-casts the elements of this vector using `static_cast`.
*
* @tparam U Target element type.
*
* @return Vector containing the type-casted elements.
*/
template <class U>
constexpr inline explicit operator vector<U, N>() const noexcept
{
return type_cast<U>(std::make_index_sequence<N>{});
}
/// @private
template <std::size_t M, std::size_t... I>
constexpr inline vector<T, M> size_cast(std::index_sequence<I...>) const noexcept
{
return {(I < N) ? elements[I] : T{0} ...};
}
/**
* Size-casts this vector to a vector with a different number of elements. Casting to a greater number of elements causes new elements to be set to zero.
*
* @tparam M Target number of elements.
*
* @return *m*-dimensional vector.
*/
template <std::size_t M>
constexpr inline explicit operator vector<T, M>() const noexcept
{
return size_cast<M>(std::make_index_sequence<M>{});
}
/// @}
/// @name Element access /// @name Element access
/// @{ /// @{
@ -250,47 +296,12 @@ struct vector
/// @} /// @}
/// @private
template <class U, std::size_t... I>
constexpr inline vector<U, N> type_cast(std::index_sequence<I...>) const noexcept
{
return {static_cast<U>(elements[I])...};
}
/**
* Type-casts the elements of this vector using `static_cast`.
*
* @tparam U Target element type.
*
* @return Vector containing the type-casted elements.
*/
template <class U>
constexpr inline explicit operator vector<U, N>() const noexcept
{
return type_cast<U>(std::make_index_sequence<N>{});
}
/// @private
template <std::size_t M, std::size_t... I>
constexpr inline vector<T, M> size_cast(std::index_sequence<I...>) const noexcept
{
return {(I < N) ? elements[I] : T{0} ...};
}
/// @name Constants
/// @{
/** /**
* Size-casts this vector to a vector with a different number of elements. Casting to a greater number of elements causes new elements to be set to zero.
*
* @tparam M Target number of elements.
*
* @return *m*-dimensional vector.
* Returns a zero vector, where every element is equal to zero.
*/ */
template <std::size_t M>
constexpr inline explicit operator vector<T, M>() const noexcept
{
return size_cast<M>(std::make_index_sequence<M>{});
}
/// Returns a zero vector, where every element is equal to zero.
static constexpr vector zero() noexcept static constexpr vector zero() noexcept
{ {
return {}; return {};
@ -306,11 +317,15 @@ struct vector
return {(I ? T{1} : T{1})...}; return {(I ? T{1} : T{1})...};
} }
/// Returns a vector of ones, where every element is equal to one.
/**
* Returns a vector of ones, where every element is equal to one.
*/
static constexpr vector one() noexcept static constexpr vector one() noexcept
{ {
return one(std::make_index_sequence<N>{}); return one(std::make_index_sequence<N>{});
} }
/// @}
}; };
/// Vector with two elements. /// Vector with two elements.
@ -883,14 +898,13 @@ constexpr inline bool any(const vector& x) noexcept
} }
/// @private /// @private
template <class T, std::size_t N, std::size_t... I>
template <std::floating_point T, std::size_t N, std::size_t... I>
constexpr inline vector<T, N> ceil(const vector<T, N>& x, std::index_sequence<I...>) constexpr inline vector<T, N> ceil(const vector<T, N>& x, std::index_sequence<I...>)
{ {
static_assert(std::is_floating_point<T>::value);
return {std::ceil(x[I])...}; return {std::ceil(x[I])...};
} }
template <class T, std::size_t N>
template <std::floating_point T, std::size_t N>
constexpr inline vector<T, N> ceil(const vector<T, N>& x) constexpr inline vector<T, N> ceil(const vector<T, N>& x)
{ {
return ceil(x, std::make_index_sequence<N>{}); return ceil(x, std::make_index_sequence<N>{});
@ -922,10 +936,9 @@ constexpr inline vector clamp(const vector& x, T min, T max)
return clamp(x, min, max, std::make_index_sequence<N>{}); return clamp(x, min, max, std::make_index_sequence<N>{});
} }
template <class T, std::size_t N>
template <std::floating_point T, std::size_t N>
vector<T, N> clamp_length(const vector<T, N>& x, T max_length) vector<T, N> clamp_length(const vector<T, N>& x, T max_length)
{ {
static_assert(std::is_floating_point<T>::value);
T length2 = sqr_length(x); T length2 = sqr_length(x);
return (length2 > max_length * max_length) ? (x * (max_length / std::sqrt(length2))) : x; return (length2 > max_length * max_length) ? (x * (max_length / std::sqrt(length2))) : x;
} }
@ -1013,56 +1026,52 @@ constexpr inline vector equal(const vector& x, const vector
} }
/// @private /// @private
template <class T, std::size_t N, std::size_t... I>
template <std::floating_point T, std::size_t N, std::size_t... I>
constexpr inline vector<T, N> floor(const vector<T, N>& x, std::index_sequence<I...>) constexpr inline vector<T, N> floor(const vector<T, N>& x, std::index_sequence<I...>)
{ {
static_assert(std::is_floating_point<T>::value);
return {std::floor(x[I])...}; return {std::floor(x[I])...};
} }
template <class T, std::size_t N>
template <std::floating_point T, std::size_t N>
constexpr inline vector<T, N> floor(const vector<T, N>& x) constexpr inline vector<T, N> floor(const vector<T, N>& x)
{ {
return floor(x, std::make_index_sequence<N>{}); return floor(x, std::make_index_sequence<N>{});
} }
/// @private /// @private
template <class T, std::size_t N, std::size_t... I>
template <std::floating_point T, std::size_t N, std::size_t... I>
constexpr inline vector<T, N> fma(const vector<T, N>& x, const vector<T, N>& y, const vector<T, N>& z, std::index_sequence<I...>) constexpr inline vector<T, N> fma(const vector<T, N>& x, const vector<T, N>& y, const vector<T, N>& z, std::index_sequence<I...>)
{ {
static_assert(std::is_floating_point<T>::value);
return {std::fma(x[I], y[I], z[I])...}; return {std::fma(x[I], y[I], z[I])...};
} }
template <class T, std::size_t N>
template <std::floating_point T, std::size_t N>
constexpr inline vector<T, N> fma(const vector<T, N>& x, const vector<T, N>& y, const vector<T, N>& z) constexpr inline vector<T, N> fma(const vector<T, N>& x, const vector<T, N>& y, const vector<T, N>& z)
{ {
return fma(x, y, z, std::make_index_sequence<N>{}); return fma(x, y, z, std::make_index_sequence<N>{});
} }
/// @private /// @private
template <class T, std::size_t N, std::size_t... I>
template <std::floating_point T, std::size_t N, std::size_t... I>
constexpr inline vector<T, N> fma(const vector<T, N>& x, T y, T z, std::index_sequence<I...>) constexpr inline vector<T, N> fma(const vector<T, N>& x, T y, T z, std::index_sequence<I...>)
{ {
static_assert(std::is_floating_point<T>::value);
return {std::fma(x[I], y, z)...}; return {std::fma(x[I], y, z)...};
} }
template <class T, std::size_t N>
template <std::floating_point T, std::size_t N>
constexpr inline vector<T, N> fma(const vector<T, N>& x, T y, T z) constexpr inline vector<T, N> fma(const vector<T, N>& x, T y, T z)
{ {
return fma(x, y, z, std::make_index_sequence<N>{}); return fma(x, y, z, std::make_index_sequence<N>{});
} }
/// @private /// @private
template <class T, std::size_t N, std::size_t... I>
template <std::floating_point T, std::size_t N, std::size_t... I>
constexpr inline vector<T, N> fract(const vector<T, N>& x, std::index_sequence<I...>) constexpr inline vector<T, N> fract(const vector<T, N>& x, std::index_sequence<I...>)
{ {
static_assert(std::is_floating_point<T>::value);
return {x[I] - std::floor(x[I])...}; return {x[I] - std::floor(x[I])...};
} }
template <class T, std::size_t N>
template <std::floating_point T, std::size_t N>
constexpr inline vector<T, N> fract(const vector<T, N>& x) constexpr inline vector<T, N> fract(const vector<T, N>& x)
{ {
return fract(x, std::make_index_sequence<N>{}); return fract(x, std::make_index_sequence<N>{});
@ -1122,16 +1131,15 @@ constexpr inline vector greater_than_equal(const vector& x, const
return greater_than_equal(x, y, std::make_index_sequence<N>{}); return greater_than_equal(x, y, std::make_index_sequence<N>{});
} }
template <class T, std::size_t N>
template <std::floating_point T, std::size_t N>
inline T inv_length(const vector<T, N>& x) inline T inv_length(const vector<T, N>& x)
{ {
return T{1} / length(x); return T{1} / length(x);
} }
template <class T, std::size_t N>
template <std::floating_point T, std::size_t N>
inline T length(const vector<T, N>& x) inline T length(const vector<T, N>& x)
{ {
static_assert(std::is_floating_point<T>::value);
return std::sqrt(sqr_length(x)); return std::sqrt(sqr_length(x));
} }
@ -1200,28 +1208,26 @@ constexpr inline T min(const vector& x)
} }
/// @private /// @private
template <class T, std::size_t N, std::size_t... I>
template <std::floating_point T, std::size_t N, std::size_t... I>
constexpr inline vector<T, N> mod(const vector<T, N>& x, const vector<T, N>& y, std::index_sequence<I...>) constexpr inline vector<T, N> mod(const vector<T, N>& x, const vector<T, N>& y, std::index_sequence<I...>)
{ {
static_assert(std::is_floating_point<T>::value);
return {std::fmod(x[I], y[I])...}; return {std::fmod(x[I], y[I])...};
} }
template <class T, std::size_t N>
template <std::floating_point T, std::size_t N>
constexpr inline vector<T, N> mod(const vector<T, N>& x, const vector<T, N>& y) constexpr inline vector<T, N> mod(const vector<T, N>& x, const vector<T, N>& y)
{ {
return mod(x, y, std::make_index_sequence<N>{}); return mod(x, y, std::make_index_sequence<N>{});
} }
/// @private /// @private
template <class T, std::size_t N, std::size_t... I>
template <std::floating_point T, std::size_t N, std::size_t... I>
constexpr inline vector<T, N> mod(const vector<T, N>& x, T y, std::index_sequence<I...>) constexpr inline vector<T, N> mod(const vector<T, N>& x, T y, std::index_sequence<I...>)
{ {
static_assert(std::is_floating_point<T>::value);
return {std::fmod(x[I], y)...}; return {std::fmod(x[I], y)...};
} }
template <class T, std::size_t N>
template <std::floating_point T, std::size_t N>
constexpr inline vector<T, N> mod(const vector<T, N>& x, T y) constexpr inline vector<T, N> mod(const vector<T, N>& x, T y)
{ {
return mod(x, y, std::make_index_sequence<N>{}); return mod(x, y, std::make_index_sequence<N>{});
@ -1266,7 +1272,7 @@ constexpr inline vector negate(const vector& x) noexcept
return negate(x, std::make_index_sequence<N>{}); return negate(x, std::make_index_sequence<N>{});
} }
template <class T, std::size_t N>
template <std::floating_point T, std::size_t N>
inline vector<T, N> normalize(const vector<T, N>& x) inline vector<T, N> normalize(const vector<T, N>& x)
{ {
return mul(x, inv_length(x)); return mul(x, inv_length(x));
@ -1299,56 +1305,52 @@ constexpr inline vector not_equal(const vector& x, const vector
} }
/// @private /// @private
template <class T, std::size_t N, std::size_t... I>
template <std::floating_point T, std::size_t N, std::size_t... I>
inline vector<T, N> pow(const vector<T, N>& x, const vector<T, N>& y, std::index_sequence<I...>) inline vector<T, N> pow(const vector<T, N>& x, const vector<T, N>& y, std::index_sequence<I...>)
{ {
static_assert(std::is_floating_point<T>::value);
return {std::pow(x[I], y[I])...}; return {std::pow(x[I], y[I])...};
} }
template <class T, std::size_t N>
template <std::floating_point T, std::size_t N>
inline vector<T, N> pow(const vector<T, N>& x, const vector<T, N>& y) inline vector<T, N> pow(const vector<T, N>& x, const vector<T, N>& y)
{ {
return pow(x, y, std::make_index_sequence<N>{}); return pow(x, y, std::make_index_sequence<N>{});
} }
/// @private /// @private
template <class T, std::size_t N, std::size_t... I>
template <std::floating_point T, std::size_t N, std::size_t... I>
inline vector<T, N> pow(const vector<T, N>& x, T y, std::index_sequence<I...>) inline vector<T, N> pow(const vector<T, N>& x, T y, std::index_sequence<I...>)
{ {
static_assert(std::is_floating_point<T>::value);
return {std::pow(x[I], y)...}; return {std::pow(x[I], y)...};
} }
template <class T, std::size_t N>
template <std::floating_point T, std::size_t N>
inline vector<T, N> pow(const vector<T, N>& x, T y) inline vector<T, N> pow(const vector<T, N>& x, T y)
{ {
return pow(x, y, std::make_index_sequence<N>{}); return pow(x, y, std::make_index_sequence<N>{});
} }
/// @private /// @private
template <class T, std::size_t N, std::size_t... I>
template <std::floating_point T, std::size_t N, std::size_t... I>
constexpr inline vector<T, N> round(const vector<T, N>& x, std::index_sequence<I...>) constexpr inline vector<T, N> round(const vector<T, N>& x, std::index_sequence<I...>)
{ {
static_assert(std::is_floating_point<T>::value);
return {std::round(x[I])...}; return {std::round(x[I])...};
} }
template <class T, std::size_t N>
template <std::floating_point T, std::size_t N>
constexpr inline vector<T, N> round(const vector<T, N>& x) constexpr inline vector<T, N> round(const vector<T, N>& x)
{ {
return round(x, std::make_index_sequence<N>{}); return round(x, std::make_index_sequence<N>{});
} }
/// @private /// @private
template <class T, std::size_t N, std::size_t... I>
template <std::floating_point T, std::size_t N, std::size_t... I>
constexpr inline vector<T, N> sign(const vector<T, N>& x, std::index_sequence<I...>) constexpr inline vector<T, N> sign(const vector<T, N>& x, std::index_sequence<I...>)
{ {
static_assert(std::is_floating_point<T>::value);
return {std::copysign(T{1}, x[I])...}; return {std::copysign(T{1}, x[I])...};
} }
template <class T, std::size_t N>
template <std::floating_point T, std::size_t N>
constexpr inline vector<T, N> sign(const vector<T, N>& x) constexpr inline vector<T, N> sign(const vector<T, N>& x)
{ {
return sign(x, std::make_index_sequence<N>{}); return sign(x, std::make_index_sequence<N>{});
@ -1367,14 +1369,13 @@ constexpr inline T sqr_length(const vector& x) noexcept
} }
/// @private /// @private
template <class T, std::size_t N, std::size_t... I>
template <std::floating_point T, std::size_t N, std::size_t... I>
inline vector<T, N> sqrt(const vector<T, N>& x, std::index_sequence<I...>) inline vector<T, N> sqrt(const vector<T, N>& x, std::index_sequence<I...>)
{ {
static_assert(std::is_floating_point<T>::value);
return {std::sqrt(x[I])...}; return {std::sqrt(x[I])...};
} }
template <class T, std::size_t N>
template <std::floating_point T, std::size_t N>
inline vector<T, N> sqrt(const vector<T, N>& x, const vector<T, N>& y) inline vector<T, N> sqrt(const vector<T, N>& x, const vector<T, N>& y)
{ {
return sqrt(x, std::make_index_sequence<N>{}); return sqrt(x, std::make_index_sequence<N>{});
@ -1439,14 +1440,13 @@ constexpr inline vector swizzle(const vector& x) no
} }
/// @private /// @private
template <class T, std::size_t N, std::size_t... I>
template <std::floating_point T, std::size_t N, std::size_t... I>
constexpr inline vector<T, N> trunc(const vector<T, N>& x, std::index_sequence<I...>) constexpr inline vector<T, N> trunc(const vector<T, N>& x, std::index_sequence<I...>)
{ {
static_assert(std::is_floating_point<T>::value);
return {std::trunc(x[I])...}; return {std::trunc(x[I])...};
} }
template <class T, std::size_t N>
template <std::floating_point T, std::size_t N>
constexpr inline vector<T, N> trunc(const vector<T, N>& x) constexpr inline vector<T, N> trunc(const vector<T, N>& x)
{ {
return trunc(x, std::make_index_sequence<N>{}); return trunc(x, std::make_index_sequence<N>{});
@ -1687,12 +1687,13 @@ namespace std
struct tuple_size<math::vector<T, N>> struct tuple_size<math::vector<T, N>>
{ {
/// Number of elements in the vector. /// Number of elements in the vector.
static constexpr std::size_t value = N;
static constexpr std::size_t value = math::vector<T, N>::element_count;
}; };
/** /**
* Provides compile-time indexed access to the type of the elements in a math::vector using a tuple-like interface. * Provides compile-time indexed access to the type of the elements in a math::vector using a tuple-like interface.
* *
* @tparam I Index of an element.
* @tparam T Element type. * @tparam T Element type.
* @tparam N Number of elements. * @tparam N Number of elements.
*/ */
@ -1700,7 +1701,7 @@ namespace std
struct tuple_element<I, math::vector<T, N>> struct tuple_element<I, math::vector<T, N>>
{ {
/// Type of elements in the vector. /// Type of elements in the vector.
using type = T;
using type = math::vector<T, N>::element_type;
}; };
} }

Loading…
Cancel
Save