microwerx icon

Matrix Class

microwerx | PRO | 04/16/18 02:08:59 PM UTC | 0 ⭐ | 866 👁️ | Never ⏰ | []
C++ |

49.57 KB

|

None

|

0 👍

/

0 👎

// SSPHH/Fluxions/Unicornfish/Viperfish/Hatchetfish/Sunfish/KASL/GLUT Extensions
// Copyright (C) 2017 Jonathan Metzgar
// All rights reserved.
//
// This program is free software : you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.If not, see <https://www.gnu.org/licenses/>.
//
// For any other type of licensing, please contact me at [email protected]
#ifndef FLUXIONS_MATRIX4_HPP
#define FLUXIONS_MATRIX4_HPP
 
 
#include <type_traits>
#include <fluxions_gte_math.hpp>
#include <fluxions_gte_vector3.hpp>
#include <fluxions_gte_vector4.hpp>
 
 
namespace Fluxions
{
    using namespace std;
 
    template <typename T>
    class TMatrix4
    {
    public:
        union
        {
            // normal access (column major)
            struct
            {
                T m11, m21, m31, m41;
                T m12, m22, m32, m42;
                T m13, m23, m33, m43;
                T m14, m24, m34, m44;
            };
            
            // transposed access
            struct
            {
                T t11, t12, t13, t14;
                T t21, t22, t23, t24;
                T t31, t32, t33, t34;
                T t41, t42, t43, t44;
            };
            
            // 2D array form
            T mm[4][4];
 
            // array form
            T m[16];
            T v[16];
        };
 
        static constexpr size_t size() { return 16; }
        static constexpr size_t numrows() { return 4; }
        static constexpr size_t numcols() { return 4; }
        
        TMatrix4() noexcept
        { 
            m11 = 1; m12 = 0; m13 = 0; m14 = 0;
            m21 = 0; m22 = 1; m23 = 0; m24 = 0;
            m31 = 0; m32 = 0; m33 = 1; m34 = 0;
            m41 = 0; m42 = 0; m43 = 0; m44 = 1;
        }
 
        constexpr TMatrix4(const TMatrix4<T> & M) noexcept
        {
            m11 = M.m11; m12 = M.m12; m13 = M.m13; m14 = M.m14;
            m21 = M.m21; m22 = M.m22; m23 = M.m23; m24 = M.m24;
            m31 = M.m31; m32 = M.m32; m33 = M.m33; m34 = M.m34;
            m41 = M.m41; m42 = M.m42; m43 = M.m43; m44 = M.m44;
        }
 
        TMatrix4(TMatrix4<T> && M) noexcept
        {
            m11 = std::move(M.m11); m12 = std::move(M.m12); m13 = std::move(M.m13); m14 = std::move(M.m14);
            m21 = std::move(M.m21); m22 = std::move(M.m22); m23 = std::move(M.m23); m24 = std::move(M.m24);
            m31 = std::move(M.m31); m32 = std::move(M.m32); m33 = std::move(M.m33); m34 = std::move(M.m34);
            m41 = std::move(M.m41); m42 = std::move(M.m42); m43 = std::move(M.m43); m44 = std::move(M.m44);
        }
 
        TMatrix4(const T value) noexcept
        { 
            m11 = value; m12 = value; m13 = value; m14 = value;
            m21 = value; m22 = value; m23 = value; m24 = value;
            m31 = value; m32 = value; m33 = value; m34 = value;
            m41 = value; m42 = value; m43 = value; m44 = value;         
        }
 
        TMatrix4(
            const T a11, const T a12, const T a13, const T a14,
            const T a21, const T a22, const T a23, const T a24,
            const T a31, const T a32, const T a33, const T a34,
            const T a41, const T a42, const T a43, const T a44) noexcept
        {
            m11 = a11; m12 = a12; m13 = a13; m14 = a14;
            m21 = a21; m22 = a22; m23 = a23; m24 = a24;
            m31 = a31; m32 = a32; m33 = a33; m34 = a34;
            m41 = a41; m42 = a42; m43 = a43; m44 = a44;
        }
 
        TMatrix4(const T M[numrows()][numcols()]) noexcept
        {
            const T *_v = M[0];
            for (auto i = 0; i < size(); i++)
            {
                v[i] = _v[i];
            }
        }
 
        TMatrix4(const T M[size()]) noexcept
        {
            const T *_v = M;
            for (auto i = 0; i < size(); i++)
            {
                v[i] = _v[i];
            }
        }
 
        constexpr auto operator = (const TMatrix4<T> & M) noexcept
        {
            m11 = M.m11; m12 = M.m12; m13 = M.m13; m14 = M.m14;
            m21 = M.m21; m22 = M.m22; m23 = M.m23; m24 = M.m24;
            m31 = M.m31; m32 = M.m32; m33 = M.m33; m34 = M.m34;
            m41 = M.m41; m42 = M.m42; m43 = M.m43; m44 = M.m44;
            return *this;
        }
 
        template <typename U> constexpr auto operator = (const TMatrix4<U> & M) noexcept
        {
            m11 = static_cast<T>(M.m11); m12 = static_cast<T>(M.m12); m13 = static_cast<T>(M.m13); m14 = static_cast<T>(M.m14);
            m21 = static_cast<T>(M.m21); m22 = static_cast<T>(M.m22); m23 = static_cast<T>(M.m23); m24 = static_cast<T>(M.m24);
            m31 = static_cast<T>(M.m31); m32 = static_cast<T>(M.m32); m33 = static_cast<T>(M.m33); m34 = static_cast<T>(M.m34);
            m41 = static_cast<T>(M.m41); m42 = static_cast<T>(M.m42); m43 = static_cast<T>(M.m43); m44 = static_cast<T>(M.m44);
            return *this;
        }
 
        //template <typename U> constexpr TMatrix4<T> & operator = (const enable_if_t<is_arithmetic_v<U>, U> value) noexcept
        template <typename U> constexpr TMatrix4<T> & operator = (const U value) noexcept
        {
            m11 = static_cast<T>(value); m12 = static_cast<T>(value); m13 = static_cast<T>(value); m14 = static_cast<T>(value);
            m21 = static_cast<T>(value); m22 = static_cast<T>(value); m23 = static_cast<T>(value); m24 = static_cast<T>(value);
            m31 = static_cast<T>(value); m32 = static_cast<T>(value); m33 = static_cast<T>(value); m34 = static_cast<T>(value);
            m41 = static_cast<T>(value); m42 = static_cast<T>(value); m43 = static_cast<T>(value); m44 = static_cast<T>(value);
            return *this;
        }
 
        template <typename U> constexpr operator TMatrix4<U>() const noexcept {
            return TMatrix4<U>(
                static_cast<U>(m11), static_cast<U>(m12), static_cast<U>(m13), static_cast<U>(m14),
                static_cast<U>(m21), static_cast<U>(m22), static_cast<U>(m23), static_cast<U>(m24),
                static_cast<U>(m31), static_cast<U>(m32), static_cast<U>(m33), static_cast<U>(m34),
                static_cast<U>(m41), static_cast<U>(m42), static_cast<U>(m43), static_cast<U>(m44)
                );
        }
 
        constexpr TVector4<T> row1() const noexcept { return TVector4<T>(m11, m12, m13, m14); }
        constexpr TVector4<T> row2() const noexcept { return TVector4<T>(m21, m22, m23, m24); }
        constexpr TVector4<T> row3() const noexcept { return TVector4<T>(m31, m32, m33, m34); }
        constexpr TVector4<T> row4() const noexcept { return TVector4<T>(m41, m42, m43, m44); }
        constexpr TVector4<T> col1() const noexcept { return TVector4<T>(m11, m21, m31, m41); }
        constexpr TVector4<T> col2() const noexcept { return TVector4<T>(m12, m22, m32, m42); }
        constexpr TVector4<T> col3() const noexcept { return TVector4<T>(m13, m23, m33, m43); }
        constexpr TVector4<T> col4() const noexcept { return TVector4<T>(m14, m24, m34, m44); }
 
        // col(i) returns the ith column of the matrix (i = 1 is column 1)
        constexpr TVector4<T> col(int i) const noexcept {
            switch (i) {
            case 1: return col1();
            case 2: return col2();
            case 3: return col3();
            case 4: return col4();
            }
            return TVector4<T>();
        }
 
        // row(i) returns the ith row of the matrix (i = 1 is row 1)
        constexpr TVector4<T> row(int i) const noexcept {
            switch (i) {
            case 1: return row1();
            case 2: return row2();
            case 3: return row3();
            case 4: return row4();
            }
            return TVector4<T>();
        }
 
        template <typename U> static constexpr auto compAdd(const TMatrix4<T> & m1, const TMatrix4<U> & m2) noexcept
        {
            return TMatrix4<common_type_t<T, U>>(
                m1.m11 + m2.m11, m1.m12 + m2.m12, m1.m13 + m2.m13, m1.m14 + m2.m14,
                m1.m21 + m2.m21, m1.m22 + m2.m22, m1.m23 + m2.m23, m1.m24 + m2.m24,
                m1.m31 + m2.m31, m1.m32 + m2.m32, m1.m33 + m2.m33, m1.m34 + m2.m34,
                m1.m41 + m2.m41, m1.m42 + m2.m42, m1.m43 + m2.m43, m1.m44 + m2.m44
                );
        }
 
        template <typename U> static constexpr auto compSub(const TMatrix4<T> & m1, const TMatrix4<U> & m2) noexcept
        {
            return TMatrix4<common_type_t<T, U>>(
                m1.m11 - m2.m11, m1.m12 - m2.m12, m1.m13 - m2.m13, m1.m14 - m2.m14,
                m1.m21 - m2.m21, m1.m22 - m2.m22, m1.m23 - m2.m23, m1.m24 - m2.m24,
                m1.m31 - m2.m31, m1.m32 - m2.m32, m1.m33 - m2.m33, m1.m34 - m2.m34,
                m1.m41 - m2.m41, m1.m42 - m2.m42, m1.m43 - m2.m43, m1.m44 - m2.m44
                );
        }
 
        template <typename U> static constexpr auto compMult(const TMatrix4<T> & m1, const TMatrix4<U> & m2) noexcept
        {
            return TMatrix4<common_type_t<T, U>>(
                m1.m11 * m2.m11, m1.m12 * m2.m12, m1.m13 * m2.m13, m1.m14 * m2.m14,
                m1.m21 * m2.m21, m1.m22 * m2.m22, m1.m23 * m2.m23, m1.m24 * m2.m24,
                m1.m31 * m2.m31, m1.m32 * m2.m32, m1.m33 * m2.m33, m1.m34 * m2.m34,
                m1.m41 * m2.m41, m1.m42 * m2.m42, m1.m43 * m2.m43, m1.m44 * m2.m44
                );
        }
 
        template <typename U> static constexpr auto compDiv(const TMatrix4<T> & m1, const TMatrix4<U> & m2) noexcept
        {
            return TMatrix4<common_type_t<T, U>>(
                m1.m11 / m2.m11, m1.m12 / m2.m12, m1.m13 / m2.m13, m1.m14 / m2.m14,
                m1.m21 / m2.m21, m1.m22 / m2.m22, m1.m23 / m2.m23, m1.m24 / m2.m24,
                m1.m31 / m2.m31, m1.m32 / m2.m32, m1.m33 / m2.m33, m1.m34 / m2.m34,
                m1.m41 / m2.m41, m1.m42 / m2.m42, m1.m43 / m2.m43, m1.m44 / m2.m44
                );
        }
 
        template <typename U> static constexpr auto multiply(const TMatrix4<T> & m1, const TMatrix4<U> & m2) noexcept
        {
            return TMatrix4<common_type_t<T, U>>(
                (m1.m14*m2.m41 + m1.m13*m2.m31 + m1.m12*m2.m21 + m1.m11*m2.m11),
                (m1.m14*m2.m42 + m1.m13*m2.m32 + m1.m12*m2.m22 + m1.m11*m2.m12),
                (m1.m14*m2.m43 + m1.m13*m2.m33 + m1.m12*m2.m23 + m1.m11*m2.m13),
                (m1.m14*m2.m44 + m1.m13*m2.m34 + m1.m12*m2.m24 + m1.m11*m2.m14),
 
                (m1.m24*m2.m41 + m1.m23*m2.m31 + m1.m22*m2.m21 + m1.m21*m2.m11),
                (m1.m24*m2.m42 + m1.m23*m2.m32 + m1.m22*m2.m22 + m1.m21*m2.m12),
                (m1.m24*m2.m43 + m1.m23*m2.m33 + m1.m22*m2.m23 + m1.m21*m2.m13),
                (m1.m24*m2.m44 + m1.m23*m2.m34 + m1.m22*m2.m24 + m1.m21*m2.m14),
 
                (m1.m34*m2.m41 + m1.m33*m2.m31 + m1.m32*m2.m21 + m1.m31*m2.m11),
                (m1.m34*m2.m42 + m1.m33*m2.m32 + m1.m32*m2.m22 + m1.m31*m2.m12),
                (m1.m34*m2.m43 + m1.m33*m2.m33 + m1.m32*m2.m23 + m1.m31*m2.m13),
                (m1.m34*m2.m44 + m1.m33*m2.m34 + m1.m32*m2.m24 + m1.m31*m2.m14),
 
                (m1.m44*m2.m41 + m1.m43*m2.m31 + m1.m42*m2.m21 + m1.m41*m2.m11),
                (m1.m44*m2.m42 + m1.m43*m2.m32 + m1.m42*m2.m22 + m1.m41*m2.m12),
                (m1.m44*m2.m43 + m1.m43*m2.m33 + m1.m42*m2.m23 + m1.m41*m2.m13),
                (m1.m44*m2.m44 + m1.m43*m2.m34 + m1.m42*m2.m24 + m1.m41*m2.m14));
        }
 
        constexpr auto LoadIdentity() noexcept
        {
            return *this = MakeIdentity();
        }
 
        constexpr auto operator - () noexcept
        {
            return TMatrix4<T>(
                -m11, -m12, -m13, -m14,
                -m21, -m22, -m23, -m24,
                -m31, -m32, -m33, -m34,
                -m41, -m42, -m43, -m44
                );
        }
 
        template <typename U> constexpr auto operator()(std::function<U(T x)> Func) noexcept
        {
            return TMatrix4<common_type_t<T, U>>(
                Func(m11), Func(m12), Func(m13), Func(m14),
                Func(m21), Func(m22), Func(m23), Func(m24),
                Func(m31), Func(m32), Func(m33), Func(m34),
                Func(m41), Func(m42), Func(m43), Func(m44)
                );
        }
 
        template <typename U> constexpr auto MultMatrix(const TMatrix4<U> & M) noexcept
        {
            return *this = multiply(*this, M);
        }
 
        template <typename U> constexpr auto operator *= (const TMatrix4<U> & M) noexcept
        {
            return *this = multiply(*this, M);
        }
 
        template <typename U> constexpr auto operator += (const TMatrix4<U> & M) noexcept
        {
            m11 += M.m11; m12 += M.m12; m13 += M.m13; m14 += M.m14;
            m21 += M.m21; m22 += M.m22; m23 += M.m23; m24 += M.m24;
            m31 += M.m31; m32 += M.m32; m33 += M.m33; m34 += M.m34;
            m41 += M.m41; m42 += M.m42; m43 += M.m43; m44 += M.m44;
            return *this;
        }
 
        template <typename U> constexpr auto operator -= (const TMatrix4<U> & M) noexcept
        {
            m11 -= M.m11; m12 -= M.m12; m13 -= M.m13; m14 -= M.m14;
            m21 -= M.m21; m22 -= M.m22; m23 -= M.m23; m24 -= M.m24;
            m31 -= M.m31; m32 -= M.m32; m33 -= M.m33; m34 -= M.m34;
            m41 -= M.m41; m42 -= M.m42; m43 -= M.m43; m44 -= M.m44;
            return *this;
        }
 
        //template <typename U> const TMatrix4<T> operator * (const TMatrix4<U> & M) const;
        //template <typename U> const TMatrix4<T> operator + (const TMatrix4<U> & M) const;
        //template <typename U> const TMatrix4<T> operator - (const TMatrix4<U> & M) const;
        
        template <typename U> constexpr auto operator += (const U c) noexcept
        {
            m11 += c; m12 += c; m13 += c; m14 += c;
            m21 += c; m22 += c; m23 += c; m24 += c;
            m31 += c; m32 += c; m33 += c; m34 += c;
            m41 += c; m42 += c; m43 += c; m44 += c;
            return *this;
        }
 
        template <typename U> constexpr auto operator -= (const U c) noexcept
        {
            m11 -= c; m12 -= c; m13 -= c; m14 -= c;
            m21 -= c; m22 -= c; m23 -= c; m24 -= c;
            m31 -= c; m32 -= c; m33 -= c; m34 -= c;
            m41 -= c; m42 -= c; m43 -= c; m44 -= c;
            return *this;
        }
 
        template <typename U> constexpr auto operator *= (const U c) noexcept
        {
            m11 *= c; m12 *= c; m13 *= c; m14 *= c;
            m21 *= c; m22 *= c; m23 *= c; m24 *= c;
            m31 *= c; m32 *= c; m33 *= c; m34 *= c;
            m41 *= c; m42 *= c; m43 *= c; m44 *= c;
            return *this;
        }
 
        template <typename U> constexpr auto operator /= (const U c) noexcept
        {
            m11 /= c; m12 /= c; m13 /= c; m14 /= c;
            m21 /= c; m22 /= c; m23 /= c; m24 /= c;
            m31 /= c; m32 /= c; m33 /= c; m34 /= c;
            m41 /= c; m42 /= c; m43 /= c; m44 /= c;
            return *this;
        }
 
        template <typename U> constexpr auto Rotate(U angleInDegrees, U x, U y, U z) noexcept
        {
            return *this *= MakeRotation((T)angleInDegrees, (T)x, (T)y, (T)z);
        }
 
        template <typename U> constexpr auto Scale(U x, U y, U z) noexcept
        {
            return *this *= MakeScaling((T)x, (T)y, (T)z);
        }
 
        template <typename U> constexpr auto Translate(U x, U y, U z) noexcept
        {
            return *this *= MakeTranslation((T)x, (T)y, (T)z);
        }
 
        template <typename U> constexpr auto Ortho(U left, U right, U bottom, U top, U near_value, U far_value) noexcept
        {
            return *this *= MakeOrtho((T)left, (T)right, (T)bottom, (T)top, (T)near_value, (T)far_value);
        }
 
        template <typename U> constexpr auto Ortho2D(U left, U right, U bottom, U top) noexcept
        {
            return *this *= MakeOrtho2D((T)left, (T)right, (T)bottom, (T)top);
        }
 
        template <typename U> constexpr auto Frustum(U left, U right, U bottom, U top, U near_value, U far_value) noexcept
        {
            return *this *= MakeFrustum((T)left, (T)right, (T)bottom, (T)top, (T)near_value, (T)far_value);
        }
 
        template <typename U> constexpr auto Perspective(U angleInDegrees, U aspect, U near_value, U far_value) noexcept
        {
            return *this *= MakePerspective((T)angleInDegrees, (T)aspect, (T)near_value, (T)far_value);
        }
 
        template <typename U> constexpr auto PerspectiveX(U angleInDegrees, U aspect, U near_value, U far_value) noexcept
        {
            return *this *= MakePerspectiveX((T)angleInDegrees, (T)aspect, (T)near_value, (T)far_value);
        }
        
        template <typename U> constexpr auto PerspectiveY(U angleInDegrees, U aspect, U near_value, U far_value) noexcept
        {
            return *this *= MakePerspectiveY((T)angleInDegrees, (T)aspect, (T)near_value, (T)far_value);
        }
 
        template <typename U> constexpr auto LookAt(TVector3<U> eye, TVector3<U> center, TVector3<U> up) noexcept
        {
            return *this *= MakeLookAt((TVector3<T>)eye, (TVector3<T>)center, (TVector3<T>)up);
        }
 
        constexpr auto ShadowBias() noexcept
        {
            return *this *= MakeShadowBias();
        }
        
        constexpr auto CubeMatrix(int face) noexcept
        {
            return *this *= MakeCubeMatrix(face);
        }
 
        constexpr auto CubeMatrixPosition(int face, const TVector3<T> & position) noexcept
        {
            return *this *= MakeCubeMatrixPosition(face, position);
        }
 
        constexpr auto AsTranspose() const noexcept
        {
            return TMatrix4<T>(
                t11, t12, t13, t14,
                t21, t22, t23, t24,
                t31, t32, t33, t34,
                t41, t42, t43, t44
            );
        }
 
        constexpr auto Transpose() noexcept
        {
            return *this = AsTranspose();
        }
 
        constexpr auto AsAdjugate() const noexcept
        {
            T t1 = m32 * m43 - m33 * m42;
            T t2 = m32 * m44 - m34 * m42;
            T t3 = m33 * m44 - m34 * m43;
            T t4 = m22 * m43 - m23 * m42;
            T t5 = m22 * m44 - m24 * m42;
            T t6 = m23 * m44 - m24 * m43;
            T t7 = m22 * m33 - m23 * m32;
            T t8 = m22 * m34 - m24 * m32;
            T t9 = m23 * m34 - m24 * m33;
            T t10 = m31 * m43 - m33 * m41;
            T t11 = m31 * m44 - m34 * m41;
            T t12 = m21 * m43 - m23 * m41;
            T t13 = m21 * m44 - m24 * m41;
            T t14 = m21 * m33 - m23 * m31;
            T t15 = m21 * m34 - m24 * m31;
            T t16 = m31 * m42 - m32 * m41;
            T t17 = m21 * m42 - m22 * m41;
            T t18 = m21 * m32 - m22 * m31;
 
            return TMatrix4<T>(m22 * t3 - m23 * t2 + m24 * t1,
                -m12 * t3 + m13 * t2 - m14 * t1,
                m12 * t6 - m13 * t5 + m14 * t4,
                -m12 * t9 + m13 * t8 - m14 * t7,
                -m21 * t3 + m23 * t11 - m24 * t10,
                m11 * t3 - m13 * t11 + m14 * t10,
                -m11 * t6 + m13 * t13 - m14 * t12,
                m11 * t9 - m13 * t15 + m14 * t14,
                m21 * t2 - m22 * t11 + m24 * t16,
                -m11 * t2 + m12 * t11 - m14 * t16,
                m11 * t5 - m12 * t13 + m14 * t17,
                -m11 * t8 + m12 * t15 - m14 * t18,
                -m21 * t1 + m22 * t10 - m23 * t16,
                m11 * t1 - m12 * t10 + m13 * t16,
                -m11 * t4 + m12 * t12 - m13 * t17,
                m11 * t7 - m12 * t14 + m13 * t18);
        }
        
        constexpr auto Adjugate() noexcept
        {
            return *this = AsAdjugate();
        }
 
        constexpr auto AsQuickInverse() const noexcept
        {
            return TMatrix4<T>(
                t11, t12, t13, -m14,
                t21, t22, t23, -m24,
                t31, t32, t33, -m34,
                T(0), T(0), T(0), T(1)
                );
        }
 
        constexpr auto QuickInvert() noexcept
        {
            if (Invertible())
                return *this = AsQuickInverse();
            return *this = MakeZero();
        }
 
        constexpr auto AsInverse() const noexcept
        {
            T t1 = m32 * m43 - m33 * m42;
            T t2 = m32 * m44 - m34 * m42;
            T t3 = m33 * m44 - m34 * m43;
            T t4 = m22 * t3 - m23 * t2 + m24 * t1;
            T t5 = m31 * m42 - m32 * m41;
            T t6 = m31 * m43 - m33 * m41;
            T t7 = -m21 * t1 + m22 * t6 - m23 * t5;
            T t8 = m31 * m44 - m34 * m41;
            T t9 = m21 * t2 - m22 * t8 + m24 * t5;
            T t10 = -m21 * t3 + m23 * t8 - m24 * t6;
            T t11 = static_cast<T>(1.0 / (m11 * t4 + m12 * t10 + m13 * t9 + m14 * t7));
            T t12 = m22 * m43 - m23 * m42;
            T t13 = m22 * m44 - m24 * m42;
            T t14 = m23 * m44 - m24 * m43;
            T t15 = m22 * m33 - m23 * m32;
            T t16 = m22 * m34 - m24 * m32;
            T t17 = m23 * m34 - m24 * m33;
            T t18 = m21 * m43 - m23 * m41;
            T t19 = m21 * m44 - m24 * m41;
            T t20 = m21 * m33 - m23 * m31;
            T t21 = m21 * m34 - m24 * m31;
            T t22 = m21 * m42 - m22 * m41;
            T t23 = m21 * m32 - m22 * m31;
 
            return TMatrix4<T>(
                t4 * t11,
                (-m12 * t3 + m13 * t2 - m14 * t1) * t11,
                (m12 * t14 - m13 * t13 + m14 * t12) * t11,
                (-m12 * t17 + m13 * t16 - m14 * t15) * t11,
                t10 * t11,
                (m11 * t3 - m13 * t8 + m14 * t6) * t11,
                (-m11 * t14 + m13 * t19 - m14 * t18) * t11,
                (m11 * t17 - m13 * t21 + m14 * t20) * t11,
                t9 * t11,
                (-m11 * t2 + m12 * t8 - m14 * t5) * t11,
                (m11 * t13 - m12 * t19 + m14 * t22) * t11,
                (-m11 * t16 + m12 * t21 - m14 * t23) * t11,
                t7 * t11,
                (m11 * t1 - m12 * t6 + m13 * t5) * t11,
                (-m11 * t12 + m12 * t18 - m13 * t22) * t11,
                (m11 * t15 - m12 * t20 + m13 * t23) * t11
                );
        }
 
        constexpr auto Invert() noexcept
        {
            if (Invertible())
                return *this = AsInverse();
            return *this = MakeZero();
        }
 
        constexpr bool Invertible() const noexcept
        {
            return Determinant() != 0;
        }
 
        constexpr T Determinant() const noexcept
        {
            T t1 = m31 * m42 - m32 * m41;
            T t2 = m31 * m43 - m33 * m41;
            T t3 = m32 * m43 - m33 * m42;
            T t4 = m31 * m44 - m34 * m41;
            T t5 = m32 * m44 - m34 * m42;
            T t6 = m33 * m44 - m34 * m43;
            return
                m11 * (m22 * t6 - m23 * t5 + m24 * t3) -
                m12 * (m21 * t6 - m23 * t4 + m24 * t2) +
                m13 * (m21 * t5 - m22 * t4 + m24 * t1) -
                m14 * (m21 * t3 - m22 * t2 + m23 * t1);
        }
 
 
        ///////////////////////////////////////////////////////////////
        // S T A T I C   M E M B E R S ////////////////////////////////
        ///////////////////////////////////////////////////////////////
 
        static constexpr auto MakeIdentity() noexcept
        {
            return TMatrix4<T>(
                1, 0, 0, 0,
                0, 1, 0, 0,
                0, 0, 1, 0,
                0, 0, 0, 1
                );
        }
 
        static constexpr auto MakeZero() noexcept
        {
            return TMatrix4<T>(
                0, 0, 0, 0,
                0, 0, 0, 0,
                0, 0, 0, 0,
                0, 0, 0, 0
                );
        }
 
        static constexpr auto MakeRotation(T angleInDegrees, T x, T y, T z) noexcept
        {
            T angleInRadians = static_cast<T>(angleInDegrees * FX_DEGREES_TO_RADIANS);
            T c = cos(angleInRadians);
            T s = sin(angleInRadians);
            T invLength = (T)(1.0 / sqrt(x*x + y*y + z*z));
            x *= invLength;
            y *= invLength;
            z *= invLength;
 
            return TMatrix4<T>(
                x * x * (1 - c) + c, x * y * (1 - c) - z * s, x * z * (1 - c) + y * s, 0.0,
                y * x * (1 - c) + z * s, y * y * (1 - c) + c, y * z * (1 - c) - x * s, 0.0,
                x * z * (1 - c) - y * s, y * z * (1 - c) + x * s, z * z * (1 - c) + c, 0.0,
                0.0, 0.0, 0.0, 1.0
                );
        }
 
        static constexpr auto MakeScaling(T x, T y, T z) noexcept
        {
            return TMatrix4<T>(
                x, 0, 0, 0,
                0, y, 0, 0,
                0, 0, z, 0,
                0, 0, 0, 1
                );
        }
 
        static constexpr auto MakeTranslation(T x, T y, T z) noexcept
        {
            return TMatrix4<T>(
                1, 0, 0, x,
                0, 1, 0, y,
                0, 0, 1, z,
                0, 0, 0, 1
                );
        }
 
        static constexpr auto MakeOrtho(T left, T right, T bottom, T top, T near_value, T far_value) noexcept
        {
            T tx = -(right + left) / (right - left);
            T ty = -(top + bottom) / (top - bottom);
            T tz = -(far_value + near_value) / (far_value - near_value);
 
            return TMatrix4<double>(
                2 / (right - left), 0, 0, tx,
                0, 2 / (top - bottom), 0, ty,
                0, 0, -2 / (far_value - near_value), tz,
                0, 0, 0, 1
                );
        }
 
        static constexpr auto MakeOrtho2D(T left, T right, T bottom, T top) noexcept
        {
            T tx = -(right + left) / (right - left);
            T ty = -(top + bottom) / (top - bottom);
 
            return TMatrix4<T>(
                2 / (right - left), 0, 0, tx,
                0, 2 / (top - bottom), 0, ty,
                0, 0, -1, 0,
                0, 0, 0, 1
                );
        }
 
        static constexpr auto MakeFrustum(T left, T right, T bottom, T top, T near_value, T far_value) noexcept
        {
            T A = (right + left) / (right - left);
            T B = (top + bottom) / (top - bottom);
            T C = -(far_value + near_value) / (far_value - near_value);
            T D = -2 * far_value * near_value / (far_value - near_value);
 
            return TMatrix4<T>(
                2 * near_value / (right - left), 0, A, 0,
                0, 2 * near_value / (top - bottom), B, 0,
                0, 0, C, D,
                0, 0, -1, 0
                );
        }
 
        static constexpr auto MakePerspective(T angleInDegrees, T aspect, T near_value, T far_value) noexcept
        {
            T f = static_cast<T>(1.0 / std::tan(FX_DEGREES_TO_RADIANS * 0.5 * angleInDegrees));
 
            return TMatrix4<T>(
                f / aspect, 0, 0, 0,
                0, f, 0, 0,
                0, 0, (far_value + near_value) / (near_value - far_value), 2 * far_value * near_value / (near_value - far_value),
                0, 0, -1, 0
                );
        }
 
        static constexpr auto MakePerspectiveX(T angleInDegrees, T aspect, T near_value, T far_value) noexcept
        {
            T f = static_cast<T>(1.0 / std::tan(FX_DEGREES_TO_RADIANS * 0.5 * angleInDegrees));
 
            return TMatrix4<T>(
                f / aspect, 0, 0, 0,
                0, f, 0, 0,
                0, 0, (far_value + near_value) / (near_value - far_value), 2 * far_value * near_value / (near_value - far_value),
                0, 0, -1, 0
                );
        }
 
        static constexpr auto MakePerspectiveY(T angleInDegrees, T aspect, T near_value, T far_value) noexcept
        {
            T f = static_cast<T>(1.0 / std::tan(FX_DEGREES_TO_RADIANS * 0.5 * angleInDegrees));
 
            return TMatrix4<T>(
                f, 0, 0, 0,
                0, f * aspect, 0, 0,
                0, 0, (far_value + near_value) / (near_value - far_value), 2 * far_value * near_value / (near_value - far_value),
                0, 0, -1, 0
                );
        }
 
        static constexpr auto MakeLookAt(TVector3<T> eye, TVector3<T> center, TVector3<T> up) noexcept
        {
            TVector3<T> F = (center - eye).norm();
            TVector3<T> S = F.cross(up).norm();
            TVector3<T> U = S.cross(F).norm();
 
            return TMatrix4<T>::multiply(TMatrix4<T>(
                S.x, S.y, S.z, 0.0,
                U.x, U.y, U.z, 0.0,
                -F.x, -F.y, -F.z, 0.0,
                0.0, 0.0, 0.0, 1.0),
                TMatrix4<T>::MakeTranslation(-eye.x, -eye.y, -eye.z));
        }
 
        static constexpr auto MakeShadowBias() noexcept
        {
            return TMatrix4<T>(
                0.5, 0.0, 0.0, 0.5,
                0.0, 0.5, 0.0, 0.5,
                0.0, 0.0, 0.5, 0.5,
                0.0, 0.0, 0.0, 1.0
                );
        }
 
        static constexpr auto MakeCubeMatrix(int face) noexcept
        {
            // support GL_TEXTURE_CUBE_MAP_POSITIVE_X, ... constants
            if (face >= 0x8515 && face <= 0x851A) face -= 0x8515;
 
            switch (face)
            {
            case 0: // GL_TEXTURE_CUBE_MAP_POSITIVE_X
                return TMatrix4<T>::MakeRotation(90.0, 0.0, 1.0, 0.0);
                break;
            case 1: // GL_TEXTURE_CUBE_MAP_NEGATIVE_X
                return TMatrix4<T>::MakeRotation(270.0, 0.0, 1.0, 0.0);
                break;
            case 2: // GL_TEXTURE_CUBE_MAP_POSITIVE_Y
                return TMatrix4<T>::MakeRotation(270.0, 1.0, 0.0, 0.0);
                break;
            case 3: // GL_TEXTURE_CUBE_MAP_NEGATIVE_Y
                return TMatrix4<T>::MakeRotation(90.0, 1.0, 0.0, 0.0);
                break;
            case 4: // GL_TEXTURE_CUBE_MAP_POSITIVE_Z
                return TMatrix4<T>::MakeIdentity();
                break;
            case 5: // GL_TEXTURE_CUBE_MAP_NEGATIVE_Z
                return TMatrix4<T>::MakeRotation(180.0, 0.0, 1.0, 0.0);
                break;
            }
            return TMatrix4<T>::MakeIdentity();
        }
 
        static constexpr TMatrix4<T> MakeCubeMatrixPosition(int face, const TVector3<T> & position) noexcept
        {
            // support GL_TEXTURE_CUBE_MAP_POSITIVE_X, ... constants
            if (face >= 0x8515 && face <= 0x851A) face -= 0x8515;
 
            switch (face)
            {
            case 0: // GL_TEXTURE_CUBE_MAP_POSITIVE_X
                return TMatrix4<T>::MakeLookAt(position, position + TVector3<T>(1, 0, 0), TVector3<T>(0, -1, 0));
                break;
            case 1: // GL_TEXTURE_CUBE_MAP_NEGATIVE_X
                return TMatrix4<T>::MakeLookAt(position, position + TVector3<T>(-1, 0, 0), TVector3<T>(0, -1, 0));
                break;
            case 2: // GL_TEXTURE_CUBE_MAP_POSITIVE_Y
                return TMatrix4<T>::MakeLookAt(position, position + TVector3<T>(0, 1, 0), TVector3<T>(0, 0, 1));
                break;
            case 3: // GL_TEXTURE_CUBE_MAP_NEGATIVE_Y
                return TMatrix4<T>::MakeLookAt(position, position + TVector3<T>(0, -1, 0), TVector3<T>(0, 0, -1));
                break;
            case 4: // GL_TEXTURE_CUBE_MAP_POSITIVE_Z
                return TMatrix4<T>::MakeLookAt(position, position + TVector3<T>(0, 0, 1), TVector3<T>(0, -1, 0));
                break;
            case 5: // GL_TEXTURE_CUBE_MAP_NEGATIVE_Z
                return TMatrix4<T>::MakeLookAt(position, position + TVector3<T>(0, 0, -1), TVector3<T>(0, -1, 0));
                break;
            }
            return TMatrix4<T>::MakeIdentity();
        }
 
    };
    
    //////////////////////////////////////////////////////////////////
    // I M P L E M E N T A T I O N ///////////////////////////////////
    //////////////////////////////////////////////////////////////////
    //template <typename T>
    //TMatrix4<T>::TMatrix4()
    //{
    //  m11 = 1; m12 = 0; m13 = 0; m14 = 0;
    //  m21 = 0; m22 = 1; m23 = 0; m24 = 0;
    //  m31 = 0; m32 = 0; m33 = 1; m34 = 0;
    //  m41 = 0; m42 = 0; m43 = 0; m44 = 1;
    //}
    //
    //template <typename T>
    //TMatrix4<T>::TMatrix4(
    //  const T a11, const T a12, const T a13, const T a14,
    //  const T a21, const T a22, const T a23, const T a24,
    //  const T a31, const T a32, const T a33, const T a34,
    //  const T a41, const T a42, const T a43, const T a44
    //  )
    //{
    //  m11 = a11; m12 = a12; m13 = a13; m14 = a14;
    //  m21 = a21; m22 = a22; m23 = a23; m24 = a24;
    //  m31 = a31; m32 = a32; m33 = a33; m34 = a34;
    //  m41 = a41; m42 = a42; m43 = a43; m44 = a44;
    //}
 
    //template <typename T>
    //TMatrix4<T>::TMatrix4(const TMatrix4<T> & M)
    //{
    //  m11 = M.m11; m12 = M.m12; m13 = M.m13; m14 = M.m14;
    //  m21 = M.m21; m22 = M.m22; m23 = M.m23; m24 = M.m24;
    //  m31 = M.m31; m32 = M.m32; m33 = M.m33; m34 = M.m34;
    //  m41 = M.m41; m42 = M.m42; m43 = M.m43; m44 = M.m44;
    //}
    //
    //template <typename T>
    //TMatrix4<T>::TMatrix4(const T M[4][4])
    //{
    //  for (int i = 0; i < 4; i++)
    //  {
    //      for (int j = 0; j < 4; j++)
    //      {
    //          mm[i][j] = M[j][i];
    //      }
    //  }
    //}
    //
    //template <typename T>
    //TMatrix4<T>::TMatrix4(const T M[16])
    //{
    //  for (int i = 0; i < 16; i++)
    //  {
    //      m[i] = M[i];
    //  }
    //}
    //
    //template <typename T>
    //template <typename U>
    //const TMatrix4<T> & TMatrix4<T>::operator = (const TMatrix4<U> & M)
    //{
    //  m11 = T(M.m11); m12 = T(M.m12); m13 = T(M.m13); m14 = T(M.m14);
    //  m21 = T(M.m21); m22 = T(M.m22); m23 = T(M.m23); m24 = T(M.m24);
    //  m31 = T(M.m31); m32 = T(M.m32); m33 = T(M.m33); m34 = T(M.m34);
    //  m41 = T(M.m41); m42 = T(M.m42); m43 = T(M.m43); m44 = T(M.m44);
    //  return *this;
    //}
 
    //
    //template <typename T>
    //const TMatrix4<T> & TMatrix4<T>::LoadIdentity()
    //{
    //  m11 = 1; m12 = 0; m13 = 0; m14 = 0;
    //  m21 = 0; m22 = 1; m23 = 0; m24 = 0;
    //  m31 = 0; m32 = 0; m33 = 1; m34 = 0;
    //  m41 = 0; m42 = 0; m43 = 0; m44 = 1;
 
    //  return *this;
    //}
 
    //template <typename T>
    //template <typename U>
    //const TMatrix4<T> TMatrix4<T>::multiply(const TMatrix4<U> &M) const
    //{
    //  return TMatrix4<T>(
    //      (T)(m14*M.m41 + m13*M.m31 + m12*M.m21 + m11*M.m11),
    //      (T)(m14*M.m42 + m13*M.m32 + m12*M.m22 + m11*M.m12),
    //      (T)(m14*M.m43 + m13*M.m33 + m12*M.m23 + m11*M.m13),
    //      (T)(m14*M.m44 + m13*M.m34 + m12*M.m24 + m11*M.m14),
 
    //      (T)(m24*M.m41 + m23*M.m31 + m22*M.m21 + m21*M.m11),
    //      (T)(m24*M.m42 + m23*M.m32 + m22*M.m22 + m21*M.m12),
    //      (T)(m24*M.m43 + m23*M.m33 + m22*M.m23 + m21*M.m13),
    //      (T)(m24*M.m44 + m23*M.m34 + m22*M.m24 + m21*M.m14),
 
    //      (T)(m34*M.m41 + m33*M.m31 + m32*M.m21 + m31*M.m11),
    //      (T)(m34*M.m42 + m33*M.m32 + m32*M.m22 + m31*M.m12),
    //      (T)(m34*M.m43 + m33*M.m33 + m32*M.m23 + m31*M.m13),
    //      (T)(m34*M.m44 + m33*M.m34 + m32*M.m24 + m31*M.m14),
 
    //      (T)(m44*M.m41 + m43*M.m31 + m42*M.m21 + m41*M.m11),
    //      (T)(m44*M.m42 + m43*M.m32 + m42*M.m22 + m41*M.m12),
    //      (T)(m44*M.m43 + m43*M.m33 + m42*M.m23 + m41*M.m13),
    //      (T)(m44*M.m44 + m43*M.m34 + m42*M.m24 + m41*M.m14));
    //}
 
    //template <typename T>
    //template <typename U>
    //const TMatrix4<T> TMatrix4<T>::compMult(const TMatrix4<U> &m) const
    //{
    //  return TMatrix4<T>(
    //      m11 * m.m11, m12 * m.m12, m13 * m.m13, m14 * m.m14,
    //      m21 * m.m21, m22 * m.m22, m23 * m.m23, m24 * m.m24,
    //      m31 * m.m31, m32 * m.m32, m33 * m.m33, m34 * m.m34,
    //      m41 * m.m41, m42 * m.m42, m43 * m.m43, m44 * m.m44
    //      );
    //}
 
    //template<typename T>
    //template<typename U>
    //inline TMatrix4<T> TMatrix4<T>::multiply(TMatrix4<T> m1, TMatrix4<U> m2)
    //{
    //  return TMatrix4<T>(
    //      (T)(m1.m14*m2.m41 + m1.m13*m2.m31 + m1.m12*m2.m21 + m1.m11*m2.m11),
    //      (T)(m1.m14*m2.m42 + m1.m13*m2.m32 + m1.m12*m2.m22 + m1.m11*m2.m12),
    //      (T)(m1.m14*m2.m43 + m1.m13*m2.m33 + m1.m12*m2.m23 + m1.m11*m2.m13),
    //      (T)(m1.m14*m2.m44 + m1.m13*m2.m34 + m1.m12*m2.m24 + m1.m11*m2.m14),
 
    //      (T)(m1.m24*m2.m41 + m1.m23*m2.m31 + m1.m22*m2.m21 + m1.m21*m2.m11),
    //      (T)(m1.m24*m2.m42 + m1.m23*m2.m32 + m1.m22*m2.m22 + m1.m21*m2.m12),
    //      (T)(m1.m24*m2.m43 + m1.m23*m2.m33 + m1.m22*m2.m23 + m1.m21*m2.m13),
    //      (T)(m1.m24*m2.m44 + m1.m23*m2.m34 + m1.m22*m2.m24 + m1.m21*m2.m14),
 
    //      (T)(m1.m34*m2.m41 + m1.m33*m2.m31 + m1.m32*m2.m21 + m1.m31*m2.m11),
    //      (T)(m1.m34*m2.m42 + m1.m33*m2.m32 + m1.m32*m2.m22 + m1.m31*m2.m12),
    //      (T)(m1.m34*m2.m43 + m1.m33*m2.m33 + m1.m32*m2.m23 + m1.m31*m2.m13),
    //      (T)(m1.m34*m2.m44 + m1.m33*m2.m34 + m1.m32*m2.m24 + m1.m31*m2.m14),
 
    //      (T)(m1.m44*m2.m41 + m1.m43*m2.m31 + m1.m42*m2.m21 + m1.m41*m2.m11),
    //      (T)(m1.m44*m2.m42 + m1.m43*m2.m32 + m1.m42*m2.m22 + m1.m41*m2.m12),
    //      (T)(m1.m44*m2.m43 + m1.m43*m2.m33 + m1.m42*m2.m23 + m1.m41*m2.m13),
    //      (T)(m1.m44*m2.m44 + m1.m43*m2.m34 + m1.m42*m2.m24 + m1.m41*m2.m14));
    //}
    //
    //template <typename T>
    //template <typename U>
    //const TMatrix4<T> & TMatrix4<T>::MultMatrix(const TMatrix4<U> & M)
    //{
    //  return *this = multiply(M);
    //}
    //
    //template <typename T>
    //template <typename U>
    //const TMatrix4<T> & TMatrix4<T>::operator *= (const TMatrix4<U> & M)
    //{
    //  return *this = multiply(M);
    //}
    //
    //template <typename T>
    //template <typename U>
    //const TMatrix4<T> & TMatrix4<T>::operator += (const TMatrix4<U> & M)
    //{
    //  m11 += M.m11; m12 += M.m12; m13 += M.m13; m14 += M.m14;
    //  m21 += M.m21; m22 += M.m22; m23 += M.m23; m24 += M.m24;
    //  m31 += M.m31; m32 += M.m32; m33 += M.m33; m34 += M.m34;
    //  m41 += M.m41; m42 += M.m42; m43 += M.m43; m44 += M.m44;
    //  return *this;
    //}
    //
    //template <typename T>
    //template <typename U>
    //const TMatrix4<T> & TMatrix4<T>::operator -= (const TMatrix4<U> & M)
    //{
    //  m11 -= M.m11; m12 -= M.m12; m13 -= M.m13; m14 -= M.m14;
    //  m21 -= M.m21; m22 -= M.m22; m23 -= M.m23; m24 -= M.m24;
    //  m31 -= M.m31; m32 -= M.m32; m33 -= M.m33; m34 -= M.m34;
    //  m41 -= M.m41; m42 -= M.m42; m43 -= M.m43; m44 -= M.m44;
    //  return *this;
    //}
 
    //template <typename T>
    //template <typename U> 
    //const TMatrix4<T> TMatrix4<T>::operator * (const TMatrix4<U> & M) const
    //{
    //  return multiply(M);
    //}
    //
    //template <typename T>
    //template <typename U> 
    //const TMatrix4<T> TMatrix4<T>::operator + (const TMatrix4<U> & M) const
    //{
    //  return TMatrix4<T>(
    //      m11 + M.m11, m12 + M.m12, m13 + M.m13, m14 + M.m14,
    //      m21 + M.m21, m22 + M.m22, m23 + M.m23, m24 + M.m24,
    //      m31 + M.m31, m32 + M.m32, m33 + M.m33, m34 + M.m34,
    //      m41 + M.m41, m42 + M.m42, m43 + M.m43, m44 + M.m44
    //  );
    //}
    //
    //template <typename T>
    //template <typename U> 
    //const TMatrix4<T> TMatrix4<T>::operator - (const TMatrix4<U> & M) const
    //{
    //  return TMatrix4<T>(
    //      m11 - M.m11, m12 - M.m12, m13 - M.m13, m14 - M.m14,
    //      m21 - M.m21, m22 - M.m22, m23 - M.m23, m24 - M.m24,
    //      m31 - M.m31, m32 - M.m32, m33 - M.m33, m34 - M.m34,
    //      m41 - M.m41, m42 - M.m42, m43 - M.m43, m44 - M.m44
    //      );
    //}
    //
    //template <typename T>
    //template <typename U>
    //const TMatrix4<T> & TMatrix4<T>::operator *= (const U X)
    //{
    //  for (int i = 0; i < 16; i++)
    //      m[i] *= X;
    //  return *this;
    //}
    //
    //template <typename T>
    //template <typename U> 
    //const TMatrix4<T> & TMatrix4<T>::operator /= (const U X)
    //{
    //  for (int i = 0; i < 16; i++)
    //      m[i] /= X;
    //  return *this;
    //}
 
 
    //template <typename T>
    //const TMatrix4<T> & TMatrix4<T>::Rotate(double angleInDegrees, double X, double y, double z)
    //{
    //  return MultMatrix(TMatrix4<double>::MakeRotation(angleInDegrees, X, y, z));
    //}
 
 
    //template <typename T>
    //const TMatrix4<T> & TMatrix4<T>::Scale(double X, double y, double z)
    //{
    //  return MultMatrix(TMatrix4<double>::MakeScaling(X, y, z));
    //}
    //
 
    //template <typename T>
    //const TMatrix4<T> & TMatrix4<T>::Translate(double X, double y, double z)
    //{
    //  return MultMatrix(TMatrix4<double>::MakeTranslation(X, y, z));
    //}
    //
 
    //template <typename T>
    //const TMatrix4<T> & TMatrix4<T>::Ortho(double left, double right, double bottom, double top, double near_value, double far_value)
    //{
    //  return MultMatrix(TMatrix4<double>::MakeOrtho(left, right, bottom, top, near_value, far_value));
    //}
    //
 
    //template <typename T>
    //const TMatrix4<T> &  TMatrix4<T>::Ortho2D(double left, double right, double bottom, double top)
    //{
    //  return MultMatrix(TMatrix4<double>::MakeOrtho2D(left, right, bottom, top));
    //}
    //
 
    //template <typename T>
    //const TMatrix4<T> & TMatrix4<T>::Frustum(double left, double right, double bottom, double top, double near_value, double far_value)
    //{
    //  return MultMatrix(TMatrix4<double>::MakeFrustum(left, right, bottom, top, near_value, far_value));
    //}
    //
 
    //template <typename T>
    //const TMatrix4<T> & TMatrix4<T>::Perspective(double angleInDegrees, double aspect, double near_value, double far_value)
    //{
    //  return MultMatrix(TMatrix4<double>::MakePerspective(angleInDegrees, aspect, near_value, far_value));
    //}
 
 
    //template <typename T>
    //const TMatrix4<T> & TMatrix4<T>::PerspectiveX(double angleInDegrees, double aspect, double near_value, double far_value)
    //{
    //  return MultMatrix(TMatrix4<double>::MakePerspectiveX(angleInDegrees, aspect, near_value, far_value));
    //}
 
    //template <typename T>
    //const TMatrix4<T> & TMatrix4<T>::PerspectiveY(double angleInDegrees, double aspect, double near_value, double far_value)
    //{
    //  return MultMatrix(TMatrix4<double>::MakePerspectiveY(angleInDegrees, aspect, near_value, far_value));
    //}
 
    //template <typename T>
    //const TMatrix4<T> &TMatrix4<T>::LookAt(TVector3<double> eye, TVector3<double> center, TVector3<double> up)
    //{
    //  return MultMatrix(TMatrix4<double>::MakeLookAt(eye, center, up));
    //}
 
    //template <typename T>
    //const TMatrix4<T> & TMatrix4<T>::ShadowBias()
    //{
    //  return MultMatrix(TMatrix4<double>::MakeShadowBias());
    //}
 
 
    //template <typename T>
    //const TMatrix4<T> &TMatrix4<T>::CubeMatrix(int face)
    //{
    //  return MultMatrix(TMatrix4<double>::MakeCubeMatrix(face));
    //}
 
 
    //template <typename T>
    //inline TMatrix4<T> & TMatrix4<T>::Transpose()
    //{
    //  return *this = AsTranspose();
    //}
 
    //template <typename T>
    //TMatrix4<T> TMatrix4<T>::AsTranspose() const
    //{
    //  return TMatrix4<T>(
    //      t11, t12, t13, t14,
    //      t21, t22, t23, t24,
    //      t31, t32, t33, t34,
    //      t41, t42, t43, t44
    //  );
    //}
 
    //template <typename T>
    //T TMatrix4<T>::Determinant() const
    //{
    //  T t1 = m31 * m42 - m32 * m41;
    //  T t2 = m31 * m43 - m33 * m41;
    //  T t3 = m32 * m43 - m33 * m42;
    //  T t4 = m31 * m44 - m34 * m41;
    //  T t5 = m32 * m44 - m34 * m42;
    //  T t6 = m33 * m44 - m34 * m43;
    //  return 
    //      m11 * (m22 * t6 - m23 * t5 + m24 * t3) - 
    //      m12 * (m21 * t6 - m23 * t4 + m24 * t2) +
    //      m13 * (m21 * t5 - m22 * t4 + m24 * t1) -
    //      m14 * (m21 * t3 - m22 * t2 + m23 * t1);
    //}
 
    //template <typename T>
    //TMatrix4<T> TMatrix4<T>::AsAdjugate() const
    //{
    //  T t1 = m32 * m43 - m33 * m42;
    //  T t2 = m32 * m44 - m34 * m42;
    //  T t3 = m33 * m44 - m34 * m43;
    //  T t4 = m22 * m43 - m23 * m42;
    //  T t5 = m22 * m44 - m24 * m42;
    //  T t6 = m23 * m44 - m24 * m43;
    //  T t7 = m22 * m33 - m23 * m32;
    //  T t8 = m22 * m34 - m24 * m32;
    //  T t9 = m23 * m34 - m24 * m33;
    //  T t10 = m31 * m43 - m33 * m41;
    //  T t11 = m31 * m44 - m34 * m41;
    //  T t12 = m21 * m43 - m23 * m41;
    //  T t13 = m21 * m44 - m24 * m41;
    //  T t14 = m21 * m33 - m23 * m31;
    //  T t15 = m21 * m34 - m24 * m31;
    //  T t16 = m31 * m42 - m32 * m41;
    //  T t17 = m21 * m42 - m22 * m41;
    //  T t18 = m21 * m32 - m22 * m31;
 
    //  return TMatrix4<T>(m22 * t3 - m23 * t2 + m24 * t1,
    //      -m12 * t3 + m13 * t2 - m14 * t1,
    //      m12 * t6 - m13 * t5 + m14 * t4,
    //      -m12 * t9 + m13 * t8 - m14 * t7,
    //      -m21 * t3 + m23 * t11 - m24 * t10,
    //      m11 * t3 - m13 * t11 + m14 * t10,
    //      -m11 * t6 + m13 * t13 - m14 * t12,
    //      m11 * t9 - m13 * t15 + m14 * t14,
    //      m21 * t2 - m22 * t11 + m24 * t16,
    //      -m11 * t2 + m12 * t11 - m14 * t16,
    //      m11 * t5 - m12 * t13 + m14 * t17,
    //      -m11 * t8 + m12 * t15 - m14 * t18,
    //      -m21 * t1 + m22 * t10 - m23 * t16,
    //      m11 * t1 - m12 * t10 + m13 * t16,
    //      -m11 * t4 + m12 * t12 - m13 * t17,
    //      m11 * t7 - m12 * t14 + m13 * t18);
    //}
    //
    //template <typename T>
    //TMatrix4<T> & TMatrix4<T>::Adjugate()
    //{
    //  return *this = AsAdjugate();
    //}
    //
    //template <typename T>
    //bool TMatrix4<T>::Invert()
    //{
    //  T det;
    //  
    //  det = Determinant();
    //  if (det == 0)
    //      return false;
 
    //  *this = AsInverse();
 
    //  return true;
    //}
 
    ////template <typename T>
    ////TMatrix4<T> TMatrix4<T>::QuickInverse() const
    ////{
    ////    return TMatrix4<T>(
    ////        t11, t12, t13, -m14,
    ////        t21, t22, t23, -m24,
    ////        t31, t32, t33, -m34,
    ////        T(0), T(0), T(0), T(1)
    ////        );
    ////}
 
 
    ////template <typename T>
    ////void TMatrix4<T>::QuickInvert()
    ////{
    ////    *this = QuickInverse();
    ////}
 
 
    //template <typename T>
    //TMatrix4<double> TMatrix4<T>::AsInverse() const
    //{
    //  double t1 = m32 * m43 - m33 * m42;
    //  double t2 = m32 * m44 - m34 * m42;
    //  double t3 = m33 * m44 - m34 * m43;
    //  double t4 = m22 * t3 - m23 * t2 + m24 * t1;
    //  double t5 = m31 * m42 - m32 * m41;
    //  double t6 = m31 * m43 - m33 * m41;
    //  double t7 = -m21 * t1 + m22 * t6 - m23 * t5;
    //  double t8 = m31 * m44 - m34 * m41;
    //  double t9 = m21 * t2 - m22 * t8 + m24 * t5;
    //  double t10 = -m21 * t3 + m23 * t8 - m24 * t6;
    //  double t11 = 1.0 / (m11 * t4 + m12 * t10 + m13 * t9 + m14 * t7);
    //  double t12 = m22 * m43 - m23 * m42;
    //  double t13 = m22 * m44 - m24 * m42;
    //  double t14 = m23 * m44 - m24 * m43;
    //  double t15 = m22 * m33 - m23 * m32;
    //  double t16 = m22 * m34 - m24 * m32;
    //  double t17 = m23 * m34 - m24 * m33;
    //  double t18 = m21 * m43 - m23 * m41;
    //  double t19 = m21 * m44 - m24 * m41;
    //  double t20 = m21 * m33 - m23 * m31;
    //  double t21 = m21 * m34 - m24 * m31;
    //  double t22 = m21 * m42 - m22 * m41;
    //  double t23 = m21 * m32 - m22 * m31;
 
    //  return TMatrix4<double>(
    //      t4 * t11,
    //      (-m12 * t3 + m13 * t2 - m14 * t1) * t11,
    //      (m12 * t14 - m13 * t13 + m14 * t12) * t11,
    //      (-m12 * t17 + m13 * t16 - m14 * t15) * t11,
    //      t10 * t11,
    //      (m11 * t3 - m13 * t8 + m14 * t6) * t11,
    //      (-m11 * t14 + m13 * t19 - m14 * t18) * t11,
    //      (m11 * t17 - m13 * t21 + m14 * t20) * t11,
    //      t9 * t11,
    //      (-m11 * t2 + m12 * t8 - m14 * t5) * t11,
    //      (m11 * t13 - m12 * t19 + m14 * t22) * t11,
    //      (-m11 * t16 + m12 * t21 - m14 * t23) * t11,
    //      t7 * t11,
    //      (m11 * t1 - m12 * t6 + m13 * t5) * t11,
    //      (-m11 * t12 + m12 * t18 - m13 * t22) * t11,
    //      (m11 * t15 - m12 * t20 + m13 * t23) * t11
    //      );
    //}
 
 
    //template <typename T>
    //TMatrix4<double> TMatrix4<T>::makeRotation(double angleInDegrees, double X, double y, double z)
    //{
    //  double angleInRadians = angleInDegrees * FX_DEGREES_TO_RADIANS;
    //  double c = cos(angleInRadians);
    //  double s = sin(angleInRadians);
    //  double invLength = 1.0 / sqrt(X*X + y*y + z*z);
    //  X *= invLength;
    //  y *= invLength;
    //  z *= invLength;
 
    //  return TMatrix4<double>(
    //      X * X * (1 - c) + c, X * y * (1 - c) - z * s, X * z * (1 - c) + y * s, 0.0,
    //      y * X * (1 - c) + z * s, y * y * (1 - c) + c, y * z * (1 - c) - X * s, 0.0,
    //      X * z * (1 - c) - y * s, y * z * (1 - c) + X * s, z * z * (1 - c) + c, 0.0,
    //      0.0, 0.0, 0.0, 1.0
    //      );
    //}
 
 
    //template <typename T>
    //TMatrix4<double> TMatrix4<T>::makeScale(double X, double y, double z)
    //{
    //  return TMatrix4<double>(
    //      X, 0.0, 0.0, 0.0,
    //      0.0, y, 1.0, 0.0,
    //      0.0, 0.0, z, 0.0,
    //      0.0, 0.0, 0.0, 1.0
    //      );
    //}
 
 
    //template <typename T>
    //TMatrix4<double> TMatrix4<T>::makeTranslation(double X, double y, double z)
    //{
    //  return TMatrix4<double>(
    //      0.0, 0.0, 0.0, X,
    //      0.0, 0.0, 1.0, y,
    //      0.0, 0.0, 0.0, z,
    //      0.0, 0.0, 0.0, 1.0
    //      );
    //}
 
 
    //template <typename T>
    //inline TMatrix4<double> TMatrix4<T>::MakeRotation(double angleInDegrees, double X, double y, double z)
    //{
    //  double angleInRadians = angleInDegrees * FX_DEGREES_TO_RADIANS;
    //  double c = cos(angleInRadians);
    //  double s = sin(angleInRadians);
    //  double invLength = 1.0 / sqrt(X*X + y*y + z*z);
    //  X *= invLength;
    //  y *= invLength;
    //  z *= invLength;
 
    //  return TMatrix4<double>(
    //      X * X * (1 - c) + c, X * y * (1 - c) - z * s, X * z * (1 - c) + y * s, 0.0,
    //      y * X * (1 - c) + z * s, y * y * (1 - c) + c, y * z * (1 - c) - X * s, 0.0,
    //      X * z * (1 - c) - y * s, y * z * (1 - c) + X * s, z * z * (1 - c) + c, 0.0,
    //      0.0, 0.0, 0.0, 1.0
    //      );
    //}
 
    //template <typename T>
    //inline TMatrix4<double> TMatrix4<T>::MakeScaling(double X, double y, double z)
    //{
    //  return TMatrix4<double>(
    //      X, 0, 0, 0,
    //      0, y, 0, 0,
    //      0, 0, z, 0,
    //      0, 0, 0, 1
    //      );
    //}
 
    //template <typename T>
    //inline TMatrix4<double> TMatrix4<T>::MakeTranslation(double X, double y, double z)
    //{
    //  return TMatrix4<double>(
    //      1, 0, 0, X,
    //      0, 1, 0, y,
    //      0, 0, 1, z,
    //      0, 0, 0, 1
    //      );
    //}
 
    //template <typename T>
    //inline TMatrix4<double> TMatrix4<T>::MakeOrtho(double left, double right, double bottom, double top, double near_value, double far_value)
    //{
    //  double tx = -(right + left) / (right - left);
    //  double ty = -(top + bottom) / (top - bottom);
    //  double tz = -(far_value + near_value) / (far_value - near_value);
 
    //  return TMatrix4<double>(
    //      2 / (right - left), 0, 0, tx,
    //      0, 2 / (top - bottom), 0, ty,
    //      0, 0, -2 / (far_value - near_value), tz,
    //      0, 0, 0, 1
    //      );
    //}
 
    //template <typename T>
    //inline TMatrix4<double> TMatrix4<T>::MakeOrtho2D(double left, double right, double bottom, double top)
    //{
    //  double tx = -(right + left) / (right - left);
    //  double ty = -(top + bottom) / (top - bottom);
 
    //  return TMatrix4<double>(
    //      2 / (right - left), 0, 0, tx,
    //      0, 2 / (top - bottom), 0, ty,
    //      0, 0, -1, 0,
    //      0, 0, 0, 1
    //      );
    //}
 
    //template <typename T>
    //inline TMatrix4<double> TMatrix4<T>::MakeFrustum(double left, double right, double bottom, double top, double near_value, double far_value)
    //{
    //  double A = (right + left) / (right - left);
    //  double B = (top + bottom) / (top - bottom);
    //  double C = -(far_value + near_value) / (far_value - near_value);
    //  double D = -2 * far_value * near_value / (far_value - near_value);
 
    //  return TMatrix4<double>(
    //      2 * near_value / (right - left), 0, A, 0,
    //      0, 2 * near_value / (top - bottom), B, 0,
    //      0, 0, C, D,
    //      0, 0, -1, 0
    //      );
    //}
 
    //template <typename T>
    //inline TMatrix4<double> TMatrix4<T>::MakePerspective(double angleInDegrees, double aspect, double near_value, double far_value)
    //{
    //  double f = 1.0 / std::tan(FX_DEGREES_TO_RADIANS * 0.5 * angleInDegrees);
 
    //  return TMatrix4<double>(
    //      f / aspect, 0, 0, 0,
    //      0, f, 0, 0,
    //      0, 0, (far_value + near_value) / (near_value - far_value), 2 * far_value * near_value / (near_value - far_value),
    //      0, 0, -1, 0
    //      );
    //}
 
    //template <typename T>
    //inline TMatrix4<double> TMatrix4<T>::MakePerspectiveX(double angleInDegrees, double aspect, double near_value, double far_value)
    //{
    //  double f = 1.0 / std::tan(FX_DEGREES_TO_RADIANS * 0.5 * angleInDegrees);
 
    //  return TMatrix4<double>(
    //      f / aspect, 0, 0, 0,
    //      0, f, 0, 0,
    //      0, 0, (far_value + near_value) / (near_value - far_value), 2 * far_value * near_value / (near_value - far_value),
    //      0, 0, -1, 0
    //      );
    //}
 
    //template <typename T>
    //inline TMatrix4<double> TMatrix4<T>::MakePerspectiveY(double angleInDegrees, double aspect, double near_value, double far_value)
    //{
    //  double f = 1.0 / std::tan(FX_DEGREES_TO_RADIANS * 0.5 * angleInDegrees);
 
    //  return TMatrix4<double>(
    //      f, 0, 0, 0,
    //      0, f * aspect, 0, 0,
    //      0, 0, (far_value + near_value) / (near_value - far_value), 2 * far_value * near_value / (near_value - far_value),
    //      0, 0, -1, 0
    //      );
    //}
 
    //template <typename T>
    //inline TMatrix4<double> TMatrix4<T>::MakeLookAt(TVector3<double> eye, TVector3<double> center, TVector3<double> up)
    //{
    //  TVector3<double> F = (center - eye).norm();
    //  TVector3<double> S = F.cross(up).norm();
    //  TVector3<double> U = S.cross(F).norm();
 
    //  return TMatrix4<double>::multiply(TMatrix4<double>(
    //      S.X, S.y, S.z, 0.0,
    //      U.X, U.y, U.z, 0.0,
    //      -F.X, -F.y, -F.z, 0.0,
    //      0.0, 0.0, 0.0, 1.0),
    //      TMatrix4<double>::MakeTranslation(-eye.X, -eye.y, -eye.z));
    //}
 
    //template <typename T>
    //inline TMatrix4<double> TMatrix4<T>::MakeShadowBias()
    //{
    //  return TMatrix4<double>(
    //      0.5, 0.0, 0.0, 0.5,
    //      0.0, 0.5, 0.0, 0.5,
    //      0.0, 0.0, 0.5, 0.5,
    //      0.0, 0.0, 0.0, 1.0);
    //}
 
 
    //template <typename T>
    //inline TMatrix4<double> TMatrix4<T>::MakeCubeMatrix(int face)
    //{
    //  // support GL_TEXTURE_CUBE_MAP_POSITIVE_X, ... constants
    //  if (face >= 0x8515 && face <= 0x851A) face -= 0x8515;
 
    //  switch (face)
    //  {
    //  case 0: // GL_TEXTURE_CUBE_MAP_POSITIVE_X
    //      return TMatrix4<double>::MakeRotation(90.0, 0.0, 1.0, 0.0);
    //      break;
    //  case 1: // GL_TEXTURE_CUBE_MAP_NEGATIVE_X
    //      return TMatrix4<double>::MakeRotation(270.0, 0.0, 1.0, 0.0);
    //      break;
    //  case 2: // GL_TEXTURE_CUBE_MAP_POSITIVE_Y
    //      return TMatrix4<double>::MakeRotation(270.0, 1.0, 0.0, 0.0);
    //      break;
    //  case 3: // GL_TEXTURE_CUBE_MAP_NEGATIVE_Y
    //      return TMatrix4<double>::MakeRotation(90.0, 1.0, 0.0, 0.0);
    //      break;
    //  case 4: // GL_TEXTURE_CUBE_MAP_POSITIVE_Z
    //      return TMatrix4<double>::MakeIdentity();
    //      break;
    //  case 5: // GL_TEXTURE_CUBE_MAP_NEGATIVE_Z
    //      return TMatrix4<double>::MakeRotation(180.0, 0.0, 1.0, 0.0);
    //      break;
    //  }
    //  return TMatrix4<double>::MakeIdentity();
    //}
 
 
    //template <typename T>
    //inline TMatrix4<double> TMatrix4<T>::MakeIdentity()
    //{
    //  return TMatrix4<double>(
    //      1.0, 0.0, 0.0, 0.0,
    //      0.0, 1.0, 0.0, 0.0,
    //      0.0, 0.0, 1.0, 0.0,
    //      0.0, 0.0, 0.0, 1.0);
    //}
 
 
    extern template class TMatrix4<float>;
    extern template class TMatrix4<double>;
 
    using Matrix4f = TMatrix4<float>;
    using Matrix4d = TMatrix4<double>;
 
 
    template <typename T, typename U>
    constexpr auto operator * (const TMatrix4<T> & m1, const TMatrix4<U> & m2) noexcept
    {
        return TMatrix4<T>::multiply(m1, m2);
    }
 
 
    template <typename T, typename U>
    constexpr auto operator * (const TMatrix4<T> & M, const TVector2<U> & V) noexcept
    {
        return TVector2<common_type_t<T, U>>(
            M.m11 * V.x + M.m12 * V.y,
            M.m21 * V.x + M.m22 * V.y
            );
    }
 
 
    template <typename T, typename U>
    constexpr auto operator * (const TMatrix4<T> & M, const TVector3<U> & V) noexcept
    {
        return TVector2<common_type_t<T, U>>(
            M.m11 * V.x + M.m12 * V.y + M.m13 * V.z,
            M.m21 * V.x + M.m22 * V.y + M.m23 * V.z,
            M.m31 * V.x + M.m32 * V.y + M.m33 * V.z
            );
    }
 
 
    template <typename T, typename U>
    constexpr auto operator * (const TMatrix4<T> & M, const TVector4<U> & V) noexcept
    {
        return TVector4<common_type_t<T, U>>(
            M.m11 * V.x + M.m12 * V.y + M.m13 * V.z + M.m14 * V.w,
            M.m21 * V.x + M.m22 * V.y + M.m23 * V.z + M.m24 * V.w,
            M.m31 * V.x + M.m32 * V.y + M.m33 * V.z + M.m34 * V.w,
            M.m41 * V.x + M.m42 * V.y + M.m43 * V.z + M.m44 * V.w
            );
    }
}
 
#endif

Comments