/* * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or * its licensors. * * For complete copyright and license terms please see the LICENSE at the root of this * distribution (the "License"). All use of this software is governed by the License, * or, if provided, by the license below or the license accompanying this file. Do not * remove or modify any license notices. This file is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * */ // Original file Copyright Crytek GMBH or its affiliates, used under license. // Description : Common matrix class #ifndef CRYINCLUDE_CRYCOMMON_CRY_MATRIX34_H #define CRYINCLUDE_CRYCOMMON_CRY_MATRIX34_H #pragma once /////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// // struct Matrix34_tpl /////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// template struct Matrix34_tpl { F m00, m01, m02, m03; F m10, m11, m12, m13; F m20, m21, m22, m23; //default constructor #if defined(_DEBUG) ILINE Matrix34_tpl() { if (sizeof(F) == 4) { uint32* p = (uint32*)&m00; p[ 0] = F32NAN; p[ 1] = F32NAN; p[ 2] = F32NAN; p[ 3] = F32NAN; p[ 4] = F32NAN; p[ 5] = F32NAN; p[ 6] = F32NAN; p[ 7] = F32NAN; p[ 8] = F32NAN; p[ 9] = F32NAN; p[10] = F32NAN; p[11] = F32NAN; } if (sizeof(F) == 8) { uint64* p = (uint64*)&m00; p[ 0] = F64NAN; p[ 1] = F64NAN; p[ 2] = F64NAN; p[ 3] = F64NAN; p[ 4] = F64NAN; p[ 5] = F64NAN; p[ 6] = F64NAN; p[ 7] = F64NAN; p[ 8] = F64NAN; p[ 9] = F64NAN; p[10] = F64NAN; p[11] = F64NAN; } } #else ILINE Matrix34_tpl(){}; #endif //set matrix to Identity ILINE Matrix34_tpl(type_identity) { m00 = 1; m01 = 0; m02 = 0; m03 = 0; m10 = 0; m11 = 1; m12 = 0; m13 = 0; m20 = 0; m21 = 0; m22 = 1; m23 = 0; } //set matrix to Zero ILINE Matrix34_tpl(type_zero) { m00 = 0; m01 = 0; m02 = 0; m03 = 0; m10 = 0; m11 = 0; m12 = 0; m13 = 0; m20 = 0; m21 = 0; m22 = 0; m23 = 0; } //ASSIGNMENT OPERATOR of identical Matrix33 types. //The assignment operator has precedence over assignment constructor //Matrix34 m; m=m34; ILINE Matrix34_tpl& operator = (const Matrix34_tpl& m) { assert(m.IsValid()); m00 = m.m00; m01 = m.m01; m02 = m.m02; m03 = m.m03; m10 = m.m10; m11 = m.m11; m12 = m.m12; m13 = m.m13; m20 = m.m20; m21 = m.m21; m22 = m.m22; m23 = m.m23; return *this; } //-------------------------------------------------------------------- //---- implementation of the constructors --- //-------------------------------------------------------------------- //CONSTRUCTOR for identical float-types. It initialises a matrix34 with 12 floats. ILINE Matrix34_tpl(F v00, F v01, F v02, F v03, F v10, F v11, F v12, F v13, F v20, F v21, F v22, F v23) { m00 = v00; m01 = v01; m02 = v02; m03 = v03; m10 = v10; m11 = v11; m12 = v12; m13 = v13; m20 = v20; m21 = v21; m22 = v22; m23 = v23; } //CONSTRUCTOR for different float-types. It initialises a matrix34 with 12 floats. template ILINE Matrix34_tpl(F1 v00, F1 v01, F1 v02, F1 v03, F1 v10, F1 v11, F1 v12, F1 v13, F1 v20, F1 v21, F1 v22, F1 v23) { m00 = F(v00); m01 = F(v01); m02 = F(v02); m03 = F(v03); m10 = F(v10); m11 = F(v11); m12 = F(v12); m13 = F(v13); m20 = F(v20); m21 = F(v21); m22 = F(v22); m23 = F(v23); } //CONSTRUCTOR for identical float-types. It converts a Matrix33 into a Matrix34. //Matrix34(m33); ILINE Matrix34_tpl(const Matrix33_tpl&m) { assert(m.IsValid()); m00 = m.m00; m01 = m.m01; m02 = m.m02; m03 = 0; m10 = m.m10; m11 = m.m11; m12 = m.m12; m13 = 0; m20 = m.m20; m21 = m.m21; m22 = m.m22; m23 = 0; } //CONSTRUCTOR for different float-types. It converts a Matrix33 into a Matrix34 and also converts between double/float. //Matrix34(Matrix33); template ILINE Matrix34_tpl(const Matrix33_tpl&m) { assert(m.IsValid()); m00 = F(m.m00); m01 = F(m.m01); m02 = F(m.m02); m03 = 0; m10 = F(m.m10); m11 = F(m.m11); m12 = F(m.m12); m13 = 0; m20 = F(m.m20); m21 = F(m.m21); m22 = F(m.m22); m23 = 0; } //CONSTRUCTOR for identical float-types. It converts a Matrix33 with a translation-vector into a Matrix34. //Matrix34(m33,Vec3(1,2,3)); ILINE Matrix34_tpl(const Matrix33_tpl&m, const Vec3_tpl&t) { assert(m.IsValid()); assert(t.IsValid()); m00 = m.m00; m01 = m.m01; m02 = m.m02; m03 = t.x; m10 = m.m10; m11 = m.m11; m12 = m.m12; m13 = t.y; m20 = m.m20; m21 = m.m21; m22 = m.m22; m23 = t.z; } //CONSTRUCTOR for different float-types. It converts a Matrix33 with a translation-vector into a Matrix34 and also converts between double/float. //Matrix34(Matrix33r,Vec3d(1,2,3)); template ILINE Matrix34_tpl(const Matrix33_tpl&m, const Vec3_tpl&t) { assert(m.IsValid()); assert(t.IsValid()); m00 = F(m.m00); m01 = F(m.m01); m02 = F(m.m02); m03 = F(t.x); m10 = F(m.m10); m11 = F(m.m11); m12 = F(m.m12); m13 = F(t.y); m20 = F(m.m20); m21 = F(m.m21); m22 = F(m.m22); m23 = F(t.z); } //CONSTRUCTOR for identical float types //Matrix34 m=m34; ILINE Matrix34_tpl(const Matrix34_tpl&m) { assert(m.IsValid()); m00 = m.m00; m01 = m.m01; m02 = m.m02; m03 = m.m03; m10 = m.m10; m11 = m.m11; m12 = m.m12; m13 = m.m13; m20 = m.m20; m21 = m.m21; m22 = m.m22; m23 = m.m23; } //CONSTRUCTOR for different float-types. //Matrix34 m=m34d; template ILINE Matrix34_tpl(const Matrix34_tpl&m) { assert(m.IsValid()); m00 = F(m.m00); m01 = F(m.m01); m02 = F(m.m02); m03 = F(m.m03); m10 = F(m.m10); m11 = F(m.m11); m12 = F(m.m12); m13 = F(m.m13); m20 = F(m.m20); m21 = F(m.m21); m22 = F(m.m22); m23 = F(m.m23); } //CONSTRUCTOR for identical float-types. It converts a Matrix44 into a Matrix34. //Needs to be 'explicit' because we loose the translation vector in the conversion process //Matrix34(m44); ILINE explicit Matrix34_tpl(const Matrix44_tpl&m) { assert(m.IsValid()); m00 = m.m00; m01 = m.m01; m02 = m.m02; m03 = m.m03; m10 = m.m10; m11 = m.m11; m12 = m.m12; m13 = m.m13; m20 = m.m20; m21 = m.m21; m22 = m.m22; m23 = m.m23; } //CONSTRUCTOR for different float types. It converts a Matrix44 into a Matrix34 and converts between double/float. //Needs to be 'explicit' because we loose the translation vector in the conversion process //Matrix34(m44r); template ILINE explicit Matrix34_tpl(const Matrix44_tpl&m) { assert(m.IsValid()); m00 = F(m.m00); m01 = F(m.m01); m02 = F(m.m02); m03 = F(m.m03); m10 = F(m.m10); m11 = F(m.m11); m12 = F(m.m12); m13 = F(m.m13); m20 = F(m.m20); m21 = F(m.m21); m22 = F(m.m22); m23 = F(m.m23); } //CONSTRUCTOR for identical float-types. It converts a Quat into a Matrix34. //Needs to be 'explicit' because we loose float-precision in the conversion process //Matrix34(QuatT); explicit ILINE Matrix34_tpl(const Quat_tpl&q) { *this = Matrix33_tpl(q); } //CONSTRUCTOR for different float-types. It converts a Quat into a Matrix34. //Needs to be 'explicit' because we loose float-precision in the conversion process //Matrix34(QuatTd); template explicit ILINE Matrix34_tpl(const Quat_tpl&q) { *this = Matrix33_tpl(q); } //CONSTRUCTOR for identical float-types. It converts a QuatT into a Matrix34. //Needs to be 'explicit' because we loose float-precision in the conversion process //Matrix34(QuatT); explicit ILINE Matrix34_tpl(const QuatT_tpl &q) { *this = Matrix34_tpl(Matrix33_tpl(q.q), q.t); } //CONSTRUCTOR for different float-types. It converts a QuatT into a Matrix34. //Needs to be 'explicit' because we loose float-precision in the conversion process //Matrix34(QuatT); template ILINE explicit Matrix34_tpl(const QuatT_tpl q) { *this = Matrix34_tpl(Matrix33_tpl(q.q), q.t); } //CONSTRUCTOR for identical float-types. It converts a QuatTS into a Matrix34. //Needs to be 'explicit' because we loose float-precision in the conversion process //Matrix34(QuatT); explicit ILINE Matrix34_tpl(const QuatTS_tpl &q) { assert(q.q.IsValid()); Vec3_tpl v2 = q.q.v + q.q.v; F xx = 1 - v2.x * q.q.v.x; F yy = v2.y * q.q.v.y; F xw = v2.x * q.q.w; F xy = v2.y * q.q.v.x; F yz = v2.z * q.q.v.y; F yw = v2.y * q.q.w; F xz = v2.z * q.q.v.x; F zz = v2.z * q.q.v.z; F zw = v2.z * q.q.w; m00 = (1 - yy - zz) * q.s; m01 = (xy - zw) * q.s; m02 = (xz + yw) * q.s; m03 = q.t.x; m10 = (xy + zw) * q.s; m11 = (xx - zz) * q.s; m12 = (yz - xw) * q.s; m13 = q.t.y; m20 = (xz - yw) * q.s; m21 = (yz + xw) * q.s; m22 = (xx - yy) * q.s; m23 = q.t.z; } //CONSTRUCTOR for different float-types. It converts a QuatTS into a Matrix34. //Needs to be 'explicit' because we loose float-precision in the conversion process //Matrix34(QuatT); template ILINE explicit Matrix34_tpl(const QuatTS_tpl &q) { assert(q.q.IsValid()); Vec3_tpl v2 = q.q.v + q.q.v; F1 xx = 1 - v2.x * q.q.v.x; F1 yy = v2.y * q.q.v.y; F1 xw = v2.x * q.q.w; F1 xy = v2.y * q.q.v.x; F1 yz = v2.z * q.q.v.y; F1 yw = v2.y * q.q.w; F1 xz = v2.z * q.q.v.x; F1 zz = v2.z * q.q.v.z; F1 zw = v2.z * q.q.w; m00 = F((1 - yy - zz) * q.s); m01 = F((xy - zw) * q.s); m02 = F((xz + yw) * q.s); m03 = F(q.t.x); m10 = F((xy + zw) * q.s); m11 = F((xx - zz) * q.s); m12 = F((yz - xw) * q.s); m13 = F(q.t.y); m20 = F((xz - yw) * q.s); m21 = F((yz + xw) * q.s); m22 = F((xx - yy) * q.s); m23 = F(q.t.z); } //CONSTRUCTOR for identical float-types. It converts a QuatTNS into a Matrix34. //Needs to be 'explicit' because we loose float-precision in the conversion process //Matrix34(QuatT); explicit ILINE Matrix34_tpl(const QuatTNS_tpl &q) { assert(q.q.IsValid()); Vec3_tpl v2 = q.q.v + q.q.v; F xx = 1 - v2.x * q.q.v.x; F yy = v2.y * q.q.v.y; F xw = v2.x * q.q.w; F xy = v2.y * q.q.v.x; F yz = v2.z * q.q.v.y; F yw = v2.y * q.q.w; F xz = v2.z * q.q.v.x; F zz = v2.z * q.q.v.z; F zw = v2.z * q.q.w; m00 = (1 - yy - zz) * q.s.x; m01 = (xy - zw) * q.s.y; m02 = (xz + yw) * q.s.z; m03 = q.t.x; m10 = (xy + zw) * q.s.x; m11 = (xx - zz) * q.s.y; m12 = (yz - xw) * q.s.z; m13 = q.t.y; m20 = (xz - yw) * q.s.x; m21 = (yz + xw) * q.s.y; m22 = (xx - yy) * q.s.z; m23 = q.t.z; } //CONSTRUCTOR for different float-types. It converts a QuatTNS into a Matrix34. //Needs to be 'explicit' because we loose float-precision in the conversion process //Matrix34(QuatT); template ILINE explicit Matrix34_tpl(const QuatTNS_tpl &q) { assert(q.q.IsValid()); Vec3_tpl v2 = q.q.v + q.q.v; F1 xx = 1 - v2.x * q.q.v.x; F1 yy = v2.y * q.q.v.y; F1 xw = v2.x * q.q.w; F1 xy = v2.y * q.q.v.x; F1 yz = v2.z * q.q.v.y; F1 yw = v2.y * q.q.w; F1 xz = v2.z * q.q.v.x; F1 zz = v2.z * q.q.v.z; F1 zw = v2.z * q.q.w; m00 = F((1 - yy - zz) * q.s.x); m01 = F((xy - zw) * q.s.y); m02 = F((xz + yw) * q.s.z); m03 = F(q.t.x); m10 = F((xy + zw) * q.s.x); m11 = F((xx - zz) * q.s.y); m12 = F((yz - xw) * q.s.z); m13 = F(q.t.y); m20 = F((xz - yw) * q.s.x); m21 = F((yz + xw) * q.s.y); m22 = F((xx - yy) * q.s.z); m23 = F(q.t.z); } //CONSTRUCTOR for identical float-types. It converts a DualQuat into a Matrix34. //Needs to be 'explicit' because we loose float-precision in the conversion process //Matrix34(QuatT); ILINE explicit Matrix34_tpl(const DualQuat_tpl &q) { assert((fabs_tpl(1 - (q.nq | q.nq))) < 0.01); //check if unit-quaternion Vec3_tpl t = (q.nq.w * q.dq.v - q.dq.w * q.nq.v + q.nq.v % q.dq.v); //perfect for HLSL Vec3_tpl v2 = q.nq.v + q.nq.v; F xx = 1 - v2.x * q.nq.v.x; F yy = v2.y * q.nq.v.y; F xw = v2.x * q.nq.w; F xy = v2.y * q.nq.v.x; F yz = v2.z * q.nq.v.y; F yw = v2.y * q.nq.w; F xz = v2.z * q.nq.v.x; F zz = v2.z * q.nq.v.z; F zw = v2.z * q.nq.w; m00 = 1 - yy - zz; m01 = xy - zw; m02 = xz + yw; m03 = t.x + t.x; m10 = xy + zw; m11 = xx - zz; m12 = yz - xw; m13 = t.y + t.y; m20 = xz - yw; m21 = yz + xw; m22 = xx - yy; m23 = t.z + t.z; } //CONSTRUCTOR for different float-types. It converts a DualQuat into a Matrix34. //Needs to be 'explicit' because we loose float-precision in the conversion process //Matrix34(QuatT); template ILINE explicit Matrix34_tpl(const DualQuat_tpl &q) { assert((fabs_tpl(1 - (q.nq | q.nq))) < 0.01); //check if unit-quaternion Vec3_tpl t = (q.nq.w * q.dq.v - q.dq.w * q.nq.v + q.nq.v % q.dq.v); //perfect for HLSL Vec3_tpl v2 = q.nq.v + q.nq.v; F1 xx = 1 - v2.x * q.nq.v.x; F1 yy = v2.y * q.nq.v.y; F1 xw = v2.x * q.nq.w; F1 xy = v2.y * q.nq.v.x; F1 yz = v2.z * q.nq.v.y; F1 yw = v2.y * q.nq.w; F1 xz = v2.z * q.nq.v.x; F1 zz = v2.z * q.nq.v.z; F1 zw = v2.z * q.nq.w; m00 = F(1 - yy - zz); m01 = F(xy - zw); m02 = F(xz + yw); m03 = F(t.x + t.x); m10 = F(xy + zw); m11 = F(xx - zz); m12 = F(yz - xw); m13 = F(t.y + t.y); m20 = F(xz - yw); m21 = F(yz + xw); m22 = F(xx - yy); m23 = F(t.z + t.z); } //apply scaling to the columns of the matrix. ILINE void ScaleColumn(const Vec3_tpl& s) { m00 *= s.x; m01 *= s.y; m02 *= s.z; m10 *= s.x; m11 *= s.y; m12 *= s.z; m20 *= s.x; m21 *= s.y; m22 *= s.z; } /*! * * Initializes the Matrix34 with the identity. * */ void SetIdentity(void) { m00 = 1.0f; m01 = 0.0f; m02 = 0.0f; m03 = 0.0f; m10 = 0.0f; m11 = 1.0f; m12 = 0.0f; m13 = 0.0f; m20 = 0.0f; m21 = 0.0f; m22 = 1.0f; m23 = 0.0f; } ILINE static Matrix34_tpl CreateIdentity(void) { Matrix34_tpl m; m.SetIdentity(); return m; } ILINE bool IsIdentity() const { return 0 == (fabs_tpl((F)1 - m00) + fabs_tpl(m01) + fabs_tpl(m02) + fabs_tpl(m03) + fabs_tpl(m10) + fabs_tpl((F)1 - m11) + fabs_tpl(m12) + fabs_tpl(m13) + fabs_tpl(m20) + fabs_tpl(m21) + fabs_tpl((F)1 - m22)) + fabs_tpl(m23); } ILINE int IsZero() const { return 0 == (fabs_tpl(m00) + fabs_tpl(m01) + fabs_tpl(m02) + fabs_tpl(m03) + fabs_tpl(m10) + fabs_tpl(m11) + fabs_tpl(m12) + fabs_tpl(m13) + fabs_tpl(m20) + fabs_tpl(m21) + fabs_tpl(m22)) + fabs_tpl(m23); } /*! * Create a rotation matrix around an arbitrary axis (Eulers Theorem). * The axis is specified as an normalized Vec3. The angle is assumed to be in radians. * This function also assumes a translation-vector and stores it in the right column. * * Example: * Matrix34 m34; * Vec3 axis=GetNormalized( Vec3(-1.0f,-0.3f,0.0f) ); * m34.SetRotationAA( 3.14314f, axis, Vec3(5,5,5) ); */ ILINE void SetRotationAA(const F rad, const Vec3_tpl& axis, const Vec3_tpl& t = Vec3(ZERO)) { *this = Matrix33_tpl::CreateRotationAA(rad, axis); this->SetTranslation(t); } ILINE static Matrix34_tpl CreateRotationAA(const F rad, const Vec3_tpl& axis, const Vec3_tpl& t = Vec3(ZERO)) { Matrix34_tpl m34; m34.SetRotationAA(rad, axis, t); return m34; } ILINE void SetRotationAA(const Vec3_tpl& rot, const Vec3_tpl& t = Vec3(ZERO)) { *this = Matrix33_tpl::CreateRotationAA(rot); this->SetTranslation(t); } ILINE static Matrix34_tpl CreateRotationAA(const Vec3_tpl& rot, const Vec3_tpl& t = Vec3(ZERO)) { Matrix34_tpl m34; m34.SetRotationAA(rot, t); return m34; } /*! * Create rotation-matrix about X axis using an angle. * The angle is assumed to be in radians. * The translation-vector is set to zero. * * Example: * Matrix34 m34; * m34.SetRotationX(0.5f); */ ILINE void SetRotationX(const f32 rad, const Vec3_tpl& t = Vec3(ZERO)) { *this = Matrix33_tpl::CreateRotationX(rad); this->SetTranslation(t); } ILINE static Matrix34_tpl CreateRotationX(const f32 rad, const Vec3_tpl& t = Vec3(ZERO)) { Matrix34_tpl m34; m34.SetRotationX(rad, t); return m34; } /*! * Create rotation-matrix about Y axis using an angle. * The angle is assumed to be in radians. * The translation-vector is set to zero. * * Example: * Matrix34 m34; * m34.SetRotationY(0.5f); */ ILINE void SetRotationY(const f32 rad, const Vec3_tpl& t = Vec3(ZERO)) { *this = Matrix33_tpl::CreateRotationY(rad); this->SetTranslation(t); } ILINE static Matrix34_tpl CreateRotationY(const f32 rad, const Vec3_tpl& t = Vec3(ZERO)) { Matrix34_tpl m34; m34.SetRotationY(rad, t); return m34; } /*! * Create rotation-matrix about Z axis using an angle. * The angle is assumed to be in radians. * The translation-vector is set to zero. * * Example: * Matrix34 m34; * m34.SetRotationZ(0.5f); */ ILINE void SetRotationZ(const f32 rad, const Vec3_tpl& t = Vec3(ZERO)) { *this = Matrix33_tpl::CreateRotationZ(rad); this->SetTranslation(t); } ILINE static Matrix34_tpl CreateRotationZ(const f32 rad, const Vec3_tpl& t = Vec3(ZERO)) { Matrix34_tpl m34; m34.SetRotationZ(rad, t); return m34; } /*! * * Convert three Euler angle to mat33 (rotation order:XYZ) * The Euler angles are assumed to be in radians. * The translation-vector is set to zero. * * Example 1: * Matrix34 m34; * m34.SetRotationXYZ( Ang3(0.5f,0.2f,0.9f), translation ); * * Example 2: * Matrix34 m34=Matrix34::CreateRotationXYZ( Ang3(0.5f,0.2f,0.9f), translation ); */ ILINE void SetRotationXYZ(const Ang3_tpl& rad, const Vec3_tpl& t = Vec3(ZERO)) { assert(rad.IsValid()); assert(t.IsValid()); *this = Matrix33_tpl::CreateRotationXYZ(rad); this->SetTranslation(t); } ILINE static Matrix34_tpl CreateRotationXYZ(const Ang3_tpl& rad, const Vec3_tpl& t = Vec3(ZERO)) { assert(rad.IsValid()); assert(t.IsValid()); Matrix34_tpl m34; m34.SetRotationXYZ(rad, t); return m34; } ILINE void SetRotationAA(F c, F s, Vec3_tpl axis, const Vec3_tpl& t = Vec3(ZERO)) { assert(axis.IsValid()); assert(t.IsValid()); *this = Matrix33_tpl::CreateRotationAA(c, s, axis); m03 = t.x; m13 = t.y; m23 = t.z; } ILINE static Matrix34_tpl CreateRotationAA(F c, F s, Vec3_tpl axis, const Vec3_tpl& t = Vec3(ZERO)) { Matrix34_tpl m34; m34.SetRotationAA(c, s, axis, t); return m34; } ILINE void SetTranslationMat(const Vec3_tpl& v) { m00 = 1.0f; m01 = 0.0f; m02 = 0.0f; m03 = v.x; m10 = 0.0f; m11 = 1.0f; m12 = 0.0f; m13 = v.y; m20 = 0.0f; m21 = 0.0f; m22 = 1.0f; m23 = v.z; } ILINE static Matrix34_tpl CreateTranslationMat(const Vec3_tpl& v) { Matrix34_tpl m34; m34.SetTranslationMat(v); return m34; } //NOTE: all vectors are stored in columns ILINE void SetFromVectors(const Vec3& vx, const Vec3& vy, const Vec3& vz, const Vec3& pos) { m00 = vx.x; m01 = vy.x; m02 = vz.x; m03 = pos.x; m10 = vx.y; m11 = vy.y; m12 = vz.y; m13 = pos.y; m20 = vx.z; m21 = vy.z; m22 = vz.z; m23 = pos.z; } ILINE static Matrix34_tpl CreateFromVectors(const Vec3_tpl& vx, const Vec3_tpl& vy, const Vec3_tpl& vz, const Vec3_tpl& pos) { Matrix34_tpl m; m.SetFromVectors(vx, vy, vz, pos); return m; } void InvertFast() { // in-place transposition assert(IsOrthonormal()); F t; Vec3 v(m03, m13, m23); t = m01; m01 = m10; m10 = t; m03 = -v.x * m00 - v.y * m01 - v.z * m20; t = m02; m02 = m20; m20 = t; m13 = -v.x * m10 - v.y * m11 - v.z * m21; t = m12; m12 = m21; m21 = t; m23 = -v.x * m20 - v.y * m21 - v.z * m22; } Matrix34_tpl GetInvertedFast() const { assert(IsOrthonormal()); Matrix34_tpl dst; dst.m00 = m00; dst.m01 = m10; dst.m02 = m20; dst.m03 = -m03 * m00 - m13 * m10 - m23 * m20; dst.m10 = m01; dst.m11 = m11; dst.m12 = m21; dst.m13 = -m03 * m01 - m13 * m11 - m23 * m21; dst.m20 = m02; dst.m21 = m12; dst.m22 = m22; dst.m23 = -m03 * m02 - m13 * m12 - m23 * m22; return dst; } //! transforms a vector. the translation is not beeing considered ILINE Vec3_tpl TransformVector(const Vec3_tpl& v) const { assert(v.IsValid()); return Vec3_tpl(m00 * v.x + m01 * v.y + m02 * v.z, m10 * v.x + m11 * v.y + m12 * v.z, m20 * v.x + m21 * v.y + m22 * v.z); } //! transforms a point and add translation vector ILINE Vec3_tpl TransformPoint(const Vec3_tpl& p) const { assert(p.IsValid()); return Vec3_tpl(m00 * p.x + m01 * p.y + m02 * p.z + m03, m10 * p.x + m11 * p.y + m12 * p.z + m13, m20 * p.x + m21 * p.y + m22 * p.z + m23); } //! Remove scale from matrix. void OrthonormalizeFast() { Vec3_tpl x(m00, m10, m20); Vec3_tpl y(m01, m11, m21); Vec3_tpl z; x = x.GetNormalized(); z = (x % y).GetNormalized(); y = (z % x).GetNormalized(); m00 = x.x; m10 = x.y; m20 = x.z; m01 = y.x; m11 = y.y; m21 = y.z; m02 = z.x; m12 = z.y; m22 = z.z; } //determinant is ambiguous: only the upper-left-submatrix's determinant is calculated ILINE f32 Determinant() const { return (m00 * m11 * m22) + (m01 * m12 * m20) + (m02 * m10 * m21) - (m02 * m11 * m20) - (m00 * m12 * m21) - (m01 * m10 * m22); } //-------------------------------------------------------------------------------- //---- helper functions to access matrix-members ------------ //-------------------------------------------------------------------------------- F* GetData() { return &m00; } const F* GetData() const { return &m00; } ILINE F operator () (uint32 i, uint32 j) const { assert ((i < 3) && (j < 4)); F* p_data = (F*)(&m00); return p_data[i * 4 + j]; } ILINE F& operator () (uint32 i, uint32 j) { assert ((i < 3) && (j < 4)); F* p_data = (F*)(&m00); return p_data[i * 4 + j]; } ILINE void SetRow(int i, const Vec3_tpl& v) { assert(i < 3); F* p = (F*)(&m00); p[0 + 4 * i] = v.x; p[1 + 4 * i] = v.y; p[2 + 4 * i] = v.z; } ILINE const Vec3_tpl& GetRow(int i) const { assert(i < 3); return *(const Vec3_tpl*)(&m00 + 4 * i); } ILINE const Vec4_tpl& GetRow4(int i) const { assert(i < 3); return *(const Vec4_tpl*)(&m00 + 4 * i); } ILINE void SetColumn(int i, const Vec3_tpl& v) { assert(i < 4); F* p = (F*)(&m00); p[i + 4 * 0] = v.x; p[i + 4 * 1] = v.y; p[i + 4 * 2] = v.z; } ILINE Vec3_tpl GetColumn(int i) const { assert(i < 4); F* p = (F*)(&m00); return Vec3(p[i + 4 * 0], p[i + 4 * 1], p[i + 4 * 2]); } ILINE Vec3_tpl GetColumn0() const { return Vec3_tpl(m00, m10, m20); } ILINE Vec3_tpl GetColumn1() const { return Vec3_tpl(m01, m11, m21); } ILINE Vec3_tpl GetColumn2() const { return Vec3_tpl(m02, m12, m22); } ILINE Vec3_tpl GetColumn3() const { return Vec3_tpl(m03, m13, m23); } ILINE void SetTranslation(const Vec3_tpl& t) { m03 = t.x; m13 = t.y; m23 = t.z; } ILINE Vec3_tpl GetTranslation() const { return Vec3_tpl(m03, m13, m23); } ILINE void ScaleTranslation (F s) { m03 *= s; m13 *= s; m23 *= s; } ILINE Matrix34_tpl AddTranslation(const Vec3_tpl& t) { m03 += t.x; m13 += t.y; m23 += t.z; return *this; } ILINE void SetRotation33(const Matrix33_tpl& m33) { m00 = m33.m00; m01 = m33.m01; m02 = m33.m02; m10 = m33.m10; m11 = m33.m11; m12 = m33.m12; m20 = m33.m20; m21 = m33.m21; m22 = m33.m22; } ILINE void GetRotation33(Matrix33_tpl& m33) const { m33.m00 = m00; m33.m01 = m01; m33.m02 = m02; m33.m10 = m10; m33.m11 = m11; m33.m12 = m12; m33.m20 = m20; m33.m21 = m21; m33.m22 = m22; } //check if we have an orthonormal-base (general case, works even with reflection matrices) int IsOrthonormal(F threshold = 0.001) const { f32 d0 = fabs_tpl(GetColumn0() | GetColumn1()); if (d0 > threshold) { return 0; } f32 d1 = fabs_tpl(GetColumn0() | GetColumn2()); if (d1 > threshold) { return 0; } f32 d2 = fabs_tpl(GetColumn1() | GetColumn2()); if (d2 > threshold) { return 0; } int a = (fabs_tpl(1 - (GetColumn0() | GetColumn0()))) < threshold; int b = (fabs_tpl(1 - (GetColumn1() | GetColumn1()))) < threshold; int c = (fabs_tpl(1 - (GetColumn2() | GetColumn2()))) < threshold; return a & b & c; } //check if we have an orthonormal-base (assuming we are using a right-handed coordinate system) int IsOrthonormalRH(F threshold = 0.001) const { int a = Vec3_tpl::IsEquivalent(GetColumn0(), GetColumn1() % GetColumn2(), threshold); int b = Vec3_tpl::IsEquivalent(GetColumn1(), GetColumn2() % GetColumn0(), threshold); int c = Vec3_tpl::IsEquivalent(GetColumn2(), GetColumn0() % GetColumn1(), threshold); return a & b & c; } bool static IsEquivalent(const Matrix34_tpl& m0, const Matrix34_tpl& m1, F e = VEC_EPSILON) { return ( (fabs_tpl(m0.m00 - m1.m00) <= e) && (fabs_tpl(m0.m01 - m1.m01) <= e) && (fabs_tpl(m0.m02 - m1.m02) <= e) && (fabs_tpl(m0.m03 - m1.m03) <= e) && (fabs_tpl(m0.m10 - m1.m10) <= e) && (fabs_tpl(m0.m11 - m1.m11) <= e) && (fabs_tpl(m0.m12 - m1.m12) <= e) && (fabs_tpl(m0.m13 - m1.m13) <= e) && (fabs_tpl(m0.m20 - m1.m20) <= e) && (fabs_tpl(m0.m21 - m1.m21) <= e) && (fabs_tpl(m0.m22 - m1.m22) <= e) && (fabs_tpl(m0.m23 - m1.m23) <= e) ); } bool IsValid() const { if (!NumberValid(m00)) { return false; } if (!NumberValid(m01)) { return false; } if (!NumberValid(m02)) { return false; } if (!NumberValid(m03)) { return false; } if (!NumberValid(m10)) { return false; } if (!NumberValid(m11)) { return false; } if (!NumberValid(m12)) { return false; } if (!NumberValid(m13)) { return false; } if (!NumberValid(m20)) { return false; } if (!NumberValid(m21)) { return false; } if (!NumberValid(m22)) { return false; } if (!NumberValid(m23)) { return false; } return true; } bool IsDegenerate(float epsilon = FLT_EPSILON) const { //check the basis vectors for 0 vector return GetColumn0().len2() < epsilon || GetColumn1().len2() < epsilon || GetColumn2().len2() < epsilon; } /*! * Create a matrix with SCALING, ROTATION and TRANSLATION (in this order). * * Example 1: * Matrix m34; * m34.SetMatrix( Vec3(1,2,3), quat, Vec3(11,22,33) ); */ ILINE void Set(const Vec3_tpl& s, const Quat_tpl& q, const Vec3_tpl& t = Vec3(ZERO)) { assert(s.IsValid()); assert(q.IsUnit(0.1f)); assert(t.IsValid()); F vxvx = q.v.x * q.v.x; F vzvz = q.v.z * q.v.z; F vyvy = q.v.y * q.v.y; F vxvy = q.v.x * q.v.y; F vxvz = q.v.x * q.v.z; F vyvz = q.v.y * q.v.z; F svx = q.w * q.v.x; F svy = q.w * q.v.y; F svz = q.w * q.v.z; m00 = (1 - (vyvy + vzvz) * 2) * s.x; m01 = (vxvy - svz) * 2 * s.y; m02 = (vxvz + svy) * 2 * s.z; m03 = t.x; m10 = (vxvy + svz) * 2 * s.x; m11 = (1 - (vxvx + vzvz) * 2) * s.y; m12 = (vyvz - svx) * 2 * s.z; m13 = t.y; m20 = (vxvz - svy) * 2 * s.x; m21 = (vyvz + svx) * 2 * s.y; m22 = (1 - (vxvx + vyvy) * 2) * s.z; m23 = t.z; } ILINE static Matrix34_tpl Create(const Vec3_tpl& s, const Quat_tpl& q, const Vec3_tpl& t = Vec3(ZERO)) { Matrix34_tpl m34; m34.Set(s, q, t); return m34; } Matrix34_tpl(const Vec3_tpl& s, const Quat_tpl& q, const Vec3_tpl& t = Vec3(ZERO)) { Set(s, q, t); } /*! * Create scaling-matrix. * The translation-vector is set to zero. * * Example 1: * Matrix m34; * m34.SetScale( Vec3(0.5f, 1.0f, 2.0f) ); * Example 2: * Matrix34 m34 = Matrix34::CreateScale( Vec3(0.5f, 1.0f, 2.0f) ); */ ILINE void SetScale(const Vec3_tpl& s, const Vec3_tpl& t = Vec3(ZERO)) { *this = Matrix33::CreateScale(s); this->SetTranslation(t); } ILINE static Matrix34_tpl CreateScale(const Vec3_tpl& s, const Vec3_tpl& t = Vec3(ZERO)) { Matrix34_tpl m34; m34.SetScale(s, t); return m34; } ILINE Matrix44_tpl GetTransposed() const { Matrix44_tpl tmp; tmp.m00 = m00; tmp.m01 = m10; tmp.m02 = m20; tmp.m03 = 0; tmp.m10 = m01; tmp.m11 = m11; tmp.m12 = m21; tmp.m13 = 0; tmp.m20 = m02; tmp.m21 = m12; tmp.m22 = m22; tmp.m23 = 0; tmp.m30 = m03; tmp.m31 = m13; tmp.m32 = m23; tmp.m33 = 1; return tmp; } /*! * calculate a real inversion of a Matrix34 * an inverse-matrix is an UnDo-matrix for all kind of transformations * * Example 1: * Matrix34 im34; im34.Invert(); * * Example 2: * Matrix34 im34 = m34.GetInverted(); */ void Invert(void) { //rescue members Matrix34_tpl m = *this; // calculate 12 cofactors m00 = m.m22 * m.m11 - m.m12 * m.m21; m10 = m.m12 * m.m20 - m.m22 * m.m10; m20 = m.m10 * m.m21 - m.m20 * m.m11; m01 = m.m02 * m.m21 - m.m22 * m.m01; m11 = m.m22 * m.m00 - m.m02 * m.m20; m21 = m.m20 * m.m01 - m.m00 * m.m21; m02 = m.m12 * m.m01 - m.m02 * m.m11; m12 = m.m02 * m.m10 - m.m12 * m.m00; m22 = m.m00 * m.m11 - m.m10 * m.m01; m03 = (m.m22 * m.m13 * m.m01 + m.m02 * m.m23 * m.m11 + m.m12 * m.m03 * m.m21) - (m.m12 * m.m23 * m.m01 + m.m22 * m.m03 * m.m11 + m.m02 * m.m13 * m.m21); m13 = (m.m12 * m.m23 * m.m00 + m.m22 * m.m03 * m.m10 + m.m02 * m.m13 * m.m20) - (m.m22 * m.m13 * m.m00 + m.m02 * m.m23 * m.m10 + m.m12 * m.m03 * m.m20); m23 = (m.m20 * m.m11 * m.m03 + m.m00 * m.m21 * m.m13 + m.m10 * m.m01 * m.m23) - (m.m10 * m.m21 * m.m03 + m.m20 * m.m01 * m.m13 + m.m00 * m.m11 * m.m23); // calculate determinant F det = m.m00 * m00 + m.m10 * m01 + m.m20 * m02; assert(fabs_tpl(det) > (F)0.00000001); F rcpDet = 1.0f / det; // calculate matrix inverse/ m00 *= rcpDet; m01 *= rcpDet; m02 *= rcpDet; m03 *= rcpDet; m10 *= rcpDet; m11 *= rcpDet; m12 *= rcpDet; m13 *= rcpDet; m20 *= rcpDet; m21 *= rcpDet; m22 *= rcpDet; m23 *= rcpDet; } ILINE Matrix34_tpl GetInverted() const { Matrix34_tpl dst = *this; dst.Invert(); return dst; } /*! * Name: ReflectMat34 * Description: reflect a rotation matrix with respect to a plane. * * Example: * Vec3 normal( 0.0f,-1.0f, 0.0f); * Vec3 pos(0,1000,0); * Matrix34 m34=CreateReflectionMat( pos, normal ); */ ILINE static Matrix34_tpl CreateReflectionMat (const Vec3_tpl& p, const Vec3_tpl& n) { Matrix34_tpl m; F vxy = -2.0f * n.x * n.y; F vxz = -2.0f * n.x * n.z; F vyz = -2.0f * n.y * n.z; F pdotn = 2.0f * (p | n); m.m00 = 1.0f - 2.0f * n.x * n.x; m.m01 = vxy; m.m02 = vxz; m.m03 = pdotn * n.x; m.m10 = vxy; m.m11 = 1.0f - 2.0f * n.y * n.y; m.m12 = vyz; m.m13 = pdotn * n.y; m.m20 = vxz; m.m21 = vyz; m.m22 = 1.0f - 2.0f * n.z * n.z; m.m23 = pdotn * n.z; return m; } AUTO_STRUCT_INFO }; /////////////////////////////////////////////////////////////////////////////// // Typedefs // /////////////////////////////////////////////////////////////////////////////// typedef Matrix34_tpl Matrix34; //always 32 bit typedef Matrix34_tpl Matrix34d;//always 64 bit typedef Matrix34_tpl Matrix34r;//variable float precision. depending on the target system it can be between 32, 64 or bit typedef _MS_ALIGN(16) Matrix34_tpl _ALIGN (16) Matrix34A; //---------------------------------------------------------------------------------- //---------------------------------------------------------------------------------- //---------------------------------------------------------------------------------- //------------- implementation of Matrix34 ------------------------------ //---------------------------------------------------------------------------------- //---------------------------------------------------------------------------------- //---------------------------------------------------------------------------------- //! multiply all matrix's values by f and return the matrix template ILINE Matrix34_tpl operator * (const Matrix34_tpl& m, const f32 f) { assert(m.IsValid()); Matrix34_tpl r; r.m00 = m.m00 * f; r.m01 = m.m01 * f; r.m02 = m.m02 * f; r.m03 = m.m03 * f; r.m10 = m.m10 * f; r.m11 = m.m11 * f; r.m12 = m.m12 * f; r.m13 = m.m13 * f; r.m20 = m.m20 * f; r.m21 = m.m21 * f; r.m22 = m.m22 * f; r.m23 = m.m23 * f; return r; } /*! * multiplication of Matrix34 by a (column) Vec3. * This function transforms the given input Vec3 * into the coordinate system defined by this matrix. * * Example: * Matrix34 m34; * Vec3 vector(44,55,66); * Vec3 result = m34*vector; */ template ILINE Vec3_tpl operator * (const Matrix34_tpl& m, const Vec3_tpl& p) { assert(m.IsValid()); assert(p.IsValid()); Vec3_tpl tp; tp.x = m.m00 * p.x + m.m01 * p.y + m.m02 * p.z + m.m03; tp.y = m.m10 * p.x + m.m11 * p.y + m.m12 * p.z + m.m13; tp.z = m.m20 * p.x + m.m21 * p.y + m.m22 * p.z + m.m23; return tp; } template ILINE Matrix34_tpl operator*(const Matrix34_tpl& l, const Diag33_tpl& r) { assert(l.IsValid()); assert(r.IsValid()); Matrix34_tpl m; m.m00 = l.m00 * r.x; m.m01 = l.m01 * r.y; m.m02 = l.m02 * r.z; m.m03 = l.m03; m.m10 = l.m10 * r.x; m.m11 = l.m11 * r.y; m.m12 = l.m12 * r.z; m.m13 = l.m13; m.m20 = l.m20 * r.x; m.m21 = l.m21 * r.y; m.m22 = l.m22 * r.z; m.m23 = l.m23; return m; } template ILINE Matrix34_tpl& operator *= (Matrix34_tpl& l, const Diag33_tpl& r) { assert(l.IsValid()); assert(r.IsValid()); l.m00 *= r.x; l.m01 *= r.y; l.m02 *= r.z; l.m10 *= r.x; l.m11 *= r.y; l.m12 *= r.z; l.m20 *= r.x; l.m21 *= r.y; l.m22 *= r.z; return l; } template ILINE Matrix34_tpl operator + (const Matrix34_tpl& l, const Matrix34_tpl& r) { assert(l.IsValid()); assert(r.IsValid()); Matrix34_tpl m; m.m00 = l.m00 + r.m00; m.m01 = l.m01 + r.m01; m.m02 = l.m02 + r.m02; m.m03 = l.m03 + r.m03; m.m10 = l.m10 + r.m10; m.m11 = l.m11 + r.m11; m.m12 = l.m12 + r.m12; m.m13 = l.m13 + r.m13; m.m20 = l.m20 + r.m20; m.m21 = l.m21 + r.m21; m.m22 = l.m22 + r.m22; m.m23 = l.m23 + r.m23; return m; } template ILINE Matrix34_tpl& operator += (Matrix34_tpl& l, const Matrix34_tpl& r) { assert(l.IsValid()); assert(r.IsValid()); l.m00 += r.m00; l.m01 += r.m01; l.m02 += r.m02; l.m03 += r.m03; l.m10 += r.m10; l.m11 += r.m11; l.m12 += r.m12; l.m13 += r.m13; l.m20 += r.m20; l.m21 += r.m21; l.m22 += r.m22; l.m23 += r.m23; return l; } /*! * Implements the multiplication operator: Matrix34=Matrix34*Matrix33 * * Matrix33 and Matrix44 are specified in collumn order for a right-handed coordinate-system. * AxB = operation B followed by operation A. * A multiplication takes 27 muls and 24 adds. * * Example: * Matrix34 m34=Matrix33::CreateRotationX(1.94192f);; * Matrix33 m33=Matrix34::CreateRotationZ(3.14192f); * Matrix34 result=m34*m33; */ template ILINE Matrix34_tpl operator * (const Matrix34_tpl& l, const Matrix33_tpl& r) { assert(l.IsValid()); assert(r.IsValid()); Matrix34_tpl m; m.m00 = l.m00 * r.m00 + l.m01 * r.m10 + l.m02 * r.m20; m.m10 = l.m10 * r.m00 + l.m11 * r.m10 + l.m12 * r.m20; m.m20 = l.m20 * r.m00 + l.m21 * r.m10 + l.m22 * r.m20; m.m01 = l.m00 * r.m01 + l.m01 * r.m11 + l.m02 * r.m21; m.m11 = l.m10 * r.m01 + l.m11 * r.m11 + l.m12 * r.m21; m.m21 = l.m20 * r.m01 + l.m21 * r.m11 + l.m22 * r.m21; m.m02 = l.m00 * r.m02 + l.m01 * r.m12 + l.m02 * r.m22; m.m12 = l.m10 * r.m02 + l.m11 * r.m12 + l.m12 * r.m22; m.m22 = l.m20 * r.m02 + l.m21 * r.m12 + l.m22 * r.m22; m.m03 = l.m03; m.m13 = l.m13; m.m23 = l.m23; return m; } /*! * Implements the multiplication operator: Matrix34=Matrix34*Matrix34 * * Matrix34 is specified in collumn order. * AxB = rotation B followed by rotation A. * This operation takes 36 mults and 27 adds. * * Example: * Matrix34 m34=Matrix34::CreateRotationX(1.94192f, Vec3(11,22,33));; * Matrix34 m34=Matrix33::CreateRotationZ(3.14192f); * Matrix34 result=m34*m34; */ template ILINE Matrix34_tpl operator * (const Matrix34_tpl& l, const Matrix34_tpl& r) { assert(l.IsValid()); assert(r.IsValid()); Matrix34_tpl m; m.m00 = l.m00 * r.m00 + l.m01 * r.m10 + l.m02 * r.m20; m.m10 = l.m10 * r.m00 + l.m11 * r.m10 + l.m12 * r.m20; m.m20 = l.m20 * r.m00 + l.m21 * r.m10 + l.m22 * r.m20; m.m01 = l.m00 * r.m01 + l.m01 * r.m11 + l.m02 * r.m21; m.m11 = l.m10 * r.m01 + l.m11 * r.m11 + l.m12 * r.m21; m.m21 = l.m20 * r.m01 + l.m21 * r.m11 + l.m22 * r.m21; m.m02 = l.m00 * r.m02 + l.m01 * r.m12 + l.m02 * r.m22; m.m12 = l.m10 * r.m02 + l.m11 * r.m12 + l.m12 * r.m22; m.m22 = l.m20 * r.m02 + l.m21 * r.m12 + l.m22 * r.m22; m.m03 = l.m00 * r.m03 + l.m01 * r.m13 + l.m02 * r.m23 + l.m03; m.m13 = l.m10 * r.m03 + l.m11 * r.m13 + l.m12 * r.m23 + l.m13; m.m23 = l.m20 * r.m03 + l.m21 * r.m13 + l.m22 * r.m23 + l.m23; return m; } /*! * Implements the multiplication operator: Matrix44=Matrix34*Matrix44 * * Matrix44 and Matrix34 are specified in collumn order. * AxB = rotation B followed by rotation A. * This operation takes 48 mults and 36 adds. * * Example: * Matrix34 m34=Matrix33::CreateRotationX(1.94192f);; * Matrix44 m44=Matrix33::CreateRotationZ(3.14192f); * Matrix44 result=m34*m44; */ template ILINE Matrix44_tpl operator * (const Matrix34_tpl& l, const Matrix44_tpl& r) { assert(l.IsValid()); assert(r.IsValid()); Matrix44_tpl m; m.m00 = l.m00 * r.m00 + l.m01 * r.m10 + l.m02 * r.m20 + l.m03 * r.m30; m.m10 = l.m10 * r.m00 + l.m11 * r.m10 + l.m12 * r.m20 + l.m13 * r.m30; m.m20 = l.m20 * r.m00 + l.m21 * r.m10 + l.m22 * r.m20 + l.m23 * r.m30; m.m30 = r.m30; m.m01 = l.m00 * r.m01 + l.m01 * r.m11 + l.m02 * r.m21 + l.m03 * r.m31; m.m11 = l.m10 * r.m01 + l.m11 * r.m11 + l.m12 * r.m21 + l.m13 * r.m31; m.m21 = l.m20 * r.m01 + l.m21 * r.m11 + l.m22 * r.m21 + l.m23 * r.m31; m.m31 = r.m31; m.m02 = l.m00 * r.m02 + l.m01 * r.m12 + l.m02 * r.m22 + l.m03 * r.m32; m.m12 = l.m10 * r.m02 + l.m11 * r.m12 + l.m12 * r.m22 + l.m13 * r.m32; m.m22 = l.m20 * r.m02 + l.m21 * r.m12 + l.m22 * r.m22 + l.m23 * r.m32; m.m32 = r.m32; m.m03 = l.m00 * r.m03 + l.m01 * r.m13 + l.m02 * r.m23 + l.m03 * r.m33; m.m13 = l.m10 * r.m03 + l.m11 * r.m13 + l.m12 * r.m23 + l.m13 * r.m33; m.m23 = l.m20 * r.m03 + l.m21 * r.m13 + l.m22 * r.m23 + l.m23 * r.m33; m.m33 = r.m33; return m; } #endif // CRYINCLUDE_CRYCOMMON_CRY_MATRIX34_H