diff --git a/headers/enduro2d/math/mat4.hpp b/headers/enduro2d/math/mat4.hpp index 338bd8e1..d3abcda6 100644 --- a/headers/enduro2d/math/mat4.hpp +++ b/headers/enduro2d/math/mat4.hpp @@ -589,6 +589,24 @@ namespace e2d::math #endif } + template < typename T > + std::enable_if_t, mat4> + make_orthographic_lh_matrix4(const vec2& lb, const vec2& rt, T znear, T zfar) noexcept { + return make_orthographic_lh_matrix4(lb.x, rt.x, lb.y, rt.y, znear, zfar); + } + + template < typename T > + std::enable_if_t, mat4> + make_orthographic_lh_matrix4(const vec2& size, T znear, T zfar) noexcept { + return make_orthographic_lh_matrix4(size * T(-0.5), size * T(0.5), znear, zfar); + } + + template < typename T > + std::enable_if_t, mat4> + make_orthographic_lh_matrix4(T width, T height, T znear, T zfar) noexcept { + return make_orthographic_lh_matrix4(vec2(width, height), znear, zfar); + } + // // make_orthographic_rh_matrix4 // @@ -652,6 +670,24 @@ namespace e2d::math #endif } + template < typename T > + std::enable_if_t, mat4> + make_orthographic_rh_matrix4(const vec2& lb, const vec2& rt, T znear, T zfar) noexcept { + return make_orthographic_rh_matrix4(lb.x, rt.x, lb.y, rt.y, znear, zfar); + } + + template < typename T > + std::enable_if_t, mat4> + make_orthographic_rh_matrix4(const vec2& size, T znear, T zfar) noexcept { + return make_orthographic_rh_matrix4(size * T(-0.5), size * T(0.5), znear, zfar); + } + + template < typename T > + std::enable_if_t, mat4> + make_orthographic_rh_matrix4(T width, T height, T znear, T zfar) noexcept { + return make_orthographic_rh_matrix4(vec2(width, height), znear, zfar); + } + // // make_perspective_lh_matrix4 // @@ -871,12 +907,11 @@ namespace e2d::math template < typename T > std::enable_if_t, std::pair, bool>> project_zo( - const vec3& v, - const mat4& model, + const vec3& world, const mat4& projection, const rect& viewport) noexcept { - const vec4 t4 = vec4(v, T(1)) * model * projection; + const vec4 t4 = vec4(world, T(1)) * projection; if ( math::is_near_zero(t4.w, T(0)) ) { return std::make_pair(vec3::zero(), false); @@ -896,12 +931,11 @@ namespace e2d::math template < typename T > std::enable_if_t, std::pair, bool>> project_no( - const vec3& v, - const mat4& model, + const vec3& world, const mat4& projection, const rect& viewport) noexcept { - const vec4 t4 = vec4(v, T(1)) * model * projection; + const vec4 t4 = vec4(world, T(1)) * projection; if ( math::is_near_zero(t4.w, T(0)) ) { return std::make_pair(vec3::zero(), false); @@ -923,14 +957,13 @@ namespace e2d::math template < typename T > std::enable_if_t, std::pair, bool>> project( - const vec3& v, - const mat4& model, + const vec3& world, const mat4& projection, const rect& viewport) noexcept { #if defined(E2D_CLIPPING_MODE) && E2D_CLIPPING_MODE == E2D_CLIPPING_MODE_ZO - return impl::project_zo(v, model, projection, viewport); + return impl::project_zo(world, projection, viewport); #elif defined(E2D_CLIPPING_MODE) && E2D_CLIPPING_MODE == E2D_CLIPPING_MODE_NO - return impl::project_no(v, model, projection, viewport); + return impl::project_no(world, projection, viewport); #else # error "E2D_CLIPPING_MODE not detected" #endif @@ -945,18 +978,15 @@ namespace e2d::math template < typename T > std::enable_if_t, std::pair, bool>> unproject_zo( - const vec3& v, - const mat4& model, - const mat4& projection, + const vec3& screen, + const mat4& inv_projection, const rect& viewport) noexcept { - const std::pair, bool> inv_matrix = math::inversed(model * projection); - - if ( !inv_matrix.second || math::is_near_zero(math::area(viewport), T(0)) ) { + if ( math::is_near_zero(math::area(viewport), T(0)) ) { return std::make_pair(vec3::zero(), false); } - vec4 t4 = vec4(v, T(1)); + vec4 t4 = vec4(screen, T(1)); t4.x = (t4.x - viewport.position.x) / viewport.size.x; t4.y = (t4.y - viewport.position.y) / viewport.size.y; @@ -964,7 +994,7 @@ namespace e2d::math t4.x = t4.x * T(2) - T(1); t4.y = t4.y * T(2) - T(1); - t4 = t4 * inv_matrix.first; + t4 = t4 * inv_projection; return math::is_near_zero(t4.w, T(0)) ? std::make_pair(vec3::zero(), false) @@ -974,18 +1004,15 @@ namespace e2d::math template < typename T > std::enable_if_t, std::pair, bool>> unproject_no( - const vec3& v, - const mat4& model, - const mat4& projection, + const vec3& screen, + const mat4& inv_projection, const rect& viewport) noexcept { - const std::pair, bool> inv_matrix = math::inversed(model * projection); - - if ( !inv_matrix.second || math::is_near_zero(math::area(viewport), T(0)) ) { + if ( math::is_near_zero(math::area(viewport), T(0)) ) { return std::make_pair(vec3::zero(), false); } - vec4 t4 = vec4(v, T(1)); + vec4 t4 = vec4(screen, T(1)); t4.x = (t4.x - viewport.position.x) / viewport.size.x; t4.y = (t4.y - viewport.position.y) / viewport.size.y; @@ -994,7 +1021,7 @@ namespace e2d::math t4.y = t4.y * T(2) - T(1); t4.z = t4.z * T(2) - T(1); - t4 = t4 * inv_matrix.first; + t4 = t4 * inv_projection; return math::is_near_zero(t4.w, T(0)) ? std::make_pair(vec3::zero(), false) @@ -1005,14 +1032,13 @@ namespace e2d::math template < typename T > std::enable_if_t, std::pair, bool>> unproject( - const vec3& v, - const mat4& model, - const mat4& projection, + const vec3& screen, + const mat4& inv_projection, const rect& viewport) noexcept { #if defined(E2D_CLIPPING_MODE) && E2D_CLIPPING_MODE == E2D_CLIPPING_MODE_ZO - return impl::unproject_zo(v, model, projection, viewport); + return impl::unproject_zo(screen, inv_projection, viewport); #elif defined(E2D_CLIPPING_MODE) && E2D_CLIPPING_MODE == E2D_CLIPPING_MODE_NO - return impl::unproject_no(v, model, projection, viewport); + return impl::unproject_no(screen, inv_projection, viewport); #else # error "E2D_CLIPPING_MODE not detected" #endif diff --git a/samples/bin/library/scripts/emmy/math/m4f.lua b/samples/bin/library/scripts/emmy/math/m4f.lua index 14327a86..593bccb1 100644 --- a/samples/bin/library/scripts/emmy/math/m4f.lua +++ b/samples/bin/library/scripts/emmy/math/m4f.lua @@ -50,21 +50,18 @@ function m4f.make_look_at_lh(eye, at, up) end ---@return m4f function m4f.make_look_at_rh(eye, at, up) end ----@param left number ----@param right number ----@param bottom number ----@param top number ----@param znear number ----@param zfar number ----@return m4f -function m4f.make_orthographic_lh(left, right, bottom, top, znear, zfar) end ----@param left number ----@param right number ----@param bottom number ----@param top number ----@param znear number ----@param zfar number +---@overload fun(left: number, right: number, bottom: number, top: number, znear: number, zfar: number): m4f +---@overload fun(lb: v2f, rt: v2f, znear: number, zfar: number): m4f +---@overload fun(size: v2f, znear: number, zfar: number): m4f +---@overload fun(width: number, height: number, znear: number, zfar: number): m4f +---@return m4f +function m4f.make_orthographic_lh() end + +---@overload fun(left: number, right: number, bottom: number, top: number, znear: number, zfar: number): m4f +---@overload fun(lb: v2f, rt: v2f, znear: number, zfar: number): m4f +---@overload fun(size: v2f, znear: number, zfar: number): m4f +---@overload fun(width: number, height: number, znear: number, zfar: number): m4f ---@return m4f function m4f.make_orthographic_rh(left, right, bottom, top, znear, zfar) end diff --git a/untests/sources/untests_math/mat4.cpp b/untests/sources/untests_math/mat4.cpp index 13fe8f86..47116c0d 100644 --- a/untests/sources/untests_math/mat4.cpp +++ b/untests/sources/untests_math/mat4.cpp @@ -36,10 +36,14 @@ TEST_CASE("mat4") { REQUIRE(math::make_rotation_matrix4(make_rad(1.f),v3f(1.f,1.f,1.f)) == math::make_rotation_matrix4(make_rad(1.f), v3f::unit())); REQUIRE(math::make_orthographic_lh_matrix4(640.f, 480.f, 0.f, 1.f) == math::make_orthographic_lh_matrix4(v2f(640,480), 0.f, 1.f)); + REQUIRE(math::make_orthographic_lh_matrix4(-320.f, 320.f, -240.f, 240.f, 0.f, 1.f) == math::make_orthographic_lh_matrix4(-v2f(320,240), v2f(320,240), 0.f, 1.f)); REQUIRE(math::make_orthographic_lh_matrix4(640.0, 480.0, 0.0, 1.0) == math::make_orthographic_lh_matrix4(v2d(640,480), 0.0, 1.0)); + REQUIRE(math::make_orthographic_lh_matrix4(-320.0, 320.0, -240.0, 240.0, 0.0, 1.0) == math::make_orthographic_lh_matrix4(-v2d(320,240), v2d(320,240), 0.0, 1.0)); - REQUIRE(math::make_orthographic_lh_matrix4(640.f, 480.f, 0.f, 1.f) == math::make_orthographic_lh_matrix4(v2f(640,480), 0.f, 1.f)); - REQUIRE(math::make_orthographic_lh_matrix4(640.0, 480.0, 0.0, 1.0) == math::make_orthographic_lh_matrix4(v2d(640,480), 0.0, 1.0)); + REQUIRE(math::make_orthographic_rh_matrix4(640.f, 480.f, 0.f, 1.f) == math::make_orthographic_rh_matrix4(v2f(640,480), 0.f, 1.f)); + REQUIRE(math::make_orthographic_rh_matrix4(-320.f, 320.f, -240.f, 240.f, 0.f, 1.f) == math::make_orthographic_rh_matrix4(-v2f(320,240), v2f(320,240), 0.f, 1.f)); + REQUIRE(math::make_orthographic_rh_matrix4(640.0, 480.0, 0.0, 1.0) == math::make_orthographic_rh_matrix4(v2d(640,480), 0.0, 1.0)); + REQUIRE(math::make_orthographic_rh_matrix4(-320.0, 320.0, -240.0, 240.0, 0.0, 1.0) == math::make_orthographic_rh_matrix4(-v2d(320,240), v2d(320,240), 0.0, 1.0)); } { REQUIRE(m4f(m4f::identity()) == m4f::identity()); @@ -168,62 +172,57 @@ TEST_CASE("mat4") { } { m4f projection = math::make_perspective_lh_matrix4(make_deg(80.f), 4.f / 3.f, 0.01f, 1.f); + const m4f inv_projection = math::inversed(projection).first; b2f viewport = make_rect(800.f, 600.f); const v3f p1 = v3f(0.f,0.f,0.01f); const v3f p2 = v3f(+1.f,0.f,0.01f); const v3f p3 = v3f(-1.f,0.f,0.01f); - REQUIRE(math::project(p1, m4f::identity(), projection, viewport).second); - REQUIRE(math::project(p2, m4f::identity(), projection, viewport).second); - REQUIRE(math::project(p3, m4f::identity(), projection, viewport).second); + REQUIRE(math::project(p1, projection, viewport).second); + REQUIRE(math::project(p2, projection, viewport).second); + REQUIRE(math::project(p3, projection, viewport).second); - REQUIRE(math::impl::project_zo(p1, m4f::identity(), projection, viewport).second); - REQUIRE(math::impl::project_zo(p2, m4f::identity(), projection, viewport).second); - REQUIRE(math::impl::project_zo(p3, m4f::identity(), projection, viewport).second); + REQUIRE(math::impl::project_zo(p1, projection, viewport).second); + REQUIRE(math::impl::project_zo(p2, projection, viewport).second); + REQUIRE(math::impl::project_zo(p3, projection, viewport).second); - REQUIRE(math::impl::project_no(p1, m4f::identity(), projection, viewport).second); - REQUIRE(math::impl::project_no(p2, m4f::identity(), projection, viewport).second); - REQUIRE(math::impl::project_no(p3, m4f::identity(), projection, viewport).second); + REQUIRE(math::impl::project_no(p1, projection, viewport).second); + REQUIRE(math::impl::project_no(p2, projection, viewport).second); + REQUIRE(math::impl::project_no(p3, projection, viewport).second); REQUIRE(math::unproject( - math::project(p1, m4f::identity(), projection, viewport).first, - m4f::identity(), - projection, + math::project(p1, projection, viewport).first, + inv_projection, viewport).second); REQUIRE(math::unproject( - math::project(p2, m4f::identity(), projection, viewport).first, - m4f::identity(), - projection, + math::project(p2, projection, viewport).first, + inv_projection, viewport).second); REQUIRE(math::unproject( - math::project(p3, m4f::identity(), projection, viewport).first, - m4f::identity(), - projection, + math::project(p3, projection, viewport).first, + inv_projection, viewport).second); REQUIRE(math::unproject( - math::project(p1, m4f::identity(), projection, viewport).first, - m4f::identity(), - projection, + math::project(p1, projection, viewport).first, + inv_projection, viewport).first == v3f(p1)); REQUIRE(math::unproject( - math::project(p2, m4f::identity(), projection, viewport).first, - m4f::identity(), - projection, + math::project(p2, projection, viewport).first, + inv_projection, viewport).first == v3f(p2)); REQUIRE(math::unproject( - math::project(p3, m4f::identity(), projection, viewport).first, - m4f::identity(), - projection, + math::project(p3, projection, viewport).first, + inv_projection, viewport).first == v3f(p3)); } { - m4f projection = math::make_orthographic_lh_matrix4({400.f, 300.f}, 0.f, 1.f); + m4f projection = math::make_orthographic_lh_matrix4(-200.f, 200.f, -300.f, 300.f, 0.f, 1.f); m4f model = math::make_scale_matrix4(2.f, 2.f); b2f viewport = make_rect(800.f, 600.f); @@ -231,93 +230,90 @@ TEST_CASE("mat4") { const v3f p2 = v3f(+1.f,0.f,0.f); const v3f p3 = v3f(-1.f,0.f,0.f); - REQUIRE(math::project(p1, model, projection, viewport).second); - REQUIRE(math::project(p2, model, projection, viewport).second); - REQUIRE(math::project(p3, model, projection, viewport).second); + REQUIRE(math::project(p1, model * projection, viewport).second); + REQUIRE(math::project(p2, model * projection, viewport).second); + REQUIRE(math::project(p3, model * projection, viewport).second); - m4f projection_zo = math::impl::make_orthographic_lh_zo_matrix4(400.f, 300.f, 0.f, 1.f); - REQUIRE(math::impl::project_zo(p1, model, projection_zo, viewport).second); - REQUIRE(math::impl::project_zo(p2, model, projection_zo, viewport).second); - REQUIRE(math::impl::project_zo(p3, model, projection_zo, viewport).second); + m4f projection_zo = math::impl::make_orthographic_lh_zo_matrix4(-200.f, 200.f, -150.f, 150.f, 0.f, 1.f); + REQUIRE(math::impl::project_zo(p1, model * projection_zo, viewport).second); + REQUIRE(math::impl::project_zo(p2, model * projection_zo, viewport).second); + REQUIRE(math::impl::project_zo(p3, model * projection_zo, viewport).second); - m4f projection_no = math::impl::make_orthographic_lh_no_matrix4(400.f, 300.f, 0.f, 1.f); - REQUIRE(math::impl::project_no(p1, model, projection_no, viewport).second); - REQUIRE(math::impl::project_no(p2, model, projection_no, viewport).second); - REQUIRE(math::impl::project_no(p3, model, projection_no, viewport).second); + m4f projection_no = math::impl::make_orthographic_lh_no_matrix4(-200.f, 200.f, -150.f, 150.f, 0.f, 1.f); + REQUIRE(math::impl::project_no(p1, model * projection_no, viewport).second); + REQUIRE(math::impl::project_no(p2, model * projection_no, viewport).second); + REQUIRE(math::impl::project_no(p3, model * projection_no, viewport).second); REQUIRE(math::approximately( - math::project(p1, model, projection, viewport).first, + math::project(p1, model * projection, viewport).first, v3f(400.f, 300.f, 0.f), 0.01f)); REQUIRE(math::approximately( - math::project(p2, model, projection, viewport).first, + math::project(p2, model * projection, viewport).first, v3f(404.f, 300.f, 0.f), 0.01f)); REQUIRE(math::approximately( - math::project(p3, model, projection, viewport).first, + math::project(p3, model * projection, viewport).first, v3f(396.f, 300.f, 0.f), 0.01f)); REQUIRE(math::approximately( - math::impl::project_zo(p1, model, projection_zo, viewport).first, + math::impl::project_zo(p1, model * projection_zo, viewport).first, v3f(400.f, 300.f, 0.f), 0.01f)); REQUIRE(math::approximately( - math::impl::project_zo(p2, model, projection_zo, viewport).first, + math::impl::project_zo(p2, model * projection_zo, viewport).first, v3f(404.f, 300.f, 0.f), 0.01f)); REQUIRE(math::approximately( - math::impl::project_zo(p3, model, projection_zo, viewport).first, + math::impl::project_zo(p3, model * projection_zo, viewport).first, v3f(396.f, 300.f, 0.f), 0.01f)); REQUIRE(math::approximately( - math::impl::project_no(p1, model, projection_no, viewport).first, + math::impl::project_no(p1, model * projection_no, viewport).first, v3f(400.f, 300.f, 0.f), 0.01f)); REQUIRE(math::approximately( - math::impl::project_no(p2, model, projection_no, viewport).first, + math::impl::project_no(p2, model * projection_no, viewport).first, v3f(404.f, 300.f, 0.f), 0.01f)); REQUIRE(math::approximately( - math::impl::project_no(p3, model, projection_no, viewport).first, + math::impl::project_no(p3, model * projection_no, viewport).first, v3f(396.f, 300.f, 0.f), 0.01f)); + const m4f inv_project = math::inversed(model * projection).first; + REQUIRE(math::inversed(model * projection).second); + REQUIRE(math::unproject( - math::project(p1, model, projection, viewport).first, - model, - projection, + math::project(p1, inv_project, viewport).first, + model * projection, viewport).second); REQUIRE(math::unproject( - math::project(p2, model, projection, viewport).first, - model, - projection, + math::project(p2, inv_project, viewport).first, + model * projection, viewport).second); REQUIRE(math::unproject( - math::project(p3, model, projection, viewport).first, - model, - projection, + math::project(p3, inv_project, viewport).first, + model * projection, viewport).second); REQUIRE(math::unproject( - math::project(p1, model, projection, viewport).first, - model, - projection, + math::project(p1, inv_project, viewport).first, + model * projection, viewport).first == v3f(p1)); REQUIRE(math::unproject( - math::project(p2, model, projection, viewport).first, - model, - projection, + math::project(p2, inv_project, viewport).first, + model * projection, viewport).first == v3f(p2)); REQUIRE(math::unproject( - math::project(p3, model, projection, viewport).first, - model, - projection, + math::project(p3, inv_project, viewport).first, + model * projection, viewport).first == v3f(p3)); } }