mat4.h File Reference

Go to the documentation of this file. Source: include/ffw/graphics/mat4.h

/* This file is part of FineFramework project */
#ifndef FFW_MAT4X4
#define FFW_MAT4X4

#include "vec4.h"
#include "vec3.h"
#include "quaternion.h"

namespace ffw {
    template <class T> struct Mat4x4 {
    public:
        T ptr[16];

        inline Mat4x4() {
            ptr[0] = 1.0f;  ptr[4] = 0.0f;  ptr[8] = 0.0f; ptr[12] = 0.0f;
            ptr[1] = 0.0f;  ptr[5] = 1.0f;  ptr[9] = 0.0f; ptr[13] = 0.0f;
            ptr[2] = 0.0f;  ptr[6] = 0.0f;  ptr[10] = 1.0f; ptr[14] = 0.0f;
            ptr[3] = 0.0f;  ptr[7] = 0.0f;  ptr[11] = 0.0f; ptr[15] = 1.0f;
        }

        inline Mat4x4(T xx, T yx, T zx, T wx,
            T xy, T yy, T zy, T wy,
            T xz, T yz, T zz, T wz,
            T xw, T yw, T zw, T ww) {
            ptr[0] = xx;    ptr[4] = yx;    ptr[8] = zx;   ptr[12] = wx;
            ptr[1] = xy;    ptr[5] = yy;    ptr[9] = zy;   ptr[13] = wy;
            ptr[2] = xz;    ptr[6] = yz;    ptr[10] = zz;   ptr[14] = wz;
            ptr[3] = xw;    ptr[7] = yw;    ptr[11] = zw;   ptr[15] = ww;
        }

        inline Mat4x4(T val) {
            ptr[0] = val;   ptr[4] = 0.0f;  ptr[8] = 0.0f; ptr[12] = 0.0f;
            ptr[1] = 0.0f;  ptr[5] = val;   ptr[9] = 0.0f; ptr[13] = 0.0f;
            ptr[2] = 0.0f;  ptr[6] = 0.0f;  ptr[10] = val;  ptr[14] = 0.0f;
            ptr[3] = 0.0f;  ptr[7] = 0.0f;  ptr[11] = 0.0f; ptr[15] = val;
        }

        inline Mat4x4(std::initializer_list<T> list) {
            if (list.size() != 16) {
                ptr[0] = 1.0f;  ptr[4] = 0.0f;  ptr[8] = 0.0f; ptr[12] = 0.0f;
                ptr[1] = 0.0f;  ptr[5] = 1.0f;  ptr[9] = 0.0f; ptr[13] = 0.0f;
                ptr[2] = 0.0f;  ptr[6] = 0.0f;  ptr[10] = 1.0f; ptr[14] = 0.0f;
                ptr[3] = 0.0f;  ptr[7] = 0.0f;  ptr[11] = 0.0f; ptr[15] = 1.0f;
                return;
            }
            for (int i = 0; i < 16; i++) {
                ptr[i] = *(list.begin() + i);
            }
        }

        inline void set(T xx, T yx, T zx, T wx,
            T xy, T yy, T zy, T wy,
            T xz, T yz, T zz, T wz,
            T xw, T yw, T zw, T ww) {
            ptr[0] = xx;    ptr[4] = yx;    ptr[8] = zx;   ptr[12] = wx;
            ptr[1] = xy;    ptr[5] = yy;    ptr[9] = zy;   ptr[13] = wy;
            ptr[2] = xz;    ptr[6] = yz;    ptr[10] = zz;   ptr[14] = wz;
            ptr[3] = xw;    ptr[7] = yw;    ptr[11] = zw;   ptr[15] = ww;
        }

        inline void set(T val) {
            ptr[0] = val;   ptr[4] = 0.0f;  ptr[8] = 0.0f; ptr[12] = 0.0f;
            ptr[1] = 0.0f;  ptr[5] = val;   ptr[9] = 0.0f; ptr[13] = 0.0f;
            ptr[2] = 0.0f;  ptr[6] = 0.0f;  ptr[10] = val;  ptr[14] = 0.0f;
            ptr[3] = 0.0f;  ptr[7] = 0.0f;  ptr[11] = 0.0f; ptr[15] = val;
        }

        inline void set(T m[16]) {
            ptr[0] = m[0];    ptr[4] = m[4];    ptr[8] = m[8];   ptr[12] = m[12];
            ptr[1] = m[1];    ptr[5] = m[5];    ptr[9] = m[9];   ptr[13] = m[13];
            ptr[2] = m[2];    ptr[6] = m[6];    ptr[10] = m[10];  ptr[14] = m[14];
            ptr[3] = m[3];    ptr[7] = m[7];    ptr[11] = m[11];  ptr[15] = m[15];
        }

        inline void set(std::initializer_list<T> list) {
            if (list.size() != 16) {
                return;
            }
            for (int i = 0; i < 16; i++) {
                ptr[i] = *(list.begin() + i);
            }
        }

        inline T* getPtr() {
            return &ptr[0];
        }

        inline const T* getPtr() const {
            return &ptr[0];
        }

        inline ffw::Mat4x4<T>& operator = (const ffw::Mat4x4<T> &m) {
            ptr[0] = m.ptr[0];  ptr[4] = m.ptr[4];  ptr[8] = m.ptr[8];     ptr[12] = m.ptr[12];
            ptr[1] = m.ptr[1];  ptr[5] = m.ptr[5];  ptr[9] = m.ptr[9];     ptr[13] = m.ptr[13];
            ptr[2] = m.ptr[2];  ptr[6] = m.ptr[6];  ptr[10] = m.ptr[10];    ptr[14] = m.ptr[14];
            ptr[3] = m.ptr[3];  ptr[7] = m.ptr[7];  ptr[11] = m.ptr[11];    ptr[15] = m.ptr[15];
            return *this;
        }

        inline ffw::Mat4x4<T> operator + (const ffw::Mat4x4<T> &m) const {
            Mat4x4 r;
            r.ptr[0] = ptr[0] + m.ptr[0];
            r.ptr[1] = ptr[1] + m.ptr[1];
            r.ptr[2] = ptr[2] + m.ptr[2];
            r.ptr[3] = ptr[3] + m.ptr[3];

            r.ptr[4] = ptr[4] + m.ptr[4];
            r.ptr[5] = ptr[5] + m.ptr[5];
            r.ptr[6] = ptr[6] + m.ptr[6];
            r.ptr[7] = ptr[7] + m.ptr[7];

            r.ptr[8] = ptr[8] + m.ptr[8];
            r.ptr[9] = ptr[9] + m.ptr[9];
            r.ptr[10] = ptr[10] + m.ptr[10];
            r.ptr[11] = ptr[11] + m.ptr[11];

            r.ptr[12] = ptr[12] + m.ptr[12];
            r.ptr[13] = ptr[13] + m.ptr[13];
            r.ptr[14] = ptr[14] + m.ptr[14];
            r.ptr[15] = ptr[15] + m.ptr[15];
            return r;
        }

        inline ffw::Mat4x4<T>&  operator += (const ffw::Mat4x4<T> &m) {
            ptr[0] += m.ptr[0];
            ptr[1] += m.ptr[1];
            ptr[2] += m.ptr[2];
            ptr[3] += m.ptr[3];

            ptr[4] += m.ptr[4];
            ptr[5] += m.ptr[5];
            ptr[6] += m.ptr[6];
            ptr[7] += m.ptr[7];

            ptr[8] += m.ptr[8];
            ptr[9] += m.ptr[9];
            ptr[10] += m.ptr[10];
            ptr[11] += m.ptr[11];

            ptr[12] += m.ptr[12];
            ptr[13] += m.ptr[13];
            ptr[14] += m.ptr[14];
            ptr[15] += m.ptr[15];
            return *this;
        }

        inline ffw::Mat4x4<T> operator - (const ffw::Mat4x4<T> &m) const {
            Mat4x4 r;
            r.ptr[0] = ptr[0] - m.ptr[0];
            r.ptr[1] = ptr[1] - m.ptr[1];
            r.ptr[2] = ptr[2] - m.ptr[2];
            r.ptr[3] = ptr[3] - m.ptr[3];

            r.ptr[4] = ptr[4] - m.ptr[4];
            r.ptr[5] = ptr[5] - m.ptr[5];
            r.ptr[6] = ptr[6] - m.ptr[6];
            r.ptr[7] = ptr[7] - m.ptr[7];

            r.ptr[8] = ptr[8] - m.ptr[8];
            r.ptr[9] = ptr[9] - m.ptr[9];
            r.ptr[10] = ptr[10] - m.ptr[10];
            r.ptr[11] = ptr[11] - m.ptr[11];

            r.ptr[12] = ptr[12] - m.ptr[12];
            r.ptr[13] = ptr[13] - m.ptr[13];
            r.ptr[14] = ptr[14] - m.ptr[14];
            r.ptr[15] = ptr[15] - m.ptr[15];
            return r;
        }

        inline ffw::Mat4x4<T>&  operator -= (const ffw::Mat4x4<T> &m) {
            ptr[0] -= m.ptr[0];
            ptr[1] -= m.ptr[1];
            ptr[2] -= m.ptr[2];
            ptr[3] -= m.ptr[3];

            ptr[4] -= m.ptr[4];
            ptr[5] -= m.ptr[5];
            ptr[6] -= m.ptr[6];
            ptr[7] -= m.ptr[7];

            ptr[8] -= m.ptr[8];
            ptr[9] -= m.ptr[9];
            ptr[10] -= m.ptr[10];
            ptr[11] -= m.ptr[11];

            ptr[12] -= m.ptr[12];
            ptr[13] -= m.ptr[13];
            ptr[14] -= m.ptr[14];
            ptr[15] -= m.ptr[15];
            return *this;
        }

        inline ffw::Mat4x4<T>  operator * (const ffw::Mat4x4<T> &m) const {
            Mat4x4 r;
            r.ptr[0] = ptr[0] * m.ptr[0] + ptr[4] * m.ptr[1] + ptr[8] * m.ptr[2] + ptr[12] * m.ptr[3];  r.ptr[4] = ptr[0] * m.ptr[4] + ptr[4] * m.ptr[5] + ptr[8] * m.ptr[6] + ptr[12] * m.ptr[7];  r.ptr[8] = ptr[0] * m.ptr[8] + ptr[4] * m.ptr[9] + ptr[8] * m.ptr[10] + ptr[12] * m.ptr[11];  r.ptr[12] = ptr[0] * m.ptr[12] + ptr[4] * m.ptr[13] + ptr[8] * m.ptr[14] + ptr[12] * m.ptr[15];
            r.ptr[1] = ptr[1] * m.ptr[0] + ptr[5] * m.ptr[1] + ptr[9] * m.ptr[2] + ptr[13] * m.ptr[3];  r.ptr[5] = ptr[1] * m.ptr[4] + ptr[5] * m.ptr[5] + ptr[9] * m.ptr[6] + ptr[13] * m.ptr[7];  r.ptr[9] = ptr[1] * m.ptr[8] + ptr[5] * m.ptr[9] + ptr[9] * m.ptr[10] + ptr[13] * m.ptr[11];  r.ptr[13] = ptr[1] * m.ptr[12] + ptr[5] * m.ptr[13] + ptr[9] * m.ptr[14] + ptr[13] * m.ptr[15];
            r.ptr[2] = ptr[2] * m.ptr[0] + ptr[6] * m.ptr[1] + ptr[10] * m.ptr[2] + ptr[14] * m.ptr[3];  r.ptr[6] = ptr[2] * m.ptr[4] + ptr[6] * m.ptr[5] + ptr[10] * m.ptr[6] + ptr[14] * m.ptr[7];  r.ptr[10] = ptr[2] * m.ptr[8] + ptr[6] * m.ptr[9] + ptr[10] * m.ptr[10] + ptr[14] * m.ptr[11];  r.ptr[14] = ptr[2] * m.ptr[12] + ptr[6] * m.ptr[13] + ptr[10] * m.ptr[14] + ptr[14] * m.ptr[15];
            r.ptr[3] = ptr[3] * m.ptr[0] + ptr[7] * m.ptr[1] + ptr[11] * m.ptr[2] + ptr[15] * m.ptr[3];  r.ptr[7] = ptr[3] * m.ptr[4] + ptr[7] * m.ptr[5] + ptr[11] * m.ptr[6] + ptr[15] * m.ptr[7];  r.ptr[11] = ptr[3] * m.ptr[8] + ptr[7] * m.ptr[9] + ptr[11] * m.ptr[10] + ptr[15] * m.ptr[11];  r.ptr[15] = ptr[3] * m.ptr[12] + ptr[7] * m.ptr[13] + ptr[11] * m.ptr[14] + ptr[15] * m.ptr[15];
            return r;
        }

        inline ffw::Mat4x4<T>&  operator *= (const ffw::Mat4x4<T> &m) {
            Mat4x4 r;
            r.ptr[0] = ptr[0] * m.ptr[0] + ptr[4] * m.ptr[1] + ptr[8] * m.ptr[2] + ptr[12] * m.ptr[3];  r.ptr[4] = ptr[0] * m.ptr[4] + ptr[4] * m.ptr[5] + ptr[8] * m.ptr[6] + ptr[12] * m.ptr[7];  r.ptr[8] = ptr[0] * m.ptr[8] + ptr[4] * m.ptr[9] + ptr[8] * m.ptr[10] + ptr[12] * m.ptr[11];  r.ptr[12] = ptr[0] * m.ptr[12] + ptr[4] * m.ptr[13] + ptr[8] * m.ptr[14] + ptr[12] * m.ptr[15];
            r.ptr[1] = ptr[1] * m.ptr[0] + ptr[5] * m.ptr[1] + ptr[9] * m.ptr[2] + ptr[13] * m.ptr[3];  r.ptr[5] = ptr[1] * m.ptr[4] + ptr[5] * m.ptr[5] + ptr[9] * m.ptr[6] + ptr[13] * m.ptr[7];  r.ptr[9] = ptr[1] * m.ptr[8] + ptr[5] * m.ptr[9] + ptr[9] * m.ptr[10] + ptr[13] * m.ptr[11];  r.ptr[13] = ptr[1] * m.ptr[12] + ptr[5] * m.ptr[13] + ptr[9] * m.ptr[14] + ptr[13] * m.ptr[15];
            r.ptr[2] = ptr[2] * m.ptr[0] + ptr[6] * m.ptr[1] + ptr[10] * m.ptr[2] + ptr[14] * m.ptr[3];  r.ptr[6] = ptr[2] * m.ptr[4] + ptr[6] * m.ptr[5] + ptr[10] * m.ptr[6] + ptr[14] * m.ptr[7];  r.ptr[10] = ptr[2] * m.ptr[8] + ptr[6] * m.ptr[9] + ptr[10] * m.ptr[10] + ptr[14] * m.ptr[11];  r.ptr[14] = ptr[2] * m.ptr[12] + ptr[6] * m.ptr[13] + ptr[10] * m.ptr[14] + ptr[14] * m.ptr[15];
            r.ptr[3] = ptr[3] * m.ptr[0] + ptr[7] * m.ptr[1] + ptr[11] * m.ptr[2] + ptr[15] * m.ptr[3];  r.ptr[7] = ptr[3] * m.ptr[4] + ptr[7] * m.ptr[5] + ptr[11] * m.ptr[6] + ptr[15] * m.ptr[7];  r.ptr[11] = ptr[3] * m.ptr[8] + ptr[7] * m.ptr[9] + ptr[11] * m.ptr[10] + ptr[15] * m.ptr[11];  r.ptr[15] = ptr[3] * m.ptr[12] + ptr[7] * m.ptr[13] + ptr[11] * m.ptr[14] + ptr[15] * m.ptr[15];
            *this = r;
            return *this;
        }

        template <class S>
        inline ffw::Vec4<S> operator * (const ffw::Vec4<S>& v) const {
            ffw::Vec4f r;
            r.x = v.x*ptr[0] + v.y*ptr[4] + v.z*ptr[8] + v.w*ptr[12];
            r.y = v.x*ptr[1] + v.y*ptr[5] + v.z*ptr[9] + v.w*ptr[13];
            r.z = v.x*ptr[2] + v.y*ptr[6] + v.z*ptr[10] + v.w*ptr[14];
            r.w = v.x*ptr[3] + v.y*ptr[7] + v.z*ptr[11] + v.w*ptr[15];
            return r;
        }

        template <class S>
        inline ffw::Vec3<S> operator * (const ffw::Vec3<S>& v) const {
            ffw::Vec3f r;
            r.x = v.x*ptr[0] + v.y*ptr[4] + v.z*ptr[8] + ptr[12];
            r.y = v.x*ptr[1] + v.y*ptr[5] + v.z*ptr[9] + ptr[13];
            r.z = v.x*ptr[2] + v.y*ptr[6] + v.z*ptr[10] + ptr[14];
            //r.w = v.x*ptr[3] + v.y*ptr[7] + v.z*ptr[11] + v.w*ptr[15];
            return r;
        }

        inline T& operator [] (int x) {
            return ptr[x];
        }

        inline const T& operator [] (int x) const {
            return ptr[x];
        }

        inline ffw::Mat4x4<T>& rotate(const ffw::Quaternion<T>& q) {
            // Taken from http://www.euclideanspace.com/maths/geometry/rotations/conversions/quaternionToMatrix/index.htm
            auto sqw = q.w*q.w;
            auto sqx = q.x*q.x;
            auto sqy = q.y*q.y;
            auto sqz = q.z*q.z;

            // invs (inverse square length) is only required if quaternion is not already normalised
            auto invs = T(1) / (sqx + sqy + sqz + sqw);
            ptr[0] = (sqx - sqy - sqz + sqw)*invs; // since sqw + sqx + sqy + sqz =1/invs*invs
            ptr[5] = (-sqx + sqy - sqz + sqw)*invs;
            ptr[10] = (-sqx - sqy + sqz + sqw)*invs;

            auto tmp1 = q.x*q.y;
            auto tmp2 = q.z*q.w;
            ptr[1] = T(2.0) * (tmp1 + tmp2)*invs;
            ptr[4] = T(2.0) * (tmp1 - tmp2)*invs;

            tmp1 = q.x*q.z;
            tmp2 = q.y*q.w;
            ptr[2] = T(2.0) * (tmp1 - tmp2)*invs;
            ptr[8] = T(2.0) * (tmp1 + tmp2)*invs;
            tmp1 = q.y*q.z;
            tmp2 = q.x*q.w;
            ptr[6] = T(2.0) * (tmp1 + tmp2)*invs;
            ptr[9] = T(2.0) * (tmp1 - tmp2)*invs;

            return *this;
        }

        inline ffw::Mat4x4<T>& translate(T x, T y, T z) {
            ptr[12] += x;
            ptr[13] += y;
            ptr[14] += z;
            return *this;
        }

        inline ffw::Mat4x4<T>& scale(T x, T y, T z) {
            Mat4x4 m;
            m[0] = x;
            m[5] = y;
            m[10] = z;
            (*this) *= m;
            return *this;
        }

        inline ffw::Mat4x4<T>& transpose() {
            T m04 = ptr[4];
            T m08 = ptr[8];
            T m09 = ptr[9];
            T m12 = ptr[12];
            T m13 = ptr[13];
            T m14 = ptr[14];
            ptr[4] = ptr[1];
            ptr[8] = ptr[2];
            ptr[9] = ptr[6];
            ptr[12] = ptr[3];
            ptr[13] = ptr[7];
            ptr[14] = ptr[11];
            ptr[1] = m04;
            ptr[2] = m08;
            ptr[6] = m09;
            ptr[3] = m12;
            ptr[7] = m13;
            ptr[11] = m14;
            return *this;
        }

        inline T determinant() const {
            // Taken from http://www.euclideanspace.com/maths/algebra/matrix/functions/determinant/fourD/index.htm
            const auto det = 
                ptr[12] * ptr[9] * ptr[6] * ptr[3] - ptr[8] * ptr[13] * ptr[6] * ptr[3] -
                ptr[12] * ptr[5] * ptr[10] * ptr[3] + ptr[4] * ptr[13] * ptr[10] * ptr[3] +
                ptr[8] * ptr[5] * ptr[14] * ptr[3] - ptr[4] * ptr[9] * ptr[14] * ptr[3] -
                ptr[12] * ptr[9] * ptr[2] * ptr[7] + ptr[8] * ptr[13] * ptr[2] * ptr[7] +
                ptr[12] * ptr[1] * ptr[10] * ptr[7] - ptr[0] * ptr[13] * ptr[10] * ptr[7] -
                ptr[8] * ptr[1] * ptr[14] * ptr[7] + ptr[0] * ptr[9] * ptr[14] * ptr[7] +
                ptr[12] * ptr[5] * ptr[2] * ptr[11] - ptr[4] * ptr[13] * ptr[2] * ptr[11] -
                ptr[12] * ptr[1] * ptr[6] * ptr[11] + ptr[0] * ptr[13] * ptr[6] * ptr[11] +
                ptr[4] * ptr[1] * ptr[14] * ptr[11] - ptr[0] * ptr[5] * ptr[14] * ptr[11] -
                ptr[8] * ptr[5] * ptr[2] * ptr[15] + ptr[4] * ptr[9] * ptr[2] * ptr[15] +
                ptr[8] * ptr[1] * ptr[6] * ptr[15] - ptr[0] * ptr[9] * ptr[6] * ptr[15] -
                ptr[4] * ptr[1] * ptr[10] * ptr[15] + ptr[0] * ptr[5] * ptr[10] * ptr[15];
            return det;
        }

        inline ffw::Mat4x4<T>& inverse() {
            ffw::Mat4x4<T> m;
            m.ptr[0] = ptr[6]*ptr[11]*ptr[13] - ptr[7]*ptr[10]*ptr[13] + ptr[7]*ptr[9]*ptr[14] - ptr[5]*ptr[11]*ptr[14] - ptr[6]*ptr[9]*ptr[15] + ptr[5]*ptr[10]*ptr[15];
            m.ptr[1] = ptr[3]*ptr[10]*ptr[13] - ptr[2]*ptr[11]*ptr[13] - ptr[3]*ptr[9]*ptr[14] + ptr[1]*ptr[11]*ptr[14] + ptr[2]*ptr[9]*ptr[15] - ptr[1]*ptr[10]*ptr[15];
            m.ptr[2] = ptr[2]*ptr[7]*ptr[13] - ptr[3]*ptr[6]*ptr[13] + ptr[3]*ptr[5]*ptr[14] - ptr[1]*ptr[7]*ptr[14] - ptr[2]*ptr[5]*ptr[15] + ptr[1]*ptr[6]*ptr[15];
            m.ptr[3] = ptr[3]*ptr[6]*ptr[9] - ptr[2]*ptr[7]*ptr[9] - ptr[3]*ptr[5]*ptr[10] + ptr[1]*ptr[7]*ptr[10] + ptr[2]*ptr[5]*ptr[11] - ptr[1]*ptr[6]*ptr[11];
            m.ptr[4] = ptr[7]*ptr[10]*ptr[12] - ptr[6]*ptr[11]*ptr[12] - ptr[7]*ptr[8]*ptr[14] + ptr[4]*ptr[11]*ptr[14] + ptr[6]*ptr[8]*ptr[15] - ptr[4]*ptr[10]*ptr[15];
            m.ptr[5] = ptr[2]*ptr[11]*ptr[12] - ptr[3]*ptr[10]*ptr[12] + ptr[3]*ptr[8]*ptr[14] - ptr[0]*ptr[11]*ptr[14] - ptr[2]*ptr[8]*ptr[15] + ptr[0]*ptr[10]*ptr[15];
            m.ptr[6] = ptr[3]*ptr[6]*ptr[12] - ptr[2]*ptr[7]*ptr[12] - ptr[3]*ptr[4]*ptr[14] + ptr[0]*ptr[7]*ptr[14] + ptr[2]*ptr[4]*ptr[15] - ptr[0]*ptr[6]*ptr[15];
            m.ptr[7] = ptr[2]*ptr[7]*ptr[8] - ptr[3]*ptr[6]*ptr[8] + ptr[3]*ptr[4]*ptr[10] - ptr[0]*ptr[7]*ptr[10] - ptr[2]*ptr[4]*ptr[11] + ptr[0]*ptr[6]*ptr[11];
            m.ptr[8] = ptr[5]*ptr[11]*ptr[12] - ptr[7]*ptr[9]*ptr[12] + ptr[7]*ptr[8]*ptr[13] - ptr[4]*ptr[11]*ptr[13] - ptr[5]*ptr[8]*ptr[15] + ptr[4]*ptr[9]*ptr[15];
            m.ptr[9] = ptr[3]*ptr[9]*ptr[12] - ptr[1]*ptr[11]*ptr[12] - ptr[3]*ptr[8]*ptr[13] + ptr[0]*ptr[11]*ptr[13] + ptr[1]*ptr[8]*ptr[15] - ptr[0]*ptr[9]*ptr[15];
            m.ptr[10] = ptr[1]*ptr[7]*ptr[12] - ptr[3]*ptr[5]*ptr[12] + ptr[3]*ptr[4]*ptr[13] - ptr[0]*ptr[7]*ptr[13] - ptr[1]*ptr[4]*ptr[15] + ptr[0]*ptr[5]*ptr[15];
            m.ptr[11] = ptr[3]*ptr[5]*ptr[8] - ptr[1]*ptr[7]*ptr[8] - ptr[3]*ptr[4]*ptr[9] + ptr[0]*ptr[7]*ptr[9] + ptr[1]*ptr[4]*ptr[11] - ptr[0]*ptr[5]*ptr[11];
            m.ptr[12] = ptr[6]*ptr[9]*ptr[12] - ptr[5]*ptr[10]*ptr[12] - ptr[6]*ptr[8]*ptr[13] + ptr[4]*ptr[10]*ptr[13] + ptr[5]*ptr[8]*ptr[14] - ptr[4]*ptr[9]*ptr[14];
            m.ptr[13] = ptr[1]*ptr[10]*ptr[12] - ptr[2]*ptr[9]*ptr[12] + ptr[2]*ptr[8]*ptr[13] - ptr[0]*ptr[10]*ptr[13] - ptr[1]*ptr[8]*ptr[14] + ptr[0]*ptr[9]*ptr[14];
            m.ptr[14] = ptr[2]*ptr[5]*ptr[12] - ptr[1]*ptr[6]*ptr[12] - ptr[2]*ptr[4]*ptr[13] + ptr[0]*ptr[6]*ptr[13] + ptr[1]*ptr[4]*ptr[14] - ptr[0]*ptr[5]*ptr[14];
            m.ptr[15] = ptr[1]*ptr[6]*ptr[8] - ptr[2]*ptr[5]*ptr[8] + ptr[2]*ptr[4]*ptr[9] - ptr[0]*ptr[6]*ptr[9] - ptr[1]*ptr[4]*ptr[10] + ptr[0]*ptr[5]*ptr[10];
            const auto det = T(1) / determinant();
            for (int i = 0; i < 16; i++)ptr[i] = m.ptr[i] * det;
            return *this;
        }
    };
    typedef Mat4x4<float> Mat4x4f;
    typedef Mat4x4<double> Mat4x4d;
    typedef Mat4x4<int> Mat4x4i;
};
#endif