WiP
This commit is contained in:
parent
cd19543627
commit
63135466a2
8 changed files with 430 additions and 470 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -3,3 +3,4 @@
|
|||
compile_commands.json
|
||||
*.autosave
|
||||
build
|
||||
.cache
|
||||
|
|
56
.vscode/settings.json
vendored
56
.vscode/settings.json
vendored
|
@ -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
|
||||
}
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue