diff --git a/libnum/include/num/vec.h b/libnum/include/num/vec.h new file mode 100644 index 0000000..b5e9443 --- /dev/null +++ b/libnum/include/num/vec.h @@ -0,0 +1,202 @@ +//---------------------------------------------------------------------------// +// ," /\ ", Azur: A game engine for CASIO fx-CG and PC // +// | _/__\_ | Designed by Lephe' and the Planète Casio community. // +// "._`\/'_." License: MIT // +//---------------------------------------------------------------------------// +// num.vec: Vector arithmetic +// +// This header provides basic vector arithmetic. It is type-generic and works +// on any numerical type, including integers, floating-point types, and this +// library's fixed-point types. Not all operations are available for all types +// however. +// +// We slightly abuse the underlying object representation by expecting the +// vector type vec to be isomorphic to T[N] so we can perform accesses to +// members with a pointer cast and array access. This access doesn't break +// strict aliasing rules since the members' type is correct. +//--- + +#pragma once + +#include + +namespace libnum { + +template requires(N > 0) +struct vec +{ + T coords[N]; + + inline constexpr int size() const { return N; } + + inline constexpr T &operator[](int i) { + return ((T *)this)[i]; + } + inline constexpr T const &operator[](int i) const { + return ((T *)this)[i]; + } +}; + +template +struct vec +{ + T x, y; + + vec(): x {0}, y {0} {} + vec(T _x, T _y): x {_x}, y {_y} {} + + inline constexpr int size() const { return 2; } + + inline constexpr T &operator[](int i) { + return ((T *)this)[i]; + } + inline constexpr T const &operator[](int i) const { + return ((T *)this)[i]; + } +}; +using vec2 = vec; + +template +struct vec +{ + T x, y, z; + + vec(): x {0}, y {0}, z {0} {} + vec(T _x, T _y, T _z): x {_x}, y {_y}, z {_z} {} + vec(T scalar): x {scalar}, y {scalar}, z {scalar} {} + vec(vec v): x {v.x}, y {v.y}, z {0} {} + vec(vec v, T _z): x {v.x}, y {v.y}, z {_z} {} + + inline constexpr int size() const { return 3; } + + inline constexpr T &operator[](int i) { + return ((T *)this)[i]; + } + inline constexpr T const &operator[](int i) const { + return ((T *)this)[i]; + } + + inline constexpr vec xy() const { + return vec(x, y); + } + inline constexpr vec xz() const { + return vec(x, z); + } + inline constexpr vec yz() const { + return vec(y, z); + } +}; +using vec3 = vec; + +template +struct vec +{ + T x, y, z, w; + + vec(): x {0}, y {0}, z {0} {} + vec(T _x, T _y, T _z, T _w): x {_x}, y {_y}, z {_z}, w {_w} {} + vec(T scalar): x {scalar}, y {scalar}, z {scalar}, w {scalar} {} + vec(vec v): x {v.x}, y {v.y}, z {0}, w {0} {} + vec(vec v, T _z, T _w): x {v.x}, y {v.y}, z {_z}, w {_w} {} + vec(vec v): x {v.x}, y {v.y}, z {v.z}, w {0} {} + vec(vec v, T _w): x {v.x}, y {v.y}, z {v.z}, w {_w} {} + + inline constexpr int size() const { return 4; } + + inline constexpr T &operator[](int i) { + return ((T *)this)[i]; + } + inline constexpr T const &operator[](int i) const { + return ((T *)this)[i]; + } + + inline constexpr vec xyz() const { + return vec(x, y, z); + } +}; +using vec4 = vec; + +/* The following concept identifies vec types */ + +template +struct is_vec_trait: std::false_type {}; + +template +struct is_vec_trait>: std::true_type {}; + +template +concept is_vec = is_vec_trait::value; + +/* Arithmetic */ + +template +inline constexpr vec &operator+=(vec &lhs, vec const &rhs) { + for(int i = 0; i < N; i++) + lhs[i] += rhs[i]; + return lhs; +} +template +inline constexpr vec &operator-=(vec &lhs, vec const &rhs) { + for(int i = 0; i < N; i++) + lhs[i] -= rhs[i]; + return lhs; +} +template +inline constexpr vec &operator*=(vec &lhs, T const &rhs) { + for(int i = 0; i < N; i++) + lhs[i] *= rhs; + return lhs; +} +template +inline constexpr vec &operator*=(vec &lhs, vec const &rhs) { + T r = T(0); + for(int i = 0; i < N; i++) + r += lhs[i] * rhs[i]; + return r; +} +template +inline constexpr vec &operator/=(vec &lhs, T const &rhs) { + for(int i = 0; i < N; i++) + lhs[i] /= rhs; + return lhs; +} + +template +inline constexpr vec operator+(vec lhs, vec const &rhs) { + return lhs += rhs; +} +template +inline constexpr vec operator-(vec lhs, vec const &rhs) { + return lhs -= rhs; +} +template +inline constexpr vec operator*(vec lhs, T const &rhs) { + return lhs *= rhs; +} +template +inline constexpr vec operator*(T const &lhs, vec rhs) { + for(int i = 0; i < N; i++) + rhs[i] *= lhs; + return rhs; +} + +/* Comparisons */ + +template +inline constexpr bool operator==(vec const &lhs, vec const &rhs) { + for(int i = 0; i < N; i++) { + if(lhs[i] != rhs[i]) + return false; + } + return true; +} +template +inline constexpr bool operator!=(vec const &lhs, vec const &rhs) { + for(int i = 0; i < N; i++) { + if(lhs[i] != rhs[i]) + return true; + } + return false; +} + +} /* namespace libnum */ diff --git a/libnum/test/unit_static.cpp b/libnum/test/unit_static.cpp index 24bb1c0..7e43036 100644 --- a/libnum/test/unit_static.cpp +++ b/libnum/test/unit_static.cpp @@ -6,6 +6,7 @@ // unit_static.cpp: Compile-time evaluation tests #include +#include using namespace libnum; static_assert(sizeof(num8) == 1); @@ -13,6 +14,10 @@ static_assert(sizeof(num16) == 2); static_assert(sizeof(num32) == 4); static_assert(sizeof(num64) == 8); +static_assert(sizeof(vec2) == sizeof(num[2])); +static_assert(sizeof(vec) == sizeof(short[3])); +static_assert(sizeof(vec) == sizeof(double[4])); + static_assert(num8(1).v == 0x00); static_assert(num8(0.5).v == 0x80); static_assert(num8(0.0625f).v == 0x10);