]> git.cworth.org Git - apitrace/blobdiff - thirdparty/directxtex/XNAMath/xnamathmatrix.inl
thirdparty/directxtex: Import DirectXTex library.
[apitrace] / thirdparty / directxtex / XNAMath / xnamathmatrix.inl
diff --git a/thirdparty/directxtex/XNAMath/xnamathmatrix.inl b/thirdparty/directxtex/XNAMath/xnamathmatrix.inl
new file mode 100644 (file)
index 0000000..eb9f164
--- /dev/null
@@ -0,0 +1,3293 @@
+/************************************************************************
+*                                                                       *
+* xnamathmatrix.inl -- SIMD C++ Math library for Windows and Xbox 360   *
+*                      Matrix functions                                 *
+*                                                                       *
+* Copyright (c) Microsoft Corp. All rights reserved.                    *
+*                                                                       *
+************************************************************************/
+
+#if defined(_MSC_VER) && (_MSC_VER > 1000)
+#pragma once
+#endif
+
+#ifndef __XNAMATHMATRIX_INL__
+#define __XNAMATHMATRIX_INL__
+
+/****************************************************************************
+ *
+ * Matrix
+ *
+ ****************************************************************************/
+
+//------------------------------------------------------------------------------
+// Comparison operations
+//------------------------------------------------------------------------------
+
+//------------------------------------------------------------------------------
+
+// Return TRUE if any entry in the matrix is NaN
+XMFINLINE BOOL XMMatrixIsNaN
+(
+    CXMMATRIX M
+)
+{
+#if defined(_XM_NO_INTRINSICS_)
+    UINT i, uTest;
+    const UINT *pWork;
+
+    i = 16;
+    pWork = (const UINT *)(&M.m[0][0]);
+    do {
+        // Fetch value into integer unit
+        uTest = pWork[0];
+        // Remove sign
+        uTest &= 0x7FFFFFFFU;
+        // NaN is 0x7F800001 through 0x7FFFFFFF inclusive
+        uTest -= 0x7F800001U;
+        if (uTest<0x007FFFFFU) {
+            break;      // NaN found
+        }
+        ++pWork;        // Next entry
+    } while (--i);
+    return (i!=0);      // i == 0 if nothing matched
+#elif defined(_XM_SSE_INTRINSICS_)
+    // Load in registers
+    XMVECTOR vX = M.r[0];
+    XMVECTOR vY = M.r[1];
+    XMVECTOR vZ = M.r[2];
+    XMVECTOR vW = M.r[3];
+    // Test themselves to check for NaN
+    vX = _mm_cmpneq_ps(vX,vX);
+    vY = _mm_cmpneq_ps(vY,vY);
+    vZ = _mm_cmpneq_ps(vZ,vZ);
+    vW = _mm_cmpneq_ps(vW,vW);
+    // Or all the results
+    vX = _mm_or_ps(vX,vZ);
+    vY = _mm_or_ps(vY,vW);
+    vX = _mm_or_ps(vX,vY);
+    // If any tested true, return true
+    return (_mm_movemask_ps(vX)!=0);
+#else
+#endif
+}
+
+//------------------------------------------------------------------------------
+
+// Return TRUE if any entry in the matrix is +/-INF
+XMFINLINE BOOL XMMatrixIsInfinite
+(
+    CXMMATRIX M
+)
+{
+#if defined(_XM_NO_INTRINSICS_)
+    UINT i, uTest;
+    const UINT *pWork;
+
+    i = 16;
+    pWork = (const UINT *)(&M.m[0][0]);
+    do {
+        // Fetch value into integer unit
+        uTest = pWork[0];
+        // Remove sign
+        uTest &= 0x7FFFFFFFU;
+        // INF is 0x7F800000
+        if (uTest==0x7F800000U) {
+            break;      // INF found
+        }
+        ++pWork;        // Next entry
+    } while (--i);
+    return (i!=0);      // i == 0 if nothing matched
+#elif defined(_XM_SSE_INTRINSICS_)
+    // Mask off the sign bits
+    XMVECTOR vTemp1 = _mm_and_ps(M.r[0],g_XMAbsMask);
+    XMVECTOR vTemp2 = _mm_and_ps(M.r[1],g_XMAbsMask);
+    XMVECTOR vTemp3 = _mm_and_ps(M.r[2],g_XMAbsMask);
+    XMVECTOR vTemp4 = _mm_and_ps(M.r[3],g_XMAbsMask);
+    // Compare to infinity
+    vTemp1 = _mm_cmpeq_ps(vTemp1,g_XMInfinity);
+    vTemp2 = _mm_cmpeq_ps(vTemp2,g_XMInfinity);
+    vTemp3 = _mm_cmpeq_ps(vTemp3,g_XMInfinity);
+    vTemp4 = _mm_cmpeq_ps(vTemp4,g_XMInfinity);
+    // Or the answers together
+    vTemp1 = _mm_or_ps(vTemp1,vTemp2);
+    vTemp3 = _mm_or_ps(vTemp3,vTemp4);
+    vTemp1 = _mm_or_ps(vTemp1,vTemp3);
+    // If any are infinity, the signs are true.
+    return (_mm_movemask_ps(vTemp1)!=0);
+#else // _XM_VMX128_INTRINSICS_
+#endif // _XM_VMX128_INTRINSICS_
+}
+
+//------------------------------------------------------------------------------
+
+// Return TRUE if the XMMatrix is equal to identity
+XMFINLINE BOOL XMMatrixIsIdentity
+(
+    CXMMATRIX M
+)
+{
+#if defined(_XM_NO_INTRINSICS_)
+    unsigned int uOne, uZero;
+    const unsigned int *pWork;
+
+    // Use the integer pipeline to reduce branching to a minimum
+    pWork = (const unsigned int*)(&M.m[0][0]);
+    // Convert 1.0f to zero and or them together
+    uOne = pWork[0]^0x3F800000U;
+    // Or all the 0.0f entries together
+    uZero = pWork[1];
+    uZero |= pWork[2];
+    uZero |= pWork[3];
+    // 2nd row
+    uZero |= pWork[4];
+    uOne |= pWork[5]^0x3F800000U;
+    uZero |= pWork[6];
+    uZero |= pWork[7];
+    // 3rd row
+    uZero |= pWork[8];
+    uZero |= pWork[9];
+    uOne |= pWork[10]^0x3F800000U;
+    uZero |= pWork[11];
+    // 4th row
+    uZero |= pWork[12];
+    uZero |= pWork[13];
+    uZero |= pWork[14];
+    uOne |= pWork[15]^0x3F800000U;
+    // If all zero entries are zero, the uZero==0
+    uZero &= 0x7FFFFFFF;    // Allow -0.0f
+    // If all 1.0f entries are 1.0f, then uOne==0
+    uOne |= uZero;
+    return (uOne==0);
+#elif defined(_XM_SSE_INTRINSICS_)
+    XMVECTOR vTemp1 = _mm_cmpeq_ps(M.r[0],g_XMIdentityR0);
+    XMVECTOR vTemp2 = _mm_cmpeq_ps(M.r[1],g_XMIdentityR1);
+    XMVECTOR vTemp3 = _mm_cmpeq_ps(M.r[2],g_XMIdentityR2);
+    XMVECTOR vTemp4 = _mm_cmpeq_ps(M.r[3],g_XMIdentityR3);
+    vTemp1 = _mm_and_ps(vTemp1,vTemp2);
+    vTemp3 = _mm_and_ps(vTemp3,vTemp4);
+    vTemp1 = _mm_and_ps(vTemp1,vTemp3);
+    return (_mm_movemask_ps(vTemp1)==0x0f);
+#else // _XM_VMX128_INTRINSICS_
+#endif // _XM_VMX128_INTRINSICS_
+}
+
+//------------------------------------------------------------------------------
+// Computation operations
+//------------------------------------------------------------------------------
+
+//------------------------------------------------------------------------------
+// Perform a 4x4 matrix multiply by a 4x4 matrix
+XMFINLINE XMMATRIX XMMatrixMultiply
+(
+    CXMMATRIX M1, 
+    CXMMATRIX M2
+)
+{
+#if defined(_XM_NO_INTRINSICS_)
+    XMMATRIX mResult;
+    // Cache the invariants in registers
+    float x = M1.m[0][0];
+    float y = M1.m[0][1];
+    float z = M1.m[0][2];
+    float w = M1.m[0][3];
+    // Perform the operation on the first row
+    mResult.m[0][0] = (M2.m[0][0]*x)+(M2.m[1][0]*y)+(M2.m[2][0]*z)+(M2.m[3][0]*w);
+    mResult.m[0][1] = (M2.m[0][1]*x)+(M2.m[1][1]*y)+(M2.m[2][1]*z)+(M2.m[3][1]*w);
+    mResult.m[0][2] = (M2.m[0][2]*x)+(M2.m[1][2]*y)+(M2.m[2][2]*z)+(M2.m[3][2]*w);
+    mResult.m[0][3] = (M2.m[0][3]*x)+(M2.m[1][3]*y)+(M2.m[2][3]*z)+(M2.m[3][3]*w);
+    // Repeat for all the other rows
+    x = M1.m[1][0];
+    y = M1.m[1][1];
+    z = M1.m[1][2];
+    w = M1.m[1][3];
+    mResult.m[1][0] = (M2.m[0][0]*x)+(M2.m[1][0]*y)+(M2.m[2][0]*z)+(M2.m[3][0]*w);
+    mResult.m[1][1] = (M2.m[0][1]*x)+(M2.m[1][1]*y)+(M2.m[2][1]*z)+(M2.m[3][1]*w);
+    mResult.m[1][2] = (M2.m[0][2]*x)+(M2.m[1][2]*y)+(M2.m[2][2]*z)+(M2.m[3][2]*w);
+    mResult.m[1][3] = (M2.m[0][3]*x)+(M2.m[1][3]*y)+(M2.m[2][3]*z)+(M2.m[3][3]*w);
+    x = M1.m[2][0];
+    y = M1.m[2][1];
+    z = M1.m[2][2];
+    w = M1.m[2][3];
+    mResult.m[2][0] = (M2.m[0][0]*x)+(M2.m[1][0]*y)+(M2.m[2][0]*z)+(M2.m[3][0]*w);
+    mResult.m[2][1] = (M2.m[0][1]*x)+(M2.m[1][1]*y)+(M2.m[2][1]*z)+(M2.m[3][1]*w);
+    mResult.m[2][2] = (M2.m[0][2]*x)+(M2.m[1][2]*y)+(M2.m[2][2]*z)+(M2.m[3][2]*w);
+    mResult.m[2][3] = (M2.m[0][3]*x)+(M2.m[1][3]*y)+(M2.m[2][3]*z)+(M2.m[3][3]*w);
+    x = M1.m[3][0];
+    y = M1.m[3][1];
+    z = M1.m[3][2];
+    w = M1.m[3][3];
+    mResult.m[3][0] = (M2.m[0][0]*x)+(M2.m[1][0]*y)+(M2.m[2][0]*z)+(M2.m[3][0]*w);
+    mResult.m[3][1] = (M2.m[0][1]*x)+(M2.m[1][1]*y)+(M2.m[2][1]*z)+(M2.m[3][1]*w);
+    mResult.m[3][2] = (M2.m[0][2]*x)+(M2.m[1][2]*y)+(M2.m[2][2]*z)+(M2.m[3][2]*w);
+    mResult.m[3][3] = (M2.m[0][3]*x)+(M2.m[1][3]*y)+(M2.m[2][3]*z)+(M2.m[3][3]*w);
+    return mResult;
+#elif defined(_XM_SSE_INTRINSICS_)
+    XMMATRIX mResult;
+    // Use vW to hold the original row
+    XMVECTOR vW = M1.r[0];
+    // Splat the component X,Y,Z then W
+    XMVECTOR vX = _mm_shuffle_ps(vW,vW,_MM_SHUFFLE(0,0,0,0));
+    XMVECTOR vY = _mm_shuffle_ps(vW,vW,_MM_SHUFFLE(1,1,1,1));
+    XMVECTOR vZ = _mm_shuffle_ps(vW,vW,_MM_SHUFFLE(2,2,2,2));
+    vW = _mm_shuffle_ps(vW,vW,_MM_SHUFFLE(3,3,3,3));
+    // Perform the opertion on the first row
+    vX = _mm_mul_ps(vX,M2.r[0]);
+    vY = _mm_mul_ps(vY,M2.r[1]);
+    vZ = _mm_mul_ps(vZ,M2.r[2]);
+    vW = _mm_mul_ps(vW,M2.r[3]);
+    // Perform a binary add to reduce cumulative errors
+    vX = _mm_add_ps(vX,vZ);
+    vY = _mm_add_ps(vY,vW);
+    vX = _mm_add_ps(vX,vY);
+    mResult.r[0] = vX;
+    // Repeat for the other 3 rows
+    vW = M1.r[1];
+    vX = _mm_shuffle_ps(vW,vW,_MM_SHUFFLE(0,0,0,0));
+    vY = _mm_shuffle_ps(vW,vW,_MM_SHUFFLE(1,1,1,1));
+    vZ = _mm_shuffle_ps(vW,vW,_MM_SHUFFLE(2,2,2,2));
+    vW = _mm_shuffle_ps(vW,vW,_MM_SHUFFLE(3,3,3,3));
+    vX = _mm_mul_ps(vX,M2.r[0]);
+    vY = _mm_mul_ps(vY,M2.r[1]);
+    vZ = _mm_mul_ps(vZ,M2.r[2]);
+    vW = _mm_mul_ps(vW,M2.r[3]);
+    vX = _mm_add_ps(vX,vZ);
+    vY = _mm_add_ps(vY,vW);
+    vX = _mm_add_ps(vX,vY);
+    mResult.r[1] = vX;
+    vW = M1.r[2];
+    vX = _mm_shuffle_ps(vW,vW,_MM_SHUFFLE(0,0,0,0));
+    vY = _mm_shuffle_ps(vW,vW,_MM_SHUFFLE(1,1,1,1));
+    vZ = _mm_shuffle_ps(vW,vW,_MM_SHUFFLE(2,2,2,2));
+    vW = _mm_shuffle_ps(vW,vW,_MM_SHUFFLE(3,3,3,3));
+    vX = _mm_mul_ps(vX,M2.r[0]);
+    vY = _mm_mul_ps(vY,M2.r[1]);
+    vZ = _mm_mul_ps(vZ,M2.r[2]);
+    vW = _mm_mul_ps(vW,M2.r[3]);
+    vX = _mm_add_ps(vX,vZ);
+    vY = _mm_add_ps(vY,vW);
+    vX = _mm_add_ps(vX,vY);
+    mResult.r[2] = vX;
+    vW = M1.r[3];
+    vX = _mm_shuffle_ps(vW,vW,_MM_SHUFFLE(0,0,0,0));
+    vY = _mm_shuffle_ps(vW,vW,_MM_SHUFFLE(1,1,1,1));
+    vZ = _mm_shuffle_ps(vW,vW,_MM_SHUFFLE(2,2,2,2));
+    vW = _mm_shuffle_ps(vW,vW,_MM_SHUFFLE(3,3,3,3));
+    vX = _mm_mul_ps(vX,M2.r[0]);
+    vY = _mm_mul_ps(vY,M2.r[1]);
+    vZ = _mm_mul_ps(vZ,M2.r[2]);
+    vW = _mm_mul_ps(vW,M2.r[3]);
+    vX = _mm_add_ps(vX,vZ);
+    vY = _mm_add_ps(vY,vW);
+    vX = _mm_add_ps(vX,vY);
+    mResult.r[3] = vX;
+    return mResult;
+#else // _XM_VMX128_INTRINSICS_
+#endif // _XM_VMX128_INTRINSICS_
+}
+
+//------------------------------------------------------------------------------
+
+XMFINLINE XMMATRIX XMMatrixMultiplyTranspose
+(
+    CXMMATRIX M1, 
+    CXMMATRIX M2
+)
+{
+#if defined(_XM_NO_INTRINSICS_)
+    XMMATRIX mResult;
+    // Cache the invariants in registers
+    float x = M2.m[0][0];
+    float y = M2.m[1][0];
+    float z = M2.m[2][0];
+    float w = M2.m[3][0];
+    // Perform the operation on the first row
+    mResult.m[0][0] = (M1.m[0][0]*x)+(M1.m[0][1]*y)+(M1.m[0][2]*z)+(M1.m[0][3]*w);
+    mResult.m[0][1] = (M1.m[1][0]*x)+(M1.m[1][1]*y)+(M1.m[1][2]*z)+(M1.m[1][3]*w);
+    mResult.m[0][2] = (M1.m[2][0]*x)+(M1.m[2][1]*y)+(M1.m[2][2]*z)+(M1.m[2][3]*w);
+    mResult.m[0][3] = (M1.m[3][0]*x)+(M1.m[3][1]*y)+(M1.m[3][2]*z)+(M1.m[3][3]*w);
+    // Repeat for all the other rows
+    x = M2.m[0][1];
+    y = M2.m[1][1];
+    z = M2.m[2][1];
+    w = M2.m[3][1];
+    mResult.m[1][0] = (M1.m[0][0]*x)+(M1.m[0][1]*y)+(M1.m[0][2]*z)+(M1.m[0][3]*w);
+    mResult.m[1][1] = (M1.m[1][0]*x)+(M1.m[1][1]*y)+(M1.m[1][2]*z)+(M1.m[1][3]*w);
+    mResult.m[1][2] = (M1.m[2][0]*x)+(M1.m[2][1]*y)+(M1.m[2][2]*z)+(M1.m[2][3]*w);
+    mResult.m[1][3] = (M1.m[3][0]*x)+(M1.m[3][1]*y)+(M1.m[3][2]*z)+(M1.m[3][3]*w);
+    x = M2.m[0][2];
+    y = M2.m[1][2];
+    z = M2.m[2][2];
+    w = M2.m[3][2];
+    mResult.m[2][0] = (M1.m[0][0]*x)+(M1.m[0][1]*y)+(M1.m[0][2]*z)+(M1.m[0][3]*w);
+    mResult.m[2][1] = (M1.m[1][0]*x)+(M1.m[1][1]*y)+(M1.m[1][2]*z)+(M1.m[1][3]*w);
+    mResult.m[2][2] = (M1.m[2][0]*x)+(M1.m[2][1]*y)+(M1.m[2][2]*z)+(M1.m[2][3]*w);
+    mResult.m[2][3] = (M1.m[3][0]*x)+(M1.m[3][1]*y)+(M1.m[3][2]*z)+(M1.m[3][3]*w);
+    x = M2.m[0][3];
+    y = M2.m[1][3];
+    z = M2.m[2][3];
+    w = M2.m[3][3];
+    mResult.m[3][0] = (M1.m[0][0]*x)+(M1.m[0][1]*y)+(M1.m[0][2]*z)+(M1.m[0][3]*w);
+    mResult.m[3][1] = (M1.m[1][0]*x)+(M1.m[1][1]*y)+(M1.m[1][2]*z)+(M1.m[1][3]*w);
+    mResult.m[3][2] = (M1.m[2][0]*x)+(M1.m[2][1]*y)+(M1.m[2][2]*z)+(M1.m[2][3]*w);
+    mResult.m[3][3] = (M1.m[3][0]*x)+(M1.m[3][1]*y)+(M1.m[3][2]*z)+(M1.m[3][3]*w);
+    return mResult;
+#elif defined(_XM_SSE_INTRINSICS_)
+    XMMATRIX Product;
+    XMMATRIX Result;
+    Product = XMMatrixMultiply(M1, M2);
+    Result = XMMatrixTranspose(Product);
+    return Result;
+#else // _XM_VMX128_INTRINSICS_
+#endif // _XM_VMX128_INTRINSICS_
+}
+
+//------------------------------------------------------------------------------
+
+XMFINLINE XMMATRIX XMMatrixTranspose
+(
+    CXMMATRIX M
+)
+{
+#if defined(_XM_NO_INTRINSICS_)
+
+    XMMATRIX P;
+    XMMATRIX MT;
+
+    // Original matrix:
+    //
+    //     m00m01m02m03
+    //     m10m11m12m13
+    //     m20m21m22m23
+    //     m30m31m32m33
+
+    P.r[0] = XMVectorMergeXY(M.r[0], M.r[2]); // m00m20m01m21
+    P.r[1] = XMVectorMergeXY(M.r[1], M.r[3]); // m10m30m11m31
+    P.r[2] = XMVectorMergeZW(M.r[0], M.r[2]); // m02m22m03m23
+    P.r[3] = XMVectorMergeZW(M.r[1], M.r[3]); // m12m32m13m33
+
+    MT.r[0] = XMVectorMergeXY(P.r[0], P.r[1]); // m00m10m20m30
+    MT.r[1] = XMVectorMergeZW(P.r[0], P.r[1]); // m01m11m21m31
+    MT.r[2] = XMVectorMergeXY(P.r[2], P.r[3]); // m02m12m22m32
+    MT.r[3] = XMVectorMergeZW(P.r[2], P.r[3]); // m03m13m23m33
+
+    return MT;
+
+#elif defined(_XM_SSE_INTRINSICS_)
+    // x.x,x.y,y.x,y.y
+    XMVECTOR vTemp1 = _mm_shuffle_ps(M.r[0],M.r[1],_MM_SHUFFLE(1,0,1,0));
+    // x.z,x.w,y.z,y.w
+    XMVECTOR vTemp3 = _mm_shuffle_ps(M.r[0],M.r[1],_MM_SHUFFLE(3,2,3,2));
+    // z.x,z.y,w.x,w.y
+    XMVECTOR vTemp2 = _mm_shuffle_ps(M.r[2],M.r[3],_MM_SHUFFLE(1,0,1,0));
+    // z.z,z.w,w.z,w.w
+    XMVECTOR vTemp4 = _mm_shuffle_ps(M.r[2],M.r[3],_MM_SHUFFLE(3,2,3,2));
+    XMMATRIX mResult;
+
+    // x.x,y.x,z.x,w.x
+    mResult.r[0] = _mm_shuffle_ps(vTemp1, vTemp2,_MM_SHUFFLE(2,0,2,0));
+    // x.y,y.y,z.y,w.y
+    mResult.r[1] = _mm_shuffle_ps(vTemp1, vTemp2,_MM_SHUFFLE(3,1,3,1));
+    // x.z,y.z,z.z,w.z
+    mResult.r[2] = _mm_shuffle_ps(vTemp3, vTemp4,_MM_SHUFFLE(2,0,2,0));
+    // x.w,y.w,z.w,w.w
+    mResult.r[3] = _mm_shuffle_ps(vTemp3, vTemp4,_MM_SHUFFLE(3,1,3,1));
+    return mResult;
+#else // _XM_VMX128_INTRINSICS_
+#endif // _XM_VMX128_INTRINSICS_
+}
+
+//------------------------------------------------------------------------------
+// Return the inverse and the determinant of a 4x4 matrix
+XMINLINE XMMATRIX XMMatrixInverse
+(
+    XMVECTOR* pDeterminant, 
+    CXMMATRIX  M
+)
+{
+#if defined(_XM_NO_INTRINSICS_)
+
+    XMMATRIX               R;
+    XMMATRIX               MT;
+    XMVECTOR               D0, D1, D2;
+    XMVECTOR               C0, C1, C2, C3, C4, C5, C6, C7;
+    XMVECTOR               V0[4], V1[4];
+    XMVECTOR               Determinant;
+    XMVECTOR               Reciprocal;
+    XMMATRIX               Result;
+    static CONST XMVECTORU32 SwizzleXXYY = {XM_PERMUTE_0X, XM_PERMUTE_0X, XM_PERMUTE_0Y, XM_PERMUTE_0Y};
+    static CONST XMVECTORU32 SwizzleZWZW = {XM_PERMUTE_0Z, XM_PERMUTE_0W, XM_PERMUTE_0Z, XM_PERMUTE_0W};
+    static CONST XMVECTORU32 SwizzleYZXY = {XM_PERMUTE_0Y, XM_PERMUTE_0Z, XM_PERMUTE_0X, XM_PERMUTE_0Y};
+    static CONST XMVECTORU32 SwizzleZWYZ = {XM_PERMUTE_0Z, XM_PERMUTE_0W, XM_PERMUTE_0Y, XM_PERMUTE_0Z};
+    static CONST XMVECTORU32 SwizzleWXWX = {XM_PERMUTE_0W, XM_PERMUTE_0X, XM_PERMUTE_0W, XM_PERMUTE_0X};
+    static CONST XMVECTORU32 SwizzleZXYX = {XM_PERMUTE_0Z, XM_PERMUTE_0X, XM_PERMUTE_0Y, XM_PERMUTE_0X};
+    static CONST XMVECTORU32 SwizzleYWXZ = {XM_PERMUTE_0Y, XM_PERMUTE_0W, XM_PERMUTE_0X, XM_PERMUTE_0Z};
+    static CONST XMVECTORU32 SwizzleWZWY = {XM_PERMUTE_0W, XM_PERMUTE_0Z, XM_PERMUTE_0W, XM_PERMUTE_0Y};
+    static CONST XMVECTORU32 Permute0X0Z1X1Z = {XM_PERMUTE_0X, XM_PERMUTE_0Z, XM_PERMUTE_1X, XM_PERMUTE_1Z};
+    static CONST XMVECTORU32 Permute0Y0W1Y1W = {XM_PERMUTE_0Y, XM_PERMUTE_0W, XM_PERMUTE_1Y, XM_PERMUTE_1W};
+    static CONST XMVECTORU32 Permute1Y0Y0W0X = {XM_PERMUTE_1Y, XM_PERMUTE_0Y, XM_PERMUTE_0W, XM_PERMUTE_0X};
+    static CONST XMVECTORU32 Permute0W0X0Y1X = {XM_PERMUTE_0W, XM_PERMUTE_0X, XM_PERMUTE_0Y, XM_PERMUTE_1X};
+    static CONST XMVECTORU32 Permute0Z1Y1X0Z = {XM_PERMUTE_0Z, XM_PERMUTE_1Y, XM_PERMUTE_1X, XM_PERMUTE_0Z};
+    static CONST XMVECTORU32 Permute0W1Y0Y0Z = {XM_PERMUTE_0W, XM_PERMUTE_1Y, XM_PERMUTE_0Y, XM_PERMUTE_0Z};
+    static CONST XMVECTORU32 Permute0Z0Y1X0X = {XM_PERMUTE_0Z, XM_PERMUTE_0Y, XM_PERMUTE_1X, XM_PERMUTE_0X};
+    static CONST XMVECTORU32 Permute1Y0X0W1X = {XM_PERMUTE_1Y, XM_PERMUTE_0X, XM_PERMUTE_0W, XM_PERMUTE_1X};
+    static CONST XMVECTORU32 Permute1W0Y0W0X = {XM_PERMUTE_1W, XM_PERMUTE_0Y, XM_PERMUTE_0W, XM_PERMUTE_0X};
+    static CONST XMVECTORU32 Permute0W0X0Y1Z = {XM_PERMUTE_0W, XM_PERMUTE_0X, XM_PERMUTE_0Y, XM_PERMUTE_1Z};
+    static CONST XMVECTORU32 Permute0Z1W1Z0Z = {XM_PERMUTE_0Z, XM_PERMUTE_1W, XM_PERMUTE_1Z, XM_PERMUTE_0Z};
+    static CONST XMVECTORU32 Permute0W1W0Y0Z = {XM_PERMUTE_0W, XM_PERMUTE_1W, XM_PERMUTE_0Y, XM_PERMUTE_0Z};
+    static CONST XMVECTORU32 Permute0Z0Y1Z0X = {XM_PERMUTE_0Z, XM_PERMUTE_0Y, XM_PERMUTE_1Z, XM_PERMUTE_0X};
+    static CONST XMVECTORU32 Permute1W0X0W1Z = {XM_PERMUTE_1W, XM_PERMUTE_0X, XM_PERMUTE_0W, XM_PERMUTE_1Z};
+
+    MT = XMMatrixTranspose(M);
+
+    V0[0] = XMVectorPermute(MT.r[2], MT.r[2], SwizzleXXYY.v);
+    V1[0] = XMVectorPermute(MT.r[3], MT.r[3], SwizzleZWZW.v);
+    V0[1] = XMVectorPermute(MT.r[0], MT.r[0], SwizzleXXYY.v);
+    V1[1] = XMVectorPermute(MT.r[1], MT.r[1], SwizzleZWZW.v);
+    V0[2] = XMVectorPermute(MT.r[2], MT.r[0], Permute0X0Z1X1Z.v);
+    V1[2] = XMVectorPermute(MT.r[3], MT.r[1], Permute0Y0W1Y1W.v);
+
+    D0 = XMVectorMultiply(V0[0], V1[0]);
+    D1 = XMVectorMultiply(V0[1], V1[1]);
+    D2 = XMVectorMultiply(V0[2], V1[2]);
+
+    V0[0] = XMVectorPermute(MT.r[2], MT.r[2], SwizzleZWZW.v);
+    V1[0] = XMVectorPermute(MT.r[3], MT.r[3], SwizzleXXYY.v);
+    V0[1] = XMVectorPermute(MT.r[0], MT.r[0], SwizzleZWZW.v);
+    V1[1] = XMVectorPermute(MT.r[1], MT.r[1], SwizzleXXYY.v);
+    V0[2] = XMVectorPermute(MT.r[2], MT.r[0], Permute0Y0W1Y1W.v);
+    V1[2] = XMVectorPermute(MT.r[3], MT.r[1], Permute0X0Z1X1Z.v);
+
+    D0 = XMVectorNegativeMultiplySubtract(V0[0], V1[0], D0);
+    D1 = XMVectorNegativeMultiplySubtract(V0[1], V1[1], D1);
+    D2 = XMVectorNegativeMultiplySubtract(V0[2], V1[2], D2);
+
+    V0[0] = XMVectorPermute(MT.r[1], MT.r[1], SwizzleYZXY.v);
+    V1[0] = XMVectorPermute(D0, D2, Permute1Y0Y0W0X.v);
+    V0[1] = XMVectorPermute(MT.r[0], MT.r[0], SwizzleZXYX.v);
+    V1[1] = XMVectorPermute(D0, D2, Permute0W1Y0Y0Z.v);
+    V0[2] = XMVectorPermute(MT.r[3], MT.r[3], SwizzleYZXY.v);
+    V1[2] = XMVectorPermute(D1, D2, Permute1W0Y0W0X.v);
+    V0[3] = XMVectorPermute(MT.r[2], MT.r[2], SwizzleZXYX.v);
+    V1[3] = XMVectorPermute(D1, D2, Permute0W1W0Y0Z.v);
+
+    C0 = XMVectorMultiply(V0[0], V1[0]);
+    C2 = XMVectorMultiply(V0[1], V1[1]);
+    C4 = XMVectorMultiply(V0[2], V1[2]);
+    C6 = XMVectorMultiply(V0[3], V1[3]);
+
+    V0[0] = XMVectorPermute(MT.r[1], MT.r[1], SwizzleZWYZ.v);
+    V1[0] = XMVectorPermute(D0, D2, Permute0W0X0Y1X.v);
+    V0[1] = XMVectorPermute(MT.r[0], MT.r[0], SwizzleWZWY.v);
+    V1[1] = XMVectorPermute(D0, D2, Permute0Z0Y1X0X.v);
+    V0[2] = XMVectorPermute(MT.r[3], MT.r[3], SwizzleZWYZ.v);
+    V1[2] = XMVectorPermute(D1, D2, Permute0W0X0Y1Z.v);
+    V0[3] = XMVectorPermute(MT.r[2], MT.r[2], SwizzleWZWY.v);
+    V1[3] = XMVectorPermute(D1, D2, Permute0Z0Y1Z0X.v);
+
+    C0 = XMVectorNegativeMultiplySubtract(V0[0], V1[0], C0);
+    C2 = XMVectorNegativeMultiplySubtract(V0[1], V1[1], C2);
+    C4 = XMVectorNegativeMultiplySubtract(V0[2], V1[2], C4);
+    C6 = XMVectorNegativeMultiplySubtract(V0[3], V1[3], C6);
+
+    V0[0] = XMVectorPermute(MT.r[1], MT.r[1], SwizzleWXWX.v);
+    V1[0] = XMVectorPermute(D0, D2, Permute0Z1Y1X0Z.v);
+    V0[1] = XMVectorPermute(MT.r[0], MT.r[0], SwizzleYWXZ.v);
+    V1[1] = XMVectorPermute(D0, D2, Permute1Y0X0W1X.v);
+    V0[2] = XMVectorPermute(MT.r[3], MT.r[3], SwizzleWXWX.v);
+    V1[2] = XMVectorPermute(D1, D2, Permute0Z1W1Z0Z.v);
+    V0[3] = XMVectorPermute(MT.r[2], MT.r[2], SwizzleYWXZ.v);
+    V1[3] = XMVectorPermute(D1, D2, Permute1W0X0W1Z.v);
+
+    C1 = XMVectorNegativeMultiplySubtract(V0[0], V1[0], C0);
+    C0 = XMVectorMultiplyAdd(V0[0], V1[0], C0);
+    C3 = XMVectorMultiplyAdd(V0[1], V1[1], C2);
+    C2 = XMVectorNegativeMultiplySubtract(V0[1], V1[1], C2);
+    C5 = XMVectorNegativeMultiplySubtract(V0[2], V1[2], C4);
+    C4 = XMVectorMultiplyAdd(V0[2], V1[2], C4);
+    C7 = XMVectorMultiplyAdd(V0[3], V1[3], C6);
+    C6 = XMVectorNegativeMultiplySubtract(V0[3], V1[3], C6);
+
+    R.r[0] = XMVectorSelect(C0, C1, g_XMSelect0101.v);
+    R.r[1] = XMVectorSelect(C2, C3, g_XMSelect0101.v);
+    R.r[2] = XMVectorSelect(C4, C5, g_XMSelect0101.v);
+    R.r[3] = XMVectorSelect(C6, C7, g_XMSelect0101.v);
+
+    Determinant = XMVector4Dot(R.r[0], MT.r[0]);
+
+    if (pDeterminant)
+        *pDeterminant = Determinant;
+
+    Reciprocal = XMVectorReciprocal(Determinant);
+
+    Result.r[0] = XMVectorMultiply(R.r[0], Reciprocal);
+    Result.r[1] = XMVectorMultiply(R.r[1], Reciprocal);
+    Result.r[2] = XMVectorMultiply(R.r[2], Reciprocal);
+    Result.r[3] = XMVectorMultiply(R.r[3], Reciprocal);
+
+    return Result;
+
+#elif defined(_XM_SSE_INTRINSICS_)
+    XMMATRIX MT = XMMatrixTranspose(M);
+    XMVECTOR V00 = _mm_shuffle_ps(MT.r[2], MT.r[2],_MM_SHUFFLE(1,1,0,0));
+    XMVECTOR V10 = _mm_shuffle_ps(MT.r[3], MT.r[3],_MM_SHUFFLE(3,2,3,2));
+    XMVECTOR V01 = _mm_shuffle_ps(MT.r[0], MT.r[0],_MM_SHUFFLE(1,1,0,0));
+    XMVECTOR V11 = _mm_shuffle_ps(MT.r[1], MT.r[1],_MM_SHUFFLE(3,2,3,2));
+    XMVECTOR V02 = _mm_shuffle_ps(MT.r[2], MT.r[0],_MM_SHUFFLE(2,0,2,0));
+    XMVECTOR V12 = _mm_shuffle_ps(MT.r[3], MT.r[1],_MM_SHUFFLE(3,1,3,1));
+
+    XMVECTOR D0 = _mm_mul_ps(V00,V10);
+    XMVECTOR D1 = _mm_mul_ps(V01,V11);
+    XMVECTOR D2 = _mm_mul_ps(V02,V12);
+
+    V00 = _mm_shuffle_ps(MT.r[2],MT.r[2],_MM_SHUFFLE(3,2,3,2));
+    V10 = _mm_shuffle_ps(MT.r[3],MT.r[3],_MM_SHUFFLE(1,1,0,0));
+    V01 = _mm_shuffle_ps(MT.r[0],MT.r[0],_MM_SHUFFLE(3,2,3,2));
+    V11 = _mm_shuffle_ps(MT.r[1],MT.r[1],_MM_SHUFFLE(1,1,0,0));
+    V02 = _mm_shuffle_ps(MT.r[2],MT.r[0],_MM_SHUFFLE(3,1,3,1));
+    V12 = _mm_shuffle_ps(MT.r[3],MT.r[1],_MM_SHUFFLE(2,0,2,0));
+
+    V00 = _mm_mul_ps(V00,V10);
+    V01 = _mm_mul_ps(V01,V11);
+    V02 = _mm_mul_ps(V02,V12);
+    D0 = _mm_sub_ps(D0,V00);
+    D1 = _mm_sub_ps(D1,V01);
+    D2 = _mm_sub_ps(D2,V02);
+    // V11 = D0Y,D0W,D2Y,D2Y
+    V11 = _mm_shuffle_ps(D0,D2,_MM_SHUFFLE(1,1,3,1));
+    V00 = _mm_shuffle_ps(MT.r[1], MT.r[1],_MM_SHUFFLE(1,0,2,1));
+    V10 = _mm_shuffle_ps(V11,D0,_MM_SHUFFLE(0,3,0,2));
+    V01 = _mm_shuffle_ps(MT.r[0], MT.r[0],_MM_SHUFFLE(0,1,0,2));
+    V11 = _mm_shuffle_ps(V11,D0,_MM_SHUFFLE(2,1,2,1));
+    // V13 = D1Y,D1W,D2W,D2W
+    XMVECTOR V13 = _mm_shuffle_ps(D1,D2,_MM_SHUFFLE(3,3,3,1));
+    V02 = _mm_shuffle_ps(MT.r[3], MT.r[3],_MM_SHUFFLE(1,0,2,1));
+    V12 = _mm_shuffle_ps(V13,D1,_MM_SHUFFLE(0,3,0,2));
+    XMVECTOR V03 = _mm_shuffle_ps(MT.r[2], MT.r[2],_MM_SHUFFLE(0,1,0,2));
+    V13 = _mm_shuffle_ps(V13,D1,_MM_SHUFFLE(2,1,2,1));
+
+    XMVECTOR C0 = _mm_mul_ps(V00,V10);
+    XMVECTOR C2 = _mm_mul_ps(V01,V11);
+    XMVECTOR C4 = _mm_mul_ps(V02,V12);
+    XMVECTOR C6 = _mm_mul_ps(V03,V13);
+
+    // V11 = D0X,D0Y,D2X,D2X
+    V11 = _mm_shuffle_ps(D0,D2,_MM_SHUFFLE(0,0,1,0));
+    V00 = _mm_shuffle_ps(MT.r[1], MT.r[1],_MM_SHUFFLE(2,1,3,2));
+    V10 = _mm_shuffle_ps(D0,V11,_MM_SHUFFLE(2,1,0,3));
+    V01 = _mm_shuffle_ps(MT.r[0], MT.r[0],_MM_SHUFFLE(1,3,2,3));
+    V11 = _mm_shuffle_ps(D0,V11,_MM_SHUFFLE(0,2,1,2));
+    // V13 = D1X,D1Y,D2Z,D2Z
+    V13 = _mm_shuffle_ps(D1,D2,_MM_SHUFFLE(2,2,1,0));
+    V02 = _mm_shuffle_ps(MT.r[3], MT.r[3],_MM_SHUFFLE(2,1,3,2));
+    V12 = _mm_shuffle_ps(D1,V13,_MM_SHUFFLE(2,1,0,3));
+    V03 = _mm_shuffle_ps(MT.r[2], MT.r[2],_MM_SHUFFLE(1,3,2,3));
+    V13 = _mm_shuffle_ps(D1,V13,_MM_SHUFFLE(0,2,1,2));
+
+    V00 = _mm_mul_ps(V00,V10);
+    V01 = _mm_mul_ps(V01,V11);
+    V02 = _mm_mul_ps(V02,V12);
+    V03 = _mm_mul_ps(V03,V13);
+    C0 = _mm_sub_ps(C0,V00);
+    C2 = _mm_sub_ps(C2,V01);
+    C4 = _mm_sub_ps(C4,V02);
+    C6 = _mm_sub_ps(C6,V03);
+
+    V00 = _mm_shuffle_ps(MT.r[1],MT.r[1],_MM_SHUFFLE(0,3,0,3));
+    // V10 = D0Z,D0Z,D2X,D2Y
+    V10 = _mm_shuffle_ps(D0,D2,_MM_SHUFFLE(1,0,2,2));
+    V10 = _mm_shuffle_ps(V10,V10,_MM_SHUFFLE(0,2,3,0));
+    V01 = _mm_shuffle_ps(MT.r[0],MT.r[0],_MM_SHUFFLE(2,0,3,1));
+    // V11 = D0X,D0W,D2X,D2Y
+    V11 = _mm_shuffle_ps(D0,D2,_MM_SHUFFLE(1,0,3,0));
+    V11 = _mm_shuffle_ps(V11,V11,_MM_SHUFFLE(2,1,0,3));
+    V02 = _mm_shuffle_ps(MT.r[3],MT.r[3],_MM_SHUFFLE(0,3,0,3));
+    // V12 = D1Z,D1Z,D2Z,D2W
+    V12 = _mm_shuffle_ps(D1,D2,_MM_SHUFFLE(3,2,2,2));
+    V12 = _mm_shuffle_ps(V12,V12,_MM_SHUFFLE(0,2,3,0));
+    V03 = _mm_shuffle_ps(MT.r[2],MT.r[2],_MM_SHUFFLE(2,0,3,1));
+    // V13 = D1X,D1W,D2Z,D2W
+    V13 = _mm_shuffle_ps(D1,D2,_MM_SHUFFLE(3,2,3,0));
+    V13 = _mm_shuffle_ps(V13,V13,_MM_SHUFFLE(2,1,0,3));
+
+    V00 = _mm_mul_ps(V00,V10);
+    V01 = _mm_mul_ps(V01,V11);
+    V02 = _mm_mul_ps(V02,V12);
+    V03 = _mm_mul_ps(V03,V13);
+    XMVECTOR C1 = _mm_sub_ps(C0,V00);
+    C0 = _mm_add_ps(C0,V00);
+    XMVECTOR C3 = _mm_add_ps(C2,V01);
+    C2 = _mm_sub_ps(C2,V01);
+    XMVECTOR C5 = _mm_sub_ps(C4,V02);
+    C4 = _mm_add_ps(C4,V02);
+    XMVECTOR C7 = _mm_add_ps(C6,V03);
+    C6 = _mm_sub_ps(C6,V03);
+
+    C0 = _mm_shuffle_ps(C0,C1,_MM_SHUFFLE(3,1,2,0));
+    C2 = _mm_shuffle_ps(C2,C3,_MM_SHUFFLE(3,1,2,0));
+    C4 = _mm_shuffle_ps(C4,C5,_MM_SHUFFLE(3,1,2,0));
+    C6 = _mm_shuffle_ps(C6,C7,_MM_SHUFFLE(3,1,2,0));
+    C0 = _mm_shuffle_ps(C0,C0,_MM_SHUFFLE(3,1,2,0));
+    C2 = _mm_shuffle_ps(C2,C2,_MM_SHUFFLE(3,1,2,0));
+    C4 = _mm_shuffle_ps(C4,C4,_MM_SHUFFLE(3,1,2,0));
+    C6 = _mm_shuffle_ps(C6,C6,_MM_SHUFFLE(3,1,2,0));
+    // Get the determinate
+    XMVECTOR vTemp = XMVector4Dot(C0,MT.r[0]);
+    if (pDeterminant)
+        *pDeterminant = vTemp;
+    vTemp = _mm_div_ps(g_XMOne,vTemp);
+    XMMATRIX mResult;
+    mResult.r[0] = _mm_mul_ps(C0,vTemp);
+    mResult.r[1] = _mm_mul_ps(C2,vTemp);
+    mResult.r[2] = _mm_mul_ps(C4,vTemp);
+    mResult.r[3] = _mm_mul_ps(C6,vTemp);
+    return mResult;
+#else // _XM_VMX128_INTRINSICS_
+#endif // _XM_VMX128_INTRINSICS_
+}
+
+//------------------------------------------------------------------------------
+
+XMINLINE XMVECTOR XMMatrixDeterminant
+(
+    CXMMATRIX M
+)
+{
+#if defined(_XM_NO_INTRINSICS_)
+
+    XMVECTOR                V0, V1, V2, V3, V4, V5;
+    XMVECTOR                P0, P1, P2, R, S;
+    XMVECTOR                Result;
+    static CONST XMVECTORU32 SwizzleYXXX = {XM_PERMUTE_0Y, XM_PERMUTE_0X, XM_PERMUTE_0X, XM_PERMUTE_0X};
+    static CONST XMVECTORU32 SwizzleZZYY = {XM_PERMUTE_0Z, XM_PERMUTE_0Z, XM_PERMUTE_0Y, XM_PERMUTE_0Y};
+    static CONST XMVECTORU32 SwizzleWWWZ = {XM_PERMUTE_0W, XM_PERMUTE_0W, XM_PERMUTE_0W, XM_PERMUTE_0Z};
+    static CONST XMVECTOR   Sign = {1.0f, -1.0f, 1.0f, -1.0f};
+
+    V0 = XMVectorPermute(M.r[2], M.r[2], SwizzleYXXX.v);
+    V1 = XMVectorPermute(M.r[3], M.r[3], SwizzleZZYY.v);
+    V2 = XMVectorPermute(M.r[2], M.r[2], SwizzleYXXX.v);
+    V3 = XMVectorPermute(M.r[3], M.r[3], SwizzleWWWZ.v);
+    V4 = XMVectorPermute(M.r[2], M.r[2], SwizzleZZYY.v);
+    V5 = XMVectorPermute(M.r[3], M.r[3], SwizzleWWWZ.v);
+
+    P0 = XMVectorMultiply(V0, V1);
+    P1 = XMVectorMultiply(V2, V3);
+    P2 = XMVectorMultiply(V4, V5);
+
+    V0 = XMVectorPermute(M.r[2], M.r[2], SwizzleZZYY.v);
+    V1 = XMVectorPermute(M.r[3], M.r[3], SwizzleYXXX.v);
+    V2 = XMVectorPermute(M.r[2], M.r[2], SwizzleWWWZ.v);
+    V3 = XMVectorPermute(M.r[3], M.r[3], SwizzleYXXX.v);
+    V4 = XMVectorPermute(M.r[2], M.r[2], SwizzleWWWZ.v);
+    V5 = XMVectorPermute(M.r[3], M.r[3], SwizzleZZYY.v);
+
+    P0 = XMVectorNegativeMultiplySubtract(V0, V1, P0);
+    P1 = XMVectorNegativeMultiplySubtract(V2, V3, P1);
+    P2 = XMVectorNegativeMultiplySubtract(V4, V5, P2);
+
+    V0 = XMVectorPermute(M.r[1], M.r[1], SwizzleWWWZ.v);
+    V1 = XMVectorPermute(M.r[1], M.r[1], SwizzleZZYY.v);
+    V2 = XMVectorPermute(M.r[1], M.r[1], SwizzleYXXX.v);
+
+    S = XMVectorMultiply(M.r[0], Sign);
+    R = XMVectorMultiply(V0, P0);
+    R = XMVectorNegativeMultiplySubtract(V1, P1, R);
+    R = XMVectorMultiplyAdd(V2, P2, R);
+
+    Result = XMVector4Dot(S, R);
+
+    return Result;
+
+#elif defined(_XM_SSE_INTRINSICS_)
+    XMVECTOR                V0, V1, V2, V3, V4, V5;
+    XMVECTOR                P0, P1, P2, R, S;
+    XMVECTOR                Result;
+    static CONST XMVECTORU32 SwizzleYXXX = {XM_PERMUTE_0Y, XM_PERMUTE_0X, XM_PERMUTE_0X, XM_PERMUTE_0X};
+    static CONST XMVECTORU32 SwizzleZZYY = {XM_PERMUTE_0Z, XM_PERMUTE_0Z, XM_PERMUTE_0Y, XM_PERMUTE_0Y};
+    static CONST XMVECTORU32 SwizzleWWWZ = {XM_PERMUTE_0W, XM_PERMUTE_0W, XM_PERMUTE_0W, XM_PERMUTE_0Z};
+    static CONST XMVECTORF32 Sign = {1.0f, -1.0f, 1.0f, -1.0f};
+
+    V0 = XMVectorPermute(M.r[2], M.r[2], SwizzleYXXX);
+    V1 = XMVectorPermute(M.r[3], M.r[3], SwizzleZZYY);
+    V2 = XMVectorPermute(M.r[2], M.r[2], SwizzleYXXX);
+    V3 = XMVectorPermute(M.r[3], M.r[3], SwizzleWWWZ);
+    V4 = XMVectorPermute(M.r[2], M.r[2], SwizzleZZYY);
+    V5 = XMVectorPermute(M.r[3], M.r[3], SwizzleWWWZ);
+
+    P0 = _mm_mul_ps(V0, V1);
+    P1 = _mm_mul_ps(V2, V3);
+    P2 = _mm_mul_ps(V4, V5);
+
+    V0 = XMVectorPermute(M.r[2], M.r[2], SwizzleZZYY);
+    V1 = XMVectorPermute(M.r[3], M.r[3], SwizzleYXXX);
+    V2 = XMVectorPermute(M.r[2], M.r[2], SwizzleWWWZ);
+    V3 = XMVectorPermute(M.r[3], M.r[3], SwizzleYXXX);
+    V4 = XMVectorPermute(M.r[2], M.r[2], SwizzleWWWZ);
+    V5 = XMVectorPermute(M.r[3], M.r[3], SwizzleZZYY);
+
+    P0 = XMVectorNegativeMultiplySubtract(V0, V1, P0);
+    P1 = XMVectorNegativeMultiplySubtract(V2, V3, P1);
+    P2 = XMVectorNegativeMultiplySubtract(V4, V5, P2);
+
+    V0 = XMVectorPermute(M.r[1], M.r[1], SwizzleWWWZ);
+    V1 = XMVectorPermute(M.r[1], M.r[1], SwizzleZZYY);
+    V2 = XMVectorPermute(M.r[1], M.r[1], SwizzleYXXX);
+
+    S = _mm_mul_ps(M.r[0], Sign);
+    R = _mm_mul_ps(V0, P0);
+    R = XMVectorNegativeMultiplySubtract(V1, P1, R);
+    R = XMVectorMultiplyAdd(V2, P2, R);
+
+    Result = XMVector4Dot(S, R);
+
+    return Result;
+
+#else // _XM_VMX128_INTRINSICS_
+#endif // _XM_VMX128_INTRINSICS_
+}
+
+#undef XMRANKDECOMPOSE
+#undef XM_DECOMP_EPSILON
+
+#define XMRANKDECOMPOSE(a, b, c, x, y, z)      \
+    if((x) < (y))                   \
+    {                               \
+        if((y) < (z))               \
+        {                           \
+            (a) = 2;                \
+            (b) = 1;                \
+            (c) = 0;                \
+        }                           \
+        else                        \
+        {                           \
+            (a) = 1;                \
+                                    \
+            if((x) < (z))           \
+            {                       \
+                (b) = 2;            \
+                (c) = 0;            \
+            }                       \
+            else                    \
+            {                       \
+                (b) = 0;            \
+                (c) = 2;            \
+            }                       \
+        }                           \
+    }                               \
+    else                            \
+    {                               \
+        if((x) < (z))               \
+        {                           \
+            (a) = 2;                \
+            (b) = 0;                \
+            (c) = 1;                \
+        }                           \
+        else                        \
+        {                           \
+            (a) = 0;                \
+                                    \
+            if((y) < (z))           \
+            {                       \
+                (b) = 2;            \
+                (c) = 1;            \
+            }                       \
+            else                    \
+            {                       \
+                (b) = 1;            \
+                (c) = 2;            \
+            }                       \
+        }                           \
+    }
+                                    
+#define XM_DECOMP_EPSILON 0.0001f
+
+XMINLINE BOOL XMMatrixDecompose
+(
+    XMVECTOR *outScale,
+    XMVECTOR *outRotQuat,
+    XMVECTOR *outTrans,
+    CXMMATRIX M
+)
+{
+    FLOAT fDet;
+    FLOAT *pfScales;
+    XMVECTOR *ppvBasis[3];
+    XMMATRIX matTemp;
+    UINT a, b, c;
+    static const XMVECTOR *pvCanonicalBasis[3] = {
+        &g_XMIdentityR0.v,
+        &g_XMIdentityR1.v,
+        &g_XMIdentityR2.v
+    };
+
+    XMASSERT( outScale != NULL );
+    XMASSERT( outRotQuat != NULL );
+    XMASSERT( outTrans != NULL );
+
+    // Get the translation
+    outTrans[0] = M.r[3];
+
+    ppvBasis[0] = &matTemp.r[0];
+    ppvBasis[1] = &matTemp.r[1];
+    ppvBasis[2] = &matTemp.r[2];
+
+    matTemp.r[0] = M.r[0];
+    matTemp.r[1] = M.r[1];
+    matTemp.r[2] = M.r[2];
+    matTemp.r[3] = g_XMIdentityR3.v;
+
+    pfScales = (FLOAT *)outScale;
+
+    XMVectorGetXPtr(&pfScales[0],XMVector3Length(ppvBasis[0][0])); 
+    XMVectorGetXPtr(&pfScales[1],XMVector3Length(ppvBasis[1][0])); 
+    XMVectorGetXPtr(&pfScales[2],XMVector3Length(ppvBasis[2][0])); 
+    pfScales[3] = 0.f;
+
+    XMRANKDECOMPOSE(a, b, c, pfScales[0], pfScales[1], pfScales[2])
+
+    if(pfScales[a] < XM_DECOMP_EPSILON)
+    {
+        ppvBasis[a][0] = pvCanonicalBasis[a][0];
+    }
+    ppvBasis[a][0] = XMVector3Normalize(ppvBasis[a][0]);
+
+    if(pfScales[b] < XM_DECOMP_EPSILON)
+    {
+        UINT aa, bb, cc;
+        FLOAT fAbsX, fAbsY, fAbsZ;
+
+        fAbsX = fabsf(XMVectorGetX(ppvBasis[a][0]));
+        fAbsY = fabsf(XMVectorGetY(ppvBasis[a][0]));
+        fAbsZ = fabsf(XMVectorGetZ(ppvBasis[a][0]));
+
+        XMRANKDECOMPOSE(aa, bb, cc, fAbsX, fAbsY, fAbsZ)
+
+        ppvBasis[b][0] = XMVector3Cross(ppvBasis[a][0],pvCanonicalBasis[cc][0]);
+    }
+
+    ppvBasis[b][0] = XMVector3Normalize(ppvBasis[b][0]);
+
+    if(pfScales[c] < XM_DECOMP_EPSILON)
+    {
+        ppvBasis[c][0] = XMVector3Cross(ppvBasis[a][0],ppvBasis[b][0]);
+    }
+        
+    ppvBasis[c][0] = XMVector3Normalize(ppvBasis[c][0]);
+
+    fDet = XMVectorGetX(XMMatrixDeterminant(matTemp));
+
+    // use Kramer's rule to check for handedness of coordinate system
+    if(fDet < 0.0f)
+    {
+        // switch coordinate system by negating the scale and inverting the basis vector on the x-axis
+        pfScales[a] = -pfScales[a];
+        ppvBasis[a][0] = XMVectorNegate(ppvBasis[a][0]);
+
+        fDet = -fDet;
+    }
+
+    fDet -= 1.0f;
+    fDet *= fDet;
+
+    if(XM_DECOMP_EPSILON < fDet)
+    {
+        // Non-SRT matrix encountered
+        return FALSE;
+    }
+
+    // generate the quaternion from the matrix
+    outRotQuat[0] = XMQuaternionRotationMatrix(matTemp);
+    return TRUE;
+}
+
+#undef XMRANKDECOMPOSE
+#undef XM_DECOMP_EPSILON
+
+//------------------------------------------------------------------------------
+// Transformation operations
+//------------------------------------------------------------------------------
+
+//------------------------------------------------------------------------------
+
+XMFINLINE XMMATRIX XMMatrixIdentity()
+{
+#if defined(_XM_NO_INTRINSICS_) 
+
+    XMMATRIX M;
+    M.r[0] = g_XMIdentityR0.v;
+    M.r[1] = g_XMIdentityR1.v;
+    M.r[2] = g_XMIdentityR2.v;
+    M.r[3] = g_XMIdentityR3.v;
+    return M;
+
+#elif defined(_XM_SSE_INTRINSICS_)
+    XMMATRIX M;
+    M.r[0] = g_XMIdentityR0;
+    M.r[1] = g_XMIdentityR1;
+    M.r[2] = g_XMIdentityR2;
+    M.r[3] = g_XMIdentityR3;
+    return M;
+#else // _XM_VMX128_INTRINSICS_
+#endif // _XM_VMX128_INTRINSICS_
+}
+
+//------------------------------------------------------------------------------
+
+XMFINLINE XMMATRIX XMMatrixSet
+(
+    FLOAT m00, FLOAT m01, FLOAT m02, FLOAT m03,
+    FLOAT m10, FLOAT m11, FLOAT m12, FLOAT m13,
+    FLOAT m20, FLOAT m21, FLOAT m22, FLOAT m23,
+    FLOAT m30, FLOAT m31, FLOAT m32, FLOAT m33
+)
+{
+    XMMATRIX M;
+
+    M.r[0] = XMVectorSet(m00, m01, m02, m03);
+    M.r[1] = XMVectorSet(m10, m11, m12, m13);
+    M.r[2] = XMVectorSet(m20, m21, m22, m23);
+    M.r[3] = XMVectorSet(m30, m31, m32, m33);
+
+    return M;
+}
+
+//------------------------------------------------------------------------------
+
+XMFINLINE XMMATRIX XMMatrixTranslation
+(
+    FLOAT OffsetX, 
+    FLOAT OffsetY, 
+    FLOAT OffsetZ
+)
+{
+#if defined(_XM_NO_INTRINSICS_)
+
+    XMMATRIX M;
+
+    M.m[0][0] = 1.0f;
+    M.m[0][1] = 0.0f;
+    M.m[0][2] = 0.0f;
+    M.m[0][3] = 0.0f;
+
+    M.m[1][0] = 0.0f;
+    M.m[1][1] = 1.0f;
+    M.m[1][2] = 0.0f;
+    M.m[1][3] = 0.0f;
+
+    M.m[2][0] = 0.0f;
+    M.m[2][1] = 0.0f;
+    M.m[2][2] = 1.0f;
+    M.m[2][3] = 0.0f;
+
+    M.m[3][0] = OffsetX;
+    M.m[3][1] = OffsetY;
+    M.m[3][2] = OffsetZ;
+    M.m[3][3] = 1.0f;
+    return M;
+
+#elif defined(_XM_SSE_INTRINSICS_)
+    XMMATRIX M;
+    M.r[0] = g_XMIdentityR0;
+    M.r[1] = g_XMIdentityR1;
+    M.r[2] = g_XMIdentityR2;
+    M.r[3] = _mm_set_ps(1.0f,OffsetZ,OffsetY,OffsetX);
+    return M;
+#else // _XM_VMX128_INTRINSICS_
+#endif // _XM_VMX128_INTRINSICS_
+}
+
+
+//------------------------------------------------------------------------------
+
+XMFINLINE XMMATRIX XMMatrixTranslationFromVector
+(
+    FXMVECTOR Offset
+)
+{
+#if defined(_XM_NO_INTRINSICS_)
+
+    XMMATRIX M;
+    M.m[0][0] = 1.0f;
+    M.m[0][1] = 0.0f;
+    M.m[0][2] = 0.0f;
+    M.m[0][3] = 0.0f;
+
+    M.m[1][0] = 0.0f;
+    M.m[1][1] = 1.0f;
+    M.m[1][2] = 0.0f;
+    M.m[1][3] = 0.0f;
+
+    M.m[2][0] = 0.0f;
+    M.m[2][1] = 0.0f;
+    M.m[2][2] = 1.0f;
+    M.m[2][3] = 0.0f;
+
+    M.m[3][0] = Offset.vector4_f32[0];
+    M.m[3][1] = Offset.vector4_f32[1];
+    M.m[3][2] = Offset.vector4_f32[2];
+    M.m[3][3] = 1.0f;
+    return M;
+
+#elif defined(_XM_SSE_INTRINSICS_)
+    XMVECTOR vTemp = _mm_and_ps(Offset,g_XMMask3);
+    vTemp = _mm_or_ps(vTemp,g_XMIdentityR3);
+    XMMATRIX M;
+    M.r[0] = g_XMIdentityR0;
+    M.r[1] = g_XMIdentityR1;
+    M.r[2] = g_XMIdentityR2;
+    M.r[3] = vTemp;
+    return M;
+#else // _XM_VMX128_INTRINSICS_
+#endif // _XM_VMX128_INTRINSICS_
+}
+
+//------------------------------------------------------------------------------
+
+XMFINLINE XMMATRIX XMMatrixScaling
+(
+    FLOAT ScaleX, 
+    FLOAT ScaleY, 
+    FLOAT ScaleZ
+)
+{
+#if defined(_XM_NO_INTRINSICS_)
+
+    XMMATRIX M;
+
+    M.r[0] = XMVectorSet(ScaleX, 0.0f, 0.0f, 0.0f);
+    M.r[1] = XMVectorSet(0.0f, ScaleY, 0.0f, 0.0f);
+    M.r[2] = XMVectorSet(0.0f, 0.0f, ScaleZ, 0.0f);
+
+    M.r[3] = g_XMIdentityR3.v;
+
+    return M;
+
+#elif defined(_XM_SSE_INTRINSICS_)
+    XMMATRIX M;
+    M.r[0] = _mm_set_ps( 0, 0, 0, ScaleX );
+    M.r[1] = _mm_set_ps( 0, 0, ScaleY, 0 );
+    M.r[2] = _mm_set_ps( 0, ScaleZ, 0, 0 );
+    M.r[3] = g_XMIdentityR3;
+    return M;
+#elif defined(XM_NO_MISALIGNED_VECTOR_ACCESS)
+#endif // _XM_VMX128_INTRINSICS_
+}
+
+//------------------------------------------------------------------------------
+
+XMFINLINE XMMATRIX XMMatrixScalingFromVector
+(
+    FXMVECTOR Scale
+)
+{
+#if defined(_XM_NO_INTRINSICS_)
+    XMMATRIX M;
+    M.m[0][0] = Scale.vector4_f32[0];
+    M.m[0][1] = 0.0f;
+    M.m[0][2] = 0.0f;
+    M.m[0][3] = 0.0f;
+
+    M.m[1][0] = 0.0f;
+    M.m[1][1] = Scale.vector4_f32[1];
+    M.m[1][2] = 0.0f;
+    M.m[1][3] = 0.0f;
+
+    M.m[2][0] = 0.0f;
+    M.m[2][1] = 0.0f;
+    M.m[2][2] = Scale.vector4_f32[2];
+    M.m[2][3] = 0.0f;
+
+    M.m[3][0] = 0.0f;
+    M.m[3][1] = 0.0f;
+    M.m[3][2] = 0.0f;
+    M.m[3][3] = 1.0f;
+    return M;
+
+#elif defined(_XM_SSE_INTRINSICS_)
+    XMMATRIX M;
+    M.r[0] = _mm_and_ps(Scale,g_XMMaskX);
+    M.r[1] = _mm_and_ps(Scale,g_XMMaskY);
+    M.r[2] = _mm_and_ps(Scale,g_XMMaskZ);
+    M.r[3] = g_XMIdentityR3;
+    return M;
+#else // _XM_VMX128_INTRINSICS_
+#endif // _XM_VMX128_INTRINSICS_
+}
+
+//------------------------------------------------------------------------------
+
+XMINLINE XMMATRIX XMMatrixRotationX
+(
+    FLOAT Angle
+)
+{
+#if defined(_XM_NO_INTRINSICS_)
+    XMMATRIX M;
+    FLOAT fSinAngle = sinf(Angle);
+    FLOAT fCosAngle = cosf(Angle);
+
+    M.m[0][0] = 1.0f;
+    M.m[0][1] = 0.0f;
+    M.m[0][2] = 0.0f;
+    M.m[0][3] = 0.0f;
+
+    M.m[1][0] = 0.0f;
+    M.m[1][1] = fCosAngle;
+    M.m[1][2] = fSinAngle;
+    M.m[1][3] = 0.0f;
+
+    M.m[2][0] = 0.0f;
+    M.m[2][1] = -fSinAngle;
+    M.m[2][2] = fCosAngle;
+    M.m[2][3] = 0.0f;
+
+    M.m[3][0] = 0.0f;
+    M.m[3][1] = 0.0f;
+    M.m[3][2] = 0.0f;
+    M.m[3][3] = 1.0f;
+    return M;
+
+#elif defined(_XM_SSE_INTRINSICS_)
+    FLOAT SinAngle = sinf(Angle);
+    FLOAT CosAngle = cosf(Angle);
+
+    XMVECTOR vSin = _mm_set_ss(SinAngle);
+    XMVECTOR vCos = _mm_set_ss(CosAngle);
+    // x = 0,y = cos,z = sin, w = 0
+    vCos = _mm_shuffle_ps(vCos,vSin,_MM_SHUFFLE(3,0,0,3));
+    XMMATRIX M;
+    M.r[0] = g_XMIdentityR0;
+    M.r[1] = vCos;
+    // x = 0,y = sin,z = cos, w = 0
+    vCos = _mm_shuffle_ps(vCos,vCos,_MM_SHUFFLE(3,1,2,0));
+    // x = 0,y = -sin,z = cos, w = 0
+    vCos = _mm_mul_ps(vCos,g_XMNegateY);
+    M.r[2] = vCos;
+    M.r[3] = g_XMIdentityR3;
+    return M;
+#else // _XM_VMX128_INTRINSICS_
+#endif // _XM_VMX128_INTRINSICS_
+}
+
+//------------------------------------------------------------------------------
+
+XMINLINE XMMATRIX XMMatrixRotationY
+(
+    FLOAT Angle
+)
+{
+#if defined(_XM_NO_INTRINSICS_)
+    XMMATRIX M;
+    FLOAT fSinAngle = sinf(Angle);
+    FLOAT fCosAngle = cosf(Angle);
+
+    M.m[0][0] = fCosAngle;
+    M.m[0][1] = 0.0f;
+    M.m[0][2] = -fSinAngle;
+    M.m[0][3] = 0.0f;
+
+    M.m[1][0] = 0.0f;
+    M.m[1][1] = 1.0f;
+    M.m[1][2] = 0.0f;
+    M.m[1][3] = 0.0f;
+
+    M.m[2][0] = fSinAngle;
+    M.m[2][1] = 0.0f;
+    M.m[2][2] = fCosAngle;
+    M.m[2][3] = 0.0f;
+
+    M.m[3][0] = 0.0f;
+    M.m[3][1] = 0.0f;
+    M.m[3][2] = 0.0f;
+    M.m[3][3] = 1.0f;
+    return M;
+#elif defined(_XM_SSE_INTRINSICS_)
+    FLOAT SinAngle = sinf(Angle);
+    FLOAT CosAngle = cosf(Angle);
+
+    XMVECTOR vSin = _mm_set_ss(SinAngle);
+    XMVECTOR vCos = _mm_set_ss(CosAngle);
+    // x = sin,y = 0,z = cos, w = 0
+    vSin = _mm_shuffle_ps(vSin,vCos,_MM_SHUFFLE(3,0,3,0));
+    XMMATRIX M;
+    M.r[2] = vSin;
+    M.r[1] = g_XMIdentityR1;
+    // x = cos,y = 0,z = sin, w = 0
+    vSin = _mm_shuffle_ps(vSin,vSin,_MM_SHUFFLE(3,0,1,2));
+    // x = cos,y = 0,z = -sin, w = 0
+    vSin = _mm_mul_ps(vSin,g_XMNegateZ);
+    M.r[0] = vSin;
+    M.r[3] = g_XMIdentityR3;
+    return M;
+#else // _XM_VMX128_INTRINSICS_
+#endif // _XM_VMX128_INTRINSICS_
+}
+
+//------------------------------------------------------------------------------
+
+XMINLINE XMMATRIX XMMatrixRotationZ
+(
+    FLOAT Angle
+)
+{
+#if defined(_XM_NO_INTRINSICS_)
+    XMMATRIX M;
+    FLOAT fSinAngle = sinf(Angle);
+    FLOAT fCosAngle = cosf(Angle);
+
+    M.m[0][0] = fCosAngle;
+    M.m[0][1] = fSinAngle;
+    M.m[0][2] = 0.0f;
+    M.m[0][3] = 0.0f;
+
+    M.m[1][0] = -fSinAngle;
+    M.m[1][1] = fCosAngle;
+    M.m[1][2] = 0.0f;
+    M.m[1][3] = 0.0f;
+
+    M.m[2][0] = 0.0f;
+    M.m[2][1] = 0.0f;
+    M.m[2][2] = 1.0f;
+    M.m[2][3] = 0.0f;
+
+    M.m[3][0] = 0.0f;
+    M.m[3][1] = 0.0f;
+    M.m[3][2] = 0.0f;
+    M.m[3][3] = 1.0f;
+    return M;
+
+#elif defined(_XM_SSE_INTRINSICS_)
+    FLOAT SinAngle = sinf(Angle);
+    FLOAT CosAngle = cosf(Angle);
+
+    XMVECTOR vSin = _mm_set_ss(SinAngle);
+    XMVECTOR vCos = _mm_set_ss(CosAngle);
+    // x = cos,y = sin,z = 0, w = 0
+    vCos = _mm_unpacklo_ps(vCos,vSin);
+    XMMATRIX M;
+    M.r[0] = vCos;
+    // x = sin,y = cos,z = 0, w = 0
+    vCos = _mm_shuffle_ps(vCos,vCos,_MM_SHUFFLE(3,2,0,1));
+    // x = cos,y = -sin,z = 0, w = 0
+    vCos = _mm_mul_ps(vCos,g_XMNegateX);
+    M.r[1] = vCos;
+    M.r[2] = g_XMIdentityR2;
+    M.r[3] = g_XMIdentityR3;
+    return M;
+#else // _XM_VMX128_INTRINSICS_
+#endif // _XM_VMX128_INTRINSICS_
+}
+
+//------------------------------------------------------------------------------
+
+XMINLINE XMMATRIX XMMatrixRotationRollPitchYaw
+(
+    FLOAT Pitch, 
+    FLOAT Yaw, 
+    FLOAT Roll
+)
+{
+    XMVECTOR Angles;
+    XMMATRIX M;
+
+    Angles = XMVectorSet(Pitch, Yaw, Roll, 0.0f);
+    M = XMMatrixRotationRollPitchYawFromVector(Angles);
+
+    return M;
+}
+
+//------------------------------------------------------------------------------
+
+XMINLINE XMMATRIX XMMatrixRotationRollPitchYawFromVector
+(
+    FXMVECTOR Angles // <Pitch, Yaw, Roll, undefined>
+)
+{
+    XMVECTOR Q;
+    XMMATRIX M;
+    
+    Q = XMQuaternionRotationRollPitchYawFromVector(Angles);
+    M = XMMatrixRotationQuaternion(Q);
+
+    return M;
+}
+
+//------------------------------------------------------------------------------
+
+XMINLINE XMMATRIX XMMatrixRotationNormal
+(
+    FXMVECTOR NormalAxis, 
+    FLOAT    Angle
+)
+{
+#if defined(_XM_NO_INTRINSICS_)
+    XMVECTOR               A;
+    XMVECTOR               N0, N1;
+    XMVECTOR               V0, V1, V2;
+    XMVECTOR               R0, R1, R2;
+    XMVECTOR               C0, C1, C2;
+    XMMATRIX               M;
+    static CONST XMVECTORU32 SwizzleYZXW = {XM_PERMUTE_0Y, XM_PERMUTE_0Z, XM_PERMUTE_0X, XM_PERMUTE_0W};
+    static CONST XMVECTORU32 SwizzleZXYW = {XM_PERMUTE_0Z, XM_PERMUTE_0X, XM_PERMUTE_0Y, XM_PERMUTE_0W};
+    static CONST XMVECTORU32 Permute0Z1Y1Z0X = {XM_PERMUTE_0Z, XM_PERMUTE_1Y, XM_PERMUTE_1Z, XM_PERMUTE_0X};
+    static CONST XMVECTORU32 Permute0Y1X0Y1X = {XM_PERMUTE_0Y, XM_PERMUTE_1X, XM_PERMUTE_0Y, XM_PERMUTE_1X};
+    static CONST XMVECTORU32 Permute0X1X1Y0W = {XM_PERMUTE_0X, XM_PERMUTE_1X, XM_PERMUTE_1Y, XM_PERMUTE_0W};
+    static CONST XMVECTORU32 Permute1Z0Y1W0W = {XM_PERMUTE_1Z, XM_PERMUTE_0Y, XM_PERMUTE_1W, XM_PERMUTE_0W};
+    static CONST XMVECTORU32 Permute1X1Y0Z0W = {XM_PERMUTE_1X, XM_PERMUTE_1Y, XM_PERMUTE_0Z, XM_PERMUTE_0W};
+
+    FLOAT fSinAngle = sinf(Angle);
+    FLOAT fCosAngle = cosf(Angle);
+
+    A = XMVectorSet(fSinAngle, fCosAngle, 1.0f - fCosAngle, 0.0f);
+
+    C2 = XMVectorSplatZ(A);
+    C1 = XMVectorSplatY(A);
+    C0 = XMVectorSplatX(A);
+
+    N0 = XMVectorPermute(NormalAxis, NormalAxis, SwizzleYZXW.v);
+    N1 = XMVectorPermute(NormalAxis, NormalAxis, SwizzleZXYW.v);
+
+    V0 = XMVectorMultiply(C2, N0);
+    V0 = XMVectorMultiply(V0, N1);
+
+    R0 = XMVectorMultiply(C2, NormalAxis);
+    R0 = XMVectorMultiplyAdd(R0, NormalAxis, C1);
+
+    R1 = XMVectorMultiplyAdd(C0, NormalAxis, V0);
+    R2 = XMVectorNegativeMultiplySubtract(C0, NormalAxis, V0);
+
+    V0 = XMVectorSelect(A, R0, g_XMSelect1110.v);
+    V1 = XMVectorPermute(R1, R2, Permute0Z1Y1Z0X.v);
+    V2 = XMVectorPermute(R1, R2, Permute0Y1X0Y1X.v);
+
+    M.r[0] = XMVectorPermute(V0, V1, Permute0X1X1Y0W.v);
+    M.r[1] = XMVectorPermute(V0, V1, Permute1Z0Y1W0W.v);
+    M.r[2] = XMVectorPermute(V0, V2, Permute1X1Y0Z0W.v);
+    M.r[3] = g_XMIdentityR3.v;
+
+    return M;
+
+#elif defined(_XM_SSE_INTRINSICS_)
+    XMVECTOR               N0, N1;
+    XMVECTOR               V0, V1, V2;
+    XMVECTOR               R0, R1, R2;
+    XMVECTOR               C0, C1, C2;
+    XMMATRIX               M;
+
+    FLOAT fSinAngle = sinf(Angle);
+    FLOAT fCosAngle = cosf(Angle);
+
+    C2 = _mm_set_ps1(1.0f - fCosAngle);
+    C1 = _mm_set_ps1(fCosAngle);
+    C0 = _mm_set_ps1(fSinAngle);
+
+    N0 = _mm_shuffle_ps(NormalAxis,NormalAxis,_MM_SHUFFLE(3,0,2,1));
+//    N0 = XMVectorPermute(NormalAxis, NormalAxis, SwizzleYZXW);
+    N1 = _mm_shuffle_ps(NormalAxis,NormalAxis,_MM_SHUFFLE(3,1,0,2));
+//    N1 = XMVectorPermute(NormalAxis, NormalAxis, SwizzleZXYW);
+
+    V0 = _mm_mul_ps(C2, N0);
+    V0 = _mm_mul_ps(V0, N1);
+
+    R0 = _mm_mul_ps(C2, NormalAxis);
+    R0 = _mm_mul_ps(R0, NormalAxis);
+    R0 = _mm_add_ps(R0, C1);
+
+    R1 = _mm_mul_ps(C0, NormalAxis);
+    R1 = _mm_add_ps(R1, V0);
+    R2 = _mm_mul_ps(C0, NormalAxis);
+    R2 = _mm_sub_ps(V0,R2);
+
+    V0 = _mm_and_ps(R0,g_XMMask3);
+//    V0 = XMVectorSelect(A, R0, g_XMSelect1110);
+    V1 = _mm_shuffle_ps(R1,R2,_MM_SHUFFLE(2,1,2,0));
+    V1 = _mm_shuffle_ps(V1,V1,_MM_SHUFFLE(0,3,2,1));
+//    V1 = XMVectorPermute(R1, R2, Permute0Z1Y1Z0X);
+    V2 = _mm_shuffle_ps(R1,R2,_MM_SHUFFLE(0,0,1,1));
+    V2 = _mm_shuffle_ps(V2,V2,_MM_SHUFFLE(2,0,2,0));
+//    V2 = XMVectorPermute(R1, R2, Permute0Y1X0Y1X);
+
+    R2 = _mm_shuffle_ps(V0,V1,_MM_SHUFFLE(1,0,3,0));
+    R2 = _mm_shuffle_ps(R2,R2,_MM_SHUFFLE(1,3,2,0));
+    M.r[0] = R2;
+//    M.r[0] = XMVectorPermute(V0, V1, Permute0X1X1Y0W);
+    R2 = _mm_shuffle_ps(V0,V1,_MM_SHUFFLE(3,2,3,1));
+    R2 = _mm_shuffle_ps(R2,R2,_MM_SHUFFLE(1,3,0,2));
+    M.r[1] = R2;
+//    M.r[1] = XMVectorPermute(V0, V1, Permute1Z0Y1W0W);
+    V2 = _mm_shuffle_ps(V2,V0,_MM_SHUFFLE(3,2,1,0));
+//    R2 = _mm_shuffle_ps(R2,R2,_MM_SHUFFLE(3,2,1,0));
+    M.r[2] = V2;
+//    M.r[2] = XMVectorPermute(V0, V2, Permute1X1Y0Z0W);
+    M.r[3] = g_XMIdentityR3;
+    return M;
+#else // _XM_VMX128_INTRINSICS_
+#endif // _XM_VMX128_INTRINSICS_
+}
+
+//------------------------------------------------------------------------------
+
+XMINLINE XMMATRIX XMMatrixRotationAxis
+(
+    FXMVECTOR Axis, 
+    FLOAT    Angle
+)
+{
+#if defined(_XM_NO_INTRINSICS_)
+
+    XMVECTOR Normal;
+    XMMATRIX M;
+
+    XMASSERT(!XMVector3Equal(Axis, XMVectorZero()));
+    XMASSERT(!XMVector3IsInfinite(Axis));
+
+    Normal = XMVector3Normalize(Axis);
+    M = XMMatrixRotationNormal(Normal, Angle);
+
+    return M;
+
+#elif defined(_XM_SSE_INTRINSICS_)
+    XMASSERT(!XMVector3Equal(Axis, XMVectorZero()));
+    XMASSERT(!XMVector3IsInfinite(Axis));
+    XMVECTOR Normal = XMVector3Normalize(Axis);
+    XMMATRIX M = XMMatrixRotationNormal(Normal, Angle);
+    return M;
+#else // _XM_VMX128_INTRINSICS_
+#endif // _XM_VMX128_INTRINSICS_
+}
+
+//------------------------------------------------------------------------------
+
+XMFINLINE XMMATRIX XMMatrixRotationQuaternion
+(
+    FXMVECTOR Quaternion
+)
+{
+#if defined(_XM_NO_INTRINSICS_)
+
+    XMMATRIX               M;
+    XMVECTOR               Q0, Q1;
+    XMVECTOR               V0, V1, V2;
+    XMVECTOR               R0, R1, R2;
+    static CONST XMVECTOR  Constant1110 = {1.0f, 1.0f, 1.0f, 0.0f};
+    static CONST XMVECTORU32 SwizzleXXYW = {XM_PERMUTE_0X, XM_PERMUTE_0X, XM_PERMUTE_0Y, XM_PERMUTE_0W};
+    static CONST XMVECTORU32 SwizzleZYZW = {XM_PERMUTE_0Z, XM_PERMUTE_0Y, XM_PERMUTE_0Z, XM_PERMUTE_0W};
+    static CONST XMVECTORU32 SwizzleYZXW = {XM_PERMUTE_0Y, XM_PERMUTE_0Z, XM_PERMUTE_0X, XM_PERMUTE_0W};
+    static CONST XMVECTORU32 Permute0Y0X0X1W = {XM_PERMUTE_0Y, XM_PERMUTE_0X, XM_PERMUTE_0X, XM_PERMUTE_1W};
+    static CONST XMVECTORU32 Permute0Z0Z0Y1W = {XM_PERMUTE_0Z, XM_PERMUTE_0Z, XM_PERMUTE_0Y, XM_PERMUTE_1W};
+    static CONST XMVECTORU32 Permute0Y1X1Y0Z = {XM_PERMUTE_0Y, XM_PERMUTE_1X, XM_PERMUTE_1Y, XM_PERMUTE_0Z};
+    static CONST XMVECTORU32 Permute0X1Z0X1Z = {XM_PERMUTE_0X, XM_PERMUTE_1Z, XM_PERMUTE_0X, XM_PERMUTE_1Z};
+    static CONST XMVECTORU32 Permute0X1X1Y0W = {XM_PERMUTE_0X, XM_PERMUTE_1X, XM_PERMUTE_1Y, XM_PERMUTE_0W};
+    static CONST XMVECTORU32 Permute1Z0Y1W0W = {XM_PERMUTE_1Z, XM_PERMUTE_0Y, XM_PERMUTE_1W, XM_PERMUTE_0W};
+    static CONST XMVECTORU32 Permute1X1Y0Z0W = {XM_PERMUTE_1X, XM_PERMUTE_1Y, XM_PERMUTE_0Z, XM_PERMUTE_0W};
+
+    Q0 = XMVectorAdd(Quaternion, Quaternion);
+    Q1 = XMVectorMultiply(Quaternion, Q0);
+
+    V0 = XMVectorPermute(Q1, Constant1110, Permute0Y0X0X1W.v);
+    V1 = XMVectorPermute(Q1, Constant1110, Permute0Z0Z0Y1W.v);
+    R0 = XMVectorSubtract(Constant1110, V0);
+    R0 = XMVectorSubtract(R0, V1);
+
+    V0 = XMVectorPermute(Quaternion, Quaternion, SwizzleXXYW.v);
+    V1 = XMVectorPermute(Q0, Q0, SwizzleZYZW.v);
+    V0 = XMVectorMultiply(V0, V1);
+
+    V1 = XMVectorSplatW(Quaternion);
+    V2 = XMVectorPermute(Q0, Q0, SwizzleYZXW.v);
+    V1 = XMVectorMultiply(V1, V2);
+
+    R1 = XMVectorAdd(V0, V1);
+    R2 = XMVectorSubtract(V0, V1);
+
+    V0 = XMVectorPermute(R1, R2, Permute0Y1X1Y0Z.v);
+    V1 = XMVectorPermute(R1, R2, Permute0X1Z0X1Z.v);
+
+    M.r[0] = XMVectorPermute(R0, V0, Permute0X1X1Y0W.v);
+    M.r[1] = XMVectorPermute(R0, V0, Permute1Z0Y1W0W.v);
+    M.r[2] = XMVectorPermute(R0, V1, Permute1X1Y0Z0W.v);
+    M.r[3] = g_XMIdentityR3.v;
+
+    return M;
+
+#elif defined(_XM_SSE_INTRINSICS_)
+    XMMATRIX M;
+    XMVECTOR               Q0, Q1;
+    XMVECTOR               V0, V1, V2;
+    XMVECTOR               R0, R1, R2;
+    static CONST XMVECTORF32  Constant1110 = {1.0f, 1.0f, 1.0f, 0.0f};
+
+    Q0 = _mm_add_ps(Quaternion,Quaternion);
+    Q1 = _mm_mul_ps(Quaternion,Q0);
+
+    V0 = _mm_shuffle_ps(Q1,Q1,_MM_SHUFFLE(3,0,0,1));
+    V0 = _mm_and_ps(V0,g_XMMask3);
+//    V0 = XMVectorPermute(Q1, Constant1110,Permute0Y0X0X1W);
+    V1 = _mm_shuffle_ps(Q1,Q1,_MM_SHUFFLE(3,1,2,2));
+    V1 = _mm_and_ps(V1,g_XMMask3);
+//    V1 = XMVectorPermute(Q1, Constant1110,Permute0Z0Z0Y1W);
+    R0 = _mm_sub_ps(Constant1110,V0);
+    R0 = _mm_sub_ps(R0, V1);
+
+    V0 = _mm_shuffle_ps(Quaternion,Quaternion,_MM_SHUFFLE(3,1,0,0));
+//    V0 = XMVectorPermute(Quaternion, Quaternion,SwizzleXXYW);
+    V1 = _mm_shuffle_ps(Q0,Q0,_MM_SHUFFLE(3,2,1,2));
+//    V1 = XMVectorPermute(Q0, Q0,SwizzleZYZW);
+    V0 = _mm_mul_ps(V0, V1);
+
+    V1 = _mm_shuffle_ps(Quaternion,Quaternion,_MM_SHUFFLE(3,3,3,3));
+//    V1 = XMVectorSplatW(Quaternion);
+    V2 = _mm_shuffle_ps(Q0,Q0,_MM_SHUFFLE(3,0,2,1));
+//    V2 = XMVectorPermute(Q0, Q0,SwizzleYZXW);
+    V1 = _mm_mul_ps(V1, V2);
+
+    R1 = _mm_add_ps(V0, V1);
+    R2 = _mm_sub_ps(V0, V1);
+
+    V0 = _mm_shuffle_ps(R1,R2,_MM_SHUFFLE(1,0,2,1));
+    V0 = _mm_shuffle_ps(V0,V0,_MM_SHUFFLE(1,3,2,0));
+//    V0 = XMVectorPermute(R1, R2,Permute0Y1X1Y0Z);
+    V1 = _mm_shuffle_ps(R1,R2,_MM_SHUFFLE(2,2,0,0));
+    V1 = _mm_shuffle_ps(V1,V1,_MM_SHUFFLE(2,0,2,0));
+//    V1 = XMVectorPermute(R1, R2,Permute0X1Z0X1Z);
+
+    Q1 = _mm_shuffle_ps(R0,V0,_MM_SHUFFLE(1,0,3,0));
+    Q1 = _mm_shuffle_ps(Q1,Q1,_MM_SHUFFLE(1,3,2,0));
+    M.r[0] = Q1;
+//    M.r[0] = XMVectorPermute(R0, V0,Permute0X1X1Y0W);
+    Q1 = _mm_shuffle_ps(R0,V0,_MM_SHUFFLE(3,2,3,1));
+    Q1 = _mm_shuffle_ps(Q1,Q1,_MM_SHUFFLE(1,3,0,2));
+    M.r[1] = Q1;
+//    M.r[1] = XMVectorPermute(R0, V0,Permute1Z0Y1W0W);
+    Q1 = _mm_shuffle_ps(V1,R0,_MM_SHUFFLE(3,2,1,0));
+    M.r[2] = Q1;
+//    M.r[2] = XMVectorPermute(R0, V1,Permute1X1Y0Z0W);
+    M.r[3] = g_XMIdentityR3;
+    return M;
+#else // _XM_VMX128_INTRINSICS_
+#endif // _XM_VMX128_INTRINSICS_
+}
+
+//------------------------------------------------------------------------------
+
+XMINLINE XMMATRIX XMMatrixTransformation2D
+(
+    FXMVECTOR ScalingOrigin, 
+    FLOAT    ScalingOrientation, 
+    FXMVECTOR Scaling, 
+    FXMVECTOR RotationOrigin, 
+    FLOAT    Rotation, 
+    CXMVECTOR Translation
+)
+{
+#if defined(_XM_NO_INTRINSICS_)
+
+    XMMATRIX M;
+    XMVECTOR VScaling;
+    XMVECTOR NegScalingOrigin;
+    XMVECTOR VScalingOrigin;
+    XMMATRIX MScalingOriginI;
+    XMMATRIX MScalingOrientation;
+    XMMATRIX MScalingOrientationT;
+    XMMATRIX MScaling;
+    XMVECTOR VRotationOrigin;
+    XMMATRIX MRotation;
+    XMVECTOR VTranslation;
+
+    // M = Inverse(MScalingOrigin) * Transpose(MScalingOrientation) * MScaling * MScalingOrientation *
+    //         MScalingOrigin * Inverse(MRotationOrigin) * MRotation * MRotationOrigin * MTranslation;
+
+    VScalingOrigin       = XMVectorSelect(g_XMSelect1100.v, ScalingOrigin, g_XMSelect1100.v);
+    NegScalingOrigin     = XMVectorNegate(VScalingOrigin);
+
+    MScalingOriginI      = XMMatrixTranslationFromVector(NegScalingOrigin);
+    MScalingOrientation  = XMMatrixRotationZ(ScalingOrientation);
+    MScalingOrientationT = XMMatrixTranspose(MScalingOrientation);
+    VScaling             = XMVectorSelect(g_XMOne.v, Scaling, g_XMSelect1100.v);
+    MScaling             = XMMatrixScalingFromVector(VScaling);
+    VRotationOrigin      = XMVectorSelect(g_XMSelect1100.v, RotationOrigin, g_XMSelect1100.v);
+    MRotation            = XMMatrixRotationZ(Rotation);
+    VTranslation         = XMVectorSelect(g_XMSelect1100.v, Translation,g_XMSelect1100.v);
+
+    M      = XMMatrixMultiply(MScalingOriginI, MScalingOrientationT);
+    M      = XMMatrixMultiply(M, MScaling);
+    M      = XMMatrixMultiply(M, MScalingOrientation);
+    M.r[3] = XMVectorAdd(M.r[3], VScalingOrigin);
+    M.r[3] = XMVectorSubtract(M.r[3], VRotationOrigin);
+    M      = XMMatrixMultiply(M, MRotation);
+    M.r[3] = XMVectorAdd(M.r[3], VRotationOrigin);
+    M.r[3] = XMVectorAdd(M.r[3], VTranslation);
+
+    return M;
+
+#elif defined(_XM_SSE_INTRINSICS_)
+    XMMATRIX M;
+    XMVECTOR VScaling;
+    XMVECTOR NegScalingOrigin;
+    XMVECTOR VScalingOrigin;
+    XMMATRIX MScalingOriginI;
+    XMMATRIX MScalingOrientation;
+    XMMATRIX MScalingOrientationT;
+    XMMATRIX MScaling;
+    XMVECTOR VRotationOrigin;
+    XMMATRIX MRotation;
+    XMVECTOR VTranslation;
+
+    // M = Inverse(MScalingOrigin) * Transpose(MScalingOrientation) * MScaling * MScalingOrientation *
+    //         MScalingOrigin * Inverse(MRotationOrigin) * MRotation * MRotationOrigin * MTranslation;
+    static const XMVECTORU32 Mask2 = {0xFFFFFFFF,0xFFFFFFFF,0,0};
+    static const XMVECTORF32 ZWOne = {0,0,1.0f,1.0f};
+
+    VScalingOrigin       = _mm_and_ps(ScalingOrigin, Mask2);
+    NegScalingOrigin     = XMVectorNegate(VScalingOrigin);
+
+    MScalingOriginI      = XMMatrixTranslationFromVector(NegScalingOrigin);
+    MScalingOrientation  = XMMatrixRotationZ(ScalingOrientation);
+    MScalingOrientationT = XMMatrixTranspose(MScalingOrientation);
+    VScaling             = _mm_and_ps(Scaling, Mask2);
+    VScaling = _mm_or_ps(VScaling,ZWOne);
+    MScaling             = XMMatrixScalingFromVector(VScaling);
+    VRotationOrigin      = _mm_and_ps(RotationOrigin, Mask2);
+    MRotation            = XMMatrixRotationZ(Rotation);
+    VTranslation         = _mm_and_ps(Translation, Mask2);
+
+    M      = XMMatrixMultiply(MScalingOriginI, MScalingOrientationT);
+    M      = XMMatrixMultiply(M, MScaling);
+    M      = XMMatrixMultiply(M, MScalingOrientation);
+    M.r[3] = XMVectorAdd(M.r[3], VScalingOrigin);
+    M.r[3] = XMVectorSubtract(M.r[3], VRotationOrigin);
+    M      = XMMatrixMultiply(M, MRotation);
+    M.r[3] = XMVectorAdd(M.r[3], VRotationOrigin);
+    M.r[3] = XMVectorAdd(M.r[3], VTranslation);
+
+    return M;
+#else // _XM_VMX128_INTRINSICS_
+#endif // _XM_VMX128_INTRINSICS_
+}
+
+//------------------------------------------------------------------------------
+
+XMINLINE XMMATRIX XMMatrixTransformation
+(
+    FXMVECTOR ScalingOrigin, 
+    FXMVECTOR ScalingOrientationQuaternion, 
+    FXMVECTOR Scaling, 
+    CXMVECTOR RotationOrigin, 
+    CXMVECTOR RotationQuaternion, 
+    CXMVECTOR Translation
+)
+{
+#if defined(_XM_NO_INTRINSICS_)
+
+    XMMATRIX M;
+    XMVECTOR NegScalingOrigin;
+    XMVECTOR VScalingOrigin;
+    XMMATRIX MScalingOriginI;
+    XMMATRIX MScalingOrientation;
+    XMMATRIX MScalingOrientationT;
+    XMMATRIX MScaling;
+    XMVECTOR VRotationOrigin;
+    XMMATRIX MRotation;
+    XMVECTOR VTranslation;
+
+    // M = Inverse(MScalingOrigin) * Transpose(MScalingOrientation) * MScaling * MScalingOrientation *
+    //         MScalingOrigin * Inverse(MRotationOrigin) * MRotation * MRotationOrigin * MTranslation;
+
+    VScalingOrigin       = XMVectorSelect(g_XMSelect1110.v, ScalingOrigin, g_XMSelect1110.v);
+    NegScalingOrigin     = XMVectorNegate(ScalingOrigin);
+
+    MScalingOriginI      = XMMatrixTranslationFromVector(NegScalingOrigin);
+    MScalingOrientation  = XMMatrixRotationQuaternion(ScalingOrientationQuaternion);
+    MScalingOrientationT = XMMatrixTranspose(MScalingOrientation);
+    MScaling             = XMMatrixScalingFromVector(Scaling);
+    VRotationOrigin      = XMVectorSelect(g_XMSelect1110.v, RotationOrigin, g_XMSelect1110.v);
+    MRotation            = XMMatrixRotationQuaternion(RotationQuaternion);
+    VTranslation         = XMVectorSelect(g_XMSelect1110.v, Translation, g_XMSelect1110.v);
+
+    M      = XMMatrixMultiply(MScalingOriginI, MScalingOrientationT);
+    M      = XMMatrixMultiply(M, MScaling);
+    M      = XMMatrixMultiply(M, MScalingOrientation);
+    M.r[3] = XMVectorAdd(M.r[3], VScalingOrigin);
+    M.r[3] = XMVectorSubtract(M.r[3], VRotationOrigin);
+    M      = XMMatrixMultiply(M, MRotation);
+    M.r[3] = XMVectorAdd(M.r[3], VRotationOrigin);
+    M.r[3] = XMVectorAdd(M.r[3], VTranslation);
+
+    return M;
+
+#elif defined(_XM_SSE_INTRINSICS_)
+    XMMATRIX M;
+    XMVECTOR NegScalingOrigin;
+    XMVECTOR VScalingOrigin;
+    XMMATRIX MScalingOriginI;
+    XMMATRIX MScalingOrientation;
+    XMMATRIX MScalingOrientationT;
+    XMMATRIX MScaling;
+    XMVECTOR VRotationOrigin;
+    XMMATRIX MRotation;
+    XMVECTOR VTranslation;
+
+    // M = Inverse(MScalingOrigin) * Transpose(MScalingOrientation) * MScaling * MScalingOrientation *
+    //         MScalingOrigin * Inverse(MRotationOrigin) * MRotation * MRotationOrigin * MTranslation;
+
+    VScalingOrigin       = _mm_and_ps(ScalingOrigin,g_XMMask3);
+    NegScalingOrigin     = XMVectorNegate(ScalingOrigin);
+
+    MScalingOriginI      = XMMatrixTranslationFromVector(NegScalingOrigin);
+    MScalingOrientation  = XMMatrixRotationQuaternion(ScalingOrientationQuaternion);
+    MScalingOrientationT = XMMatrixTranspose(MScalingOrientation);
+    MScaling             = XMMatrixScalingFromVector(Scaling);
+    VRotationOrigin      = _mm_and_ps(RotationOrigin,g_XMMask3);
+    MRotation            = XMMatrixRotationQuaternion(RotationQuaternion);
+    VTranslation         = _mm_and_ps(Translation,g_XMMask3);
+
+    M      = XMMatrixMultiply(MScalingOriginI, MScalingOrientationT);
+    M      = XMMatrixMultiply(M, MScaling);
+    M      = XMMatrixMultiply(M, MScalingOrientation);
+    M.r[3] = XMVectorAdd(M.r[3], VScalingOrigin);
+    M.r[3] = XMVectorSubtract(M.r[3], VRotationOrigin);
+    M      = XMMatrixMultiply(M, MRotation);
+    M.r[3] = XMVectorAdd(M.r[3], VRotationOrigin);
+    M.r[3] = XMVectorAdd(M.r[3], VTranslation);
+
+    return M;
+#else // _XM_VMX128_INTRINSICS_
+#endif // _XM_VMX128_INTRINSICS_
+}
+
+//------------------------------------------------------------------------------
+
+XMINLINE XMMATRIX XMMatrixAffineTransformation2D
+(
+    FXMVECTOR Scaling, 
+    FXMVECTOR RotationOrigin, 
+    FLOAT    Rotation, 
+    FXMVECTOR Translation
+)
+{
+#if defined(_XM_NO_INTRINSICS_)
+
+    XMMATRIX M;
+    XMVECTOR VScaling;
+    XMMATRIX MScaling;
+    XMVECTOR VRotationOrigin;
+    XMMATRIX MRotation;
+    XMVECTOR VTranslation;
+
+    // M = MScaling * Inverse(MRotationOrigin) * MRotation * MRotationOrigin * MTranslation;
+
+    VScaling             = XMVectorSelect(g_XMOne.v, Scaling, g_XMSelect1100.v);
+    MScaling             = XMMatrixScalingFromVector(VScaling);
+    VRotationOrigin      = XMVectorSelect(g_XMSelect1100.v, RotationOrigin, g_XMSelect1100.v);
+    MRotation            = XMMatrixRotationZ(Rotation);
+    VTranslation         = XMVectorSelect(g_XMSelect1100.v, Translation,g_XMSelect1100.v);
+
+    M      = MScaling;
+    M.r[3] = XMVectorSubtract(M.r[3], VRotationOrigin);
+    M      = XMMatrixMultiply(M, MRotation);
+    M.r[3] = XMVectorAdd(M.r[3], VRotationOrigin);
+    M.r[3] = XMVectorAdd(M.r[3], VTranslation);
+
+    return M;
+
+#elif defined(_XM_SSE_INTRINSICS_)
+    XMMATRIX M;
+    XMVECTOR VScaling;
+    XMMATRIX MScaling;
+    XMVECTOR VRotationOrigin;
+    XMMATRIX MRotation;
+    XMVECTOR VTranslation;
+    static const XMVECTORU32 Mask2 = {0xFFFFFFFFU,0xFFFFFFFFU,0,0};
+    static const XMVECTORF32 ZW1 = {0,0,1.0f,1.0f};
+
+    // M = MScaling * Inverse(MRotationOrigin) * MRotation * MRotationOrigin * MTranslation;
+
+    VScaling = _mm_and_ps(Scaling, Mask2);
+    VScaling = _mm_or_ps(VScaling, ZW1);
+    MScaling = XMMatrixScalingFromVector(VScaling);
+    VRotationOrigin = _mm_and_ps(RotationOrigin, Mask2);
+    MRotation = XMMatrixRotationZ(Rotation);
+    VTranslation = _mm_and_ps(Translation, Mask2);
+
+    M      = MScaling;
+    M.r[3] = _mm_sub_ps(M.r[3], VRotationOrigin);
+    M      = XMMatrixMultiply(M, MRotation);
+    M.r[3] = _mm_add_ps(M.r[3], VRotationOrigin);
+    M.r[3] = _mm_add_ps(M.r[3], VTranslation);
+    return M;
+#else // _XM_VMX128_INTRINSICS_
+#endif // _XM_VMX128_INTRINSICS_
+}
+
+//------------------------------------------------------------------------------
+
+XMINLINE XMMATRIX XMMatrixAffineTransformation
+(
+    FXMVECTOR Scaling, 
+    FXMVECTOR RotationOrigin, 
+    FXMVECTOR RotationQuaternion, 
+    CXMVECTOR Translation
+)
+{
+#if defined(_XM_NO_INTRINSICS_)
+
+    XMMATRIX M;
+    XMMATRIX MScaling;
+    XMVECTOR VRotationOrigin;
+    XMMATRIX MRotation;
+    XMVECTOR VTranslation;
+
+    // M = MScaling * Inverse(MRotationOrigin) * MRotation * MRotationOrigin * MTranslation;
+
+    MScaling            = XMMatrixScalingFromVector(Scaling);
+    VRotationOrigin     = XMVectorSelect(g_XMSelect1110.v, RotationOrigin,g_XMSelect1110.v);
+    MRotation           = XMMatrixRotationQuaternion(RotationQuaternion);
+    VTranslation        = XMVectorSelect(g_XMSelect1110.v, Translation,g_XMSelect1110.v);
+
+    M      = MScaling;
+    M.r[3] = XMVectorSubtract(M.r[3], VRotationOrigin);
+    M      = XMMatrixMultiply(M, MRotation);
+    M.r[3] = XMVectorAdd(M.r[3], VRotationOrigin);
+    M.r[3] = XMVectorAdd(M.r[3], VTranslation);
+
+    return M;
+
+#elif defined(_XM_SSE_INTRINSICS_)
+    XMMATRIX M;
+    XMMATRIX MScaling;
+    XMVECTOR VRotationOrigin;
+    XMMATRIX MRotation;
+    XMVECTOR VTranslation;
+
+    // M = MScaling * Inverse(MRotationOrigin) * MRotation * MRotationOrigin * MTranslation;
+
+    MScaling            = XMMatrixScalingFromVector(Scaling);
+    VRotationOrigin     = _mm_and_ps(RotationOrigin,g_XMMask3);
+    MRotation           = XMMatrixRotationQuaternion(RotationQuaternion);
+    VTranslation        = _mm_and_ps(Translation,g_XMMask3);
+
+    M      = MScaling;
+    M.r[3] = _mm_sub_ps(M.r[3], VRotationOrigin);
+    M      = XMMatrixMultiply(M, MRotation);
+    M.r[3] = _mm_add_ps(M.r[3], VRotationOrigin);
+    M.r[3] = _mm_add_ps(M.r[3], VTranslation);
+
+    return M;
+#else // _XM_VMX128_INTRINSICS_
+#endif // _XM_VMX128_INTRINSICS_
+}
+
+//------------------------------------------------------------------------------
+
+XMFINLINE XMMATRIX XMMatrixReflect
+(
+    FXMVECTOR ReflectionPlane
+)
+{
+#if defined(_XM_NO_INTRINSICS_)
+
+    XMVECTOR               P;
+    XMVECTOR               S;
+    XMVECTOR               A, B, C, D;
+    XMMATRIX               M;
+    static CONST XMVECTOR  NegativeTwo = {-2.0f, -2.0f, -2.0f, 0.0f};
+
+    XMASSERT(!XMVector3Equal(ReflectionPlane, XMVectorZero()));
+    XMASSERT(!XMPlaneIsInfinite(ReflectionPlane));
+
+    P = XMPlaneNormalize(ReflectionPlane);
+    S = XMVectorMultiply(P, NegativeTwo);
+
+    A = XMVectorSplatX(P);
+    B = XMVectorSplatY(P);
+    C = XMVectorSplatZ(P);
+    D = XMVectorSplatW(P);
+
+    M.r[0] = XMVectorMultiplyAdd(A, S, g_XMIdentityR0.v);
+    M.r[1] = XMVectorMultiplyAdd(B, S, g_XMIdentityR1.v);
+    M.r[2] = XMVectorMultiplyAdd(C, S, g_XMIdentityR2.v);
+    M.r[3] = XMVectorMultiplyAdd(D, S, g_XMIdentityR3.v);
+
+    return M;
+
+#elif defined(_XM_SSE_INTRINSICS_)
+    XMMATRIX M;
+    static CONST XMVECTORF32 NegativeTwo = {-2.0f, -2.0f, -2.0f, 0.0f};
+
+    XMASSERT(!XMVector3Equal(ReflectionPlane, XMVectorZero()));
+    XMASSERT(!XMPlaneIsInfinite(ReflectionPlane));
+
+    XMVECTOR P = XMPlaneNormalize(ReflectionPlane);
+    XMVECTOR S = _mm_mul_ps(P,NegativeTwo);
+    XMVECTOR X = _mm_shuffle_ps(P,P,_MM_SHUFFLE(0,0,0,0));
+    XMVECTOR Y = _mm_shuffle_ps(P,P,_MM_SHUFFLE(1,1,1,1));
+    XMVECTOR Z = _mm_shuffle_ps(P,P,_MM_SHUFFLE(2,2,2,2));
+    P = _mm_shuffle_ps(P,P,_MM_SHUFFLE(3,3,3,3));
+    X = _mm_mul_ps(X,S);
+    Y = _mm_mul_ps(Y,S);
+    Z = _mm_mul_ps(Z,S);
+    P = _mm_mul_ps(P,S);
+    X = _mm_add_ps(X,g_XMIdentityR0);
+    Y = _mm_add_ps(Y,g_XMIdentityR1);
+    Z = _mm_add_ps(Z,g_XMIdentityR2);
+    P = _mm_add_ps(P,g_XMIdentityR3);
+    M.r[0] = X;
+    M.r[1] = Y;
+    M.r[2] = Z;
+    M.r[3] = P;
+    return M;
+#else // _XM_VMX128_INTRINSICS_
+#endif // _XM_VMX128_INTRINSICS_
+}
+
+//------------------------------------------------------------------------------
+
+XMFINLINE XMMATRIX XMMatrixShadow
+(
+    FXMVECTOR ShadowPlane, 
+    FXMVECTOR LightPosition
+)
+{
+#if defined(_XM_NO_INTRINSICS_)
+
+    XMVECTOR               P;
+    XMVECTOR               Dot;
+    XMVECTOR               A, B, C, D;
+    XMMATRIX               M;
+    static CONST XMVECTORU32 Select0001 = {XM_SELECT_0, XM_SELECT_0, XM_SELECT_0, XM_SELECT_1};
+
+    XMASSERT(!XMVector3Equal(ShadowPlane, XMVectorZero()));
+    XMASSERT(!XMPlaneIsInfinite(ShadowPlane));
+
+    P = XMPlaneNormalize(ShadowPlane);
+    Dot = XMPlaneDot(P, LightPosition);
+    P = XMVectorNegate(P);
+    D = XMVectorSplatW(P);
+    C = XMVectorSplatZ(P);
+    B = XMVectorSplatY(P);
+    A = XMVectorSplatX(P);
+    Dot = XMVectorSelect(Select0001.v, Dot, Select0001.v);
+    M.r[3] = XMVectorMultiplyAdd(D, LightPosition, Dot);
+    Dot = XMVectorRotateLeft(Dot, 1);
+    M.r[2] = XMVectorMultiplyAdd(C, LightPosition, Dot);
+    Dot = XMVectorRotateLeft(Dot, 1);
+    M.r[1] = XMVectorMultiplyAdd(B, LightPosition, Dot);
+    Dot = XMVectorRotateLeft(Dot, 1);
+    M.r[0] = XMVectorMultiplyAdd(A, LightPosition, Dot);
+    return M;
+
+#elif defined(_XM_SSE_INTRINSICS_)
+    XMMATRIX M;
+    XMASSERT(!XMVector3Equal(ShadowPlane, XMVectorZero()));
+    XMASSERT(!XMPlaneIsInfinite(ShadowPlane));
+    XMVECTOR P = XMPlaneNormalize(ShadowPlane);
+    XMVECTOR Dot = XMPlaneDot(P,LightPosition);
+    // Negate
+    P = _mm_mul_ps(P,g_XMNegativeOne);
+    XMVECTOR X = _mm_shuffle_ps(P,P,_MM_SHUFFLE(0,0,0,0));
+    XMVECTOR Y = _mm_shuffle_ps(P,P,_MM_SHUFFLE(1,1,1,1));
+    XMVECTOR Z = _mm_shuffle_ps(P,P,_MM_SHUFFLE(2,2,2,2));
+    P = _mm_shuffle_ps(P,P,_MM_SHUFFLE(3,3,3,3));
+    Dot = _mm_and_ps(Dot,g_XMMaskW);
+    X = _mm_mul_ps(X,LightPosition);
+    Y = _mm_mul_ps(Y,LightPosition);
+    Z = _mm_mul_ps(Z,LightPosition);
+    P = _mm_mul_ps(P,LightPosition);
+    P = _mm_add_ps(P,Dot);
+    Dot = _mm_shuffle_ps(Dot,Dot,_MM_SHUFFLE(0,3,2,1));
+    Z = _mm_add_ps(Z,Dot);
+    Dot = _mm_shuffle_ps(Dot,Dot,_MM_SHUFFLE(0,3,2,1));
+    Y = _mm_add_ps(Y,Dot);
+    Dot = _mm_shuffle_ps(Dot,Dot,_MM_SHUFFLE(0,3,2,1));
+    X = _mm_add_ps(X,Dot);
+    // Store the resulting matrix
+    M.r[0] = X;
+    M.r[1] = Y;
+    M.r[2] = Z;
+    M.r[3] = P;
+    return M;
+#else // _XM_VMX128_INTRINSICS_
+#endif // _XM_VMX128_INTRINSICS_
+}
+
+//------------------------------------------------------------------------------
+// View and projection initialization operations
+//------------------------------------------------------------------------------
+
+
+//------------------------------------------------------------------------------
+
+XMFINLINE XMMATRIX XMMatrixLookAtLH
+(
+    FXMVECTOR EyePosition, 
+    FXMVECTOR FocusPosition, 
+    FXMVECTOR UpDirection
+)
+{
+    XMVECTOR EyeDirection;
+    XMMATRIX M;
+
+    EyeDirection = XMVectorSubtract(FocusPosition, EyePosition);
+    M = XMMatrixLookToLH(EyePosition, EyeDirection, UpDirection);
+    
+    return M;
+}
+
+//------------------------------------------------------------------------------
+
+XMFINLINE XMMATRIX XMMatrixLookAtRH
+(
+    FXMVECTOR EyePosition, 
+    FXMVECTOR FocusPosition, 
+    FXMVECTOR UpDirection
+)
+{
+    XMVECTOR NegEyeDirection;
+    XMMATRIX M;
+
+    NegEyeDirection = XMVectorSubtract(EyePosition, FocusPosition);
+    M = XMMatrixLookToLH(EyePosition, NegEyeDirection, UpDirection);
+    
+    return M;
+}
+
+//------------------------------------------------------------------------------
+
+XMINLINE XMMATRIX XMMatrixLookToLH
+(
+    FXMVECTOR EyePosition, 
+    FXMVECTOR EyeDirection, 
+    FXMVECTOR UpDirection
+)
+{
+#if defined(_XM_NO_INTRINSICS_)
+
+    XMVECTOR NegEyePosition;
+    XMVECTOR D0, D1, D2;
+    XMVECTOR R0, R1, R2;
+    XMMATRIX M;
+
+    XMASSERT(!XMVector3Equal(EyeDirection, XMVectorZero()));
+    XMASSERT(!XMVector3IsInfinite(EyeDirection));
+    XMASSERT(!XMVector3Equal(UpDirection, XMVectorZero()));
+    XMASSERT(!XMVector3IsInfinite(UpDirection));
+
+    R2 = XMVector3Normalize(EyeDirection);
+
+    R0 = XMVector3Cross(UpDirection, R2);
+    R0 = XMVector3Normalize(R0);
+
+    R1 = XMVector3Cross(R2, R0);
+
+    NegEyePosition = XMVectorNegate(EyePosition);
+
+    D0 = XMVector3Dot(R0, NegEyePosition);
+    D1 = XMVector3Dot(R1, NegEyePosition);
+    D2 = XMVector3Dot(R2, NegEyePosition);
+
+    M.r[0] = XMVectorSelect(D0, R0, g_XMSelect1110.v);
+    M.r[1] = XMVectorSelect(D1, R1, g_XMSelect1110.v);
+    M.r[2] = XMVectorSelect(D2, R2, g_XMSelect1110.v);
+    M.r[3] = g_XMIdentityR3.v;
+
+    M = XMMatrixTranspose(M);
+
+    return M;
+
+#elif defined(_XM_SSE_INTRINSICS_)
+    XMMATRIX M;
+
+    XMASSERT(!XMVector3Equal(EyeDirection, XMVectorZero()));
+    XMASSERT(!XMVector3IsInfinite(EyeDirection));
+    XMASSERT(!XMVector3Equal(UpDirection, XMVectorZero()));
+    XMASSERT(!XMVector3IsInfinite(UpDirection));
+
+    XMVECTOR R2 = XMVector3Normalize(EyeDirection);
+    XMVECTOR R0 = XMVector3Cross(UpDirection, R2);
+    R0 = XMVector3Normalize(R0);
+    XMVECTOR R1 = XMVector3Cross(R2,R0);
+    XMVECTOR NegEyePosition = _mm_mul_ps(EyePosition,g_XMNegativeOne);
+    XMVECTOR D0 = XMVector3Dot(R0,NegEyePosition);
+    XMVECTOR D1 = XMVector3Dot(R1,NegEyePosition);
+    XMVECTOR D2 = XMVector3Dot(R2,NegEyePosition);
+    R0 = _mm_and_ps(R0,g_XMMask3);
+    R1 = _mm_and_ps(R1,g_XMMask3);
+    R2 = _mm_and_ps(R2,g_XMMask3);
+    D0 = _mm_and_ps(D0,g_XMMaskW);
+    D1 = _mm_and_ps(D1,g_XMMaskW);
+    D2 = _mm_and_ps(D2,g_XMMaskW);
+    D0 = _mm_or_ps(D0,R0);
+    D1 = _mm_or_ps(D1,R1);
+    D2 = _mm_or_ps(D2,R2);
+    M.r[0] = D0;
+    M.r[1] = D1;
+    M.r[2] = D2;
+    M.r[3] = g_XMIdentityR3;
+    M = XMMatrixTranspose(M);
+    return M;
+#else // _XM_VMX128_INTRINSICS_
+#endif // _XM_VMX128_INTRINSICS_
+}
+
+//------------------------------------------------------------------------------
+
+XMFINLINE XMMATRIX XMMatrixLookToRH
+(
+    FXMVECTOR EyePosition, 
+    FXMVECTOR EyeDirection, 
+    FXMVECTOR UpDirection
+)
+{
+    XMVECTOR NegEyeDirection;
+    XMMATRIX M;
+
+    NegEyeDirection = XMVectorNegate(EyeDirection);
+    M = XMMatrixLookToLH(EyePosition, NegEyeDirection, UpDirection);
+
+    return M;
+}
+
+//------------------------------------------------------------------------------
+
+XMFINLINE XMMATRIX XMMatrixPerspectiveLH
+(
+    FLOAT ViewWidth, 
+    FLOAT ViewHeight, 
+    FLOAT NearZ, 
+    FLOAT FarZ
+)
+{
+#if defined(_XM_NO_INTRINSICS_)
+
+    FLOAT TwoNearZ, fRange;
+    XMMATRIX M;
+
+    XMASSERT(!XMScalarNearEqual(ViewWidth, 0.0f, 0.00001f));
+    XMASSERT(!XMScalarNearEqual(ViewHeight, 0.0f, 0.00001f));
+    XMASSERT(!XMScalarNearEqual(FarZ, NearZ, 0.00001f));
+
+    TwoNearZ = NearZ + NearZ;
+    fRange = FarZ / (FarZ - NearZ);
+    M.m[0][0] = TwoNearZ / ViewWidth;
+    M.m[0][1] = 0.0f;
+    M.m[0][2] = 0.0f;
+    M.m[0][3] = 0.0f;
+
+    M.m[1][0] = 0.0f;
+    M.m[1][1] = TwoNearZ / ViewHeight;
+    M.m[1][2] = 0.0f;
+    M.m[1][3] = 0.0f;
+
+    M.m[2][0] = 0.0f;
+    M.m[2][1] = 0.0f;
+    M.m[2][2] = fRange;
+    M.m[2][3] = 1.0f;
+
+    M.m[3][0] = 0.0f;  
+    M.m[3][1] = 0.0f;
+    M.m[3][2] = -fRange * NearZ;
+    M.m[3][3] = 0.0f;
+
+    return M;
+
+#elif defined(_XM_SSE_INTRINSICS_)
+    XMASSERT(!XMScalarNearEqual(ViewWidth, 0.0f, 0.00001f));
+    XMASSERT(!XMScalarNearEqual(ViewHeight, 0.0f, 0.00001f));
+    XMASSERT(!XMScalarNearEqual(FarZ, NearZ, 0.00001f));
+
+    XMMATRIX M;
+    FLOAT TwoNearZ = NearZ + NearZ;
+    FLOAT fRange = FarZ / (FarZ - NearZ);
+    // Note: This is recorded on the stack
+    XMVECTOR rMem = {
+        TwoNearZ / ViewWidth,
+        TwoNearZ / ViewHeight,
+        fRange,
+        -fRange * NearZ
+    };
+    // Copy from memory to SSE register
+    XMVECTOR vValues = rMem;
+    XMVECTOR vTemp = _mm_setzero_ps(); 
+    // Copy x only
+    vTemp = _mm_move_ss(vTemp,vValues);
+    // TwoNearZ / ViewWidth,0,0,0
+    M.r[0] = vTemp;
+    // 0,TwoNearZ / ViewHeight,0,0
+    vTemp = vValues;
+    vTemp = _mm_and_ps(vTemp,g_XMMaskY);
+    M.r[1] = vTemp;
+    // x=fRange,y=-fRange * NearZ,0,1.0f
+    vValues = _mm_shuffle_ps(vValues,g_XMIdentityR3,_MM_SHUFFLE(3,2,3,2));
+    // 0,0,fRange,1.0f
+    vTemp = _mm_setzero_ps();
+    vTemp = _mm_shuffle_ps(vTemp,vValues,_MM_SHUFFLE(3,0,0,0));
+    M.r[2] = vTemp;
+    // 0,0,-fRange * NearZ,0
+    vTemp = _mm_shuffle_ps(vTemp,vValues,_MM_SHUFFLE(2,1,0,0));
+    M.r[3] = vTemp;
+
+    return M;
+#else // _XM_VMX128_INTRINSICS_
+#endif // _XM_VMX128_INTRINSICS_
+}
+
+//------------------------------------------------------------------------------
+
+XMFINLINE XMMATRIX XMMatrixPerspectiveRH
+(
+    FLOAT ViewWidth, 
+    FLOAT ViewHeight, 
+    FLOAT NearZ, 
+    FLOAT FarZ
+)
+{
+#if defined(_XM_NO_INTRINSICS_)
+
+    FLOAT TwoNearZ, fRange;
+    XMMATRIX M;
+
+    XMASSERT(!XMScalarNearEqual(ViewWidth, 0.0f, 0.00001f));
+    XMASSERT(!XMScalarNearEqual(ViewHeight, 0.0f, 0.00001f));
+    XMASSERT(!XMScalarNearEqual(FarZ, NearZ, 0.00001f));
+
+    TwoNearZ = NearZ + NearZ;
+    fRange = FarZ / (NearZ - FarZ);
+    M.m[0][0] = TwoNearZ / ViewWidth;
+    M.m[0][1] = 0.0f;
+    M.m[0][2] = 0.0f;
+    M.m[0][3] = 0.0f;
+
+    M.m[1][0] = 0.0f;
+    M.m[1][1] = TwoNearZ / ViewHeight;
+    M.m[1][2] = 0.0f;
+    M.m[1][3] = 0.0f;
+
+    M.m[2][0] = 0.0f;
+    M.m[2][1] = 0.0f;
+    M.m[2][2] = fRange;
+    M.m[2][3] = -1.0f;
+
+    M.m[3][0] = 0.0f;
+    M.m[3][1] = 0.0f;
+    M.m[3][2] = fRange * NearZ;
+    M.m[3][3] = 0.0f;
+
+    return M;
+
+#elif defined(_XM_SSE_INTRINSICS_)
+    XMASSERT(!XMScalarNearEqual(ViewWidth, 0.0f, 0.00001f));
+    XMASSERT(!XMScalarNearEqual(ViewHeight, 0.0f, 0.00001f));
+    XMASSERT(!XMScalarNearEqual(FarZ, NearZ, 0.00001f));
+
+    XMMATRIX M;
+    FLOAT TwoNearZ = NearZ + NearZ;
+    FLOAT fRange = FarZ / (NearZ-FarZ);
+    // Note: This is recorded on the stack
+    XMVECTOR rMem = {
+        TwoNearZ / ViewWidth,
+        TwoNearZ / ViewHeight,
+        fRange,
+        fRange * NearZ
+    };
+    // Copy from memory to SSE register
+    XMVECTOR vValues = rMem;
+    XMVECTOR vTemp = _mm_setzero_ps(); 
+    // Copy x only
+    vTemp = _mm_move_ss(vTemp,vValues);
+    // TwoNearZ / ViewWidth,0,0,0
+    M.r[0] = vTemp;
+    // 0,TwoNearZ / ViewHeight,0,0
+    vTemp = vValues;
+    vTemp = _mm_and_ps(vTemp,g_XMMaskY);
+    M.r[1] = vTemp;
+    // x=fRange,y=-fRange * NearZ,0,-1.0f
+    vValues = _mm_shuffle_ps(vValues,g_XMNegIdentityR3,_MM_SHUFFLE(3,2,3,2));
+    // 0,0,fRange,-1.0f
+    vTemp = _mm_setzero_ps();
+    vTemp = _mm_shuffle_ps(vTemp,vValues,_MM_SHUFFLE(3,0,0,0));
+    M.r[2] = vTemp;
+    // 0,0,-fRange * NearZ,0
+    vTemp = _mm_shuffle_ps(vTemp,vValues,_MM_SHUFFLE(2,1,0,0));
+    M.r[3] = vTemp;
+    return M;
+#else // _XM_VMX128_INTRINSICS_
+#endif // _XM_VMX128_INTRINSICS_
+}
+
+//------------------------------------------------------------------------------
+
+XMFINLINE XMMATRIX XMMatrixPerspectiveFovLH
+(
+    FLOAT FovAngleY, 
+    FLOAT AspectHByW, 
+    FLOAT NearZ, 
+    FLOAT FarZ
+)
+{
+#if defined(_XM_NO_INTRINSICS_)
+
+    FLOAT    SinFov;
+    FLOAT    CosFov;
+    FLOAT    Height;
+    FLOAT    Width;
+    XMMATRIX M;
+
+    XMASSERT(!XMScalarNearEqual(FovAngleY, 0.0f, 0.00001f * 2.0f));
+    XMASSERT(!XMScalarNearEqual(AspectHByW, 0.0f, 0.00001f));
+    XMASSERT(!XMScalarNearEqual(FarZ, NearZ, 0.00001f));
+
+    XMScalarSinCos(&SinFov, &CosFov, 0.5f * FovAngleY);
+
+    Height = CosFov / SinFov;
+    Width = Height / AspectHByW;
+
+    M.r[0] = XMVectorSet(Width, 0.0f, 0.0f, 0.0f);
+    M.r[1] = XMVectorSet(0.0f, Height, 0.0f, 0.0f);
+    M.r[2] = XMVectorSet(0.0f, 0.0f, FarZ / (FarZ - NearZ), 1.0f);
+    M.r[3] = XMVectorSet(0.0f, 0.0f, -M.r[2].vector4_f32[2] * NearZ, 0.0f);
+
+    return M;
+
+#elif defined(_XM_SSE_INTRINSICS_)
+    XMASSERT(!XMScalarNearEqual(FovAngleY, 0.0f, 0.00001f * 2.0f));
+    XMASSERT(!XMScalarNearEqual(AspectHByW, 0.0f, 0.00001f));
+    XMASSERT(!XMScalarNearEqual(FarZ, NearZ, 0.00001f));
+    XMMATRIX M;
+    FLOAT    SinFov;
+    FLOAT    CosFov;
+    XMScalarSinCos(&SinFov, &CosFov, 0.5f * FovAngleY);
+    FLOAT fRange = FarZ / (FarZ-NearZ);
+    // Note: This is recorded on the stack
+    FLOAT Height = CosFov / SinFov;
+    XMVECTOR rMem = {
+        Height / AspectHByW,
+        Height,
+        fRange,
+        -fRange * NearZ
+    };
+    // Copy from memory to SSE register
+    XMVECTOR vValues = rMem;
+    XMVECTOR vTemp = _mm_setzero_ps(); 
+    // Copy x only
+    vTemp = _mm_move_ss(vTemp,vValues);
+    // CosFov / SinFov,0,0,0
+    M.r[0] = vTemp;
+    // 0,Height / AspectHByW,0,0
+    vTemp = vValues;
+    vTemp = _mm_and_ps(vTemp,g_XMMaskY);
+    M.r[1] = vTemp;
+    // x=fRange,y=-fRange * NearZ,0,1.0f
+    vTemp = _mm_setzero_ps();
+    vValues = _mm_shuffle_ps(vValues,g_XMIdentityR3,_MM_SHUFFLE(3,2,3,2));
+    // 0,0,fRange,1.0f
+    vTemp = _mm_shuffle_ps(vTemp,vValues,_MM_SHUFFLE(3,0,0,0));
+    M.r[2] = vTemp;
+    // 0,0,-fRange * NearZ,0.0f
+    vTemp = _mm_shuffle_ps(vTemp,vValues,_MM_SHUFFLE(2,1,0,0));
+    M.r[3] = vTemp;
+    return M;
+#else // _XM_VMX128_INTRINSICS_
+#endif // _XM_VMX128_INTRINSICS_
+}
+
+//------------------------------------------------------------------------------
+
+XMFINLINE XMMATRIX XMMatrixPerspectiveFovRH
+(
+    FLOAT FovAngleY, 
+    FLOAT AspectHByW, 
+    FLOAT NearZ, 
+    FLOAT FarZ
+)
+{
+#if defined(_XM_NO_INTRINSICS_)
+
+    FLOAT    SinFov;
+    FLOAT    CosFov;
+    FLOAT    Height;
+    FLOAT    Width;
+    XMMATRIX M;
+
+    XMASSERT(!XMScalarNearEqual(FovAngleY, 0.0f, 0.00001f * 2.0f));
+    XMASSERT(!XMScalarNearEqual(AspectHByW, 0.0f, 0.00001f));
+    XMASSERT(!XMScalarNearEqual(FarZ, NearZ, 0.00001f));
+
+    XMScalarSinCos(&SinFov, &CosFov, 0.5f * FovAngleY);
+
+    Height = CosFov / SinFov;
+    Width = Height / AspectHByW;
+
+    M.r[0] = XMVectorSet(Width, 0.0f, 0.0f, 0.0f);
+    M.r[1] = XMVectorSet(0.0f, Height, 0.0f, 0.0f);
+    M.r[2] = XMVectorSet(0.0f, 0.0f, FarZ / (NearZ - FarZ), -1.0f);
+    M.r[3] = XMVectorSet(0.0f, 0.0f, M.r[2].vector4_f32[2] * NearZ, 0.0f);
+
+    return M;
+
+#elif defined(_XM_SSE_INTRINSICS_)
+    XMASSERT(!XMScalarNearEqual(FovAngleY, 0.0f, 0.00001f * 2.0f));
+    XMASSERT(!XMScalarNearEqual(AspectHByW, 0.0f, 0.00001f));
+    XMASSERT(!XMScalarNearEqual(FarZ, NearZ, 0.00001f));
+    XMMATRIX M;
+    FLOAT    SinFov;
+    FLOAT    CosFov;
+    XMScalarSinCos(&SinFov, &CosFov, 0.5f * FovAngleY);
+    FLOAT fRange = FarZ / (NearZ-FarZ);
+    // Note: This is recorded on the stack
+    FLOAT Height = CosFov / SinFov;
+    XMVECTOR rMem = {
+        Height / AspectHByW,
+        Height,
+        fRange,
+        fRange * NearZ
+    };
+    // Copy from memory to SSE register
+    XMVECTOR vValues = rMem;
+    XMVECTOR vTemp = _mm_setzero_ps(); 
+    // Copy x only
+    vTemp = _mm_move_ss(vTemp,vValues);
+    // CosFov / SinFov,0,0,0
+    M.r[0] = vTemp;
+    // 0,Height / AspectHByW,0,0
+    vTemp = vValues;
+    vTemp = _mm_and_ps(vTemp,g_XMMaskY);
+    M.r[1] = vTemp;
+    // x=fRange,y=-fRange * NearZ,0,-1.0f
+    vTemp = _mm_setzero_ps();
+    vValues = _mm_shuffle_ps(vValues,g_XMNegIdentityR3,_MM_SHUFFLE(3,2,3,2));
+    // 0,0,fRange,-1.0f
+    vTemp = _mm_shuffle_ps(vTemp,vValues,_MM_SHUFFLE(3,0,0,0));
+    M.r[2] = vTemp;
+    // 0,0,fRange * NearZ,0.0f
+    vTemp = _mm_shuffle_ps(vTemp,vValues,_MM_SHUFFLE(2,1,0,0));
+    M.r[3] = vTemp;
+    return M;
+#else // _XM_VMX128_INTRINSICS_
+#endif // _XM_VMX128_INTRINSICS_
+}
+
+//------------------------------------------------------------------------------
+
+XMFINLINE XMMATRIX XMMatrixPerspectiveOffCenterLH
+(
+    FLOAT ViewLeft, 
+    FLOAT ViewRight, 
+    FLOAT ViewBottom, 
+    FLOAT ViewTop, 
+    FLOAT NearZ, 
+    FLOAT FarZ
+)
+{
+#if defined(_XM_NO_INTRINSICS_)
+
+    FLOAT    TwoNearZ;
+    FLOAT    ReciprocalWidth;
+    FLOAT    ReciprocalHeight;
+    FLOAT    fRange;
+    XMMATRIX M;
+
+    XMASSERT(!XMScalarNearEqual(ViewRight, ViewLeft, 0.00001f));
+    XMASSERT(!XMScalarNearEqual(ViewTop, ViewBottom, 0.00001f));
+    XMASSERT(!XMScalarNearEqual(FarZ, NearZ, 0.00001f));
+
+    TwoNearZ = NearZ + NearZ;
+    ReciprocalWidth = 1.0f / (ViewRight - ViewLeft);
+    ReciprocalHeight = 1.0f / (ViewTop - ViewBottom);
+    fRange = FarZ / (FarZ-NearZ);
+
+    M.m[0][0] = TwoNearZ * ReciprocalWidth;
+    M.m[0][1] = 0.0f;
+    M.m[0][2] = 0.0f;
+    M.m[0][3] = 0.0f;
+
+    M.m[1][0] = 0.0f;
+    M.m[1][1] = TwoNearZ * ReciprocalHeight;
+    M.m[1][2] = 0.0f;
+    M.m[1][3] = 0.0f;
+
+    M.m[2][0] = -(ViewLeft + ViewRight) * ReciprocalWidth;
+    M.m[2][1] = -(ViewTop + ViewBottom) * ReciprocalHeight;
+    M.m[2][2] = fRange;
+    M.m[2][3] = 1.0f;
+
+    M.m[3][0] = 0.0f;
+    M.m[3][1] = 0.0f;
+    M.m[3][2] = -fRange * NearZ;
+    M.m[3][3] = 0.0f;
+    return M;
+
+#elif defined(_XM_SSE_INTRINSICS_)
+    XMASSERT(!XMScalarNearEqual(ViewRight, ViewLeft, 0.00001f));
+    XMASSERT(!XMScalarNearEqual(ViewTop, ViewBottom, 0.00001f));
+    XMASSERT(!XMScalarNearEqual(FarZ, NearZ, 0.00001f));
+    XMMATRIX M;
+    FLOAT TwoNearZ = NearZ+NearZ;
+    FLOAT ReciprocalWidth = 1.0f / (ViewRight - ViewLeft);
+    FLOAT ReciprocalHeight = 1.0f / (ViewTop - ViewBottom);
+    FLOAT fRange = FarZ / (FarZ-NearZ);
+    // Note: This is recorded on the stack
+    XMVECTOR rMem = {
+        TwoNearZ*ReciprocalWidth,
+        TwoNearZ*ReciprocalHeight,
+        -fRange * NearZ,
+        0
+    };
+    // Copy from memory to SSE register
+    XMVECTOR vValues = rMem;
+    XMVECTOR vTemp = _mm_setzero_ps(); 
+    // Copy x only
+    vTemp = _mm_move_ss(vTemp,vValues);
+    // TwoNearZ*ReciprocalWidth,0,0,0
+    M.r[0] = vTemp;
+    // 0,TwoNearZ*ReciprocalHeight,0,0
+    vTemp = vValues;
+    vTemp = _mm_and_ps(vTemp,g_XMMaskY);
+    M.r[1] = vTemp;
+    // 0,0,fRange,1.0f
+    M.r[2] = XMVectorSet( -(ViewLeft + ViewRight) * ReciprocalWidth,
+                          -(ViewTop + ViewBottom) * ReciprocalHeight,
+                          fRange,
+                          1.0f );
+    // 0,0,-fRange * NearZ,0.0f
+    vValues = _mm_and_ps(vValues,g_XMMaskZ);
+    M.r[3] = vValues;
+    return M;
+#else // _XM_VMX128_INTRINSICS_
+#endif // _XM_VMX128_INTRINSICS_
+}
+
+//------------------------------------------------------------------------------
+
+XMFINLINE XMMATRIX XMMatrixPerspectiveOffCenterRH
+(
+    FLOAT ViewLeft, 
+    FLOAT ViewRight, 
+    FLOAT ViewBottom, 
+    FLOAT ViewTop, 
+    FLOAT NearZ, 
+    FLOAT FarZ
+)
+{
+#if defined(_XM_NO_INTRINSICS_)
+
+    FLOAT    TwoNearZ;
+    FLOAT    ReciprocalWidth;
+    FLOAT    ReciprocalHeight;
+    FLOAT    fRange;
+    XMMATRIX M;
+
+    XMASSERT(!XMScalarNearEqual(ViewRight, ViewLeft, 0.00001f));
+    XMASSERT(!XMScalarNearEqual(ViewTop, ViewBottom, 0.00001f));
+    XMASSERT(!XMScalarNearEqual(FarZ, NearZ, 0.00001f));
+
+    TwoNearZ = NearZ + NearZ;
+    ReciprocalWidth = 1.0f / (ViewRight - ViewLeft);
+    ReciprocalHeight = 1.0f / (ViewTop - ViewBottom);
+    fRange = FarZ / (NearZ-FarZ);
+
+    M.m[0][0] = TwoNearZ * ReciprocalWidth;
+    M.m[0][1] = 0.0f;
+    M.m[0][2] = 0.0f;
+    M.m[0][3] = 0.0f;
+
+    M.m[1][0] = 0.0f;
+    M.m[1][1] = TwoNearZ * ReciprocalHeight;
+    M.m[1][2] = 0.0f;
+    M.m[1][3] = 0.0f;
+
+    M.m[2][0] = (ViewLeft + ViewRight) * ReciprocalWidth;
+    M.m[2][1] = (ViewTop + ViewBottom) * ReciprocalHeight;
+    M.m[2][2] = fRange;
+    M.m[2][3] = -1.0f;
+
+    M.m[3][0] = 0.0f;
+    M.m[3][1] = 0.0f;
+    M.m[3][2] = fRange * NearZ;
+    M.m[3][3] = 0.0f;
+    return M;
+
+#elif defined(_XM_SSE_INTRINSICS_)
+    XMASSERT(!XMScalarNearEqual(ViewRight, ViewLeft, 0.00001f));
+    XMASSERT(!XMScalarNearEqual(ViewTop, ViewBottom, 0.00001f));
+    XMASSERT(!XMScalarNearEqual(FarZ, NearZ, 0.00001f));
+
+    XMMATRIX M;
+    FLOAT TwoNearZ = NearZ+NearZ;
+    FLOAT ReciprocalWidth = 1.0f / (ViewRight - ViewLeft);
+    FLOAT ReciprocalHeight = 1.0f / (ViewTop - ViewBottom);
+    FLOAT fRange = FarZ / (NearZ-FarZ);
+    // Note: This is recorded on the stack
+    XMVECTOR rMem = {
+        TwoNearZ*ReciprocalWidth,
+        TwoNearZ*ReciprocalHeight,
+        fRange * NearZ,
+        0
+    };
+    // Copy from memory to SSE register
+    XMVECTOR vValues = rMem;
+    XMVECTOR vTemp = _mm_setzero_ps(); 
+    // Copy x only
+    vTemp = _mm_move_ss(vTemp,vValues);
+    // TwoNearZ*ReciprocalWidth,0,0,0
+    M.r[0] = vTemp;
+    // 0,TwoNearZ*ReciprocalHeight,0,0
+    vTemp = vValues;
+    vTemp = _mm_and_ps(vTemp,g_XMMaskY);
+    M.r[1] = vTemp;
+    // 0,0,fRange,1.0f
+    M.r[2] = XMVectorSet((ViewLeft + ViewRight) * ReciprocalWidth, 
+                         (ViewTop + ViewBottom) * ReciprocalHeight,
+                         fRange,
+                         -1.0f);
+    // 0,0,-fRange * NearZ,0.0f
+    vValues = _mm_and_ps(vValues,g_XMMaskZ);
+    M.r[3] = vValues;
+    return M;
+#else // _XM_VMX128_INTRINSICS_
+#endif // _XM_VMX128_INTRINSICS_
+}
+
+//------------------------------------------------------------------------------
+
+XMFINLINE XMMATRIX XMMatrixOrthographicLH
+(
+    FLOAT ViewWidth, 
+    FLOAT ViewHeight, 
+    FLOAT NearZ, 
+    FLOAT FarZ
+)
+{
+#if defined(_XM_NO_INTRINSICS_)
+
+    FLOAT fRange;
+    XMMATRIX M;
+
+    XMASSERT(!XMScalarNearEqual(ViewWidth, 0.0f, 0.00001f));
+    XMASSERT(!XMScalarNearEqual(ViewHeight, 0.0f, 0.00001f));
+    XMASSERT(!XMScalarNearEqual(FarZ, NearZ, 0.00001f));
+
+    fRange = 1.0f / (FarZ-NearZ);
+    M.r[0] = XMVectorSet(2.0f / ViewWidth, 0.0f, 0.0f, 0.0f);
+    M.r[1] = XMVectorSet(0.0f, 2.0f / ViewHeight, 0.0f, 0.0f);
+    M.r[2] = XMVectorSet(0.0f, 0.0f, fRange, 0.0f);
+    M.r[3] = XMVectorSet(0.0f, 0.0f, -fRange * NearZ, 1.0f);
+
+    return M;
+
+#elif defined(_XM_SSE_INTRINSICS_)
+    XMASSERT(!XMScalarNearEqual(ViewWidth, 0.0f, 0.00001f));
+    XMASSERT(!XMScalarNearEqual(ViewHeight, 0.0f, 0.00001f));
+    XMASSERT(!XMScalarNearEqual(FarZ, NearZ, 0.00001f));
+    XMMATRIX M;
+    FLOAT fRange = 1.0f / (FarZ-NearZ);
+    // Note: This is recorded on the stack
+    XMVECTOR rMem = {
+        2.0f / ViewWidth,
+        2.0f / ViewHeight,
+        fRange,
+        -fRange * NearZ
+    };
+    // Copy from memory to SSE register
+    XMVECTOR vValues = rMem;
+    XMVECTOR vTemp = _mm_setzero_ps(); 
+    // Copy x only
+    vTemp = _mm_move_ss(vTemp,vValues);
+    // 2.0f / ViewWidth,0,0,0
+    M.r[0] = vTemp;
+    // 0,2.0f / ViewHeight,0,0
+    vTemp = vValues;
+    vTemp = _mm_and_ps(vTemp,g_XMMaskY);
+    M.r[1] = vTemp;
+    // x=fRange,y=-fRange * NearZ,0,1.0f
+    vTemp = _mm_setzero_ps();
+    vValues = _mm_shuffle_ps(vValues,g_XMIdentityR3,_MM_SHUFFLE(3,2,3,2));
+    // 0,0,fRange,0.0f
+    vTemp = _mm_shuffle_ps(vTemp,vValues,_MM_SHUFFLE(2,0,0,0));
+    M.r[2] = vTemp;
+    // 0,0,-fRange * NearZ,1.0f
+    vTemp = _mm_shuffle_ps(vTemp,vValues,_MM_SHUFFLE(3,1,0,0));
+    M.r[3] = vTemp;
+    return M;
+#else // _XM_VMX128_INTRINSICS_
+#endif // _XM_VMX128_INTRINSICS_
+}
+
+//------------------------------------------------------------------------------
+
+XMFINLINE XMMATRIX XMMatrixOrthographicRH
+(
+    FLOAT ViewWidth, 
+    FLOAT ViewHeight, 
+    FLOAT NearZ, 
+    FLOAT FarZ
+)
+{
+#if defined(_XM_NO_INTRINSICS_)
+
+    XMMATRIX M;
+
+    XMASSERT(!XMScalarNearEqual(ViewWidth, 0.0f, 0.00001f));
+    XMASSERT(!XMScalarNearEqual(ViewHeight, 0.0f, 0.00001f));
+    XMASSERT(!XMScalarNearEqual(FarZ, NearZ, 0.00001f));
+
+    M.r[0] = XMVectorSet(2.0f / ViewWidth, 0.0f, 0.0f, 0.0f);
+    M.r[1] = XMVectorSet(0.0f, 2.0f / ViewHeight, 0.0f, 0.0f);
+    M.r[2] = XMVectorSet(0.0f, 0.0f, 1.0f / (NearZ - FarZ), 0.0f);
+    M.r[3] = XMVectorSet(0.0f, 0.0f, M.r[2].vector4_f32[2] * NearZ, 1.0f);
+
+    return M;
+
+#elif defined(_XM_SSE_INTRINSICS_)
+    XMASSERT(!XMScalarNearEqual(ViewWidth, 0.0f, 0.00001f));
+    XMASSERT(!XMScalarNearEqual(ViewHeight, 0.0f, 0.00001f));
+    XMASSERT(!XMScalarNearEqual(FarZ, NearZ, 0.00001f));
+    XMMATRIX M;
+    FLOAT fRange = 1.0f / (NearZ-FarZ);
+    // Note: This is recorded on the stack
+    XMVECTOR rMem = {
+        2.0f / ViewWidth,
+        2.0f / ViewHeight,
+        fRange,
+        fRange * NearZ
+    };
+    // Copy from memory to SSE register
+    XMVECTOR vValues = rMem;
+    XMVECTOR vTemp = _mm_setzero_ps(); 
+    // Copy x only
+    vTemp = _mm_move_ss(vTemp,vValues);
+    // 2.0f / ViewWidth,0,0,0
+    M.r[0] = vTemp;
+    // 0,2.0f / ViewHeight,0,0
+    vTemp = vValues;
+    vTemp = _mm_and_ps(vTemp,g_XMMaskY);
+    M.r[1] = vTemp;
+    // x=fRange,y=fRange * NearZ,0,1.0f
+    vTemp = _mm_setzero_ps();
+    vValues = _mm_shuffle_ps(vValues,g_XMIdentityR3,_MM_SHUFFLE(3,2,3,2));
+    // 0,0,fRange,0.0f
+    vTemp = _mm_shuffle_ps(vTemp,vValues,_MM_SHUFFLE(2,0,0,0));
+    M.r[2] = vTemp;
+    // 0,0,fRange * NearZ,1.0f
+    vTemp = _mm_shuffle_ps(vTemp,vValues,_MM_SHUFFLE(3,1,0,0));
+    M.r[3] = vTemp;
+    return M;
+#else // _XM_VMX128_INTRINSICS_
+#endif // _XM_VMX128_INTRINSICS_
+}
+
+//------------------------------------------------------------------------------
+
+XMFINLINE XMMATRIX XMMatrixOrthographicOffCenterLH
+(
+    FLOAT ViewLeft, 
+    FLOAT ViewRight, 
+    FLOAT ViewBottom, 
+    FLOAT ViewTop, 
+    FLOAT NearZ, 
+    FLOAT FarZ
+)
+{
+#if defined(_XM_NO_INTRINSICS_)
+
+    FLOAT    ReciprocalWidth;
+    FLOAT    ReciprocalHeight;
+    XMMATRIX M;
+
+    XMASSERT(!XMScalarNearEqual(ViewRight, ViewLeft, 0.00001f));
+    XMASSERT(!XMScalarNearEqual(ViewTop, ViewBottom, 0.00001f));
+    XMASSERT(!XMScalarNearEqual(FarZ, NearZ, 0.00001f));
+
+    ReciprocalWidth = 1.0f / (ViewRight - ViewLeft);
+    ReciprocalHeight = 1.0f / (ViewTop - ViewBottom);
+
+    M.r[0] = XMVectorSet(ReciprocalWidth + ReciprocalWidth, 0.0f, 0.0f, 0.0f);
+    M.r[1] = XMVectorSet(0.0f, ReciprocalHeight + ReciprocalHeight, 0.0f, 0.0f);
+    M.r[2] = XMVectorSet(0.0f, 0.0f, 1.0f / (FarZ - NearZ), 0.0f);
+    M.r[3] = XMVectorSet(-(ViewLeft + ViewRight) * ReciprocalWidth, 
+                         -(ViewTop + ViewBottom) * ReciprocalHeight,
+                         -M.r[2].vector4_f32[2] * NearZ,
+                         1.0f);
+
+    return M;
+
+#elif defined(_XM_SSE_INTRINSICS_)
+    XMMATRIX M;
+    FLOAT fReciprocalWidth = 1.0f / (ViewRight - ViewLeft);
+    FLOAT fReciprocalHeight = 1.0f / (ViewTop - ViewBottom);
+    FLOAT fRange = 1.0f / (FarZ-NearZ);
+    // Note: This is recorded on the stack
+    XMVECTOR rMem = {
+        fReciprocalWidth,
+        fReciprocalHeight,
+        fRange,
+        1.0f
+    };
+    XMVECTOR rMem2 = {
+        -(ViewLeft + ViewRight),
+        -(ViewTop + ViewBottom),
+        -NearZ,
+        1.0f
+    };
+    // Copy from memory to SSE register
+    XMVECTOR vValues = rMem;
+    XMVECTOR vTemp = _mm_setzero_ps(); 
+    // Copy x only
+    vTemp = _mm_move_ss(vTemp,vValues);
+    // fReciprocalWidth*2,0,0,0
+    vTemp = _mm_add_ss(vTemp,vTemp);
+    M.r[0] = vTemp;
+    // 0,fReciprocalHeight*2,0,0
+    vTemp = vValues;
+    vTemp = _mm_and_ps(vTemp,g_XMMaskY);
+    vTemp = _mm_add_ps(vTemp,vTemp);
+    M.r[1] = vTemp;
+    // 0,0,fRange,0.0f
+    vTemp = vValues;
+    vTemp = _mm_and_ps(vTemp,g_XMMaskZ);
+    M.r[2] = vTemp;
+    // -(ViewLeft + ViewRight)*fReciprocalWidth,-(ViewTop + ViewBottom)*fReciprocalHeight,fRange*-NearZ,1.0f
+    vValues = _mm_mul_ps(vValues,rMem2);
+    M.r[3] = vValues;
+    return M;
+#else // _XM_VMX128_INTRINSICS_
+#endif // _XM_VMX128_INTRINSICS_
+}
+
+//------------------------------------------------------------------------------
+
+XMFINLINE XMMATRIX XMMatrixOrthographicOffCenterRH
+(
+    FLOAT ViewLeft, 
+    FLOAT ViewRight, 
+    FLOAT ViewBottom, 
+    FLOAT ViewTop, 
+    FLOAT NearZ, 
+    FLOAT FarZ
+)
+{
+#if defined(_XM_NO_INTRINSICS_)
+
+    FLOAT    ReciprocalWidth;
+    FLOAT    ReciprocalHeight;
+    XMMATRIX M;
+
+    XMASSERT(!XMScalarNearEqual(ViewRight, ViewLeft, 0.00001f));
+    XMASSERT(!XMScalarNearEqual(ViewTop, ViewBottom, 0.00001f));
+    XMASSERT(!XMScalarNearEqual(FarZ, NearZ, 0.00001f));
+
+    ReciprocalWidth = 1.0f / (ViewRight - ViewLeft);
+    ReciprocalHeight = 1.0f / (ViewTop - ViewBottom);
+
+    M.r[0] = XMVectorSet(ReciprocalWidth + ReciprocalWidth, 0.0f, 0.0f, 0.0f);
+    M.r[1] = XMVectorSet(0.0f, ReciprocalHeight + ReciprocalHeight, 0.0f, 0.0f);
+    M.r[2] = XMVectorSet(0.0f, 0.0f, 1.0f / (NearZ - FarZ), 0.0f);
+    M.r[3] = XMVectorSet(-(ViewLeft + ViewRight) * ReciprocalWidth, 
+                         -(ViewTop + ViewBottom) * ReciprocalHeight,
+                         M.r[2].vector4_f32[2] * NearZ,
+                         1.0f);
+
+    return M;
+
+#elif defined(_XM_SSE_INTRINSICS_)
+    XMMATRIX M;
+    FLOAT fReciprocalWidth = 1.0f / (ViewRight - ViewLeft);
+    FLOAT fReciprocalHeight = 1.0f / (ViewTop - ViewBottom);
+    FLOAT fRange = 1.0f / (NearZ-FarZ);
+    // Note: This is recorded on the stack
+    XMVECTOR rMem = {
+        fReciprocalWidth,
+        fReciprocalHeight,
+        fRange,
+        1.0f
+    };
+    XMVECTOR rMem2 = {
+        -(ViewLeft + ViewRight),
+        -(ViewTop + ViewBottom),
+        NearZ,
+        1.0f
+    };
+    // Copy from memory to SSE register
+    XMVECTOR vValues = rMem;
+    XMVECTOR vTemp = _mm_setzero_ps(); 
+    // Copy x only
+    vTemp = _mm_move_ss(vTemp,vValues);
+    // fReciprocalWidth*2,0,0,0
+    vTemp = _mm_add_ss(vTemp,vTemp);
+    M.r[0] = vTemp;
+    // 0,fReciprocalHeight*2,0,0
+    vTemp = vValues;
+    vTemp = _mm_and_ps(vTemp,g_XMMaskY);
+    vTemp = _mm_add_ps(vTemp,vTemp);
+    M.r[1] = vTemp;
+    // 0,0,fRange,0.0f
+    vTemp = vValues;
+    vTemp = _mm_and_ps(vTemp,g_XMMaskZ);
+    M.r[2] = vTemp;
+    // -(ViewLeft + ViewRight)*fReciprocalWidth,-(ViewTop + ViewBottom)*fReciprocalHeight,fRange*-NearZ,1.0f
+    vValues = _mm_mul_ps(vValues,rMem2);
+    M.r[3] = vValues;
+    return M;
+#else // _XM_VMX128_INTRINSICS_
+#endif // _XM_VMX128_INTRINSICS_
+}
+
+
+#ifdef __cplusplus
+
+/****************************************************************************
+ *
+ * XMMATRIX operators and methods
+ *
+ ****************************************************************************/
+
+//------------------------------------------------------------------------------
+
+XMFINLINE _XMMATRIX::_XMMATRIX
+(
+    FXMVECTOR R0,
+    FXMVECTOR R1,
+    FXMVECTOR R2,
+    CXMVECTOR R3
+)
+{
+    r[0] = R0;
+    r[1] = R1;
+    r[2] = R2;
+    r[3] = R3;
+}
+
+//------------------------------------------------------------------------------
+
+XMFINLINE _XMMATRIX::_XMMATRIX
+(
+    FLOAT m00, FLOAT m01, FLOAT m02, FLOAT m03,
+    FLOAT m10, FLOAT m11, FLOAT m12, FLOAT m13,
+    FLOAT m20, FLOAT m21, FLOAT m22, FLOAT m23,
+    FLOAT m30, FLOAT m31, FLOAT m32, FLOAT m33
+)
+{
+    r[0] = XMVectorSet(m00, m01, m02, m03);
+    r[1] = XMVectorSet(m10, m11, m12, m13);
+    r[2] = XMVectorSet(m20, m21, m22, m23);
+    r[3] = XMVectorSet(m30, m31, m32, m33);
+}
+
+//------------------------------------------------------------------------------
+
+XMFINLINE _XMMATRIX::_XMMATRIX
+(
+    CONST FLOAT* pArray
+)
+{
+    r[0] = XMLoadFloat4((const XMFLOAT4*)pArray);
+    r[1] = XMLoadFloat4((const XMFLOAT4*)(pArray + 4));
+    r[2] = XMLoadFloat4((const XMFLOAT4*)(pArray + 8));
+    r[3] = XMLoadFloat4((const XMFLOAT4*)(pArray + 12));
+}
+
+//------------------------------------------------------------------------------
+
+XMFINLINE _XMMATRIX& _XMMATRIX::operator=
+(
+    CONST _XMMATRIX& M
+)
+{
+    r[0] = M.r[0];
+    r[1] = M.r[1];
+    r[2] = M.r[2];
+    r[3] = M.r[3];
+    return *this;
+}
+
+//------------------------------------------------------------------------------
+
+#ifndef XM_NO_OPERATOR_OVERLOADS
+
+#if !defined(_XBOX_VER) && defined(_XM_ISVS2005_) && defined(_XM_X64_)
+#pragma warning(push)
+#pragma warning(disable : 4328)
+#endif
+
+XMFINLINE _XMMATRIX& _XMMATRIX::operator*=
+(
+    CONST _XMMATRIX& M
+)
+{
+    *this = XMMatrixMultiply(*this, M);
+    return *this;
+}
+
+//------------------------------------------------------------------------------
+
+XMFINLINE _XMMATRIX _XMMATRIX::operator* 
+(
+    CONST _XMMATRIX& M
+) CONST
+{
+    return XMMatrixMultiply(*this, M);
+}
+
+#if !defined(_XBOX_VER) && defined(_XM_ISVS2005_) && defined(_XM_X64_)
+#pragma warning(pop)
+#endif
+
+#endif // !XM_NO_OPERATOR_OVERLOADS
+
+/****************************************************************************
+ *
+ * XMFLOAT3X3 operators
+ *
+ ****************************************************************************/
+
+//------------------------------------------------------------------------------
+
+XMFINLINE _XMFLOAT3X3::_XMFLOAT3X3
+(
+    FLOAT m00, FLOAT m01, FLOAT m02,
+    FLOAT m10, FLOAT m11, FLOAT m12,
+    FLOAT m20, FLOAT m21, FLOAT m22
+)
+{
+    m[0][0] = m00;
+    m[0][1] = m01;
+    m[0][2] = m02;
+
+    m[1][0] = m10;
+    m[1][1] = m11;
+    m[1][2] = m12;
+
+    m[2][0] = m20;
+    m[2][1] = m21;
+    m[2][2] = m22;
+}
+
+//------------------------------------------------------------------------------
+
+XMFINLINE _XMFLOAT3X3::_XMFLOAT3X3
+(
+    CONST FLOAT* pArray
+)
+{
+    UINT Row;
+    UINT Column;
+
+    for (Row = 0; Row < 3; Row++)
+    {
+        for (Column = 0; Column < 3; Column++)
+        {
+            m[Row][Column] = pArray[Row * 3 + Column];
+        }
+    }
+}
+
+//------------------------------------------------------------------------------
+
+XMFINLINE _XMFLOAT3X3& _XMFLOAT3X3::operator=
+(
+    CONST _XMFLOAT3X3& Float3x3
+)
+{
+    _11 = Float3x3._11;
+    _12 = Float3x3._12;
+    _13 = Float3x3._13;
+    _21 = Float3x3._21;
+    _22 = Float3x3._22;
+    _23 = Float3x3._23;
+    _31 = Float3x3._31;
+    _32 = Float3x3._32;
+    _33 = Float3x3._33;
+
+    return *this;
+}
+
+/****************************************************************************
+ *
+ * XMFLOAT4X3 operators
+ *
+ ****************************************************************************/
+
+//------------------------------------------------------------------------------
+
+XMFINLINE _XMFLOAT4X3::_XMFLOAT4X3
+(
+    FLOAT m00, FLOAT m01, FLOAT m02,
+    FLOAT m10, FLOAT m11, FLOAT m12,
+    FLOAT m20, FLOAT m21, FLOAT m22,
+    FLOAT m30, FLOAT m31, FLOAT m32
+)
+{
+    m[0][0] = m00;
+    m[0][1] = m01;
+    m[0][2] = m02;
+
+    m[1][0] = m10;
+    m[1][1] = m11;
+    m[1][2] = m12;
+
+    m[2][0] = m20;
+    m[2][1] = m21;
+    m[2][2] = m22;
+
+    m[3][0] = m30;
+    m[3][1] = m31;
+    m[3][2] = m32;
+}
+
+//------------------------------------------------------------------------------
+
+XMFINLINE _XMFLOAT4X3::_XMFLOAT4X3
+(
+    CONST FLOAT* pArray
+)
+{
+    UINT Row;
+    UINT Column;
+
+    for (Row = 0; Row < 4; Row++)
+    {
+        for (Column = 0; Column < 3; Column++)
+        {
+            m[Row][Column] = pArray[Row * 3 + Column];
+        }
+    }
+}
+
+//------------------------------------------------------------------------------
+
+XMFINLINE _XMFLOAT4X3& _XMFLOAT4X3::operator=
+(
+    CONST _XMFLOAT4X3& Float4x3
+)
+{
+    XMVECTOR V1 = XMLoadFloat4((const XMFLOAT4*)&Float4x3._11);
+    XMVECTOR V2 = XMLoadFloat4((const XMFLOAT4*)&Float4x3._22);
+    XMVECTOR V3 = XMLoadFloat4((const XMFLOAT4*)&Float4x3._33);
+
+    XMStoreFloat4((XMFLOAT4*)&_11, V1);
+    XMStoreFloat4((XMFLOAT4*)&_22, V2);
+    XMStoreFloat4((XMFLOAT4*)&_33, V3);
+
+    return *this;
+}
+
+//------------------------------------------------------------------------------
+
+XMFINLINE XMFLOAT4X3A& XMFLOAT4X3A::operator=
+(
+    CONST XMFLOAT4X3A& Float4x3
+)
+{
+    XMVECTOR V1 = XMLoadFloat4A((const XMFLOAT4A*)&Float4x3._11);
+    XMVECTOR V2 = XMLoadFloat4A((const XMFLOAT4A*)&Float4x3._22);
+    XMVECTOR V3 = XMLoadFloat4A((const XMFLOAT4A*)&Float4x3._33);
+
+    XMStoreFloat4A((XMFLOAT4A*)&_11, V1);
+    XMStoreFloat4A((XMFLOAT4A*)&_22, V2);
+    XMStoreFloat4A((XMFLOAT4A*)&_33, V3);
+
+    return *this;
+}
+
+/****************************************************************************
+ *
+ * XMFLOAT4X4 operators
+ *
+ ****************************************************************************/
+
+//------------------------------------------------------------------------------
+
+XMFINLINE _XMFLOAT4X4::_XMFLOAT4X4
+(
+    FLOAT m00, FLOAT m01, FLOAT m02, FLOAT m03,
+    FLOAT m10, FLOAT m11, FLOAT m12, FLOAT m13,
+    FLOAT m20, FLOAT m21, FLOAT m22, FLOAT m23,
+    FLOAT m30, FLOAT m31, FLOAT m32, FLOAT m33
+)
+{
+    m[0][0] = m00;
+    m[0][1] = m01;
+    m[0][2] = m02;
+    m[0][3] = m03;
+
+    m[1][0] = m10;
+    m[1][1] = m11;
+    m[1][2] = m12;
+    m[1][3] = m13;
+
+    m[2][0] = m20;
+    m[2][1] = m21;
+    m[2][2] = m22;
+    m[2][3] = m23;
+
+    m[3][0] = m30;
+    m[3][1] = m31;
+    m[3][2] = m32;
+    m[3][3] = m33;
+}
+
+//------------------------------------------------------------------------------
+
+XMFINLINE _XMFLOAT4X4::_XMFLOAT4X4
+(
+    CONST FLOAT* pArray
+)
+{
+    UINT Row;
+    UINT Column;
+
+    for (Row = 0; Row < 4; Row++)
+    {
+        for (Column = 0; Column < 4; Column++)
+        {
+            m[Row][Column] = pArray[Row * 4 + Column];
+        }
+    }
+}
+
+//------------------------------------------------------------------------------
+
+XMFINLINE _XMFLOAT4X4& _XMFLOAT4X4::operator=
+(
+    CONST _XMFLOAT4X4& Float4x4
+)
+{
+    XMVECTOR V1 = XMLoadFloat4((const XMFLOAT4*)&Float4x4._11);
+    XMVECTOR V2 = XMLoadFloat4((const XMFLOAT4*)&Float4x4._21);
+    XMVECTOR V3 = XMLoadFloat4((const XMFLOAT4*)&Float4x4._31);
+    XMVECTOR V4 = XMLoadFloat4((const XMFLOAT4*)&Float4x4._41);
+
+    XMStoreFloat4((XMFLOAT4*)&_11, V1);
+    XMStoreFloat4((XMFLOAT4*)&_21, V2);
+    XMStoreFloat4((XMFLOAT4*)&_31, V3);
+    XMStoreFloat4((XMFLOAT4*)&_41, V4);
+
+    return *this;
+}
+
+//------------------------------------------------------------------------------
+
+XMFINLINE XMFLOAT4X4A& XMFLOAT4X4A::operator=
+(
+    CONST XMFLOAT4X4A& Float4x4
+)
+{
+    XMVECTOR V1 = XMLoadFloat4A((const XMFLOAT4A*)&Float4x4._11);
+    XMVECTOR V2 = XMLoadFloat4A((const XMFLOAT4A*)&Float4x4._21);
+    XMVECTOR V3 = XMLoadFloat4A((const XMFLOAT4A*)&Float4x4._31);
+    XMVECTOR V4 = XMLoadFloat4A((const XMFLOAT4A*)&Float4x4._41);
+
+    XMStoreFloat4A((XMFLOAT4A*)&_11, V1);
+    XMStoreFloat4A((XMFLOAT4A*)&_21, V2);
+    XMStoreFloat4A((XMFLOAT4A*)&_31, V3);
+    XMStoreFloat4A((XMFLOAT4A*)&_41, V4);
+
+    return *this;
+}
+
+#endif // __cplusplus
+
+#endif // __XNAMATHMATRIX_INL__
+