mtl/include/mtl/vec.hpp

215 lines
3.6 KiB
C++

#pragma once
#include "mtl/target.hpp"
#include <cstddef>
#include "mtl/fixed.hpp"
namespace mtl {
template <size_t M, size_t N>
class mat;
template <size_t N>
class vec {
public:
fixed e[N];
constexpr vec() noexcept {}
constexpr vec(const vec<N>& other) noexcept {
// We need to explicitly define the copy constructor, otherwise
// GCC uses memcpy to copy while in Thumb mode, and that's slow.
#pragma GCC unroll 4 // Force unroll loops. Can't use pragmas or attributes
// because they don't work for inlined functions. Requires
// GCC 8.1
for (size_t i = 0; i < N; ++i) {
e[i] = other.e[i];
}
}
constexpr vec(const fixed (&_e)[N]) noexcept {
#pragma GCC unroll 4
for (size_t i = 0; i < N; ++i) {
e[i] = _e[i];
}
}
constexpr fixed& operator[](size_t i) noexcept {
return e[i];
}
constexpr const fixed& operator[](size_t i) const noexcept {
return e[i];
}
vec<N> operator+(const vec<N>& rhs) const noexcept {
vec<N> res;
#pragma GCC unroll 4
for (size_t i = 0; i < N; ++i) {
res[i] = e[i] + rhs[i];
}
return res;
}
vec<N> operator-(const vec<N>& rhs) const noexcept {
vec<N> res;
#pragma GCC unroll 4
for (size_t i = 0; i < N; ++i) {
res[i] = e[i] - rhs[i];
}
return res;
}
vec<N> operator-() const noexcept {
vec<N> res;
#pragma GCC unroll 4
for (size_t i = 0; i < N; ++i) {
res[i] = -e[i];
}
return res;
}
vec<N> operator*(fixed rhs) const noexcept {
vec<N> res;
#pragma GCC unroll 4
for (size_t i = 0; i < N; ++i) {
res[i] = e[i] * rhs;
}
return res;
}
friend vec<N> operator*(fixed lhs, vec<N> rhs) noexcept {
return rhs * lhs;
}
fixed operator*(const vec<N>& rhs) const noexcept {
fixed res;
#pragma GCC unroll 4
for (size_t i = 0; i < N; ++i) {
res += e[i] * rhs[i];
}
return res;
}
vec<N> operator/(fixed rhs) const noexcept {
vec<N> r;
#pragma GCC unroll 4
for (size_t i = 0; i < N; ++i) {
r[i] = e[i] / rhs;
}
return r;
}
fixed magnitude_sqr() const noexcept {
fixed r;
#pragma GCC unroll 4
for (size_t i = 0; i < N; ++i) {
r += e[i] * e[i];
}
return r;
}
mat<1, N> transpose() const noexcept {
mat<1, N> r;
#pragma GCC unroll 4
for (size_t i = 0; i < N; ++i) {
r.e[0][i] = e[i];
}
return r;
}
bool operator==(const vec<N>& rhs) noexcept {
#pragma GCC unroll 4
for (size_t i = 0; i < N; ++i) {
if (e[i] != rhs.e[i]) {
return false;
}
}
return true;
}
bool operator!=(const vec<N>& rhs) noexcept {
return !(*this == rhs);
}
};
class vec2 : public vec<2> {
public:
fixed& x = e[0];
fixed& y = e[1];
constexpr vec2() noexcept {}
constexpr vec2(const vec<2>& other) noexcept : vec(other) {}
constexpr vec2(fixed _x, fixed _y) noexcept {
x = _x;
y = _y;
}
};
class vec3 : public vec<3> {
public:
fixed& x = e[0];
fixed& y = e[1];
fixed& z = e[2];
constexpr vec3() noexcept {}
constexpr vec3(const vec<3>& other) noexcept : vec(other) {}
constexpr vec3(fixed _x, fixed _y, fixed _z) noexcept {
x = _x;
y = _y;
z = _z;
}
};
class vec4 : public vec<4> {
public:
fixed& x = e[0];
fixed& y = e[1];
fixed& z = e[2];
fixed& w = e[3];
constexpr vec4() noexcept {}
constexpr vec4(const vec<4>& other) noexcept : vec(other) {}
constexpr vec4(fixed _x, fixed _y, fixed _z, fixed _w) noexcept {
x = _x;
y = _y;
z = _z;
w = _w;
}
};
template <typename STREAM_TYPE, size_t N>
STREAM_TYPE& operator<<(STREAM_TYPE& lhs, const vec<N>& rhs) {
lhs << '<';
for (size_t i = 0; i < N; ++i) {
lhs << rhs.e[i];
if (i < N - 1) {
lhs << ", ";
}
}
lhs << '>';
return lhs;
}
} // namespace mtl