text: //-------------------------------------------------------------------------------------
  // FMathLib.inl -- Simplified C++ Math wrapper for DirectXMath
  //
  // Copyright (c) Microsoft Corporation. All rights reserved.
  // Licensed under the MIT License.
  //
  // http://go.microsoft.com/fwlink/?LinkId=248929
  // http://go.microsoft.com/fwlink/?LinkID=615561
  //-------------------------------------------------------------------------------------
  
  #pragma once
  
  
  /****************************************************************************
  *
  * Rectangle
  *
  ****************************************************************************/
  
  //------------------------------------------------------------------------------
  // Rectangle operations
  //------------------------------------------------------------------------------
  inline Vector2 Rectangle::Location() const noexcept
  {
      return Vector2(float(x), float(y));
  }
  
  inline Vector2 Rectangle::Center() const noexcept
  {
      return Vector2(float(x) + (float(width) / 2.f), float(y) + (float(height) / 2.f));
  }
  
  inline bool Rectangle::Contains(const Vector2& point) const noexcept
  {
      return (float(x) <= point.x) && (point.x < float(x + width)) && (float(y) <= point.y) && (point.y < float(y + height));
  }
  
  inline void Rectangle::Inflate(long horizAmount, long vertAmount) noexcept
  {
      x -= horizAmount;
      y -= vertAmount;
      width += horizAmount;
      height += vertAmount;
  }
  
  //------------------------------------------------------------------------------
  // Static functions
  //------------------------------------------------------------------------------
  
  inline Rectangle Rectangle::Intersect(const Rectangle& ra, const Rectangle& rb) noexcept
  {
      long righta = ra.x + ra.width;
      long rightb = rb.x + rb.width;
  
      long bottoma = ra.y + ra.height;
      long bottomb = rb.y + rb.height;
  
      long maxX = ra.x > rb.x ? ra.x : rb.x;
      long maxY = ra.y > rb.y ? ra.y : rb.y;
  
      long minRight = righta < rightb ? righta : rightb;
      long minBottom = bottoma < bottomb ? bottoma : bottomb;
  
      Rectangle result;
  
      if ((minRight > maxX) && (minBottom > maxY))
      {
          result.x = maxX;
          result.y = maxY;
          result.width = minRight - maxX;
          result.height = minBottom - maxY;
      }
      else
      {
          result.x = 0;
          result.y = 0;
          result.width = 0;
          result.height = 0;
      }
  
      return result;
  }
  
  inline RECT Rectangle::Intersect(const RECT& rcta, const RECT& rctb) noexcept
  {
      long maxX = rcta.left > rctb.left ? rcta.left : rctb.left;
      long maxY = rcta.top > rctb.top ? rcta.top : rctb.top;
  
      long minRight = rcta.right < rctb.right ? rcta.right : rctb.right;
      long minBottom = rcta.bottom < rctb.bottom ? rcta.bottom : rctb.bottom;
  
      RECT result;
  
      if ((minRight > maxX) && (minBottom > maxY))
      {
          result.left = maxX;
          result.top = maxY;
          result.right = minRight;
          result.bottom = minBottom;
      }
      else
      {
          result.left = 0;
          result.top = 0;
          result.right = 0;
          result.bottom = 0;
      }
  
      return result;
  }
  
  inline Rectangle Rectangle::Union(const Rectangle& ra, const Rectangle& rb) noexcept
  {
      long righta = ra.x + ra.width;
      long rightb = rb.x + rb.width;
  
      long bottoma = ra.y + ra.height;
      long bottomb = rb.y + rb.height;
  
      int minX = ra.x < rb.x ? ra.x : rb.x;
      int minY = ra.y < rb.y ? ra.y : rb.y;
  
      int maxRight = righta > rightb ? righta : rightb;
      int maxBottom = bottoma > bottomb ? bottoma : bottomb;
  
      Rectangle result;
      result.x = minX;
      result.y = minY;
      result.width = maxRight - minX;
      result.height = maxBottom - minY;
      return result;
  }
  
  inline RECT Rectangle::Union(const RECT& rcta, const RECT& rctb) noexcept
  {
      RECT result;
      result.left = rcta.left < rctb.left ? rcta.left : rctb.left;
      result.top = rcta.top < rctb.top ? rcta.top : rctb.top;
      result.right = rcta.right > rctb.right ? rcta.right : rctb.right;
      result.bottom = rcta.bottom > rctb.bottom ? rcta.bottom : rctb.bottom;
      return result;
  }
  
  
  /****************************************************************************
   *
   * Vector2
   *
   ****************************************************************************/
  
  //------------------------------------------------------------------------------
  // Comparision operators
  //------------------------------------------------------------------------------
  
  inline bool Vector2::operator == (const Vector2& V) const noexcept
  {
      using namespace DirectX;
      XMVECTOR v1 = XMLoadFloat2(this);
      XMVECTOR v2 = XMLoadFloat2(&V);
      return XMVector2Equal(v1, v2);
  }
  
  inline bool Vector2::operator != (const Vector2& V) const noexcept
  {
      using namespace DirectX;
      XMVECTOR v1 = XMLoadFloat2(this);
      XMVECTOR v2 = XMLoadFloat2(&V);
      return XMVector2NotEqual(v1, v2);
  }
  
  //------------------------------------------------------------------------------
  // Assignment operators
  //------------------------------------------------------------------------------
  
  inline Vector2& Vector2::operator+= (const Vector2& V) noexcept
  {
      using namespace DirectX;
      XMVECTOR v1 = XMLoadFloat2(this);
      XMVECTOR v2 = XMLoadFloat2(&V);
      XMVECTOR X = XMVectorAdd(v1, v2);
      XMStoreFloat2(this, X);
      return *this;
  }
  
  inline Vector2& Vector2::operator-= (const Vector2& V) noexcept
  {
      using namespace DirectX;
      XMVECTOR v1 = XMLoadFloat2(this);
      XMVECTOR v2 = XMLoadFloat2(&V);
      XMVECTOR X = XMVectorSubtract(v1, v2);
      XMStoreFloat2(this, X);
      return *this;
  }
  
  inline Vector2& Vector2::operator*= (const Vector2& V) noexcept
  {
      using namespace DirectX;
      XMVECTOR v1 = XMLoadFloat2(this);
      XMVECTOR v2 = XMLoadFloat2(&V);
      XMVECTOR X = XMVectorMultiply(v1, v2);
      XMStoreFloat2(this, X);
      return *this;
  }
  
  inline Vector2& Vector2::operator*= (float S) noexcept
  {
      using namespace DirectX;
      XMVECTOR v1 = XMLoadFloat2(this);
      XMVECTOR X = XMVectorScale(v1, S);
      XMStoreFloat2(this, X);
      return *this;
  }
  
  inline Vector2& Vector2::operator/= (float S) noexcept
  {
      using namespace DirectX;
      assert(S != 0.0f);
      XMVECTOR v1 = XMLoadFloat2(this);
      XMVECTOR X = XMVectorScale(v1, 1.f / S);
      XMStoreFloat2(this, X);
      return *this;
  }
  
  //------------------------------------------------------------------------------
  // Binary operators
  //------------------------------------------------------------------------------
  
  inline Vector2 operator+ (const Vector2& V1, const Vector2& V2) noexcept
  {
      using namespace DirectX;
      XMVECTOR v1 = XMLoadFloat2(&V1);
      XMVECTOR v2 = XMLoadFloat2(&V2);
      XMVECTOR X = XMVectorAdd(v1, v2);
      Vector2 R;
      XMStoreFloat2(&R, X);
      return R;
  }
  
  inline Vector2 operator- (const Vector2& V1, const Vector2& V2) noexcept
  {
      using namespace DirectX;
      XMVECTOR v1 = XMLoadFloat2(&V1);
      XMVECTOR v2 = XMLoadFloat2(&V2);
      XMVECTOR X = XMVectorSubtract(v1, v2);
      Vector2 R;
      XMStoreFloat2(&R, X);
      return R;
  }
  
  inline Vector2 operator* (const Vector2& V1, const Vector2& V2) noexcept
  {
      using namespace DirectX;
      XMVECTOR v1 = XMLoadFloat2(&V1);
      XMVECTOR v2 = XMLoadFloat2(&V2);
      XMVECTOR X = XMVectorMultiply(v1, v2);
      Vector2 R;
      XMStoreFloat2(&R, X);
      return R;
  }
  
  inline Vector2 operator* (const Vector2& V, float S) noexcept
  {
      using namespace DirectX;
      XMVECTOR v1 = XMLoadFloat2(&V);
      XMVECTOR X = XMVectorScale(v1, S);
      Vector2 R;
      XMStoreFloat2(&R, X);
      return R;
  }
  
  inline Vector2 operator/ (const Vector2& V1, const Vector2& V2) noexcept
  {
      using namespace DirectX;
      XMVECTOR v1 = XMLoadFloat2(&V1);
      XMVECTOR v2 = XMLoadFloat2(&V2);
      XMVECTOR X = XMVectorDivide(v1, v2);
      Vector2 R;
      XMStoreFloat2(&R, X);
      return R;
  }
  
  inline Vector2 operator/ (const Vector2& V, float S) noexcept
  {
      using namespace DirectX;
      XMVECTOR v1 = XMLoadFloat2(&V);
      XMVECTOR X = XMVectorScale(v1, 1.f / S);
      Vector2 R;
      XMStoreFloat2(&R, X);
      return R;
  }
  
  inline Vector2 operator* (float S, const Vector2& V) noexcept
  {
      using namespace DirectX;
      XMVECTOR v1 = XMLoadFloat2(&V);
      XMVECTOR X = XMVectorScale(v1, S);
      Vector2 R;
      XMStoreFloat2(&R, X);
      return R;
  }
  
  //------------------------------------------------------------------------------
  // Vector operations
  //------------------------------------------------------------------------------
  
  inline bool Vector2::InBounds(const Vector2& Bounds) const noexcept
  {
      using namespace DirectX;
      XMVECTOR v1 = XMLoadFloat2(this);
      XMVECTOR v2 = XMLoadFloat2(&Bounds);
      return XMVector2InBounds(v1, v2);
  }
  
  inline float Vector2::Length() const noexcept
  {
      using namespace DirectX;
      XMVECTOR v1 = XMLoadFloat2(this);
      XMVECTOR X = XMVector2Length(v1);
      return XMVectorGetX(X);
  }
  
  inline float Vector2::LengthSquared() const noexcept
  {
      using namespace DirectX;
      XMVECTOR v1 = XMLoadFloat2(this);
      XMVECTOR X = XMVector2LengthSq(v1);
      return XMVectorGetX(X);
  }
  
  inline float Vector2::Dot(const Vector2& V) const noexcept
  {
      using namespace DirectX;
      XMVECTOR v1 = XMLoadFloat2(this);
      XMVECTOR v2 = XMLoadFloat2(&V);
      XMVECTOR X = XMVector2Dot(v1, v2);
      return XMVectorGetX(X);
  }
  
  inline void Vector2::Cross(const Vector2& V, Vector2& result) const noexcept
  {
      using namespace DirectX;
      XMVECTOR v1 = XMLoadFloat2(this);
      XMVECTOR v2 = XMLoadFloat2(&V);
      XMVECTOR R = XMVector2Cross(v1, v2);
      XMStoreFloat2(&result, R);
  }
  
  inline Vector2 Vector2::Cross(const Vector2& V) const noexcept
  {
      using namespace DirectX;
      XMVECTOR v1 = XMLoadFloat2(this);
      XMVECTOR v2 = XMLoadFloat2(&V);
      XMVECTOR R = XMVector2Cross(v1, v2);
  
      Vector2 result;
      XMStoreFloat2(&result, R);
      return result;
  }
  
  inline void Vector2::Normalize() noexcept
  {
      using namespace DirectX;
      XMVECTOR v1 = XMLoadFloat2(this);
      XMVECTOR X = XMVector2Normalize(v1);
      XMStoreFloat2(this, X);
  }
  
  inline void Vector2::Normalize(Vector2& result) const noexcept
  {
      using namespace DirectX;
      XMVECTOR v1 = XMLoadFloat2(this);
      XMVECTOR X = XMVector2Normalize(v1);
      XMStoreFloat2(&result, X);
  }
  
  inline void Vector2::Clamp(const Vector2& vmin, const Vector2& vmax) noexcept
  {
      using namespace DirectX;
      XMVECTOR v1 = XMLoadFloat2(this);
      XMVECTOR v2 = XMLoadFloat2(&vmin);
      XMVECTOR v3 = XMLoadFloat2(&vmax);
      XMVECTOR X = XMVectorClamp(v1, v2, v3);
      XMStoreFloat2(this, X);
  }
  
  inline void Vector2::Clamp(const Vector2& vmin, const Vector2& vmax, Vector2& result) const noexcept
  {
      using namespace DirectX;
      XMVECTOR v1 = XMLoadFloat2(this);
      XMVECTOR v2 = XMLoadFloat2(&vmin);
      XMVECTOR v3 = XMLoadFloat2(&vmax);
      XMVECTOR X = XMVectorClamp(v1, v2, v3);
      XMStoreFloat2(&result, X);
  }
  
  //------------------------------------------------------------------------------
  // Static functions
  //------------------------------------------------------------------------------
  
  inline float Vector2::Distance(const Vector2& v1, const Vector2& v2) noexcept
  {
      using namespace DirectX;
      XMVECTOR x1 = XMLoadFloat2(&v1);
      XMVECTOR x2 = XMLoadFloat2(&v2);
      XMVECTOR V = XMVectorSubtract(x2, x1);
      XMVECTOR X = XMVector2Length(V);
      return XMVectorGetX(X);
  }
  
  inline float Vector2::DistanceSquared(const Vector2& v1, const Vector2& v2) noexcept
  {
      using namespace DirectX;
      XMVECTOR x1 = XMLoadFloat2(&v1);
      XMVECTOR x2 = XMLoadFloat2(&v2);
      XMVECTOR V = XMVectorSubtract(x2, x1);
      XMVECTOR X = XMVector2LengthSq(V);
      return XMVectorGetX(X);
  }
  
  inline void Vector2::Min(const Vector2& v1, const Vector2& v2, Vector2& result) noexcept
  {
      using namespace DirectX;
      XMVECTOR x1 = XMLoadFloat2(&v1);
      XMVECTOR x2 = XMLoadFloat2(&v2);
      XMVECTOR X = XMVectorMin(x1, x2);
      XMStoreFloat2(&result, X);
  }
  
  inline Vector2 Vector2::Min(const Vector2& v1, const Vector2& v2) noexcept
  {
      using namespace DirectX;
      XMVECTOR x1 = XMLoadFloat2(&v1);
      XMVECTOR x2 = XMLoadFloat2(&v2);
      XMVECTOR X = XMVectorMin(x1, x2);
  
      Vector2 result;
      XMStoreFloat2(&result, X);
      return result;
  }
  
  inline void Vector2::Max(const Vector2& v1, const Vector2& v2, Vector2& result) noexcept
  {
      using namespace DirectX;
      XMVECTOR x1 = XMLoadFloat2(&v1);
      XMVECTOR x2 = XMLoadFloat2(&v2);
      XMVECTOR X = XMVectorMax(x1, x2);
      XMStoreFloat2(&result, X);
  }
  
  inline Vector2 Vector2::Max(const Vector2& v1, const Vector2& v2) noexcept
  {
      using namespace DirectX;
      XMVECTOR x1 = XMLoadFloat2(&v1);
      XMVECTOR x2 = XMLoadFloat2(&v2);
      XMVECTOR X = XMVectorMax(x1, x2);
  
      Vector2 result;
      XMStoreFloat2(&result, X);
      return result;
  }
  
  inline void Vector2::Lerp(const Vector2& v1, const Vector2& v2, float t, Vector2& result) noexcept
  {
      using namespace DirectX;
      XMVECTOR x1 = XMLoadFloat2(&v1);
      XMVECTOR x2 = XMLoadFloat2(&v2);
      XMVECTOR X = XMVectorLerp(x1, x2, t);
      XMStoreFloat2(&result, X);
  }
  
  inline Vector2 Vector2::Lerp(const Vector2& v1, const Vector2& v2, float t) noexcept
  {
      using namespace DirectX;
      XMVECTOR x1 = XMLoadFloat2(&v1);
      XMVECTOR x2 = XMLoadFloat2(&v2);
      XMVECTOR X = XMVectorLerp(x1, x2, t);
  
      Vector2 result;
      XMStoreFloat2(&result, X);
      return result;
  }
  
  inline void Vector2::SmoothStep(const Vector2& v1, const Vector2& v2, float t, Vector2& result) noexcept
  {
      using namespace DirectX;
      t = (t > 1.0f) ? 1.0f : ((t < 0.0f) ? 0.0f : t);  // Clamp value to 0 to 1
      t = t * t*(3.f - 2.f*t);
      XMVECTOR x1 = XMLoadFloat2(&v1);
      XMVECTOR x2 = XMLoadFloat2(&v2);
      XMVECTOR X = XMVectorLerp(x1, x2, t);
      XMStoreFloat2(&result, X);
  }
  
  inline Vector2 Vector2::SmoothStep(const Vector2& v1, const Vector2& v2, float t) noexcept
  {
      using namespace DirectX;
      t = (t > 1.0f) ? 1.0f : ((t < 0.0f) ? 0.0f : t);  // Clamp value to 0 to 1
      t = t * t*(3.f - 2.f*t);
      XMVECTOR x1 = XMLoadFloat2(&v1);
      XMVECTOR x2 = XMLoadFloat2(&v2);
      XMVECTOR X = XMVectorLerp(x1, x2, t);
  
      Vector2 result;
      XMStoreFloat2(&result, X);
      return result;
  }
  
  inline void Vector2::Barycentric(const Vector2& v1, const Vector2& v2, const Vector2& v3, float f, float g, Vector2& result) noexcept
  {
      using namespace DirectX;
      XMVECTOR x1 = XMLoadFloat2(&v1);
      XMVECTOR x2 = XMLoadFloat2(&v2);
      XMVECTOR x3 = XMLoadFloat2(&v3);
      XMVECTOR X = XMVectorBaryCentric(x1, x2, x3, f, g);
      XMStoreFloat2(&result, X);
  }
  
  inline Vector2 Vector2::Barycentric(const Vector2& v1, const Vector2& v2, const Vector2& v3, float f, float g) noexcept
  {
      using namespace DirectX;
      XMVECTOR x1 = XMLoadFloat2(&v1);
      XMVECTOR x2 = XMLoadFloat2(&v2);
      XMVECTOR x3 = XMLoadFloat2(&v3);
      XMVECTOR X = XMVectorBaryCentric(x1, x2, x3, f, g);
  
      Vector2 result;
      XMStoreFloat2(&result, X);
      return result;
  }
  
  inline void Vector2::CatmullRom(const Vector2& v1, const Vector2& v2, const Vector2& v3, const Vector2& v4, float t, Vector2& result) noexcept
  {
      using namespace DirectX;
      XMVECTOR x1 = XMLoadFloat2(&v1);
      XMVECTOR x2 = XMLoadFloat2(&v2);
      XMVECTOR x3 = XMLoadFloat2(&v3);
      XMVECTOR x4 = XMLoadFloat2(&v4);
      XMVECTOR X = XMVectorCatmullRom(x1, x2, x3, x4, t);
      XMStoreFloat2(&result, X);
  }
  
  inline Vector2 Vector2::CatmullRom(const Vector2& v1, const Vector2& v2, const Vector2& v3, const Vector2& v4, float t) noexcept
  {
      using namespace DirectX;
      XMVECTOR x1 = XMLoadFloat2(&v1);
      XMVECTOR x2 = XMLoadFloat2(&v2);
      XMVECTOR x3 = XMLoadFloat2(&v3);
      XMVECTOR x4 = XMLoadFloat2(&v4);
      XMVECTOR X = XMVectorCatmullRom(x1, x2, x3, x4, t);
  
      Vector2 result;
      XMStoreFloat2(&result, X);
      return result;
  }
  
  inline void Vector2::Hermite(const Vector2& v1, const Vector2& t1, const Vector2& v2, const Vector2& t2, float t, Vector2& result) noexcept
  {
      using namespace DirectX;
      XMVECTOR x1 = XMLoadFloat2(&v1);
      XMVECTOR x2 = XMLoadFloat2(&t1);
      XMVECTOR x3 = XMLoadFloat2(&v2);
      XMVECTOR x4 = XMLoadFloat2(&t2);
      XMVECTOR X = XMVectorHermite(x1, x2, x3, x4, t);
      XMStoreFloat2(&result, X);
  }
  
  inline Vector2 Vector2::Hermite(const Vector2& v1, const Vector2& t1, const Vector2& v2, const Vector2& t2, float t) noexcept
  {
      using namespace DirectX;
      XMVECTOR x1 = XMLoadFloat2(&v1);
      XMVECTOR x2 = XMLoadFloat2(&t1);
      XMVECTOR x3 = XMLoadFloat2(&v2);
      XMVECTOR x4 = XMLoadFloat2(&t2);
      XMVECTOR X = XMVectorHermite(x1, x2, x3, x4, t);
  
      Vector2 result;
      XMStoreFloat2(&result, X);
      return result;
  }
  
  inline void Vector2::Reflect(const Vector2& ivec, const Vector2& nvec, Vector2& result) noexcept
  {
      using namespace DirectX;
      XMVECTOR i = XMLoadFloat2(&ivec);
      XMVECTOR n = XMLoadFloat2(&nvec);
      XMVECTOR X = XMVector2Reflect(i, n);
      XMStoreFloat2(&result, X);
  }
  
  inline Vector2 Vector2::Reflect(const Vector2& ivec, const Vector2& nvec) noexcept
  {
      using namespace DirectX;
      XMVECTOR i = XMLoadFloat2(&ivec);
      XMVECTOR n = XMLoadFloat2(&nvec);
      XMVECTOR X = XMVector2Reflect(i, n);
  
      Vector2 result;
      XMStoreFloat2(&result, X);
      return result;
  }
  
  inline void Vector2::Refract(const Vector2& ivec, const Vector2& nvec, float refractionIndex, Vector2& result) noexcept
  {
      using namespace DirectX;
      XMVECTOR i = XMLoadFloat2(&ivec);
      XMVECTOR n = XMLoadFloat2(&nvec);
      XMVECTOR X = XMVector2Refract(i, n, refractionIndex);
      XMStoreFloat2(&result, X);
  }
  
  inline Vector2 Vector2::Refract(const Vector2& ivec, const Vector2& nvec, float refractionIndex) noexcept
  {
      using namespace DirectX;
      XMVECTOR i = XMLoadFloat2(&ivec);
      XMVECTOR n = XMLoadFloat2(&nvec);
      XMVECTOR X = XMVector2Refract(i, n, refractionIndex);
  
      Vector2 result;
      XMStoreFloat2(&result, X);
      return result;
  }
  
  inline void Vector2::Transform(const Vector2& v, const Quaternion& quat, Vector2& result) noexcept
  {
      using namespace DirectX;
      XMVECTOR v1 = XMLoadFloat2(&v);
      XMVECTOR q = XMLoadFloat4(&quat);
      XMVECTOR X = XMVector3Rotate(v1, q);
      XMStoreFloat2(&result, X);
  }
  
  inline Vector2 Vector2::Transform(const Vector2& v, const Quaternion& quat) noexcept
  {
      using namespace DirectX;
      XMVECTOR v1 = XMLoadFloat2(&v);
      XMVECTOR q = XMLoadFloat4(&quat);
      XMVECTOR X = XMVector3Rotate(v1, q);
  
      Vector2 result;
      XMStoreFloat2(&result, X);
      return result;
  }
  
  inline void Vector2::Transform(const Vector2& v, const Matrix& m, Vector2& result) noexcept
  {
      using namespace DirectX;
      XMVECTOR v1 = XMLoadFloat2(&v);
      XMMATRIX M = XMLoadFloat4x4(&m);
      XMVECTOR X = XMVector2TransformCoord(v1, M);
      XMStoreFloat2(&result, X);
  }
  
  inline Vector2 Vector2::Transform(const Vector2& v, const Matrix& m) noexcept
  {
      using namespace DirectX;
      XMVECTOR v1 = XMLoadFloat2(&v);
      XMMATRIX M = XMLoadFloat4x4(&m);
      XMVECTOR X = XMVector2TransformCoord(v1, M);
  
      Vector2 result;
      XMStoreFloat2(&result, X);
      return result;
  }
  
  _Use_decl_annotations_
  inline void Vector2::Transform(const Vector2* varray, size_t count, const Matrix& m, Vector2* resultArray) noexcept
  {
      using namespace DirectX;
      XMMATRIX M = XMLoadFloat4x4(&m);
      XMVector2TransformCoordStream(resultArray, sizeof(XMFLOAT2), varray, sizeof(XMFLOAT2), count, M);
  }
  
  inline void Vector2::Transform(const Vector2& v, const Matrix& m, Vector4& result) noexcept
  {
      using namespace DirectX;
      XMVECTOR v1 = XMLoadFloat2(&v);
      XMMATRIX M = XMLoadFloat4x4(&m);
      XMVECTOR X = XMVector2Transform(v1, M);
      XMStoreFloat4(&result, X);
  }
  
  _Use_decl_annotations_
  inline void Vector2::Transform(const Vector2* varray, size_t count, const Matrix& m, Vector4* resultArray) noexcept
  {
      using namespace DirectX;
      XMMATRIX M = XMLoadFloat4x4(&m);
      XMVector2TransformStream(resultArray, sizeof(XMFLOAT4), varray, sizeof(XMFLOAT2), count, M);
  }
  
  inline void Vector2::TransformNormal(const Vector2& v, const Matrix& m, Vector2& result) noexcept
  {
      using namespace DirectX;
      XMVECTOR v1 = XMLoadFloat2(&v);
      XMMATRIX M = XMLoadFloat4x4(&m);
      XMVECTOR X = XMVector2TransformNormal(v1, M);
      XMStoreFloat2(&result, X);
  }
  
  inline Vector2 Vector2::TransformNormal(const Vector2& v, const Matrix& m) noexcept
  {
      using namespace DirectX;
      XMVECTOR v1 = XMLoadFloat2(&v);
      XMMATRIX M = XMLoadFloat4x4(&m);
      XMVECTOR X = XMVector2TransformNormal(v1, M);
  
      Vector2 result;
      XMStoreFloat2(&result, X);
      return result;
  }
  
  _Use_decl_annotations_
  inline void Vector2::TransformNormal(const Vector2* varray, size_t count, const Matrix& m, Vector2* resultArray) noexcept
  {
      using namespace DirectX;
      XMMATRIX M = XMLoadFloat4x4(&m);
      XMVector2TransformNormalStream(resultArray, sizeof(XMFLOAT2), varray, sizeof(XMFLOAT2), count, M);
  }
  
  
  /****************************************************************************
   *
   * Vector3
   *
   ****************************************************************************/
  
  //------------------------------------------------------------------------------
  // Comparision operators
  //------------------------------------------------------------------------------
  
  inline bool Vector3::operator == (const Vector3& V) const noexcept
  {
      using namespace DirectX;
      XMVECTOR v1 = XMLoadFloat3(this);
      XMVECTOR v2 = XMLoadFloat3(&V);
      return XMVector3Equal(v1, v2);
  }
  
  inline bool Vector3::operator != (const Vector3& V) const noexcept
  {
      using namespace DirectX;
      XMVECTOR v1 = XMLoadFloat3(this);
      XMVECTOR v2 = XMLoadFloat3(&V);
      return XMVector3NotEqual(v1, v2);
  }
  
  //------------------------------------------------------------------------------
  // Assignment operators
  //------------------------------------------------------------------------------
  
  inline Vector3& Vector3::operator+= (const Vector3& V) noexcept
  {
      using namespace DirectX;
      XMVECTOR v1 = XMLoadFloat3(this);
      XMVECTOR v2 = XMLoadFloat3(&V);
      XMVECTOR X = XMVectorAdd(v1, v2);
      XMStoreFloat3(this, X);
      return *this;
  }
  
  inline Vector3& Vector3::operator-= (const Vector3& V) noexcept
  {
      using namespace DirectX;
      XMVECTOR v1 = XMLoadFloat3(this);
      XMVECTOR v2 = XMLoadFloat3(&V);
      XMVECTOR X = XMVectorSubtract(v1, v2);
      XMStoreFloat3(this, X);
      return *this;
  }
  
  inline Vector3& Vector3::operator*= (const Vector3& V) noexcept
  {
      using namespace DirectX;
      XMVECTOR v1 = XMLoadFloat3(this);
      XMVECTOR v2 = XMLoadFloat3(&V);
      XMVECTOR X = XMVectorMultiply(v1, v2);
      XMStoreFloat3(this, X);
      return *this;
  }
  
  inline Vector3& Vector3::operator*= (float S) noexcept
  {
      using namespace DirectX;
      XMVECTOR v1 = XMLoadFloat3(this);
      XMVECTOR X = XMVectorScale(v1, S);
      XMStoreFloat3(this, X);
      return *this;
  }
  
  inline Vector3& Vector3::operator/= (float S) noexcept
  {
      using namespace DirectX;
      assert(S != 0.0f);
      XMVECTOR v1 = XMLoadFloat3(this);
      XMVECTOR X = XMVectorScale(v1, 1.f / S);
      XMStoreFloat3(this, X);
      return *this;
  }
  
  //------------------------------------------------------------------------------
  // Urnary operators
  //------------------------------------------------------------------------------
  
  inline Vector3 Vector3::operator- () const noexcept
  {
      using namespace DirectX;
      XMVECTOR v1 = XMLoadFloat3(this);
      XMVECTOR X = XMVectorNegate(v1);
      Vector3 R;
      XMStoreFloat3(&R, X);
      return R;
  }
  
  //------------------------------------------------------------------------------
  // Binary operators
  //------------------------------------------------------------------------------
  
  inline Vector3 operator+ (const Vector3& V1, const Vector3& V2) noexcept
  {
      using namespace DirectX;
      XMVECTOR v1 = XMLoadFloat3(&V1);
      XMVECTOR v2 = XMLoadFloat3(&V2);
      XMVECTOR X = XMVectorAdd(v1, v2);
      Vector3 R;
      XMStoreFloat3(&R, X);
      return R;
  }
  
  inline Vector3 operator- (const Vector3& V1, const Vector3& V2) noexcept
  {
      using namespace DirectX;
      XMVECTOR v1 = XMLoadFloat3(&V1);
      XMVECTOR v2 = XMLoadFloat3(&V2);
      XMVECTOR X = XMVectorSubtract(v1, v2);
      Vector3 R;
      XMStoreFloat3(&R, X);
      return R;
  }
  
  inline Vector3 operator* (const Vector3& V1, const Vector3& V2) noexcept
  {
      using namespace DirectX;
      XMVECTOR v1 = XMLoadFloat3(&V1);
      XMVECTOR v2 = XMLoadFloat3(&V2);
      XMVECTOR X = XMVectorMultiply(v1, v2);
      Vector3 R;
      XMStoreFloat3(&R, X);
      return R;
  }
  
  inline Vector3 operator* (const Vector3& V, float S) noexcept
  {
      using namespace DirectX;
      XMVECTOR v1 = XMLoadFloat3(&V);
      XMVECTOR X = XMVectorScale(v1, S);
      Vector3 R;
      XMStoreFloat3(&R, X);
      return R;
  }
  
  inline Vector3 operator/ (const Vector3& V1, const Vector3& V2) noexcept
  {
      using namespace DirectX;
      XMVECTOR v1 = XMLoadFloat3(&V1);
      XMVECTOR v2 = XMLoadFloat3(&V2);
      XMVECTOR X = XMVectorDivide(v1, v2);
      Vector3 R;
      XMStoreFloat3(&R, X);
      return R;
  }
  
  inline Vector3 operator/ (const Vector3& V, float S) noexcept
  {
      using namespace DirectX;
      XMVECTOR v1 = XMLoadFloat3(&V);
      XMVECTOR X = XMVectorScale(v1, 1.f / S);
      Vector3 R;
      XMStoreFloat3(&R, X);
      return R;
  }
  
  inline Vector3 operator* (float S, const Vector3& V) noexcept
  {
      using namespace DirectX;
      XMVECTOR v1 = XMLoadFloat3(&V);
      XMVECTOR X = XMVectorScale(v1, S);
      Vector3 R;
      XMStoreFloat3(&R, X);
      return R;
  }
  
  //------------------------------------------------------------------------------
  // Vector operations
  //------------------------------------------------------------------------------
  
  inline bool Vector3::InBounds(const Vector3& Bounds) const noexcept
  {
      using namespace DirectX;
      XMVECTOR v1 = XMLoadFloat3(this);
      XMVECTOR v2 = XMLoadFloat3(&Bounds);
      return XMVector3InBounds(v1, v2);
  }
  
  inline float Vector3::Length() const noexcept
  {
      using namespace DirectX;
      XMVECTOR v1 = XMLoadFloat3(this);
      XMVECTOR X = XMVector3Length(v1);
      return XMVectorGetX(X);
  }
  
  inline float Vector3::LengthSquared() const noexcept
  {
      using namespace DirectX;
      XMVECTOR v1 = XMLoadFloat3(this);
      XMVECTOR X = XMVector3LengthSq(v1);
      return XMVectorGetX(X);
  }
  
  inline float Vector3::Dot(const Vector3& V) const noexcept
  {
      using namespace DirectX;
      XMVECTOR v1 = XMLoadFloat3(this);
      XMVECTOR v2 = XMLoadFloat3(&V);
      XMVECTOR X = XMVector3Dot(v1, v2);
      return XMVectorGetX(X);
  }
  
  inline void Vector3::Cross(const Vector3& V, Vector3& result) const noexcept
  {
      using namespace DirectX;
      XMVECTOR v1 = XMLoadFloat3(this);
      XMVECTOR v2 = XMLoadFloat3(&V);
      XMVECTOR R = XMVector3Cross(v1, v2);
      XMStoreFloat3(&result, R);
  }
  
  inline Vector3 Vector3::Cross(const Vector3& V) const noexcept
  {
      using namespace DirectX;
      XMVECTOR v1 = XMLoadFloat3(this);
      XMVECTOR v2 = XMLoadFloat3(&V);
      XMVECTOR R = XMVector3Cross(v1, v2);
  
      Vector3 result;
      XMStoreFloat3(&result, R);
      return result;
  }
  
  inline void Vector3::Normalize() noexcept
  {
      using namespace DirectX;
      XMVECTOR v1 = XMLoadFloat3(this);
      XMVECTOR X = XMVector3Normalize(v1);
      XMStoreFloat3(this, X);
  }
  
  inline void Vector3::Normalize(Vector3& result) const noexcept
  {
      using namespace DirectX;
      XMVECTOR v1 = XMLoadFloat3(this);
      XMVECTOR X = XMVector3Normalize(v1);
      XMStoreFloat3(&result, X);
  }
  
  inline void Vector3::Clamp(const Vector3& vmin, const Vector3& vmax) noexcept
  {
      using namespace DirectX;
      XMVECTOR v1 = XMLoadFloat3(this);
      XMVECTOR v2 = XMLoadFloat3(&vmin);
      XMVECTOR v3 = XMLoadFloat3(&vmax);
      XMVECTOR X = XMVectorClamp(v1, v2, v3);
      XMStoreFloat3(this, X);
  }
  
  inline void Vector3::Clamp(const Vector3& vmin, const Vector3& vmax, Vector3& result) const noexcept
  {
      using namespace DirectX;
      XMVECTOR v1 = XMLoadFloat3(this);
      XMVECTOR v2 = XMLoadFloat3(&vmin);
      XMVECTOR v3 = XMLoadFloat3(&vmax);
      XMVECTOR X = XMVectorClamp(v1, v2, v3);
      XMStoreFloat3(&result, X);
  }
  
  //------------------------------------------------------------------------------
  // Static functions
  //------------------------------------------------------------------------------
  
  inline float Vector3::Distance(const Vector3& v1, const Vector3& v2) noexcept
  {
      using namespace DirectX;
      XMVECTOR x1 = XMLoadFloat3(&v1);
      XMVECTOR x2 = XMLoadFloat3(&v2);
      XMVECTOR V = XMVectorSubtract(x2, x1);
      XMVECTOR X = XMVector3Length(V);
      return XMVectorGetX(X);
  }
  
  inline float Vector3::DistanceSquared(const Vector3& v1, const Vector3& v2) noexcept
  {
      using namespace DirectX;
      XMVECTOR x1 = XMLoadFloat3(&v1);
      XMVECTOR x2 = XMLoadFloat3(&v2);
      XMVECTOR V = XMVectorSubtract(x2, x1);
      XMVECTOR X = XMVector3LengthSq(V);
      return XMVectorGetX(X);
  }
  
  inline void Vector3::Min(const Vector3& v1, const Vector3& v2, Vector3& result) noexcept
  {
      using namespace DirectX;
      XMVECTOR x1 = XMLoadFloat3(&v1);
      XMVECTOR x2 = XMLoadFloat3(&v2);
      XMVECTOR X = XMVectorMin(x1, x2);
      XMStoreFloat3(&result, X);
  }
  
  inline Vector3 Vector3::Min(const Vector3& v1, const Vector3& v2) noexcept
  {
      using namespace DirectX;
      XMVECTOR x1 = XMLoadFloat3(&v1);
      XMVECTOR x2 = XMLoadFloat3(&v2);
      XMVECTOR X = XMVectorMin(x1, x2);
  
      Vector3 result;
      XMStoreFloat3(&result, X);
      return result;
  }
  
  inline void Vector3::Max(const Vector3& v1, const Vector3& v2, Vector3& result) noexcept
  {
      using namespace DirectX;
      XMVECTOR x1 = XMLoadFloat3(&v1);
      XMVECTOR x2 = XMLoadFloat3(&v2);
      XMVECTOR X = XMVectorMax(x1, x2);
      XMStoreFloat3(&result, X);
  }
  
  inline Vector3 Vector3::Max(const Vector3& v1, const Vector3& v2) noexcept
  {
      using namespace DirectX;
      XMVECTOR x1 = XMLoadFloat3(&v1);
      XMVECTOR x2 = XMLoadFloat3(&v2);
      XMVECTOR X = XMVectorMax(x1, x2);
  
      Vector3 result;
      XMStoreFloat3(&result, X);
      return result;
  }
  
  inline void Vector3::Lerp(const Vector3& v1, const Vector3& v2, float t, Vector3& result) noexcept
  {
      using namespace DirectX;
      XMVECTOR x1 = XMLoadFloat3(&v1);
      XMVECTOR x2 = XMLoadFloat3(&v2);
      XMVECTOR X = XMVectorLerp(x1, x2, t);
      XMStoreFloat3(&result, X);
  }
  
  inline Vector3 Vector3::Lerp(const Vector3& v1, const Vector3& v2, float t) noexcept
  {
      using namespace DirectX;
      XMVECTOR x1 = XMLoadFloat3(&v1);
      XMVECTOR x2 = XMLoadFloat3(&v2);
      XMVECTOR X = XMVectorLerp(x1, x2, t);
  
      Vector3 result;
      XMStoreFloat3(&result, X);
      return result;
  }
  
  inline void Vector3::SmoothStep(const Vector3& v1, const Vector3& v2, float t, Vector3& result) noexcept
  {
      using namespace DirectX;
      t = (t > 1.0f) ? 1.0f : ((t < 0.0f) ? 0.0f : t);  // Clamp value to 0 to 1
      t = t * t*(3.f - 2.f*t);
      XMVECTOR x1 = XMLoadFloat3(&v1);
      XMVECTOR x2 = XMLoadFloat3(&v2);
      XMVECTOR X = XMVectorLerp(x1, x2, t);
      XMStoreFloat3(&result, X);
  }
  
  inline Vector3 Vector3::SmoothStep(const Vector3& v1, const Vector3& v2, float t) noexcept
  {
      using namespace DirectX;
      t = (t > 1.0f) ? 1.0f : ((t < 0.0f) ? 0.0f : t);  // Clamp value to 0 to 1
      t = t * t*(3.f - 2.f*t);
      XMVECTOR x1 = XMLoadFloat3(&v1);
      XMVECTOR x2 = XMLoadFloat3(&v2);
      XMVECTOR X = XMVectorLerp(x1, x2, t);
  
      Vector3 result;
      XMStoreFloat3(&result, X);
      return result;
  }
  
  inline void Vector3::Barycentric(const Vector3& v1, const Vector3& v2, const Vector3& v3, float f, float g, Vector3& result) noexcept
  {
      using namespace DirectX;
      XMVECTOR x1 = XMLoadFloat3(&v1);
      XMVECTOR x2 = XMLoadFloat3(&v2);
      XMVECTOR x3 = XMLoadFloat3(&v3);
      XMVECTOR X = XMVectorBaryCentric(x1, x2, x3, f, g);
      XMStoreFloat3(&result, X);
  }
  
  inline Vector3 Vector3::Barycentric(const Vector3& v1, const Vector3& v2, const Vector3& v3, float f, float g) noexcept
  {
      using namespace DirectX;
      XMVECTOR x1 = XMLoadFloat3(&v1);
      XMVECTOR x2 = XMLoadFloat3(&v2);
      XMVECTOR x3 = XMLoadFloat3(&v3);
      XMVECTOR X = XMVectorBaryCentric(x1, x2, x3, f, g);
  
      Vector3 result;
      XMStoreFloat3(&result, X);
      return result;
  }
  
  inline void Vector3::CatmullRom(const Vector3& v1, const Vector3& v2, const Vector3& v3, const Vector3& v4, float t, Vector3& result) noexcept
  {
      using namespace DirectX;
      XMVECTOR x1 = XMLoadFloat3(&v1);
      XMVECTOR x2 = XMLoadFloat3(&v2);
      XMVECTOR x3 = XMLoadFloat3(&v3);
      XMVECTOR x4 = XMLoadFloat3(&v4);
      XMVECTOR X = XMVectorCatmullRom(x1, x2, x3, x4, t);
      XMStoreFloat3(&result, X);
  }
  
  inline Vector3 Vector3::CatmullRom(const Vector3& v1, const Vector3& v2, const Vector3& v3, const Vector3& v4, float t) noexcept
  {
      using namespace DirectX;
      XMVECTOR x1 = XMLoadFloat3(&v1);
      XMVECTOR x2 = XMLoadFloat3(&v2);
      XMVECTOR x3 = XMLoadFloat3(&v3);
      XMVECTOR x4 = XMLoadFloat3(&v4);
      XMVECTOR X = XMVectorCatmullRom(x1, x2, x3, x4, t);
  
      Vector3 result;
      XMStoreFloat3(&result, X);
      return result;
  }
  
  inline void Vector3::Hermite(const Vector3& v1, const Vector3& t1, const Vector3& v2, const Vector3& t2, float t, Vector3& result) noexcept
  {
      using namespace DirectX;
      XMVECTOR x1 = XMLoadFloat3(&v1);
      XMVECTOR x2 = XMLoadFloat3(&t1);
      XMVECTOR x3 = XMLoadFloat3(&v2);
      XMVECTOR x4 = XMLoadFloat3(&t2);
      XMVECTOR X = XMVectorHermite(x1, x2, x3, x4, t);
      XMStoreFloat3(&result, X);
  }
  
  inline Vector3 Vector3::Hermite(const Vector3& v1, const Vector3& t1, const Vector3& v2, const Vector3& t2, float t) noexcept
  {
      using namespace DirectX;
      XMVECTOR x1 = XMLoadFloat3(&v1);
      XMVECTOR x2 = XMLoadFloat3(&t1);
      XMVECTOR x3 = XMLoadFloat3(&v2);
      XMVECTOR x4 = XMLoadFloat3(&t2);
      XMVECTOR X = XMVectorHermite(x1, x2, x3, x4, t);
  
      Vector3 result;
      XMStoreFloat3(&result, X);
      return result;
  }
  
  inline void Vector3::Reflect(const Vector3& ivec, const Vector3& nvec, Vector3& result) noexcept
  {
      using namespace DirectX;
      XMVECTOR i = XMLoadFloat3(&ivec);
      XMVECTOR n = XMLoadFloat3(&nvec);
      XMVECTOR X = XMVector3Reflect(i, n);
      XMStoreFloat3(&result, X);
  }
  
  inline Vector3 Vector3::Reflect(const Vector3& ivec, const Vector3& nvec) noexcept
  {
      using namespace DirectX;
      XMVECTOR i = XMLoadFloat3(&ivec);
      XMVECTOR n = XMLoadFloat3(&nvec);
      XMVECTOR X = XMVector3Reflect(i, n);
  
      Vector3 result;
      XMStoreFloat3(&result, X);
      return result;
  }
  
  inline void Vector3::Refract(const Vector3& ivec, const Vector3& nvec, float refractionIndex, Vector3& result) noexcept
  {
      using namespace DirectX;
      XMVECTOR i = XMLoadFloat3(&ivec);
      XMVECTOR n = XMLoadFloat3(&nvec);
      XMVECTOR X = XMVector3Refract(i, n, refractionIndex);
      XMStoreFloat3(&result, X);
  }
  
  inline Vector3 Vector3::Refract(const Vector3& ivec, const Vector3& nvec, float refractionIndex) noexcept
  {
      using namespace DirectX;
      XMVECTOR i = XMLoadFloat3(&ivec);
      XMVECTOR n = XMLoadFloat3(&nvec);
      XMVECTOR X = XMVector3Refract(i, n, refractionIndex);
  
      Vector3 result;
      XMStoreFloat3(&result, X);
      return result;
  }
  
  inline void Vector3::Transform(const Vector3& v, const Quaternion& quat, Vector3& result) noexcept
  {
      using namespace DirectX;
      XMVECTOR v1 = XMLoadFloat3(&v);
      XMVECTOR q = XMLoadFloat4(&quat);
      XMVECTOR X = XMVector3Rotate(v1, q);
      XMStoreFloat3(&result, X);
  }
  
  inline Vector3 Vector3::Transform(const Vector3& v, const Quaternion& quat) noexcept
  {
      using namespace DirectX;
      XMVECTOR v1 = XMLoadFloat3(&v);
      XMVECTOR q = XMLoadFloat4(&quat);
      XMVECTOR X = XMVector3Rotate(v1, q);
  
      Vector3 result;
      XMStoreFloat3(&result, X);
      return result;
  }
  
  inline void Vector3::Transform(const Vector3& v, const Matrix& m, Vector3& result) noexcept
  {
      using namespace DirectX;
      XMVECTOR v1 = XMLoadFloat3(&v);
      XMMATRIX M = XMLoadFloat4x4(&m);
      XMVECTOR X = XMVector3TransformCoord(v1, M);
      XMStoreFloat3(&result, X);
  }
  
  inline Vector3 Vector3::Transform(const Vector3& v, const Matrix& m) noexcept
  {
      using namespace DirectX;
      XMVECTOR v1 = XMLoadFloat3(&v);
      XMMATRIX M = XMLoadFloat4x4(&m);
      XMVECTOR X = XMVector3TransformCoord(v1, M);
  
      Vector3 result;
      XMStoreFloat3(&result, X);
      return result;
  }
  
  _Use_decl_annotations_
  inline void Vector3::Transform(const Vector3* varray, size_t count, const Matrix& m, Vector3* resultArray) noexcept
  {
      using namespace DirectX;
      XMMATRIX M = XMLoadFloat4x4(&m);
      XMVector3TransformCoordStream(resultArray, sizeof(XMFLOAT3), varray, sizeof(XMFLOAT3), count, M);
  }
  
  inline void Vector3::Transform(const Vector3& v, const Matrix& m, Vector4& result) noexcept
  {
      using namespace DirectX;
      XMVECTOR v1 = XMLoadFloat3(&v);
      XMMATRIX M = XMLoadFloat4x4(&m);
      XMVECTOR X = XMVector3Transform(v1, M);
      XMStoreFloat4(&result, X);
  }
  
  _Use_decl_annotations_
  inline void Vector3::Transform(const Vector3* varray, size_t count, const Matrix& m, Vector4* resultArray) noexcept
  {
      using namespace DirectX;
      XMMATRIX M = XMLoadFloat4x4(&m);
      XMVector3TransformStream(resultArray, sizeof(XMFLOAT4), varray, sizeof(XMFLOAT3), count, M);
  }
  
  inline void Vector3::TransformNormal(const Vector3& v, const Matrix& m, Vector3& result) noexcept
  {
      using namespace DirectX;
      XMVECTOR v1 = XMLoadFloat3(&v);
      XMMATRIX M = XMLoadFloat4x4(&m);
      XMVECTOR X = XMVector3TransformNormal(v1, M);
      XMStoreFloat3(&result, X);
  }
  
  inline Vector3 Vector3::TransformNormal(const Vector3& v, const Matrix& m) noexcept
  {
      using namespace DirectX;
      XMVECTOR v1 = XMLoadFloat3(&v);
      XMMATRIX M = XMLoadFloat4x4(&m);
      XMVECTOR X = XMVector3TransformNormal(v1, M);
  
      Vector3 result;
      XMStoreFloat3(&result, X);
      return result;
  }
  
  _Use_decl_annotations_
  inline void Vector3::TransformNormal(const Vector3* varray, size_t count, const Matrix& m, Vector3* resultArray) noexcept
  {
      using namespace DirectX;
      XMMATRIX M = XMLoadFloat4x4(&m);
      XMVector3TransformNormalStream(resultArray, sizeof(XMFLOAT3), varray, sizeof(XMFLOAT3), count, M);
  }
  
  
  /****************************************************************************
   *
   * Vector4
   *
   ****************************************************************************/
  
  //------------------------------------------------------------------------------
  // Comparision operators
  //------------------------------------------------------------------------------
  
  inline bool Vector4::operator == (const Vector4& V) const noexcept
  {
      using namespace DirectX;
      XMVECTOR v1 = XMLoadFloat4(this);
      XMVECTOR v2 = XMLoadFloat4(&V);
      return XMVector4Equal(v1, v2);
  }
  
  inline bool Vector4::operator != (const Vector4& V) const noexcept
  {
      using namespace DirectX;
      XMVECTOR v1 = XMLoadFloat4(this);
      XMVECTOR v2 = XMLoadFloat4(&V);
      return XMVector4NotEqual(v1, v2);
  }
  
  //------------------------------------------------------------------------------
  // Assignment operators
  //------------------------------------------------------------------------------
  
  inline Vector4& Vector4::operator+= (const Vector4& V) noexcept
  {
      using namespace DirectX;
      XMVECTOR v1 = XMLoadFloat4(this);
      XMVECTOR v2 = XMLoadFloat4(&V);
      XMVECTOR X = XMVectorAdd(v1, v2);
      XMStoreFloat4(this, X);
      return *this;
  }
  
  inline Vector4& Vector4::operator-= (const Vector4& V) noexcept
  {
      using namespace DirectX;
      XMVECTOR v1 = XMLoadFloat4(this);
      XMVECTOR v2 = XMLoadFloat4(&V);
      XMVECTOR X = XMVectorSubtract(v1, v2);
      XMStoreFloat4(this, X);
      return *this;
  }
  
  inline Vector4& Vector4::operator*= (const Vector4& V) noexcept
  {
      using namespace DirectX;
      XMVECTOR v1 = XMLoadFloat4(this);
      XMVECTOR v2 = XMLoadFloat4(&V);
      XMVECTOR X = XMVectorMultiply(v1, v2);
      XMStoreFloat4(this, X);
      return *this;
  }
  
  inline Vector4& Vector4::operator*= (float S) noexcept
  {
      using namespace DirectX;
      XMVECTOR v1 = XMLoadFloat4(this);
      XMVECTOR X = XMVectorScale(v1, S);
      XMStoreFloat4(this, X);
      return *this;
  }
  
  inline Vector4& Vector4::operator/= (float S) noexcept
  {
      using namespace DirectX;
      assert(S != 0.0f);
      XMVECTOR v1 = XMLoadFloat4(this);
      XMVECTOR X = XMVectorScale(v1, 1.f / S);
      XMStoreFloat4(this, X);
      return *this;
  }
  
  //------------------------------------------------------------------------------
  // Urnary operators
  //------------------------------------------------------------------------------
  
  inline Vector4 Vector4::operator- () const noexcept
  {
      using namespace DirectX;
      XMVECTOR v1 = XMLoadFloat4(this);
      XMVECTOR X = XMVectorNegate(v1);
      Vector4 R;
      XMStoreFloat4(&R, X);
      return R;
  }
  
  //------------------------------------------------------------------------------
  // Binary operators
  //------------------------------------------------------------------------------
  
  inline Vector4 operator+ (const Vector4& V1, const Vector4& V2) noexcept
  {
      using namespace DirectX;
      XMVECTOR v1 = XMLoadFloat4(&V1);
      XMVECTOR v2 = XMLoadFloat4(&V2);
      XMVECTOR X = XMVectorAdd(v1, v2);
      Vector4 R;
      XMStoreFloat4(&R, X);
      return R;
  }
  
  inline Vector4 operator- (const Vector4& V1, const Vector4& V2) noexcept
  {
      using namespace DirectX;
      XMVECTOR v1 = XMLoadFloat4(&V1);
      XMVECTOR v2 = XMLoadFloat4(&V2);
      XMVECTOR X = XMVectorSubtract(v1, v2);
      Vector4 R;
      XMStoreFloat4(&R, X);
      return R;
  }
  
  inline Vector4 operator* (const Vector4& V1, const Vector4& V2) noexcept
  {
      using namespace DirectX;
      XMVECTOR v1 = XMLoadFloat4(&V1);
      XMVECTOR v2 = XMLoadFloat4(&V2);
      XMVECTOR X = XMVectorMultiply(v1, v2);
      Vector4 R;
      XMStoreFloat4(&R, X);
      return R;
  }
  
  inline Vector4 operator* (const Vector4& V, float S) noexcept
  {
      using namespace DirectX;
      XMVECTOR v1 = XMLoadFloat4(&V);
      XMVECTOR X = XMVectorScale(v1, S);
      Vector4 R;
      XMStoreFloat4(&R, X);
      return R;
  }
  
  inline Vector4 operator/ (const Vector4& V1, const Vector4& V2) noexcept
  {
      using namespace DirectX;
      XMVECTOR v1 = XMLoadFloat4(&V1);
      XMVECTOR v2 = XMLoadFloat4(&V2);
      XMVECTOR X = XMVectorDivide(v1, v2);
      Vector4 R;
      XMStoreFloat4(&R, X);
      return R;
  }
  
  inline Vector4 operator/ (const Vector4& V, float S) noexcept
  {
      using namespace DirectX;
      XMVECTOR v1 = XMLoadFloat4(&V);
      XMVECTOR X = XMVectorScale(v1, 1.f / S);
      Vector4 R;
      XMStoreFloat4(&R, X);
      return R;
  }
  
  inline Vector4 operator* (float S, const Vector4& V) noexcept
  {
      using namespace DirectX;
      XMVECTOR v1 = XMLoadFloat4(&V);
      XMVECTOR X = XMVectorScale(v1, S);
      Vector4 R;
      XMStoreFloat4(&R, X);
      return R;
  }
  
  //------------------------------------------------------------------------------
  // Vector operations
  //------------------------------------------------------------------------------
  
  inline bool Vector4::InBounds(const Vector4& Bounds) const noexcept
  {
      using namespace DirectX;
      XMVECTOR v1 = XMLoadFloat4(this);
      XMVECTOR v2 = XMLoadFloat4(&Bounds);
      return XMVector4InBounds(v1, v2);
  }
  
  inline float Vector4::Length() const noexcept
  {
      using namespace DirectX;
      XMVECTOR v1 = XMLoadFloat4(this);
      XMVECTOR X = XMVector4Length(v1);
      return XMVectorGetX(X);
  }
  
  inline float Vector4::LengthSquared() const noexcept
  {
      using namespace DirectX;
      XMVECTOR v1 = XMLoadFloat4(this);
      XMVECTOR X = XMVector4LengthSq(v1);
      return XMVectorGetX(X);
  }
  
  inline float Vector4::Dot(const Vector4& V) const noexcept
  {
      using namespace DirectX;
      XMVECTOR v1 = XMLoadFloat4(this);
      XMVECTOR v2 = XMLoadFloat4(&V);
      XMVECTOR X = XMVector4Dot(v1, v2);
      return XMVectorGetX(X);
  }
  
  inline void Vector4::Cross(const Vector4& v1, const Vector4& v2, Vector4& result) const noexcept
  {
      using namespace DirectX;
      XMVECTOR x1 = XMLoadFloat4(this);
      XMVECTOR x2 = XMLoadFloat4(&v1);
      XMVECTOR x3 = XMLoadFloat4(&v2);
      XMVECTOR R = XMVector4Cross(x1, x2, x3);
      XMStoreFloat4(&result, R);
  }
  
  inline Vector4 Vector4::Cross(const Vector4& v1, const Vector4& v2) const noexcept
  {
      using namespace DirectX;
      XMVECTOR x1 = XMLoadFloat4(this);
      XMVECTOR x2 = XMLoadFloat4(&v1);
      XMVECTOR x3 = XMLoadFloat4(&v2);
      XMVECTOR R = XMVector4Cross(x1, x2, x3);
  
      Vector4 result;
      XMStoreFloat4(&result, R);
      return result;
  }
  
  inline void Vector4::Normalize() noexcept
  {
      using namespace DirectX;
      XMVECTOR v1 = XMLoadFloat4(this);
      XMVECTOR X = XMVector4Normalize(v1);
      XMStoreFloat4(this, X);
  }
  
  inline void Vector4::Normalize(Vector4& result) const noexcept
  {
      using namespace DirectX;
      XMVECTOR v1 = XMLoadFloat4(this);
      XMVECTOR X = XMVector4Normalize(v1);
      XMStoreFloat4(&result, X);
  }
  
  inline void Vector4::Clamp(const Vector4& vmin, const Vector4& vmax) noexcept
  {
      using namespace DirectX;
      XMVECTOR v1 = XMLoadFloat4(this);
      XMVECTOR v2 = XMLoadFloat4(&vmin);
      XMVECTOR v3 = XMLoadFloat4(&vmax);
      XMVECTOR X = XMVectorClamp(v1, v2, v3);
      XMStoreFloat4(this, X);
  }
  
  inline void Vector4::Clamp(const Vector4& vmin, const Vector4& vmax, Vector4& result) const noexcept
  {
      using namespace DirectX;
      XMVECTOR v1 = XMLoadFloat4(this);
      XMVECTOR v2 = XMLoadFloat4(&vmin);
      XMVECTOR v3 = XMLoadFloat4(&vmax);
      XMVECTOR X = XMVectorClamp(v1, v2, v3);
      XMStoreFloat4(&result, X);
  }
  
  //------------------------------------------------------------------------------
  // Static functions
  //------------------------------------------------------------------------------
  
  inline float Vector4::Distance(const Vector4& v1, const Vector4& v2) noexcept
  {
      using namespace DirectX;
      XMVECTOR x1 = XMLoadFloat4(&v1);
      XMVECTOR x2 = XMLoadFloat4(&v2);
      XMVECTOR V = XMVectorSubtract(x2, x1);
      XMVECTOR X = XMVector4Length(V);
      return XMVectorGetX(X);
  }
  
  inline float Vector4::DistanceSquared(const Vector4& v1, const Vector4& v2) noexcept
  {
      using namespace DirectX;
      XMVECTOR x1 = XMLoadFloat4(&v1);
      XMVECTOR x2 = XMLoadFloat4(&v2);
      XMVECTOR V = XMVectorSubtract(x2, x1);
      XMVECTOR X = XMVector4LengthSq(V);
      return XMVectorGetX(X);
  }
  
  inline void Vector4::Min(const Vector4& v1, const Vector4& v2, Vector4& result) noexcept
  {
      using namespace DirectX;
      XMVECTOR x1 = XMLoadFloat4(&v1);
      XMVECTOR x2 = XMLoadFloat4(&v2);
      XMVECTOR X = XMVectorMin(x1, x2);
      XMStoreFloat4(&result, X);
  }
  
  inline Vector4 Vector4::Min(const Vector4& v1, const Vector4& v2) noexcept
  {
      using namespace DirectX;
      XMVECTOR x1 = XMLoadFloat4(&v1);
      XMVECTOR x2 = XMLoadFloat4(&v2);
      XMVECTOR X = XMVectorMin(x1, x2);
  
      Vector4 result;
      XMStoreFloat4(&result, X);
      return result;
  }
  
  inline void Vector4::Max(const Vector4& v1, const Vector4& v2, Vector4& result) noexcept
  {
      using namespace DirectX;
      XMVECTOR x1 = XMLoadFloat4(&v1);
      XMVECTOR x2 = XMLoadFloat4(&v2);
      XMVECTOR X = XMVectorMax(x1, x2);
      XMStoreFloat4(&result, X);
  }
  
  inline Vector4 Vector4::Max(const Vector4& v1, const Vector4& v2) noexcept
  {
      using namespace DirectX;
      XMVECTOR x1 = XMLoadFloat4(&v1);
      XMVECTOR x2 = XMLoadFloat4(&v2);
      XMVECTOR X = XMVectorMax(x1, x2);
  
      Vector4 result;
      XMStoreFloat4(&result, X);
      return result;
  }
  
  inline void Vector4::Lerp(const Vector4& v1, const Vector4& v2, float t, Vector4& result) noexcept
  {
      using namespace DirectX;
      XMVECTOR x1 = XMLoadFloat4(&v1);
      XMVECTOR x2 = XMLoadFloat4(&v2);
      XMVECTOR X = XMVectorLerp(x1, x2, t);
      XMStoreFloat4(&result, X);
  }
  
  inline Vector4 Vector4::Lerp(const Vector4& v1, const Vector4& v2, float t) noexcept
  {
      using namespace DirectX;
      XMVECTOR x1 = XMLoadFloat4(&v1);
      XMVECTOR x2 = XMLoadFloat4(&v2);
      XMVECTOR X = XMVectorLerp(x1, x2, t);
  
      Vector4 result;
      XMStoreFloat4(&result, X);
      return result;
  }
  
  inline void Vector4::SmoothStep(const Vector4& v1, const Vector4& v2, float t, Vector4& result) noexcept
  {
      using namespace DirectX;
      t = (t > 1.0f) ? 1.0f : ((t < 0.0f) ? 0.0f : t);  // Clamp value to 0 to 1
      t = t * t*(3.f - 2.f*t);
      XMVECTOR x1 = XMLoadFloat4(&v1);
      XMVECTOR x2 = XMLoadFloat4(&v2);
      XMVECTOR X = XMVectorLerp(x1, x2, t);
      XMStoreFloat4(&result, X);
  }
  
  inline Vector4 Vector4::SmoothStep(const Vector4& v1, const Vector4& v2, float t) noexcept
  {
      using namespace DirectX;
      t = (t > 1.0f) ? 1.0f : ((t < 0.0f) ? 0.0f : t);  // Clamp value to 0 to 1
      t = t * t*(3.f - 2.f*t);
      XMVECTOR x1 = XMLoadFloat4(&v1);
      XMVECTOR x2 = XMLoadFloat4(&v2);
      XMVECTOR X = XMVectorLerp(x1, x2, t);
  
      Vector4 result;
      XMStoreFloat4(&result, X);
      return result;
  }
  
  inline void Vector4::Barycentric(const Vector4& v1, const Vector4& v2, const Vector4& v3, float f, float g, Vector4& result) noexcept
  {
      using namespace DirectX;
      XMVECTOR x1 = XMLoadFloat4(&v1);
      XMVECTOR x2 = XMLoadFloat4(&v2);
      XMVECTOR x3 = XMLoadFloat4(&v3);
      XMVECTOR X = XMVectorBaryCentric(x1, x2, x3, f, g);
      XMStoreFloat4(&result, X);
  }
  
  inline Vector4 Vector4::Barycentric(const Vector4& v1, const Vector4& v2, const Vector4& v3, float f, float g) noexcept
  {
      using namespace DirectX;
      XMVECTOR x1 = XMLoadFloat4(&v1);
      XMVECTOR x2 = XMLoadFloat4(&v2);
      XMVECTOR x3 = XMLoadFloat4(&v3);
      XMVECTOR X = XMVectorBaryCentric(x1, x2, x3, f, g);
  
      Vector4 result;
      XMStoreFloat4(&result, X);
      return result;
  }
  
  inline void Vector4::CatmullRom(const Vector4& v1, const Vector4& v2, const Vector4& v3, const Vector4& v4, float t, Vector4& result) noexcept
  {
      using namespace DirectX;
      XMVECTOR x1 = XMLoadFloat4(&v1);
      XMVECTOR x2 = XMLoadFloat4(&v2);
      XMVECTOR x3 = XMLoadFloat4(&v3);
      XMVECTOR x4 = XMLoadFloat4(&v4);
      XMVECTOR X = XMVectorCatmullRom(x1, x2, x3, x4, t);
      XMStoreFloat4(&result, X);
  }
  
  inline Vector4 Vector4::CatmullRom(const Vector4& v1, const Vector4& v2, const Vector4& v3, const Vector4& v4, float t) noexcept
  {
      using namespace DirectX;
      XMVECTOR x1 = XMLoadFloat4(&v1);
      XMVECTOR x2 = XMLoadFloat4(&v2);
      XMVECTOR x3 = XMLoadFloat4(&v3);
      XMVECTOR x4 = XMLoadFloat4(&v4);
      XMVECTOR X = XMVectorCatmullRom(x1, x2, x3, x4, t);
  
      Vector4 result;
      XMStoreFloat4(&result, X);
      return result;
  }
  
  inline void Vector4::Hermite(const Vector4& v1, const Vector4& t1, const Vector4& v2, const Vector4& t2, float t, Vector4& result) noexcept
  {
      using namespace DirectX;
      XMVECTOR x1 = XMLoadFloat4(&v1);
      XMVECTOR x2 = XMLoadFloat4(&t1);
      XMVECTOR x3 = XMLoadFloat4(&v2);
      XMVECTOR x4 = XMLoadFloat4(&t2);
      XMVECTOR X = XMVectorHermite(x1, x2, x3, x4, t);
      XMStoreFloat4(&result, X);
  }
  
  inline Vector4 Vector4::Hermite(const Vector4& v1, const Vector4& t1, const Vector4& v2, const Vector4& t2, float t) noexcept
  {
      using namespace DirectX;
      XMVECTOR x1 = XMLoadFloat4(&v1);
      XMVECTOR x2 = XMLoadFloat4(&t1);
      XMVECTOR x3 = XMLoadFloat4(&v2);
      XMVECTOR x4 = XMLoadFloat4(&t2);
      XMVECTOR X = XMVectorHermite(x1, x2, x3, x4, t);
  
      Vector4 result;
      XMStoreFloat4(&result, X);
      return result;
  }
  
  inline void Vector4::Reflect(const Vector4& ivec, const Vector4& nvec, Vector4& result) noexcept
  {
      using namespace DirectX;
      XMVECTOR i = XMLoadFloat4(&ivec);
      XMVECTOR n = XMLoadFloat4(&nvec);
      XMVECTOR X = XMVector4Reflect(i, n);
      XMStoreFloat4(&result, X);
  }
  
  inline Vector4 Vector4::Reflect(const Vector4& ivec, const Vector4& nvec) noexcept
  {
      using namespace DirectX;
      XMVECTOR i = XMLoadFloat4(&ivec);
      XMVECTOR n = XMLoadFloat4(&nvec);
      XMVECTOR X = XMVector4Reflect(i, n);
  
      Vector4 result;
      XMStoreFloat4(&result, X);
      return result;
  }
  
  inline void Vector4::Refract(const Vector4& ivec, const Vector4& nvec, float refractionIndex, Vector4& result) noexcept
  {
      using namespace DirectX;
      XMVECTOR i = XMLoadFloat4(&ivec);
      XMVECTOR n = XMLoadFloat4(&nvec);
      XMVECTOR X = XMVector4Refract(i, n, refractionIndex);
      XMStoreFloat4(&result, X);
  }
  
  inline Vector4 Vector4::Refract(const Vector4& ivec, const Vector4& nvec, float refractionIndex) noexcept
  {
      using namespace DirectX;
      XMVECTOR i = XMLoadFloat4(&ivec);
      XMVECTOR n = XMLoadFloat4(&nvec);
      XMVECTOR X = XMVector4Refract(i, n, refractionIndex);
  
      Vector4 result;
      XMStoreFloat4(&result, X);
      return result;
  }
  
  inline void Vector4::Transform(const Vector2& v, const Quaternion& quat, Vector4& result) noexcept
  {
      using namespace DirectX;
      XMVECTOR v1 = XMLoadFloat2(&v);
      XMVECTOR q = XMLoadFloat4(&quat);
      XMVECTOR X = XMVector3Rotate(v1, q);
      X = XMVectorSelect(g_XMIdentityR3, X, g_XMSelect1110); // result.w = 1.f
      XMStoreFloat4(&result, X);
  }
  
  inline Vector4 Vector4::Transform(const Vector2& v, const Quaternion& quat) noexcept
  {
      using namespace DirectX;
      XMVECTOR v1 = XMLoadFloat2(&v);
      XMVECTOR q = XMLoadFloat4(&quat);
      XMVECTOR X = XMVector3Rotate(v1, q);
      X = XMVectorSelect(g_XMIdentityR3, X, g_XMSelect1110); // result.w = 1.f
  
      Vector4 result;
      XMStoreFloat4(&result, X);
      return result;
  }
  
  inline void Vector4::Transform(const Vector3& v, const Quaternion& quat, Vector4& result) noexcept
  {
      using namespace DirectX;
      XMVECTOR v1 = XMLoadFloat3(&v);
      XMVECTOR q = XMLoadFloat4(&quat);
      XMVECTOR X = XMVector3Rotate(v1, q);
      X = XMVectorSelect(g_XMIdentityR3, X, g_XMSelect1110); // result.w = 1.f
      XMStoreFloat4(&result, X);
  }
  
  inline Vector4 Vector4::Transform(const Vector3& v, const Quaternion& quat) noexcept
  {
      using namespace DirectX;
      XMVECTOR v1 = XMLoadFloat3(&v);
      XMVECTOR q = XMLoadFloat4(&quat);
      XMVECTOR X = XMVector3Rotate(v1, q);
      X = XMVectorSelect(g_XMIdentityR3, X, g_XMSelect1110); // result.w = 1.f
  
      Vector4 result;
      XMStoreFloat4(&result, X);
      return result;
  }
  
  inline void Vector4::Transform(const Vector4& v, const Quaternion& quat, Vector4& result) noexcept
  {
      using namespace DirectX;
      XMVECTOR v1 = XMLoadFloat4(&v);
      XMVECTOR q = XMLoadFloat4(&quat);
      XMVECTOR X = XMVector3Rotate(v1, q);
      X = XMVectorSelect(v1, X, g_XMSelect1110); // result.w = v.w
      XMStoreFloat4(&result, X);
  }
  
  inline Vector4 Vector4::Transform(const Vector4& v, const Quaternion& quat) noexcept
  {
      using namespace DirectX;
      XMVECTOR v1 = XMLoadFloat4(&v);
      XMVECTOR q = XMLoadFloat4(&quat);
      XMVECTOR X = XMVector3Rotate(v1, q);
      X = XMVectorSelect(v1, X, g_XMSelect1110); // result.w = v.w
  
      Vector4 result;
      XMStoreFloat4(&result, X);
      return result;
  }
  
  inline void Vector4::Transform(const Vector4& v, const Matrix& m, Vector4& result) noexcept
  {
      using namespace DirectX;
      XMVECTOR v1 = XMLoadFloat4(&v);
      XMMATRIX M = XMLoadFloat4x4(&m);
      XMVECTOR X = XMVector4Transform(v1, M);
      XMStoreFloat4(&result, X);
  }
  
  inline Vector4 Vector4::Transform(const Vector4& v, const Matrix& m) noexcept
  {
      using namespace DirectX;
      XMVECTOR v1 = XMLoadFloat4(&v);
      XMMATRIX M = XMLoadFloat4x4(&m);
      XMVECTOR X = XMVector4Transform(v1, M);
  
      Vector4 result;
      XMStoreFloat4(&result, X);
      return result;
  }
  
  _Use_decl_annotations_
  inline void Vector4::Transform(const Vector4* varray, size_t count, const Matrix& m, Vector4* resultArray) noexcept
  {
      using namespace DirectX;
      XMMATRIX M = XMLoadFloat4x4(&m);
      XMVector4TransformStream(resultArray, sizeof(XMFLOAT4), varray, sizeof(XMFLOAT4), count, M);
  }
  
  
  /****************************************************************************
   *
   * Matrix
   *
   ****************************************************************************/
  
  //------------------------------------------------------------------------------
  // Comparision operators
  //------------------------------------------------------------------------------
  
  inline bool Matrix::operator == (const Matrix& M) const noexcept
  {
      using namespace DirectX;
      XMVECTOR x1 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&_11));
      XMVECTOR x2 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&_21));
      XMVECTOR x3 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&_31));
      XMVECTOR x4 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&_41));
  
      XMVECTOR y1 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&M._11));
      XMVECTOR y2 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&M._21));
      XMVECTOR y3 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&M._31));
      XMVECTOR y4 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&M._41));
  
      return (XMVector4Equal(x1, y1)
              && XMVector4Equal(x2, y2)
              && XMVector4Equal(x3, y3)
              && XMVector4Equal(x4, y4)) != 0;
  }
  
  inline bool Matrix::operator != (const Matrix& M) const noexcept
  {
      using namespace DirectX;
      XMVECTOR x1 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&_11));
      XMVECTOR x2 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&_21));
      XMVECTOR x3 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&_31));
      XMVECTOR x4 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&_41));
  
      XMVECTOR y1 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&M._11));
      XMVECTOR y2 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&M._21));
      XMVECTOR y3 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&M._31));
      XMVECTOR y4 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&M._41));
  
      return (XMVector4NotEqual(x1, y1)
              || XMVector4NotEqual(x2, y2)
              || XMVector4NotEqual(x3, y3)
              || XMVector4NotEqual(x4, y4)) != 0;
  }
  
  //------------------------------------------------------------------------------
  // Assignment operators
  //------------------------------------------------------------------------------
  
  inline Matrix::Matrix(const XMFLOAT3X3& M) noexcept
  {
      _11 = M._11; _12 = M._12; _13 = M._13; _14 = 0.f;
      _21 = M._21; _22 = M._22; _23 = M._23; _24 = 0.f;
      _31 = M._31; _32 = M._32; _33 = M._33; _34 = 0.f;
      _41 = 0.f;   _42 = 0.f;   _43 = 0.f;   _44 = 1.f;
  }
  
  inline Matrix::Matrix(const XMFLOAT4X3& M) noexcept
  {
      _11 = M._11; _12 = M._12; _13 = M._13; _14 = 0.f;
      _21 = M._21; _22 = M._22; _23 = M._23; _24 = 0.f;
      _31 = M._31; _32 = M._32; _33 = M._33; _34 = 0.f;
      _41 = M._41; _42 = M._42; _43 = M._43; _44 = 1.f;
  }
  
  inline Matrix& Matrix::operator= (const XMFLOAT3X3& M) noexcept
  {
      _11 = M._11; _12 = M._12; _13 = M._13; _14 = 0.f;
      _21 = M._21; _22 = M._22; _23 = M._23; _24 = 0.f;
      _31 = M._31; _32 = M._32; _33 = M._33; _34 = 0.f;
      _41 = 0.f;   _42 = 0.f;   _43 = 0.f;   _44 = 1.f;
      return *this;
  }
  
  inline Matrix& Matrix::operator= (const XMFLOAT4X3& M) noexcept
  {
      _11 = M._11; _12 = M._12; _13 = M._13; _14 = 0.f;
      _21 = M._21; _22 = M._22; _23 = M._23; _24 = 0.f;
      _31 = M._31; _32 = M._32; _33 = M._33; _34 = 0.f;
      _41 = M._41; _42 = M._42; _43 = M._43; _44 = 1.f;
      return *this;
  }
  
  inline Matrix& Matrix::operator+= (const Matrix& M) noexcept
  {
      using namespace DirectX;
      XMVECTOR x1 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&_11));
      XMVECTOR x2 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&_21));
      XMVECTOR x3 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&_31));
      XMVECTOR x4 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&_41));
  
      XMVECTOR y1 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&M._11));
      XMVECTOR y2 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&M._21));
      XMVECTOR y3 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&M._31));
      XMVECTOR y4 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&M._41));
  
      x1 = XMVectorAdd(x1, y1);
      x2 = XMVectorAdd(x2, y2);
      x3 = XMVectorAdd(x3, y3);
      x4 = XMVectorAdd(x4, y4);
  
      XMStoreFloat4(reinterpret_cast<XMFLOAT4*>(&_11), x1);
      XMStoreFloat4(reinterpret_cast<XMFLOAT4*>(&_21), x2);
      XMStoreFloat4(reinterpret_cast<XMFLOAT4*>(&_31), x3);
      XMStoreFloat4(reinterpret_cast<XMFLOAT4*>(&_41), x4);
      return *this;
  }
  
  inline Matrix& Matrix::operator-= (const Matrix& M) noexcept
  {
      using namespace DirectX;
      XMVECTOR x1 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&_11));
      XMVECTOR x2 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&_21));
      XMVECTOR x3 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&_31));
      XMVECTOR x4 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&_41));
  
      XMVECTOR y1 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&M._11));
      XMVECTOR y2 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&M._21));
      XMVECTOR y3 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&M._31));
      XMVECTOR y4 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&M._41));
  
      x1 = XMVectorSubtract(x1, y1);
      x2 = XMVectorSubtract(x2, y2);
      x3 = XMVectorSubtract(x3, y3);
      x4 = XMVectorSubtract(x4, y4);
  
      XMStoreFloat4(reinterpret_cast<XMFLOAT4*>(&_11), x1);
      XMStoreFloat4(reinterpret_cast<XMFLOAT4*>(&_21), x2);
      XMStoreFloat4(reinterpret_cast<XMFLOAT4*>(&_31), x3);
      XMStoreFloat4(reinterpret_cast<XMFLOAT4*>(&_41), x4);
      return *this;
  }
  
  inline Matrix& Matrix::operator*= (const Matrix& M) noexcept
  {
      using namespace DirectX;
      XMMATRIX M1 = XMLoadFloat4x4(this);
      XMMATRIX M2 = XMLoadFloat4x4(&M);
      XMMATRIX X = XMMatrixMultiply(M1, M2);
      XMStoreFloat4x4(this, X);
      return *this;
  }
  
  inline Matrix& Matrix::operator*= (float S) noexcept
  {
      using namespace DirectX;
      XMVECTOR x1 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&_11));
      XMVECTOR x2 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&_21));
      XMVECTOR x3 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&_31));
      XMVECTOR x4 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&_41));
  
      x1 = XMVectorScale(x1, S);
      x2 = XMVectorScale(x2, S);
      x3 = XMVectorScale(x3, S);
      x4 = XMVectorScale(x4, S);
  
      XMStoreFloat4(reinterpret_cast<XMFLOAT4*>(&_11), x1);
      XMStoreFloat4(reinterpret_cast<XMFLOAT4*>(&_21), x2);
      XMStoreFloat4(reinterpret_cast<XMFLOAT4*>(&_31), x3);
      XMStoreFloat4(reinterpret_cast<XMFLOAT4*>(&_41), x4);
      return *this;
  }
  
  inline Matrix& Matrix::operator/= (float S) noexcept
  {
      using namespace DirectX;
      assert(S != 0.f);
      XMVECTOR x1 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&_11));
      XMVECTOR x2 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&_21));
      XMVECTOR x3 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&_31));
      XMVECTOR x4 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&_41));
  
      float rs = 1.f / S;
  
      x1 = XMVectorScale(x1, rs);
      x2 = XMVectorScale(x2, rs);
      x3 = XMVectorScale(x3, rs);
      x4 = XMVectorScale(x4, rs);
  
      XMStoreFloat4(reinterpret_cast<XMFLOAT4*>(&_11), x1);
      XMStoreFloat4(reinterpret_cast<XMFLOAT4*>(&_21), x2);
      XMStoreFloat4(reinterpret_cast<XMFLOAT4*>(&_31), x3);
      XMStoreFloat4(reinterpret_cast<XMFLOAT4*>(&_41), x4);
      return *this;
  }
  
  inline Matrix& Matrix::operator/= (const Matrix& M) noexcept
  {
      using namespace DirectX;
      XMVECTOR x1 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&_11));
      XMVECTOR x2 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&_21));
      XMVECTOR x3 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&_31));
      XMVECTOR x4 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&_41));
  
      XMVECTOR y1 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&M._11));
      XMVECTOR y2 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&M._21));
      XMVECTOR y3 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&M._31));
      XMVECTOR y4 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&M._41));
  
      x1 = XMVectorDivide(x1, y1);
      x2 = XMVectorDivide(x2, y2);
      x3 = XMVectorDivide(x3, y3);
      x4 = XMVectorDivide(x4, y4);
  
      XMStoreFloat4(reinterpret_cast<XMFLOAT4*>(&_11), x1);
      XMStoreFloat4(reinterpret_cast<XMFLOAT4*>(&_21), x2);
      XMStoreFloat4(reinterpret_cast<XMFLOAT4*>(&_31), x3);
      XMStoreFloat4(reinterpret_cast<XMFLOAT4*>(&_41), x4);
      return *this;
  }
  
  //------------------------------------------------------------------------------
  // Urnary operators
  //------------------------------------------------------------------------------
  
  inline Matrix Matrix::operator- () const noexcept
  {
      using namespace DirectX;
      XMVECTOR v1 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&_11));
      XMVECTOR v2 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&_21));
      XMVECTOR v3 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&_31));
      XMVECTOR v4 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&_41));
  
      v1 = XMVectorNegate(v1);
      v2 = XMVectorNegate(v2);
      v3 = XMVectorNegate(v3);
      v4 = XMVectorNegate(v4);
  
      Matrix R;
      XMStoreFloat4(reinterpret_cast<XMFLOAT4*>(&R._11), v1);
      XMStoreFloat4(reinterpret_cast<XMFLOAT4*>(&R._21), v2);
      XMStoreFloat4(reinterpret_cast<XMFLOAT4*>(&R._31), v3);
      XMStoreFloat4(reinterpret_cast<XMFLOAT4*>(&R._41), v4);
      return R;
  }
  
  //------------------------------------------------------------------------------
  // Binary operators
  //------------------------------------------------------------------------------
  
  inline Matrix operator+ (const Matrix& M1, const Matrix& M2) noexcept
  {
      using namespace DirectX;
      XMVECTOR x1 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&M1._11));
      XMVECTOR x2 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&M1._21));
      XMVECTOR x3 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&M1._31));
      XMVECTOR x4 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&M1._41));
  
      XMVECTOR y1 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&M2._11));
      XMVECTOR y2 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&M2._21));
      XMVECTOR y3 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&M2._31));
      XMVECTOR y4 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&M2._41));
  
      x1 = XMVectorAdd(x1, y1);
      x2 = XMVectorAdd(x2, y2);
      x3 = XMVectorAdd(x3, y3);
      x4 = XMVectorAdd(x4, y4);
  
      Matrix R;
      XMStoreFloat4(reinterpret_cast<XMFLOAT4*>(&R._11), x1);
      XMStoreFloat4(reinterpret_cast<XMFLOAT4*>(&R._21), x2);
      XMStoreFloat4(reinterpret_cast<XMFLOAT4*>(&R._31), x3);
      XMStoreFloat4(reinterpret_cast<XMFLOAT4*>(&R._41), x4);
      return R;
  }
  
  inline Matrix operator- (const Matrix& M1, const Matrix& M2) noexcept
  {
      using namespace DirectX;
      XMVECTOR x1 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&M1._11));
      XMVECTOR x2 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&M1._21));
      XMVECTOR x3 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&M1._31));
      XMVECTOR x4 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&M1._41));
  
      XMVECTOR y1 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&M2._11));
      XMVECTOR y2 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&M2._21));
      XMVECTOR y3 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&M2._31));
      XMVECTOR y4 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&M2._41));
  
      x1 = XMVectorSubtract(x1, y1);
      x2 = XMVectorSubtract(x2, y2);
      x3 = XMVectorSubtract(x3, y3);
      x4 = XMVectorSubtract(x4, y4);
  
      Matrix R;
      XMStoreFloat4(reinterpret_cast<XMFLOAT4*>(&R._11), x1);
      XMStoreFloat4(reinterpret_cast<XMFLOAT4*>(&R._21), x2);
      XMStoreFloat4(reinterpret_cast<XMFLOAT4*>(&R._31), x3);
      XMStoreFloat4(reinterpret_cast<XMFLOAT4*>(&R._41), x4);
      return R;
  }
  
  inline Matrix operator* (const Matrix& M1, const Matrix& M2) noexcept
  {
      using namespace DirectX;
      XMMATRIX m1 = XMLoadFloat4x4(&M1);
      XMMATRIX m2 = XMLoadFloat4x4(&M2);
      XMMATRIX X = XMMatrixMultiply(m1, m2);
  
      Matrix R;
      XMStoreFloat4x4(&R, X);
      return R;
  }
  
  inline Matrix operator* (const Matrix& M, float S) noexcept
  {
      using namespace DirectX;
      XMVECTOR x1 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&M._11));
      XMVECTOR x2 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&M._21));
      XMVECTOR x3 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&M._31));
      XMVECTOR x4 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&M._41));
  
      x1 = XMVectorScale(x1, S);
      x2 = XMVectorScale(x2, S);
      x3 = XMVectorScale(x3, S);
      x4 = XMVectorScale(x4, S);
  
      Matrix R;
      XMStoreFloat4(reinterpret_cast<XMFLOAT4*>(&R._11), x1);
      XMStoreFloat4(reinterpret_cast<XMFLOAT4*>(&R._21), x2);
      XMStoreFloat4(reinterpret_cast<XMFLOAT4*>(&R._31), x3);
      XMStoreFloat4(reinterpret_cast<XMFLOAT4*>(&R._41), x4);
      return R;
  }
  
  inline Matrix operator/ (const Matrix& M, float S) noexcept
  {
      using namespace DirectX;
      assert(S != 0.f);
  
      XMVECTOR x1 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&M._11));
      XMVECTOR x2 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&M._21));
      XMVECTOR x3 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&M._31));
      XMVECTOR x4 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&M._41));
  
      float rs = 1.f / S;
  
      x1 = XMVectorScale(x1, rs);
      x2 = XMVectorScale(x2, rs);
      x3 = XMVectorScale(x3, rs);
      x4 = XMVectorScale(x4, rs);
  
      Matrix R;
      XMStoreFloat4(reinterpret_cast<XMFLOAT4*>(&R._11), x1);
      XMStoreFloat4(reinterpret_cast<XMFLOAT4*>(&R._21), x2);
      XMStoreFloat4(reinterpret_cast<XMFLOAT4*>(&R._31), x3);
      XMStoreFloat4(reinterpret_cast<XMFLOAT4*>(&R._41), x4);
      return R;
  }
  
  inline Matrix operator/ (const Matrix& M1, const Matrix& M2) noexcept
  {
      using namespace DirectX;
      XMVECTOR x1 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&M1._11));
      XMVECTOR x2 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&M1._21));
      XMVECTOR x3 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&M1._31));
      XMVECTOR x4 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&M1._41));
  
      XMVECTOR y1 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&M2._11));
      XMVECTOR y2 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&M2._21));
      XMVECTOR y3 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&M2._31));
      XMVECTOR y4 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&M2._41));
  
      x1 = XMVectorDivide(x1, y1);
      x2 = XMVectorDivide(x2, y2);
      x3 = XMVectorDivide(x3, y3);
      x4 = XMVectorDivide(x4, y4);
  
      Matrix R;
      XMStoreFloat4(reinterpret_cast<XMFLOAT4*>(&R._11), x1);
      XMStoreFloat4(reinterpret_cast<XMFLOAT4*>(&R._21), x2);
      XMStoreFloat4(reinterpret_cast<XMFLOAT4*>(&R._31), x3);
      XMStoreFloat4(reinterpret_cast<XMFLOAT4*>(&R._41), x4);
      return R;
  }
  
  inline Matrix operator* (float S, const Matrix& M) noexcept
  {
      using namespace DirectX;
  
      XMVECTOR x1 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&M._11));
      XMVECTOR x2 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&M._21));
      XMVECTOR x3 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&M._31));
      XMVECTOR x4 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&M._41));
  
      x1 = XMVectorScale(x1, S);
      x2 = XMVectorScale(x2, S);
      x3 = XMVectorScale(x3, S);
      x4 = XMVectorScale(x4, S);
  
      Matrix R;
      XMStoreFloat4(reinterpret_cast<XMFLOAT4*>(&R._11), x1);
      XMStoreFloat4(reinterpret_cast<XMFLOAT4*>(&R._21), x2);
      XMStoreFloat4(reinterpret_cast<XMFLOAT4*>(&R._31), x3);
      XMStoreFloat4(reinterpret_cast<XMFLOAT4*>(&R._41), x4);
      return R;
  }
  
  //------------------------------------------------------------------------------
  // Matrix operations
  //------------------------------------------------------------------------------
  
  inline bool Matrix::Decompose(Vector3& scale, Quaternion& rotation, Vector3& translation) noexcept
  {
      using namespace DirectX;
  
      XMVECTOR s, r, t;
  
      if (!XMMatrixDecompose(&s, &r, &t, *this))
          return false;
  
      XMStoreFloat3(&scale, s);
      XMStoreFloat4(&rotation, r);
      XMStoreFloat3(&translation, t);
  
      return true;
  }
  
  inline Matrix Matrix::Transpose() const noexcept
  {
      using namespace DirectX;
      XMMATRIX M = XMLoadFloat4x4(this);
      Matrix R;
      XMStoreFloat4x4(&R, XMMatrixTranspose(M));
      return R;
  }
  
  inline void Matrix::Transpose(Matrix& result) const noexcept
  {
      using namespace DirectX;
      XMMATRIX M = XMLoadFloat4x4(this);
      XMStoreFloat4x4(&result, XMMatrixTranspose(M));
  }
  
  inline Matrix Matrix::Invert() const noexcept
  {
      using namespace DirectX;
      XMMATRIX M = XMLoadFloat4x4(this);
      Matrix R;
      XMVECTOR det;
      XMStoreFloat4x4(&R, XMMatrixInverse(&det, M));
      return R;
  }
  
  inline void Matrix::Invert(Matrix& result) const noexcept
  {
      using namespace DirectX;
      XMMATRIX M = XMLoadFloat4x4(this);
      XMVECTOR det;
      XMStoreFloat4x4(&result, XMMatrixInverse(&det, M));
  }
  
  inline float Matrix::Determinant() const noexcept
  {
      using namespace DirectX;
      XMMATRIX M = XMLoadFloat4x4(this);
      return XMVectorGetX(XMMatrixDeterminant(M));
  }
  
  //------------------------------------------------------------------------------
  // Static functions
  //------------------------------------------------------------------------------
  
  _Use_decl_annotations_
  inline Matrix Matrix::CreateBillboard(
      const Vector3& object,
      const Vector3& cameraPosition,
      const Vector3& cameraUp,
      const Vector3* cameraForward) noexcept
  {
      using namespace DirectX;
      XMVECTOR O = XMLoadFloat3(&object);
      XMVECTOR C = XMLoadFloat3(&cameraPosition);
      XMVECTOR Z = XMVectorSubtract(O, C);
  
      XMVECTOR N = XMVector3LengthSq(Z);
      if (XMVector3Less(N, g_XMEpsilon))
      {
          if (cameraForward)
          {
              XMVECTOR F = XMLoadFloat3(cameraForward);
              Z = XMVectorNegate(F);
          }
          else
              Z = g_XMNegIdentityR2;
      }
      else
      {
          Z = XMVector3Normalize(Z);
      }
  
      XMVECTOR up = XMLoadFloat3(&cameraUp);
      XMVECTOR X = XMVector3Cross(up, Z);
      X = XMVector3Normalize(X);
  
      XMVECTOR Y = XMVector3Cross(Z, X);
  
      XMMATRIX M;
      M.r[0] = X;
      M.r[1] = Y;
      M.r[2] = Z;
      M.r[3] = XMVectorSetW(O, 1.f);
  
      Matrix R;
      XMStoreFloat4x4(&R, M);
      return R;
  }
  
  _Use_decl_annotations_
  inline Matrix Matrix::CreateConstrainedBillboard(
      const Vector3& object,
      const Vector3& cameraPosition,
      const Vector3& rotateAxis,
      const Vector3* cameraForward,
      const Vector3* objectForward) noexcept
  {
      using namespace DirectX;
  
      static const XMVECTORF32 s_minAngle = { { { 0.99825467075f, 0.99825467075f, 0.99825467075f, 0.99825467075f } } }; // 1.0 - XMConvertToRadians( 0.1f );
  
      XMVECTOR O = XMLoadFloat3(&object);
      XMVECTOR C = XMLoadFloat3(&cameraPosition);
      XMVECTOR faceDir = XMVectorSubtract(O, C);
  
      XMVECTOR N = XMVector3LengthSq(faceDir);
      if (XMVector3Less(N, g_XMEpsilon))
      {
          if (cameraForward)
          {
              XMVECTOR F = XMLoadFloat3(cameraForward);
              faceDir = XMVectorNegate(F);
          }
          else
              faceDir = g_XMNegIdentityR2;
      }
      else
      {
          faceDir = XMVector3Normalize(faceDir);
      }
  
      XMVECTOR Y = XMLoadFloat3(&rotateAxis);
      XMVECTOR X, Z;
  
      XMVECTOR dot = XMVectorAbs(XMVector3Dot(Y, faceDir));
      if (XMVector3Greater(dot, s_minAngle))
      {
          if (objectForward)
          {
              Z = XMLoadFloat3(objectForward);
              dot = XMVectorAbs(XMVector3Dot(Y, Z));
              if (XMVector3Greater(dot, s_minAngle))
              {
                  dot = XMVectorAbs(XMVector3Dot(Y, g_XMNegIdentityR2));
                  Z = (XMVector3Greater(dot, s_minAngle)) ? g_XMIdentityR0 : g_XMNegIdentityR2;
              }
          }
          else
          {
              dot = XMVectorAbs(XMVector3Dot(Y, g_XMNegIdentityR2));
              Z = (XMVector3Greater(dot, s_minAngle)) ? g_XMIdentityR0 : g_XMNegIdentityR2;
          }
  
          X = XMVector3Cross(Y, Z);
          X = XMVector3Normalize(X);
  
          Z = XMVector3Cross(X, Y);
          Z = XMVector3Normalize(Z);
      }
      else
      {
          X = XMVector3Cross(Y, faceDir);
          X = XMVector3Normalize(X);
  
          Z = XMVector3Cross(X, Y);
          Z = XMVector3Normalize(Z);
      }
  
      XMMATRIX M;
      M.r[0] = X;
      M.r[1] = Y;
      M.r[2] = Z;
      M.r[3] = XMVectorSetW(O, 1.f);
  
      Matrix R;
      XMStoreFloat4x4(&R, M);
      return R;
  }
  
  inline Matrix Matrix::CreateTranslation(const Vector3& position) noexcept
  {
      using namespace DirectX;
      Matrix R;
      XMStoreFloat4x4(&R, XMMatrixTranslation(position.x, position.y, position.z));
      return R;
  }
  
  inline Matrix Matrix::CreateTranslation(float x, float y, float z) noexcept
  {
      using namespace DirectX;
      Matrix R;
      XMStoreFloat4x4(&R, XMMatrixTranslation(x, y, z));
      return R;
  }
  
  inline Matrix Matrix::CreateScale(const Vector3& scales) noexcept
  {
      using namespace DirectX;
      Matrix R;
      XMStoreFloat4x4(&R, XMMatrixScaling(scales.x, scales.y, scales.z));
      return R;
  }
  
  inline Matrix Matrix::CreateScale(float xs, float ys, float zs) noexcept
  {
      using namespace DirectX;
      Matrix R;
      XMStoreFloat4x4(&R, XMMatrixScaling(xs, ys, zs));
      return R;
  }
  
  inline Matrix Matrix::CreateScale(float scale) noexcept
  {
      using namespace DirectX;
      Matrix R;
      XMStoreFloat4x4(&R, XMMatrixScaling(scale, scale, scale));
      return R;
  }
  
  inline Matrix Matrix::CreateRotationX(float radians) noexcept
  {
      using namespace DirectX;
      Matrix R;
      XMStoreFloat4x4(&R, XMMatrixRotationX(radians));
      return R;
  }
  
  inline Matrix Matrix::CreateRotationY(float radians) noexcept
  {
      using namespace DirectX;
      Matrix R;
      XMStoreFloat4x4(&R, XMMatrixRotationY(radians));
      return R;
  }
  
  inline Matrix Matrix::CreateRotationZ(float radians) noexcept
  {
      using namespace DirectX;
      Matrix R;
      XMStoreFloat4x4(&R, XMMatrixRotationZ(radians));
      return R;
  }
  
  inline Matrix Matrix::CreateFromAxisAngle(const Vector3& axis, float angle) noexcept
  {
      using namespace DirectX;
      Matrix R;
      XMVECTOR a = XMLoadFloat3(&axis);
      XMStoreFloat4x4(&R, XMMatrixRotationAxis(a, angle));
      return R;
  }
  
  inline Matrix Matrix::CreatePerspectiveFieldOfView(float fov, float aspectRatio, float nearPlane, float farPlane) noexcept
  {
      using namespace DirectX;
      Matrix R;
      XMStoreFloat4x4(&R, XMMatrixPerspectiveFovRH(fov, aspectRatio, nearPlane, farPlane));
      return R;
  }
  
  inline Matrix Matrix::CreatePerspective(float width, float height, float nearPlane, float farPlane) noexcept
  {
      using namespace DirectX;
      Matrix R;
      XMStoreFloat4x4(&R, XMMatrixPerspectiveRH(width, height, nearPlane, farPlane));
      return R;
  }
  
  inline Matrix Matrix::CreatePerspectiveOffCenter(float left, float right, float bottom, float top, float nearPlane, float farPlane) noexcept
  {
      using namespace DirectX;
      Matrix R;
      XMStoreFloat4x4(&R, XMMatrixPerspectiveOffCenterRH(left, right, bottom, top, nearPlane, farPlane));
      return R;
  }
  
  inline Matrix Matrix::CreateOrthographic(float width, float height, float zNearPlane, float zFarPlane) noexcept
  {
      using namespace DirectX;
      Matrix R;
      XMStoreFloat4x4(&R, XMMatrixOrthographicRH(width, height, zNearPlane, zFarPlane));
      return R;
  }
  
  inline Matrix Matrix::CreateOrthographicOffCenter(float left, float right, float bottom, float top, float zNearPlane, float zFarPlane) noexcept
  {
      using namespace DirectX;
      Matrix R;
      XMStoreFloat4x4(&R, XMMatrixOrthographicOffCenterRH(left, right, bottom, top, zNearPlane, zFarPlane));
      return R;
  }
  
  inline Matrix Matrix::CreateLookAt(const Vector3& eye, const Vector3& target, const Vector3& up) noexcept
  {
      using namespace DirectX;
      Matrix R;
      XMVECTOR eyev = XMLoadFloat3(&eye);
      XMVECTOR targetv = XMLoadFloat3(&target);
      XMVECTOR upv = XMLoadFloat3(&up);
      XMStoreFloat4x4(&R, XMMatrixLookAtRH(eyev, targetv, upv));
      return R;
  }
  
  inline Matrix Matrix::CreateWorld(const Vector3& position, const Vector3& forward, const Vector3& up) noexcept
  {
      using namespace DirectX;
      XMVECTOR zaxis = XMVector3Normalize(XMVectorNegate(XMLoadFloat3(&forward)));
      XMVECTOR yaxis = XMLoadFloat3(&up);
      XMVECTOR xaxis = XMVector3Normalize(XMVector3Cross(yaxis, zaxis));
      yaxis = XMVector3Cross(zaxis, xaxis);
  
      Matrix R;
      XMStoreFloat3(reinterpret_cast<XMFLOAT3*>(&R._11), xaxis);
      XMStoreFloat3(reinterpret_cast<XMFLOAT3*>(&R._21), yaxis);
      XMStoreFloat3(reinterpret_cast<XMFLOAT3*>(&R._31), zaxis);
      R._14 = R._24 = R._34 = 0.f;
      R._41 = position.x; R._42 = position.y; R._43 = position.z;
      R._44 = 1.f;
      return R;
  }
  
  inline Matrix Matrix::CreateFromQuaternion(const Quaternion& rotation) noexcept
  {
      using namespace DirectX;
      Matrix R;
      XMVECTOR quatv = XMLoadFloat4(&rotation);
      XMStoreFloat4x4(&R, XMMatrixRotationQuaternion(quatv));
      return R;
  }
  
  inline Matrix Matrix::CreateFromYawPitchRoll(float yaw, float pitch, float roll) noexcept
  {
      using namespace DirectX;
      Matrix R;
      XMStoreFloat4x4(&R, XMMatrixRotationRollPitchYaw(pitch, yaw, roll));
      return R;
  }
  
  inline Matrix Matrix::CreateShadow(const Vector3& lightDir, const Plane& plane) noexcept
  {
      using namespace DirectX;
      Matrix R;
      XMVECTOR light = XMLoadFloat3(&lightDir);
      XMVECTOR planev = XMLoadFloat4(&plane);
      XMStoreFloat4x4(&R, XMMatrixShadow(planev, light));
      return R;
  }
  
  inline Matrix Matrix::CreateReflection(const Plane& plane) noexcept
  {
      using namespace DirectX;
      Matrix R;
      XMVECTOR planev = XMLoadFloat4(&plane);
      XMStoreFloat4x4(&R, XMMatrixReflect(planev));
      return R;
  }
  
  inline void Matrix::Lerp(const Matrix& M1, const Matrix& M2, float t, Matrix& result) noexcept
  {
      using namespace DirectX;
      XMVECTOR x1 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&M1._11));
      XMVECTOR x2 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&M1._21));
      XMVECTOR x3 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&M1._31));
      XMVECTOR x4 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&M1._41));
  
      XMVECTOR y1 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&M2._11));
      XMVECTOR y2 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&M2._21));
      XMVECTOR y3 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&M2._31));
      XMVECTOR y4 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&M2._41));
  
      x1 = XMVectorLerp(x1, y1, t);
      x2 = XMVectorLerp(x2, y2, t);
      x3 = XMVectorLerp(x3, y3, t);
      x4 = XMVectorLerp(x4, y4, t);
  
      XMStoreFloat4(reinterpret_cast<XMFLOAT4*>(&result._11), x1);
      XMStoreFloat4(reinterpret_cast<XMFLOAT4*>(&result._21), x2);
      XMStoreFloat4(reinterpret_cast<XMFLOAT4*>(&result._31), x3);
      XMStoreFloat4(reinterpret_cast<XMFLOAT4*>(&result._41), x4);
  }
  
  inline Matrix Matrix::Lerp(const Matrix& M1, const Matrix& M2, float t) noexcept
  {
      using namespace DirectX;
      XMVECTOR x1 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&M1._11));
      XMVECTOR x2 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&M1._21));
      XMVECTOR x3 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&M1._31));
      XMVECTOR x4 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&M1._41));
  
      XMVECTOR y1 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&M2._11));
      XMVECTOR y2 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&M2._21));
      XMVECTOR y3 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&M2._31));
      XMVECTOR y4 = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&M2._41));
  
      x1 = XMVectorLerp(x1, y1, t);
      x2 = XMVectorLerp(x2, y2, t);
      x3 = XMVectorLerp(x3, y3, t);
      x4 = XMVectorLerp(x4, y4, t);
  
      Matrix result;
      XMStoreFloat4(reinterpret_cast<XMFLOAT4*>(&result._11), x1);
      XMStoreFloat4(reinterpret_cast<XMFLOAT4*>(&result._21), x2);
      XMStoreFloat4(reinterpret_cast<XMFLOAT4*>(&result._31), x3);
      XMStoreFloat4(reinterpret_cast<XMFLOAT4*>(&result._41), x4);
      return result;
  }
  
  inline void Matrix::Transform(const Matrix& M, const Quaternion& rotation, Matrix& result) noexcept
  {
      using namespace DirectX;
      XMVECTOR quatv = XMLoadFloat4(&rotation);
  
      XMMATRIX M0 = XMLoadFloat4x4(&M);
      XMMATRIX M1 = XMMatrixRotationQuaternion(quatv);
  
      XMStoreFloat4x4(&result, XMMatrixMultiply(M0, M1));
  }
  
  inline Matrix Matrix::Transform(const Matrix& M, const Quaternion& rotation) noexcept
  {
      using namespace DirectX;
      XMVECTOR quatv = XMLoadFloat4(&rotation);
  
      XMMATRIX M0 = XMLoadFloat4x4(&M);
      XMMATRIX M1 = XMMatrixRotationQuaternion(quatv);
  
      Matrix result;
      XMStoreFloat4x4(&result, XMMatrixMultiply(M0, M1));
      return result;
  }
  
  
  /****************************************************************************
   *
   * Plane
   *
   ****************************************************************************/
  
  inline Plane::Plane(const Vector3& point1, const Vector3& point2, const Vector3& point3) noexcept
  {
      using namespace DirectX;
      XMVECTOR P0 = XMLoadFloat3(&point1);
      XMVECTOR P1 = XMLoadFloat3(&point2);
      XMVECTOR P2 = XMLoadFloat3(&point3);
      XMStoreFloat4(this, XMPlaneFromPoints(P0, P1, P2));
  }
  
  inline Plane::Plane(const Vector3& point, const Vector3& normal) noexcept
  {
      using namespace DirectX;
      XMVECTOR P = XMLoadFloat3(&point);
      XMVECTOR N = XMLoadFloat3(&normal);
      XMStoreFloat4(this, XMPlaneFromPointNormal(P, N));
  }
  
  //------------------------------------------------------------------------------
  // Comparision operators
  //------------------------------------------------------------------------------
  
  inline bool Plane::operator == (const Plane& p) const noexcept
  {
      using namespace DirectX;
      XMVECTOR p1 = XMLoadFloat4(this);
      XMVECTOR p2 = XMLoadFloat4(&p);
      return XMPlaneEqual(p1, p2);
  }
  
  inline bool Plane::operator != (const Plane& p) const noexcept
  {
      using namespace DirectX;
      XMVECTOR p1 = XMLoadFloat4(this);
      XMVECTOR p2 = XMLoadFloat4(&p);
      return XMPlaneNotEqual(p1, p2);
  }
  
  //------------------------------------------------------------------------------
  // Plane operations
  //------------------------------------------------------------------------------
  
  inline void Plane::Normalize() noexcept
  {
      using namespace DirectX;
      XMVECTOR p = XMLoadFloat4(this);
      XMStoreFloat4(this, XMPlaneNormalize(p));
  }
  
  inline void Plane::Normalize(Plane& result) const noexcept
  {
      using namespace DirectX;
      XMVECTOR p = XMLoadFloat4(this);
      XMStoreFloat4(&result, XMPlaneNormalize(p));
  }
  
  inline float Plane::Dot(const Vector4& v) const noexcept
  {
      using namespace DirectX;
      XMVECTOR p = XMLoadFloat4(this);
      XMVECTOR v0 = XMLoadFloat4(&v);
      return XMVectorGetX(XMPlaneDot(p, v0));
  }
  
  inline float Plane::DotCoordinate(const Vector3& position) const noexcept
  {
      using namespace DirectX;
      XMVECTOR p = XMLoadFloat4(this);
      XMVECTOR v0 = XMLoadFloat3(&position);
      return XMVectorGetX(XMPlaneDotCoord(p, v0));
  }
  
  inline float Plane::DotNormal(const Vector3& normal) const noexcept
  {
      using namespace DirectX;
      XMVECTOR p = XMLoadFloat4(this);
      XMVECTOR n0 = XMLoadFloat3(&normal);
      return XMVectorGetX(XMPlaneDotNormal(p, n0));
  }
  
  //------------------------------------------------------------------------------
  // Static functions
  //------------------------------------------------------------------------------
  
  inline void Plane::Transform(const Plane& plane, const Matrix& M, Plane& result) noexcept
  {
      using namespace DirectX;
      XMVECTOR p = XMLoadFloat4(&plane);
      XMMATRIX m0 = XMLoadFloat4x4(&M);
      XMStoreFloat4(&result, XMPlaneTransform(p, m0));
  }
  
  inline Plane Plane::Transform(const Plane& plane, const Matrix& M) noexcept
  {
      using namespace DirectX;
      XMVECTOR p = XMLoadFloat4(&plane);
      XMMATRIX m0 = XMLoadFloat4x4(&M);
  
      Plane result;
      XMStoreFloat4(&result, XMPlaneTransform(p, m0));
      return result;
  }
  
  inline void Plane::Transform(const Plane& plane, const Quaternion& rotation, Plane& result) noexcept
  {
      using namespace DirectX;
      XMVECTOR p = XMLoadFloat4(&plane);
      XMVECTOR q = XMLoadFloat4(&rotation);
      XMVECTOR X = XMVector3Rotate(p, q);
      X = XMVectorSelect(p, X, g_XMSelect1110); // result.d = plane.d
      XMStoreFloat4(&result, X);
  }
  
  inline Plane Plane::Transform(const Plane& plane, const Quaternion& rotation) noexcept
  {
      using namespace DirectX;
      XMVECTOR p = XMLoadFloat4(&plane);
      XMVECTOR q = XMLoadFloat4(&rotation);
      XMVECTOR X = XMVector3Rotate(p, q);
      X = XMVectorSelect(p, X, g_XMSelect1110); // result.d = plane.d
  
      Plane result;
      XMStoreFloat4(&result, X);
      return result;
  }
  
  
  /****************************************************************************
   *
   * Quaternion
   *
   ****************************************************************************/
  
  //------------------------------------------------------------------------------
  // Comparision operators
  //------------------------------------------------------------------------------
  
  inline bool Quaternion::operator == (const Quaternion& q) const noexcept
  {
      using namespace DirectX;
      XMVECTOR q1 = XMLoadFloat4(this);
      XMVECTOR q2 = XMLoadFloat4(&q);
      return XMQuaternionEqual(q1, q2);
  }
  
  inline bool Quaternion::operator != (const Quaternion& q) const noexcept
  {
      using namespace DirectX;
      XMVECTOR q1 = XMLoadFloat4(this);
      XMVECTOR q2 = XMLoadFloat4(&q);
      return XMQuaternionNotEqual(q1, q2);
  }
  
  //------------------------------------------------------------------------------
  // Assignment operators
  //------------------------------------------------------------------------------
  
  inline Quaternion& Quaternion::operator+= (const Quaternion& q) noexcept
  {
      using namespace DirectX;
      XMVECTOR q1 = XMLoadFloat4(this);
      XMVECTOR q2 = XMLoadFloat4(&q);
      XMStoreFloat4(this, XMVectorAdd(q1, q2));
      return *this;
  }
  
  inline Quaternion& Quaternion::operator-= (const Quaternion& q) noexcept
  {
      using namespace DirectX;
      XMVECTOR q1 = XMLoadFloat4(this);
      XMVECTOR q2 = XMLoadFloat4(&q);
      XMStoreFloat4(this, XMVectorSubtract(q1, q2));
      return *this;
  }
  
  inline Quaternion& Quaternion::operator*= (const Quaternion& q) noexcept
  {
      using namespace DirectX;
      XMVECTOR q1 = XMLoadFloat4(this);
      XMVECTOR q2 = XMLoadFloat4(&q);
      XMStoreFloat4(this, XMQuaternionMultiply(q1, q2));
      return *this;
  }
  
  inline Quaternion& Quaternion::operator*= (float S) noexcept
  {
      using namespace DirectX;
      XMVECTOR q = XMLoadFloat4(this);
      XMStoreFloat4(this, XMVectorScale(q, S));
      return *this;
  }
  
  inline Quaternion& Quaternion::operator/= (const Quaternion& q) noexcept
  {
      using namespace DirectX;
      XMVECTOR q1 = XMLoadFloat4(this);
      XMVECTOR q2 = XMLoadFloat4(&q);
      q2 = XMQuaternionInverse(q2);
      XMStoreFloat4(this, XMQuaternionMultiply(q1, q2));
      return *this;
  }
  
  //------------------------------------------------------------------------------
  // Urnary operators
  //------------------------------------------------------------------------------
  
  inline Quaternion Quaternion::operator- () const noexcept
  {
      using namespace DirectX;
      XMVECTOR q = XMLoadFloat4(this);
  
      Quaternion R;
      XMStoreFloat4(&R, XMVectorNegate(q));
      return R;
  }
  
  //------------------------------------------------------------------------------
  // Binary operators
  //------------------------------------------------------------------------------
  
  inline Quaternion operator+ (const Quaternion& Q1, const Quaternion& Q2) noexcept
  {
      using namespace DirectX;
      XMVECTOR q1 = XMLoadFloat4(&Q1);
      XMVECTOR q2 = XMLoadFloat4(&Q2);
  
      Quaternion R;
      XMStoreFloat4(&R, XMVectorAdd(q1, q2));
      return R;
  }
  
  inline Quaternion operator- (const Quaternion& Q1, const Quaternion& Q2) noexcept
  {
      using namespace DirectX;
      XMVECTOR q1 = XMLoadFloat4(&Q1);
      XMVECTOR q2 = XMLoadFloat4(&Q2);
  
      Quaternion R;
      XMStoreFloat4(&R, XMVectorSubtract(q1, q2));
      return R;
  }
  
  inline Quaternion operator* (const Quaternion& Q1, const Quaternion& Q2) noexcept
  {
      using namespace DirectX;
      XMVECTOR q1 = XMLoadFloat4(&Q1);
      XMVECTOR q2 = XMLoadFloat4(&Q2);
  
      Quaternion R;
      XMStoreFloat4(&R, XMQuaternionMultiply(q1, q2));
      return R;
  }
  
  inline Quaternion operator* (const Quaternion& Q, float S) noexcept
  {
      using namespace DirectX;
      XMVECTOR q = XMLoadFloat4(&Q);
  
      Quaternion R;
      XMStoreFloat4(&R, XMVectorScale(q, S));
      return R;
  }
  
  inline Quaternion operator/ (const Quaternion& Q1, const Quaternion& Q2) noexcept
  {
      using namespace DirectX;
      XMVECTOR q1 = XMLoadFloat4(&Q1);
      XMVECTOR q2 = XMLoadFloat4(&Q2);
      q2 = XMQuaternionInverse(q2);
  
      Quaternion R;
      XMStoreFloat4(&R, XMQuaternionMultiply(q1, q2));
      return R;
  }
  
  inline Quaternion operator* (float S, const Quaternion& Q) noexcept
  {
      using namespace DirectX;
      XMVECTOR q1 = XMLoadFloat4(&Q);
  
      Quaternion R;
      XMStoreFloat4(&R, XMVectorScale(q1, S));
      return R;
  }
  
  //------------------------------------------------------------------------------
  // Quaternion operations
  //------------------------------------------------------------------------------
  
  inline float Quaternion::Length() const noexcept
  {
      using namespace DirectX;
      XMVECTOR q = XMLoadFloat4(this);
      return XMVectorGetX(XMQuaternionLength(q));
  }
  
  inline float Quaternion::LengthSquared() const noexcept
  {
      using namespace DirectX;
      XMVECTOR q = XMLoadFloat4(this);
      return XMVectorGetX(XMQuaternionLengthSq(q));
  }
  
  inline void Quaternion::Normalize() noexcept
  {
      using namespace DirectX;
      XMVECTOR q = XMLoadFloat4(this);
      XMStoreFloat4(this, XMQuaternionNormalize(q));
  }
  
  inline void Quaternion::Normalize(Quaternion& result) const noexcept
  {
      using namespace DirectX;
      XMVECTOR q = XMLoadFloat4(this);
      XMStoreFloat4(&result, XMQuaternionNormalize(q));
  }
  
  inline void Quaternion::Conjugate() noexcept
  {
      using namespace DirectX;
      XMVECTOR q = XMLoadFloat4(this);
      XMStoreFloat4(this, XMQuaternionConjugate(q));
  }
  
  inline void Quaternion::Conjugate(Quaternion& result) const noexcept
  {
      using namespace DirectX;
      XMVECTOR q = XMLoadFloat4(this);
      XMStoreFloat4(&result, XMQuaternionConjugate(q));
  }
  
  inline void Quaternion::Inverse(Quaternion& result) const noexcept
  {
      using namespace DirectX;
      XMVECTOR q = XMLoadFloat4(this);
      XMStoreFloat4(&result, XMQuaternionInverse(q));
  }
  
  inline float Quaternion::Dot(const Quaternion& q) const noexcept
  {
      using namespace DirectX;
      XMVECTOR q1 = XMLoadFloat4(this);
      XMVECTOR q2 = XMLoadFloat4(&q);
      return XMVectorGetX(XMQuaternionDot(q1, q2));
  }
  
  //------------------------------------------------------------------------------
  // Static functions
  //------------------------------------------------------------------------------
  
  inline Quaternion Quaternion::CreateFromAxisAngle(const Vector3& axis, float angle) noexcept
  {
      using namespace DirectX;
      XMVECTOR a = XMLoadFloat3(&axis);
  
      Quaternion R;
      XMStoreFloat4(&R, XMQuaternionRotationAxis(a, angle));
      return R;
  }
  
  inline Quaternion Quaternion::CreateFromYawPitchRoll(float yaw, float pitch, float roll) noexcept
  {
      using namespace DirectX;
      Quaternion R;
      XMStoreFloat4(&R, XMQuaternionRotationRollPitchYaw(pitch, yaw, roll));
      return R;
  }
  
  inline Quaternion Quaternion::CreateFromRotationMatrix(const Matrix& M) noexcept
  {
      using namespace DirectX;
      XMMATRIX M0 = XMLoadFloat4x4(&M);
  
      Quaternion R;
      XMStoreFloat4(&R, XMQuaternionRotationMatrix(M0));
      return R;
  }
  
  inline void Quaternion::Lerp(const Quaternion& q1, const Quaternion& q2, float t, Quaternion& result) noexcept
  {
      using namespace DirectX;
      XMVECTOR Q0 = XMLoadFloat4(&q1);
      XMVECTOR Q1 = XMLoadFloat4(&q2);
  
      XMVECTOR dot = XMVector4Dot(Q0, Q1);
  
      XMVECTOR R;
      if (XMVector4GreaterOrEqual(dot, XMVectorZero()))
      {
          R = XMVectorLerp(Q0, Q1, t);
      }
      else
      {
          XMVECTOR tv = XMVectorReplicate(t);
          XMVECTOR t1v = XMVectorReplicate(1.f - t);
          XMVECTOR X0 = XMVectorMultiply(Q0, t1v);
          XMVECTOR X1 = XMVectorMultiply(Q1, tv);
          R = XMVectorSubtract(X0, X1);
      }
  
      XMStoreFloat4(&result, XMQuaternionNormalize(R));
  }
  
  inline Quaternion Quaternion::Lerp(const Quaternion& q1, const Quaternion& q2, float t) noexcept
  {
      using namespace DirectX;
      XMVECTOR Q0 = XMLoadFloat4(&q1);
      XMVECTOR Q1 = XMLoadFloat4(&q2);
  
      XMVECTOR dot = XMVector4Dot(Q0, Q1);
  
      XMVECTOR R;
      if (XMVector4GreaterOrEqual(dot, XMVectorZero()))
      {
          R = XMVectorLerp(Q0, Q1, t);
      }
      else
      {
          XMVECTOR tv = XMVectorReplicate(t);
          XMVECTOR t1v = XMVectorReplicate(1.f - t);
          XMVECTOR X0 = XMVectorMultiply(Q0, t1v);
          XMVECTOR X1 = XMVectorMultiply(Q1, tv);
          R = XMVectorSubtract(X0, X1);
      }
  
      Quaternion result;
      XMStoreFloat4(&result, XMQuaternionNormalize(R));
      return result;
  }
  
  inline void Quaternion::Slerp(const Quaternion& q1, const Quaternion& q2, float t, Quaternion& result) noexcept
  {
      using namespace DirectX;
      XMVECTOR Q0 = XMLoadFloat4(&q1);
      XMVECTOR Q1 = XMLoadFloat4(&q2);
      XMStoreFloat4(&result, XMQuaternionSlerp(Q0, Q1, t));
  }
  
  inline Quaternion Quaternion::Slerp(const Quaternion& q1, const Quaternion& q2, float t) noexcept
  {
      using namespace DirectX;
      XMVECTOR Q0 = XMLoadFloat4(&q1);
      XMVECTOR Q1 = XMLoadFloat4(&q2);
  
      Quaternion result;
      XMStoreFloat4(&result, XMQuaternionSlerp(Q0, Q1, t));
      return result;
  }
  
  inline void Quaternion::Concatenate(const Quaternion& q1, const Quaternion& q2, Quaternion& result) noexcept
  {
      using namespace DirectX;
      XMVECTOR Q0 = XMLoadFloat4(&q1);
      XMVECTOR Q1 = XMLoadFloat4(&q2);
      XMStoreFloat4(&result, XMQuaternionMultiply(Q1, Q0));
  }
  
  inline Quaternion Quaternion::Concatenate(const Quaternion& q1, const Quaternion& q2) noexcept
  {
      using namespace DirectX;
      XMVECTOR Q0 = XMLoadFloat4(&q1);
      XMVECTOR Q1 = XMLoadFloat4(&q2);
  
      Quaternion result;
      XMStoreFloat4(&result, XMQuaternionMultiply(Q1, Q0));
      return result;
  }
  
  
  /****************************************************************************
   *
   * Color
   *
   ****************************************************************************/
  
  inline Color::Color(const DirectX::PackedVector::XMCOLOR& Packed) noexcept
  {
      using namespace DirectX;
      XMStoreFloat4(this, PackedVector::XMLoadColor(&Packed));
  }
  
  inline Color::Color(const DirectX::PackedVector::XMUBYTEN4& Packed) noexcept
  {
      using namespace DirectX;
      XMStoreFloat4(this, PackedVector::XMLoadUByteN4(&Packed));
  }
  
  //------------------------------------------------------------------------------
  // Comparision operators
  //------------------------------------------------------------------------------
  inline bool Color::operator == (const Color& c) const noexcept
  {
      using namespace DirectX;
      XMVECTOR c1 = XMLoadFloat4(this);
      XMVECTOR c2 = XMLoadFloat4(&c);
      return XMColorEqual(c1, c2);
  }
  
  inline bool Color::operator != (const Color& c) const noexcept
  {
      using namespace DirectX;
      XMVECTOR c1 = XMLoadFloat4(this);
      XMVECTOR c2 = XMLoadFloat4(&c);
      return XMColorNotEqual(c1, c2);
  }
  
  //------------------------------------------------------------------------------
  // Assignment operators
  //------------------------------------------------------------------------------
  
  inline Color& Color::operator= (const DirectX::PackedVector::XMCOLOR& Packed) noexcept
  {
      using namespace DirectX;
      XMStoreFloat4(this, PackedVector::XMLoadColor(&Packed));
      return *this;
  }
  
  inline Color& Color::operator= (const DirectX::PackedVector::XMUBYTEN4& Packed) noexcept
  {
      using namespace DirectX;
      XMStoreFloat4(this, PackedVector::XMLoadUByteN4(&Packed));
      return *this;
  }
  
  inline Color& Color::operator+= (const Color& c) noexcept
  {
      using namespace DirectX;
      XMVECTOR c1 = XMLoadFloat4(this);
      XMVECTOR c2 = XMLoadFloat4(&c);
      XMStoreFloat4(this, XMVectorAdd(c1, c2));
      return *this;
  }
  
  inline Color& Color::operator-= (const Color& c) noexcept
  {
      using namespace DirectX;
      XMVECTOR c1 = XMLoadFloat4(this);
      XMVECTOR c2 = XMLoadFloat4(&c);
      XMStoreFloat4(this, XMVectorSubtract(c1, c2));
      return *this;
  }
  
  inline Color& Color::operator*= (const Color& c) noexcept
  {
      using namespace DirectX;
      XMVECTOR c1 = XMLoadFloat4(this);
      XMVECTOR c2 = XMLoadFloat4(&c);
      XMStoreFloat4(this, XMVectorMultiply(c1, c2));
      return *this;
  }
  
  inline Color& Color::operator*= (float S) noexcept
  {
      using namespace DirectX;
      XMVECTOR c = XMLoadFloat4(this);
      XMStoreFloat4(this, XMVectorScale(c, S));
      return *this;
  }
  
  inline Color& Color::operator/= (const Color& c) noexcept
  {
      using namespace DirectX;
      XMVECTOR c1 = XMLoadFloat4(this);
      XMVECTOR c2 = XMLoadFloat4(&c);
      XMStoreFloat4(this, XMVectorDivide(c1, c2));
      return *this;
  }
  
  //------------------------------------------------------------------------------
  // Urnary operators
  //------------------------------------------------------------------------------
  
  inline Color Color::operator- () const noexcept
  {
      using namespace DirectX;
      XMVECTOR c = XMLoadFloat4(this);
      Color R;
      XMStoreFloat4(&R, XMVectorNegate(c));
      return R;
  }
  
  //------------------------------------------------------------------------------
  // Binary operators
  //------------------------------------------------------------------------------
  
  inline Color operator+ (const Color& C1, const Color& C2) noexcept
  {
      using namespace DirectX;
      XMVECTOR c1 = XMLoadFloat4(&C1);
      XMVECTOR c2 = XMLoadFloat4(&C2);
      Color R;
      XMStoreFloat4(&R, XMVectorAdd(c1, c2));
      return R;
  }
  
  inline Color operator- (const Color& C1, const Color& C2) noexcept
  {
      using namespace DirectX;
      XMVECTOR c1 = XMLoadFloat4(&C1);
      XMVECTOR c2 = XMLoadFloat4(&C2);
      Color R;
      XMStoreFloat4(&R, XMVectorSubtract(c1, c2));
      return R;
  }
  
  inline Color operator* (const Color& C1, const Color& C2) noexcept
  {
      using namespace DirectX;
      XMVECTOR c1 = XMLoadFloat4(&C1);
      XMVECTOR c2 = XMLoadFloat4(&C2);
      Color R;
      XMStoreFloat4(&R, XMVectorMultiply(c1, c2));
      return R;
  }
  
  inline Color operator* (const Color& C, float S) noexcept
  {
      using namespace DirectX;
      XMVECTOR c = XMLoadFloat4(&C);
      Color R;
      XMStoreFloat4(&R, XMVectorScale(c, S));
      return R;
  }
  
  inline Color operator/ (const Color& C1, const Color& C2) noexcept
  {
      using namespace DirectX;
      XMVECTOR c1 = XMLoadFloat4(&C1);
      XMVECTOR c2 = XMLoadFloat4(&C2);
      Color R;
      XMStoreFloat4(&R, XMVectorDivide(c1, c2));
      return R;
  }
  
  inline Color operator* (float S, const Color& C) noexcept
  {
      using namespace DirectX;
      XMVECTOR c1 = XMLoadFloat4(&C);
      Color R;
      XMStoreFloat4(&R, XMVectorScale(c1, S));
      return R;
  }
  
  //------------------------------------------------------------------------------
  // Color operations
  //------------------------------------------------------------------------------
  
  inline DirectX::PackedVector::XMCOLOR Color::BGRA() const noexcept
  {
      using namespace DirectX;
      XMVECTOR clr = XMLoadFloat4(this);
      PackedVector::XMCOLOR Packed;
      PackedVector::XMStoreColor(&Packed, clr);
      return Packed;
  }
  
  inline DirectX::PackedVector::XMUBYTEN4 Color::RGBA() const noexcept
  {
      using namespace DirectX;
      XMVECTOR clr = XMLoadFloat4(this);
      PackedVector::XMUBYTEN4 Packed;
      PackedVector::XMStoreUByteN4(&Packed, clr);
      return Packed;
  }
  
  inline Vector3 Color::ToVector3() const noexcept
  {
      return Vector3(x, y, z);
  }
  
  inline Vector4 Color::ToVector4() const noexcept
  {
      return Vector4(x, y, z, w);
  }
  
  inline void Color::Negate() noexcept
  {
      using namespace DirectX;
      XMVECTOR c = XMLoadFloat4(this);
      XMStoreFloat4(this, XMColorNegative(c));
  }
  
  inline void Color::Negate(Color& result) const noexcept
  {
      using namespace DirectX;
      XMVECTOR c = XMLoadFloat4(this);
      XMStoreFloat4(&result, XMColorNegative(c));
  }
  
  inline void Color::Saturate() noexcept
  {
      using namespace DirectX;
      XMVECTOR c = XMLoadFloat4(this);
      XMStoreFloat4(this, XMVectorSaturate(c));
  }
  
  inline void Color::Saturate(Color& result) const noexcept
  {
      using namespace DirectX;
      XMVECTOR c = XMLoadFloat4(this);
      XMStoreFloat4(&result, XMVectorSaturate(c));
  }
  
  inline void Color::Premultiply() noexcept
  {
      using namespace DirectX;
      XMVECTOR c = XMLoadFloat4(this);
      XMVECTOR a = XMVectorSplatW(c);
      a = XMVectorSelect(g_XMIdentityR3, a, g_XMSelect1110);
      XMStoreFloat4(this, XMVectorMultiply(c, a));
  }
  
  inline void Color::Premultiply(Color& result) const noexcept
  {
      using namespace DirectX;
      XMVECTOR c = XMLoadFloat4(this);
      XMVECTOR a = XMVectorSplatW(c);
      a = XMVectorSelect(g_XMIdentityR3, a, g_XMSelect1110);
      XMStoreFloat4(&result, XMVectorMultiply(c, a));
  }
  
  inline void Color::AdjustSaturation(float sat) noexcept
  {
      using namespace DirectX;
      XMVECTOR c = XMLoadFloat4(this);
      XMStoreFloat4(this, XMColorAdjustSaturation(c, sat));
  }
  
  inline void Color::AdjustSaturation(float sat, Color& result) const noexcept
  {
      using namespace DirectX;
      XMVECTOR c = XMLoadFloat4(this);
      XMStoreFloat4(&result, XMColorAdjustSaturation(c, sat));
  }
  
  inline void Color::AdjustContrast(float contrast) noexcept
  {
      using namespace DirectX;
      XMVECTOR c = XMLoadFloat4(this);
      XMStoreFloat4(this, XMColorAdjustContrast(c, contrast));
  }
  
  inline void Color::AdjustContrast(float contrast, Color& result) const noexcept
  {
      using namespace DirectX;
      XMVECTOR c = XMLoadFloat4(this);
      XMStoreFloat4(&result, XMColorAdjustContrast(c, contrast));
  }
  
  //------------------------------------------------------------------------------
  // Static functions
  //------------------------------------------------------------------------------
  
  inline void Color::Modulate(const Color& c1, const Color& c2, Color& result) noexcept
  {
      using namespace DirectX;
      XMVECTOR C0 = XMLoadFloat4(&c1);
      XMVECTOR C1 = XMLoadFloat4(&c2);
      XMStoreFloat4(&result, XMColorModulate(C0, C1));
  }
  
  inline Color Color::Modulate(const Color& c1, const Color& c2) noexcept
  {
      using namespace DirectX;
      XMVECTOR C0 = XMLoadFloat4(&c1);
      XMVECTOR C1 = XMLoadFloat4(&c2);
  
      Color result;
      XMStoreFloat4(&result, XMColorModulate(C0, C1));
      return result;
  }
  
  inline void Color::Lerp(const Color& c1, const Color& c2, float t, Color& result) noexcept
  {
      using namespace DirectX;
      XMVECTOR C0 = XMLoadFloat4(&c1);
      XMVECTOR C1 = XMLoadFloat4(&c2);
      XMStoreFloat4(&result, XMVectorLerp(C0, C1, t));
  }
  
  inline Color Color::Lerp(const Color& c1, const Color& c2, float t) noexcept
  {
      using namespace DirectX;
      XMVECTOR C0 = XMLoadFloat4(&c1);
      XMVECTOR C1 = XMLoadFloat4(&c2);
  
      Color result;
      XMStoreFloat4(&result, XMVectorLerp(C0, C1, t));
      return result;
  }
  
  
  /****************************************************************************
   *
   * Ray
   *
   ****************************************************************************/
  
  //-----------------------------------------------------------------------------
  // Comparision operators
  //------------------------------------------------------------------------------
  inline bool Ray::operator == (const Ray& r) const noexcept
  {
      using namespace DirectX;
      XMVECTOR r1p = XMLoadFloat3(&position);
      XMVECTOR r2p = XMLoadFloat3(&r.position);
      XMVECTOR r1d = XMLoadFloat3(&direction);
      XMVECTOR r2d = XMLoadFloat3(&r.direction);
      return XMVector3Equal(r1p, r2p) && XMVector3Equal(r1d, r2d);
  }
  
  inline bool Ray::operator != (const Ray& r) const noexcept
  {
      using namespace DirectX;
      XMVECTOR r1p = XMLoadFloat3(&position);
      XMVECTOR r2p = XMLoadFloat3(&r.position);
      XMVECTOR r1d = XMLoadFloat3(&direction);
      XMVECTOR r2d = XMLoadFloat3(&r.direction);
      return XMVector3NotEqual(r1p, r2p) && XMVector3NotEqual(r1d, r2d);
  }
  
  //-----------------------------------------------------------------------------
  // Ray operators
  //------------------------------------------------------------------------------
  
  inline bool Ray::Intersects(const BoundingSphere& sphere, _Out_ float& Dist) const noexcept
  {
      return sphere.Intersects(position, direction, Dist);
  }
  
  inline bool Ray::Intersects(const BoundingBox& box, _Out_ float& Dist) const noexcept
  {
      return box.Intersects(position, direction, Dist);
  }
  
  inline bool Ray::Intersects(const Vector3& tri0, const Vector3& tri1, const Vector3& tri2, _Out_ float& Dist) const noexcept
  {
      return DirectX::TriangleTests::Intersects(position, direction, tri0, tri1, tri2, Dist);
  }
  
  inline bool Ray::Intersects(const Plane& plane, _Out_ float& Dist) const noexcept
  {
      using namespace DirectX;
  
      XMVECTOR p = XMLoadFloat4(&plane);
      XMVECTOR dir = XMLoadFloat3(&direction);
  
      XMVECTOR nd = XMPlaneDotNormal(p, dir);
  
      if (XMVector3LessOrEqual(XMVectorAbs(nd), g_RayEpsilon))
      {
          Dist = 0.f;
          return false;
      }
      else
      {
          // t = -(dot(n,origin) + D) / dot(n,dir)
          XMVECTOR pos = XMLoadFloat3(&position);
          XMVECTOR v = XMPlaneDotNormal(p, pos);
          v = XMVectorAdd(v, XMVectorSplatW(p));
          v = XMVectorDivide(v, nd);
          float dist = -XMVectorGetX(v);
          if (dist < 0)
          {
              Dist = 0.f;
              return false;
          }
          else
          {
              Dist = dist;
              return true;
          }
      }
  }
  
  
  /****************************************************************************
   *
   * Viewport
   *
   ****************************************************************************/
  
  //------------------------------------------------------------------------------
  // Comparision operators
  //------------------------------------------------------------------------------
  
  inline bool Viewport::operator == (const Viewport& vp) const noexcept
  {
      return (x == vp.x && y == vp.y
              && width == vp.width && height == vp.height
              && minDepth == vp.minDepth && maxDepth == vp.maxDepth);
  }
  
  inline bool Viewport::operator != (const Viewport& vp) const noexcept
  {
      return (x != vp.x || y != vp.y
              || width != vp.width || height != vp.height
              || minDepth != vp.minDepth || maxDepth != vp.maxDepth);
  }
  
  //------------------------------------------------------------------------------
  // Assignment operators
  //------------------------------------------------------------------------------
  
  inline Viewport& Viewport::operator= (const RECT& rct) noexcept
  {
      x = float(rct.left); y = float(rct.top);
      width = float(rct.right - rct.left);
      height = float(rct.bottom - rct.top);
      minDepth = 0.f; maxDepth = 1.f;
      return *this;
  }
  
  #if defined(__d3d11_h__) || defined(__d3d11_x_h__)
  inline Viewport& Viewport::operator= (const D3D11_VIEWPORT& vp) noexcept
  {
      x = vp.TopLeftX; y = vp.TopLeftY;
      width = vp.Width; height = vp.Height;
      minDepth = vp.MinDepth; maxDepth = vp.MaxDepth;
      return *this;
  }
  #endif
  
  #if defined(__d3d12_h__) || defined(__d3d12_x_h__) || defined(__XBOX_D3D12_X__)
  inline Viewport& Viewport::operator= (const D3D12_VIEWPORT& vp) noexcept
  {
      x = vp.TopLeftX; y = vp.TopLeftY;
      width = vp.Width; height = vp.Height;
      minDepth = vp.MinDepth; maxDepth = vp.MaxDepth;
      return *this;
  }
  #endif
  
  //------------------------------------------------------------------------------
  // Viewport operations
  //------------------------------------------------------------------------------
  
  inline float Viewport::AspectRatio() const noexcept
  {
      if (width == 0.f || height == 0.f)
          return 0.f;
  
      return (width / height);
  }
  
  inline Vector3 Viewport::Project(const Vector3& p, const Matrix& proj, const Matrix& view, const Matrix& world) const noexcept
  {
      using namespace DirectX;
      XMVECTOR v = XMLoadFloat3(&p);
      XMMATRIX projection = XMLoadFloat4x4(&proj);
      v = XMVector3Project(v, x, y, width, height, minDepth, maxDepth, projection, view, world);
      Vector3 result;
      XMStoreFloat3(&result, v);
      return result;
  }
  
  inline void Viewport::Project(const Vector3& p, const Matrix& proj, const Matrix& view, const Matrix& world, Vector3& result) const noexcept
  {
      using namespace DirectX;
      XMVECTOR v = XMLoadFloat3(&p);
      XMMATRIX projection = XMLoadFloat4x4(&proj);
      v = XMVector3Project(v, x, y, width, height, minDepth, maxDepth, projection, view, world);
      XMStoreFloat3(&result, v);
  }
  
  inline Vector3 Viewport::Unproject(const Vector3& p, const Matrix& proj, const Matrix& view, const Matrix& world) const noexcept
  {
      using namespace DirectX;
      XMVECTOR v = XMLoadFloat3(&p);
      XMMATRIX projection = XMLoadFloat4x4(&proj);
      v = XMVector3Unproject(v, x, y, width, height, minDepth, maxDepth, projection, view, world);
      Vector3 result;
      XMStoreFloat3(&result, v);
      return result;
  }
  
  inline void Viewport::Unproject(const Vector3& p, const Matrix& proj, const Matrix& view, const Matrix& world, Vector3& result) const noexcept
  {
      using namespace DirectX;
      XMVECTOR v = XMLoadFloat3(&p);
      XMMATRIX projection = XMLoadFloat4x4(&proj);
      v = XMVector3Unproject(v, x, y, width, height, minDepth, maxDepth, projection, view, world);
      XMStoreFloat3(&result, v);
  }
  