Merge pull request #1 from BlackMATov/dev

Dev
This commit is contained in:
2020-11-27 05:11:39 +07:00
committed by GitHub
17 changed files with 5162 additions and 21 deletions
+1129
View File
File diff suppressed because it is too large Load Diff
+10 -3
View File
@@ -6,6 +6,13 @@
#pragma once
namespace vmath_hpp
{
}
#include "vmath_fwd.hpp"
#include "vmath_fun.hpp"
#include "vmath_ext.hpp"
#include "vmath_mat.hpp"
#include "vmath_mat_fun.hpp"
#include "vmath_vec.hpp"
#include "vmath_vec_fun.hpp"
+539
View File
@@ -0,0 +1,539 @@
/*******************************************************************************
* This file is part of the "https://github.com/blackmatov/vmath.hpp"
* For conditions of distribution and use, see copyright notice in LICENSE.md
* Copyright (C) 2020, by Matvey Cherevko (blackmatov@gmail.com)
******************************************************************************/
#pragma once
#include "vmath_fwd.hpp"
#include "vmath_fun.hpp"
#include "vmath_vec_fun.hpp"
#include "vmath_mat_fun.hpp"
//
// Units
//
namespace vmath_hpp
{
template < typename T > inline constexpr vec<T, 2> zero2{0, 0};
template < typename T > inline constexpr vec<T, 3> zero3{0, 0, 0};
template < typename T > inline constexpr vec<T, 4> zero4{0, 0, 0, 0};
template < typename T > inline constexpr vec<T, 2> unit2{1, 1};
template < typename T > inline constexpr vec<T, 3> unit3{1, 1, 1};
template < typename T > inline constexpr vec<T, 4> unit4{1, 1, 1, 1};
template < typename T > inline constexpr vec<T, 2> unit2_x{1, 0};
template < typename T > inline constexpr vec<T, 2> unit2_y{0, 1};
template < typename T > inline constexpr vec<T, 3> unit3_x{1, 0, 0};
template < typename T > inline constexpr vec<T, 3> unit3_y{0, 1, 0};
template < typename T > inline constexpr vec<T, 3> unit3_z{0, 0, 1};
template < typename T > inline constexpr vec<T, 4> unit4_x{1, 0, 0, 0};
template < typename T > inline constexpr vec<T, 4> unit4_y{0, 1, 0, 0};
template < typename T > inline constexpr vec<T, 4> unit4_z{0, 0, 1, 0};
template < typename T > inline constexpr vec<T, 4> unit4_w{0, 0, 0, 1};
template < typename T > inline constexpr mat<T, 2> zero2x2{0, 0, 0, 0};
template < typename T > inline constexpr mat<T, 3> zero3x3{0, 0, 0, 0, 0, 0, 0, 0, 0};
template < typename T > inline constexpr mat<T, 4> zero4x4{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
template < typename T > inline constexpr mat<T, 2> unit2x2{1, 1, 1, 1};
template < typename T > inline constexpr mat<T, 3> unit3x3{1, 1, 1, 1, 1, 1, 1, 1, 1};
template < typename T > inline constexpr mat<T, 4> unit4x4{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1};
template < typename T > inline constexpr mat<T, 2> identity2x2{1, 0, 0, 1};
template < typename T > inline constexpr mat<T, 3> identity3x3{1, 0, 0, 0, 1, 0, 0, 0, 1};
template < typename T > inline constexpr mat<T, 4> identity4x4{1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1};
}
//
// Hash
//
namespace vmath_hpp::detail
{
struct hash_combiner {
template < typename T >
[[nodiscard]] std::size_t operator()(std::size_t seed, const T& x) noexcept {
return (seed ^= std::hash<T>{}(x) + 0x9e3779b9 + (seed << 6) + ( seed >> 2));
}
};
template < typename T, size_t Size >
[[nodiscard]] std::size_t hash(const vec<T, Size>& v) noexcept {
return fold(hash_combiner{}, std::size_t{}, v);
}
template < typename T, size_t Size >
[[nodiscard]] std::size_t hash(const mat<T, Size>& m) noexcept {
return fold(hash_combiner{}, std::size_t{}, m);
}
}
namespace std
{
template < typename T, size_t Size >
struct hash<vmath_hpp::vec<T, Size>> {
size_t operator()(const vmath_hpp::vec<T, Size>& v) const noexcept {
return vmath_hpp::detail::hash(v);
}
};
template < typename T, size_t Size >
struct hash<vmath_hpp::mat<T, Size>> {
size_t operator()(const vmath_hpp::mat<T, Size>& m) const noexcept {
return vmath_hpp::detail::hash(m);
}
};
}
//
// Cast
//
namespace vmath_hpp
{
template < typename To, typename From >
[[nodiscard]] std::enable_if_t<
std::is_arithmetic_v<To> && std::is_arithmetic_v<From>
, To>
constexpr cast_to(From x) noexcept {
return static_cast<To>(x);
}
template < typename To, typename From, std::size_t Size >
[[nodiscard]] constexpr vec<To, Size> cast_to(const vec<From, Size>& v) {
return detail::map([](From x){ return cast_to<To>(x); }, v);
}
template < typename To, typename From, std::size_t Size >
[[nodiscard]] constexpr mat<To, Size> cast_to(const mat<From, Size>& m) {
return detail::map([](const vec<From, Size>& v){ return cast_to<To>(v); }, m);
}
}
//
// Access
//
namespace vmath_hpp
{
// component
template < typename T, std::size_t Size >
[[nodiscard]] constexpr T component(const vec<T, Size>& v, std::size_t index) {
return v[index];
}
template < typename T, std::size_t Size >
[[nodiscard]] constexpr vec<T, Size> component(vec<T, Size> v, std::size_t index, T x) {
v[index] = x;
return v;
}
// row
template < typename T, std::size_t Size >
[[nodiscard]] constexpr vec<T, Size> row(const mat<T, Size>& m, std::size_t index) {
return m.rows[index];
}
template < typename T, std::size_t Size >
[[nodiscard]] constexpr mat<T, Size> row(mat<T, Size> m, std::size_t index, const vec<T, Size>& v) {
m.rows[index] = v;
return m;
}
// column
namespace impl
{
template < typename T, std::size_t Size, std::size_t... Is >
[[nodiscard]] constexpr vec<T, Size> column_impl(const mat<T, Size>& m, std::size_t index, std::index_sequence<Is...>) {
return { m[Is][index]... };
}
template < typename T, std::size_t Size, std::size_t... Is >
[[nodiscard]] constexpr mat<T, Size> column_impl(const mat<T, Size>& m, std::size_t index, const vec<T, Size>& v, std::index_sequence<Is...>) {
return { component(m[Is], index, v[Is])... };
}
}
template < typename T, std::size_t Size >
[[nodiscard]] constexpr vec<T, Size> column(const mat<T, Size>& m, std::size_t index) {
return impl::column_impl(m, index, std::make_index_sequence<Size>{});
}
template < typename T, std::size_t Size >
[[nodiscard]] constexpr mat<T, Size> column(const mat<T, Size>& m, std::size_t index, const vec<T, Size>& v) {
return impl::column_impl(m, index, v, std::make_index_sequence<Size>{});
}
}
//
// Matrix Transform 3D
//
namespace vmath_hpp
{
// translate
template < typename T >
[[nodiscard]] constexpr mat<T, 4> translate(const vec<T, 3>& v) {
return {
{ 1, 0, 0, 0},
{ 0, 1, 0, 0},
{ 0, 0, 1, 0},
{v.x, v.y, v.z, 1}};
}
template < typename T >
[[nodiscard]] constexpr mat<T, 4> translate(const mat<T, 4>& m, const vec<T, 3>& v) {
return m * translate(v);
}
// rotate
template < typename T >
[[nodiscard]] mat<T, 4> rotate(T angle, const vec<T, 3>& axis) {
const T x = axis.x;
const T y = axis.y;
const T z = axis.z;
const T px = x * x;
const T py = y * y;
const T pz = z * z;
const T cs = cos(angle);
const T sn = sin(angle);
const T ics = T(1) - cs;
const T xym = x * y * ics;
const T xzm = x * z * ics;
const T yzm = y * z * ics;
const T xsn = x * sn;
const T ysn = y * sn;
const T zsn = z * sn;
return {
px * ics + cs, xym + zsn, xzm - ysn, 0,
xym - zsn, py * ics + cs, yzm + xsn, 0,
xzm + ysn, yzm - xsn, pz * ics + cs, 0,
0, 0, 0, 1};
}
template < typename T >
[[nodiscard]] mat<T, 4> rotate(const mat<T, 4>& m, T angle, const vec<T, 3>& axis) {
return m * rotate(angle, axis);
}
// scale
template < typename T >
[[nodiscard]] constexpr mat<T, 4> scale(const vec<T, 3>& v) {
return {
{v.x, 0, 0, 0},
{ 0, v.y, 0, 0},
{ 0, 0, v.z, 0},
{ 0, 0, 0, 1}};
}
template < typename T >
[[nodiscard]] constexpr mat<T, 4> scale(const mat<T, 4>& m, const vec<T, 3>& v) {
return m * scale(v);
}
// look_at
template < typename T >
[[nodiscard]] mat<T, 4> look_at_lh(const vec<T, 3>& eye, const vec<T, 3>& at, const vec<T, 3>& up) {
const vec<T, 3> az = normalize(at - eye);
const vec<T, 3> ax = normalize(cross(up, az));
const vec<T, 3> ay = cross(az, ax);
const T dx = dot(ax, eye);
const T dy = dot(ay, eye);
const T dz = dot(az, eye);
return {
ax.x, ay.x, az.x, 0,
ax.y, ay.y, az.y, 0,
ax.z, ay.z, az.z, 0,
-dx, -dy, -dz, 1};
}
template < typename T >
[[nodiscard]] mat<T, 4> look_at_rh(const vec<T, 3>& eye, const vec<T, 3>& at, const vec<T, 3>& up) {
const vec<T, 3> az = normalize(eye - at);
const vec<T, 3> ax = normalize(cross(up, az));
const vec<T, 3> ay = cross(az, ax);
const T dx = dot(ax, eye);
const T dy = dot(ay, eye);
const T dz = dot(az, eye);
return {
ax.x, ay.x, az.x, 0,
ax.y, ay.y, az.y, 0,
ax.z, ay.z, az.z, 0,
-dx, -dy, -dz, 1};
}
}
//
// Matrix Transform 2D
//
namespace vmath_hpp
{
// translate
template < typename T >
[[nodiscard]] constexpr mat<T, 3> translate(const vec<T, 2>& v) {
return {
{ 1, 0, 0},
{ 0, 1, 0},
{v.x, v.y, 1}};
}
template < typename T >
[[nodiscard]] constexpr mat<T, 3> translate(const mat<T, 3>& m, const vec<T, 2>& v) {
return m * translate(v);
}
// rotate
template < typename T >
[[nodiscard]] mat<T, 3> rotate(T angle) {
const T cs = cos(angle);
const T sn = sin(angle);
return {
cs, sn, 0,
-sn, cs, 0,
0, 0, 1};
}
template < typename T >
[[nodiscard]] mat<T, 3> rotate(const mat<T, 3>& m, T angle) {
return m * rotate(angle);
}
// scale
template < typename T >
[[nodiscard]] constexpr mat<T, 3> scale(const vec<T, 2>& v) {
return {
{v.x, 0, 0},
{ 0, v.y, 0},
{ 0, 0, 1}};
}
template < typename T >
[[nodiscard]] constexpr mat<T, 3> scale(const mat<T, 3>& m, const vec<T, 2>& v) {
return m * scale(v);
}
// shear
template < typename T >
[[nodiscard]] constexpr mat<T, 3> shear(const vec<T, 2>& v) {
return {
{ 1, v.y, 0},
{v.x, 1, 0},
{ 0, 0, 1}};
}
template < typename T >
[[nodiscard]] constexpr mat<T, 3> shear(const mat<T, 3>& m, const vec<T, 2>& v) {
return m * shear(v);
}
template < typename T >
[[nodiscard]] constexpr mat<T, 3> shear_x(T y) {
return {
{1, 0, 0},
{y, 1, 0},
{0, 0, 1}};
}
template < typename T >
[[nodiscard]] constexpr mat<T, 3> shear_x(const mat<T, 3>& m, T y) {
return m * shear_x(y);
}
template < typename T >
[[nodiscard]] constexpr mat<T, 3> shear_y(T x) {
return {
{1, x, 0},
{0, 1, 0},
{0, 0, 1}};
}
template < typename T >
[[nodiscard]] constexpr mat<T, 3> shear_y(const mat<T, 3>& m, T x) {
return m * shear_y(x);
}
}
//
// Matrix Projections
//
namespace vmath_hpp
{
// orthographic
template < typename T >
[[nodiscard]] mat<T, 4> orthographic_lh_zo(T left, T right, T bottom, T top, T znear, T zfar) {
const T sx = T(2) / (right - left);
const T sy = T(2) / (top - bottom);
const T sz = T(1) / (zfar - znear);
const T tx = - (right + left) / (right - left);
const T ty = - (top + bottom) / (top - bottom);
const T tz = - znear / (zfar - znear);
return {
sx, 0, 0, 0,
0, sy, 0, 0,
0, 0, sz, 0,
tx, ty, tz, 1};
}
template < typename T >
[[nodiscard]] mat<T, 4> orthographic_lh_no(T left, T right, T bottom, T top, T znear, T zfar) {
const T sx = T(2) / (right - left);
const T sy = T(2) / (top - bottom);
const T sz = T(2) / (zfar - znear);
const T tx = - (right + left) / (right - left);
const T ty = - (top + bottom) / (top - bottom);
const T tz = - (zfar + znear) / (zfar - znear);
return {
sx, 0, 0, 0,
0, sy, 0, 0,
0, 0, sz, 0,
tx, ty, tz, 1};
}
template < typename T >
[[nodiscard]] mat<T, 4> orthographic_rh_zo(T left, T right, T bottom, T top, T znear, T zfar) {
const T sx = T(2) / (right - left);
const T sy = T(2) / (top - bottom);
const T sz = -T(1) / (zfar - znear);
const T tx = - (right + left) / (right - left);
const T ty = - (top + bottom) / (top - bottom);
const T tz = - znear / (zfar - znear);
return {
sx, 0, 0, 0,
0, sy, 0, 0,
0, 0, sz, 0,
tx, ty, tz, 1};
}
template < typename T >
[[nodiscard]] mat<T, 4> orthographic_rh_no(T left, T right, T bottom, T top, T znear, T zfar) {
const T sx = T(2) / (right - left);
const T sy = T(2) / (top - bottom);
const T sz = -T(2) / (zfar - znear);
const T tx = - (right + left) / (right - left);
const T ty = - (top + bottom) / (top - bottom);
const T tz = - (zfar + znear) / (zfar - znear);
return {
sx, 0, 0, 0,
0, sy, 0, 0,
0, 0, sz, 0,
tx, ty, tz, 1};
}
// perspective
template < typename T >
[[nodiscard]] mat<T, 4> perspective_lh_zo(T fov, T aspect, T znear, T zfar) {
const T sy = T(1) / tan(fov * T(0.5));
const T sx = sy / aspect;
const T sz = zfar / (zfar - znear);
const T tz = (znear * zfar) / (znear - zfar);
return {
sx, 0, 0, 0,
0, sy, 0, 0,
0, 0, sz, 1,
0, 0, tz, 0};
}
template < typename T >
[[nodiscard]] mat<T, 4> perspective_lh_no(T fov, T aspect, T znear, T zfar) {
const T sy = T(1) / tan(fov * T(0.5));
const T sx = sy / aspect;
const T sz = (zfar + znear) / (zfar - znear);
const T tz = (T(2) * znear * zfar) / (znear - zfar);
return {
sx, 0, 0, 0,
0, sy, 0, 0,
0, 0, sz, 1,
0, 0, tz, 0};
}
template < typename T >
[[nodiscard]] mat<T, 4> perspective_rh_zo(T fov, T aspect, T znear, T zfar) {
const T sy = T(1) / tan(fov * T(0.5));
const T sx = sy / aspect;
const T sz = zfar / (znear - zfar);
const T tz = (znear * zfar) / (znear - zfar);
return {
sx, 0, 0, 0,
0, sy, 0, 0,
0, 0, sz, -1,
0, 0, tz, 0};
}
template < typename T >
[[nodiscard]] mat<T, 4> perspective_rh_no(T fov, T aspect, T znear, T zfar) {
const T sy = T(1) / tan(fov * T(0.5));
const T sx = sy / aspect;
const T sz = (zfar + znear) / (znear - zfar);
const T tz = (T(2) * znear * zfar) / (znear - zfar);
return {
sx, 0, 0, 0,
0, sy, 0, 0,
0, 0, sz, -1,
0, 0, tz, 0};
}
}
//
// Vector Transform
//
namespace vmath_hpp
{
// angle
template < typename T, std::size_t Size >
[[nodiscard]] T angle(const vec<T, Size>& x, const vec<T, Size>& y) {
return acos(dot(x, y) * rsqrt(length2(x) * length2(y)));
}
// rotate
template < typename T >
[[nodiscard]] vec<T, 2> rotate(const vec<T, 2>& v, T angle) {
const T cs = cos(angle);
const T sn = sin(angle);
return {
v.x * cs - v.y * sn,
v.x * sn + v.y * cs};
}
template < typename T >
[[nodiscard]] vec<T, 3> rotate(const vec<T, 3>& v, T angle, const vec<T, 3>& normal) {
return v * mat<T, 3>(rotate(angle, normal));
}
template < typename T >
[[nodiscard]] vec<T, 4> rotate(const vec<T, 4>& v, T angle, const vec<T, 3>& normal) {
return v * rotate(angle, normal);
}
}
+439
View File
@@ -0,0 +1,439 @@
/*******************************************************************************
* This file is part of the "https://github.com/blackmatov/vmath.hpp"
* For conditions of distribution and use, see copyright notice in LICENSE.md
* Copyright (C) 2020, by Matvey Cherevko (blackmatov@gmail.com)
******************************************************************************/
#pragma once
#include "vmath_fwd.hpp"
//
// Angle and Trigonometry Functions
//
namespace vmath_hpp
{
template < typename T >
[[nodiscard]] std::enable_if_t<std::is_floating_point_v<T>, T>
constexpr radians(T degrees) noexcept {
return degrees * T(0.01745329251994329576923690768489);
}
template < typename T >
[[nodiscard]] std::enable_if_t<std::is_floating_point_v<T>, T>
constexpr degrees(T radians) noexcept {
return radians * T(57.295779513082320876798154814105);
}
template < typename T >
[[nodiscard]] std::enable_if_t<std::is_floating_point_v<T>, T>
sin(T x) noexcept {
return std::sin(x);
}
template < typename T >
[[nodiscard]] std::enable_if_t<std::is_floating_point_v<T>, T>
cos(T x) noexcept {
return std::cos(x);
}
template < typename T >
[[nodiscard]] std::enable_if_t<std::is_floating_point_v<T>, T>
tan(T x) noexcept {
return std::tan(x);
}
template < typename T >
[[nodiscard]] std::enable_if_t<std::is_floating_point_v<T>, T>
asin(T x) noexcept {
return std::asin(x);
}
template < typename T >
[[nodiscard]] std::enable_if_t<std::is_floating_point_v<T>, T>
acos(T x) noexcept {
return std::acos(x);
}
template < typename T >
[[nodiscard]] std::enable_if_t<std::is_floating_point_v<T>, T>
atan(T x) noexcept {
return std::atan(x);
}
template < typename T >
[[nodiscard]] std::enable_if_t<std::is_floating_point_v<T>, T>
atan2(T y, T x) noexcept {
return std::atan2(y, x);
}
template < typename T >
[[nodiscard]] std::enable_if_t<std::is_floating_point_v<T>, T>
sinh(T x) noexcept {
return std::sinh(x);
}
template < typename T >
[[nodiscard]] std::enable_if_t<std::is_floating_point_v<T>, T>
cosh(T x) noexcept {
return std::cosh(x);
}
template < typename T >
[[nodiscard]] std::enable_if_t<std::is_floating_point_v<T>, T>
tanh(T x) noexcept {
return std::tanh(x);
}
template < typename T >
[[nodiscard]] std::enable_if_t<std::is_floating_point_v<T>, T>
asinh(T x) noexcept {
return std::asinh(x);
}
template < typename T >
[[nodiscard]] std::enable_if_t<std::is_floating_point_v<T>, T>
acosh(T x) noexcept {
return std::acosh(x);
}
template < typename T >
[[nodiscard]] std::enable_if_t<std::is_floating_point_v<T>, T>
atanh(T x) noexcept {
return std::atanh(x);
}
}
//
// Exponential Functions
//
namespace vmath_hpp
{
template < typename T >
[[nodiscard]] std::enable_if_t<std::is_floating_point_v<T>, T>
pow(T x, T y) noexcept {
return std::pow(x, y);
}
template < typename T >
[[nodiscard]] std::enable_if_t<std::is_floating_point_v<T>, T>
exp(T x) noexcept {
return std::exp(x);
}
template < typename T >
[[nodiscard]] std::enable_if_t<std::is_floating_point_v<T>, T>
log(T x) noexcept {
return std::log(x);
}
template < typename T >
[[nodiscard]] std::enable_if_t<std::is_floating_point_v<T>, T>
exp2(T x) noexcept {
return std::exp2(x);
}
template < typename T >
[[nodiscard]] std::enable_if_t<std::is_floating_point_v<T>, T>
log2(T x) noexcept {
return std::log2(x);
}
template < typename T >
[[nodiscard]] std::enable_if_t<std::is_floating_point_v<T>, T>
sqrt(T x) noexcept {
return std::sqrt(x);
}
template < typename T >
[[nodiscard]] std::enable_if_t<std::is_floating_point_v<T>, T>
rsqrt(T x) noexcept {
return T(1) / sqrt(x);
}
}
//
// Common Functions
//
namespace vmath_hpp
{
template < typename T >
[[nodiscard]] std::enable_if_t<std::is_unsigned_v<T>, T>
constexpr abs(T x) noexcept {
return x;
}
template < typename T >
[[nodiscard]] std::enable_if_t<std::is_signed_v<T>, T>
constexpr abs(T x) noexcept {
return x >= T(0) ? x : -x;
}
template < typename T >
[[nodiscard]] std::enable_if_t<std::is_arithmetic_v<T>, T>
constexpr sign(T x) noexcept {
return static_cast<T>((T(0) < x) - (x < T(0)));
}
template < typename T >
[[nodiscard]] std::enable_if_t<std::is_floating_point_v<T>, T>
constexpr reciprocal(T x) noexcept {
return T(1) / x;
}
template < typename T >
[[nodiscard]] std::enable_if_t<std::is_floating_point_v<T>, T>
floor(T x) noexcept {
return std::floor(x);
}
template < typename T >
[[nodiscard]] std::enable_if_t<std::is_floating_point_v<T>, T>
trunc(T x) noexcept {
return std::trunc(x);
}
template < typename T >
[[nodiscard]] std::enable_if_t<std::is_floating_point_v<T>, T>
round(T x) noexcept {
return std::round(x);
}
template < typename T >
[[nodiscard]] std::enable_if_t<std::is_floating_point_v<T>, T>
ceil(T x) noexcept {
return std::ceil(x);
}
template < typename T >
[[nodiscard]] std::enable_if_t<std::is_floating_point_v<T>, T>
fract(T x) noexcept {
return x - floor(x);
}
template < typename T >
[[nodiscard]] std::enable_if_t<std::is_floating_point_v<T>, T>
fmod(T x, T y) noexcept {
return std::fmod(x, y);
}
template < typename T >
[[nodiscard]] std::enable_if_t<std::is_floating_point_v<T>, T>
modf(T x, T* y) noexcept {
return std::modf(x, y);
}
template < typename T >
[[nodiscard]] std::enable_if_t<std::is_arithmetic_v<T>, T>
constexpr min(T x, T y) noexcept {
return std::min(x, y);
}
template < typename T >
[[nodiscard]] std::enable_if_t<std::is_arithmetic_v<T>, T>
constexpr max(T x, T y) noexcept {
return std::max(x, y);
}
template < typename T >
[[nodiscard]] std::enable_if_t<std::is_arithmetic_v<T>, T>
constexpr clamp(T x, T min_x, T max_x) noexcept {
return min(max(x, min_x), max_x);
}
template < typename T >
[[nodiscard]] std::enable_if_t<std::is_arithmetic_v<T>, T>
constexpr saturate(T x) noexcept {
return clamp(x, T(0), T(1));
}
template < typename T >
[[nodiscard]] std::enable_if_t<std::is_floating_point_v<T>, T>
constexpr lerp(T x, T y, T a) noexcept {
return x * (T(1) - a) + y * a;
}
template < typename T >
[[nodiscard]] std::enable_if_t<std::is_floating_point_v<T>, T>
constexpr step(T edge, T x) noexcept {
return x < edge ? T(0) : T(1);
}
template < typename T >
[[nodiscard]] std::enable_if_t<std::is_floating_point_v<T>, T>
constexpr smoothstep(T edge0, T edge1, T x) noexcept {
const T t = clamp((x - edge0) / (edge1 - edge0), T(0), T(1));
return t * t * (T(3) - T(2) * t);
}
template < typename T >
[[nodiscard]] std::enable_if_t<std::is_arithmetic_v<T>, bool>
isnan(T x) noexcept {
return std::isnan(x);
}
template < typename T >
[[nodiscard]] std::enable_if_t<std::is_arithmetic_v<T>, bool>
isinf(T x) noexcept {
return std::isinf(x);
}
template < typename T >
[[nodiscard]] std::enable_if_t<std::is_arithmetic_v<T>, bool>
isfinite(T x) noexcept {
return std::isfinite(x);
}
//
template < typename T >
[[nodiscard]] std::enable_if_t<std::is_floating_point_v<T>, T>
fma(T x, T y, T z) noexcept {
return std::fma(x, y, z);
}
template < typename T >
[[nodiscard]] std::enable_if_t<std::is_floating_point_v<T>, T>
frexp(T x, int* exp) noexcept {
return std::frexp(x, exp);
}
template < typename T >
[[nodiscard]] std::enable_if_t<std::is_floating_point_v<T>, T>
ldexp(T x, int exp) noexcept {
return std::ldexp(x, exp);
}
}
//
// Geometric Functions
//
namespace vmath_hpp
{
template < typename T >
[[nodiscard]] std::enable_if_t<std::is_arithmetic_v<T>, T>
constexpr dot(T x, T y) noexcept {
return x * y;
}
template < typename T >
[[nodiscard]] std::enable_if_t<std::is_arithmetic_v<T>, T>
constexpr length(T x) noexcept {
return abs(x);
}
template < typename T >
[[nodiscard]] std::enable_if_t<std::is_arithmetic_v<T>, T>
constexpr length2(T x) noexcept {
return dot(x, x);
}
template < typename T >
[[nodiscard]] std::enable_if_t<std::is_arithmetic_v<T>, T>
constexpr distance(T x, T y) noexcept {
return length(y - x);
}
template < typename T >
[[nodiscard]] std::enable_if_t<std::is_arithmetic_v<T>, T>
constexpr distance2(T x, T y) noexcept {
return length2(y - x);
}
template < typename T >
[[nodiscard]] std::enable_if_t<std::is_floating_point_v<T>, T>
normalize(T x) noexcept {
return x * rsqrt(dot(x, x));
}
template < typename T >
[[nodiscard]] std::enable_if_t<std::is_floating_point_v<T>, T>
constexpr faceforward(T n, T i, T nref) noexcept {
return dot(nref, i) < T(0) ? n : -n;
}
template < typename T >
[[nodiscard]] std::enable_if_t<std::is_floating_point_v<T>, T>
constexpr reflect(T i, T n) noexcept {
return i - n * dot(n, i) * T(2);
}
template < typename T >
[[nodiscard]] std::enable_if_t<std::is_floating_point_v<T>, T>
refract(T i, T n, T eta) noexcept {
const T d = dot(n, i);
const T k = T(1) - eta * eta * (T(1) - d * d);
return T(k >= T(0)) * (eta * i - (eta * d + sqrt(k)) * n);
}
}
//
// Scalar Relational Functions
//
namespace vmath_hpp
{
template < typename T >
[[nodiscard]] std::enable_if_t<std::is_arithmetic_v<T>, bool>
constexpr less(T x, T y) noexcept {
return x < y;
}
template < typename T >
[[nodiscard]] std::enable_if_t<std::is_arithmetic_v<T>, bool>
constexpr less_equal(T x, T y) noexcept {
return x <= y;
}
template < typename T >
[[nodiscard]] std::enable_if_t<std::is_arithmetic_v<T>, bool>
constexpr greater(T x, T y) noexcept {
return x > y;
}
template < typename T >
[[nodiscard]] std::enable_if_t<std::is_arithmetic_v<T>, bool>
constexpr greater_equal(T x, T y) noexcept {
return x >= y;
}
template < typename T >
[[nodiscard]] std::enable_if_t<std::is_arithmetic_v<T>, bool>
constexpr equal_to(T x, T y) noexcept {
return x == y;
}
template < typename T >
[[nodiscard]] std::enable_if_t<std::is_arithmetic_v<T>, bool>
constexpr equal_to(T x, T y, T epsilon) noexcept {
return abs(x - y) <= epsilon;
}
template < typename T >
[[nodiscard]] std::enable_if_t<std::is_arithmetic_v<T>, bool>
constexpr not_equal_to(T x, T y) noexcept {
return x != y;
}
template < typename T >
[[nodiscard]] std::enable_if_t<std::is_arithmetic_v<T>, bool>
constexpr not_equal_to(T x, T y, T epsilon) noexcept {
return abs(x - y) > epsilon;
}
template < typename T >
[[nodiscard]] std::enable_if_t<std::is_arithmetic_v<T>, bool>
constexpr any(T x) noexcept {
return !!x;
}
template < typename T >
[[nodiscard]] std::enable_if_t<std::is_arithmetic_v<T>, bool>
constexpr all(T x) noexcept {
return !!x;
}
}
+84
View File
@@ -0,0 +1,84 @@
/*******************************************************************************
* This file is part of the "https://github.com/blackmatov/vmath.hpp"
* For conditions of distribution and use, see copyright notice in LICENSE.md
* Copyright (C) 2020, by Matvey Cherevko (blackmatov@gmail.com)
******************************************************************************/
#pragma once
#include <cmath>
#include <cstddef>
#include <algorithm>
#include <functional>
#include <stdexcept>
#include <type_traits>
#include <utility>
namespace vmath_hpp
{
template < typename T, std::size_t Size >
class vec;
using bool2 = vec<bool, 2>;
using bool3 = vec<bool, 3>;
using bool4 = vec<bool, 4>;
using int2 = vec<int, 2>;
using int3 = vec<int, 3>;
using int4 = vec<int, 4>;
using uint2 = vec<unsigned, 2>;
using uint3 = vec<unsigned, 3>;
using uint4 = vec<unsigned, 4>;
using float2 = vec<float, 2>;
using float3 = vec<float, 3>;
using float4 = vec<float, 4>;
using double2 = vec<double, 2>;
using double3 = vec<double, 3>;
using double4 = vec<double, 4>;
using size2 = vec<std::size_t, 2>;
using size3 = vec<std::size_t, 3>;
using size4 = vec<std::size_t, 4>;
using ptrdiff2 = vec<std::ptrdiff_t, 2>;
using ptrdiff3 = vec<std::ptrdiff_t, 3>;
using ptrdiff4 = vec<std::ptrdiff_t, 4>;
}
namespace vmath_hpp
{
template < typename T, std::size_t Size >
class mat;
using bool2x2 = mat<bool, 2>;
using bool3x3 = mat<bool, 3>;
using bool4x4 = mat<bool, 4>;
using int2x2 = mat<int, 2>;
using int3x3 = mat<int, 3>;
using int4x4 = mat<int, 4>;
using uint2x2 = mat<unsigned, 2>;
using uint3x3 = mat<unsigned, 3>;
using uint4x4 = mat<unsigned, 4>;
using float2x2 = mat<float, 2>;
using float3x3 = mat<float, 3>;
using float4x4 = mat<float, 4>;
using double2x2 = mat<double, 2>;
using double3x3 = mat<double, 3>;
using double4x4 = mat<double, 4>;
using size2x2 = mat<std::size_t, 2>;
using size3x3 = mat<std::size_t, 3>;
using size4x4 = mat<std::size_t, 4>;
using ptrdiff2x2 = mat<std::ptrdiff_t, 2>;
using ptrdiff3x3 = mat<std::ptrdiff_t, 3>;
using ptrdiff4x4 = mat<std::ptrdiff_t, 4>;
}
+224
View File
@@ -0,0 +1,224 @@
/*******************************************************************************
* This file is part of the "https://github.com/blackmatov/vmath.hpp"
* For conditions of distribution and use, see copyright notice in LICENSE.md
* Copyright (C) 2020, by Matvey Cherevko (blackmatov@gmail.com)
******************************************************************************/
#pragma once
#include "vmath_fwd.hpp"
#include "vmath_vec.hpp"
#include "vmath_vec_fun.hpp"
namespace vmath_hpp::detail
{
template < typename T, std::size_t Size >
class mat_base;
template < typename T >
class mat_base<T, 2> {
public:
using row_type = vec<T, 2>;
row_type rows[2] = {
{1, 0},
{0, 1}};
public:
mat_base() = default;
constexpr explicit mat_base(T v)
: rows{
row_type{v, 0},
row_type{0, v}} {}
constexpr mat_base(
T m11, T m12,
T m21, T m22)
: rows{
row_type{m11, m12},
row_type{m21, m22}} {}
constexpr mat_base(
const row_type& row0,
const row_type& row1)
: rows{row0, row1} {}
constexpr explicit mat_base(
const mat_base<T, 3>& other)
: rows{
row_type{other.rows[0]},
row_type{other.rows[1]}} {}
constexpr explicit mat_base(
const mat_base<T, 4>& other)
: rows{
row_type{other.rows[0]},
row_type{other.rows[1]}} {}
};
template < typename T >
class mat_base<T, 3> {
public:
using row_type = vec<T, 3>;
row_type rows[3] = {
{1, 0, 0},
{0, 1, 0},
{0, 0, 1}};
public:
mat_base() = default;
constexpr explicit mat_base(T v)
: rows{
row_type{v, 0, 0},
row_type{0, v, 0},
row_type{0, 0, v}} {}
constexpr mat_base(
T m11, T m12, T m13,
T m21, T m22, T m23,
T m31, T m32, T m33)
: rows{
row_type{m11, m12, m13},
row_type{m21, m22, m23},
row_type{m31, m32, m33}} {}
constexpr mat_base(
const row_type& row0,
const row_type& row1,
const row_type& row2)
: rows{row0, row1, row2} {}
constexpr explicit mat_base(
const mat_base<T, 2>& other)
: rows{
row_type{other.rows[0], 0},
row_type{other.rows[1], 0},
row_type{0, 0, 1}} {}
constexpr explicit mat_base(
const mat_base<T, 4>& other)
: rows{
row_type{other.rows[0]},
row_type{other.rows[1]},
row_type{other.rows[2]}} {}
};
template < typename T >
class mat_base<T, 4> {
public:
using row_type = vec<T, 4>;
row_type rows[4] = {
{1, 0, 0, 0},
{0, 1, 0, 0},
{0, 0, 1, 0},
{0, 0, 0, 1}};
public:
mat_base() = default;
constexpr explicit mat_base(T v)
: rows{
row_type{v, 0, 0, 0},
row_type{0, v, 0, 0},
row_type{0, 0, v, 0},
row_type{0, 0, 0, v}} {}
constexpr mat_base(
T m11, T m12, T m13, T m14,
T m21, T m22, T m23, T m24,
T m31, T m32, T m33, T m34,
T m41, T m42, T m43, T m44)
: rows{
row_type{m11, m12, m13, m14},
row_type{m21, m22, m23, m24},
row_type{m31, m32, m33, m34},
row_type{m41, m42, m43, m44}} {}
constexpr mat_base(
const row_type& row0,
const row_type& row1,
const row_type& row2,
const row_type& row3)
: rows{row0, row1, row2, row3} {}
constexpr explicit mat_base(
const mat_base<T, 2>& other)
: rows{
row_type{other.rows[0], 0, 0},
row_type{other.rows[1], 0, 0},
row_type{0, 0, 1, 0},
row_type{0, 0, 0, 1}} {}
constexpr explicit mat_base(
const mat_base<T, 3>& other)
: rows{
row_type{other.rows[0], 0},
row_type{other.rows[1], 0},
row_type{other.rows[2], 0},
row_type{0, 0, 0, 1}} {}
};
}
namespace vmath_hpp
{
template < typename T, std::size_t Size >
class mat final : public detail::mat_base<T, Size> {
public:
using self_type = mat;
using base_type = detail::mat_base<T, Size>;
public:
using row_type = vec<T, Size>;
using pointer = row_type*;
using const_pointer = const row_type*;
using reference = row_type&;
using const_reference = const row_type&;
static constexpr std::size_t size = Size;
public:
using base_type::mat_base;
using base_type::rows;
mat() = default;
mat(mat&&) = default;
mat& operator=(mat&&) = default;
mat(const mat&) = default;
mat& operator=(const mat&) = default;
void swap(mat& other) noexcept(std::is_nothrow_swappable_v<T>) {
for ( std::size_t i = 0; i < Size; ++i ) {
using std::swap;
swap((*this)[i], other[i]);
}
}
[[nodiscard]] constexpr reference operator[](std::size_t index) noexcept {
return rows[index];
}
[[nodiscard]] constexpr const_reference operator[](std::size_t index) const noexcept {
return rows[index];
}
[[nodiscard]] constexpr reference at(std::size_t index) {
if ( index >= Size ) {
throw std::out_of_range("mat::at");
}
return rows[index];
}
[[nodiscard]] constexpr const_reference at(std::size_t index) const {
if ( index >= Size ) {
throw std::out_of_range("mat::at");
}
return rows[index];
}
};
template < typename T, std::size_t Size >
void swap(mat<T, Size>& l, mat<T, Size>& r) noexcept(noexcept(l.swap(r))) {
l.swap(r);
}
}
+565
View File
@@ -0,0 +1,565 @@
/*******************************************************************************
* This file is part of the "https://github.com/blackmatov/vmath.hpp"
* For conditions of distribution and use, see copyright notice in LICENSE.md
* Copyright (C) 2020, by Matvey Cherevko (blackmatov@gmail.com)
******************************************************************************/
#pragma once
#include "vmath_fwd.hpp"
#include "vmath_fun.hpp"
#include "vmath_mat.hpp"
#include "vmath_vec.hpp"
#include "vmath_vec_fun.hpp"
namespace vmath_hpp::detail
{
namespace impl
{
template < typename A, std::size_t Size, typename F, std::size_t... Is >
[[nodiscard]] constexpr auto map_impl(F&& f, const mat<A, Size>& a, std::index_sequence<Is...>)
-> mat<typename std::invoke_result_t<F, vec<A, Size>>::value_type, Size>
{
return { f(a[Is])... };
}
template < typename A, typename B, std::size_t Size, typename F, std::size_t... Is >
[[nodiscard]] constexpr auto zip_impl(F&& f, const mat<A, Size>& a, const mat<B, Size>& b, std::index_sequence<Is...>)
-> mat<typename std::invoke_result_t<F, vec<A, Size>, vec<B, Size>>::value_type, Size>
{
return { f(a[Is], b[Is])... };
}
template < typename A, typename B, typename C, std::size_t Size, typename F, std::size_t... Is >
[[nodiscard]] constexpr auto zip_impl(F&& f, const mat<A, Size>& a, const mat<B, Size>& b, const mat<C, Size>& c, std::index_sequence<Is...>)
-> mat<typename std::invoke_result_t<F, vec<A, Size>, vec<B, Size>, vec<C, Size>>::value_type, Size>
{
return { f(a[Is], b[Is], c[Is])... };
}
template < typename A, typename B, std::size_t Size, typename F, std::size_t... Is >
[[nodiscard]] constexpr A fold_impl(F&& f, A init, const mat<B, Size>& b, std::index_sequence<Is...>) {
return ((init = f(std::move(init), b[Is])), ...);
}
template < typename A, typename B, typename C, std::size_t Size, typename F, std::size_t... Is >
[[nodiscard]] constexpr A fold_impl(F&& f, A init, const mat<B, Size>& b, const mat<C, Size>& c, std::index_sequence<Is...>) {
return ((init = f(std::move(init), b[Is], c[Is])), ...);
}
template < typename A, std::size_t Size, typename F, std::size_t I, std::size_t... Is >
[[nodiscard]] constexpr vec<A, Size> fold1_impl(F&& f, const mat<A, Size>& a, std::index_sequence<I, Is...>) {
vec<A, Size> init = a[I];
return ((init = f(std::move(init), a[Is])), ...);
}
}
template < typename A, std::size_t Size, typename F >
[[nodiscard]] constexpr auto map(F&& f, const mat<A, Size>& a)
-> mat<typename std::invoke_result_t<F, vec<A, Size>>::value_type, Size>
{
return impl::map_impl(std::forward<F>(f), a, std::make_index_sequence<Size>{});
}
template < typename A, typename B, std::size_t Size, typename F >
[[nodiscard]] constexpr auto zip(F&& f, const mat<A, Size>& a, const mat<B, Size>& b)
-> mat<typename std::invoke_result_t<F, vec<A, Size>, vec<B, Size>>::value_type, Size>
{
return impl::zip_impl(std::forward<F>(f), a, b, std::make_index_sequence<Size>{});
}
template < typename A, typename B, typename C, std::size_t Size, typename F >
[[nodiscard]] constexpr auto zip(F&& f, const mat<A, Size>& a, const mat<B, Size>& b, const mat<C, Size>& c)
-> mat<typename std::invoke_result_t<F, vec<A, Size>, vec<B, Size>, vec<C, Size>>::value_type, Size>
{
return impl::zip_impl(std::forward<F>(f), a, b, c, std::make_index_sequence<Size>{});
}
template < typename A, typename B, std::size_t Size, typename F >
[[nodiscard]] constexpr A fold(F&& f, A init, const mat<B, Size>& b) {
return impl::fold_impl(std::forward<F>(f), std::move(init), b, std::make_index_sequence<Size>{});
}
template < typename A, typename B, typename C, std::size_t Size, typename F >
[[nodiscard]] constexpr A fold(F&& f, A init, const mat<B, Size>& b, const mat<C, Size>& c) {
return impl::fold_impl(std::forward<F>(f), std::move(init), b, c, std::make_index_sequence<Size>{});
}
template < typename A, std::size_t Size, typename F >
[[nodiscard]] constexpr vec<A, Size> fold1(F&& f, const mat<A, Size>& a) {
return impl::fold1_impl(std::forward<F>(f), a, std::make_index_sequence<Size>{});
}
}
//
// Operators
//
namespace vmath_hpp
{
// -operator
template < typename T, std::size_t Size >
[[nodiscard]] constexpr mat<T, Size> operator-(const mat<T, Size>& xs) {
return map(std::negate<>(), xs);
}
// operator+
template < typename T, std::size_t Size >
[[nodiscard]] constexpr mat<T, Size> operator+(const mat<T, Size>& xs, T y) {
return map([y](const vec<T, Size>& x){ return x + y; }, xs);
}
template < typename T, std::size_t Size >
[[nodiscard]] constexpr mat<T, Size> operator+(T x, const mat<T, Size>& ys) {
return map([x](const vec<T, Size>& y){ return x + y; }, ys);
}
template < typename T, std::size_t Size >
[[nodiscard]] constexpr mat<T, Size> operator+(const mat<T, Size>& xs, const mat<T, Size>& ys) {
return zip(std::plus<>(), xs, ys);
}
// operator+=
template < typename T, std::size_t Size >
constexpr mat<T, Size>& operator+=(mat<T, Size>& xs, T y) {
return (xs = xs + y);
}
template < typename T, std::size_t Size >
constexpr mat<T, Size>& operator+=(mat<T, Size>& xs, const mat<T, Size>& ys) {
return (xs = xs + ys);
}
// operator-
template < typename T, std::size_t Size >
[[nodiscard]] constexpr mat<T, Size> operator-(const mat<T, Size>& xs, T y) {
return map([y](const vec<T, Size>& x){ return x - y; }, xs);
}
template < typename T, std::size_t Size >
[[nodiscard]] constexpr mat<T, Size> operator-(T x, const mat<T, Size>& ys) {
return map([x](const vec<T, Size>& y){ return x - y; }, ys);
}
template < typename T, std::size_t Size >
[[nodiscard]] constexpr mat<T, Size> operator-(const mat<T, Size>& xs, const mat<T, Size>& ys) {
return zip(std::minus<>(), xs, ys);
}
// operator-=
template < typename T, std::size_t Size >
constexpr mat<T, Size>& operator-=(mat<T, Size>& xs, T y) {
return (xs = xs - y);
}
template < typename T, std::size_t Size >
constexpr mat<T, Size>& operator-=(mat<T, Size>& xs, const mat<T, Size>& ys) {
return (xs = xs - ys);
}
// operator*
template < typename T, std::size_t Size >
[[nodiscard]] constexpr mat<T, Size> operator*(const mat<T, Size>& xs, T y) {
return map([y](const vec<T, Size>& x){ return x * y; }, xs);
}
template < typename T, std::size_t Size >
[[nodiscard]] constexpr mat<T, Size> operator*(T x, const mat<T, Size>& ys) {
return map([x](const vec<T, Size>& y){ return x * y; }, ys);
}
template < typename T >
[[nodiscard]] constexpr vec<T, 2> operator*(const vec<T, 2>& xs, const mat<T, 2>& ys) {
return {
xs.x * ys[0][0] + xs.y * ys[1][0],
xs.x * ys[0][1] + xs.y * ys[1][1]};
}
template < typename T >
[[nodiscard]] constexpr mat<T, 2> operator*(const mat<T, 2>& xs, const mat<T, 2>& ys) {
return {
xs[0][0] * ys[0][0] + xs[0][1] * ys[1][0],
xs[0][0] * ys[0][1] + xs[0][1] * ys[1][1],
xs[1][0] * ys[0][0] + xs[1][1] * ys[1][0],
xs[1][0] * ys[0][1] + xs[1][1] * ys[1][1]};
}
template < typename T >
[[nodiscard]] constexpr vec<T, 3> operator*(const vec<T, 3>& xs, const mat<T, 3>& ys) {
return {
xs.x * ys[0][0] + xs.y * ys[1][0] + xs.z * ys[2][0],
xs.x * ys[0][1] + xs.y * ys[1][1] + xs.z * ys[2][1],
xs.x * ys[0][2] + xs.y * ys[1][2] + xs.z * ys[2][2]};
}
template < typename T >
[[nodiscard]] constexpr mat<T, 3> operator*(const mat<T, 3>& xs, const mat<T, 3>& ys) {
return {
xs[0][0] * ys[0][0] + xs[0][1] * ys[1][0] + xs[0][2] * ys[2][0],
xs[0][0] * ys[0][1] + xs[0][1] * ys[1][1] + xs[0][2] * ys[2][1],
xs[0][0] * ys[0][2] + xs[0][1] * ys[1][2] + xs[0][2] * ys[2][2],
xs[1][0] * ys[0][0] + xs[1][1] * ys[1][0] + xs[1][2] * ys[2][0],
xs[1][0] * ys[0][1] + xs[1][1] * ys[1][1] + xs[1][2] * ys[2][1],
xs[1][0] * ys[0][2] + xs[1][1] * ys[1][2] + xs[1][2] * ys[2][2],
xs[2][0] * ys[0][0] + xs[2][1] * ys[1][0] + xs[2][2] * ys[2][0],
xs[2][0] * ys[0][1] + xs[2][1] * ys[1][1] + xs[2][2] * ys[2][1],
xs[2][0] * ys[0][2] + xs[2][1] * ys[1][2] + xs[2][2] * ys[2][2]};
}
template < typename T >
[[nodiscard]] constexpr vec<T, 4> operator*(const vec<T, 4>& xs, const mat<T, 4>& ys) {
return {
xs.x * ys[0][0] + xs.y * ys[1][0] + xs.z * ys[2][0] + xs.w * ys[3][0],
xs.x * ys[0][1] + xs.y * ys[1][1] + xs.z * ys[2][1] + xs.w * ys[3][1],
xs.x * ys[0][2] + xs.y * ys[1][2] + xs.z * ys[2][2] + xs.w * ys[3][2],
xs.x * ys[0][3] + xs.y * ys[1][3] + xs.z * ys[2][3] + xs.w * ys[3][3]};
}
template < typename T >
[[nodiscard]] constexpr mat<T, 4> operator*(const mat<T, 4>& xs, const mat<T, 4>& ys) {
return {
xs[0][0] * ys[0][0] + xs[0][1] * ys[1][0] + xs[0][2] * ys[2][0] + xs[0][3] * ys[3][0],
xs[0][0] * ys[0][1] + xs[0][1] * ys[1][1] + xs[0][2] * ys[2][1] + xs[0][3] * ys[3][1],
xs[0][0] * ys[0][2] + xs[0][1] * ys[1][2] + xs[0][2] * ys[2][2] + xs[0][3] * ys[3][2],
xs[0][0] * ys[0][3] + xs[0][1] * ys[1][3] + xs[0][2] * ys[2][3] + xs[0][3] * ys[3][3],
xs[1][0] * ys[0][0] + xs[1][1] * ys[1][0] + xs[1][2] * ys[2][0] + xs[1][3] * ys[3][0],
xs[1][0] * ys[0][1] + xs[1][1] * ys[1][1] + xs[1][2] * ys[2][1] + xs[1][3] * ys[3][1],
xs[1][0] * ys[0][2] + xs[1][1] * ys[1][2] + xs[1][2] * ys[2][2] + xs[1][3] * ys[3][2],
xs[1][0] * ys[0][3] + xs[1][1] * ys[1][3] + xs[1][2] * ys[2][3] + xs[1][3] * ys[3][3],
xs[2][0] * ys[0][0] + xs[2][1] * ys[1][0] + xs[2][2] * ys[2][0] + xs[2][3] * ys[3][0],
xs[2][0] * ys[0][1] + xs[2][1] * ys[1][1] + xs[2][2] * ys[2][1] + xs[2][3] * ys[3][1],
xs[2][0] * ys[0][2] + xs[2][1] * ys[1][2] + xs[2][2] * ys[2][2] + xs[2][3] * ys[3][2],
xs[2][0] * ys[0][3] + xs[2][1] * ys[1][3] + xs[2][2] * ys[2][3] + xs[2][3] * ys[3][3],
xs[3][0] * ys[0][0] + xs[3][1] * ys[1][0] + xs[3][2] * ys[2][0] + xs[3][3] * ys[3][0],
xs[3][0] * ys[0][1] + xs[3][1] * ys[1][1] + xs[3][2] * ys[2][1] + xs[3][3] * ys[3][1],
xs[3][0] * ys[0][2] + xs[3][1] * ys[1][2] + xs[3][2] * ys[2][2] + xs[3][3] * ys[3][2],
xs[3][0] * ys[0][3] + xs[3][1] * ys[1][3] + xs[3][2] * ys[2][3] + xs[3][3] * ys[3][3]};
}
// operator*=
template < typename T, std::size_t Size >
constexpr mat<T, Size>& operator*=(mat<T, Size>& xs, T y) {
return (xs = xs * y);
}
template < typename T, std::size_t Size >
constexpr vec<T, Size>& operator*=(vec<T, Size>& xs, const mat<T, Size>& ys) {
return (xs = xs * ys);
}
template < typename T, std::size_t Size >
constexpr mat<T, Size>& operator*=(mat<T, Size>& xs, const mat<T, Size>& ys) {
return (xs = xs * ys);
}
// operator/
template < typename T, std::size_t Size >
[[nodiscard]] constexpr mat<T, Size> operator/(const mat<T, Size>& xs, T y) {
return map([y](const vec<T, Size>& x){ return x / y; }, xs);
}
template < typename T, std::size_t Size >
[[nodiscard]] constexpr mat<T, Size> operator/(T x, const mat<T, Size>& ys) {
return map([x](const vec<T, Size>& y){ return x / y; }, ys);
}
template < typename T, std::size_t Size >
[[nodiscard]] constexpr mat<T, Size> operator/(const mat<T, Size>& xs, const mat<T, Size>& ys) {
return zip(std::divides<>(), xs, ys);
}
// operator/=
template < typename T, std::size_t Size >
constexpr mat<T, Size>& operator/=(mat<T, Size>& xs, T y) {
return (xs = xs / y);
}
template < typename T, std::size_t Size >
constexpr mat<T, Size>& operator/=(mat<T, Size>& xs, const mat<T, Size>& ys) {
return (xs = xs / ys);
}
// operator==
template < typename T, std::size_t Size >
[[nodiscard]] constexpr bool operator==(const mat<T, Size>& xs, const mat<T, Size>& ys) {
return fold([](bool acc, const vec<T, Size>& x, const vec<T, Size>& y){
return acc && (x == y);
}, true, xs, ys);
}
template < typename T, std::size_t Size >
[[nodiscard]] constexpr bool operator!=(const mat<T, Size>& xs, const mat<T, Size>& ys) {
return fold([](bool acc, const vec<T, Size>& x, const vec<T, Size>& y){
return acc || (x != y);
}, false, xs, ys);
}
// operator<
template < typename T, std::size_t Size >
[[nodiscard]] constexpr bool operator<(const mat<T, Size>& xs, const mat<T, Size>& ys) {
for ( std::size_t i = 0; i < Size; ++i ) {
if ( xs[i] < ys[i] ) {
return true;
}
if ( ys[i] < xs[i] ) {
return false;
}
}
return false;
}
}
//
// Matrix Functions
//
namespace vmath_hpp
{
namespace impl
{
template < typename T >
[[nodiscard]] constexpr mat<T, 2> transpose_2x2_impl(
T a, T c,
T b, T d)
{
return {
a, b,
c, d};
}
template < typename T >
[[nodiscard]] constexpr mat<T, 3> transpose_3x3_impl(
T a, T d, T g,
T b, T e, T h,
T c, T f, T i)
{
return {
a, b, c,
d, e, f,
g, h, i};
}
template < typename T >
[[nodiscard]] constexpr mat<T, 4> transpose_4x4_impl(
T a, T e, T i, T m,
T b, T f, T j, T n,
T c, T g, T k, T o,
T d, T h, T l, T p)
{
return {
a, b, c, d,
e, f, g, h,
i, j, k, l,
m, n, o, p};
}
}
template < typename T >
[[nodiscard]] constexpr mat<T, 2> transpose(const mat<T, 2>& m) {
return impl::transpose_2x2_impl(
m[0][0], m[0][1],
m[1][0], m[1][1]);
}
template < typename T >
[[nodiscard]] constexpr mat<T, 3> transpose(const mat<T, 3>& m) {
return impl::transpose_3x3_impl(
m[0][0], m[0][1], m[0][2],
m[1][0], m[1][1], m[1][2],
m[2][0], m[2][1], m[2][2]);
}
template < typename T >
[[nodiscard]] constexpr mat<T, 4> transpose(const mat<T, 4>& m) {
return impl::transpose_4x4_impl(
m[0][0], m[0][1], m[0][2], m[0][3],
m[1][0], m[1][1], m[1][2], m[1][3],
m[2][0], m[2][1], m[2][2], m[2][3],
m[3][0], m[3][1], m[3][2], m[3][3]);
}
namespace impl
{
template < typename T >
[[nodiscard]] constexpr T determinant_2x2_impl(
T a, T b,
T c, T d)
{
return
+ a * d
- b * c;
}
template < typename T >
[[nodiscard]] constexpr T determinant_3x3_impl(
T a, T b, T c,
T d, T e, T f,
T g, T h, T i)
{
return
+ a * determinant_2x2_impl(e, f, h, i)
- b * determinant_2x2_impl(d, f, g, i)
+ c * determinant_2x2_impl(d, e, g, h);
}
template < typename T >
[[nodiscard]] constexpr T determinant_4x4_impl(
T a, T b, T c, T d,
T e, T f, T g, T h,
T i, T j, T k, T l,
T m, T n, T o, T p)
{
return
+ a * determinant_3x3_impl(f, g, h, j, k, l, n, o, p)
- b * determinant_3x3_impl(e, g, h, i, k, l, m, o, p)
+ c * determinant_3x3_impl(e, f, h, i, j, l, m, n, p)
- d * determinant_3x3_impl(e, f, g, i, j, k, m, n, o);
}
}
template < typename T >
[[nodiscard]] constexpr T determinant(const mat<T, 2>& m) {
return impl::determinant_2x2_impl(
m[0][0], m[0][1],
m[1][0], m[1][1]);
}
template < typename T >
[[nodiscard]] constexpr T determinant(const mat<T, 3>& m) {
return impl::determinant_3x3_impl(
m[0][0], m[0][1], m[0][2],
m[1][0], m[1][1], m[1][2],
m[2][0], m[2][1], m[2][2]);
}
template < typename T >
[[nodiscard]] constexpr T determinant(const mat<T, 4>& m) {
return impl::determinant_4x4_impl(
m[0][0], m[0][1], m[0][2], m[0][3],
m[1][0], m[1][1], m[1][2], m[1][3],
m[2][0], m[2][1], m[2][2], m[2][3],
m[3][0], m[3][1], m[3][2], m[3][3]);
}
namespace impl
{
template < typename T >
[[nodiscard]] constexpr mat<T, 2> inverse_2x2_impl(
T a, T b,
T c, T d)
{
const T inv_det = reciprocal(determinant_2x2_impl(
a, b,
c, d));
const mat<T, 2> inv_m(
d, -b,
-c, a);
return inv_m * inv_det;
}
template < typename T >
[[nodiscard]] constexpr mat<T, 3> inverse_3x3_impl(
T a, T b, T c,
T d, T e, T f,
T g, T h, T i)
{
const T inv_det = reciprocal(determinant_3x3_impl(
a, b, c,
d, e, f,
g, h, i));
const mat<T, 3> inv_m(
e * i - f * h,
c * h - b * i,
b * f - c * e,
f * g - d * i,
a * i - c * g,
c * d - a * f,
d * h - e * g,
b * g - a * h,
a * e - b * d);
return inv_m * inv_det;
}
template < typename T >
[[nodiscard]] constexpr mat<T, 4> inverse_4x4_impl(
T a, T b, T c, T d,
T e, T f, T g, T h,
T i, T j, T k, T l,
T m, T n, T o, T p)
{
const T inv_det = reciprocal(determinant_4x4_impl(
a, b, c, d,
e, f, g, h,
i, j, k, l,
m, n, o, p));
const mat<T, 4> inv_m(
(f * (k * p - l * o) + g * (l * n - j * p) + h * (j * o - k * n)),
(j * (c * p - d * o) + k * (d * n - b * p) + l * (b * o - c * n)),
(n * (c * h - d * g) + o * (d * f - b * h) + p * (b * g - c * f)),
(b * (h * k - g * l) + c * (f * l - h * j) + d * (g * j - f * k)),
(g * (i * p - l * m) + h * (k * m - i * o) + e * (l * o - k * p)),
(k * (a * p - d * m) + l * (c * m - a * o) + i * (d * o - c * p)),
(o * (a * h - d * e) + p * (c * e - a * g) + m * (d * g - c * h)),
(c * (h * i - e * l) + d * (e * k - g * i) + a * (g * l - h * k)),
(h * (i * n - j * m) + e * (j * p - l * n) + f * (l * m - i * p)),
(l * (a * n - b * m) + i * (b * p - d * n) + j * (d * m - a * p)),
(p * (a * f - b * e) + m * (b * h - d * f) + n * (d * e - a * h)),
(d * (f * i - e * j) + a * (h * j - f * l) + b * (e * l - h * i)),
(e * (k * n - j * o) + f * (i * o - k * m) + g * (j * m - i * n)),
(i * (c * n - b * o) + j * (a * o - c * m) + k * (b * m - a * n)),
(m * (c * f - b * g) + n * (a * g - c * e) + o * (b * e - a * f)),
(a * (f * k - g * j) + b * (g * i - e * k) + c * (e * j - f * i)));
return inv_m * inv_det;
}
}
template < typename T >
[[nodiscard]] constexpr mat<T, 2> inverse(const mat<T, 2>& m) {
return impl::inverse_2x2_impl(
m[0][0], m[0][1],
m[1][0], m[1][1]);
}
template < typename T >
[[nodiscard]] constexpr mat<T, 3> inverse(const mat<T, 3>& m) {
return impl::inverse_3x3_impl(
m[0][0], m[0][1], m[0][2],
m[1][0], m[1][1], m[1][2],
m[2][0], m[2][1], m[2][2]);
}
template < typename T >
[[nodiscard]] constexpr mat<T, 4> inverse(const mat<T, 4>& m) {
return impl::inverse_4x4_impl(
m[0][0], m[0][1], m[0][2], m[0][3],
m[1][0], m[1][1], m[1][2], m[1][3],
m[2][0], m[2][1], m[2][2], m[2][3],
m[3][0], m[3][1], m[3][2], m[3][3]);
}
}
+201
View File
@@ -0,0 +1,201 @@
/*******************************************************************************
* This file is part of the "https://github.com/blackmatov/vmath.hpp"
* For conditions of distribution and use, see copyright notice in LICENSE.md
* Copyright (C) 2020, by Matvey Cherevko (blackmatov@gmail.com)
******************************************************************************/
#pragma once
#include "vmath_fwd.hpp"
namespace vmath_hpp::detail
{
template < typename T, std::size_t Size >
class vec_base;
template < typename T >
class vec_base<T, 2> {
public:
T x{}, y{};
public:
vec_base() = default;
constexpr explicit vec_base(T v)
: x{v}, y{v} {}
constexpr vec_base(T x, T y)
: x{x}, y{y} {}
constexpr explicit vec_base(const vec_base<T, 3>& xy)
: x{xy[0]}, y{xy[1]} {}
constexpr explicit vec_base(const vec_base<T, 4>& xy)
: x{xy[0]}, y{xy[1]} {}
[[nodiscard]] constexpr T& operator[](std::size_t index) noexcept {
switch ( index ) {
default:
case 0: return x;
case 1: return y;
}
}
[[nodiscard]] constexpr const T& operator[](std::size_t index) const noexcept {
switch ( index ) {
default:
case 0: return x;
case 1: return y;
}
}
};
template < typename T >
class vec_base<T, 3> {
public:
T x{}, y{}, z{};
public:
vec_base() = default;
constexpr explicit vec_base(T v)
: x{v}, y{v}, z{v} {}
constexpr vec_base(T x, T y, T z)
: x{x}, y{y}, z{z} {}
constexpr vec_base(const vec_base<T, 2>& xy, T z)
: x{xy[0]}, y{xy[1]}, z{z} {}
constexpr vec_base(T x, const vec_base<T, 2>& yz)
: x{x}, y{yz[0]}, z{yz[1]} {}
constexpr explicit vec_base(const vec_base<T, 4>& xyz)
: x{xyz[0]}, y{xyz[1]}, z{xyz[2]} {}
[[nodiscard]] constexpr T& operator[](std::size_t index) noexcept {
switch ( index ) {
default:
case 0: return x;
case 1: return y;
case 2: return z;
}
}
[[nodiscard]] constexpr const T& operator[](std::size_t index) const noexcept {
switch ( index ) {
default:
case 0: return x;
case 1: return y;
case 2: return z;
}
}
};
template < typename T >
class vec_base<T, 4> {
public:
T x{}, y{}, z{}, w{};
public:
vec_base() = default;
constexpr explicit vec_base(T v)
: x{v}, y{v}, z{v}, w{v} {}
constexpr vec_base(T x, T y, T z, T w)
: x{x}, y{y}, z{z}, w{w} {}
constexpr vec_base(const vec_base<T, 2>& xy, T z, T w)
: x{xy[0]}, y{xy[1]}, z{z}, w{w} {}
constexpr vec_base(T x, const vec_base<T, 2>& yz, T w)
: x{x}, y{yz[0]}, z{yz[1]}, w{w} {}
constexpr vec_base(T x, T y, const vec_base<T, 2>& zw)
: x{x}, y{y}, z{zw[0]}, w{zw[1]} {}
constexpr vec_base(const vec_base<T, 2>& xy, const vec_base<T, 2>& zw)
: x{xy[0]}, y{xy[1]}, z{zw[0]}, w{zw[1]} {}
constexpr vec_base(const vec_base<T, 3>& xyz, T w)
: x{xyz[0]}, y{xyz[1]}, z{xyz[2]}, w{w} {}
constexpr vec_base(T x, const vec_base<T, 3>& yzw)
: x{x}, y{yzw[0]}, z{yzw[1]}, w{yzw[2]} {}
[[nodiscard]] constexpr T& operator[](std::size_t index) noexcept {
switch ( index ) {
default:
case 0: return x;
case 1: return y;
case 2: return z;
case 3: return w;
}
}
[[nodiscard]] constexpr const T& operator[](std::size_t index) const noexcept {
switch ( index ) {
default:
case 0: return x;
case 1: return y;
case 2: return z;
case 3: return w;
}
}
};
}
namespace vmath_hpp
{
template < typename T, std::size_t Size >
class vec final : public detail::vec_base<T, Size> {
public:
using self_type = vec;
using base_type = detail::vec_base<T, Size>;
public:
using value_type = T;
using pointer = value_type*;
using const_pointer = const value_type*;
using reference = value_type&;
using const_reference = const value_type&;
static constexpr std::size_t size = Size;
public:
using base_type::vec_base;
using base_type::operator[];
vec() = default;
vec(vec&&) = default;
vec& operator=(vec&&) = default;
vec(const vec&) = default;
vec& operator=(const vec&) = default;
void swap(vec& other) noexcept(std::is_nothrow_swappable_v<T>) {
for ( std::size_t i = 0; i < Size; ++i ) {
using std::swap;
swap((*this)[i], other[i]);
}
}
[[nodiscard]] constexpr reference at(std::size_t index) {
if ( index >= Size ) {
throw std::out_of_range("vec::at");
}
return (*this)[index];
}
[[nodiscard]] constexpr const_reference at(std::size_t index) const {
if ( index >= Size ) {
throw std::out_of_range("vec::at");
}
return (*this)[index];
}
};
template < typename T, std::size_t Size >
void swap(vec<T, Size>& l, vec<T, Size>& r) noexcept(noexcept(l.swap(r))) {
l.swap(r);
}
}
+685
View File
@@ -0,0 +1,685 @@
/*******************************************************************************
* This file is part of the "https://github.com/blackmatov/vmath.hpp"
* For conditions of distribution and use, see copyright notice in LICENSE.md
* Copyright (C) 2020, by Matvey Cherevko (blackmatov@gmail.com)
******************************************************************************/
#pragma once
#include "vmath_fwd.hpp"
#include "vmath_fun.hpp"
#include "vmath_vec.hpp"
namespace vmath_hpp::detail
{
namespace impl
{
template < typename A, std::size_t Size, typename F, std::size_t... Is >
[[nodiscard]] constexpr auto map_impl(F&& f, const vec<A, Size>& a, std::index_sequence<Is...>)
-> vec<std::invoke_result_t<F, A>, Size>
{
return { f(a[Is])... };
}
template < typename A, typename B, std::size_t Size, typename F, std::size_t... Is >
[[nodiscard]] constexpr auto zip_impl(F&& f, const vec<A, Size>& a, const vec<B, Size>& b, std::index_sequence<Is...>)
-> vec<std::invoke_result_t<F, A, B>, Size>
{
return { f(a[Is], b[Is])... };
}
template < typename A, typename B, typename C, std::size_t Size, typename F, std::size_t... Is >
[[nodiscard]] constexpr auto zip_impl(F&& f, const vec<A, Size>& a, const vec<B, Size>& b, const vec<C, Size>& c, std::index_sequence<Is...>)
-> vec<std::invoke_result_t<F, A, B, C>, Size>
{
return { f(a[Is], b[Is], c[Is])... };
}
template < typename A, typename B, std::size_t Size, typename F, std::size_t... Is >
[[nodiscard]] constexpr A fold_impl(F&& f, A init, const vec<B, Size>& b, std::index_sequence<Is...>) {
return ((init = f(std::move(init), b[Is])), ...);
}
template < typename A, typename B, typename C, std::size_t Size, typename F, std::size_t... Is >
[[nodiscard]] constexpr A fold_impl(F&& f, A init, const vec<B, Size>& b, const vec<C, Size>& c, std::index_sequence<Is...>) {
return ((init = f(std::move(init), b[Is], c[Is])), ...);
}
template < typename A, std::size_t Size, typename F, std::size_t I, std::size_t... Is >
[[nodiscard]] constexpr A fold1_impl(F&& f, const vec<A, Size>& a, std::index_sequence<I, Is...>) {
A init = a[I];
return ((init = f(std::move(init), a[Is])), ...);
}
}
template < typename A, std::size_t Size, typename F >
[[nodiscard]] constexpr auto map(F&& f, const vec<A, Size>& a)
-> vec<std::invoke_result_t<F, A>, Size>
{
return impl::map_impl(std::forward<F>(f), a, std::make_index_sequence<Size>{});
}
template < typename A, typename B, std::size_t Size, typename F >
[[nodiscard]] constexpr auto zip(F&& f, const vec<A, Size>& a, const vec<B, Size>& b)
-> vec<std::invoke_result_t<F, A, B>, Size>
{
return impl::zip_impl(std::forward<F>(f), a, b, std::make_index_sequence<Size>{});
}
template < typename A, typename B, typename C, std::size_t Size, typename F >
[[nodiscard]] constexpr auto zip(F&& f, const vec<A, Size>& a, const vec<B, Size>& b, const vec<C, Size>& c)
-> vec<std::invoke_result_t<F, A, B, C>, Size>
{
return impl::zip_impl(std::forward<F>(f), a, b, c, std::make_index_sequence<Size>{});
}
template < typename A, typename B, std::size_t Size, typename F >
[[nodiscard]] constexpr A fold(F&& f, A init, const vec<B, Size>& b) {
return impl::fold_impl(std::forward<F>(f), std::move(init), b, std::make_index_sequence<Size>{});
}
template < typename A, typename B, typename C, std::size_t Size, typename F >
[[nodiscard]] constexpr A fold(F&& f, A init, const vec<B, Size>& b, const vec<C, Size>& c) {
return impl::fold_impl(std::forward<F>(f), std::move(init), b, c, std::make_index_sequence<Size>{});
}
template < typename A, std::size_t Size, typename F >
[[nodiscard]] constexpr A fold1(F&& f, const vec<A, Size>& a) {
return impl::fold1_impl(std::forward<F>(f), a, std::make_index_sequence<Size>{});
}
}
//
// Operators
//
namespace vmath_hpp
{
// -operator
template < typename T, std::size_t Size >
[[nodiscard]] constexpr vec<T, Size> operator-(const vec<T, Size>& xs) {
return map(std::negate<>(), xs);
}
// operator+
template < typename T, std::size_t Size >
[[nodiscard]] constexpr vec<T, Size> operator+(const vec<T, Size>& xs, T y) {
return map([y](T x){ return x + y; }, xs);
}
template < typename T, std::size_t Size >
[[nodiscard]] constexpr vec<T, Size> operator+(T x, const vec<T, Size>& ys) {
return map([x](T y){ return x + y; }, ys);
}
template < typename T, std::size_t Size >
[[nodiscard]] constexpr vec<T, Size> operator+(const vec<T, Size>& xs, const vec<T, Size>& ys) {
return zip(std::plus<>(), xs, ys);
}
// operator+=
template < typename T, std::size_t Size >
constexpr vec<T, Size>& operator+=(vec<T, Size>& xs, T y) {
return (xs = xs + y);
}
template < typename T, std::size_t Size >
constexpr vec<T, Size>& operator+=(vec<T, Size>& xs, const vec<T, Size>& ys) {
return (xs = xs + ys);
}
// operator-
template < typename T, std::size_t Size >
[[nodiscard]] constexpr vec<T, Size> operator-(const vec<T, Size>& xs, T y) {
return map([y](T x){ return x - y; }, xs);
}
template < typename T, std::size_t Size >
[[nodiscard]] constexpr vec<T, Size> operator-(T x, const vec<T, Size>& ys) {
return map([x](T y){ return x - y; }, ys);
}
template < typename T, std::size_t Size >
[[nodiscard]] constexpr vec<T, Size> operator-(const vec<T, Size>& xs, const vec<T, Size>& ys) {
return zip(std::minus<>(), xs, ys);
}
// operator-=
template < typename T, std::size_t Size >
constexpr vec<T, Size>& operator-=(vec<T, Size>& xs, T y) {
return (xs = xs - y);
}
template < typename T, std::size_t Size >
constexpr vec<T, Size>& operator-=(vec<T, Size>& xs, const vec<T, Size>& ys) {
return (xs = xs - ys);
}
// operator*
template < typename T, std::size_t Size >
[[nodiscard]] constexpr vec<T, Size> operator*(const vec<T, Size>& xs, T y) {
return map([y](T x){ return x * y; }, xs);
}
template < typename T, std::size_t Size >
[[nodiscard]] constexpr vec<T, Size> operator*(T x, const vec<T, Size>& ys) {
return map([x](T y){ return x * y; }, ys);
}
template < typename T, std::size_t Size >
[[nodiscard]] constexpr vec<T, Size> operator*(const vec<T, Size>& xs, const vec<T, Size>& ys) {
return zip(std::multiplies<>(), xs, ys);
}
// operator*=
template < typename T, std::size_t Size >
constexpr vec<T, Size>& operator*=(vec<T, Size>& xs, T y) {
return (xs = xs * y);
}
template < typename T, std::size_t Size >
constexpr vec<T, Size>& operator*=(vec<T, Size>& xs, const vec<T, Size>& ys) {
return (xs = xs * ys);
}
// operator/
template < typename T, std::size_t Size >
[[nodiscard]] constexpr vec<T, Size> operator/(const vec<T, Size>& xs, T y) {
return map([y](T x){ return x / y; }, xs);
}
template < typename T, std::size_t Size >
[[nodiscard]] constexpr vec<T, Size> operator/(T x, const vec<T, Size>& ys) {
return map([x](T y){ return x / y; }, ys);
}
template < typename T, std::size_t Size >
[[nodiscard]] constexpr vec<T, Size> operator/(const vec<T, Size>& xs, const vec<T, Size>& ys) {
return zip(std::divides<>(), xs, ys);
}
// operator/=
template < typename T, std::size_t Size >
constexpr vec<T, Size>& operator/=(vec<T, Size>& xs, T y) {
return (xs = xs / y);
}
template < typename T, std::size_t Size >
constexpr vec<T, Size>& operator/=(vec<T, Size>& xs, const vec<T, Size>& ys) {
return (xs = xs / ys);
}
// operator==
template < typename T, std::size_t Size >
[[nodiscard]] constexpr bool operator==(const vec<T, Size>& xs, const vec<T, Size>& ys) {
return fold([](bool acc, T x, T y){
return acc && (x == y);
}, true, xs, ys);
}
template < typename T, std::size_t Size >
[[nodiscard]] constexpr bool operator!=(const vec<T, Size>& xs, const vec<T, Size>& ys) {
return fold([](bool acc, T x, T y){
return acc || (x != y);
}, false, xs, ys);
}
// operator<
template < typename T, std::size_t Size >
[[nodiscard]] constexpr bool operator<(const vec<T, Size>& xs, const vec<T, Size>& ys) {
for ( std::size_t i = 0; i < Size; ++i ) {
if ( xs[i] < ys[i] ) {
return true;
}
if ( ys[i] < xs[i] ) {
return false;
}
}
return false;
}
}
//
// Angle and Trigonometry Functions
//
namespace vmath_hpp
{
template < typename T, std::size_t Size >
[[nodiscard]] constexpr vec<T, Size> radians(const vec<T, Size>& degrees) {
return map([](T x) { return radians(x); }, degrees);
}
template < typename T, std::size_t Size >
[[nodiscard]] constexpr vec<T, Size> degrees(const vec<T, Size>& radians) {
return map([](T x) { return degrees(x); }, radians);
}
template < typename T, std::size_t Size >
[[nodiscard]] vec<T, Size> sin(const vec<T, Size>& xs) {
return map([](T x) { return sin(x); }, xs);
}
template < typename T, std::size_t Size >
[[nodiscard]] vec<T, Size> cos(const vec<T, Size>& xs) {
return map([](T x) { return cos(x); }, xs);
}
template < typename T, std::size_t Size >
[[nodiscard]] vec<T, Size> tan(const vec<T, Size>& xs) {
return map([](T x) { return tan(x); }, xs);
}
template < typename T, std::size_t Size >
[[nodiscard]] vec<T, Size> asin(const vec<T, Size>& xs) {
return map([](T x) { return asin(x); }, xs);
}
template < typename T, std::size_t Size >
[[nodiscard]] vec<T, Size> acos(const vec<T, Size>& xs) {
return map([](T x) { return acos(x); }, xs);
}
template < typename T, std::size_t Size >
[[nodiscard]] vec<T, Size> atan(const vec<T, Size>& xs) {
return map([](T x) { return atan(x); }, xs);
}
template < typename T, std::size_t Size >
[[nodiscard]] vec<T, Size> atan2(const vec<T, Size>& ys, const vec<T, Size>& xs) {
return zip([](T y, T x) { return atan2(y, x); }, ys, xs);
}
template < typename T, std::size_t Size >
[[nodiscard]] vec<T, Size> sinh(const vec<T, Size>& xs) {
return map([](T x) { return sinh(x); }, xs);
}
template < typename T, std::size_t Size >
[[nodiscard]] vec<T, Size> cosh(const vec<T, Size>& xs) {
return map([](T x) { return cosh(x); }, xs);
}
template < typename T, std::size_t Size >
[[nodiscard]] vec<T, Size> tanh(const vec<T, Size>& xs) {
return map([](T x) { return tanh(x); }, xs);
}
template < typename T, std::size_t Size >
[[nodiscard]] vec<T, Size> asinh(const vec<T, Size>& xs) {
return map([](T x) { return asinh(x); }, xs);
}
template < typename T, std::size_t Size >
[[nodiscard]] vec<T, Size> acosh(const vec<T, Size>& xs) {
return map([](T x) { return acosh(x); }, xs);
}
template < typename T, std::size_t Size >
[[nodiscard]] vec<T, Size> atanh(const vec<T, Size>& xs) {
return map([](T x) { return atanh(x); }, xs);
}
}
//
// Exponential Functions
//
namespace vmath_hpp
{
template < typename T, std::size_t Size >
[[nodiscard]] vec<T, Size> pow(const vec<T, Size>& xs, const vec<T, Size>& ys) {
return zip([](T x, T y) { return pow(x, y); }, xs, ys);
}
template < typename T, std::size_t Size >
[[nodiscard]] vec<T, Size> exp(const vec<T, Size>& xs) {
return map([](T x) { return exp(x); }, xs);
}
template < typename T, std::size_t Size >
[[nodiscard]] vec<T, Size> log(const vec<T, Size>& xs) {
return map([](T x) { return log(x); }, xs);
}
template < typename T, std::size_t Size >
[[nodiscard]] vec<T, Size> exp2(const vec<T, Size>& xs) {
return map([](T x) { return exp2(x); }, xs);
}
template < typename T, std::size_t Size >
[[nodiscard]] vec<T, Size> log2(const vec<T, Size>& xs) {
return map([](T x) { return log2(x); }, xs);
}
template < typename T, std::size_t Size >
[[nodiscard]] vec<T, Size> sqrt(const vec<T, Size>& xs) {
return map([](T x) { return sqrt(x); }, xs);
}
template < typename T, std::size_t Size >
[[nodiscard]] vec<T, Size> rsqrt(const vec<T, Size>& xs) {
return map([](T x) { return rsqrt(x); }, xs);
}
}
//
// Common Functions
//
namespace vmath_hpp
{
template < typename T, std::size_t Size >
[[nodiscard]] constexpr vec<T, Size> abs(const vec<T, Size>& xs) {
return map([](T x) { return abs(x); }, xs);
}
template < typename T, std::size_t Size >
[[nodiscard]] constexpr vec<T, Size> sign(const vec<T, Size>& xs) {
return map([](T x) { return sign(x); }, xs);
}
template < typename T, std::size_t Size >
[[nodiscard]] constexpr vec<T, Size> reciprocal(const vec<T, Size>& xs) {
return map([](T x) { return reciprocal(x); }, xs);
}
template < typename T, std::size_t Size >
[[nodiscard]] vec<T, Size> floor(const vec<T, Size>& xs) {
return map([](T x) { return floor(x); }, xs);
}
template < typename T, std::size_t Size >
[[nodiscard]] vec<T, Size> trunc(const vec<T, Size>& xs) {
return map([](T x) { return trunc(x); }, xs);
}
template < typename T, std::size_t Size >
[[nodiscard]] vec<T, Size> round(const vec<T, Size>& xs) {
return map([](T x) { return round(x); }, xs);
}
template < typename T, std::size_t Size >
[[nodiscard]] vec<T, Size> ceil(const vec<T, Size>& xs) {
return map([](T x) { return ceil(x); }, xs);
}
template < typename T, std::size_t Size >
[[nodiscard]] vec<T, Size> fract(const vec<T, Size>& xs) {
return map([](T x) { return fract(x); }, xs);
}
template < typename T, std::size_t Size >
[[nodiscard]] vec<T, Size> fmod(const vec<T, Size>& xs, T y) {
return map([y](T x) { return fmod(x, y); }, xs);
}
template < typename T, std::size_t Size >
[[nodiscard]] vec<T, Size> fmod(const vec<T, Size>& xs, const vec<T, Size>& ys) {
return zip([](T x, T y) { return fmod(x, y); }, xs, ys);
}
namespace impl
{
template < typename T, std::size_t Size, std::size_t... Is >
vec<T, Size> modf_impl(const vec<T, Size>& xs, vec<T, Size>* is, std::index_sequence<Is...>) {
return { modf(xs[Is], &(*is)[Is])... };
}
}
template < typename T, std::size_t Size >
vec<T, Size> modf(const vec<T, Size>& xs, vec<T, Size>* is) {
return impl::modf_impl(xs, is, std::make_index_sequence<Size>{});
}
template < typename T, std::size_t Size >
[[nodiscard]] constexpr T min(const vec<T, Size>& xs) {
return fold1([](T acc, T x){ return min(acc, x); }, xs);
}
template < typename T, std::size_t Size >
[[nodiscard]] constexpr vec<T, Size> min(const vec<T, Size>& xs, T y) {
return map([y](T x) { return min(x, y); }, xs);
}
template < typename T, std::size_t Size >
[[nodiscard]] constexpr vec<T, Size> min(const vec<T, Size>& xs, const vec<T, Size>& ys) {
return zip([](T x, T y) { return min(x, y); }, xs, ys);
}
template < typename T, std::size_t Size >
[[nodiscard]] constexpr T max(const vec<T, Size>& xs) {
return fold1([](T acc, T x){ return max(acc, x); }, xs);
}
template < typename T, std::size_t Size >
[[nodiscard]] constexpr vec<T, Size> max(const vec<T, Size>& xs, T y) {
return map([y](T x) { return max(x, y); }, xs);
}
template < typename T, std::size_t Size >
[[nodiscard]] constexpr vec<T, Size> max(const vec<T, Size>& xs, const vec<T, Size>& ys) {
return zip([](T x, T y) { return max(x, y); }, xs, ys);
}
template < typename T, std::size_t Size >
[[nodiscard]] constexpr vec<T, Size> clamp(const vec<T, Size>& xs, T min_x, T max_x) {
return map([min_x, max_x](T x) { return clamp(x, min_x, max_x); }, xs);
}
template < typename T, std::size_t Size >
[[nodiscard]] constexpr vec<T, Size> clamp(const vec<T, Size>& xs, const vec<T, Size>& min_xs, const vec<T, Size>& max_xs) {
return zip([](T x, T min_x, T max_x) { return clamp(x, min_x, max_x); }, xs, min_xs, max_xs);
}
template < typename T, std::size_t Size >
[[nodiscard]] constexpr vec<T, Size> saturate(const vec<T, Size>& xs) {
return map([](T x) { return saturate(x); }, xs);
}
template < typename T, std::size_t Size >
[[nodiscard]] constexpr vec<T, Size> lerp(const vec<T, Size>& xs, const vec<T, Size>& ys, T a) {
return zip([a](T x, T y) { return lerp(x, y, a); }, xs, ys);
}
template < typename T, std::size_t Size >
[[nodiscard]] constexpr vec<T, Size> lerp(const vec<T, Size>& xs, const vec<T, Size>& ys, const vec<T, Size>& as) {
return zip([](T x, T y, T a) { return lerp(x, y, a); }, xs, ys, as);
}
template < typename T, std::size_t Size >
[[nodiscard]] constexpr vec<T, Size> step(T edge, const vec<T, Size>& xs) {
return map([edge](T x) { return step(edge, x); }, xs);
}
template < typename T, std::size_t Size >
[[nodiscard]] constexpr vec<T, Size> step(const vec<T, Size>& edges, const vec<T, Size>& xs) {
return zip([](T edge, T x) { return step(edge, x); }, edges, xs);
}
template < typename T, std::size_t Size >
[[nodiscard]] constexpr vec<T, Size> smoothstep(T edge0, T edge1, const vec<T, Size>& xs) {
return map([edge0, edge1](T x) { return smoothstep(edge0, edge1, x); }, xs);
}
template < typename T, std::size_t Size >
[[nodiscard]] constexpr vec<T, Size> smoothstep(const vec<T, Size>& edges0, const vec<T, Size>& edges1, const vec<T, Size>& xs) {
return zip([](T edge0, T edge1, T x) { return smoothstep(edge0, edge1, x); }, edges0, edges1, xs);
}
template < typename T, std::size_t Size >
[[nodiscard]] vec<bool, Size> isnan(const vec<T, Size>& xs) {
return map([](T x) { return isnan(x); }, xs);
}
template < typename T, std::size_t Size >
[[nodiscard]] vec<bool, Size> isinf(const vec<T, Size>& xs) {
return map([](T x) { return isinf(x); }, xs);
}
template < typename T, std::size_t Size >
[[nodiscard]] vec<bool, Size> isfinite(const vec<T, Size>& xs) {
return map([](T x) { return isfinite(x); }, xs);
}
template < typename T, std::size_t Size >
[[nodiscard]] vec<T, Size> fma(const vec<T, Size>& as, const vec<T, Size>& bs, const vec<T, Size>& cs) {
return zip([](T a, T b, T c) { return fma(a, b, c); }, as, bs, cs);
}
namespace impl
{
template < typename T, std::size_t Size, std::size_t... Is >
vec<T, Size> frexp_impl(const vec<T, Size>& xs, vec<int, Size>* exps, std::index_sequence<Is...>) {
return { frexp(xs[Is], &(*exps)[Is])... };
}
}
template < typename T, std::size_t Size >
vec<T, Size> frexp(const vec<T, Size>& xs, vec<int, Size>* exps) {
return impl::frexp_impl(xs, exps, std::make_index_sequence<Size>{});
}
template < typename T, std::size_t Size >
[[nodiscard]] vec<T, Size> ldexp(const vec<T, Size>& xs, const vec<int, Size>& exps) {
return zip([](T x, int exp) { return ldexp(x, exp); }, xs, exps);
}
}
//
// Geometric Functions
//
namespace vmath_hpp
{
template < typename T, std::size_t Size >
[[nodiscard]] constexpr T dot(const vec<T, Size>& xs, const vec<T, Size>& ys) {
return fold([](T acc, T x, T y){
return acc + (x * y);
}, T(0), xs, ys);
}
template < typename T, std::size_t Size >
[[nodiscard]] T length(const vec<T, Size>& xs) {
return sqrt(dot(xs, xs));
}
template < typename T, std::size_t Size >
[[nodiscard]] constexpr T length2(const vec<T, Size>& xs) {
return dot(xs, xs);
}
template < typename T, std::size_t Size >
[[nodiscard]] T distance(const vec<T, Size>& xs, const vec<T, Size>& ys) {
return length(ys - xs);
}
template < typename T, std::size_t Size >
[[nodiscard]] constexpr T distance2(const vec<T, Size>& xs, const vec<T, Size>& ys) {
return length2(ys - xs);
}
template < typename T >
[[nodiscard]] constexpr T cross(const vec<T, 2>& xs, const vec<T, 2>& ys) {
return xs.x * ys.y - xs.y * ys.x;
}
template < typename T >
[[nodiscard]] constexpr vec<T, 3> cross(const vec<T, 3>& xs, const vec<T, 3>& ys) {
return {
xs.y * ys.z - xs.z * ys.y,
xs.z * ys.x - xs.x * ys.z,
xs.x * ys.y - xs.y * ys.x};
}
template < typename T, std::size_t Size >
[[nodiscard]] vec<T, Size> normalize(const vec<T, Size>& xs) {
return xs * rsqrt(dot(xs, xs));
}
template < typename T, std::size_t Size >
[[nodiscard]] constexpr vec<T, Size> faceforward(const vec<T, Size>& n, const vec<T, Size>& i, const vec<T, Size>& nref) {
return dot(nref, i) < T(0) ? n : -n;
}
template < typename T, std::size_t Size >
[[nodiscard]] constexpr vec<T, Size> reflect(const vec<T, Size>& i, const vec<T, Size>& n) {
return i - n * dot(n, i) * T(2);
}
template < typename T, std::size_t Size >
[[nodiscard]] vec<T, Size> refract(const vec<T, Size>& i, const vec<T, Size>& n, T eta) {
const T d = dot(n, i);
const T k = T(1) - eta * eta * (T(1) - d * d);
return T(k >= T(0)) * (eta * i - (eta * d + sqrt(k)) * n);
}
}
//
// Vector Relational Functions
//
namespace vmath_hpp
{
template < typename T, std::size_t Size >
[[nodiscard]] constexpr vec<bool, Size> less(const vec<T, Size>& xs, const vec<T, Size>& ys) {
return zip([](T x, T y){ return less(x, y); }, xs, ys);
}
template < typename T, std::size_t Size >
[[nodiscard]] constexpr vec<bool, Size> less_equal(const vec<T, Size>& xs, const vec<T, Size>& ys) {
return zip([](T x, T y){ return less_equal(x, y); }, xs, ys);
}
template < typename T, std::size_t Size >
[[nodiscard]] constexpr vec<bool, Size> greater(const vec<T, Size>& xs, const vec<T, Size>& ys) {
return zip([](T x, T y){ return greater(x, y); }, xs, ys);
}
template < typename T, std::size_t Size >
[[nodiscard]] constexpr vec<bool, Size> greater_equal(const vec<T, Size>& xs, const vec<T, Size>& ys) {
return zip([](T x, T y){ return greater_equal(x, y); }, xs, ys);
}
template < typename T, std::size_t Size >
[[nodiscard]] constexpr vec<bool, Size> equal_to(const vec<T, Size>& xs, const vec<T, Size>& ys) {
return zip([](T x, T y){ return equal_to(x, y); }, xs, ys);
}
template < typename T, std::size_t Size >
[[nodiscard]] constexpr vec<bool, Size> equal_to(const vec<T, Size>& xs, const vec<T, Size>& ys, T epsilon) {
return zip([epsilon](T x, T y){ return equal_to(x, y, epsilon); }, xs, ys);
}
template < typename T, std::size_t Size >
[[nodiscard]] constexpr vec<bool, Size> not_equal_to(const vec<T, Size>& xs, const vec<T, Size>& ys) {
return zip([](T x, T y){ return not_equal_to(x, y); }, xs, ys);
}
template < typename T, std::size_t Size >
[[nodiscard]] constexpr vec<bool, Size> not_equal_to(const vec<T, Size>& xs, const vec<T, Size>& ys, T epsilon) {
return zip([epsilon](T x, T y){ return not_equal_to(x, y, epsilon); }, xs, ys);
}
template < typename T, std::size_t Size >
[[nodiscard]] constexpr bool any(const vec<T, Size>& xs) {
return fold([](bool acc, T x){ return acc || any(x); }, false, xs);
}
template < typename T, std::size_t Size >
[[nodiscard]] constexpr bool all(const vec<T, Size>& xs) {
return fold([](bool acc, T x){ return acc && all(x); }, true, xs);
}
}
+219
View File
@@ -0,0 +1,219 @@
/*******************************************************************************
* This file is part of the "https://github.com/blackmatov/vmath.hpp"
* For conditions of distribution and use, see copyright notice in LICENSE.md
* Copyright (C) 2020, by Matvey Cherevko (blackmatov@gmail.com)
******************************************************************************/
#include <vmath.hpp/vmath_ext.hpp>
#define CATCH_CONFIG_FAST_COMPILE
#include <catch2/catch.hpp>
#include "vmath_tests.hpp"
#include <set>
#include <map>
#include <unordered_set>
#include <unordered_map>
namespace
{
using namespace vmath_hpp;
using namespace vmath_tests;
}
TEST_CASE("vmath/ext") {
SECTION("units") {
STATIC_REQUIRE(zero2<int> == int2(0,0));
STATIC_REQUIRE(zero3<int> == int3(0,0,0));
STATIC_REQUIRE(zero4<int> == int4(0,0,0,0));
STATIC_REQUIRE(unit2<int> == int2(1,1));
STATIC_REQUIRE(unit2_x<int> == int2(1,0));
STATIC_REQUIRE(unit2_y<int> == int2(0,1));
STATIC_REQUIRE(unit3<int> == int3(1,1,1));
STATIC_REQUIRE(unit3_x<int> == int3(1,0,0));
STATIC_REQUIRE(unit3_y<int> == int3(0,1,0));
STATIC_REQUIRE(unit3_z<int> == int3(0,0,1));
STATIC_REQUIRE(unit4<int> == int4(1,1,1,1));
STATIC_REQUIRE(unit4_x<int> == int4(1,0,0,0));
STATIC_REQUIRE(unit4_y<int> == int4(0,1,0,0));
STATIC_REQUIRE(unit4_z<int> == int4(0,0,1,0));
STATIC_REQUIRE(unit4_w<int> == int4(0,0,0,1));
STATIC_REQUIRE(zero2x2<int> == int2x2(0,0,0,0));
STATIC_REQUIRE(zero3x3<int> == int3x3(0,0,0,0,0,0,0,0,0));
STATIC_REQUIRE(zero4x4<int> == int4x4(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0));
STATIC_REQUIRE(unit2x2<int> == int2x2(1,1,1,1));
STATIC_REQUIRE(unit3x3<int> == int3x3(1,1,1,1,1,1,1,1,1));
STATIC_REQUIRE(unit4x4<int> == int4x4(1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1));
STATIC_REQUIRE(identity2x2<int> == int2x2());
STATIC_REQUIRE(identity3x3<int> == int3x3());
STATIC_REQUIRE(identity4x4<int> == int4x4());
}
SECTION("hash") {
REQUIRE(std::hash<int2>{}({1,2}) == std::hash<int2>{}({1,2}));
REQUIRE_FALSE(std::hash<int2>{}({1,2}) == std::hash<int2>{}({2,1}));
REQUIRE(std::hash<int3>{}({1,2,3}) == std::hash<int3>{}({1,2,3}));
REQUIRE_FALSE(std::hash<int3>{}({1,2,3}) == std::hash<int3>{}({3,2,1}));
REQUIRE(std::hash<int4>{}({1,2,3,4}) == std::hash<int4>{}({1,2,3,4}));
REQUIRE_FALSE(std::hash<int4>{}({1,2,3,4}) == std::hash<int4>{}({3,2,1,4}));
REQUIRE(std::hash<int2x2>{}({1,2,3,4}) == std::hash<int2x2>{}({1,2,3,4}));
REQUIRE_FALSE(std::hash<int2x2>{}({1,2,3,4}) == std::hash<int2x2>{}({1,2,4,3}));
{
std::set<int2> s;
s.insert(int2(1,2));
REQUIRE(s.count(int2(1,2)) > 0);
REQUIRE_FALSE(s.count(int2(1,1)) > 0);
}
{
std::map<int2, int> s;
s.emplace(int2(1,2),3);
s.emplace(int2(2,3),5);
REQUIRE(s[int2(1,2)] == 3);
REQUIRE(s[int2(2,3)] == 5);
}
{
std::unordered_set<int2> s;
s.insert(int2(1,2));
REQUIRE(s.count(int2(1,2)) > 0);
REQUIRE_FALSE(s.count(int2(1,1)) > 0);
}
{
std::unordered_map<int2, int> s;
s.emplace(int2(1,2),3);
s.emplace(int2(2,3),5);
REQUIRE(s[int2(1,2)] == 3);
REQUIRE(s[int2(2,3)] == 5);
}
}
SECTION("cast_to") {
{
constexpr auto i = cast_to<int>(1.5f);
STATIC_REQUIRE(i == 1);
STATIC_REQUIRE(std::is_same_v<decltype(i), const int>);
}
{
constexpr auto v = cast_to<int>(float2{1.5f});
STATIC_REQUIRE(v == int2(1));
STATIC_REQUIRE(std::is_same_v<decltype(v)::value_type, int>);
}
{
constexpr auto m = cast_to<int>(float2x2{1.5f});
STATIC_REQUIRE(m == int2x2(1));
STATIC_REQUIRE(std::is_same_v<decltype(m)::row_type, int2>);
}
}
SECTION("component") {
STATIC_REQUIRE(component(int2{1,2}, 0) == 1);
STATIC_REQUIRE(component(int2{1,2}, 1) == 2);
STATIC_REQUIRE(component(int2{0,0}, 0, 1) == int2{1,0});
STATIC_REQUIRE(component(int2{0,0}, 1, 2) == int2{0,2});
}
SECTION("row") {
STATIC_REQUIRE(row(int2x2(1,2,3,4), 0) == int2(1,2));
STATIC_REQUIRE(row(int2x2(1,2,3,4), 1) == int2(3,4));
STATIC_REQUIRE(row(int2x2(), 0, {1,2}) == int2x2(1,2,0,1));
STATIC_REQUIRE(row(int2x2(), 1, {3,4}) == int2x2(1,0,3,4));
}
SECTION("column") {
STATIC_REQUIRE(column(int2x2(1,2,3,4), 0) == int2(1,3));
STATIC_REQUIRE(column(int2x2(1,2,3,4), 1) == int2(2,4));
STATIC_REQUIRE(column(int2x2(), 0, {2,3}) == int2x2(2,0,3,1));
STATIC_REQUIRE(column(int2x2(), 1, {3,4}) == int2x2(1,3,0,4));
}
SECTION("matrix translate") {
STATIC_REQUIRE(float3(2.f,3.f,1.f) * translate(float2{1.f,2.f}) == approx3(3.f,5.f,1.f));
STATIC_REQUIRE(float3(2.f,3.f,1.f) * translate(translate(float2{1.f,2.f}), float2{1.f,2.f}) == approx3(4.f,7.f,1.f));
STATIC_REQUIRE(float4(2.f,3.f,4.f,1.f) * translate(float3{1.f,2.f,3.f}) == approx4(3.f,5.f,7.f,1.f));
STATIC_REQUIRE(float4(2.f,3.f,4.f,1.f) * translate(translate(float3{1.f,2.f,3.f}), float3{1.f,2.f,3.f}) == approx4(4.f,7.f,10.f,1.f));
}
SECTION("matrix rotate") {
constexpr float pi = radians(180.f);
constexpr float pi_2 = radians(90.f);
REQUIRE(float3(2.f,3.f,1.f) * rotate(pi) == approx3(-2.f,-3.f,1.f));
REQUIRE(float4(2.f,3.f,4.f,1.f) * rotate(pi,{0.f,0.f,1.f}) == approx4(-2.f,-3.f,4.f,1.f));
REQUIRE(float4(2.f,3.f,4.f,1.f) * rotate(pi,float3{0.f,0.f,1.f}) == approx4(-2.f,-3.f,4.f,1.f));
REQUIRE(float3(2.f,3.f,1.f) * rotate(rotate(pi_2),pi_2) == approx3(-2.f,-3.f,1.f));
REQUIRE(float4(2.f,3.f,4.f,1.f) * rotate(rotate(pi_2,{0.f,0.f,1.f}),pi_2,{0.f,0.f,1.f}) == approx4(-2.f,-3.f,4.f,1.f));
REQUIRE(float4(2.f,3.f,4.f,1.f) * rotate(rotate(pi_2,float3{0.f,0.f,1.f}),pi_2,float3{0.f,0.f,1.f}) == approx4(-2.f,-3.f,4.f,1.f));
}
SECTION("matrix scale") {
STATIC_REQUIRE(float3(2.f,3.f,1.f) * scale(float2{2.f,3.f}) == approx3(4.f,9.f,1.f));
STATIC_REQUIRE(float4(2.f,3.f,4.f,1.f) * scale(float3{2.f,3.f,4.f}) == approx4(4.f,9.f,16.f,1.f));
STATIC_REQUIRE(float4(2.f,3.f,4.f,1.f) * scale(float3{2.f,3.f,4.f}) == approx4(4.f,9.f,16.f,1.f));
STATIC_REQUIRE(float3(2.f,3.f,1.f) * scale(scale(float2{2.f,2.f}), {2.f,3.f}) == approx3(8.f,18.f,1.f));
STATIC_REQUIRE(float4(2.f,3.f,4.f,1.f) * scale(scale(float3{2.f,2.f,2.f}), {2.f,3.f,4.f}) == approx4(8.f,18.f,32.f,1.f));
STATIC_REQUIRE(float4(2.f,3.f,4.f,1.f) * scale(scale(float3{2.f,2.f,2.f}), float3{2.f,3.f,4.f}) == approx4(8.f,18.f,32.f,1.f));
}
SECTION("matrix shear") {
STATIC_REQUIRE(float3(2.f,3.f,1.f) * shear_x(0.f) == approx3(2.f,3.f,1.f));
STATIC_REQUIRE(float3(2.f,3.f,1.f) * shear_x(1.f) == approx3(5.f,3.f,1.f));
STATIC_REQUIRE(float3(2.f,3.f,1.f) * shear_x(shear_x(1.f),1.f) == approx3(8.f,3.f,1.f));
STATIC_REQUIRE(float3(2.f,3.f,1.f) * shear_y(0.f) == approx3(2.f,3.f,1.f));
STATIC_REQUIRE(float3(2.f,3.f,1.f) * shear_y(1.f) == approx3(2.f,5.f,1.f));
STATIC_REQUIRE(float3(2.f,3.f,1.f) * shear_y(shear_y(1.f),1.f) == approx3(2.f,7.f,1.f));
STATIC_REQUIRE(float3(2.f,3.f,1.f) * shear(float2(0.f,0.f)) == approx3(2.f,3.f,1.f));
STATIC_REQUIRE(float3(2.f,3.f,1.f) * shear(float2(1.f,0.f)) == approx3(5.f,3.f,1.f));
STATIC_REQUIRE(float3(2.f,3.f,1.f) * shear(float2(0.f,1.f)) == approx3(2.f,5.f,1.f));
STATIC_REQUIRE(float3(2.f,3.f,1.f) * shear(shear(float2(1.f,0.f)),float2(1.f,0.f)) == approx3(8.f,3.f,1.f));
STATIC_REQUIRE(float3(2.f,3.f,1.f) * shear(shear(float2(0.f,1.f)),float2(0.f,1.f)) == approx3(2.f,7.f,1.f));
}
SECTION("matrix look_at") {
(void)look_at_lh(float3(-10.f), float3(0.f), float3(0,-1,0));
(void)look_at_rh(float3(-10.f), float3(0.f), float3(0,-1,0));
(void)orthographic_lh_zo(0.f, 800.f, 0.f, 640.f, 0.f, 10.f);
(void)orthographic_lh_no(0.f, 800.f, 0.f, 640.f, 0.f, 10.f);
(void)orthographic_rh_zo(0.f, 800.f, 0.f, 640.f, 0.f, 10.f);
(void)orthographic_rh_no(0.f, 800.f, 0.f, 640.f, 0.f, 10.f);
(void)perspective_lh_zo(1.f, 1.3f, 0.f, 10.f);
(void)perspective_lh_no(1.f, 1.3f, 0.f, 10.f);
(void)perspective_rh_zo(1.f, 1.3f, 0.f, 10.f);
(void)perspective_rh_no(1.f, 1.3f, 0.f, 10.f);
}
SECTION("vector angle") {
REQUIRE(angle(float2(2.f,0.f), float2(0.f,1.f)) == Approx(radians(90.f)));
REQUIRE(angle(float2(0.f,3.f), float2(1.f,0.f)) == Approx(radians(90.f)));
REQUIRE(angle(float2(0.5f,0.f), float2(-1.f,0.f)) == Approx(radians(180.f)));
REQUIRE(angle(float2(-0.2f,0.f), float2(1.f,0.f)) == Approx(radians(180.f)));
REQUIRE(angle(float3(0.f,2.f,0.f), float3(0.f,0.f,1.f)) == Approx(radians(90.f)));
REQUIRE(angle(float3(0.f,0.f,3.f), float3(0.f,1.f,0.f)) == Approx(radians(90.f)));
}
SECTION("vector rotate") {
REQUIRE(rotate(float2(2.f,0.f), radians(90.f)) == approx2(0.f,2.f));
REQUIRE(rotate(float2(1.5f,0.f), radians(-90.f)) == approx2(0.f,-1.5f));
REQUIRE(rotate(float3(1.5f,0.f,0.f), radians(90.f), float3(0,0,1)) == approx3(0.f,1.5f,0.f));
REQUIRE(rotate(float4(1.5f,0.f,0.f,1.f), radians(90.f), float3(0,0,1)) == approx4(0.f,1.5f,0.f,1.f));
}
}
+170
View File
@@ -0,0 +1,170 @@
/*******************************************************************************
* This file is part of the "https://github.com/blackmatov/vmath.hpp"
* For conditions of distribution and use, see copyright notice in LICENSE.md
* Copyright (C) 2020, by Matvey Cherevko (blackmatov@gmail.com)
******************************************************************************/
#include <vmath.hpp/vmath_fun.hpp>
#define CATCH_CONFIG_FAST_COMPILE
#include <catch2/catch.hpp>
#include "vmath_tests.hpp"
namespace
{
using namespace vmath_hpp;
using namespace vmath_tests;
}
TEST_CASE("vmath/fun") {
SECTION("Angle and Trigonometry Functions") {
STATIC_REQUIRE(radians(degrees(12.13f)) == approx(12.13f));
STATIC_REQUIRE(degrees(radians(12.13f)) == approx(12.13f));
(void)sin(0.f);
(void)cos(0.f);
(void)tan(0.f);
(void)asin(0.f);
(void)acos(0.f);
(void)atan(0.f);
(void)atan2(0.f, 0.f);
(void)sinh(0.f);
(void)cosh(0.f);
(void)tanh(0.f);
(void)asinh(0.f);
(void)acosh(0.f);
(void)atanh(0.f);
}
SECTION("Exponential Functions") {
(void)pow(2.f, 3.f);
(void)exp(2.f);
(void)log(2.f);
(void)exp2(2.f);
(void)log2(2.f);
(void)sqrt(2.f);
(void)rsqrt(2.f);
}
SECTION("Common Functions") {
STATIC_REQUIRE(vmath_hpp::abs(1) == 1);
STATIC_REQUIRE(vmath_hpp::abs(-1) == 1);
STATIC_REQUIRE(vmath_hpp::abs(1.f) == approx(1.f));
STATIC_REQUIRE(vmath_hpp::abs(-1.f) == approx(1.f));
STATIC_REQUIRE(sign(2) == 1);
STATIC_REQUIRE(sign(-2) == -1);
STATIC_REQUIRE(sign(0) == 0);
STATIC_REQUIRE(sign(2.f) == approx(1.f));
STATIC_REQUIRE(sign(-2.f) == approx(-1.f));
STATIC_REQUIRE(sign(0.f) == approx(0.f));
STATIC_REQUIRE(reciprocal(2.f) == approx(0.5f));
STATIC_REQUIRE(reciprocal(4.f) == approx(0.25f));
REQUIRE(floor(1.7f) == approx(1.f));
REQUIRE(trunc(1.7f) == approx(1.f));
REQUIRE(round(1.7f) == approx(2.f));
REQUIRE(ceil(1.7f) == approx(2.f));
REQUIRE(fract(1.7f) == approx(0.7f));
REQUIRE(fract(-2.3f) == approx(0.7f));
REQUIRE(fmod(1.7f, 1.2f) == approx(0.5f));
{
float out_i{};
REQUIRE(modf(1.7f, &out_i) == approx(0.7f));
REQUIRE(out_i == approx(1.f));
}
STATIC_REQUIRE(min(1.f, 2.f) == approx(1.f));
STATIC_REQUIRE(max(1.f, 2.f) == approx(2.f));
STATIC_REQUIRE(clamp(1.0f, 2.f, 3.f) == approx(2.0f));
STATIC_REQUIRE(clamp(2.5f, 2.f, 3.f) == approx(2.5f));
STATIC_REQUIRE(clamp(3.5f, 2.f, 3.f) == approx(3.0f));
STATIC_REQUIRE(saturate(-0.5f) == approx(0.f));
STATIC_REQUIRE(saturate(0.5f) == approx(0.5f));
STATIC_REQUIRE(saturate(1.5f) == approx(1.f));
STATIC_REQUIRE(lerp(0.f, 10.f, 0.5f) == approx(5.f));
STATIC_REQUIRE(step(0.5f, 0.4f) == approx(0.f));
STATIC_REQUIRE(step(0.5f, 0.6f) == approx(1.f));
STATIC_REQUIRE(smoothstep(0.f, 1.f, 0.1f) == approx(0.028f));
REQUIRE_FALSE(vmath_hpp::isnan(1.f));
REQUIRE_FALSE(vmath_hpp::isinf(1.f));
REQUIRE(vmath_hpp::isfinite(1.f));
REQUIRE(fma(2.f, 3.f, 4.f) == approx(10.f));
{
int out_exp{};
REQUIRE(frexp(1.7f, &out_exp) == approx(0.85f));
REQUIRE(out_exp == 1);
}
REQUIRE(ldexp(0.85f, 1) == approx(1.7f));
}
SECTION("Geometric Functions") {
STATIC_REQUIRE(length(10.f) == approx(10.f));
STATIC_REQUIRE(length(-10.f) == approx(10.f));
STATIC_REQUIRE(length2(10.f) == approx(100.f));
STATIC_REQUIRE(length2(-10.f) == approx(100.f));
STATIC_REQUIRE(distance(5.f, 10.f) == approx(5.f));
STATIC_REQUIRE(distance(-5.f, -10.f) == approx(5.f));
STATIC_REQUIRE(distance2(5.f, 10.f) == approx(25.f));
STATIC_REQUIRE(distance2(-5.f, -10.f) == approx(25.f));
STATIC_REQUIRE(dot(2.f, 5.f) == approx(10.f));
REQUIRE(normalize(0.5f) == approx(1.f));
STATIC_REQUIRE(faceforward(1.f, 2.f, 3.f) == approx(-1.f));
STATIC_REQUIRE(reflect(1.f, 2.f) == approx(-7.f));
REQUIRE(refract(1.f, 2.f, 1.f) == approx(-7.f));
}
SECTION("Scalar Relational Functions") {
STATIC_REQUIRE(less(0, 1));
STATIC_REQUIRE(less_equal(0, 1));
STATIC_REQUIRE_FALSE(less(1, 1));
STATIC_REQUIRE(less_equal(1, 1));
STATIC_REQUIRE(greater(1, 0));
STATIC_REQUIRE(greater_equal(1, 0));
STATIC_REQUIRE_FALSE(greater(1, 1));
STATIC_REQUIRE(greater_equal(1, 1));
STATIC_REQUIRE(equal_to(1, 1));
STATIC_REQUIRE_FALSE(equal_to(0, 1));
STATIC_REQUIRE_FALSE(equal_to(0, 1, 0));
STATIC_REQUIRE(equal_to(0, 1, 1));
STATIC_REQUIRE(not_equal_to(0, 1));
STATIC_REQUIRE(not_equal_to(0, 1, 0));
STATIC_REQUIRE_FALSE(not_equal_to(0, 1, 1));
STATIC_REQUIRE_FALSE(not_equal_to(1, 1));
STATIC_REQUIRE_FALSE(not_equal_to(1, 1, 0));
STATIC_REQUIRE_FALSE(not_equal_to(1, 1, 1));
STATIC_REQUIRE_FALSE(any(false));
STATIC_REQUIRE_FALSE(any(0));
STATIC_REQUIRE(any(true));
STATIC_REQUIRE(any(1));
STATIC_REQUIRE_FALSE(all(false));
STATIC_REQUIRE_FALSE(all(0));
STATIC_REQUIRE(all(true));
STATIC_REQUIRE(all(1));
}
}
+201
View File
@@ -0,0 +1,201 @@
/*******************************************************************************
* This file is part of the "https://github.com/blackmatov/vmath.hpp"
* For conditions of distribution and use, see copyright notice in LICENSE.md
* Copyright (C) 2020, by Matvey Cherevko (blackmatov@gmail.com)
******************************************************************************/
#include <vmath.hpp/vmath_ext.hpp>
#define CATCH_CONFIG_FAST_COMPILE
#include <catch2/catch.hpp>
#include "vmath_tests.hpp"
namespace
{
using namespace vmath_hpp;
using namespace vmath_tests;
template < typename T, int Size >
constexpr mat<T, Size> generate_frank_matrix() {
mat<T, Size> m;
for ( int i = 1; i <= Size; ++i ) {
for ( int j = 1; j <= Size; ++j ) {
if ( j < i - Size ) {
m[i - 1][j - 1] = 0;
} else if ( j == (i - 1) ) {
m[i - 1][j - 1] = Size + 1 - i;
} else {
m[i - 1][j - 1] = Size + 1 - j;
}
}
}
return m;
}
}
TEST_CASE("vmath/mat_fun") {
SECTION("Detail") {
STATIC_REQUIRE(map([](const int2& x){
return x * 2;
}, int2x2{}) == int2x2(2,0,0,2));
STATIC_REQUIRE(zip([](const int2& x, const int2& y){
return x + y;
}, int2x2{}, int2x2{}) == int2x2(2,0,0,2));
STATIC_REQUIRE(zip([](const int2& x, const int2& y, const int2& z){
return x + y + z;
}, int2x2{}, int2x2{}, int2x2{}) == int2x2(3,0,0,3));
STATIC_REQUIRE(fold([](int acc, const int2& x){
return acc + x.x;
}, 0, int2x2{}) == 1);
STATIC_REQUIRE(fold([](int acc, const int2& x, const int2& y){
return acc + x.x + y.x;
}, 0, int2x2{}, int2x2{}) == 2);
STATIC_REQUIRE(fold1([](const int2& acc, const int2& x){
return acc + x;
}, int2x2{}) == int2(1,1));
}
SECTION("Operators") {
STATIC_REQUIRE(-int2x2(1,2,3,4) == int2x2(-1,-2,-3,-4));
STATIC_REQUIRE(int2x2(1,2,3,4) + 2 == int2x2(3,4,5,6));
STATIC_REQUIRE(int2x2(1,2,3,4) - 2 == int2x2(-1,0,1,2));
STATIC_REQUIRE(int2x2(1,2,3,4) * 2 == int2x2(2,4,6,8));
STATIC_REQUIRE(int2x2(1,2,3,4) / 2 == int2x2(0,1,1,2));
STATIC_REQUIRE(4 + int2x2(1,2,3,4) == int2x2(5,6,7,8));
STATIC_REQUIRE(4 - int2x2(1,2,3,4) == int2x2(3,2,1,0));
STATIC_REQUIRE(4 * int2x2(1,2,3,4) == int2x2(4,8,12,16));
STATIC_REQUIRE(4 / int2x2(1,2,3,4) == int2x2(4,2,1,1));
STATIC_REQUIRE(int2x2(1,2,3,4) + int2x2(5,6,7,8) == int2x2(6,8,10,12));
STATIC_REQUIRE(int2x2(1,2,3,4) - int2x2(5,6,7,8) == int2x2(-4,-4,-4,-4));
STATIC_REQUIRE(int2x2(5,6,7,8) / int2x2(1,2,3,4) == int2x2(5,3,2,2));
STATIC_REQUIRE(int2x2() * int2x2() == int2x2());
STATIC_REQUIRE(int3x3() * int3x3() == int3x3());
STATIC_REQUIRE(int2(1,2) * int2x2() == int2(1,2));
STATIC_REQUIRE(int3(1,2,3) * int3x3() == int3(1,2,3));
STATIC_REQUIRE(int4(1,2,3,4) * int4x4() == int4(1,2,3,4));
{
int2x2 v{1,2,3,4};
REQUIRE(&v == &(v += 3));
REQUIRE(v == int2x2{4,5,6,7});
REQUIRE(&v == &(v += int2x2{1,2,3,4}));
REQUIRE(v == int2x2{5,7,9,11});
}
{
int2x2 v{4,5,6,7};
REQUIRE(&v == &(v -= 3));
REQUIRE(v == int2x2{1,2,3,4});
REQUIRE(&v == &(v -= int2x2{2,4,6,8}));
REQUIRE(v == int2x2{-1,-2,-3,-4});
}
{
int2x2 v{1,2,3,4};
REQUIRE(&v == &(v *= 3));
REQUIRE(v == int2x2{3,6,9,12});
}
{
int2x2 v{6,18,36,60};
REQUIRE(&v == &(v /= 2));
REQUIRE(v == int2x2{3,9,18,30});
REQUIRE(&v == &(v /= int2x2{3,4,3,10}));
REQUIRE(v == int2x2{1,2,6,3});
}
{
int4 v{0, 0, 0, 1};
REQUIRE(&v == &(v *= translate(int3{1,2,3})));
REQUIRE(v == approx4(1,2,3,1));
}
{
int3 v{1, 2, 3};
REQUIRE(&v == &(v *= int3x3(scale(int3{2,3,4}))));
REQUIRE(v == int3(2,6,12));
}
{
int4x4 v = translate(int3{1, 2, 3});
REQUIRE(&v == &(v *= translate(int3{1,2,3})));
REQUIRE(v == translate(int3{2,4,6}));
}
{
int3x3 v = int3x3(scale(int3{1, 2, 3}));
REQUIRE(&v == &(v *= int3x3(scale(int3{2,3,4}))));
REQUIRE(v == int3x3(scale(int3{2,6,12})));
}
}
SECTION("Matrix Functions") {
{
STATIC_REQUIRE(transpose(int2x2(
1, 2,
3, 4
)) == int2x2(
1, 3,
2, 4
));
STATIC_REQUIRE(transpose(int3x3(
1, 2, 3,
4, 5, 6,
7, 8, 9
)) == int3x3(
1, 4, 7,
2, 5, 8,
3, 6, 9
));
STATIC_REQUIRE(transpose(int4x4(
1, 2, 3, 4,
5, 6, 7, 8,
9, 10, 11, 12,
13, 14, 15, 16
)) == int4x4(
1, 5, 9, 13,
2, 6, 10, 14,
3, 7, 11, 15,
4, 8, 12, 16
));
}
{
constexpr int2x2 m2{1,2,3,4};
constexpr int3x3 m3{1,2,3,4,5,6,7,8,9};
constexpr int4x4 m4{1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16};
STATIC_REQUIRE(determinant(m2) == determinant(transpose(m2)));
STATIC_REQUIRE(determinant(m3) == determinant(transpose(m3)));
STATIC_REQUIRE(determinant(m4) == determinant(transpose(m4)));
STATIC_REQUIRE(determinant(generate_frank_matrix<int, 2>()) == 1);
STATIC_REQUIRE(determinant(generate_frank_matrix<int, 3>()) == 1);
STATIC_REQUIRE(determinant(generate_frank_matrix<int, 4>()) == 1);
STATIC_REQUIRE(determinant(transpose(generate_frank_matrix<int, 2>())) == 1);
STATIC_REQUIRE(determinant(transpose(generate_frank_matrix<int, 3>())) == 1);
STATIC_REQUIRE(determinant(transpose(generate_frank_matrix<int, 4>())) == 1);
}
{
STATIC_REQUIRE(inverse(float2x2()) == float2x2());
STATIC_REQUIRE(inverse(float3x3()) == float3x3());
STATIC_REQUIRE(inverse(float4x4()) == float4x4());
STATIC_REQUIRE(inverse(float2x2(0.5)) == float2x2(2.f));
STATIC_REQUIRE(inverse(float3x3(0.5)) == float3x3(2.f));
STATIC_REQUIRE(inverse(float4x4(0.5)) == float4x4(2.f));
STATIC_REQUIRE(inverse(translate(float3{1.f,2.f,3.f})) == approx4x4(translate(float3{-1.f,-2.f,-3.f})));
REQUIRE(inverse(rotate(0.5f,normalize(float3{1.f,2.f,3.f}))) == approx4x4(rotate(-0.5f,normalize(float3{1.f,2.f,3.f}))));
REQUIRE(inverse(float3x3(rotate(0.5f,normalize(float3{1.f,2.f,3.f})))) == approx3x3(float3x3(rotate(-0.5f,normalize(float3{1.f,2.f,3.f})))));
REQUIRE(inverse(float2x2(rotate(0.5f,float3{0,0,1}))) == approx2x2(float2x2(rotate(-0.5f,float3{0,0,1}))));
}
}
}
+174
View File
@@ -0,0 +1,174 @@
/*******************************************************************************
* This file is part of the "https://github.com/blackmatov/vmath.hpp"
* For conditions of distribution and use, see copyright notice in LICENSE.md
* Copyright (C) 2020, by Matvey Cherevko (blackmatov@gmail.com)
******************************************************************************/
#include <vmath.hpp/vmath_mat.hpp>
#include <vmath.hpp/vmath_mat_fun.hpp>
#define CATCH_CONFIG_FAST_COMPILE
#include <catch2/catch.hpp>
#include "vmath_tests.hpp"
namespace
{
using namespace vmath_hpp;
using namespace vmath_tests;
}
TEST_CASE("vmath/mat") {
SECTION("size/sizeof") {
STATIC_REQUIRE(int2x2{}.size == 2);
STATIC_REQUIRE(int3x3{}.size == 3);
STATIC_REQUIRE(int4x4{}.size == 4);
STATIC_REQUIRE(sizeof(int2x2{}) == sizeof(int) * 2 * 2);
STATIC_REQUIRE(sizeof(int3x3{}) == sizeof(int) * 3 * 3);
STATIC_REQUIRE(sizeof(int4x4{}) == sizeof(int) * 4 * 4);
}
SECTION("ctors") {
{
STATIC_REQUIRE(int2x2()[0] == int2(1,0));
STATIC_REQUIRE(int2x2()[1] == int2(0,1));
STATIC_REQUIRE(int2x2(1,2,3,4)[0] == int2(1,2));
STATIC_REQUIRE(int2x2(1,2,3,4)[1] == int2(3,4));
STATIC_REQUIRE(int2x2({1,2},{3,4})[0] == int2(1,2));
STATIC_REQUIRE(int2x2({1,2},{3,4})[1] == int2(3,4));
}
{
constexpr int2x2 v(1,2,3,4);
constexpr int2x2 v2 = v;
STATIC_REQUIRE(v2 == int2x2(1,2,3,4));
}
{
constexpr int2x2 v(1,2,3,4);
constexpr int2x2 v2 = std::move(v);
STATIC_REQUIRE(v2 == int2x2(1,2,3,4));
}
{
STATIC_REQUIRE(int2x2() == int2x2(1,0,0,1));
STATIC_REQUIRE(int2x2(2) == int2x2(2,0,0,2));
STATIC_REQUIRE(int2x2(1,2,3,4) == int2x2(1,2,3,4));
STATIC_REQUIRE(int2x2({1,2},{3,4}) == int2x2(1,2,3,4));
STATIC_REQUIRE(int2x2(int2x2({1,2},{3,4})) == int2x2(1,2,3,4));
STATIC_REQUIRE(int2x2(int3x3({1,2,3},{4,5,6},{7,8,9})) == int2x2(1,2,4,5));
STATIC_REQUIRE(int2x2(int4x4({1,2,3,4},{5,6,7,8},{9,10,11,12},{13,14,15,16})) == int2x2(1,2,5,6));
STATIC_REQUIRE(int3x3() == int3x3(1,0,0,0,1,0,0,0,1));
STATIC_REQUIRE(int3x3(2) == int3x3(2,0,0,0,2,0,0,0,2));
STATIC_REQUIRE(int3x3(1,2,3,4,5,6,7,8,9) == int3x3(1,2,3,4,5,6,7,8,9));
STATIC_REQUIRE(int3x3({1,2,3},{4,5,6},{7,8,9}) == int3x3(1,2,3,4,5,6,7,8,9));
STATIC_REQUIRE(int3x3(int3x3({1,2,3},{4,5,6},{7,8,9})) == int3x3(1,2,3,4,5,6,7,8,9));
STATIC_REQUIRE(int3x3(int2x2({1,2},{3,4})) == int3x3(1,2,0,3,4,0,0,0,1));
STATIC_REQUIRE(int3x3(int4x4({1,2,3,4},{5,6,7,8},{9,10,11,12},{13,14,15,16})) == int3x3(1,2,3,5,6,7,9,10,11));
STATIC_REQUIRE(int4x4() == int4x4(1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1));
STATIC_REQUIRE(int4x4(2) == int4x4(2,0,0,0,0,2,0,0,0,0,2,0,0,0,0,2));
STATIC_REQUIRE(int4x4(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16) == int4x4(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16));
STATIC_REQUIRE(int4x4({1,2,3,4},{5,6,7,8},{9,10,11,12},{13,14,15,16}) == int4x4(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16));
STATIC_REQUIRE(int4x4(int4x4({1,2,3,4},{5,6,7,8},{9,10,11,12},{13,14,15,16})) == int4x4(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16));
STATIC_REQUIRE(int4x4(int2x2({1,2},{3,4})) == int4x4(1,2,0,0,3,4,0,0,0,0,1,0,0,0,0,1));
STATIC_REQUIRE(int4x4(int3x3({1,2,3},{4,5,6},{7,8,9})) == int4x4(1,2,3,0,4,5,6,0,7,8,9,0,0,0,0,1));
}
}
SECTION("operator=") {
{
int2x2 v(1,2,3,4);
int2x2 v2;
v2 = v;
REQUIRE(v2 == int2x2(1,2,3,4));
}
{
int2x2 v(1,2,3,4);
int2x2 v2;
v2 = std::move(v);
REQUIRE(v2 == int2x2(1,2,3,4));
}
}
SECTION("swap") {
{
int2x2 v1(1,2,3,4);
int2x2 v2(4,5,6,7);
v1.swap(v2);
REQUIRE(v1 == int2x2(4,5,6,7));
REQUIRE(v2 == int2x2(1,2,3,4));
}
{
int2x2 v1(1,2,3,4);
int2x2 v2(4,5,6,7);
swap(v1, v2);
REQUIRE(v1 == int2x2(4,5,6,7));
REQUIRE(v2 == int2x2(1,2,3,4));
}
}
SECTION("operator[]") {
{
STATIC_REQUIRE(int2x2()[0] == int2(1,0));
STATIC_REQUIRE(int2x2()[1] == int2(0,1));
STATIC_REQUIRE(int3x3()[0] == int3(1,0,0));
STATIC_REQUIRE(int3x3()[1] == int3(0,1,0));
STATIC_REQUIRE(int3x3()[2] == int3(0,0,1));
STATIC_REQUIRE(int4x4()[0] == int4(1,0,0,0));
STATIC_REQUIRE(int4x4()[1] == int4(0,1,0,0));
STATIC_REQUIRE(int4x4()[2] == int4(0,0,1,0));
STATIC_REQUIRE(int4x4()[3] == int4(0,0,0,1));
}
{
int2x2 v;
v[0] = int2(1,2);
v[1] = int2(3,4);
REQUIRE(v == int2x2(1,2,3,4));
}
{
int3x3 v;
v[0] = int3(1,2,3);
v[1] = int3(4,5,6);
v[2] = int3(7,8,9);
REQUIRE(v == int3x3(1,2,3,4,5,6,7,8,9));
}
{
int4x4 v;
v[0] = int4(1,2,3,4);
v[1] = int4(5,6,7,8);
v[2] = int4(9,10,11,12);
v[3] = int4(13,14,15,16);
REQUIRE(v == int4x4(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16));
}
}
SECTION("at") {
STATIC_REQUIRE(int2x2(1,2,3,4).at(0) == int2(1,2));
STATIC_REQUIRE(int2x2(1,2,3,4).at(1) == int2(3,4));
REQUIRE_THROWS_AS(int2x2(1,2,3,4).at(2), std::out_of_range);
}
SECTION("operator==/operator!=") {
STATIC_REQUIRE(int2x2(1,2,3,4) == int2x2(1,2,3,4));
STATIC_REQUIRE_FALSE(int2x2(1,2,3,4) == int2x2(2,2,3,4));
STATIC_REQUIRE_FALSE(int2x2(1,2,3,4) == int2x2(1,3,3,4));
STATIC_REQUIRE_FALSE(int2x2(1,2,3,4) != int2x2(1,2,3,4));
STATIC_REQUIRE(int2x2(1,2,3,4) != int2x2(2,2,3,4));
STATIC_REQUIRE(int2x2(1,2,3,4) != int2x2(1,3,3,4));
}
SECTION("operator<") {
STATIC_REQUIRE_FALSE(int2x2(1,2,3,4) < int2x2(1,2,3,4));
STATIC_REQUIRE(int2x2(1,1,3,4) < int2x2(1,2,3,4));
STATIC_REQUIRE_FALSE(int2x2(1,2,3,4) < int2x2(1,1,3,4));
STATIC_REQUIRE(int2x2(0,3,3,4) < int2x2(1,2,3,4));
STATIC_REQUIRE_FALSE(int2x2(1,2,3,4) < int2x2(0,3,3,4));
}
}
-18
View File
@@ -1,18 +0,0 @@
/*******************************************************************************
* This file is part of the "https://github.com/blackmatov/vmath.hpp"
* For conditions of distribution and use, see copyright notice in LICENSE.md
* Copyright (C) 2020, by Matvey Cherevko (blackmatov@gmail.com)
******************************************************************************/
#define CATCH_CONFIG_FAST_COMPILE
#include <catch2/catch.hpp>
#include <vmath.hpp/vmath.hpp>
namespace
{
}
TEST_CASE("vmath") {
REQUIRE(true);
}
+100
View File
@@ -0,0 +1,100 @@
/*******************************************************************************
* This file is part of the "https://github.com/blackmatov/vmath.hpp"
* For conditions of distribution and use, see copyright notice in LICENSE.md
* Copyright (C) 2020, by Matvey Cherevko (blackmatov@gmail.com)
******************************************************************************/
#include <vmath.hpp/vmath_vec.hpp>
#include <vmath.hpp/vmath_vec_fun.hpp>
#include <limits>
namespace vmath_tests
{
using namespace vmath_hpp;
template < typename T >
inline constexpr T epsilon = std::numeric_limits<T>::epsilon() * 100;
template < typename T >
struct approx {
T value;
explicit constexpr approx(T v) : value(v) {}
friend constexpr bool operator==(const T& l, const approx& r) {
return equal_to(l, r.value, epsilon<T>);
}
};
template < typename T >
struct approx2 {
vec<T, 2> value;
constexpr explicit approx2(T v) : value(v) {}
constexpr explicit approx2(T x, T y) : value(x, y) {}
constexpr explicit approx2(const vec<T, 2>& v) : value(v) {}
friend constexpr bool operator==(const vec<T, 2>& l, const approx2& r) {
return all(equal_to(l, r.value, epsilon<T>));
}
};
template < typename T >
struct approx3 {
vec<T, 3> value;
constexpr explicit approx3(T v) : value(v) {}
constexpr explicit approx3(T x, T y, T z) : value(x, y, z) {}
constexpr explicit approx3(const vec<T, 3>& v) : value(v) {}
friend constexpr bool operator==(const vec<T, 3>& l, const approx3& r) {
return all(equal_to(l, r.value, epsilon<T>));
}
};
template < typename T >
struct approx4 {
vec<T, 4> value;
constexpr explicit approx4(T v) : value(v) {}
constexpr explicit approx4(T x, T y, T z, T w) : value(x, y, z, w) {}
constexpr explicit approx4(const vec<T, 4>& v) : value(v) {}
friend constexpr bool operator==(const vec<T, 4>& l, const approx4& r) {
return all(equal_to(l, r.value, epsilon<T>));
}
};
template < typename T >
struct approx2x2 {
mat<T, 2> value;
constexpr explicit approx2x2(const mat<T, 2>& v) : value(v) {}
friend constexpr bool operator==(const mat<T, 2>& l, const approx2x2& r) {
return l[0] == approx2(r.value[0])
&& l[1] == approx2(r.value[1]);
}
};
template < typename T >
struct approx3x3 {
mat<T, 3> value;
constexpr explicit approx3x3(const mat<T, 3>& v) : value(v) {}
friend constexpr bool operator==(const mat<T, 3>& l, const approx3x3& r) {
return l[0] == approx3(r.value[0])
&& l[1] == approx3(r.value[1])
&& l[2] == approx3(r.value[2]);
}
};
template < typename T >
struct approx4x4 {
mat<T, 4> value;
constexpr explicit approx4x4(const mat<T, 4>& v) : value(v) {}
friend constexpr bool operator==(const mat<T, 4>& l, const approx4x4& r) {
return l[0] == approx4(r.value[0])
&& l[1] == approx4(r.value[1])
&& l[2] == approx4(r.value[2])
&& l[3] == approx4(r.value[3]);
}
};
}
+246
View File
@@ -0,0 +1,246 @@
/*******************************************************************************
* This file is part of the "https://github.com/blackmatov/vmath.hpp"
* For conditions of distribution and use, see copyright notice in LICENSE.md
* Copyright (C) 2020, by Matvey Cherevko (blackmatov@gmail.com)
******************************************************************************/
#include <vmath.hpp/vmath_ext.hpp>
#define CATCH_CONFIG_FAST_COMPILE
#include <catch2/catch.hpp>
#include "vmath_tests.hpp"
namespace
{
using namespace vmath_hpp;
using namespace vmath_tests;
}
TEST_CASE("vmath/vec_fun") {
SECTION("Detail") {
STATIC_REQUIRE(map([](const int& x){
return x * 2;
}, int2{1}) == int2{2});
STATIC_REQUIRE(zip([](const int& x, const int& y){
return x + y;
}, int2{1}, int2{1}) == int2{2});
STATIC_REQUIRE(zip([](const int& x, const int& y, const int& z){
return x + y + z;
}, int2{1}, int2{1}, int2{1}) == int2(3));
STATIC_REQUIRE(fold([](int acc, const int& x){
return acc + x;
}, 0, int2{1}) == 2);
STATIC_REQUIRE(fold([](int acc, const int& x, const int& y){
return acc + x + y;
}, 0, int2{1}, int2{1}) == 4);
STATIC_REQUIRE(fold1([](const int& acc, const int& x){
return acc + x;
}, int2{1}) == 2);
}
SECTION("Operators") {
STATIC_REQUIRE(-int2(1,-2) == int2(-1,2));
STATIC_REQUIRE(int2(1,2) + 3 == int2(4,5));
STATIC_REQUIRE(int2(1,2) - 3 == int2(-2,-1));
STATIC_REQUIRE(int2(1,2) * 3 == int2(3,6));
STATIC_REQUIRE(int2(2,4) / 2 == int2(1,2));
STATIC_REQUIRE(3 + int2(1,2) == int2(4,5));
STATIC_REQUIRE(3 - int2(1,2) == int2(2,1));
STATIC_REQUIRE(3 * int2(1,2) == int2(3,6));
STATIC_REQUIRE(4 / int2(2,4) == int2(2,1));
STATIC_REQUIRE(int2(1,2) + int2(3,4) == int2(4,6));
STATIC_REQUIRE(int2(1,2) - int2(3,4) == int2(-2,-2));
STATIC_REQUIRE(int2(1,2) * int2(3,4) == int2(3,8));
STATIC_REQUIRE(int2(3,4) / int2(1,2) == int2(3,2));
{
int2 v{1,2};
REQUIRE(&v == &(v += 3));
REQUIRE(v == int2{4,5});
REQUIRE(&v == &(v += int2{1,2}));
REQUIRE(v == int2{5,7});
}
{
int2 v{4,5};
REQUIRE(&v == &(v -= 3));
REQUIRE(v == int2{1,2});
REQUIRE(&v == &(v -= int2{2,4}));
REQUIRE(v == int2{-1,-2});
}
{
int2 v{1,2};
REQUIRE(&v == &(v *= 3));
REQUIRE(v == int2{3,6});
REQUIRE(&v == &(v *= int2{2,3}));
REQUIRE(v == int2{6,18});
}
{
int2 v{6,18};
REQUIRE(&v == &(v /= 2));
REQUIRE(v == int2{3,9});
REQUIRE(&v == &(v /= int2{3,4}));
REQUIRE(v == int2{1,2});
}
}
SECTION("Angle and Trigonometry Functions") {
STATIC_REQUIRE(radians(degrees(float2(12.13f))) == approx2(12.13f));
STATIC_REQUIRE(degrees(radians(float2(12.13f))) == approx2(12.13f));
(void)sin(float2(1.f));
(void)cos(float2(1.f));
(void)tan(float2(1.f));
(void)asin(float2(1.f));
(void)acos(float2(1.f));
(void)atan(float2(1.f));
(void)atan2(float2(1.f), float2(1.f));
(void)sinh(float2(1.f));
(void)cosh(float2(1.f));
(void)tanh(float2(1.f));
(void)asinh(float2(1.f));
(void)acosh(float2(1.f));
(void)atanh(float2(1.f));
}
SECTION("Exponential Functions") {
(void)pow(float2(1.f), float2(2.f));
(void)exp(float2(1.f));
(void)log(float2(1.f));
(void)exp2(float2(1.f));
(void)log2(float2(1.f));
(void)sqrt(float2(1.f));
(void)rsqrt(float2(1.f));
}
SECTION("Common Functions") {
STATIC_REQUIRE(abs(float2(1.f, -1.f)) == approx2(1.f,1.f));
STATIC_REQUIRE(sign(float3(1.f, -1.f, 0.f)) == approx3(1.f,-1.f,0.f));
STATIC_REQUIRE(reciprocal(float2(2.f, 4.f)) == approx2(0.5f,0.25f));
(void)floor(float2(1.f, -1.f));
(void)trunc(float2(1.f, -1.f));
(void)round(float2(1.f, -1.f));
(void)ceil(float2(1.f, -1.f));
(void)fract(float2(1.f, -1.f));
REQUIRE(fmod(float2(1.7f), 1.2f) == approx2(0.5f));
REQUIRE(fmod(float2(1.7f), float2(1.2f)) == approx2(0.5f));
{
float2 out_i{};
REQUIRE(modf(float2(1.7f), &out_i) == approx2(0.7f));
REQUIRE(out_i.x == Approx(1.f));
}
STATIC_REQUIRE(min(int2(1,2)) == 1);
STATIC_REQUIRE(min(int2(1,2), 1) == int2(1,1));
STATIC_REQUIRE(min(int2(1,1), int2(0,2)) == int2(0,1));
STATIC_REQUIRE(max(int2(1,2)) == 2);
STATIC_REQUIRE(max(int2(1,2), 1) == int2(1,2));
STATIC_REQUIRE(max(int2(1,1), int2(0,2)) == int2(1,2));
STATIC_REQUIRE(clamp(int2(1,2), 0, 1) == int2(1,1));
STATIC_REQUIRE(clamp(int2(1,2), int2(0), int2(1)) == int2(1,1));
STATIC_REQUIRE(saturate(float3(-1.f,0.5,1.5f)) == approx3(0.f,0.5f,1.f));
STATIC_REQUIRE(lerp(float2(0.f), float2(10.f), 0.5f) == approx2(5.f));
STATIC_REQUIRE(lerp(float2(0.f), float2(10.f), float2(0.5f)) == approx2(5.f));
STATIC_REQUIRE(step(0.5f, float2(0.4f)) == approx2(0.f));
STATIC_REQUIRE(step(0.5f, float2(0.6f)) == approx2(1.f));
STATIC_REQUIRE(step(float2(0.5f), float2(0.4f)) == approx2(0.f));
STATIC_REQUIRE(step(float2(0.5f), float2(0.6f)) == approx2(1.f));
STATIC_REQUIRE(smoothstep(0.f, 1.f, float2(0.1f)) == approx2(0.028f));
STATIC_REQUIRE(smoothstep(float2(0.f), float2(1.f), float2(0.1f)) == approx2(0.028f));
REQUIRE_FALSE(isnan(float2(1.f)).x);
REQUIRE_FALSE(isinf(float2(1.f)).x);
REQUIRE(isfinite(float2(1.f)).x);
REQUIRE_FALSE(fma(float2(2.f), float2(3.f), float2(4.f)).x == Approx(12.f));
{
int2 out_exp{};
REQUIRE(frexp(float2(1.7f), &out_exp).x == Approx(0.85f));
REQUIRE(out_exp == int2(1));
}
REQUIRE(ldexp(float2(0.85f), int2(1)).x == Approx(1.7f));
}
SECTION("Geometric Functions") {
REQUIRE(length(float2(10.f,0.f)) == Approx(10.f));
REQUIRE(length(float2(-10.f,0.f)) == Approx(10.f));
STATIC_REQUIRE(length2(float2(10.f,0.f)) == approx(100.f));
STATIC_REQUIRE(length2(float2(-10.f,0.f)) == approx(100.f));
REQUIRE(distance(float2(5.f,0.f), float2(10.f,0.f)) == Approx(5.f));
REQUIRE(distance(float2(-5.f,0.f), float2(-10.f,0.f)) == Approx(5.f));
STATIC_REQUIRE(distance2(float2(5.f,0.f), float2(10.f,0.f)) == approx(25.f));
STATIC_REQUIRE(distance2(float2(-5.f,0.f), float2(-10.f,0.f)) == approx(25.f));
STATIC_REQUIRE(dot(int2(1,2),int2(3,4)) == 11);
STATIC_REQUIRE(cross(int2(1,0),int2(0,1)) == 1);
STATIC_REQUIRE(cross(int3(1,0,0),int3(0,1,0)) == int3(0,0,1));
REQUIRE(normalize(float2(0.5f,0.f)).x == Approx(1.f));
STATIC_REQUIRE(faceforward(float2(1.f), float2(2.f), float2(3.f)).x == approx(-1.f));
STATIC_REQUIRE(reflect(float2(1.f), float2(2.f)).x == approx(-15.f));
REQUIRE(refract(float2(1.f), float2(2.f), 1.f).x == Approx(-15.f));
}
SECTION("Vector Relational Functions") {
STATIC_REQUIRE(less(int3(1,1,1), int3(0,1,2)) == bool3(false, false, true));
STATIC_REQUIRE(less_equal(int3(1,1,1), int3(0,1,2)) == bool3(false, true, true));
STATIC_REQUIRE(greater(int3(1,1,1), int3(0,1,2)) == bool3(true, false, false));
STATIC_REQUIRE(greater_equal(int3(1,1,1), int3(0,1,2)) == bool3(true, true, false));
STATIC_REQUIRE(equal_to(int3(1,1,1), int3(0,1,2)) == bool3(false, true, false));
STATIC_REQUIRE(equal_to(int4(1,1,1,1), int4(0,1,2,3), 0) == bool4(false, true, false, false));
STATIC_REQUIRE(equal_to(int4(1,1,1,1), int4(0,1,2,3), 1) == bool4(true, true, true, false));
STATIC_REQUIRE(equal_to(int4(1,1,1,1), int4(0,1,2,3), 2) == bool4(true, true, true, true));
STATIC_REQUIRE(not_equal_to(int3(1,1,1), int3(0,1,2)) == bool3(true, false, true));
STATIC_REQUIRE(not_equal_to(int4(1,1,1,1), int4(0,1,2,3), 0) == bool4(true, false, true, true));
STATIC_REQUIRE(not_equal_to(int4(1,1,1,1), int4(0,1,2,3), 1) == bool4(false, false, false, true));
STATIC_REQUIRE(not_equal_to(int4(1,1,1,1), int4(0,1,2,3), 2) == bool4(false, false, false, false));
STATIC_REQUIRE_FALSE(any(bool2(false, false)));
STATIC_REQUIRE(any(bool2(true, false)));
STATIC_REQUIRE(any(bool2(false, true)));
STATIC_REQUIRE(any(bool2(true, true)));
STATIC_REQUIRE_FALSE(any(int2(0, 0)));
STATIC_REQUIRE(any(int2(1, 0)));
STATIC_REQUIRE(any(int2(0, 1)));
STATIC_REQUIRE(any(int2(1, 1)));
STATIC_REQUIRE_FALSE(all(bool2(false, false)));
STATIC_REQUIRE_FALSE(all(bool2(true, false)));
STATIC_REQUIRE_FALSE(all(bool2(false, true)));
STATIC_REQUIRE(all(bool2(true, true)));
STATIC_REQUIRE_FALSE(all(int2(0, 0)));
STATIC_REQUIRE_FALSE(all(int2(1, 0)));
STATIC_REQUIRE_FALSE(all(int2(0, 1)));
STATIC_REQUIRE(all(int2(1, 1)));
}
}
+176
View File
@@ -0,0 +1,176 @@
/*******************************************************************************
* This file is part of the "https://github.com/blackmatov/vmath.hpp"
* For conditions of distribution and use, see copyright notice in LICENSE.md
* Copyright (C) 2020, by Matvey Cherevko (blackmatov@gmail.com)
******************************************************************************/
#include <vmath.hpp/vmath_vec.hpp>
#include <vmath.hpp/vmath_vec_fun.hpp>
#define CATCH_CONFIG_FAST_COMPILE
#include <catch2/catch.hpp>
#include "vmath_tests.hpp"
namespace
{
using namespace vmath_hpp;
using namespace vmath_tests;
}
TEST_CASE("vmath/vec") {
SECTION("size/sizeof") {
STATIC_REQUIRE(int2{}.size == 2);
STATIC_REQUIRE(int3{}.size == 3);
STATIC_REQUIRE(int4{}.size == 4);
STATIC_REQUIRE(sizeof(int2{}) == sizeof(int) * 2);
STATIC_REQUIRE(sizeof(int3{}) == sizeof(int) * 3);
STATIC_REQUIRE(sizeof(int4{}) == sizeof(int) * 4);
}
SECTION("ctors") {
{
STATIC_REQUIRE(int2().x == 0);
STATIC_REQUIRE(int2().y == 0);
STATIC_REQUIRE(int2(1).x == 1);
STATIC_REQUIRE(int2(1).y == 1);
STATIC_REQUIRE(int2(1,2).x == 1);
STATIC_REQUIRE(int2(1,2).y == 2);
}
{
constexpr int2 v(1,2);
constexpr int2 v2 = v;
STATIC_REQUIRE(v2 == int2(1,2));
}
{
constexpr int2 v(1,2);
constexpr int2 v2 = std::move(v);
STATIC_REQUIRE(v2 == int2(1,2));
}
{
STATIC_REQUIRE(int2(1) == int2(1,1));
STATIC_REQUIRE(int2(1,2) == int2(1,2));
STATIC_REQUIRE(int2(int2(1,2)) == int2(1,2));
STATIC_REQUIRE(int2(int3(1,2,3)) == int2(1,2));
STATIC_REQUIRE(int2(int4(1,2,3,4)) == int2(1,2));
STATIC_REQUIRE(int3(1) == int3(1,1,1));
STATIC_REQUIRE(int3(1,2,3) == int3(1,2,3));
STATIC_REQUIRE(int3(int2(1,2),3) == int3(1,2,3));
STATIC_REQUIRE(int3(1,int2(2,3)) == int3(1,2,3));
STATIC_REQUIRE(int3(int3(1,2,3)) == int3(1,2,3));
STATIC_REQUIRE(int3(int4(1,2,3,4)) == int3(1,2,3));
STATIC_REQUIRE(int4(1) == int4(1,1,1,1));
STATIC_REQUIRE(int4(1,2,3,4) == int4(1,2,3,4));
STATIC_REQUIRE(int4(int2(1,2),3,4) == int4(1,2,3,4));
STATIC_REQUIRE(int4(1,int2(2,3),4) == int4(1,2,3,4));
STATIC_REQUIRE(int4(1,2,int2(3,4)) == int4(1,2,3,4));
STATIC_REQUIRE(int4(int2(1,2),int2(3,4)) == int4(1,2,3,4));
STATIC_REQUIRE(int4(int3(1,2,3),4) == int4(1,2,3,4));
STATIC_REQUIRE(int4(1,int3(2,3,4)) == int4(1,2,3,4));
}
}
SECTION("operator=") {
{
int2 v(1,2);
int2 v2;
v2 = v;
REQUIRE(v2 == int2(1,2));
}
{
int2 v(1,2);
int2 v2;
v2 = std::move(v);
REQUIRE(v2 == int2(1,2));
}
}
SECTION("swap") {
{
int2 v1(1,2);
int2 v2(4,5);
v1.swap(v2);
REQUIRE(v1 == int2(4,5));
REQUIRE(v2 == int2(1,2));
}
{
int2 v1(1,2);
int2 v2(4,5);
swap(v1, v2);
REQUIRE(v1 == int2(4,5));
REQUIRE(v2 == int2(1,2));
}
}
SECTION("operator[]") {
{
STATIC_REQUIRE(int2(1,2).x == 1);
STATIC_REQUIRE(int2(1,2).y == 2);
STATIC_REQUIRE(int3(1,2,3).x == 1);
STATIC_REQUIRE(int3(1,2,3).y == 2);
STATIC_REQUIRE(int3(1,2,3).z == 3);
STATIC_REQUIRE(int4(1,2,3,4).x == 1);
STATIC_REQUIRE(int4(1,2,3,4).y == 2);
STATIC_REQUIRE(int4(1,2,3,4).z == 3);
STATIC_REQUIRE(int4(1,2,3,4).w == 4);
}
{
STATIC_REQUIRE(int2(1,2)[0] == 1);
STATIC_REQUIRE(int2(1,2)[1] == 2);
}
{
int2 v;
v.x = 1;
v.y = 2;
REQUIRE(v == int2(1,2));
}
{
int3 v;
v.x = 1;
v.y = 2;
v.z = 3;
REQUIRE(v == int3(1,2,3));
}
{
int4 v;
v.x = 1;
v.y = 2;
v.z = 3;
v.w = 4;
REQUIRE(v == int4(1,2,3,4));
}
}
SECTION("at") {
STATIC_REQUIRE(int2(1,2).at(0) == 1);
STATIC_REQUIRE(int2(1,2).at(1) == 2);
REQUIRE_THROWS_AS(int2(1,2).at(2), std::out_of_range);
}
SECTION("operator==/operator!=") {
STATIC_REQUIRE(int2(1,2) == int2(1,2));
STATIC_REQUIRE_FALSE(int2(1,2) == int2(2,2));
STATIC_REQUIRE_FALSE(int2(1,2) == int2(1,3));
STATIC_REQUIRE_FALSE(int2(1,2) != int2(1,2));
STATIC_REQUIRE(int2(1,2) != int2(2,2));
STATIC_REQUIRE(int2(1,2) != int2(1,3));
}
SECTION("operator<") {
STATIC_REQUIRE_FALSE(int2(1,2) < int2(1,2));
STATIC_REQUIRE(int2(1,1) < int2(1,2));
STATIC_REQUIRE_FALSE(int2(1,2) < int2(1,1));
STATIC_REQUIRE(int2(0,3) < int2(1,2));
STATIC_REQUIRE_FALSE(int2(1,2) < int2(0,3));
}
}