text: /************************************************************************
  *                                                                       *
  * xnamathmisc.inl -- SIMD C++ Math library for Windows and Xbox 360     *
  *                    Quaternion, plane, and color functions             *
  *                                                                       *
  * Copyright (c) Microsoft Corp. All rights reserved.                    *
  *                                                                       *
  ************************************************************************/
  
  #if defined(_MSC_VER) && (_MSC_VER > 1000)
  #pragma once
  #endif
  
  #ifndef __XNAMATHMISC_INL__
  #define __XNAMATHMISC_INL__
  
  /****************************************************************************
   *
   * Quaternion
   *
   ****************************************************************************/
  
  //------------------------------------------------------------------------------
  // Comparison operations
  //------------------------------------------------------------------------------
  
  //------------------------------------------------------------------------------
  
  XMFINLINE BOOL XMQuaternionEqual
  (
      FXMVECTOR Q1,
      FXMVECTOR Q2
  )
  {
      return XMVector4Equal(Q1, Q2);
  }
  
  //------------------------------------------------------------------------------
  
  XMFINLINE BOOL XMQuaternionNotEqual
  (
      FXMVECTOR Q1,
      FXMVECTOR Q2
  )
  {
      return XMVector4NotEqual(Q1, Q2);
  }
  
  //------------------------------------------------------------------------------
  
  XMFINLINE BOOL XMQuaternionIsNaN
  (
      FXMVECTOR Q
  )
  {
      return XMVector4IsNaN(Q);
  }
  
  //------------------------------------------------------------------------------
  
  XMFINLINE BOOL XMQuaternionIsInfinite
  (
      FXMVECTOR Q
  )
  {
      return XMVector4IsInfinite(Q);
  }
  
  //------------------------------------------------------------------------------
  
  XMFINLINE BOOL XMQuaternionIsIdentity
  (
      FXMVECTOR Q
  )
  {
  #if defined(_XM_NO_INTRINSICS_)
  
      return XMVector4Equal(Q, g_XMIdentityR3.v);
  
  #elif defined(_XM_SSE_INTRINSICS_)
      XMVECTOR vTemp = _mm_cmpeq_ps(Q,g_XMIdentityR3);
      return (_mm_movemask_ps(vTemp)==0x0f);
  #else // _XM_VMX128_INTRINSICS_
  #endif // _XM_VMX128_INTRINSICS_
  }
  
  //------------------------------------------------------------------------------
  // Computation operations
  //------------------------------------------------------------------------------
  
  //------------------------------------------------------------------------------
  
  XMFINLINE XMVECTOR XMQuaternionDot
  (
      FXMVECTOR Q1,
      FXMVECTOR Q2
  )
  {
      return XMVector4Dot(Q1, Q2);
  }
  
  //------------------------------------------------------------------------------
  
  XMFINLINE XMVECTOR XMQuaternionMultiply
  (
      FXMVECTOR Q1,
      FXMVECTOR Q2
  )
  {
  #if defined(_XM_NO_INTRINSICS_)
  
      XMVECTOR         NegativeQ1;
      XMVECTOR         Q2X;
      XMVECTOR         Q2Y;
      XMVECTOR         Q2Z;
      XMVECTOR         Q2W;
      XMVECTOR         Q1WZYX;
      XMVECTOR         Q1ZWXY;
      XMVECTOR         Q1YXWZ;
      XMVECTOR         Result;
      CONST XMVECTORU32 ControlWZYX = {XM_PERMUTE_0W, XM_PERMUTE_1Z, XM_PERMUTE_0Y, XM_PERMUTE_1X};
      CONST XMVECTORU32 ControlZWXY = {XM_PERMUTE_0Z, XM_PERMUTE_0W, XM_PERMUTE_1X, XM_PERMUTE_1Y};
      CONST XMVECTORU32 ControlYXWZ = {XM_PERMUTE_1Y, XM_PERMUTE_0X, XM_PERMUTE_0W, XM_PERMUTE_1Z};
  
      NegativeQ1 = XMVectorNegate(Q1);
  
      Q2W = XMVectorSplatW(Q2);
      Q2X = XMVectorSplatX(Q2);
      Q2Y = XMVectorSplatY(Q2);
      Q2Z = XMVectorSplatZ(Q2);
  
      Q1WZYX = XMVectorPermute(Q1, NegativeQ1, ControlWZYX.v);
      Q1ZWXY = XMVectorPermute(Q1, NegativeQ1, ControlZWXY.v);
      Q1YXWZ = XMVectorPermute(Q1, NegativeQ1, ControlYXWZ.v);
  
      Result = XMVectorMultiply(Q1, Q2W);
      Result = XMVectorMultiplyAdd(Q1WZYX, Q2X, Result);
      Result = XMVectorMultiplyAdd(Q1ZWXY, Q2Y, Result);
      Result = XMVectorMultiplyAdd(Q1YXWZ, Q2Z, Result);
  
      return Result;
  
  #elif defined(_XM_SSE_INTRINSICS_)
      static CONST XMVECTORF32 ControlWZYX = { 1.0f,-1.0f, 1.0f,-1.0f};
      static CONST XMVECTORF32 ControlZWXY = { 1.0f, 1.0f,-1.0f,-1.0f};
      static CONST XMVECTORF32 ControlYXWZ = {-1.0f, 1.0f, 1.0f,-1.0f};
      // Copy to SSE registers and use as few as possible for x86
      XMVECTOR Q2X = Q2;
      XMVECTOR Q2Y = Q2;
      XMVECTOR Q2Z = Q2;
      XMVECTOR vResult = Q2;
      // Splat with one instruction
      vResult = _mm_shuffle_ps(vResult,vResult,_MM_SHUFFLE(3,3,3,3));
      Q2X = _mm_shuffle_ps(Q2X,Q2X,_MM_SHUFFLE(0,0,0,0));
      Q2Y = _mm_shuffle_ps(Q2Y,Q2Y,_MM_SHUFFLE(1,1,1,1));
      Q2Z = _mm_shuffle_ps(Q2Z,Q2Z,_MM_SHUFFLE(2,2,2,2));
      // Retire Q1 and perform Q1*Q2W
      vResult = _mm_mul_ps(vResult,Q1);
      XMVECTOR Q1Shuffle = Q1;
      // Shuffle the copies of Q1
      Q1Shuffle = _mm_shuffle_ps(Q1Shuffle,Q1Shuffle,_MM_SHUFFLE(0,1,2,3));
      // Mul by Q1WZYX
      Q2X = _mm_mul_ps(Q2X,Q1Shuffle);
      Q1Shuffle = _mm_shuffle_ps(Q1Shuffle,Q1Shuffle,_MM_SHUFFLE(2,3,0,1));
      // Flip the signs on y and z
      Q2X = _mm_mul_ps(Q2X,ControlWZYX);
      // Mul by Q1ZWXY
      Q2Y = _mm_mul_ps(Q2Y,Q1Shuffle);
      Q1Shuffle = _mm_shuffle_ps(Q1Shuffle,Q1Shuffle,_MM_SHUFFLE(0,1,2,3));
      // Flip the signs on z and w
      Q2Y = _mm_mul_ps(Q2Y,ControlZWXY);
      // Mul by Q1YXWZ
      Q2Z = _mm_mul_ps(Q2Z,Q1Shuffle);
      vResult = _mm_add_ps(vResult,Q2X);
      // Flip the signs on x and w
      Q2Z = _mm_mul_ps(Q2Z,ControlYXWZ);
      Q2Y = _mm_add_ps(Q2Y,Q2Z);
      vResult = _mm_add_ps(vResult,Q2Y);
      return vResult;
  #else // _XM_VMX128_INTRINSICS_
  #endif // _XM_VMX128_INTRINSICS_
  }
  
  //------------------------------------------------------------------------------
  
  XMFINLINE XMVECTOR XMQuaternionLengthSq
  (
      FXMVECTOR Q
  )
  {
      return XMVector4LengthSq(Q);
  }
  
  //------------------------------------------------------------------------------
  
  XMFINLINE XMVECTOR XMQuaternionReciprocalLength
  (
      FXMVECTOR Q
  )
  {
      return XMVector4ReciprocalLength(Q);
  }
  
  //------------------------------------------------------------------------------
  
  XMFINLINE XMVECTOR XMQuaternionLength
  (
      FXMVECTOR Q
  )
  {
      return XMVector4Length(Q);
  }
  
  //------------------------------------------------------------------------------
  
  XMFINLINE XMVECTOR XMQuaternionNormalizeEst
  (
      FXMVECTOR Q
  )
  {
      return XMVector4NormalizeEst(Q);
  }
  
  //------------------------------------------------------------------------------
  
  XMFINLINE XMVECTOR XMQuaternionNormalize
  (
      FXMVECTOR Q
  )
  {
      return XMVector4Normalize(Q);
  }
  
  //------------------------------------------------------------------------------
  
  XMFINLINE XMVECTOR XMQuaternionConjugate
  (
      FXMVECTOR Q
  )
  {
  #if defined(_XM_NO_INTRINSICS_)
  
      XMVECTOR Result = {
          -Q.vector4_f32[0],
          -Q.vector4_f32[1],
          -Q.vector4_f32[2],
          Q.vector4_f32[3]
      };
      return Result;
  #elif defined(_XM_SSE_INTRINSICS_)
      static const XMVECTORF32 NegativeOne3 = {-1.0f,-1.0f,-1.0f,1.0f};
      XMVECTOR Result = _mm_mul_ps(Q,NegativeOne3);
      return Result;
  #else // _XM_VMX128_INTRINSICS_
  #endif // _XM_VMX128_INTRINSICS_
  }
  
  //------------------------------------------------------------------------------
  
  XMFINLINE XMVECTOR XMQuaternionInverse
  (
      FXMVECTOR Q
  )
  {
  #if defined(_XM_NO_INTRINSICS_)
  
      XMVECTOR        Conjugate;
      XMVECTOR        L;
      XMVECTOR        Control;
      XMVECTOR        Result;
      CONST XMVECTOR  Zero = XMVectorZero();
  
      L = XMVector4LengthSq(Q);
      Conjugate = XMQuaternionConjugate(Q);
  
      Control = XMVectorLessOrEqual(L, g_XMEpsilon.v);
  
      L = XMVectorReciprocal(L);
      Result = XMVectorMultiply(Conjugate, L);
  
      Result = XMVectorSelect(Result, Zero, Control);
  
      return Result;
  
  #elif defined(_XM_SSE_INTRINSICS_)
      XMVECTOR        Conjugate;
      XMVECTOR        L;
      XMVECTOR        Control;
      XMVECTOR        Result;
      XMVECTOR  Zero = XMVectorZero();
  
      L = XMVector4LengthSq(Q);
      Conjugate = XMQuaternionConjugate(Q);
      Control = XMVectorLessOrEqual(L, g_XMEpsilon);
      Result = _mm_div_ps(Conjugate,L);
      Result = XMVectorSelect(Result, Zero, Control);
      return Result;
  #else // _XM_VMX128_INTRINSICS_
  #endif // _XM_VMX128_INTRINSICS_
  }
  
  //------------------------------------------------------------------------------
  
  XMFINLINE XMVECTOR XMQuaternionLn
  (
      FXMVECTOR Q
  )
  {
  #if defined(_XM_NO_INTRINSICS_)
  
      XMVECTOR Q0;
      XMVECTOR QW;
      XMVECTOR Theta;
      XMVECTOR SinTheta;
      XMVECTOR S;
      XMVECTOR ControlW;
      XMVECTOR Result;
      static CONST XMVECTOR OneMinusEpsilon = {1.0f - 0.00001f, 1.0f - 0.00001f, 1.0f - 0.00001f, 1.0f - 0.00001f};
  
      QW = XMVectorSplatW(Q);
      Q0 = XMVectorSelect(g_XMSelect1110.v, Q, g_XMSelect1110.v);
  
      ControlW = XMVectorInBounds(QW, OneMinusEpsilon);
  
      Theta = XMVectorACos(QW);
      SinTheta = XMVectorSin(Theta);
  
      S = XMVectorReciprocal(SinTheta);
      S = XMVectorMultiply(Theta, S);
  
      Result = XMVectorMultiply(Q0, S);
  
      Result = XMVectorSelect(Q0, Result, ControlW);
  
      return Result;
  
  #elif defined(_XM_SSE_INTRINSICS_)
      static CONST XMVECTORF32 OneMinusEpsilon = {1.0f - 0.00001f, 1.0f - 0.00001f, 1.0f - 0.00001f, 1.0f - 0.00001f};
      static CONST XMVECTORF32 NegOneMinusEpsilon = {-(1.0f - 0.00001f), -(1.0f - 0.00001f),-(1.0f - 0.00001f),-(1.0f - 0.00001f)};
      // Get W only
      XMVECTOR QW = _mm_shuffle_ps(Q,Q,_MM_SHUFFLE(3,3,3,3));
      // W = 0
      XMVECTOR Q0 = _mm_and_ps(Q,g_XMMask3);
      // Use W if within bounds
      XMVECTOR ControlW = _mm_cmple_ps(QW,OneMinusEpsilon);
      XMVECTOR vTemp2 = _mm_cmpge_ps(QW,NegOneMinusEpsilon);
      ControlW = _mm_and_ps(ControlW,vTemp2);
      // Get theta
      XMVECTOR vTheta = XMVectorACos(QW);
      // Get Sine of theta
      vTemp2 = XMVectorSin(vTheta);
      // theta/sine of theta
      vTheta = _mm_div_ps(vTheta,vTemp2);
      // Here's the answer
      vTheta = _mm_mul_ps(vTheta,Q0);
      // Was W in bounds? If not, return input as is
      vTheta = XMVectorSelect(Q0,vTheta,ControlW);
      return vTheta;
  #else // _XM_VMX128_INTRINSICS_
  #endif // _XM_VMX128_INTRINSICS_
  }
  
  //------------------------------------------------------------------------------
  
  XMFINLINE XMVECTOR XMQuaternionExp
  (
      FXMVECTOR Q
  )
  {
  #if defined(_XM_NO_INTRINSICS_) 
  
      XMVECTOR Theta;
      XMVECTOR SinTheta;
      XMVECTOR CosTheta;
      XMVECTOR S;
      XMVECTOR Control;
      XMVECTOR Zero;
      XMVECTOR Result;
  
      Theta = XMVector3Length(Q);
      XMVectorSinCos(&SinTheta, &CosTheta, Theta);
  
      S = XMVectorReciprocal(Theta);
      S = XMVectorMultiply(SinTheta, S);
  
      Result = XMVectorMultiply(Q, S);
  
      Zero = XMVectorZero();
      Control = XMVectorNearEqual(Theta, Zero, g_XMEpsilon.v);
      Result = XMVectorSelect(Result, Q, Control);
  
      Result = XMVectorSelect(CosTheta, Result, g_XMSelect1110.v);
  
      return Result;
  
  #elif defined(_XM_SSE_INTRINSICS_)
      XMVECTOR Theta;
      XMVECTOR SinTheta;
      XMVECTOR CosTheta;
      XMVECTOR S;
      XMVECTOR Control;
      XMVECTOR Zero;
      XMVECTOR Result;
      Theta = XMVector3Length(Q);
      XMVectorSinCos(&SinTheta, &CosTheta, Theta);
      S = _mm_div_ps(SinTheta,Theta);
      Result = _mm_mul_ps(Q, S);
      Zero = XMVectorZero();
      Control = XMVectorNearEqual(Theta, Zero, g_XMEpsilon);
      Result = XMVectorSelect(Result,Q,Control);
      Result = _mm_and_ps(Result,g_XMMask3);
      CosTheta = _mm_and_ps(CosTheta,g_XMMaskW);
      Result = _mm_or_ps(Result,CosTheta);
      return Result;
  #else // _XM_VMX128_INTRINSICS_
  #endif // _XM_VMX128_INTRINSICS_
  }
  
  //------------------------------------------------------------------------------
  
  XMINLINE XMVECTOR XMQuaternionSlerp
  (
      FXMVECTOR Q0,
      FXMVECTOR Q1,
      FLOAT    t
  )
  {
      XMVECTOR T = XMVectorReplicate(t);
      return XMQuaternionSlerpV(Q0, Q1, T);
  }
  
  //------------------------------------------------------------------------------
  
  XMINLINE XMVECTOR XMQuaternionSlerpV
  (
      FXMVECTOR Q0,
      FXMVECTOR Q1,
      FXMVECTOR T
  )
  {
  #if defined(_XM_NO_INTRINSICS_)
  
      // Result = Q0 * sin((1.0 - t) * Omega) / sin(Omega) + Q1 * sin(t * Omega) / sin(Omega)
      XMVECTOR Omega;
      XMVECTOR CosOmega;
      XMVECTOR SinOmega;
      XMVECTOR InvSinOmega;
      XMVECTOR V01;
      XMVECTOR C1000;
      XMVECTOR SignMask;
      XMVECTOR S0;
      XMVECTOR S1;
      XMVECTOR Sign;
      XMVECTOR Control;
      XMVECTOR Result;
      XMVECTOR Zero;
      CONST XMVECTOR OneMinusEpsilon = {1.0f - 0.00001f, 1.0f - 0.00001f, 1.0f - 0.00001f, 1.0f - 0.00001f};
  
      XMASSERT((T.vector4_f32[1] == T.vector4_f32[0]) && (T.vector4_f32[2] == T.vector4_f32[0]) && (T.vector4_f32[3] == T.vector4_f32[0]));
  
      CosOmega = XMQuaternionDot(Q0, Q1);
  
      Zero = XMVectorZero();
      Control = XMVectorLess(CosOmega, Zero);
      Sign = XMVectorSelect(g_XMOne.v, g_XMNegativeOne.v, Control);
  
      CosOmega = XMVectorMultiply(CosOmega, Sign);
  
      Control = XMVectorLess(CosOmega, OneMinusEpsilon);
  
      SinOmega = XMVectorNegativeMultiplySubtract(CosOmega, CosOmega, g_XMOne.v);
      SinOmega = XMVectorSqrt(SinOmega);
  
      Omega = XMVectorATan2(SinOmega, CosOmega);
  
      SignMask = XMVectorSplatSignMask();
      C1000 = XMVectorSetBinaryConstant(1, 0, 0, 0);
      V01 = XMVectorShiftLeft(T, Zero, 2);
      SignMask = XMVectorShiftLeft(SignMask, Zero, 3);
      V01 = XMVectorXorInt(V01, SignMask);
      V01 = XMVectorAdd(C1000, V01);
  
      InvSinOmega = XMVectorReciprocal(SinOmega);
  
      S0 = XMVectorMultiply(V01, Omega);
      S0 = XMVectorSin(S0);
      S0 = XMVectorMultiply(S0, InvSinOmega);
  
      S0 = XMVectorSelect(V01, S0, Control);
  
      S1 = XMVectorSplatY(S0);
      S0 = XMVectorSplatX(S0);
  
      S1 = XMVectorMultiply(S1, Sign);
  
      Result = XMVectorMultiply(Q0, S0);
      Result = XMVectorMultiplyAdd(Q1, S1, Result);
  
      return Result;
  
  #elif defined(_XM_SSE_INTRINSICS_)
      // Result = Q0 * sin((1.0 - t) * Omega) / sin(Omega) + Q1 * sin(t * Omega) / sin(Omega)
      XMVECTOR Omega;
      XMVECTOR CosOmega;
      XMVECTOR SinOmega;
      XMVECTOR V01;
      XMVECTOR S0;
      XMVECTOR S1;
      XMVECTOR Sign;
      XMVECTOR Control;
      XMVECTOR Result;
      XMVECTOR Zero;
      static const XMVECTORF32 OneMinusEpsilon = {1.0f - 0.00001f, 1.0f - 0.00001f, 1.0f - 0.00001f, 1.0f - 0.00001f};
      static const XMVECTORI32 SignMask2 = {0x80000000,0x00000000,0x00000000,0x00000000};
      static const XMVECTORI32 MaskXY = {0xFFFFFFFF,0xFFFFFFFF,0x00000000,0x00000000};
  
      XMASSERT((XMVectorGetY(T) == XMVectorGetX(T)) && (XMVectorGetZ(T) == XMVectorGetX(T)) && (XMVectorGetW(T) == XMVectorGetX(T)));
  
      CosOmega = XMQuaternionDot(Q0, Q1);
  
      Zero = XMVectorZero();
      Control = XMVectorLess(CosOmega, Zero);
      Sign = XMVectorSelect(g_XMOne, g_XMNegativeOne, Control);
  
      CosOmega = _mm_mul_ps(CosOmega, Sign);
  
      Control = XMVectorLess(CosOmega, OneMinusEpsilon);
  
      SinOmega = _mm_mul_ps(CosOmega,CosOmega);
      SinOmega = _mm_sub_ps(g_XMOne,SinOmega);
      SinOmega = _mm_sqrt_ps(SinOmega);
  
      Omega = XMVectorATan2(SinOmega, CosOmega);
  
      V01 = _mm_shuffle_ps(T,T,_MM_SHUFFLE(2,3,0,1));
      V01 = _mm_and_ps(V01,MaskXY);
      V01 = _mm_xor_ps(V01,SignMask2);
      V01 = _mm_add_ps(g_XMIdentityR0, V01);
  
      S0 = _mm_mul_ps(V01, Omega);
      S0 = XMVectorSin(S0);
      S0 = _mm_div_ps(S0, SinOmega);
  
      S0 = XMVectorSelect(V01, S0, Control);
  
      S1 = XMVectorSplatY(S0);
      S0 = XMVectorSplatX(S0);
  
      S1 = _mm_mul_ps(S1, Sign);
      Result = _mm_mul_ps(Q0, S0);
      S1 = _mm_mul_ps(S1, Q1);
      Result = _mm_add_ps(Result,S1);
      return Result;
  #else // _XM_VMX128_INTRINSICS_
  #endif // _XM_VMX128_INTRINSICS_
  }
  
  //------------------------------------------------------------------------------
  
  XMFINLINE XMVECTOR XMQuaternionSquad
  (
      FXMVECTOR Q0,
      FXMVECTOR Q1,
      FXMVECTOR Q2,
      CXMVECTOR Q3,
      FLOAT    t
  )
  {
      XMVECTOR T = XMVectorReplicate(t);
      return XMQuaternionSquadV(Q0, Q1, Q2, Q3, T);
  }
  
  //------------------------------------------------------------------------------
  
  XMFINLINE XMVECTOR XMQuaternionSquadV
  (
      FXMVECTOR Q0,
      FXMVECTOR Q1,
      FXMVECTOR Q2,
      CXMVECTOR Q3,
      CXMVECTOR T
  )
  {
      XMVECTOR Q03;
      XMVECTOR Q12;
      XMVECTOR TP;
      XMVECTOR Two;
      XMVECTOR Result;
  
      XMASSERT( (XMVectorGetY(T) == XMVectorGetX(T)) && (XMVectorGetZ(T) == XMVectorGetX(T)) && (XMVectorGetW(T) == XMVectorGetX(T)) );
  
      TP = T;
      Two = XMVectorSplatConstant(2, 0);
  
      Q03 = XMQuaternionSlerpV(Q0, Q3, T);
      Q12 = XMQuaternionSlerpV(Q1, Q2, T);
  
      TP = XMVectorNegativeMultiplySubtract(TP, TP, TP);
      TP = XMVectorMultiply(TP, Two);
  
      Result = XMQuaternionSlerpV(Q03, Q12, TP);
  
      return Result;
  
  }
  
  //------------------------------------------------------------------------------
  
  XMINLINE VOID XMQuaternionSquadSetup
  (
      XMVECTOR* pA,
      XMVECTOR* pB,
      XMVECTOR* pC,
      FXMVECTOR  Q0,
      FXMVECTOR  Q1,
      FXMVECTOR  Q2,
      CXMVECTOR  Q3
  )
  {
      XMVECTOR SQ0, SQ2, SQ3;
      XMVECTOR InvQ1, InvQ2;
      XMVECTOR LnQ0, LnQ1, LnQ2, LnQ3;
      XMVECTOR ExpQ02, ExpQ13;
      XMVECTOR LS01, LS12, LS23;
      XMVECTOR LD01, LD12, LD23;
      XMVECTOR Control0, Control1, Control2;
      XMVECTOR NegativeOneQuarter;
  
      XMASSERT(pA);
      XMASSERT(pB);
      XMASSERT(pC);
  
      LS12 = XMQuaternionLengthSq(XMVectorAdd(Q1, Q2));
      LD12 = XMQuaternionLengthSq(XMVectorSubtract(Q1, Q2));
      SQ2 = XMVectorNegate(Q2);
  
      Control1 = XMVectorLess(LS12, LD12);
      SQ2 = XMVectorSelect(Q2, SQ2, Control1);
  
      LS01 = XMQuaternionLengthSq(XMVectorAdd(Q0, Q1));
      LD01 = XMQuaternionLengthSq(XMVectorSubtract(Q0, Q1));
      SQ0 = XMVectorNegate(Q0);
  
      LS23 = XMQuaternionLengthSq(XMVectorAdd(SQ2, Q3));
      LD23 = XMQuaternionLengthSq(XMVectorSubtract(SQ2, Q3));
      SQ3 = XMVectorNegate(Q3);
  
      Control0 = XMVectorLess(LS01, LD01);
      Control2 = XMVectorLess(LS23, LD23);
  
      SQ0 = XMVectorSelect(Q0, SQ0, Control0);
      SQ3 = XMVectorSelect(Q3, SQ3, Control2);
  
      InvQ1 = XMQuaternionInverse(Q1);
      InvQ2 = XMQuaternionInverse(SQ2);
  
      LnQ0 = XMQuaternionLn(XMQuaternionMultiply(InvQ1, SQ0));
      LnQ2 = XMQuaternionLn(XMQuaternionMultiply(InvQ1, SQ2));
      LnQ1 = XMQuaternionLn(XMQuaternionMultiply(InvQ2, Q1));
      LnQ3 = XMQuaternionLn(XMQuaternionMultiply(InvQ2, SQ3));
  
      NegativeOneQuarter = XMVectorSplatConstant(-1, 2);
  
      ExpQ02 = XMVectorMultiply(XMVectorAdd(LnQ0, LnQ2), NegativeOneQuarter);
      ExpQ13 = XMVectorMultiply(XMVectorAdd(LnQ1, LnQ3), NegativeOneQuarter);
      ExpQ02 = XMQuaternionExp(ExpQ02);
      ExpQ13 = XMQuaternionExp(ExpQ13);
  
      *pA = XMQuaternionMultiply(Q1, ExpQ02);
      *pB = XMQuaternionMultiply(SQ2, ExpQ13);
      *pC = SQ2;
  }
  
  //------------------------------------------------------------------------------
  
  XMFINLINE XMVECTOR XMQuaternionBaryCentric
  (
      FXMVECTOR Q0,
      FXMVECTOR Q1,
      FXMVECTOR Q2,
      FLOAT    f,
      FLOAT    g
  )
  {
      XMVECTOR Q01;
      XMVECTOR Q02;
      FLOAT    s;
      XMVECTOR Result;
  
      s = f + g;
  
      if ((s < 0.00001f) && (s > -0.00001f))
      {
          Result = Q0;
      }
      else
      {
          Q01 = XMQuaternionSlerp(Q0, Q1, s);
          Q02 = XMQuaternionSlerp(Q0, Q2, s);
  
          Result = XMQuaternionSlerp(Q01, Q02, g / s);
      }
  
      return Result;
  }
  
  //------------------------------------------------------------------------------
  
  XMFINLINE XMVECTOR XMQuaternionBaryCentricV
  (
      FXMVECTOR Q0,
      FXMVECTOR Q1,
      FXMVECTOR Q2,
      CXMVECTOR F,
      CXMVECTOR G
  )
  {
      XMVECTOR Q01;
      XMVECTOR Q02;
      XMVECTOR S, GS;
      XMVECTOR Epsilon;
      XMVECTOR Result;
  
      XMASSERT( (XMVectorGetY(F) == XMVectorGetX(F)) && (XMVectorGetZ(F) == XMVectorGetX(F)) && (XMVectorGetW(F) == XMVectorGetX(F)) );
      XMASSERT( (XMVectorGetY(G) == XMVectorGetX(G)) && (XMVectorGetZ(G) == XMVectorGetX(G)) && (XMVectorGetW(G) == XMVectorGetX(G)) );
  
      Epsilon = XMVectorSplatConstant(1, 16);
  
      S = XMVectorAdd(F, G);
  
      if (XMVector4InBounds(S, Epsilon))
      {
          Result = Q0;
      }
      else
      {
          Q01 = XMQuaternionSlerpV(Q0, Q1, S);
          Q02 = XMQuaternionSlerpV(Q0, Q2, S);
          GS = XMVectorReciprocal(S);
          GS = XMVectorMultiply(G, GS);
  
          Result = XMQuaternionSlerpV(Q01, Q02, GS);
      }
  
      return Result;
  }
  
  //------------------------------------------------------------------------------
  // Transformation operations
  //------------------------------------------------------------------------------
  
  //------------------------------------------------------------------------------
  
  XMFINLINE XMVECTOR XMQuaternionIdentity()
  {
  #if defined(_XM_NO_INTRINSICS_)
      return g_XMIdentityR3.v;
  #elif defined(_XM_SSE_INTRINSICS_)
      return g_XMIdentityR3;
  #else // _XM_VMX128_INTRINSICS_
  #endif // _XM_VMX128_INTRINSICS_
  }
  
  //------------------------------------------------------------------------------
  
  XMFINLINE XMVECTOR XMQuaternionRotationRollPitchYaw
  (
      FLOAT Pitch,
      FLOAT Yaw,
      FLOAT Roll
  )
  {
      XMVECTOR Angles;
      XMVECTOR Q;
  
      Angles = XMVectorSet(Pitch, Yaw, Roll, 0.0f);
      Q = XMQuaternionRotationRollPitchYawFromVector(Angles);
  
      return Q;
  }
  
  //------------------------------------------------------------------------------
  
  XMFINLINE XMVECTOR XMQuaternionRotationRollPitchYawFromVector
  (
      FXMVECTOR Angles // <Pitch, Yaw, Roll, 0>
  )
  {
  #if defined(_XM_NO_INTRINSICS_)
  
      XMVECTOR                Q, Q0, Q1;
      XMVECTOR                P0, P1, Y0, Y1, R0, R1;
      XMVECTOR                HalfAngles;
      XMVECTOR                SinAngles, CosAngles;
      static CONST XMVECTORU32 ControlPitch = {XM_PERMUTE_0X, XM_PERMUTE_1X, XM_PERMUTE_1X, XM_PERMUTE_1X};
      static CONST XMVECTORU32 ControlYaw = {XM_PERMUTE_1Y, XM_PERMUTE_0Y, XM_PERMUTE_1Y, XM_PERMUTE_1Y};
      static CONST XMVECTORU32 ControlRoll = {XM_PERMUTE_1Z, XM_PERMUTE_1Z, XM_PERMUTE_0Z, XM_PERMUTE_1Z};
      static CONST XMVECTOR   Sign = {1.0f, -1.0f, -1.0f, 1.0f};
  
      HalfAngles = XMVectorMultiply(Angles, g_XMOneHalf.v);
      XMVectorSinCos(&SinAngles, &CosAngles, HalfAngles);
  
      P0 = XMVectorPermute(SinAngles, CosAngles, ControlPitch.v);
      Y0 = XMVectorPermute(SinAngles, CosAngles, ControlYaw.v);
      R0 = XMVectorPermute(SinAngles, CosAngles, ControlRoll.v);
      P1 = XMVectorPermute(CosAngles, SinAngles, ControlPitch.v);
      Y1 = XMVectorPermute(CosAngles, SinAngles, ControlYaw.v);
      R1 = XMVectorPermute(CosAngles, SinAngles, ControlRoll.v);
  
      Q1 = XMVectorMultiply(P1, Sign);
      Q0 = XMVectorMultiply(P0, Y0);
      Q1 = XMVectorMultiply(Q1, Y1);
      Q0 = XMVectorMultiply(Q0, R0);
      Q = XMVectorMultiplyAdd(Q1, R1, Q0);
  
      return Q;
  
  #elif defined(_XM_SSE_INTRINSICS_)
      XMVECTOR                Q, Q0, Q1;
      XMVECTOR                P0, P1, Y0, Y1, R0, R1;
      XMVECTOR                HalfAngles;
      XMVECTOR                SinAngles, CosAngles;
      static CONST XMVECTORI32 ControlPitch = {XM_PERMUTE_0X, XM_PERMUTE_1X, XM_PERMUTE_1X, XM_PERMUTE_1X};
      static CONST XMVECTORI32 ControlYaw = {XM_PERMUTE_1Y, XM_PERMUTE_0Y, XM_PERMUTE_1Y, XM_PERMUTE_1Y};
      static CONST XMVECTORI32 ControlRoll = {XM_PERMUTE_1Z, XM_PERMUTE_1Z, XM_PERMUTE_0Z, XM_PERMUTE_1Z};
      static CONST XMVECTORF32 Sign = {1.0f, -1.0f, -1.0f, 1.0f};
  
      HalfAngles = _mm_mul_ps(Angles, g_XMOneHalf);
      XMVectorSinCos(&SinAngles, &CosAngles, HalfAngles);
  
      P0 = XMVectorPermute(SinAngles, CosAngles, ControlPitch);
      Y0 = XMVectorPermute(SinAngles, CosAngles, ControlYaw);
      R0 = XMVectorPermute(SinAngles, CosAngles, ControlRoll);
      P1 = XMVectorPermute(CosAngles, SinAngles, ControlPitch);
      Y1 = XMVectorPermute(CosAngles, SinAngles, ControlYaw);
      R1 = XMVectorPermute(CosAngles, SinAngles, ControlRoll);
  
      Q1 = _mm_mul_ps(P1, Sign);
      Q0 = _mm_mul_ps(P0, Y0);
      Q1 = _mm_mul_ps(Q1, Y1);
      Q0 = _mm_mul_ps(Q0, R0);
      Q = _mm_mul_ps(Q1, R1);
      Q = _mm_add_ps(Q,Q0);
      return Q;
  #else // _XM_VMX128_INTRINSICS_
  #endif // _XM_VMX128_INTRINSICS_
  }
  
  //------------------------------------------------------------------------------
  
  XMFINLINE XMVECTOR XMQuaternionRotationNormal
  (
      FXMVECTOR NormalAxis,
      FLOAT    Angle
  )
  {
  #if defined(_XM_NO_INTRINSICS_)
  
      XMVECTOR Q;
      XMVECTOR N;
      XMVECTOR Scale;
  
      N = XMVectorSelect(g_XMOne.v, NormalAxis, g_XMSelect1110.v);
  
      XMScalarSinCos(&Scale.vector4_f32[2], &Scale.vector4_f32[3], 0.5f * Angle);
  
      Scale.vector4_f32[0] = Scale.vector4_f32[1] = Scale.vector4_f32[2];
  
      Q = XMVectorMultiply(N, Scale);
  
      return Q;
  
  #elif defined(_XM_SSE_INTRINSICS_)
      XMVECTOR N = _mm_and_ps(NormalAxis,g_XMMask3);
      N = _mm_or_ps(N,g_XMIdentityR3);
      XMVECTOR Scale = _mm_set_ps1(0.5f * Angle);
      XMVECTOR vSine;
      XMVECTOR vCosine;
      XMVectorSinCos(&vSine,&vCosine,Scale);
      Scale = _mm_and_ps(vSine,g_XMMask3);
      vCosine = _mm_and_ps(vCosine,g_XMMaskW);
      Scale = _mm_or_ps(Scale,vCosine);
      N = _mm_mul_ps(N,Scale);
      return N;
  #else // _XM_VMX128_INTRINSICS_
  #endif // _XM_VMX128_INTRINSICS_
  }
  
  //------------------------------------------------------------------------------
  
  XMFINLINE XMVECTOR XMQuaternionRotationAxis
  (
      FXMVECTOR Axis,
      FLOAT    Angle
  )
  {
  #if defined(_XM_NO_INTRINSICS_)
  
      XMVECTOR Normal;
      XMVECTOR Q;
  
      XMASSERT(!XMVector3Equal(Axis, XMVectorZero()));
      XMASSERT(!XMVector3IsInfinite(Axis));
  
      Normal = XMVector3Normalize(Axis);
      Q = XMQuaternionRotationNormal(Normal, Angle);
  
      return Q;
  
  #elif defined(_XM_SSE_INTRINSICS_)
      XMVECTOR Normal;
      XMVECTOR Q;
  
      XMASSERT(!XMVector3Equal(Axis, XMVectorZero()));
      XMASSERT(!XMVector3IsInfinite(Axis));
  
      Normal = XMVector3Normalize(Axis);
      Q = XMQuaternionRotationNormal(Normal, Angle);
      return Q;
  #else // _XM_VMX128_INTRINSICS_
  #endif // _XM_VMX128_INTRINSICS_
  }
  
  //------------------------------------------------------------------------------
  
  XMINLINE XMVECTOR XMQuaternionRotationMatrix
  (
      CXMMATRIX M
  )
  {
  #if defined(_XM_NO_INTRINSICS_) || defined(_XM_SSE_INTRINSICS_)
  
      XMVECTOR Q0, Q1, Q2;
      XMVECTOR M00, M11, M22;
      XMVECTOR CQ0, CQ1, C;
      XMVECTOR CX, CY, CZ, CW;
      XMVECTOR SQ1, Scale;
      XMVECTOR Rsq, Sqrt, VEqualsNaN;
      XMVECTOR A, B, P;
      XMVECTOR PermuteSplat, PermuteSplatT;
      XMVECTOR SignB, SignBT;
      XMVECTOR PermuteControl, PermuteControlT;
      XMVECTOR Result;
      static CONST XMVECTORF32 OneQuarter = {0.25f, 0.25f, 0.25f, 0.25f};
      static CONST XMVECTORF32 SignPNNP = {1.0f, -1.0f, -1.0f, 1.0f};
      static CONST XMVECTORF32 SignNPNP = {-1.0f, 1.0f, -1.0f, 1.0f};
      static CONST XMVECTORF32 SignNNPP = {-1.0f, -1.0f, 1.0f, 1.0f};
      static CONST XMVECTORF32 SignPNPP = {1.0f, -1.0f, 1.0f, 1.0f};
      static CONST XMVECTORF32 SignPPNP = {1.0f, 1.0f, -1.0f, 1.0f};
      static CONST XMVECTORF32 SignNPPP = {-1.0f, 1.0f, 1.0f, 1.0f};
      static CONST XMVECTORU32 Permute0X0X0Y0W = {XM_PERMUTE_0X, XM_PERMUTE_0X, XM_PERMUTE_0Y, XM_PERMUTE_0W};
      static CONST XMVECTORU32 Permute0Y0Z0Z1W = {XM_PERMUTE_0Y, XM_PERMUTE_0Z, XM_PERMUTE_0Z, XM_PERMUTE_1W};
      static CONST XMVECTORU32 SplatX = {XM_PERMUTE_0X, XM_PERMUTE_0X, XM_PERMUTE_0X, XM_PERMUTE_0X};
      static CONST XMVECTORU32 SplatY = {XM_PERMUTE_0Y, XM_PERMUTE_0Y, XM_PERMUTE_0Y, XM_PERMUTE_0Y};
      static CONST XMVECTORU32 SplatZ = {XM_PERMUTE_0Z, XM_PERMUTE_0Z, XM_PERMUTE_0Z, XM_PERMUTE_0Z};
      static CONST XMVECTORU32 SplatW = {XM_PERMUTE_0W, XM_PERMUTE_0W, XM_PERMUTE_0W, XM_PERMUTE_0W};
      static CONST XMVECTORU32 PermuteC = {XM_PERMUTE_0X, XM_PERMUTE_0Z, XM_PERMUTE_1X, XM_PERMUTE_1Y};
      static CONST XMVECTORU32 PermuteA = {XM_PERMUTE_0Y, XM_PERMUTE_1Y, XM_PERMUTE_1Z, XM_PERMUTE_0W};
      static CONST XMVECTORU32 PermuteB = {XM_PERMUTE_1X, XM_PERMUTE_1W, XM_PERMUTE_0Z, XM_PERMUTE_0W};
      static CONST XMVECTORU32 Permute0 = {XM_PERMUTE_0X, XM_PERMUTE_1X, XM_PERMUTE_1Z, XM_PERMUTE_1Y};
      static CONST XMVECTORU32 Permute1 = {XM_PERMUTE_1X, XM_PERMUTE_0Y, XM_PERMUTE_1Y, XM_PERMUTE_1Z};
      static CONST XMVECTORU32 Permute2 = {XM_PERMUTE_1Z, XM_PERMUTE_1Y, XM_PERMUTE_0Z, XM_PERMUTE_1X};
      static CONST XMVECTORU32 Permute3 = {XM_PERMUTE_1Y, XM_PERMUTE_1Z, XM_PERMUTE_1X, XM_PERMUTE_0W};
  
      M00 = XMVectorSplatX(M.r[0]);
      M11 = XMVectorSplatY(M.r[1]);
      M22 = XMVectorSplatZ(M.r[2]);
  
      Q0 = XMVectorMultiply(SignPNNP.v, M00);
      Q0 = XMVectorMultiplyAdd(SignNPNP.v, M11, Q0);
      Q0 = XMVectorMultiplyAdd(SignNNPP.v, M22, Q0);
  
      Q1 = XMVectorAdd(Q0, g_XMOne.v);
  
      Rsq = XMVectorReciprocalSqrt(Q1);
      VEqualsNaN = XMVectorIsNaN(Rsq);
      Sqrt = XMVectorMultiply(Q1, Rsq);
      Q1 = XMVectorSelect(Sqrt, Q1, VEqualsNaN);
  
      Q1 = XMVectorMultiply(Q1, g_XMOneHalf.v);
  
      SQ1 = XMVectorMultiply(Rsq, g_XMOneHalf.v);
  
      CQ0 = XMVectorPermute(Q0, Q0, Permute0X0X0Y0W.v);
      CQ1 = XMVectorPermute(Q0, g_XMEpsilon.v, Permute0Y0Z0Z1W.v);
      C = XMVectorGreaterOrEqual(CQ0, CQ1);
  
      CX = XMVectorSplatX(C);
      CY = XMVectorSplatY(C);
      CZ = XMVectorSplatZ(C);
      CW = XMVectorSplatW(C);
  
      PermuteSplat = XMVectorSelect(SplatZ.v, SplatY.v, CZ);
      SignB = XMVectorSelect(SignNPPP.v, SignPPNP.v, CZ);
      PermuteControl = XMVectorSelect(Permute2.v, Permute1.v, CZ);
  
      PermuteSplat = XMVectorSelect(PermuteSplat, SplatZ.v, CX);
      SignB = XMVectorSelect(SignB, SignNPPP.v, CX);
      PermuteControl = XMVectorSelect(PermuteControl, Permute2.v, CX);
  
      PermuteSplatT = XMVectorSelect(PermuteSplat,SplatX.v, CY);
      SignBT = XMVectorSelect(SignB, SignPNPP.v, CY);
      PermuteControlT = XMVectorSelect(PermuteControl,Permute0.v, CY);
  
      PermuteSplat = XMVectorSelect(PermuteSplat, PermuteSplatT, CX);
      SignB = XMVectorSelect(SignB, SignBT, CX);
      PermuteControl = XMVectorSelect(PermuteControl, PermuteControlT, CX);
  
      PermuteSplat = XMVectorSelect(PermuteSplat,SplatW.v, CW);
      SignB = XMVectorSelect(SignB, g_XMNegativeOne.v, CW);
      PermuteControl = XMVectorSelect(PermuteControl,Permute3.v, CW);
  
      Scale = XMVectorPermute(SQ1, SQ1, PermuteSplat);
  
      P = XMVectorPermute(M.r[1], M.r[2],PermuteC.v);  // {M10, M12, M20, M21}
      A = XMVectorPermute(M.r[0], P, PermuteA.v);       // {M01, M12, M20, M03}
      B = XMVectorPermute(M.r[0], P, PermuteB.v);       // {M10, M21, M02, M03}
  
      Q2 = XMVectorMultiplyAdd(SignB, B, A);
      Q2 = XMVectorMultiply(Q2, Scale);
  
      Result = XMVectorPermute(Q1, Q2, PermuteControl);
  
      return Result;
  
  #else // _XM_VMX128_INTRINSICS_
  #endif // _XM_VMX128_INTRINSICS_
  }
  
  //------------------------------------------------------------------------------
  // Conversion operations
  //------------------------------------------------------------------------------
  
  //------------------------------------------------------------------------------
  
  XMFINLINE VOID XMQuaternionToAxisAngle
  (
      XMVECTOR* pAxis,
      FLOAT*    pAngle,
      FXMVECTOR  Q
  )
  {
      XMASSERT(pAxis);
      XMASSERT(pAngle);
  
      *pAxis = Q;
  
  #if defined(_XM_SSE_INTRINSICS_) && !defined(_XM_NO_INTRINSICS_)
      *pAngle = 2.0f * acosf(XMVectorGetW(Q));
  #else
      *pAngle = 2.0f * XMScalarACos(XMVectorGetW(Q));
  #endif
  }
  
  /****************************************************************************
   *
   * Plane
   *
   ****************************************************************************/
  
  //------------------------------------------------------------------------------
  // Comparison operations
  //------------------------------------------------------------------------------
  
  //------------------------------------------------------------------------------
  
  XMFINLINE BOOL XMPlaneEqual
  (
      FXMVECTOR P1,
      FXMVECTOR P2
  )
  {
      return XMVector4Equal(P1, P2);
  }
  
  //------------------------------------------------------------------------------
  
  XMFINLINE BOOL XMPlaneNearEqual
  (
      FXMVECTOR P1,
      FXMVECTOR P2,
      FXMVECTOR Epsilon
  )
  {
      XMVECTOR NP1 = XMPlaneNormalize(P1);
      XMVECTOR NP2 = XMPlaneNormalize(P2);
      return XMVector4NearEqual(NP1, NP2, Epsilon);
  }
  
  //------------------------------------------------------------------------------
  
  XMFINLINE BOOL XMPlaneNotEqual
  (
      FXMVECTOR P1,
      FXMVECTOR P2
  )
  {
      return XMVector4NotEqual(P1, P2);
  }
  
  //------------------------------------------------------------------------------
  
  XMFINLINE BOOL XMPlaneIsNaN
  (
      FXMVECTOR P
  )
  {
      return XMVector4IsNaN(P);
  }
  
  //------------------------------------------------------------------------------
  
  XMFINLINE BOOL XMPlaneIsInfinite
  (
      FXMVECTOR P
  )
  {
      return XMVector4IsInfinite(P);
  }
  
  //------------------------------------------------------------------------------
  // Computation operations
  //------------------------------------------------------------------------------
  
  //------------------------------------------------------------------------------
  
  XMFINLINE XMVECTOR XMPlaneDot
  (
      FXMVECTOR P,
      FXMVECTOR V
  )
  {
  #if defined(_XM_NO_INTRINSICS_)
  
      return XMVector4Dot(P, V);
  
  #elif defined(_XM_SSE_INTRINSICS_)
      __m128 vTemp2 = V;
      __m128 vTemp = _mm_mul_ps(P,vTemp2);
      vTemp2 = _mm_shuffle_ps(vTemp2,vTemp,_MM_SHUFFLE(1,0,0,0)); // Copy X to the Z position and Y to the W position
      vTemp2 = _mm_add_ps(vTemp2,vTemp);          // Add Z = X+Z; W = Y+W;
      vTemp = _mm_shuffle_ps(vTemp,vTemp2,_MM_SHUFFLE(0,3,0,0));  // Copy W to the Z position
      vTemp = _mm_add_ps(vTemp,vTemp2);           // Add Z and W together
      return _mm_shuffle_ps(vTemp,vTemp,_MM_SHUFFLE(2,2,2,2));    // Splat Z and return
  #else // _XM_VMX128_INTRINSICS_
  #endif // _XM_VMX128_INTRINSICS_
  }
  
  //------------------------------------------------------------------------------
  
  XMFINLINE XMVECTOR XMPlaneDotCoord
  (
      FXMVECTOR P,
      FXMVECTOR V
  )
  {
  #if defined(_XM_NO_INTRINSICS_)
  
      XMVECTOR V3;
      XMVECTOR Result;
  
      // Result = P[0] * V[0] + P[1] * V[1] + P[2] * V[2] + P[3]
      V3 = XMVectorSelect(g_XMOne.v, V, g_XMSelect1110.v);
      Result = XMVector4Dot(P, V3);
  
      return Result;
  
  #elif defined(_XM_SSE_INTRINSICS_)
      XMVECTOR vTemp2 = _mm_and_ps(V,g_XMMask3);
      vTemp2 = _mm_or_ps(vTemp2,g_XMIdentityR3);
      XMVECTOR vTemp = _mm_mul_ps(P,vTemp2);
      vTemp2 = _mm_shuffle_ps(vTemp2,vTemp,_MM_SHUFFLE(1,0,0,0)); // Copy X to the Z position and Y to the W position
      vTemp2 = _mm_add_ps(vTemp2,vTemp);          // Add Z = X+Z; W = Y+W;
      vTemp = _mm_shuffle_ps(vTemp,vTemp2,_MM_SHUFFLE(0,3,0,0));  // Copy W to the Z position
      vTemp = _mm_add_ps(vTemp,vTemp2);           // Add Z and W together
      return _mm_shuffle_ps(vTemp,vTemp,_MM_SHUFFLE(2,2,2,2));    // Splat Z and return
  #else // _XM_VMX128_INTRINSICS_
  #endif // _XM_VMX128_INTRINSICS_
  }
  
  //------------------------------------------------------------------------------
  
  XMFINLINE XMVECTOR XMPlaneDotNormal
  (
      FXMVECTOR P,
      FXMVECTOR V
  )
  {
      return XMVector3Dot(P, V);
  }
  
  //------------------------------------------------------------------------------
  // XMPlaneNormalizeEst uses a reciprocal estimate and
  // returns QNaN on zero and infinite vectors.
  
  XMFINLINE XMVECTOR XMPlaneNormalizeEst
  (
      FXMVECTOR P
  )
  {
  #if defined(_XM_NO_INTRINSICS_)
  
      XMVECTOR Result;
      Result = XMVector3ReciprocalLength(P);
      Result = XMVectorMultiply(P, Result);
      return Result;
  
  #elif defined(_XM_SSE_INTRINSICS_)
      // Perform the dot product
      XMVECTOR vDot = _mm_mul_ps(P,P);
      // x=Dot.y, y=Dot.z
      XMVECTOR vTemp = _mm_shuffle_ps(vDot,vDot,_MM_SHUFFLE(2,1,2,1));
      // Result.x = x+y
      vDot = _mm_add_ss(vDot,vTemp);
      // x=Dot.z
      vTemp = _mm_shuffle_ps(vTemp,vTemp,_MM_SHUFFLE(1,1,1,1));
      // Result.x = (x+y)+z
      vDot = _mm_add_ss(vDot,vTemp);
      // Splat x
  	vDot = _mm_shuffle_ps(vDot,vDot,_MM_SHUFFLE(0,0,0,0));
      // Get the reciprocal
      vDot = _mm_rsqrt_ps(vDot);
      // Get the reciprocal
      vDot = _mm_mul_ps(vDot,P);
      return vDot;
  #else // _XM_VMX128_INTRINSICS_
  #endif // _XM_VMX128_INTRINSICS_
  }
  
  //------------------------------------------------------------------------------
  
  XMFINLINE XMVECTOR XMPlaneNormalize
  (
      FXMVECTOR P
  )
  {
  #if defined(_XM_NO_INTRINSICS_)
      FLOAT fLengthSq = sqrtf((P.vector4_f32[0]*P.vector4_f32[0])+(P.vector4_f32[1]*P.vector4_f32[1])+(P.vector4_f32[2]*P.vector4_f32[2]));
      // Prevent divide by zero
      if (fLengthSq) {
          fLengthSq = 1.0f/fLengthSq;
      }
      {
      XMVECTOR vResult = {
          P.vector4_f32[0]*fLengthSq,
          P.vector4_f32[1]*fLengthSq,
          P.vector4_f32[2]*fLengthSq,
          P.vector4_f32[3]*fLengthSq
      };
      return vResult;
      }
  #elif defined(_XM_SSE_INTRINSICS_)
      // Perform the dot product on x,y and z only
      XMVECTOR vLengthSq = _mm_mul_ps(P,P);
      XMVECTOR vTemp = _mm_shuffle_ps(vLengthSq,vLengthSq,_MM_SHUFFLE(2,1,2,1));
      vLengthSq = _mm_add_ss(vLengthSq,vTemp);
      vTemp = _mm_shuffle_ps(vTemp,vTemp,_MM_SHUFFLE(1,1,1,1));
      vLengthSq = _mm_add_ss(vLengthSq,vTemp);
  	vLengthSq = _mm_shuffle_ps(vLengthSq,vLengthSq,_MM_SHUFFLE(0,0,0,0));
      // Prepare for the division
      XMVECTOR vResult = _mm_sqrt_ps(vLengthSq);
      // Failsafe on zero (Or epsilon) length planes
      // If the length is infinity, set the elements to zero
      vLengthSq = _mm_cmpneq_ps(vLengthSq,g_XMInfinity);
      // Reciprocal mul to perform the normalization
      vResult = _mm_div_ps(P,vResult);
      // Any that are infinity, set to zero
      vResult = _mm_and_ps(vResult,vLengthSq);
      return vResult;
  #else // _XM_VMX128_INTRINSICS_
  #endif // _XM_VMX128_INTRINSICS_
  }
  
  //------------------------------------------------------------------------------
  
  XMFINLINE XMVECTOR XMPlaneIntersectLine
  (
      FXMVECTOR P,
      FXMVECTOR LinePoint1,
      FXMVECTOR LinePoint2
  )
  {
  #if defined(_XM_NO_INTRINSICS_)
  
      XMVECTOR V1;
      XMVECTOR V2;
      XMVECTOR D;
      XMVECTOR ReciprocalD;
      XMVECTOR VT;
      XMVECTOR Point;
      XMVECTOR Zero;
      XMVECTOR Control;
      XMVECTOR Result;
  
      V1 = XMVector3Dot(P, LinePoint1);
      V2 = XMVector3Dot(P, LinePoint2);
      D = XMVectorSubtract(V1, V2);
  
      ReciprocalD = XMVectorReciprocal(D);
      VT = XMPlaneDotCoord(P, LinePoint1);
      VT = XMVectorMultiply(VT, ReciprocalD);
  
      Point = XMVectorSubtract(LinePoint2, LinePoint1);
      Point = XMVectorMultiplyAdd(Point, VT, LinePoint1);
  
      Zero = XMVectorZero();
      Control = XMVectorNearEqual(D, Zero, g_XMEpsilon.v);
  
      Result = XMVectorSelect(Point, g_XMQNaN.v, Control);
  
      return Result;
  
  #elif defined(_XM_SSE_INTRINSICS_)
      XMVECTOR V1;
      XMVECTOR V2;
      XMVECTOR D;
      XMVECTOR VT;
      XMVECTOR Point;
      XMVECTOR Zero;
      XMVECTOR Control;
      XMVECTOR Result;
  
      V1 = XMVector3Dot(P, LinePoint1);
      V2 = XMVector3Dot(P, LinePoint2);
      D = _mm_sub_ps(V1, V2);
  
      VT = XMPlaneDotCoord(P, LinePoint1);
      VT = _mm_div_ps(VT, D);
  
      Point = _mm_sub_ps(LinePoint2, LinePoint1);
      Point = _mm_mul_ps(Point,VT);
      Point = _mm_add_ps(Point,LinePoint1);
      Zero = XMVectorZero();
      Control = XMVectorNearEqual(D, Zero, g_XMEpsilon);
      Result = XMVectorSelect(Point, g_XMQNaN, Control);
      return Result;
  #else // _XM_VMX128_INTRINSICS_
  #endif // _XM_VMX128_INTRINSICS_
  }
  
  //------------------------------------------------------------------------------
  
  XMINLINE VOID XMPlaneIntersectPlane
  (
      XMVECTOR* pLinePoint1,
      XMVECTOR* pLinePoint2,
      FXMVECTOR  P1,
      FXMVECTOR  P2
  )
  {
  #if defined(_XM_NO_INTRINSICS_)
  
      XMVECTOR V1;
      XMVECTOR V2;
      XMVECTOR V3;
      XMVECTOR LengthSq;
      XMVECTOR RcpLengthSq;
      XMVECTOR Point;
      XMVECTOR P1W;
      XMVECTOR P2W;
      XMVECTOR Control;
      XMVECTOR LinePoint1;
      XMVECTOR LinePoint2;
  
      XMASSERT(pLinePoint1);
      XMASSERT(pLinePoint2);
  
      V1 = XMVector3Cross(P2, P1);
  
      LengthSq = XMVector3LengthSq(V1);
  
      V2 = XMVector3Cross(P2, V1);
  
      P1W = XMVectorSplatW(P1);
      Point = XMVectorMultiply(V2, P1W);
  
      V3 = XMVector3Cross(V1, P1);
  
      P2W = XMVectorSplatW(P2);
      Point = XMVectorMultiplyAdd(V3, P2W, Point);
  
      RcpLengthSq = XMVectorReciprocal(LengthSq);
      LinePoint1 = XMVectorMultiply(Point, RcpLengthSq);
  
      LinePoint2 = XMVectorAdd(LinePoint1, V1);
  
      Control = XMVectorLessOrEqual(LengthSq, g_XMEpsilon.v);
      *pLinePoint1 = XMVectorSelect(LinePoint1,g_XMQNaN.v, Control);
      *pLinePoint2 = XMVectorSelect(LinePoint2,g_XMQNaN.v, Control);
  
  #elif defined(_XM_SSE_INTRINSICS_)
      XMASSERT(pLinePoint1);
      XMASSERT(pLinePoint2);
      XMVECTOR V1;
      XMVECTOR V2;
      XMVECTOR V3;
      XMVECTOR LengthSq;
      XMVECTOR Point;
      XMVECTOR P1W;
      XMVECTOR P2W;
      XMVECTOR Control;
      XMVECTOR LinePoint1;
      XMVECTOR LinePoint2;
  
      V1 = XMVector3Cross(P2, P1);
  
      LengthSq = XMVector3LengthSq(V1);
  
      V2 = XMVector3Cross(P2, V1);
  
      P1W = _mm_shuffle_ps(P1,P1,_MM_SHUFFLE(3,3,3,3));
      Point = _mm_mul_ps(V2, P1W);
  
      V3 = XMVector3Cross(V1, P1);
  
      P2W = _mm_shuffle_ps(P2,P2,_MM_SHUFFLE(3,3,3,3));
      V3 = _mm_mul_ps(V3,P2W);
      Point = _mm_add_ps(Point,V3);
      LinePoint1 = _mm_div_ps(Point,LengthSq);
  
      LinePoint2 = _mm_add_ps(LinePoint1, V1);
  
      Control = XMVectorLessOrEqual(LengthSq, g_XMEpsilon);
      *pLinePoint1 = XMVectorSelect(LinePoint1,g_XMQNaN, Control);
      *pLinePoint2 = XMVectorSelect(LinePoint2,g_XMQNaN, Control);
  #else // _XM_VMX128_INTRINSICS_
  #endif // _XM_VMX128_INTRINSICS_
  }
  
  //------------------------------------------------------------------------------
  
  XMFINLINE XMVECTOR XMPlaneTransform
  (
      FXMVECTOR P,
      CXMMATRIX M
  )
  {
  #if defined(_XM_NO_INTRINSICS_)
  
      XMVECTOR X;
      XMVECTOR Y;
      XMVECTOR Z;
      XMVECTOR W;
      XMVECTOR Result;
  
      W = XMVectorSplatW(P);
      Z = XMVectorSplatZ(P);
      Y = XMVectorSplatY(P);
      X = XMVectorSplatX(P);
  
      Result = XMVectorMultiply(W, M.r[3]);
      Result = XMVectorMultiplyAdd(Z, M.r[2], Result);
      Result = XMVectorMultiplyAdd(Y, M.r[1], Result);
      Result = XMVectorMultiplyAdd(X, M.r[0], Result);
  
      return Result;
  
  #elif defined(_XM_SSE_INTRINSICS_)
      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));
      XMVECTOR W = _mm_shuffle_ps(P,P,_MM_SHUFFLE(3,3,3,3));
      X = _mm_mul_ps(X, M.r[0]);
      Y = _mm_mul_ps(Y, M.r[1]);
      Z = _mm_mul_ps(Z, M.r[2]);
      W = _mm_mul_ps(W, M.r[3]);
      X = _mm_add_ps(X,Z);
      Y = _mm_add_ps(Y,W);
      X = _mm_add_ps(X,Y);
      return X;
  #else // _XM_VMX128_INTRINSICS_
  #endif // _XM_VMX128_INTRINSICS_
  }
  
  //------------------------------------------------------------------------------
  
  XMFINLINE XMFLOAT4* XMPlaneTransformStream
  (
      XMFLOAT4*       pOutputStream,
      size_t          OutputStride,
      CONST XMFLOAT4* pInputStream,
      size_t          InputStride,
      size_t          PlaneCount,
      CXMMATRIX       M
  )
  {
      return XMVector4TransformStream(pOutputStream,
                                      OutputStride,
                                      pInputStream,
                                      InputStride,
                                      PlaneCount,
                                      M);
  }
  
  //------------------------------------------------------------------------------
  // Conversion operations
  //------------------------------------------------------------------------------
  
  //------------------------------------------------------------------------------
  
  XMFINLINE XMVECTOR XMPlaneFromPointNormal
  (
      FXMVECTOR Point,
      FXMVECTOR Normal
  )
  {
  #if defined(_XM_NO_INTRINSICS_)
  
      XMVECTOR W;
      XMVECTOR Result;
  
      W = XMVector3Dot(Point, Normal);
      W = XMVectorNegate(W);
      Result = XMVectorSelect(W, Normal, g_XMSelect1110.v);
  
      return Result;
  
  #elif defined(_XM_SSE_INTRINSICS_)
      XMVECTOR W;
      XMVECTOR Result;
      W = XMVector3Dot(Point,Normal);
      W = _mm_mul_ps(W,g_XMNegativeOne);
      Result = _mm_and_ps(Normal,g_XMMask3);
      W = _mm_and_ps(W,g_XMMaskW);
      Result = _mm_or_ps(Result,W);
      return Result;
  #else // _XM_VMX128_INTRINSICS_
  #endif // _XM_VMX128_INTRINSICS_
  }
  
  //------------------------------------------------------------------------------
  
  XMFINLINE XMVECTOR XMPlaneFromPoints
  (
      FXMVECTOR Point1,
      FXMVECTOR Point2,
      FXMVECTOR Point3
  )
  {
  #if defined(_XM_NO_INTRINSICS_)
  
      XMVECTOR N;
      XMVECTOR D;
      XMVECTOR V21;
      XMVECTOR V31;
      XMVECTOR Result;
  
      V21 = XMVectorSubtract(Point1, Point2);
      V31 = XMVectorSubtract(Point1, Point3);
  
      N = XMVector3Cross(V21, V31);
      N = XMVector3Normalize(N);
  
      D = XMPlaneDotNormal(N, Point1);
      D = XMVectorNegate(D);
  
      Result = XMVectorSelect(D, N, g_XMSelect1110.v);
  
      return Result;
  
  #elif defined(_XM_SSE_INTRINSICS_)
      XMVECTOR N;
      XMVECTOR D;
      XMVECTOR V21;
      XMVECTOR V31;
      XMVECTOR Result;
  
      V21 = _mm_sub_ps(Point1, Point2);
      V31 = _mm_sub_ps(Point1, Point3);
  
      N = XMVector3Cross(V21, V31);
      N = XMVector3Normalize(N);
  
      D = XMPlaneDotNormal(N, Point1);
      D = _mm_mul_ps(D,g_XMNegativeOne);
      N = _mm_and_ps(N,g_XMMask3);
      D = _mm_and_ps(D,g_XMMaskW);
      Result = _mm_or_ps(D,N);
      return Result;
  #else // _XM_VMX128_INTRINSICS_
  #endif // _XM_VMX128_INTRINSICS_
  }
  
  /****************************************************************************
   *
   * Color
   *
   ****************************************************************************/
  
  //------------------------------------------------------------------------------
  // Comparison operations
  //------------------------------------------------------------------------------
  
  //------------------------------------------------------------------------------
  
  XMFINLINE BOOL XMColorEqual
  (
      FXMVECTOR C1,
      FXMVECTOR C2
  )
  {
      return XMVector4Equal(C1, C2);
  }
  
  //------------------------------------------------------------------------------
  
  XMFINLINE BOOL XMColorNotEqual
  (
      FXMVECTOR C1,
      FXMVECTOR C2
  )
  {
      return XMVector4NotEqual(C1, C2);
  }
  
  //------------------------------------------------------------------------------
  
  XMFINLINE BOOL XMColorGreater
  (
      FXMVECTOR C1,
      FXMVECTOR C2
  )
  {
      return XMVector4Greater(C1, C2);
  }
  
  //------------------------------------------------------------------------------
  
  XMFINLINE BOOL XMColorGreaterOrEqual
  (
      FXMVECTOR C1,
      FXMVECTOR C2
  )
  {
      return XMVector4GreaterOrEqual(C1, C2);
  }
  
  //------------------------------------------------------------------------------
  
  XMFINLINE BOOL XMColorLess
  (
      FXMVECTOR C1,
      FXMVECTOR C2
  )
  {
      return XMVector4Less(C1, C2);
  }
  
  //------------------------------------------------------------------------------
  
  XMFINLINE BOOL XMColorLessOrEqual
  (
      FXMVECTOR C1,
      FXMVECTOR C2
  )
  {
      return XMVector4LessOrEqual(C1, C2);
  }
  
  //------------------------------------------------------------------------------
  
  XMFINLINE BOOL XMColorIsNaN
  (
      FXMVECTOR C
  )
  {
      return XMVector4IsNaN(C);
  }
  
  //------------------------------------------------------------------------------
  
  XMFINLINE BOOL XMColorIsInfinite
  (
      FXMVECTOR C
  )
  {
      return XMVector4IsInfinite(C);
  }
  
  //------------------------------------------------------------------------------
  // Computation operations
  //------------------------------------------------------------------------------
  
  //------------------------------------------------------------------------------
  
  XMFINLINE XMVECTOR XMColorNegative
  (
      FXMVECTOR vColor
  )
  {
  #if defined(_XM_NO_INTRINSICS_)
  //    XMASSERT(XMVector4GreaterOrEqual(C, XMVectorReplicate(0.0f)));
  //    XMASSERT(XMVector4LessOrEqual(C, XMVectorReplicate(1.0f)));
      XMVECTOR vResult = {
          1.0f - vColor.vector4_f32[0],
          1.0f - vColor.vector4_f32[1],
          1.0f - vColor.vector4_f32[2],
          vColor.vector4_f32[3]
      };
      return vResult;
  
  #elif defined(_XM_SSE_INTRINSICS_)
      // Negate only x,y and z.
      XMVECTOR vTemp = _mm_xor_ps(vColor,g_XMNegate3);
      // Add 1,1,1,0 to -x,-y,-z,w
  	return _mm_add_ps(vTemp,g_XMOne3);
  #else // _XM_VMX128_INTRINSICS_
  #endif // _XM_VMX128_INTRINSICS_
  }
  
  //------------------------------------------------------------------------------
  
  XMFINLINE XMVECTOR XMColorModulate
  (
      FXMVECTOR C1,
      FXMVECTOR C2
  )
  {
      return XMVectorMultiply(C1, C2);
  }
  
  //------------------------------------------------------------------------------
  
  XMFINLINE XMVECTOR XMColorAdjustSaturation
  (
      FXMVECTOR vColor,
      FLOAT    fSaturation
  )
  {
  #if defined(_XM_NO_INTRINSICS_)
      CONST XMVECTOR gvLuminance = {0.2125f, 0.7154f, 0.0721f, 0.0f};
  
      // Luminance = 0.2125f * C[0] + 0.7154f * C[1] + 0.0721f * C[2];
      // Result = (C - Luminance) * Saturation + Luminance;
  
      FLOAT fLuminance = (vColor.vector4_f32[0]*gvLuminance.vector4_f32[0])+(vColor.vector4_f32[1]*gvLuminance.vector4_f32[1])+(vColor.vector4_f32[2]*gvLuminance.vector4_f32[2]);
      XMVECTOR vResult = {
          ((vColor.vector4_f32[0] - fLuminance)*fSaturation)+fLuminance,
          ((vColor.vector4_f32[1] - fLuminance)*fSaturation)+fLuminance,
          ((vColor.vector4_f32[2] - fLuminance)*fSaturation)+fLuminance,
          vColor.vector4_f32[3]};
      return vResult;
  
  #elif defined(_XM_SSE_INTRINSICS_)
      static const XMVECTORF32 gvLuminance = {0.2125f, 0.7154f, 0.0721f, 0.0f};
  // Mul RGB by intensity constants
      XMVECTOR vLuminance = _mm_mul_ps(vColor,gvLuminance);      
  // vResult.x = vLuminance.y, vResult.y = vLuminance.y,
  // vResult.z = vLuminance.z, vResult.w = vLuminance.z 
      XMVECTOR vResult = vLuminance;
      vResult = _mm_shuffle_ps(vResult,vResult,_MM_SHUFFLE(2,2,1,1)); 
  // vLuminance.x += vLuminance.y
      vLuminance = _mm_add_ss(vLuminance,vResult);
  // Splat vLuminance.z
      vResult = _mm_shuffle_ps(vResult,vResult,_MM_SHUFFLE(2,2,2,2));
  // vLuminance.x += vLuminance.z (Dot product)
      vLuminance = _mm_add_ss(vLuminance,vResult);
  // Splat vLuminance
      vLuminance = _mm_shuffle_ps(vLuminance,vLuminance,_MM_SHUFFLE(0,0,0,0));
  // Splat fSaturation
      XMVECTOR vSaturation = _mm_set_ps1(fSaturation);
  // vResult = ((vColor-vLuminance)*vSaturation)+vLuminance;
      vResult = _mm_sub_ps(vColor,vLuminance);
      vResult = _mm_mul_ps(vResult,vSaturation);
      vResult = _mm_add_ps(vResult,vLuminance);
  // Retain w from the source color
      vLuminance = _mm_shuffle_ps(vResult,vColor,_MM_SHUFFLE(3,2,2,2));   // x = vResult.z,y = vResult.z,z = vColor.z,w=vColor.w
      vResult = _mm_shuffle_ps(vResult,vLuminance,_MM_SHUFFLE(3,0,1,0));  // x = vResult.x,y = vResult.y,z = vResult.z,w=vColor.w
      return vResult;
  #elif defined(XM_NO_MISALIGNED_VECTOR_ACCESS)
  #endif // _XM_VMX128_INTRINSICS_
  }
  
  //------------------------------------------------------------------------------
  
  XMFINLINE XMVECTOR XMColorAdjustContrast
  (
      FXMVECTOR vColor,
      FLOAT    fContrast
  )
  {
  #if defined(_XM_NO_INTRINSICS_)
      // Result = (vColor - 0.5f) * fContrast + 0.5f;
      XMVECTOR vResult = {
          ((vColor.vector4_f32[0]-0.5f) * fContrast) + 0.5f,
          ((vColor.vector4_f32[1]-0.5f) * fContrast) + 0.5f,
          ((vColor.vector4_f32[2]-0.5f) * fContrast) + 0.5f,
          vColor.vector4_f32[3]        // Leave W untouched
      };
      return vResult;
  
  #elif defined(_XM_SSE_INTRINSICS_)
      XMVECTOR vScale = _mm_set_ps1(fContrast);           // Splat the scale
      XMVECTOR vResult = _mm_sub_ps(vColor,g_XMOneHalf);  // Subtract 0.5f from the source (Saving source)
      vResult = _mm_mul_ps(vResult,vScale);               // Mul by scale
      vResult = _mm_add_ps(vResult,g_XMOneHalf);          // Add 0.5f
  // Retain w from the source color
      vScale = _mm_shuffle_ps(vResult,vColor,_MM_SHUFFLE(3,2,2,2));   // x = vResult.z,y = vResult.z,z = vColor.z,w=vColor.w
      vResult = _mm_shuffle_ps(vResult,vScale,_MM_SHUFFLE(3,0,1,0));  // x = vResult.x,y = vResult.y,z = vResult.z,w=vColor.w
      return vResult;
  #elif defined(XM_NO_MISALIGNED_VECTOR_ACCESS)
  #endif // _XM_VMX128_INTRINSICS_
  }
  
  /****************************************************************************
   *
   * Miscellaneous
   *
   ****************************************************************************/
  
  //------------------------------------------------------------------------------
  
  XMINLINE BOOL XMVerifyCPUSupport()
  {
  #if defined(_XM_NO_INTRINSICS_) || !defined(_XM_SSE_INTRINSICS_)
  	return TRUE;
  #else // _XM_SSE_INTRINSICS_
  	// Note that on Windows 2000 or older, SSE2 detection is not supported so this will always fail
  	// Detecting SSE2 on older versions of Windows would require using cpuid directly
  	return ( IsProcessorFeaturePresent( PF_XMMI_INSTRUCTIONS_AVAILABLE ) && IsProcessorFeaturePresent( PF_XMMI64_INSTRUCTIONS_AVAILABLE ) );
  #endif
  }
  
  
  //------------------------------------------------------------------------------
  
  #define XMASSERT_LINE_STRING_SIZE 16
  
  XMINLINE VOID XMAssert
  (
      CONST CHAR* pExpression,
      CONST CHAR* pFileName,
      UINT        LineNumber
  )
  {
      CHAR        aLineString[XMASSERT_LINE_STRING_SIZE];
      CHAR*       pLineString;
      UINT        Line;
  
      aLineString[XMASSERT_LINE_STRING_SIZE - 2] = '0';
      aLineString[XMASSERT_LINE_STRING_SIZE - 1] = '\0';
      for (Line = LineNumber, pLineString = aLineString + XMASSERT_LINE_STRING_SIZE - 2;
           Line != 0 && pLineString >= aLineString;
           Line /= 10, pLineString--)
      {
          *pLineString = (CHAR)('0' + (Line % 10));
      }
  
  #ifndef NO_OUTPUT_DEBUG_STRING
      OutputDebugStringA("Assertion failed: ");
      OutputDebugStringA(pExpression);
      OutputDebugStringA(", file ");
      OutputDebugStringA(pFileName);
      OutputDebugStringA(", line ");
      OutputDebugStringA(pLineString + 1);
      OutputDebugStringA("\r\n");
  #else
      DbgPrint("Assertion failed: %s, file %s, line %d\r\n", pExpression, pFileName, LineNumber);
  #endif
  
      __debugbreak();
  }
  
  //------------------------------------------------------------------------------
  
  XMFINLINE XMVECTOR XMFresnelTerm
  (
      FXMVECTOR CosIncidentAngle,
      FXMVECTOR RefractionIndex
  )
  {
  #if defined(_XM_NO_INTRINSICS_)
  
      XMVECTOR G;
      XMVECTOR D, S;
      XMVECTOR V0, V1, V2, V3;
      XMVECTOR Result;
  
      // Result = 0.5f * (g - c)^2 / (g + c)^2 * ((c * (g + c) - 1)^2 / (c * (g - c) + 1)^2 + 1) where
      // c = CosIncidentAngle
      // g = sqrt(c^2 + RefractionIndex^2 - 1)
  
      XMASSERT(!XMVector4IsInfinite(CosIncidentAngle));
  
      G = XMVectorMultiplyAdd(RefractionIndex, RefractionIndex, g_XMNegativeOne.v);
      G = XMVectorMultiplyAdd(CosIncidentAngle, CosIncidentAngle, G);
      G = XMVectorAbs(G);
      G = XMVectorSqrt(G);
  
      S = XMVectorAdd(G, CosIncidentAngle);
      D = XMVectorSubtract(G, CosIncidentAngle);
  
      V0 = XMVectorMultiply(D, D);
      V1 = XMVectorMultiply(S, S);
      V1 = XMVectorReciprocal(V1);
      V0 = XMVectorMultiply(g_XMOneHalf.v, V0);
      V0 = XMVectorMultiply(V0, V1);
  
      V2 = XMVectorMultiplyAdd(CosIncidentAngle, S, g_XMNegativeOne.v);
      V3 = XMVectorMultiplyAdd(CosIncidentAngle, D, g_XMOne.v);
      V2 = XMVectorMultiply(V2, V2);
      V3 = XMVectorMultiply(V3, V3);
      V3 = XMVectorReciprocal(V3);
      V2 = XMVectorMultiplyAdd(V2, V3, g_XMOne.v);
  
      Result = XMVectorMultiply(V0, V2);
  
      Result = XMVectorSaturate(Result);
  
      return Result;
  
  #elif defined(_XM_SSE_INTRINSICS_)
      // Result = 0.5f * (g - c)^2 / (g + c)^2 * ((c * (g + c) - 1)^2 / (c * (g - c) + 1)^2 + 1) where
      // c = CosIncidentAngle
      // g = sqrt(c^2 + RefractionIndex^2 - 1)
  
      XMASSERT(!XMVector4IsInfinite(CosIncidentAngle));
  
      // G = sqrt(abs((RefractionIndex^2-1) + CosIncidentAngle^2))
      XMVECTOR G = _mm_mul_ps(RefractionIndex,RefractionIndex);
      XMVECTOR vTemp = _mm_mul_ps(CosIncidentAngle,CosIncidentAngle);
      G = _mm_sub_ps(G,g_XMOne);
      vTemp = _mm_add_ps(vTemp,G);
      // max((0-vTemp),vTemp) == abs(vTemp)
      // The abs is needed to deal with refraction and cosine being zero
  	G = _mm_setzero_ps();
  	G = _mm_sub_ps(G,vTemp);
  	G = _mm_max_ps(G,vTemp);
      // Last operation, the sqrt()
      G = _mm_sqrt_ps(G);
  
      // Calc G-C and G+C
      XMVECTOR GAddC = _mm_add_ps(G,CosIncidentAngle);
      XMVECTOR GSubC = _mm_sub_ps(G,CosIncidentAngle);
      // Perform the term (0.5f *(g - c)^2) / (g + c)^2 
      XMVECTOR vResult = _mm_mul_ps(GSubC,GSubC);
      vTemp = _mm_mul_ps(GAddC,GAddC);
      vResult = _mm_mul_ps(vResult,g_XMOneHalf);
      vResult = _mm_div_ps(vResult,vTemp);
      // Perform the term ((c * (g + c) - 1)^2 / (c * (g - c) + 1)^2 + 1)
      GAddC = _mm_mul_ps(GAddC,CosIncidentAngle);
      GSubC = _mm_mul_ps(GSubC,CosIncidentAngle);
      GAddC = _mm_sub_ps(GAddC,g_XMOne);
      GSubC = _mm_add_ps(GSubC,g_XMOne);
      GAddC = _mm_mul_ps(GAddC,GAddC);
      GSubC = _mm_mul_ps(GSubC,GSubC);
      GAddC = _mm_div_ps(GAddC,GSubC);
      GAddC = _mm_add_ps(GAddC,g_XMOne);
      // Multiply the two term parts
      vResult = _mm_mul_ps(vResult,GAddC);
      // Clamp to 0.0 - 1.0f
      vResult = _mm_max_ps(vResult,g_XMZero);
      vResult = _mm_min_ps(vResult,g_XMOne);
      return vResult;
  #else // _XM_VMX128_INTRINSICS_
  #endif // _XM_VMX128_INTRINSICS_
  }
  
  //------------------------------------------------------------------------------
  
  XMFINLINE BOOL XMScalarNearEqual
  (
      FLOAT S1,
      FLOAT S2,
      FLOAT Epsilon
  )
  {
      FLOAT Delta = S1 - S2;
  #if defined(_XM_NO_INTRINSICS_)
      UINT  AbsDelta = *(const UINT*)&Delta & 0x7FFFFFFF;
      return (*(FLOAT*)&AbsDelta <= Epsilon);
  #elif defined(_XM_SSE_INTRINSICS_)
      return (fabsf(Delta) <= Epsilon);
  #else
      return (__fabs(Delta) <= Epsilon);
  #endif
  }
  
  //------------------------------------------------------------------------------
  // Modulo the range of the given angle such that -XM_PI <= Angle < XM_PI
  XMFINLINE FLOAT XMScalarModAngle
  (
      FLOAT Angle
  )
  {
      // Note: The modulo is performed with unsigned math only to work
      // around a precision error on numbers that are close to PI
      float fTemp;
  #if defined(_XM_NO_INTRINSICS_) || !defined(_XM_VMX128_INTRINSICS_)
      // Normalize the range from 0.0f to XM_2PI
      Angle = Angle + XM_PI;
      // Perform the modulo, unsigned
      fTemp = fabsf(Angle);
      fTemp = fTemp - (XM_2PI * (FLOAT)((INT)(fTemp/XM_2PI)));
      // Restore the number to the range of -XM_PI to XM_PI-epsilon
      fTemp = fTemp - XM_PI;
      // If the modulo'd value was negative, restore negation
      if (Angle<0.0f) {
          fTemp = -fTemp;
      }
      return fTemp;
  #else
  #endif
  }
  
  //------------------------------------------------------------------------------
  
  XMINLINE FLOAT XMScalarSin
  (
      FLOAT Value
  )
  {
  #if defined(_XM_NO_INTRINSICS_)
  
      FLOAT                  ValueMod;
      FLOAT                  ValueSq;
      XMVECTOR               V0123, V0246, V1357, V9111315, V17192123;
      XMVECTOR               V1, V7, V8;
      XMVECTOR               R0, R1, R2;
  
      ValueMod = XMScalarModAngle(Value);
  
      // sin(V) ~= V - V^3 / 3! + V^5 / 5! - V^7 / 7! + V^9 / 9! - V^11 / 11! + V^13 / 13! - V^15 / 15! +
      //           V^17 / 17! - V^19 / 19! + V^21 / 21! - V^23 / 23! (for -PI <= V < PI)
  
      ValueSq = ValueMod * ValueMod;
  
      V0123     = XMVectorSet(1.0f, ValueMod, ValueSq, ValueSq * ValueMod);
      V1        = XMVectorSplatY(V0123);
      V0246     = XMVectorMultiply(V0123, V0123);
      V1357     = XMVectorMultiply(V0246, V1);
      V7        = XMVectorSplatW(V1357);
      V8        = XMVectorMultiply(V7, V1);
      V9111315  = XMVectorMultiply(V1357, V8);
      V17192123 = XMVectorMultiply(V9111315, V8);
  
      R0        = XMVector4Dot(V1357, g_XMSinCoefficients0.v);
      R1        = XMVector4Dot(V9111315, g_XMSinCoefficients1.v);
      R2        = XMVector4Dot(V17192123, g_XMSinCoefficients2.v);
  
      return R0.vector4_f32[0] + R1.vector4_f32[0] + R2.vector4_f32[0];
  
  #elif defined(_XM_SSE_INTRINSICS_)
      return sinf( Value );
  #else // _XM_VMX128_INTRINSICS_
  #endif // _XM_VMX128_INTRINSICS_
  }
  
  //------------------------------------------------------------------------------
  
  XMINLINE FLOAT XMScalarCos
  (
      FLOAT Value
  )
  {
  #if defined(_XM_NO_INTRINSICS_)
  
      FLOAT                  ValueMod;
      FLOAT                  ValueSq;
      XMVECTOR               V0123, V0246, V8101214, V16182022;
      XMVECTOR               V2, V6, V8;
      XMVECTOR               R0, R1, R2;
  
      ValueMod = XMScalarModAngle(Value);
  
      // cos(V) ~= 1 - V^2 / 2! + V^4 / 4! - V^6 / 6! + V^8 / 8! - V^10 / 10! +
      //           V^12 / 12! - V^14 / 14! + V^16 / 16! - V^18 / 18! + V^20 / 20! - V^22 / 22! (for -PI <= V < PI)
  
      ValueSq = ValueMod * ValueMod;
  
      V0123 = XMVectorSet(1.0f, ValueMod, ValueSq, ValueSq * ValueMod);
      V0246 = XMVectorMultiply(V0123, V0123);
  
      V2 = XMVectorSplatZ(V0123);
      V6 = XMVectorSplatW(V0246);
      V8 = XMVectorMultiply(V6, V2);
  
      V8101214 = XMVectorMultiply(V0246, V8);
      V16182022 = XMVectorMultiply(V8101214, V8);
  
      R0 = XMVector4Dot(V0246, g_XMCosCoefficients0.v);
      R1 = XMVector4Dot(V8101214, g_XMCosCoefficients1.v);
      R2 = XMVector4Dot(V16182022, g_XMCosCoefficients2.v);
  
      return R0.vector4_f32[0] + R1.vector4_f32[0] + R2.vector4_f32[0];
  
  #elif defined(_XM_SSE_INTRINSICS_)
      return cosf(Value);
  #else // _XM_VMX128_INTRINSICS_
  #endif // _XM_VMX128_INTRINSICS_
  }
  
  //------------------------------------------------------------------------------
  
  XMINLINE VOID XMScalarSinCos
  (
      FLOAT* pSin,
      FLOAT* pCos,
      FLOAT  Value
  )
  {
  #if defined(_XM_NO_INTRINSICS_)
  
      FLOAT                  ValueMod;
      FLOAT                  ValueSq;
      XMVECTOR               V0123, V0246, V1357, V8101214, V9111315, V16182022, V17192123;
      XMVECTOR               V1, V2, V6, V8;
      XMVECTOR               S0, S1, S2, C0, C1, C2;
  
      XMASSERT(pSin);
      XMASSERT(pCos);
  
      ValueMod = XMScalarModAngle(Value);
  
      // sin(V) ~= V - V^3 / 3! + V^5 / 5! - V^7 / 7! + V^9 / 9! - V^11 / 11! + V^13 / 13! - V^15 / 15! +
      //           V^17 / 17! - V^19 / 19! + V^21 / 21! - V^23 / 23! (for -PI <= V < PI)
      // cos(V) ~= 1 - V^2 / 2! + V^4 / 4! - V^6 / 6! + V^8 / 8! - V^10 / 10! +
      //           V^12 / 12! - V^14 / 14! + V^16 / 16! - V^18 / 18! + V^20 / 20! - V^22 / 22! (for -PI <= V < PI)
  
      ValueSq = ValueMod * ValueMod;
  
      V0123 = XMVectorSet(1.0f, ValueMod, ValueSq, ValueSq * ValueMod);
  
      V1 = XMVectorSplatY(V0123);
      V2 = XMVectorSplatZ(V0123);
  
      V0246 = XMVectorMultiply(V0123, V0123);
      V1357 = XMVectorMultiply(V0246, V1);
  
      V6 = XMVectorSplatW(V0246);
      V8 = XMVectorMultiply(V6, V2);
  
      V8101214 = XMVectorMultiply(V0246, V8);
      V9111315 = XMVectorMultiply(V1357, V8);
      V16182022 = XMVectorMultiply(V8101214, V8);
      V17192123 = XMVectorMultiply(V9111315, V8);
  
      C0 = XMVector4Dot(V0246, g_XMCosCoefficients0.v);
      S0 = XMVector4Dot(V1357, g_XMSinCoefficients0.v);
      C1 = XMVector4Dot(V8101214, g_XMCosCoefficients1.v);
      S1 = XMVector4Dot(V9111315, g_XMSinCoefficients1.v);
      C2 = XMVector4Dot(V16182022, g_XMCosCoefficients2.v);
      S2 = XMVector4Dot(V17192123, g_XMSinCoefficients2.v);
  
      *pCos = C0.vector4_f32[0] + C1.vector4_f32[0] + C2.vector4_f32[0];
      *pSin = S0.vector4_f32[0] + S1.vector4_f32[0] + S2.vector4_f32[0];
  
  #elif defined(_XM_SSE_INTRINSICS_)
      XMASSERT(pSin);
      XMASSERT(pCos);
  
      *pSin = sinf(Value);
      *pCos = cosf(Value);
  #else // _XM_VMX128_INTRINSICS_
  #endif // _XM_VMX128_INTRINSICS_
  }
  
  //------------------------------------------------------------------------------
  
  XMINLINE FLOAT XMScalarASin
  (
      FLOAT Value
  )
  {
  #if defined(_XM_NO_INTRINSICS_)
  
      FLOAT AbsValue, Value2, Value3, D;
      XMVECTOR AbsV, R0, R1, Result;
      XMVECTOR V3;
  
      *(UINT*)&AbsValue = *(const UINT*)&Value & 0x7FFFFFFF;
  
      Value2 = Value * AbsValue;
      Value3 = Value * Value2;
      D = (Value - Value2) / sqrtf(1.00000011921f - AbsValue);
  
      AbsV = XMVectorReplicate(AbsValue);
  
      V3.vector4_f32[0] = Value3;
      V3.vector4_f32[1] = 1.0f;
      V3.vector4_f32[2] = Value3;
      V3.vector4_f32[3] = 1.0f;
  
      R1 = XMVectorSet(D, D, Value, Value);
      R1 = XMVectorMultiply(R1, V3);
  
      R0 = XMVectorMultiplyAdd(AbsV, g_XMASinCoefficients0.v, g_XMASinCoefficients1.v);
      R0 = XMVectorMultiplyAdd(AbsV, R0, g_XMASinCoefficients2.v);
  
      Result = XMVector4Dot(R0, R1);
  
      return Result.vector4_f32[0];
  
  #elif defined(_XM_SSE_INTRINSICS_)
      return asinf(Value);
  #else // _XM_VMX128_INTRINSICS_
  #endif // _XM_VMX128_INTRINSICS_
  }
  
  //------------------------------------------------------------------------------
  
  XMINLINE FLOAT XMScalarACos
  (
      FLOAT Value
  )
  {
  #if defined(_XM_NO_INTRINSICS_)
  
      return XM_PIDIV2 - XMScalarASin(Value);
  
  #elif defined(_XM_SSE_INTRINSICS_)
      return acosf(Value);
  #else // _XM_VMX128_INTRINSICS_
  #endif // _XM_VMX128_INTRINSICS_
  }
  
  //------------------------------------------------------------------------------
  
  XMFINLINE FLOAT XMScalarSinEst
  (
      FLOAT Value
  )
  {
  #if defined(_XM_NO_INTRINSICS_)
  
      FLOAT                  ValueSq;
      XMVECTOR               V;
      XMVECTOR               Y;
      XMVECTOR               Result;
  
      XMASSERT(Value >= -XM_PI);
      XMASSERT(Value < XM_PI);
  
      // sin(V) ~= V - V^3 / 3! + V^5 / 5! - V^7 / 7! (for -PI <= V < PI)
  
      ValueSq = Value * Value;
  
      V = XMVectorSet(1.0f, Value, ValueSq, ValueSq * Value);
      Y = XMVectorSplatY(V);
      V = XMVectorMultiply(V, V);
      V = XMVectorMultiply(V, Y);
  
      Result = XMVector4Dot(V, g_XMSinEstCoefficients.v);
  
      return Result.vector4_f32[0];
  
  #elif defined(_XM_SSE_INTRINSICS_)
      XMASSERT(Value >= -XM_PI);
      XMASSERT(Value < XM_PI);
      float ValueSq = Value*Value;
      XMVECTOR vValue = _mm_set_ps1(Value);
      XMVECTOR vTemp = _mm_set_ps(ValueSq * Value,ValueSq,Value,1.0f); 
      vTemp = _mm_mul_ps(vTemp,vTemp);
      vTemp = _mm_mul_ps(vTemp,vValue);
      // vTemp = Value,Value^3,Value^5,Value^7
      vTemp = _mm_mul_ps(vTemp,g_XMSinEstCoefficients);
      vValue = _mm_shuffle_ps(vValue,vTemp,_MM_SHUFFLE(1,0,0,0)); // Copy X to the Z position and Y to the W position
      vValue = _mm_add_ps(vValue,vTemp);          // Add Z = X+Z; W = Y+W;
      vTemp = _mm_shuffle_ps(vTemp,vValue,_MM_SHUFFLE(0,3,0,0));  // Copy W to the Z position
      vTemp = _mm_add_ps(vTemp,vValue);           // Add Z and W together
      vTemp = _mm_shuffle_ps(vTemp,vTemp,_MM_SHUFFLE(2,2,2,2));    // Splat Z and return
  #if defined(_MSC_VER) && (_MSC_VER>=1500)
      return _mm_cvtss_f32(vTemp);    
  #else
      return vTemp.m128_f32[0];
  #endif
  #else // _XM_VMX128_INTRINSICS_
  #endif // _XM_VMX128_INTRINSICS_
  }
  
  //------------------------------------------------------------------------------
  
  XMFINLINE FLOAT XMScalarCosEst
  (
      FLOAT Value
  )
  {
  #if defined(_XM_NO_INTRINSICS_)
      FLOAT    ValueSq;
      XMVECTOR V;
      XMVECTOR Result;
      XMASSERT(Value >= -XM_PI);
      XMASSERT(Value < XM_PI);
      // cos(V) ~= 1 - V^2 / 2! + V^4 / 4! - V^6 / 6! (for -PI <= V < PI)
      ValueSq = Value * Value;
      V = XMVectorSet(1.0f, Value, ValueSq, ValueSq * Value);
      V = XMVectorMultiply(V, V);
      Result = XMVector4Dot(V, g_XMCosEstCoefficients.v);
      return Result.vector4_f32[0];
  #elif defined(_XM_SSE_INTRINSICS_)
      XMASSERT(Value >= -XM_PI);
      XMASSERT(Value < XM_PI);
      float ValueSq = Value*Value;
      XMVECTOR vValue = _mm_setzero_ps();
      XMVECTOR vTemp = _mm_set_ps(ValueSq * Value,ValueSq,Value,1.0f); 
      vTemp = _mm_mul_ps(vTemp,vTemp);
      // vTemp = 1.0f,Value^2,Value^4,Value^6
      vTemp = _mm_mul_ps(vTemp,g_XMCosEstCoefficients);
      vValue = _mm_shuffle_ps(vValue,vTemp,_MM_SHUFFLE(1,0,0,0)); // Copy X to the Z position and Y to the W position
      vValue = _mm_add_ps(vValue,vTemp);          // Add Z = X+Z; W = Y+W;
      vTemp = _mm_shuffle_ps(vTemp,vValue,_MM_SHUFFLE(0,3,0,0));  // Copy W to the Z position
      vTemp = _mm_add_ps(vTemp,vValue);           // Add Z and W together
      vTemp = _mm_shuffle_ps(vTemp,vTemp,_MM_SHUFFLE(2,2,2,2));    // Splat Z and return
  #if defined(_MSC_VER) && (_MSC_VER>=1500)
      return _mm_cvtss_f32(vTemp);    
  #else
      return vTemp.m128_f32[0];
  #endif
  #else // _XM_VMX128_INTRINSICS_
  #endif // _XM_VMX128_INTRINSICS_
  }
  
  //------------------------------------------------------------------------------
  
  XMFINLINE VOID XMScalarSinCosEst
  (
      FLOAT* pSin,
      FLOAT* pCos,
      FLOAT  Value
  )
  {
  #if defined(_XM_NO_INTRINSICS_)
  
      FLOAT    ValueSq;
      XMVECTOR V, Sin, Cos;
      XMVECTOR Y;
  
      XMASSERT(pSin);
      XMASSERT(pCos);
      XMASSERT(Value >= -XM_PI);
      XMASSERT(Value < XM_PI);
  
      // sin(V) ~= V - V^3 / 3! + V^5 / 5! - V^7 / 7! (for -PI <= V < PI)
      // cos(V) ~= 1 - V^2 / 2! + V^4 / 4! - V^6 / 6! (for -PI <= V < PI)
  
      ValueSq = Value * Value;
      V = XMVectorSet(1.0f, Value, ValueSq, Value * ValueSq);
      Y = XMVectorSplatY(V);
      Cos = XMVectorMultiply(V, V);
      Sin = XMVectorMultiply(Cos, Y);
  
      Cos = XMVector4Dot(Cos, g_XMCosEstCoefficients.v);
      Sin = XMVector4Dot(Sin, g_XMSinEstCoefficients.v);
  
      *pCos = Cos.vector4_f32[0];
      *pSin = Sin.vector4_f32[0];
  
  #elif defined(_XM_SSE_INTRINSICS_)
      XMASSERT(pSin);
      XMASSERT(pCos);
      XMASSERT(Value >= -XM_PI);
      XMASSERT(Value < XM_PI);
      float ValueSq = Value * Value;
      XMVECTOR Cos = _mm_set_ps(Value * ValueSq,ValueSq,Value,1.0f);
      XMVECTOR Sin = _mm_set_ps1(Value);
      Cos = _mm_mul_ps(Cos,Cos);
      Sin = _mm_mul_ps(Sin,Cos);
      // Cos = 1.0f,Value^2,Value^4,Value^6
      Cos = XMVector4Dot(Cos,g_XMCosEstCoefficients);
      _mm_store_ss(pCos,Cos);
      // Sin = Value,Value^3,Value^5,Value^7
      Sin = XMVector4Dot(Sin, g_XMSinEstCoefficients);
      _mm_store_ss(pSin,Sin);
  #else // _XM_VMX128_INTRINSICS_
  #endif // _XM_VMX128_INTRINSICS_
  }
  
  //------------------------------------------------------------------------------
  
  XMFINLINE FLOAT XMScalarASinEst
  (
      FLOAT Value
  )
  {
  #if defined(_XM_NO_INTRINSICS_)
  
      XMVECTOR VR, CR, CS;
      XMVECTOR Result;
      FLOAT AbsV, V2, D;
      CONST FLOAT OnePlusEps = 1.00000011921f;
  
      *(UINT*)&AbsV = *(const UINT*)&Value & 0x7FFFFFFF;
      V2 = Value * AbsV;
      D = OnePlusEps - AbsV;
  
      CS = XMVectorSet(Value, 1.0f, 1.0f, V2);
      VR = XMVectorSet(sqrtf(D), Value, V2, D * AbsV);
      CR = XMVectorMultiply(CS, g_XMASinEstCoefficients.v);
  
      Result = XMVector4Dot(VR, CR);
  
      return Result.vector4_f32[0];
  
  #elif defined(_XM_SSE_INTRINSICS_)
      CONST FLOAT OnePlusEps = 1.00000011921f;
      FLOAT AbsV = fabsf(Value);
      FLOAT V2 = Value * AbsV;    // Square with sign retained
      FLOAT D = OnePlusEps - AbsV;
  
      XMVECTOR Result = _mm_set_ps(V2,1.0f,1.0f,Value);
      XMVECTOR VR = _mm_set_ps(D * AbsV,V2,Value,sqrtf(D));
      Result = _mm_mul_ps(Result, g_XMASinEstCoefficients);
      Result = XMVector4Dot(VR,Result);
  #if defined(_MSC_VER) && (_MSC_VER>=1500)
      return _mm_cvtss_f32(Result);    
  #else
      return Result.m128_f32[0];
  #endif
  #else // _XM_VMX128_INTRINSICS_
  #endif // _XM_VMX128_INTRINSICS_
  }
  
  //------------------------------------------------------------------------------
  
  XMFINLINE FLOAT XMScalarACosEst
  (
      FLOAT Value
  )
  {
  #if defined(_XM_NO_INTRINSICS_)
  
      XMVECTOR VR, CR, CS;
      XMVECTOR Result;
      FLOAT AbsV, V2, D;
      CONST FLOAT OnePlusEps = 1.00000011921f;
  
      // return XM_PIDIV2 - XMScalarASin(Value);
  
      *(UINT*)&AbsV = *(const UINT*)&Value & 0x7FFFFFFF;
      V2 = Value * AbsV;
      D = OnePlusEps - AbsV;
  
      CS = XMVectorSet(Value, 1.0f, 1.0f, V2);
      VR = XMVectorSet(sqrtf(D), Value, V2, D * AbsV);
      CR = XMVectorMultiply(CS, g_XMASinEstCoefficients.v);
  
      Result = XMVector4Dot(VR, CR);
  
      return XM_PIDIV2 - Result.vector4_f32[0];
  
  #elif defined(_XM_SSE_INTRINSICS_)
      CONST FLOAT OnePlusEps = 1.00000011921f;
      FLOAT AbsV = fabsf(Value);
      FLOAT V2 = Value * AbsV;    // Value^2 retaining sign
      FLOAT D = OnePlusEps - AbsV;
      XMVECTOR Result = _mm_set_ps(V2,1.0f,1.0f,Value);
      XMVECTOR VR = _mm_set_ps(D * AbsV,V2,Value,sqrtf(D));
      Result = _mm_mul_ps(Result,g_XMASinEstCoefficients);
      Result = XMVector4Dot(VR,Result);
  #if defined(_MSC_VER) && (_MSC_VER>=1500)
      return XM_PIDIV2 - _mm_cvtss_f32(Result);    
  #else
      return XM_PIDIV2 - Result.m128_f32[0];
  #endif
  #else // _XM_VMX128_INTRINSICS_
  #endif // _XM_VMX128_INTRINSICS_
  }
  
  #endif // __XNAMATHMISC_INL__
  
  