This commit is contained in:
Hartmut Seichter 2024-07-11 09:22:39 +02:00
parent cd19543627
commit 63135466a2
8 changed files with 430 additions and 470 deletions

1
.gitignore vendored
View file

@ -3,3 +3,4 @@
compile_commands.json
*.autosave
build
.cache

56
.vscode/settings.json vendored
View file

@ -50,7 +50,61 @@
"typeinfo": "cpp",
"drawable": "cpp",
"userdatacontainer": "cpp",
"*.txx": "cpp"
"*.txx": "cpp",
"cctype": "cpp",
"clocale": "cpp",
"csignal": "cpp",
"cstdarg": "cpp",
"cstddef": "cpp",
"cstdio": "cpp",
"cstdlib": "cpp",
"cstring": "cpp",
"ctime": "cpp",
"cwctype": "cpp",
"any": "cpp",
"atomic": "cpp",
"hash_map": "cpp",
"strstream": "cpp",
"cfenv": "cpp",
"charconv": "cpp",
"cinttypes": "cpp",
"codecvt": "cpp",
"compare": "cpp",
"complex": "cpp",
"condition_variable": "cpp",
"coroutine": "cpp",
"cstdint": "cpp",
"deque": "cpp",
"forward_list": "cpp",
"list": "cpp",
"map": "cpp",
"set": "cpp",
"string": "cpp",
"unordered_set": "cpp",
"algorithm": "cpp",
"iterator": "cpp",
"memory": "cpp",
"memory_resource": "cpp",
"numeric": "cpp",
"random": "cpp",
"ratio": "cpp",
"source_location": "cpp",
"string_view": "cpp",
"system_error": "cpp",
"utility": "cpp",
"hash_set": "cpp",
"fstream": "cpp",
"iomanip": "cpp",
"iostream": "cpp",
"limits": "cpp",
"mutex": "cpp",
"numbers": "cpp",
"semaphore": "cpp",
"sstream": "cpp",
"stdfloat": "cpp",
"text_encoding": "cpp",
"typeindex": "cpp",
"variant": "cpp"
},
"mesonbuild.configureOnOpen": false
}

View file

@ -33,8 +33,8 @@ set(misc
set(srcs
# src/buffer.cpp
src/core.cpp
# src/image.cpp
# src/debug.cpp
src/image.cpp
src/debug.cpp
# src/geometry.cpp
# src/material.cpp
# src/resource.cpp

View file

@ -25,215 +25,11 @@
#include <pw/core/globals.hpp>
#include <pw/core/math.hpp>
#include <pw/core/matrixbase.hpp>
// #include <array>
#include <numeric>
#include <pw/core/vector.hpp>
namespace pw {
template <std::size_t R, std::size_t C, typename T, bool RowMajor = false>
struct matrix_ : matrixbase_<T, matrix_<R, C, T>> {
using base_type = matrixbase_<T, matrix_<R, C, T>>;
using typename base_type::value_type;
using typename base_type::derived_type;
static constexpr std::size_t rows{R};
static constexpr std::size_t cols{C};
static constexpr std::size_t coefficients{R * C};
static constexpr std::size_t diagonal_size{std::min(R,C)};
using col_type = matrix_<R, 1, T>;
using row_type = matrix_<1, C, T>;
using diag_type = matrix_<diagonal_size, 1, T>;
using transpose_type = matrix_<C, R, T>;
value_type data[R * C]{};
template <typename... Arguments>
static constexpr auto make(Arguments&&... values) -> matrix_ {
static_assert(sizeof...(Arguments) == coefficients,
"Incorrect number of arguments");
return {.data = { T(values)... } };
}
constexpr size_t offset(size_t r, size_t c) const noexcept {
return (RowMajor) ? r * C + c : c * R + r;
}
constexpr T& operator()(std::size_t r, std::size_t c) noexcept {
return data[offset(r, c)];
}
constexpr const T& operator()(std::size_t r, std::size_t c) const noexcept {
return data[offset(r, c)];
}
constexpr const T* ptr() const noexcept { return &data[0]; }
//! set identity
constexpr matrix_& set_identity() {
for (std::size_t r = 0; r < rows; r++)
for (std::size_t c = 0; c < cols; c++)
(*this)(r, c) = (c == r) ? T(1) : T(0);
return *this;
}
constexpr matrix_& set_uniform(const T& v) {
std::fill(std::begin(data), std::end(data), v);
return *this;
}
template <std::size_t Rs, std::size_t Cs, bool RowMajorSlice = RowMajor>
auto slice(std::size_t r, std::size_t c) const {
matrix_<Rs, Cs, T, RowMajorSlice> s;
for (std::size_t ri = 0; ri < Rs; ri++)
for (std::size_t ci = 0; ci < Cs; ci++)
s(ri, ci) = (*this)(ri + r, ci + c);
return s;
}
template <std::size_t Rs, std::size_t Cs, bool RowMajorSlice = RowMajor>
matrix_& set_slice(const matrix_<Rs, Cs, T, RowMajorSlice>& s,
std::size_t r, std::size_t c) {
for (std::size_t ri = 0; ri < Rs; ri++)
for (std::size_t ci = 0; ci < Cs; ci++)
(*this)(ri + r, ci + c) = s(ri, ci);
return *this;
}
template <std::size_t Rs, std::size_t Cs, bool RowMajorSlice = RowMajor>
auto minor(std::size_t r0, std::size_t c0) const {
matrix_<Rs, Cs, T, RowMajorSlice> m;
size_t r = 0;
for (size_t ri = 0; ri < R; ri++) {
size_t c = 0;
if (ri == r0)
continue;
for (size_t ci = 0; ci < C; ci++) {
if (ci == c0)
continue;
m(r, c) = (*this)(ri, ci);
c++;
}
r++;
}
return m;
}
constexpr T determinant() const {
T det(0);
for (size_t c = 0; c < C; c++)
det += ((c % 2 == 0) ? (*this)(0, c) : -(*this)(0, c)) *
this->minor<R - 1, C - 1, RowMajor>(0, c).determinant();
return det;
}
auto transposed() const {
transpose_type res;
for (size_t r = rows; r-- > 0;)
for (size_t c = cols; c-- > 0;)
res(c, r) = (*this)(r, c);
return res;
}
auto inverse() const {
T invDet = T(1) / this->determinant();
matrix_<R, C, T, RowMajor> inv;
for (int j = 0; j < C; j++)
for (int i = 0; i < R; i++) {
const T minorDet =
this->minor<R - 1, C - 1, RowMajor>(j, i).determinant();
const T coFactor = ((i + j) % 2 == 1) ? -minorDet : minorDet;
inv(i, j) = invDet * coFactor;
}
return inv;
}
constexpr bool row_major() const { return RowMajor; }
constexpr bool square() const { return R == C; }
constexpr const matrix_ operator+(const matrix_& other) const {
matrix_ res(*this);
for (size_t r = 0; r < R; r++)
for (size_t c = 0; c < C; c++)
res(r, c) += other(r, c);
return res;
}
constexpr const matrix_ operator-(const matrix_& other) const {
matrix_ res(*this);
for (size_t r = 0; r < R; r++)
for (size_t c = 0; c < C; c++)
res(r, c) -= other(r, c);
return res;
}
auto row(size_t row_) const {
row_type r;
for (size_t i = 0; i < cols; i++)
r[i] = (*this)(row_, i);
return r;
}
auto column(size_t col_) const {
col_type c;
for (size_t i = 0; i < rows; i++)
c[i] = (*this)(i, col_);
return c;
}
static constexpr auto identity() {
matrix_ res;
for (std::size_t r = 0; r < rows; r++)
for (std::size_t c = 0; c < cols; c++)
res(r, c) = (c == r) ? T(1) : T(0);
return res;
}
};
template <> constexpr float matrix_<1, 1, float>::determinant() const {
return (*this)(0, 0);
}
template <> constexpr double matrix_<1, 1, double>::determinant() const {
return (*this)(0, 0);
}
template <typename T, std::size_t R, std::size_t Ca, std::size_t Cb>
auto operator*(const matrix_<R, Ca, T>& A, const matrix_<R, Cb, T>& B) {
matrix_<R, Cb, T> result;
result.zero(); // zero the output
for (size_t r = 0; r < R; r++)
for (size_t c = 0; c < Cb; c++)
for (size_t iI = 0; iI < R; iI++)
result(r, c) += A(r, iI) * B(iI, c); // inner product
return result;
}
//
// common matrix types
//
template <typename T> using matrix2x2_ = matrix_<2, 2, T>;
template <typename T> using matrix3x3_ = matrix_<3, 3, T>;
template <typename T> using matrix4x4_ = matrix_<4, 4, T>;
using matrix2x2f = matrix2x2_<float>;
using matrix2x2d = matrix2x2_<double>;
using matrix2x2 = matrix2x2_<real_t>;
using matrix3x3f = matrix3x3_<float>;
using matrix3x3d = matrix3x3_<double>;
using matrix3x3 = matrix3x3_<real_t>;
using matrix4x4f = matrix4x4_<float>;
using matrix4x4d = matrix4x4_<double>;
using matrix4x4 = matrix4x4_<real_t>;
} // namespace pw
#endif

View file

@ -8,8 +8,8 @@
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
@ -27,144 +27,137 @@
namespace pw {
template <typename T>
struct matrix_transform {
template <typename T> struct matrix_transform {
constexpr static matrix_<4,4,T> scale_matrix(const vector3_<T>& s) noexcept
{
matrix_<4,4,T> scale; scale.zero();
scale(0,0) = s[0]; scale(1,1) = s[1]; scale(2,2) = s[2]; scale(3,3) = T(1);
constexpr static matrix_<4, 4, T>
scale_matrix(const vector3_<T>& s) noexcept {
matrix_<4, 4, T> scale;
scale.zero();
scale(0, 0) = s[0];
scale(1, 1) = s[1];
scale(2, 2) = s[2];
scale(3, 3) = T(1);
return scale;
}
inline static
matrix_<4,4,T> perspective_frustum_rh(const T &left,const T &right,
const T &bottom,const T &top,
const T &z_near,const T &z_far)
{
matrix_<4,4,T> frustum; frustum.zero();
constexpr auto perspective_frustum_rh(const T& left, const T& right,
const T& bottom, const T& top,
const T& z_near, const T& z_far) {
matrix<T, 4, 4> frustum::identity();
frustum(0,0) = T(2) * z_near / (right - left);
frustum(1,1) = T(2) * z_near / (top - bottom);
frustum[0][0] = T(2) * z_near / (right - left);
frustum[1][1] = T(2) * z_near / (top - bottom);
frustum(0,2) = (right+left)/(right-left); //A
frustum(1,2) = (top+bottom)/(top-bottom); //B
frustum(2,2) = -(z_far+z_near)/(z_far-z_near); //C
frustum(2,3) = -T(2) * z_far*z_near/(z_far-z_near); //D
frustum[0][2] = (right + left) / (right - left); // A
frustum[1][2] = (top + bottom) / (top - bottom); // B
frustum[2][2] = -(z_far + z_near) / (z_far - z_near); // C
frustum[2][3] = -T(2) * z_far * z_near / (z_far - z_near); // D
frustum(3,2) = -T(1);
frustum[3][2] = -T(1);
return frustum;
}
return frustum;
}
// /// creates a projection from a frustum planes with a reversed depth
// mapped to [0..1] pub fn make_projection_rh_from_frustum_reversed(
// left: f32,
// right: f32,
// bottom: f32,
// top: f32,
// z_near: f32,
// z_far: f32,
// ) -> Mat4 {
// assert!(z_near > 0.0 && z_far > 0.0);
// /// creates a projection from a frustum planes with a reversed depth mapped to [0..1]
// pub fn make_projection_rh_from_frustum_reversed(
// left: f32,
// right: f32,
// bottom: f32,
// top: f32,
// z_near: f32,
// z_far: f32,
// ) -> Mat4 {
// assert!(z_near > 0.0 && z_far > 0.0);
// // info!("near {:?}", z_near);
// // info!("near {:?}", z_near);
// //
// // reversed z 0..1 projection
// //
// let a = (right + left) / (right - left); // position in frame
// horizontal let b = (top + bottom) / (top - bottom); // position in
// frame vertical
// //
// // reversed z 0..1 projection
// //
// let a = (right + left) / (right - left); // position in frame horizontal
// let b = (top + bottom) / (top - bottom); // position in frame vertical
// let c = z_near / (z_far - z_near); // lower bound
// let d = z_far * z_near / (z_far - z_near); // upper bound
// let c = z_near / (z_far - z_near); // lower bound
// let d = z_far * z_near / (z_far - z_near); // upper bound
// let sx = 2.0 * z_near / (right - left); // scale x
// let sy = 2.0 * z_near / (top - bottom); // scale y
// let sx = 2.0 * z_near / (right - left); // scale x
// let sy = 2.0 * z_near / (top - bottom); // scale y
// // reverse z 0..1
// // --------------
// // sx 0 a 0
// // 0 sy b 0
// // 0 0 c d
// // 0 0 -1 0
// // reverse z 0..1
// // --------------
// // sx 0 a 0
// // 0 sy b 0
// // 0 0 c d
// // 0 0 -1 0
// Mat4::from_cols(
// Vec4::new(sx, 0.0, 0.0, 0.0),
// Vec4::new(0.0, sy, 0.0, 0.0),
// Vec4::new(a, b, c, -1.0),
// Vec4::new(0.0, 0.0, d, 0.0),
// )
// }
inline static matrix_<4, 4, T>
perspective_projection(const T& field_of_view, const T& aspect_ratio,
const T& z_near, const T& z_far) {
const auto tan_half = tan(field_of_view / T(2));
const auto right = tan_half * z_near / aspect_ratio;
const auto left = -right;
const auto top = right / aspect_ratio;
const auto bottom = -top;
// Mat4::from_cols(
// Vec4::new(sx, 0.0, 0.0, 0.0),
// Vec4::new(0.0, sy, 0.0, 0.0),
// Vec4::new(a, b, c, -1.0),
// Vec4::new(0.0, 0.0, d, 0.0),
// )
// }
inline static
matrix_<4,4,T> perspective_projection(const T &field_of_view,
const T &aspect_ratio,
const T &z_near,const T &z_far)
{
const auto tan_half = tan(field_of_view / T(2));
const auto right = tan_half * z_near / aspect_ratio;
const auto left = -right;
const auto top = right / aspect_ratio;
const auto bottom = -top;
return perspective_frustum_rh(left, right, bottom, top, z_near, z_far);
}
return perspective_frustum_rh(left,right,
bottom,top,
z_near,z_far);
}
inline static matrix_<4, 4, T>
orthographic_frustum(T left, T right, T bottom, T top, T z_near, T z_far) {
matrix_<4, 4, T> ortho;
ortho.fill(0);
inline static
matrix_<4,4,T> orthographic_frustum(T left, T right,
T bottom,T top,
T z_near, T z_far)
{
ortho(0, 0) = static_cast<T>(2) / (right - left);
ortho(1, 1) = static_cast<T>(2) / (top - bottom);
ortho(2, 2) = -static_cast<T>(2) / (z_far - z_near);
matrix_<4,4,T> ortho; ortho.fill(0);
ortho(3, 0) = -(right + left) / (right - left);
ortho(3, 1) = -(top + bottom) / (top - bottom);
ortho(3, 2) = -(z_far + z_near) / (z_far - z_near);
ortho(0,0) = static_cast<T>(2) / (right-left);
ortho(1,1) = static_cast<T>(2) / (top-bottom);
ortho(2,2) = -static_cast<T>(2) / (z_far-z_near);
ortho(3,0) = -(right+left)/(right-left);
ortho(3,1) = -(top+bottom)/(top-bottom);
ortho(3,2) = -(z_far+z_near)/(z_far-z_near);
ortho(3,3) = 1;
ortho(3, 3) = 1;
return ortho;
}
inline static
matrix_<4,4,T> orthographic_projection(T width,T height,T z_near, T z_far)
{
return orthographic_frustum(-width / 2, width / 2,
-height / 2, height / 2,
z_near,z_far);
}
inline static matrix_<4, 4, T> orthographic_projection(T width, T height,
T z_near, T z_far) {
return orthographic_frustum(-width / 2, width / 2, -height / 2,
height / 2, z_near, z_far);
}
inline static matrix_<4, 4, T> look_at(const vector3_<T>& position,
const vector3_<T>& target,
const vector3_<T>& up) {
matrix_<4, 4, T> view_matrix;
view_matrix.set_identity();
inline static
matrix_<4,4,T> look_at(const vector3_<T> &position,
const vector3_<T> &target,
const vector3_<T> &up)
{
matrix_<4,4,T> view_matrix; view_matrix.set_identity();
const vector3_<T> los = (target - position).normalized(); // line of sight
const vector3_<T> sid = vector3_<T>::cross(los,up).normalized(); // side vector
const vector3_<T> upd = vector3_<T>::cross(sid,los).normalized(); // upvector
const vector3_<T> los =
(target - position).normalized(); // line of sight
const vector3_<T> sid =
vector3_<T>::cross(los, up).normalized(); // side vector
const vector3_<T> upd =
vector3_<T>::cross(sid, los).normalized(); // upvector
// set base vectors
view_matrix.set_slice(sid, 0, 0);
view_matrix.set_slice(upd, 0, 1);
view_matrix.set_slice(los * T(-1), 0, 2);
view_matrix.set_slice(position, 0, 3);
view_matrix.set_slice(sid, 0, 0);
view_matrix.set_slice(upd, 0, 1);
view_matrix.set_slice(los * T(-1), 0, 2);
view_matrix.set_slice(position, 0, 3);
return view_matrix;
return view_matrix;
}
};
}
} // namespace pw
#endif

View file

@ -106,15 +106,88 @@ struct matrixbase_ {
}
constexpr void operator *= (const T& b) { for (auto & e : *this) e *= b; }
constexpr void operator /= (const T& b) { for (auto & e : *this) e /= b; }
constexpr void operator += (const T& b) { for (auto & e : *this) e += b; }
constexpr void operator -= (const T& b) { for (auto & e : *this) e -= b; }
//
// M (op) scalar
//
constexpr Derived operator*(const T& b) const {
Derived r(derived());
for (auto& e : r)
e *= b;
return r;
}
constexpr Derived operator/(const T& b) const {
Derived r(derived());
for (auto& e : r)
e /= b;
return r;
}
constexpr Derived operator+(const T& b) const {
Derived r(derived());
for (auto& e : r)
e += b;
return r;
}
constexpr Derived operator-(const T& b) const {
Derived r(derived());
for (auto& e : r)
e -= b;
return r;
}
constexpr const Derived operator * (const T& b) const { Derived r(derived()); for (auto & e : r) e *= b; return r; }
constexpr const Derived operator / (const T& b) const { Derived r(derived()); for (auto & e : r) e /= b; return r; }
constexpr const Derived operator + (const T& b) const { Derived r(derived()); for (auto & e : r) e += b; return r; }
constexpr const Derived operator - (const T& b) const { Derived r(derived()); for (auto & e : r) e -= b; return r; }
//
// M (op)== N
//
constexpr void operator*=(const std::convertible_to<T> auto& b) {
for (auto& e : derived())
e *= b;
}
constexpr void operator/=(const std::convertible_to<T> auto& b) {
for (auto& e : derived())
e /= b;
}
constexpr void operator+=(const std::convertible_to<T> auto& b) {
for (auto& e : derived())
e += b;
}
constexpr void operator-=(const std::convertible_to<T> auto& b) {
for (auto& e : derived())
e -= b;
}
//
// M (op) N
//
/// @brief in-place addition with matrix of same size
/// @param rhs righthand-side matrix
constexpr void operator+=(const Derived& b) noexcept {
std::transform(b.cbegin(), b.cend(), (*this).cbegin(), (*this).begin(),
std::plus<>{});
}
/// @brief in-place subtraction with matrix of same size
/// @param rhs righthand-side matrix
constexpr void operator-=(const Derived& b) noexcept {
std::transform(b.cbegin(), b.cend(), (*this).cbegin(), (*this).begin(),
std::minus<>{});
}
/// @brief addition with matrix of same size
/// @param rhs righthand-side matrix
constexpr Derived operator+(const std::convertible_to<Derived> auto& rhs) const noexcept {
Derived d{derived()};
std::transform(std::begin(rhs), std::end(rhs), (d).begin(), std::plus<>{});
return d;
}
/// @brief subtraction with matrix of same size
/// @param rhs righthand-side matrix
constexpr Derived operator-(const Derived& rhs) const noexcept {
Derived d(derived());
d -= rhs;
return d;
}
};

View file

@ -23,137 +23,154 @@
#ifndef PW_CORE_VECTOR_HPP
#define PW_CORE_VECTOR_HPP
#include <pw/core/matrix.hpp>
namespace pw {
/**
* Basic vector types used in pixwerx.
*/
template <typename Scalar, unsigned int size> struct vector final {
template <typename T> struct vector2_ : matrix_<2, 1, T> {
using value_type = Scalar;
static constexpr unsigned int coefficients{size};
using base_type = matrix_<2, 1, T>;
Scalar v_[size]{};
using base_type::base_type;
using base_type::operator=;
vector2_(const base_type& m) : base_type(m) {}
vector2_(T x_, T y_) : base_type({x_, y_}) {}
constexpr const T& x() const { return (*this)[0]; }
constexpr T& x() { return (*this)[0]; }
constexpr const T& y() const { return (*this)[1]; }
constexpr T& y() { return (*this)[1]; }
constexpr auto homogenous(T w = 1) const {
return matrix_<3, 1, T>({x(), y(), w});
auto&& data(this auto&& self) {
return std::forward<decltype(self)>(self).v_;
}
static T angle_between(const vector2_& a, const vector2_& b) {
return std::acos(dot(a.normalized(), b.normalized()));
auto&& operator[](this auto&& self, unsigned int e) {
return std::forward<decltype(self)>(self).v_[e];
}
static constexpr auto zero() { return vector2_<T>(0, 0); }
static constexpr auto basis(const auto& d) noexcept {
return [&d]<std::size_t... Ss>(std::index_sequence<Ss...>) {
return vector{(d == Ss) ? Scalar(1) : Scalar(0)...};
}(std::make_index_sequence<size>{});
}
template <typename... Args>
static constexpr auto
make(Args&&... values) noexcept -> vector<Scalar, sizeof...(Args)> {
static_assert(sizeof...(Args) == size, "incorrect number of arguments");
return {{Scalar(values)...}};
}
static constexpr auto all(Scalar value) noexcept -> vector {
return [&value]<std::size_t... Is>(std::index_sequence<Is...>) {
return vector{value + Scalar(Is * 0)...};
}(std::make_index_sequence<size>{});
}
template <typename... Args>
constexpr auto swizzle(Args&&... indices) const noexcept
-> vector<Scalar, sizeof...(Args)> {
return {{Scalar(v_[indices])...}};
}
constexpr auto minor(std::unsigned_integral auto d0) const noexcept {
return [this, &d0]<std::size_t... Ss>(std::index_sequence<Ss...>) {
return vector<Scalar, size - 1>{
(*this).v_[(Ss < d0) ? Ss : Ss + 1]...};
}(std::make_index_sequence<size - 1>{});
}
static constexpr auto sequence(Scalar factor = Scalar{1},
Scalar offset = Scalar{0}) noexcept {
return [&]<std::size_t... Ss>(std::index_sequence<Ss...>) {
return vector<Scalar, size>{{Scalar{Ss} * factor + offset...}};
}(std::make_index_sequence<size>{});
}
constexpr Scalar dot(const auto& other) const {
return [this, &other]<std::size_t... Ss>(std::index_sequence<Ss...>) {
return (... + (other[Ss] * (*this)[Ss]));
}(std::make_index_sequence<size>{});
}
constexpr auto squared_norm() const noexcept { return dot(*this); }
constexpr auto norm() const noexcept {
return std::sqrt(this->squared_norm());
}
constexpr vector operator*(const Scalar& v) const noexcept {
return [this, &v]<std::size_t... Ss>(std::index_sequence<Ss...>) {
return vector{{(*this)[Ss] * v...}};
}(std::make_index_sequence<size>{});
}
constexpr vector operator/(const Scalar& v) const noexcept {
return (*this).operator*(Scalar{1} / v);
}
constexpr vector operator+(const vector& v) const noexcept {
return [this, &v]<std::size_t... Ss>(std::index_sequence<Ss...>) {
return vector{{(*this)[Ss] + v[Ss]...}};
}(std::make_index_sequence<size>{});
}
constexpr vector operator-(const vector& v) const noexcept {
return [this, &v]<std::size_t... Ss>(std::index_sequence<Ss...>) {
return vector{{(*this)[Ss] - v[Ss]...}};
}(std::make_index_sequence<size>{});
}
};
template <typename T> struct vector3_ : matrix_<3, 1, T> {
template <typename Scalar>
struct vector2 : vector<Scalar, 2> {
typedef matrix_<3, 1, T> base_type;
constexpr const Scalar& x() const { return (*this)[0]; }
constexpr Scalar& x() { return (*this)[0]; }
// using base_type::base_type;
// using base_type::operator=;
constexpr const T& x() const { return (*this)[0]; }
constexpr T& x() { return (*this)[0]; }
constexpr vector3_& set_x(T val) {
(*this)[0] = val;
return *this;
}
constexpr const T& y() const { return (*this)[1]; }
constexpr T& y() { return (*this)[1]; }
constexpr vector3_& set_y(T val) {
(*this)[1] = val;
return *this;
}
constexpr const T& z() const { return (*this)[2]; }
constexpr T& z() { return (*this)[2]; }
constexpr vector3_& set_z(T val) {
(*this)[2] = val;
return *this;
}
constexpr auto xy() const { return vector2_({x(), y()}); }
constexpr auto homogenous(T w = 1) const {
return matrix_<4, 1, T>::make(x(), y(), z(), w);
}
constexpr static vector3_ cross(const vector3_& lhs, const vector3_& rhs) {
return vector3_::make(lhs[1] * rhs[2] - rhs[1] * lhs[2],
lhs[2] * rhs[0] - rhs[2] * lhs[0],
lhs[0] * rhs[1] - rhs[0] * lhs[1]);
}
constexpr static auto forward() { return vector3_<T>::make(0, 0, -1); }
constexpr static auto backward() { return vector3_<T>::make(0, 0, +1); }
constexpr static auto up() { return vector3_<T>::make(0, +1, 0); }
constexpr static auto down() { return vector3_<T>::make(0, -1, 0); }
constexpr static auto right() { return vector3_<T>::make(+1, 0, 0); }
constexpr static auto left() { return vector3_<T>::make(-1, 0, 0); }
constexpr static auto x_axis() { return vector3_<T>::make(0, 0, +1); }
constexpr static auto y_axis() { return vector3_<T>::make(0, 0, +1); }
constexpr static auto z_axis() { return vector3_<T>::make(0, 0, +1); }
static constexpr auto zero() { return vector3_(0, 0, 0); }
constexpr const Scalar& y() const { return (*this)[1]; }
constexpr Scalar& y() { return (*this)[1]; }
};
template <typename T> struct vector4_ : matrix_<4, 1, T> {
template <typename Scalar> struct vector3 : vector<Scalar, 3> {
using base_type = matrix_<4, 1, T>;
// using base_type::operator=;
constexpr const T& x() const { return (*this)[0]; }
constexpr T& x() { return (*this)[0]; }
constexpr const T& y() const { return (*this)[1]; }
constexpr T& y() { return (*this)[1]; }
constexpr const T& z() const { return (*this)[2]; }
constexpr T& z() { return (*this)[2]; }
constexpr const T& w() const { return (*this)[3]; }
constexpr T& w() { return (*this)[3]; }
constexpr auto xyz() const { return vector3_<T>::make(x(), y(), z()); }
constexpr auto project() const {
return vector3_<T>::make(x() / w(), y() / w(), z() / w());
constexpr static vector3 cross(const vector3& lhs, const vector3& rhs) {
return {lhs[1] * rhs[2] - rhs[1] * lhs[2],
lhs[2] * rhs[0] - rhs[2] * lhs[0],
lhs[0] * rhs[1] - rhs[0] * lhs[1]};
}
static constexpr auto zero() { return vector2_<T>(0, 0, 0, 0); }
constexpr static auto forward() { return {0, 0, -1}; }
constexpr static auto backward() { return {0, 0, +1}; }
constexpr static auto up() { return {0, +1, 0}; }
constexpr static auto down() { return {0, -1, 0}; }
constexpr static auto right() { return {+1, 0, 0}; }
constexpr static auto left() { return {-1, 0, 0}; }
constexpr static auto x_axis() { return {0, 0, +1}; }
constexpr static auto y_axis() { return {0, 0, +1}; }
constexpr static auto z_axis() { return {0, 0, +1}; }
};
//
//
//
template <typename Scalar> struct vector4 : vector<Scalar, 4> {
using vector2f = vector2_<float>;
using vector2d = vector2_<double>;
using vector2i = vector2_<int>;
using vector2 = vector2_<real_t>;
using vector2_array = std::vector<vector2>;
using base_type = vector<Scalar, 4>;
using vector3f = vector3_<float>;
using vector3d = vector3_<double>;
using vector3 = vector3_<real_t>;
using vector3_array = std::vector<vector3>;
constexpr const Scalar& x() const { return (*this)[0]; }
constexpr Scalar& x() { return (*this)[0]; }
constexpr const Scalar& y() const { return (*this)[1]; }
constexpr Scalar& y() { return (*this)[1]; }
constexpr const Scalar& z() const { return (*this)[2]; }
constexpr Scalar& z() { return (*this)[2]; }
constexpr const Scalar& w() const { return (*this)[3]; }
constexpr Scalar& w() { return (*this)[3]; }
constexpr auto xyz() const { return base_type::swizzle(0,1,2); }
};
using vector2f = vector2<float>;
using vector2d = vector2<double>;
using vector2i = vector2<int>;
using vector3f = vector3<float>;
using vector3d = vector3<double>;
using vector4f = vector4_<float>;
using vector4d = vector4_<double>;
using vector4 = vector4_<real_t>;
} // namespace pw

View file

@ -4,63 +4,89 @@
#include <pw/core/vector.hpp>
TEST_CASE("core", "[matrix]") {
auto m44 = pw::matrix_<2, 2, float>{};
auto m44 = pw::matrix<float,2,2>{};
REQUIRE(m44(0, 0) == 0);
REQUIRE(m44(0, 1) == 0);
REQUIRE(m44(1, 0) == 0);
REQUIRE(m44(1, 1) == 0);
REQUIRE(m44[0][0] == 0);
REQUIRE(m44[0][1] == 0);
REQUIRE(m44[1][0] == 0);
REQUIRE(m44[1][1] == 0);
m44 = pw::matrix2x2_<float>::all(42.42f);
// auto m44_1 = pw::matrix<2, 2, float>{ 5, 4, 3, 2 };
REQUIRE(m44(0, 0) == 42.42f);
REQUIRE(m44(0, 1) == 42.42f);
REQUIRE(m44(1, 0) == 42.42f);
REQUIRE(m44(1, 1) == 42.42f);
// REQUIRE(m44_1(0, 0) == 5);
// REQUIRE(m44_1(0, 1) == 3);
// REQUIRE(m44_1(1, 0) == 4);
// REQUIRE(m44_1(1, 1) == 2);
m44 *= 2;
REQUIRE(m44(0, 0) == 84.84f);
REQUIRE(m44(0, 1) == 84.84f);
REQUIRE(m44(1, 0) == 84.84f);
REQUIRE(m44(1, 1) == 84.84f);
// auto m44_2 = pw::matrix2x2_<float>::all(42.42f);
m44.set_identity();
REQUIRE(m44(0, 0) == 1.0f);
REQUIRE(m44(0, 1) == 0.0f);
REQUIRE(m44(1, 0) == 0.0f);
REQUIRE(m44(1, 1) == 1.0f);
// REQUIRE(m44_2(0, 0) == 42.42f);
// REQUIRE(m44_2(0, 1) == 42.42f);
// REQUIRE(m44_2(1, 0) == 42.42f);
// REQUIRE(m44_2(1, 1) == 42.42f);
auto m44_2 = pw::matrix2x2::make(0, 1, 2, 3);
// m44 *= 2;
// REQUIRE(m44(0, 0) == 84.84f);
// REQUIRE(m44(0, 1) == 84.84f);
// REQUIRE(m44(1, 0) == 84.84f);
// REQUIRE(m44(1, 1) == 84.84f);
REQUIRE(m44_2(0, 0) == 0.0f);
REQUIRE(m44_2(1, 0) == 1.0f);
REQUIRE(m44_2(0, 1) == 2.0f);
REQUIRE(m44_2(1, 1) == 3.0f);
// m44.set_identity();
// REQUIRE(m44(0, 0) == 1.0f);
// REQUIRE(m44(0, 1) == 0.0f);
// REQUIRE(m44(1, 0) == 0.0f);
// REQUIRE(m44(1, 1) == 1.0f);
// auto m44_2 = pw::matrix2x2::make(0, 1, 2, 3);
// REQUIRE(m44_2(0, 0) == 0.0f);
// REQUIRE(m44_2(1, 0) == 1.0f);
// REQUIRE(m44_2(0, 1) == 2.0f);
// REQUIRE(m44_2(1, 1) == 3.0f);
pw::matrix2x2 m44_3 = {{},{1, 2, 3, 4}};
// pw::matrix2x2 m44_3 = {{},{1, 2, 3, 4}};
REQUIRE(m44_3(0, 0) == 1.0f);
REQUIRE(m44_3(1, 0) == 2.0f);
REQUIRE(m44_3(0, 1) == 3.0f);
REQUIRE(m44_3(1, 1) == 4.0f);
// REQUIRE(m44_3(0, 0) == 1.0f);
// REQUIRE(m44_3(1, 0) == 2.0f);
// REQUIRE(m44_3(0, 1) == 3.0f);
// REQUIRE(m44_3(1, 1) == 4.0f);
}
TEST_CASE("core", "[vector.matrix]") {
// auto vec4_1 = pw::vector4_<float>{};
// auto mat4_1 = pw::matrix_<4,1,float>{};
// mat4_1 = vec4_1; // down is easy
// vec4_1 = mat4_1;
}
TEST_CASE("core", "[vector]") {
auto vec4_1 = pw::vector4_<float>{};
auto vec4_2 = pw::vector4::make(1, 2, 3, 4);
// auto vec4_1 = pw::vector4_<float>{};
// auto vec4_2 = pw::vector4::make(1, 2, 3, 4);
auto vec4_3 = vec4_1 + vec4_2;
// pw::vector4 vec4_3 = vec4_1 + vec4_2;
REQUIRE(vec4_3[0] == 1.0f);
REQUIRE(vec4_3[1] == 2.0f);
REQUIRE(vec4_3[2] == 3.0f);
REQUIRE(vec4_3[3] == 4.0f);
// REQUIRE(vec4_3[0] == 1.0f);
// REQUIRE(vec4_3[1] == 2.0f);
// REQUIRE(vec4_3[2] == 3.0f);
// REQUIRE(vec4_3[3] == 4.0f);
// auto vec4_4 = vec4_3 * 2;
// REQUIRE(vec4_4[0] == 1.0f * 2);
// REQUIRE(vec4_4[1] == 2.0f * 2);
// REQUIRE(vec4_4[2] == 3.0f * 2);
// REQUIRE(vec4_4[3] == 4.0f * 2);
}