diff --git a/src/core/include/pw/core/color.hpp b/src/core/include/pw/core/color.hpp index 0b6cb0b..6af8e64 100644 --- a/src/core/include/pw/core/color.hpp +++ b/src/core/include/pw/core/color.hpp @@ -23,9 +23,9 @@ #ifndef PW_CORE_COLOR_HPP #define PW_CORE_COLOR_HPP +#include #include -#include namespace pw { @@ -46,7 +46,9 @@ struct color { (v & 0x0000ff00) >> 8, (v & 0x000000ff)); } - uint32_t to_rgb8888() const { return 0; } + uint32_t to_rgb8888() const { + return 0; + } }; } // namespace pw diff --git a/src/core/include/pw/core/globals.hpp b/src/core/include/pw/core/globals.hpp index e66d0f6..3844bb3 100644 --- a/src/core/include/pw/core/globals.hpp +++ b/src/core/include/pw/core/globals.hpp @@ -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, @@ -24,6 +24,8 @@ #define PW_CORE_GLOBALS_HPP #include +#include + #include #include #include @@ -34,11 +36,9 @@ using std::shared_ptr; using std::unique_ptr; using std::weak_ptr; -using std::make_unique; using std::make_shared; +using std::make_unique; -using real_t = float; - -} +} // namespace pw #endif diff --git a/src/core/include/pw/core/math.hpp b/src/core/include/pw/core/math.hpp index 0330f6b..1a06ec4 100644 --- a/src/core/include/pw/core/math.hpp +++ b/src/core/include/pw/core/math.hpp @@ -27,9 +27,6 @@ #include #include -//#include -//#include - namespace pw { constexpr double __PW_PI = 3.1415926535897932384626433832795028841971693993751058209; diff --git a/src/core/include/pw/core/matrix.hpp b/src/core/include/pw/core/matrix.hpp index ec302fa..5199228 100644 --- a/src/core/include/pw/core/matrix.hpp +++ b/src/core/include/pw/core/matrix.hpp @@ -97,6 +97,15 @@ struct matrix final { }(std::make_index_sequence{}); } + static constexpr auto from_diagonal(const diag_type& d) noexcept -> matrix { + static_assert( + Rows == Cols, + "creating from diagonal vector only defined for square matrices"); + return [&d](std::index_sequence) { + return matrix{vector::basis(Rs) * d[Rs]...}; + }(std::make_index_sequence{}); + } + constexpr auto minor(std::unsigned_integral auto r0, std::unsigned_integral auto c0) const noexcept { static_assert(Rows > 1 && Cols > 1, "cannot create minor matrix"); diff --git a/src/core/include/pw/core/matrix_transform.hpp b/src/core/include/pw/core/matrix_transform.hpp index ffac9d8..5616ddf 100644 --- a/src/core/include/pw/core/matrix_transform.hpp +++ b/src/core/include/pw/core/matrix_transform.hpp @@ -23,40 +23,88 @@ #ifndef PW_CORE_MATRIX_TRANSFORM_HPP #define PW_CORE_MATRIX_TRANSFORM_HPP +#include +#include #include namespace pw { -template struct matrix_transform { +template struct frustum final { + Scalar left{-1}, right{1}, bottom{-1}, top{1}, z_near{-1}, z_far{1}; - constexpr static matrix_<4, 4, T> - scale_matrix(const vector3_& 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; + static constexpr auto make_perspective_symmetric(Scalar fov_h_deg, + Scalar aspect_ratio, + Scalar z_near, + Scalar z_far) -> frustum { + const auto tangent_half{std::tan(pw::deg_to_rad(fov_h_deg / 2))}; + const auto top{tangent_half * z_near}; + const auto right{top * aspect_ratio}; + + return {.left = -right, + .right = right, + .bottom = -top, + .top = top, + .z_near = z_near, + .z_far = z_far}; } - 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 frustum::identity(); - - 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[3][2] = -T(1); - - return frustum; + static constexpr auto make_orthographic_symmetric(Scalar scale, + Scalar aspect_ratio, + Scalar z_near, + Scalar z_far) -> frustum { + return {.left = -scale, + .right = scale, + .bottom = -scale * aspect_ratio, + .top = scale * aspect_ratio, + .z_near = z_near, + .z_far = z_far}; } +}; + +struct matrix_transform { + + template + constexpr static auto + scale_matrix(vector&& diag) noexcept -> matrix { + return matrix::from_diagonal( + std::forward>(diag)); + } + + template + constexpr static auto + frustum_matrix(const frustum& f) -> matrix { + + const auto Sx{Scalar{2} * f.z_near / (f.right - f.left)}; + const auto Sy{Scalar{2} * f.z_near / (f.top - f.bottom)}; + + const auto A{(f.right + f.left) / (f.right - f.left)}; + const auto B{(f.top + f.bottom) / (f.top - f.bottom)}; + const auto C{-(f.z_far + f.z_near) / (f.z_far - f.z_near)}; + const auto D{-Scalar{2} * f.z_far * f.z_near / (f.z_far - f.z_near)}; + + // clang-format off + return {vector{Sx, 0, A, 0}, + vector{0, Sy, B, 0}, + vector{0, 0, C, D}, + vector{0, 0, -1, Scalar{1}}}; + // clang-format on + } + + template + constexpr static auto + look_at_matrix(vector3 position, vector3 target, + vector3 up) -> matrix { + + const auto lofs = (target - position).normalized(); // line of sight + const auto side = lofs.cross(up).normalized(); // side vector + const auto upvc = side.cross(lofs).normalized(); // upvector + + return {side.unproject(0), upvc.unproject(0), + lofs.unproject(0) * Scalar{-1}, position.unproject(1)}; + } +}; + +#if 0 // /// creates a projection from a frustum planes with a reversed depth // mapped to [0..1] pub fn make_projection_rh_from_frustum_reversed( @@ -156,7 +204,8 @@ template struct matrix_transform { return view_matrix; } -}; + +#endif } // namespace pw diff --git a/src/core/tests/CMakeLists.txt b/src/core/tests/CMakeLists.txt index f5b0b35..c4f33f0 100644 --- a/src/core/tests/CMakeLists.txt +++ b/src/core/tests/CMakeLists.txt @@ -8,6 +8,6 @@ make_test(pwcore_test_matrix) make_test(pwcore_test_axisangle) make_test(pwcore_test_quaternion) make_test(pwcore_test_color) +make_test(pwcore_test_transform_tools) -# make_test(pwcore_test_transform_tools) # make_test(pwcore_test_mesh) diff --git a/src/core/tests/pwcore_test_transform_tools.cpp b/src/core/tests/pwcore_test_transform_tools.cpp index 1a4c0b0..965b57b 100644 --- a/src/core/tests/pwcore_test_transform_tools.cpp +++ b/src/core/tests/pwcore_test_transform_tools.cpp @@ -1,18 +1,38 @@ -#include -#include +#include #include +#include +#include -#include +auto main() -> int { -int main(int argc,char **argv) { + pw::debug::d() << "pixwerx.matrix_transform.test\n"; - auto perspective_mat = pw::matrix_transform::perspective_projection(45.f,1.3f,10,100); - auto ortho_mat = pw::matrix_transform::orthographic_frustum(-1,1,1,-1,10,100); - auto lookat_mat = pw::matrix_transform::look_at(pw::vector3(0,0,5),pw::vector3(0,0,0),pw::vector3(0,1,0)); + auto scale_123 = + pw::matrix_transform::scale_matrix({1.f, 2.f, 3.f, 1.f}); + pw::debug::d() << "matrix_transform::scale(1,2,3) -> \n" + << pw::serialize::to_string(scale_123); + auto fm_default = + pw::matrix_transform::frustum_matrix(pw::frustum{}); + pw::debug::d() << "matrix_transform::frustum::default -> \n" + << pw::serialize::to_string(fm_default); - std::cout << pw::serialize::matrix(perspective_mat) << std::endl; - std::cout << pw::serialize::matrix(ortho_mat) << std::endl; - std::cout << pw::serialize::matrix(lookat_mat) << std::endl; + auto fm_45deg_1dot3 = pw::matrix_transform::frustum_matrix( + pw::frustum::make_perspective_symmetric(45.f, 1.3f, 0.1f, + 1000.f)); + pw::debug::d() << "matrix_transform::frustum::45deg -> \n" + << pw::serialize::to_string(fm_45deg_1dot3); + + auto fm_ortho = pw::matrix_transform::frustum_matrix( + pw::frustum::make_orthographic_symmetric(0.5f, 1.3f, 0.1f, + 1000.f)); + pw::debug::d() << "matrix_transform::frustum::ortho -> \n" + << pw::serialize::to_string(fm_ortho); + + auto lookat_mat = pw::matrix_transform::look_at_matrix( + pw::vector{0.f, 0, 5}, pw::vector{0.f, 0, 0}, pw::vector{0.f, 1, 0}); + + pw::debug::d() << "matrix_transform::look_at -> \n" + << pw::serialize::to_string(lookat_mat); }