//-------------------------------------------------------------------------------------
// SimpleMath.h -- Simplified C++ Math wrapper for DirectXMath
//
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
//
// http://go.microsoft.com/fwlink/?LinkId=248929
// http://go.microsoft.com/fwlink/?LinkID=615561
//-------------------------------------------------------------------------------------

#pragma once

#if (defined(_WIN32) || defined(WINAPI_FAMILY)) && !(defined(_XBOX_ONE) && defined(_TITLE)) && !defined(_GAMING_XBOX)
#include <dxgi1_2.h>
#endif

#include <cassert>
#include <cstddef>
#include <cstring>
#include <functional>

#if (__cplusplus >= 202002L)
#include <compare>
#endif

#include <DirectXMath.h>
#include <DirectXPackedVector.h>
#include <DirectXCollision.h>

#ifdef __clang__
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wfloat-equal"
#pragma clang diagnostic ignored "-Wunknown-warning-option"
#pragma clang diagnostic ignored "-Wunsafe-buffer-usage"
#endif


namespace DirectX
{
    namespace SimpleMath
    {
        struct Vector2;
        struct Vector4;
        struct Matrix;
        struct Quaternion;
        struct Plane;

        //------------------------------------------------------------------------------
        // 2D rectangle
        struct Rectangle
        {
            long x;
            long y;
            long width;
            long height;

            // Creators
            Rectangle() noexcept : x(0), y(0), width(0), height(0) {}
            constexpr Rectangle(long ix, long iy, long iw, long ih) noexcept : x(ix), y(iy), width(iw), height(ih) {}
            explicit Rectangle(const RECT& rct) noexcept : x(rct.left), y(rct.top), width(rct.right - rct.left), height(rct.bottom - rct.top) {}

            Rectangle(const Rectangle&) = default;
            Rectangle& operator=(const Rectangle&) = default;

            Rectangle(Rectangle&&) = default;
            Rectangle& operator=(Rectangle&&) = default;

            operator RECT() noexcept { RECT rct; rct.left = x; rct.top = y; rct.right = (x + width); rct.bottom = (y + height); return rct; }
#ifdef __cplusplus_winrt
            operator Windows::Foundation::Rect() noexcept { return Windows::Foundation::Rect(float(x), float(y), float(width), float(height)); }
#endif

            // Comparison operators
#if (__cplusplus >= 202002L)
            bool operator == (const Rectangle&) const = default;
            auto operator <=> (const Rectangle&) const = default;
#else
            bool operator == (const Rectangle& r) const noexcept { return (x == r.x) && (y == r.y) && (width == r.width) && (height == r.height); }
            bool operator != (const Rectangle& r) const noexcept { return (x != r.x) || (y != r.y) || (width != r.width) || (height != r.height); }
#endif
            bool operator == (const RECT& rct) const noexcept { return (x == rct.left) && (y == rct.top) && (width == (rct.right - rct.left)) && (height == (rct.bottom - rct.top)); }
            bool operator != (const RECT& rct) const noexcept { return (x != rct.left) || (y != rct.top) || (width != (rct.right - rct.left)) || (height != (rct.bottom - rct.top)); }

            // Assignment operators
            Rectangle& operator=(_In_ const RECT& rct) noexcept { x = rct.left; y = rct.top; width = (rct.right - rct.left); height = (rct.bottom - rct.top); return *this; }

            // Rectangle operations
            Vector2 Location() const noexcept;
            Vector2 Center() const noexcept;

            bool IsEmpty() const noexcept { return (width == 0 && height == 0 && x == 0 && y == 0); }

            bool Contains(long ix, long iy) const noexcept { return (x <= ix) && (ix < (x + width)) && (y <= iy) && (iy < (y + height)); }
            bool Contains(const Vector2& point) const noexcept;
            bool Contains(const Rectangle& r) const noexcept { return (x <= r.x) && ((r.x + r.width) <= (x + width)) && (y <= r.y) && ((r.y + r.height) <= (y + height)); }
            bool Contains(const RECT& rct) const noexcept { return (x <= rct.left) && (rct.right <= (x + width)) && (y <= rct.top) && (rct.bottom <= (y + height)); }

            void Inflate(long horizAmount, long vertAmount) noexcept;

            bool Intersects(const Rectangle& r) const noexcept { return (r.x < (x + width)) && (x < (r.x + r.width)) && (r.y < (y + height)) && (y < (r.y + r.height)); }
            bool Intersects(const RECT& rct) const noexcept { return (rct.left < (x + width)) && (x < rct.right) && (rct.top < (y + height)) && (y < rct.bottom); }

            void Offset(long ox, long oy) noexcept { x += ox; y += oy; }

            // Static functions
            static Rectangle Intersect(const Rectangle& ra, const Rectangle& rb) noexcept;
            static RECT Intersect(const RECT& rcta, const RECT& rctb) noexcept;

            static Rectangle Union(const Rectangle& ra, const Rectangle& rb) noexcept;
            static RECT Union(const RECT& rcta, const RECT& rctb) noexcept;
        };

        //------------------------------------------------------------------------------
        // 2D vector
        struct Vector2 : public XMFLOAT2
        {
            Vector2() noexcept : XMFLOAT2(0.f, 0.f) {}
            constexpr explicit Vector2(float ix) noexcept : XMFLOAT2(ix, ix) {}
            constexpr Vector2(float ix, float iy) noexcept : XMFLOAT2(ix, iy) {}
            explicit Vector2(_In_reads_(2) const float* pArray) noexcept : XMFLOAT2(pArray) {}
            Vector2(FXMVECTOR V) noexcept { XMStoreFloat2(this, V); }
            Vector2(const XMFLOAT2& V) noexcept { this->x = V.x; this->y = V.y; }
            explicit Vector2(const XMVECTORF32& F) noexcept { this->x = F.f[0]; this->y = F.f[1]; }

            Vector2(const Vector2&) = default;
            Vector2& operator=(const Vector2&) = default;

            Vector2(Vector2&&) = default;
            Vector2& operator=(Vector2&&) = default;

            operator XMVECTOR() const noexcept { return XMLoadFloat2(this); }

            // Comparison operators
            bool operator == (const Vector2& V) const noexcept;
            bool operator != (const Vector2& V) const noexcept;

            // Assignment operators
            Vector2& operator= (const XMVECTORF32& F) noexcept { x = F.f[0]; y = F.f[1]; return *this; }
            Vector2& operator+= (const Vector2& V) noexcept;
            Vector2& operator-= (const Vector2& V) noexcept;
            Vector2& operator*= (const Vector2& V) noexcept;
            Vector2& operator*= (float S) noexcept;
            Vector2& operator/= (float S) noexcept;

            // Unary operators
            Vector2 operator+ () const noexcept { return *this; }
            Vector2 operator- () const noexcept { return Vector2(-x, -y); }

            // Vector operations
            bool InBounds(const Vector2& Bounds) const noexcept;

            float Length() const noexcept;
            float LengthSquared() const noexcept;

            float Dot(const Vector2& V) const noexcept;
            void Cross(const Vector2& V, Vector2& result) const noexcept;
            Vector2 Cross(const Vector2& V) const noexcept;

            void Normalize() noexcept;
            void Normalize(Vector2& result) const noexcept;

            void Clamp(const Vector2& vmin, const Vector2& vmax) noexcept;
            void Clamp(const Vector2& vmin, const Vector2& vmax, Vector2& result) const noexcept;

            // Static functions
            static float Distance(const Vector2& v1, const Vector2& v2) noexcept;
            static float DistanceSquared(const Vector2& v1, const Vector2& v2) noexcept;

            static void Min(const Vector2& v1, const Vector2& v2, Vector2& result) noexcept;
            static Vector2 Min(const Vector2& v1, const Vector2& v2) noexcept;

            static void Max(const Vector2& v1, const Vector2& v2, Vector2& result) noexcept;
            static Vector2 Max(const Vector2& v1, const Vector2& v2) noexcept;

            static void Lerp(const Vector2& v1, const Vector2& v2, float t, Vector2& result) noexcept;
            static Vector2 Lerp(const Vector2& v1, const Vector2& v2, float t) noexcept;

            static void SmoothStep(const Vector2& v1, const Vector2& v2, float t, Vector2& result) noexcept;
            static Vector2 SmoothStep(const Vector2& v1, const Vector2& v2, float t) noexcept;

            static void Barycentric(const Vector2& v1, const Vector2& v2, const Vector2& v3, float f, float g, Vector2& result) noexcept;
            static Vector2 Barycentric(const Vector2& v1, const Vector2& v2, const Vector2& v3, float f, float g) noexcept;

            static void CatmullRom(const Vector2& v1, const Vector2& v2, const Vector2& v3, const Vector2& v4, float t, Vector2& result) noexcept;
            static Vector2 CatmullRom(const Vector2& v1, const Vector2& v2, const Vector2& v3, const Vector2& v4, float t) noexcept;

            static void Hermite(const Vector2& v1, const Vector2& t1, const Vector2& v2, const Vector2& t2, float t, Vector2& result) noexcept;
            static Vector2 Hermite(const Vector2& v1, const Vector2& t1, const Vector2& v2, const Vector2& t2, float t) noexcept;

            static void Reflect(const Vector2& ivec, const Vector2& nvec, Vector2& result) noexcept;
            static Vector2 Reflect(const Vector2& ivec, const Vector2& nvec) noexcept;

            static void Refract(const Vector2& ivec, const Vector2& nvec, float refractionIndex, Vector2& result) noexcept;
            static Vector2 Refract(const Vector2& ivec, const Vector2& nvec, float refractionIndex) noexcept;

            static void Transform(const Vector2& v, const Quaternion& quat, Vector2& result) noexcept;
            static Vector2 Transform(const Vector2& v, const Quaternion& quat) noexcept;

            static void Transform(const Vector2& v, const Matrix& m, Vector2& result) noexcept;
            static Vector2 Transform(const Vector2& v, const Matrix& m) noexcept;
            static void Transform(_In_reads_(count) const Vector2* varray, size_t count, const Matrix& m, _Out_writes_(count) Vector2* resultArray) noexcept;

            static void Transform(const Vector2& v, const Matrix& m, Vector4& result) noexcept;
            static void Transform(_In_reads_(count) const Vector2* varray, size_t count, const Matrix& m, _Out_writes_(count) Vector4* resultArray) noexcept;

            static void TransformNormal(const Vector2& v, const Matrix& m, Vector2& result) noexcept;
            static Vector2 TransformNormal(const Vector2& v, const Matrix& m) noexcept;
            static void TransformNormal(_In_reads_(count) const Vector2* varray, size_t count, const Matrix& m, _Out_writes_(count) Vector2* resultArray) noexcept;

            // Constants
            static const Vector2 Zero;
            static const Vector2 One;
            static const Vector2 UnitX;
            static const Vector2 UnitY;
        };

        // Binary operators
        Vector2 operator+ (const Vector2& V1, const Vector2& V2) noexcept;
        Vector2 operator- (const Vector2& V1, const Vector2& V2) noexcept;
        Vector2 operator* (const Vector2& V1, const Vector2& V2) noexcept;
        Vector2 operator* (const Vector2& V, float S) noexcept;
        Vector2 operator/ (const Vector2& V1, const Vector2& V2) noexcept;
        Vector2 operator/ (const Vector2& V, float S) noexcept;
        Vector2 operator* (float S, const Vector2& V) noexcept;

        //------------------------------------------------------------------------------
        // 3D vector
        struct Vector3 : public XMFLOAT3
        {
            Vector3() noexcept : XMFLOAT3(0.f, 0.f, 0.f) {}
            constexpr explicit Vector3(float ix) noexcept : XMFLOAT3(ix, ix, ix) {}
            constexpr Vector3(float ix, float iy, float iz) noexcept : XMFLOAT3(ix, iy, iz) {}
            explicit Vector3(_In_reads_(3) const float* pArray) noexcept : XMFLOAT3(pArray) {}
            Vector3(FXMVECTOR V) noexcept { XMStoreFloat3(this, V); }
            Vector3(const XMFLOAT3& V) noexcept { this->x = V.x; this->y = V.y; this->z = V.z; }
            explicit Vector3(const XMVECTORF32& F) noexcept { this->x = F.f[0]; this->y = F.f[1]; this->z = F.f[2]; }

            Vector3(const Vector3&) = default;
            Vector3& operator=(const Vector3&) = default;

            Vector3(Vector3&&) = default;
            Vector3& operator=(Vector3&&) = default;

            operator XMVECTOR() const noexcept { return XMLoadFloat3(this); }

            // Comparison operators
            bool operator == (const Vector3& V) const noexcept;
            bool operator != (const Vector3& V) const noexcept;

            // Assignment operators
            Vector3& operator= (const XMVECTORF32& F) noexcept { x = F.f[0]; y = F.f[1]; z = F.f[2]; return *this; }
            Vector3& operator+= (const Vector3& V) noexcept;
            Vector3& operator-= (const Vector3& V) noexcept;
            Vector3& operator*= (const Vector3& V) noexcept;
            Vector3& operator*= (float S) noexcept;
            Vector3& operator/= (float S) noexcept;

            // Unary operators
            Vector3 operator+ () const noexcept { return *this; }
            Vector3 operator- () const noexcept;

            // Vector operations
            bool InBounds(const Vector3& Bounds) const noexcept;

            float Length() const noexcept;
            float LengthSquared() const noexcept;

            float Dot(const Vector3& V) const noexcept;
            void Cross(const Vector3& V, Vector3& result) const noexcept;
            Vector3 Cross(const Vector3& V) const noexcept;

            void Normalize() noexcept;
            void Normalize(Vector3& result) const noexcept;

            void Clamp(const Vector3& vmin, const Vector3& vmax) noexcept;
            void Clamp(const Vector3& vmin, const Vector3& vmax, Vector3& result) const noexcept;

            // Static functions
            static float Distance(const Vector3& v1, const Vector3& v2) noexcept;
            static float DistanceSquared(const Vector3& v1, const Vector3& v2) noexcept;

            static void Min(const Vector3& v1, const Vector3& v2, Vector3& result) noexcept;
            static Vector3 Min(const Vector3& v1, const Vector3& v2) noexcept;

            static void Max(const Vector3& v1, const Vector3& v2, Vector3& result) noexcept;
            static Vector3 Max(const Vector3& v1, const Vector3& v2) noexcept;

            static void Lerp(const Vector3& v1, const Vector3& v2, float t, Vector3& result) noexcept;
            static Vector3 Lerp(const Vector3& v1, const Vector3& v2, float t) noexcept;

            static void SmoothStep(const Vector3& v1, const Vector3& v2, float t, Vector3& result) noexcept;
            static Vector3 SmoothStep(const Vector3& v1, const Vector3& v2, float t) noexcept;

            static void Barycentric(const Vector3& v1, const Vector3& v2, const Vector3& v3, float f, float g, Vector3& result) noexcept;
            static Vector3 Barycentric(const Vector3& v1, const Vector3& v2, const Vector3& v3, float f, float g) noexcept;

            static void CatmullRom(const Vector3& v1, const Vector3& v2, const Vector3& v3, const Vector3& v4, float t, Vector3& result) noexcept;
            static Vector3 CatmullRom(const Vector3& v1, const Vector3& v2, const Vector3& v3, const Vector3& v4, float t) noexcept;

            static void Hermite(const Vector3& v1, const Vector3& t1, const Vector3& v2, const Vector3& t2, float t, Vector3& result) noexcept;
            static Vector3 Hermite(const Vector3& v1, const Vector3& t1, const Vector3& v2, const Vector3& t2, float t) noexcept;

            static void Reflect(const Vector3& ivec, const Vector3& nvec, Vector3& result) noexcept;
            static Vector3 Reflect(const Vector3& ivec, const Vector3& nvec) noexcept;

            static void Refract(const Vector3& ivec, const Vector3& nvec, float refractionIndex, Vector3& result) noexcept;
            static Vector3 Refract(const Vector3& ivec, const Vector3& nvec, float refractionIndex) noexcept;

            static void Transform(const Vector3& v, const Quaternion& quat, Vector3& result) noexcept;
            static Vector3 Transform(const Vector3& v, const Quaternion& quat) noexcept;

            static void Transform(const Vector3& v, const Matrix& m, Vector3& result) noexcept;
            static Vector3 Transform(const Vector3& v, const Matrix& m) noexcept;
            static void Transform(_In_reads_(count) const Vector3* varray, size_t count, const Matrix& m, _Out_writes_(count) Vector3* resultArray) noexcept;

            static void Transform(const Vector3& v, const Matrix& m, Vector4& result) noexcept;
            static void Transform(_In_reads_(count) const Vector3* varray, size_t count, const Matrix& m, _Out_writes_(count) Vector4* resultArray) noexcept;

            static void TransformNormal(const Vector3& v, const Matrix& m, Vector3& result) noexcept;
            static Vector3 TransformNormal(const Vector3& v, const Matrix& m) noexcept;
            static void TransformNormal(_In_reads_(count) const Vector3* varray, size_t count, const Matrix& m, _Out_writes_(count) Vector3* resultArray) noexcept;

            // Constants
            static const Vector3 Zero;
            static const Vector3 One;
            static const Vector3 UnitX;
            static const Vector3 UnitY;
            static const Vector3 UnitZ;
            static const Vector3 Up;
            static const Vector3 Down;
            static const Vector3 Right;
            static const Vector3 Left;
            static const Vector3 Forward;
            static const Vector3 Backward;
        };

        // Binary operators
        Vector3 operator+ (const Vector3& V1, const Vector3& V2) noexcept;
        Vector3 operator- (const Vector3& V1, const Vector3& V2) noexcept;
        Vector3 operator* (const Vector3& V1, const Vector3& V2) noexcept;
        Vector3 operator* (const Vector3& V, float S) noexcept;
        Vector3 operator/ (const Vector3& V1, const Vector3& V2) noexcept;
        Vector3 operator/ (const Vector3& V, float S) noexcept;
        Vector3 operator* (float S, const Vector3& V) noexcept;

        //------------------------------------------------------------------------------
        // 4D vector
        struct Vector4 : public XMFLOAT4
        {
            Vector4() noexcept : XMFLOAT4(0.f, 0.f, 0.f, 0.f) {}
            constexpr explicit Vector4(float ix) noexcept : XMFLOAT4(ix, ix, ix, ix) {}
            constexpr Vector4(float ix, float iy, float iz, float iw) noexcept : XMFLOAT4(ix, iy, iz, iw) {}
            explicit Vector4(_In_reads_(4) const float* pArray) noexcept : XMFLOAT4(pArray) {}
            Vector4(FXMVECTOR V) noexcept { XMStoreFloat4(this, V); }
            Vector4(const XMFLOAT4& V) noexcept { this->x = V.x; this->y = V.y; this->z = V.z; this->w = V.w; }
            explicit Vector4(const XMVECTORF32& F) noexcept { this->x = F.f[0]; this->y = F.f[1]; this->z = F.f[2]; this->w = F.f[3]; }

            Vector4(const Vector4&) = default;
            Vector4& operator=(const Vector4&) = default;

            Vector4(Vector4&&) = default;
            Vector4& operator=(Vector4&&) = default;

            operator XMVECTOR() const  noexcept { return XMLoadFloat4(this); }

            // Comparison operators
            bool operator == (const Vector4& V) const noexcept;
            bool operator != (const Vector4& V) const noexcept;

            // Assignment operators
            Vector4& operator= (const XMVECTORF32& F) noexcept { x = F.f[0]; y = F.f[1]; z = F.f[2]; w = F.f[3]; return *this; }
            Vector4& operator+= (const Vector4& V) noexcept;
            Vector4& operator-= (const Vector4& V) noexcept;
            Vector4& operator*= (const Vector4& V) noexcept;
            Vector4& operator*= (float S) noexcept;
            Vector4& operator/= (float S) noexcept;

            // Unary operators
            Vector4 operator+ () const noexcept { return *this; }
            Vector4 operator- () const noexcept;

            // Vector operations
            bool InBounds(const Vector4& Bounds) const noexcept;

            float Length() const noexcept;
            float LengthSquared() const noexcept;

            float Dot(const Vector4& V) const noexcept;
            void Cross(const Vector4& v1, const Vector4& v2, Vector4& result) const noexcept;
            Vector4 Cross(const Vector4& v1, const Vector4& v2) const noexcept;

            void Normalize() noexcept;
            void Normalize(Vector4& result) const noexcept;

            void Clamp(const Vector4& vmin, const Vector4& vmax) noexcept;
            void Clamp(const Vector4& vmin, const Vector4& vmax, Vector4& result) const noexcept;

            // Static functions
            static float Distance(const Vector4& v1, const Vector4& v2) noexcept;
            static float DistanceSquared(const Vector4& v1, const Vector4& v2) noexcept;

            static void Min(const Vector4& v1, const Vector4& v2, Vector4& result) noexcept;
            static Vector4 Min(const Vector4& v1, const Vector4& v2) noexcept;

            static void Max(const Vector4& v1, const Vector4& v2, Vector4& result) noexcept;
            static Vector4 Max(const Vector4& v1, const Vector4& v2) noexcept;

            static void Lerp(const Vector4& v1, const Vector4& v2, float t, Vector4& result) noexcept;
            static Vector4 Lerp(const Vector4& v1, const Vector4& v2, float t) noexcept;

            static void SmoothStep(const Vector4& v1, const Vector4& v2, float t, Vector4& result) noexcept;
            static Vector4 SmoothStep(const Vector4& v1, const Vector4& v2, float t) noexcept;

            static void Barycentric(const Vector4& v1, const Vector4& v2, const Vector4& v3, float f, float g, Vector4& result) noexcept;
            static Vector4 Barycentric(const Vector4& v1, const Vector4& v2, const Vector4& v3, float f, float g) noexcept;

            static void CatmullRom(const Vector4& v1, const Vector4& v2, const Vector4& v3, const Vector4& v4, float t, Vector4& result) noexcept;
            static Vector4 CatmullRom(const Vector4& v1, const Vector4& v2, const Vector4& v3, const Vector4& v4, float t) noexcept;

            static void Hermite(const Vector4& v1, const Vector4& t1, const Vector4& v2, const Vector4& t2, float t, Vector4& result) noexcept;
            static Vector4 Hermite(const Vector4& v1, const Vector4& t1, const Vector4& v2, const Vector4& t2, float t) noexcept;

            static void Reflect(const Vector4& ivec, const Vector4& nvec, Vector4& result) noexcept;
            static Vector4 Reflect(const Vector4& ivec, const Vector4& nvec) noexcept;

            static void Refract(const Vector4& ivec, const Vector4& nvec, float refractionIndex, Vector4& result) noexcept;
            static Vector4 Refract(const Vector4& ivec, const Vector4& nvec, float refractionIndex) noexcept;

            static void Transform(const Vector2& v, const Quaternion& quat, Vector4& result) noexcept;
            static Vector4 Transform(const Vector2& v, const Quaternion& quat) noexcept;

            static void Transform(const Vector3& v, const Quaternion& quat, Vector4& result) noexcept;
            static Vector4 Transform(const Vector3& v, const Quaternion& quat) noexcept;

            static void Transform(const Vector4& v, const Quaternion& quat, Vector4& result) noexcept;
            static Vector4 Transform(const Vector4& v, const Quaternion& quat) noexcept;

            static void Transform(const Vector4& v, const Matrix& m, Vector4& result) noexcept;
            static Vector4 Transform(const Vector4& v, const Matrix& m) noexcept;
            static void Transform(_In_reads_(count) const Vector4* varray, size_t count, const Matrix& m, _Out_writes_(count) Vector4* resultArray) noexcept;

            // Constants
            static const Vector4 Zero;
            static const Vector4 One;
            static const Vector4 UnitX;
            static const Vector4 UnitY;
            static const Vector4 UnitZ;
            static const Vector4 UnitW;
        };

        // Binary operators
        Vector4 operator+ (const Vector4& V1, const Vector4& V2) noexcept;
        Vector4 operator- (const Vector4& V1, const Vector4& V2) noexcept;
        Vector4 operator* (const Vector4& V1, const Vector4& V2) noexcept;
        Vector4 operator* (const Vector4& V, float S) noexcept;
        Vector4 operator/ (const Vector4& V1, const Vector4& V2) noexcept;
        Vector4 operator/ (const Vector4& V, float S) noexcept;
        Vector4 operator* (float S, const Vector4& V) noexcept;

        //------------------------------------------------------------------------------
        // 4x4 Matrix (assumes right-handed cooordinates)
        struct Matrix : public XMFLOAT4X4
        {
            Matrix() noexcept
                : XMFLOAT4X4(1.f, 0, 0, 0,
                    0, 1.f, 0, 0,
                    0, 0, 1.f, 0,
                    0, 0, 0, 1.f)
            {
            }
            constexpr Matrix(float m00, float m01, float m02, float m03,
                float m10, float m11, float m12, float m13,
                float m20, float m21, float m22, float m23,
                float m30, float m31, float m32, float m33) noexcept
                : XMFLOAT4X4(m00, m01, m02, m03,
                    m10, m11, m12, m13,
                    m20, m21, m22, m23,
                    m30, m31, m32, m33)
            {
            }
            explicit Matrix(const Vector3& r0, const Vector3& r1, const Vector3& r2) noexcept
                : XMFLOAT4X4(r0.x, r0.y, r0.z, 0,
                    r1.x, r1.y, r1.z, 0,
                    r2.x, r2.y, r2.z, 0,
                    0, 0, 0, 1.f)
            {
            }
            explicit Matrix(const Vector4& r0, const Vector4& r1, const Vector4& r2, const Vector4& r3) noexcept
                : XMFLOAT4X4(r0.x, r0.y, r0.z, r0.w,
                    r1.x, r1.y, r1.z, r1.w,
                    r2.x, r2.y, r2.z, r2.w,
                    r3.x, r3.y, r3.z, r3.w)
            {
            }
            Matrix(const XMFLOAT4X4& M) noexcept { memcpy(this, &M, sizeof(XMFLOAT4X4)); }
            Matrix(const XMFLOAT3X3& M) noexcept;
            Matrix(const XMFLOAT4X3& M) noexcept;

            explicit Matrix(_In_reads_(16) const float* pArray) noexcept : XMFLOAT4X4(pArray) {}
            Matrix(CXMMATRIX M) noexcept { XMStoreFloat4x4(this, M); }

            Matrix(const Matrix&) = default;
            Matrix& operator=(const Matrix&) = default;

            Matrix(Matrix&&) = default;
            Matrix& operator=(Matrix&&) = default;

            operator XMMATRIX() const noexcept { return XMLoadFloat4x4(this); }

            // Comparison operators
            bool operator == (const Matrix& M) const noexcept;
            bool operator != (const Matrix& M) const noexcept;

            // Assignment operators
            Matrix& operator= (const XMFLOAT3X3& M) noexcept;
            Matrix& operator= (const XMFLOAT4X3& M) noexcept;
            Matrix& operator+= (const Matrix& M) noexcept;
            Matrix& operator-= (const Matrix& M) noexcept;
            Matrix& operator*= (const Matrix& M) noexcept;
            Matrix& operator*= (float S) noexcept;
            Matrix& operator/= (float S) noexcept;

            Matrix& operator/= (const Matrix& M) noexcept;
            // Element-wise divide

        // Unary operators
            Matrix operator+ () const noexcept { return *this; }
            Matrix operator- () const noexcept;

            // Properties
            Vector3 Up() const noexcept { return Vector3(_21, _22, _23); }
            void Up(const Vector3& v) noexcept { _21 = v.x; _22 = v.y; _23 = v.z; }

            Vector3 Down() const  noexcept { return Vector3(-_21, -_22, -_23); }
            void Down(const Vector3& v) noexcept { _21 = -v.x; _22 = -v.y; _23 = -v.z; }

            Vector3 Right() const noexcept { return Vector3(_11, _12, _13); }
            void Right(const Vector3& v) noexcept { _11 = v.x; _12 = v.y; _13 = v.z; }

            Vector3 Left() const noexcept { return Vector3(-_11, -_12, -_13); }
            void Left(const Vector3& v) noexcept { _11 = -v.x; _12 = -v.y; _13 = -v.z; }

            Vector3 Forward() const noexcept { return Vector3(-_31, -_32, -_33); }
            void Forward(const Vector3& v) noexcept { _31 = -v.x; _32 = -v.y; _33 = -v.z; }

            Vector3 Backward() const noexcept { return Vector3(_31, _32, _33); }
            void Backward(const Vector3& v) noexcept { _31 = v.x; _32 = v.y; _33 = v.z; }

            Vector3 Translation() const  noexcept { return Vector3(_41, _42, _43); }
            void Translation(const Vector3& v) noexcept { _41 = v.x; _42 = v.y; _43 = v.z; }

            // Matrix operations
            bool Decompose(Vector3& scale, Quaternion& rotation, Vector3& translation) noexcept;

            Matrix Transpose() const noexcept;
            void Transpose(Matrix& result) const noexcept;

            Matrix Invert() const noexcept;
            void Invert(Matrix& result) const noexcept;

            float Determinant() const noexcept;

            // Computes rotation about y-axis (y), then x-axis (x), then z-axis (z)
            Vector3 ToEuler() const noexcept;

            // Static functions
            static Matrix CreateBillboard(
                const Vector3& object, const Vector3& cameraPosition, const Vector3& cameraUp, _In_opt_ const Vector3* cameraForward = nullptr) noexcept;

            static Matrix CreateConstrainedBillboard(
                const Vector3& object, const Vector3& cameraPosition, const Vector3& rotateAxis,
                _In_opt_ const Vector3* cameraForward = nullptr, _In_opt_ const Vector3* objectForward = nullptr) noexcept;

            static Matrix CreateTranslation(const Vector3& position) noexcept;
            static Matrix CreateTranslation(float x, float y, float z) noexcept;

            static Matrix CreateScale(const Vector3& scales) noexcept;
            static Matrix CreateScale(float xs, float ys, float zs) noexcept;
            static Matrix CreateScale(float scale) noexcept;

            static Matrix CreateRotationX(float radians) noexcept;
            static Matrix CreateRotationY(float radians) noexcept;
            static Matrix CreateRotationZ(float radians) noexcept;

            static Matrix CreateFromAxisAngle(const Vector3& axis, float angle) noexcept;

            static Matrix CreatePerspectiveFieldOfView(float fov, float aspectRatio, float nearPlane, float farPlane) noexcept;
            static Matrix CreatePerspective(float width, float height, float nearPlane, float farPlane) noexcept;
            static Matrix CreatePerspectiveOffCenter(float left, float right, float bottom, float top, float nearPlane, float farPlane) noexcept;
            static Matrix CreateOrthographic(float width, float height, float zNearPlane, float zFarPlane) noexcept;
            static Matrix CreateOrthographicOffCenter(float left, float right, float bottom, float top, float zNearPlane, float zFarPlane) noexcept;

            static Matrix CreateLookAt(const Vector3& position, const Vector3& target, const Vector3& up) noexcept;
            static Matrix CreateWorld(const Vector3& position, const Vector3& forward, const Vector3& up) noexcept;

            static Matrix CreateFromQuaternion(const Quaternion& quat) noexcept;

            // Rotates about y-axis (yaw), then x-axis (pitch), then z-axis (roll)
            static Matrix CreateFromYawPitchRoll(float yaw, float pitch, float roll) noexcept;

            // Rotates about y-axis (angles.y), then x-axis (angles.x), then z-axis (angles.z)
            static Matrix CreateFromYawPitchRoll(const Vector3& angles) noexcept;

            static Matrix CreateShadow(const Vector3& lightDir, const Plane& plane) noexcept;

            static Matrix CreateReflection(const Plane& plane) noexcept;

            static void Lerp(const Matrix& M1, const Matrix& M2, float t, Matrix& result) noexcept;
            static Matrix Lerp(const Matrix& M1, const Matrix& M2, float t) noexcept;

            static void Transform(const Matrix& M, const Quaternion& rotation, Matrix& result) noexcept;
            static Matrix Transform(const Matrix& M, const Quaternion& rotation) noexcept;

            // Constants
            static const Matrix Identity;
        };

        // Binary operators
        Matrix operator+ (const Matrix& M1, const Matrix& M2) noexcept;
        Matrix operator- (const Matrix& M1, const Matrix& M2) noexcept;
        Matrix operator* (const Matrix& M1, const Matrix& M2) noexcept;
        Matrix operator* (const Matrix& M, float S) noexcept;
        Matrix operator/ (const Matrix& M, float S) noexcept;
        Matrix operator/ (const Matrix& M1, const Matrix& M2) noexcept;
        // Element-wise divide
        Matrix operator* (float S, const Matrix& M) noexcept;


        //-----------------------------------------------------------------------------
        // Plane
        struct Plane : public XMFLOAT4
        {
            Plane() noexcept : XMFLOAT4(0.f, 1.f, 0.f, 0.f) {}
            constexpr Plane(float ix, float iy, float iz, float iw) noexcept : XMFLOAT4(ix, iy, iz, iw) {}
            Plane(const Vector3& normal, float d) noexcept : XMFLOAT4(normal.x, normal.y, normal.z, d) {}
            Plane(const Vector3& point1, const Vector3& point2, const Vector3& point3) noexcept;
            Plane(const Vector3& point, const Vector3& normal) noexcept;
            explicit Plane(const Vector4& v) noexcept : XMFLOAT4(v.x, v.y, v.z, v.w) {}
            explicit Plane(_In_reads_(4) const float* pArray) noexcept : XMFLOAT4(pArray) {}
            Plane(FXMVECTOR V) noexcept { XMStoreFloat4(this, V); }
            Plane(const XMFLOAT4& p) noexcept { this->x = p.x; this->y = p.y; this->z = p.z; this->w = p.w; }
            explicit Plane(const XMVECTORF32& F) noexcept { this->x = F.f[0]; this->y = F.f[1]; this->z = F.f[2]; this->w = F.f[3]; }

            Plane(const Plane&) = default;
            Plane& operator=(const Plane&) = default;

            Plane(Plane&&) = default;
            Plane& operator=(Plane&&) = default;

            operator XMVECTOR() const noexcept { return XMLoadFloat4(this); }

            // Comparison operators
            bool operator == (const Plane& p) const noexcept;
            bool operator != (const Plane& p) const noexcept;

            // Assignment operators
            Plane& operator= (const XMVECTORF32& F) noexcept { x = F.f[0]; y = F.f[1]; z = F.f[2]; w = F.f[3]; return *this; }

            // Properties
            Vector3 Normal() const noexcept { return Vector3(x, y, z); }
            void Normal(const Vector3& normal) noexcept { x = normal.x; y = normal.y; z = normal.z; }

            float D() const noexcept { return w; }
            void D(float d) noexcept { w = d; }

            // Plane operations
            void Normalize() noexcept;
            void Normalize(Plane& result) const noexcept;

            float Dot(const Vector4& v) const noexcept;
            float DotCoordinate(const Vector3& position) const noexcept;
            float DotNormal(const Vector3& normal) const noexcept;

            // Static functions
            static void Transform(const Plane& plane, const Matrix& M, Plane& result) noexcept;
            static Plane Transform(const Plane& plane, const Matrix& M) noexcept;

            static void Transform(const Plane& plane, const Quaternion& rotation, Plane& result) noexcept;
            static Plane Transform(const Plane& plane, const Quaternion& rotation) noexcept;
            // Input quaternion must be the inverse transpose of the transformation
        };

        //------------------------------------------------------------------------------
        // Quaternion
        struct Quaternion : public XMFLOAT4
        {
            Quaternion() noexcept : XMFLOAT4(0, 0, 0, 1.f) {}
            constexpr Quaternion(float ix, float iy, float iz, float iw) noexcept : XMFLOAT4(ix, iy, iz, iw) {}
            Quaternion(const Vector3& v, float scalar) noexcept : XMFLOAT4(v.x, v.y, v.z, scalar) {}
            explicit Quaternion(const Vector4& v) noexcept : XMFLOAT4(v.x, v.y, v.z, v.w) {}
            explicit Quaternion(_In_reads_(4) const float* pArray) noexcept : XMFLOAT4(pArray) {}
            Quaternion(FXMVECTOR V) noexcept { XMStoreFloat4(this, V); }
            Quaternion(const XMFLOAT4& q) noexcept { this->x = q.x; this->y = q.y; this->z = q.z; this->w = q.w; }
            explicit Quaternion(const XMVECTORF32& F) noexcept { this->x = F.f[0]; this->y = F.f[1]; this->z = F.f[2]; this->w = F.f[3]; }

            Quaternion(const Quaternion&) = default;
            Quaternion& operator=(const Quaternion&) = default;

            Quaternion(Quaternion&&) = default;
            Quaternion& operator=(Quaternion&&) = default;

            operator XMVECTOR() const noexcept { return XMLoadFloat4(this); }

            // Comparison operators
            bool operator == (const Quaternion& q) const noexcept;
            bool operator != (const Quaternion& q) const noexcept;

            // Assignment operators
            Quaternion& operator= (const XMVECTORF32& F) noexcept { x = F.f[0]; y = F.f[1]; z = F.f[2]; w = F.f[3]; return *this; }
            Quaternion& operator+= (const Quaternion& q) noexcept;
            Quaternion& operator-= (const Quaternion& q) noexcept;
            Quaternion& operator*= (const Quaternion& q) noexcept;
            Quaternion& operator*= (float S) noexcept;
            Quaternion& operator/= (const Quaternion& q) noexcept;

            // Unary operators
            Quaternion operator+ () const  noexcept { return *this; }
            Quaternion operator- () const noexcept;

            // Quaternion operations
            float Length() const noexcept;
            float LengthSquared() const noexcept;

            void Normalize() noexcept;
            void Normalize(Quaternion& result) const noexcept;

            void Conjugate() noexcept;
            void Conjugate(Quaternion& result) const noexcept;

            void Inverse(Quaternion& result) const noexcept;

            float Dot(const Quaternion& Q) const noexcept;

            void RotateTowards(const Quaternion& target, float maxAngle) noexcept;
            void __cdecl RotateTowards(const Quaternion& target, float maxAngle, Quaternion& result) const noexcept;

            // Computes rotation about y-axis (y), then x-axis (x), then z-axis (z)
            Vector3 ToEuler() const noexcept;

            // Static functions
            static Quaternion CreateFromAxisAngle(const Vector3& axis, float angle) noexcept;

            // Rotates about y-axis (yaw), then x-axis (pitch), then z-axis (roll)
            static Quaternion CreateFromYawPitchRoll(float yaw, float pitch, float roll) noexcept;

            // Rotates about y-axis (angles.y), then x-axis (angles.x), then z-axis (angles.z)
            static Quaternion CreateFromYawPitchRoll(const Vector3& angles) noexcept;

            static Quaternion CreateFromRotationMatrix(const Matrix& M) noexcept;

            static void Lerp(const Quaternion& q1, const Quaternion& q2, float t, Quaternion& result) noexcept;
            static Quaternion Lerp(const Quaternion& q1, const Quaternion& q2, float t) noexcept;

            static void Slerp(const Quaternion& q1, const Quaternion& q2, float t, Quaternion& result) noexcept;
            static Quaternion Slerp(const Quaternion& q1, const Quaternion& q2, float t) noexcept;

            static void Concatenate(const Quaternion& q1, const Quaternion& q2, Quaternion& result) noexcept;
            static Quaternion Concatenate(const Quaternion& q1, const Quaternion& q2) noexcept;

            static void __cdecl FromToRotation(const Vector3& fromDir, const Vector3& toDir, Quaternion& result) noexcept;
            static Quaternion FromToRotation(const Vector3& fromDir, const Vector3& toDir) noexcept;

            static void __cdecl LookRotation(const Vector3& forward, const Vector3& up, Quaternion& result) noexcept;
            static Quaternion LookRotation(const Vector3& forward, const Vector3& up) noexcept;

            static float Angle(const Quaternion& q1, const Quaternion& q2) noexcept;

            // Constants
            static const Quaternion Identity;
        };

        // Binary operators
        Quaternion operator+ (const Quaternion& Q1, const Quaternion& Q2) noexcept;
        Quaternion operator- (const Quaternion& Q1, const Quaternion& Q2) noexcept;
        Quaternion operator* (const Quaternion& Q1, const Quaternion& Q2) noexcept;
        Quaternion operator* (const Quaternion& Q, float S) noexcept;
        Quaternion operator/ (const Quaternion& Q1, const Quaternion& Q2) noexcept;
        Quaternion operator* (float S, const Quaternion& Q) noexcept;

        //------------------------------------------------------------------------------
        // Color
        struct Color : public XMFLOAT4
        {
            Color() noexcept : XMFLOAT4(0, 0, 0, 1.f) {}
            constexpr Color(float _r, float _g, float _b) noexcept : XMFLOAT4(_r, _g, _b, 1.f) {}
            constexpr Color(float _r, float _g, float _b, float _a) noexcept : XMFLOAT4(_r, _g, _b, _a) {}
            explicit Color(const Vector3& clr) noexcept : XMFLOAT4(clr.x, clr.y, clr.z, 1.f) {}
            explicit Color(const Vector4& clr) noexcept : XMFLOAT4(clr.x, clr.y, clr.z, clr.w) {}
            explicit Color(_In_reads_(4) const float* pArray) noexcept : XMFLOAT4(pArray) {}
            Color(FXMVECTOR V) noexcept { XMStoreFloat4(this, V); }
            Color(const XMFLOAT4& c) noexcept { this->x = c.x; this->y = c.y; this->z = c.z; this->w = c.w; }
            explicit Color(const XMVECTORF32& F) noexcept { this->x = F.f[0]; this->y = F.f[1]; this->z = F.f[2]; this->w = F.f[3]; }

            // BGRA Direct3D 9 D3DCOLOR packed color
            explicit Color(const DirectX::PackedVector::XMCOLOR& Packed) noexcept;

            // RGBA XNA Game Studio packed color
            explicit Color(const DirectX::PackedVector::XMUBYTEN4& Packed) noexcept;

            Color(const Color&) = default;
            Color& operator=(const Color&) = default;

            Color(Color&&) = default;
            Color& operator=(Color&&) = default;

            operator XMVECTOR() const noexcept { return XMLoadFloat4(this); }
            operator const float* () const noexcept { return reinterpret_cast<const float*>(this); }

            // Comparison operators
            bool operator == (const Color& c) const noexcept;
            bool operator != (const Color& c) const noexcept;

            // Assignment operators
            Color& operator= (const XMVECTORF32& F) noexcept { x = F.f[0]; y = F.f[1]; z = F.f[2]; w = F.f[3]; return *this; }
            Color& operator= (const DirectX::PackedVector::XMCOLOR& Packed) noexcept;
            Color& operator= (const DirectX::PackedVector::XMUBYTEN4& Packed) noexcept;
            Color& operator+= (const Color& c) noexcept;
            Color& operator-= (const Color& c) noexcept;
            Color& operator*= (const Color& c) noexcept;
            Color& operator*= (float S) noexcept;
            Color& operator/= (const Color& c) noexcept;

            // Unary operators
            Color operator+ () const noexcept { return *this; }
            Color operator- () const noexcept;

            // Properties
            float R() const noexcept { return x; }
            void R(float r) noexcept { x = r; }

            float G() const noexcept { return y; }
            void G(float g) noexcept { y = g; }

            float B() const noexcept { return z; }
            void B(float b) noexcept { z = b; }

            float A() const noexcept { return w; }
            void A(float a) noexcept { w = a; }

            // Color operations
            DirectX::PackedVector::XMCOLOR BGRA() const noexcept;
            DirectX::PackedVector::XMUBYTEN4 RGBA() const noexcept;

            Vector3 ToVector3() const noexcept;
            Vector4 ToVector4() const noexcept;

            void Negate() noexcept;
            void Negate(Color& result) const noexcept;

            void Saturate() noexcept;
            void Saturate(Color& result) const noexcept;

            void Premultiply() noexcept;
            void Premultiply(Color& result) const noexcept;

            void AdjustSaturation(float sat) noexcept;
            void AdjustSaturation(float sat, Color& result) const noexcept;

            void AdjustContrast(float contrast) noexcept;
            void AdjustContrast(float contrast, Color& result) const noexcept;

            // Static functions
            static void Modulate(const Color& c1, const Color& c2, Color& result) noexcept;
            static Color Modulate(const Color& c1, const Color& c2) noexcept;

            static void Lerp(const Color& c1, const Color& c2, float t, Color& result) noexcept;
            static Color Lerp(const Color& c1, const Color& c2, float t) noexcept;
        };

        // Binary operators
        Color operator+ (const Color& C1, const Color& C2) noexcept;
        Color operator- (const Color& C1, const Color& C2) noexcept;
        Color operator* (const Color& C1, const Color& C2) noexcept;
        Color operator* (const Color& C, float S) noexcept;
        Color operator/ (const Color& C1, const Color& C2) noexcept;
        Color operator* (float S, const Color& C) noexcept;

        //------------------------------------------------------------------------------
        // Ray
        class Ray
        {
        public:
            Vector3 position;
            Vector3 direction;

            Ray() noexcept : position(0, 0, 0), direction(0, 0, 1) {}
            Ray(const Vector3& pos, const Vector3& dir) noexcept : position(pos), direction(dir) {}

            Ray(const Ray&) = default;
            Ray& operator=(const Ray&) = default;

            Ray(Ray&&) = default;
            Ray& operator=(Ray&&) = default;

            // Comparison operators
            bool operator == (const Ray& r) const noexcept;
            bool operator != (const Ray& r) const noexcept;

            // Ray operations
            bool Intersects(const BoundingSphere& sphere, _Out_ float& Dist) const noexcept;
            bool Intersects(const BoundingBox& box, _Out_ float& Dist) const noexcept;
            bool Intersects(const Vector3& tri0, const Vector3& tri1, const Vector3& tri2, _Out_ float& Dist) const noexcept;
            bool Intersects(const Plane& plane, _Out_ float& Dist) const noexcept;
        };

        //------------------------------------------------------------------------------
        // Viewport
        class Viewport
        {
        public:
            float x;
            float y;
            float width;
            float height;
            float minDepth;
            float maxDepth;

            Viewport() noexcept :
                x(0.f), y(0.f), width(0.f), height(0.f), minDepth(0.f), maxDepth(1.f)
            {
            }
            constexpr Viewport(float ix, float iy, float iw, float ih, float iminz = 0.f, float imaxz = 1.f) noexcept :
                x(ix), y(iy), width(iw), height(ih), minDepth(iminz), maxDepth(imaxz)
            {
            }
            explicit Viewport(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)
            {
            }

#if defined(__d3d11_h__) || defined(__d3d11_x_h__)
            // Direct3D 11 interop
            explicit Viewport(const D3D11_VIEWPORT& vp) noexcept :
                x(vp.TopLeftX), y(vp.TopLeftY),
                width(vp.Width), height(vp.Height),
                minDepth(vp.MinDepth), maxDepth(vp.MaxDepth)
            {
            }

            operator D3D11_VIEWPORT() noexcept { return *reinterpret_cast<const D3D11_VIEWPORT*>(this); }
            const D3D11_VIEWPORT* Get11() const noexcept { return reinterpret_cast<const D3D11_VIEWPORT*>(this); }
            Viewport& operator= (const D3D11_VIEWPORT& vp) noexcept;
#endif

#if defined(__d3d12_h__) || defined(__d3d12_x_h__) || defined(__XBOX_D3D12_X__)
            // Direct3D 12 interop
            explicit Viewport(const D3D12_VIEWPORT& vp) noexcept :
                x(vp.TopLeftX), y(vp.TopLeftY),
                width(vp.Width), height(vp.Height),
                minDepth(vp.MinDepth), maxDepth(vp.MaxDepth)
            {
            }

            operator D3D12_VIEWPORT() noexcept { return *reinterpret_cast<const D3D12_VIEWPORT*>(this); }
            const D3D12_VIEWPORT* Get12() const noexcept { return reinterpret_cast<const D3D12_VIEWPORT*>(this); }
            Viewport& operator= (const D3D12_VIEWPORT& vp) noexcept;
#endif

            Viewport(const Viewport&) = default;
            Viewport& operator=(const Viewport&) = default;

            Viewport(Viewport&&) = default;
            Viewport& operator=(Viewport&&) = default;

            // Comparison operators
#if (__cplusplus >= 202002L)
            bool operator == (const Viewport&) const = default;
            auto operator <=> (const Viewport&) const = default;
#else
            bool operator == (const Viewport& vp) const noexcept;
            bool operator != (const Viewport& vp) const noexcept;
#endif

            // Assignment operators
            Viewport& operator= (const RECT& rct) noexcept;

            // Viewport operations
            float AspectRatio() const noexcept;

            Vector3 Project(const Vector3& p, const Matrix& proj, const Matrix& view, const Matrix& world) const noexcept;
            void Project(const Vector3& p, const Matrix& proj, const Matrix& view, const Matrix& world, Vector3& result) const noexcept;

            Vector3 Unproject(const Vector3& p, const Matrix& proj, const Matrix& view, const Matrix& world) const noexcept;
            void Unproject(const Vector3& p, const Matrix& proj, const Matrix& view, const Matrix& world, Vector3& result) const noexcept;

            // Static methods
#if defined(__dxgi1_2_h__) || defined(__d3d11_x_h__) || defined(__d3d12_x_h__) || defined(__XBOX_D3D12_X__)
            static RECT __cdecl ComputeDisplayArea(DXGI_SCALING scaling, UINT backBufferWidth, UINT backBufferHeight, int outputWidth, int outputHeight) noexcept;
#endif
            static RECT __cdecl ComputeTitleSafeArea(UINT backBufferWidth, UINT backBufferHeight) noexcept;
        };

#include "SimpleMath.inl"

    } // namespace SimpleMath

} // namespace DirectX

//------------------------------------------------------------------------------
// Support for SimpleMath and Standard C++ Library containers
namespace std
{

    template<> struct less<DirectX::SimpleMath::Rectangle>
    {
        bool operator()(const DirectX::SimpleMath::Rectangle& r1, const DirectX::SimpleMath::Rectangle& r2) const noexcept
        {
            return ((r1.x < r2.x)
                || ((r1.x == r2.x) && (r1.y < r2.y))
                || ((r1.x == r2.x) && (r1.y == r2.y) && (r1.width < r2.width))
                || ((r1.x == r2.x) && (r1.y == r2.y) && (r1.width == r2.width) && (r1.height < r2.height)));
        }
    };

    template<> struct less<DirectX::SimpleMath::Vector2>
    {
        bool operator()(const DirectX::SimpleMath::Vector2& V1, const DirectX::SimpleMath::Vector2& V2) const noexcept
        {
            return ((V1.x < V2.x) || ((V1.x == V2.x) && (V1.y < V2.y)));
        }
    };

    template<> struct less<DirectX::SimpleMath::Vector3>
    {
        bool operator()(const DirectX::SimpleMath::Vector3& V1, const DirectX::SimpleMath::Vector3& V2) const noexcept
        {
            return ((V1.x < V2.x)
                || ((V1.x == V2.x) && (V1.y < V2.y))
                || ((V1.x == V2.x) && (V1.y == V2.y) && (V1.z < V2.z)));
        }
    };

    template<> struct less<DirectX::SimpleMath::Vector4>
    {
        bool operator()(const DirectX::SimpleMath::Vector4& V1, const DirectX::SimpleMath::Vector4& V2) const noexcept
        {
            return ((V1.x < V2.x)
                || ((V1.x == V2.x) && (V1.y < V2.y))
                || ((V1.x == V2.x) && (V1.y == V2.y) && (V1.z < V2.z))
                || ((V1.x == V2.x) && (V1.y == V2.y) && (V1.z == V2.z) && (V1.w < V2.w)));
        }
    };

    template<> struct less<DirectX::SimpleMath::Matrix>
    {
        bool operator()(const DirectX::SimpleMath::Matrix& M1, const DirectX::SimpleMath::Matrix& M2) const noexcept
        {
            if (M1._11 != M2._11) return M1._11 < M2._11;
            if (M1._12 != M2._12) return M1._12 < M2._12;
            if (M1._13 != M2._13) return M1._13 < M2._13;
            if (M1._14 != M2._14) return M1._14 < M2._14;
            if (M1._21 != M2._21) return M1._21 < M2._21;
            if (M1._22 != M2._22) return M1._22 < M2._22;
            if (M1._23 != M2._23) return M1._23 < M2._23;
            if (M1._24 != M2._24) return M1._24 < M2._24;
            if (M1._31 != M2._31) return M1._31 < M2._31;
            if (M1._32 != M2._32) return M1._32 < M2._32;
            if (M1._33 != M2._33) return M1._33 < M2._33;
            if (M1._34 != M2._34) return M1._34 < M2._34;
            if (M1._41 != M2._41) return M1._41 < M2._41;
            if (M1._42 != M2._42) return M1._42 < M2._42;
            if (M1._43 != M2._43) return M1._43 < M2._43;
            if (M1._44 != M2._44) return M1._44 < M2._44;

            return false;
        }
    };

    template<> struct less<DirectX::SimpleMath::Plane>
    {
        bool operator()(const DirectX::SimpleMath::Plane& P1, const DirectX::SimpleMath::Plane& P2) const noexcept
        {
            return ((P1.x < P2.x)
                || ((P1.x == P2.x) && (P1.y < P2.y))
                || ((P1.x == P2.x) && (P1.y == P2.y) && (P1.z < P2.z))
                || ((P1.x == P2.x) && (P1.y == P2.y) && (P1.z == P2.z) && (P1.w < P2.w)));
        }
    };

    template<> struct less<DirectX::SimpleMath::Quaternion>
    {
        bool operator()(const DirectX::SimpleMath::Quaternion& Q1, const DirectX::SimpleMath::Quaternion& Q2) const noexcept
        {
            return ((Q1.x < Q2.x)
                || ((Q1.x == Q2.x) && (Q1.y < Q2.y))
                || ((Q1.x == Q2.x) && (Q1.y == Q2.y) && (Q1.z < Q2.z))
                || ((Q1.x == Q2.x) && (Q1.y == Q2.y) && (Q1.z == Q2.z) && (Q1.w < Q2.w)));
        }
    };

    template<> struct less<DirectX::SimpleMath::Color>
    {
        bool operator()(const DirectX::SimpleMath::Color& C1, const DirectX::SimpleMath::Color& C2) const noexcept
        {
            return ((C1.x < C2.x)
                || ((C1.x == C2.x) && (C1.y < C2.y))
                || ((C1.x == C2.x) && (C1.y == C2.y) && (C1.z < C2.z))
                || ((C1.x == C2.x) && (C1.y == C2.y) && (C1.z == C2.z) && (C1.w < C2.w)));
        }
    };

    template<> struct less<DirectX::SimpleMath::Ray>
    {
        bool operator()(const DirectX::SimpleMath::Ray& R1, const DirectX::SimpleMath::Ray& R2) const noexcept
        {
            if (R1.position.x != R2.position.x) return R1.position.x < R2.position.x;
            if (R1.position.y != R2.position.y) return R1.position.y < R2.position.y;
            if (R1.position.z != R2.position.z) return R1.position.z < R2.position.z;

            if (R1.direction.x != R2.direction.x) return R1.direction.x < R2.direction.x;
            if (R1.direction.y != R2.direction.y) return R1.direction.y < R2.direction.y;
            if (R1.direction.z != R2.direction.z) return R1.direction.z < R2.direction.z;

            return false;
        }
    };

    template<> struct less<DirectX::SimpleMath::Viewport>
    {
        bool operator()(const DirectX::SimpleMath::Viewport& vp1, const DirectX::SimpleMath::Viewport& vp2) const noexcept
        {
            if (vp1.x != vp2.x) return (vp1.x < vp2.x);
            if (vp1.y != vp2.y) return (vp1.y < vp2.y);

            if (vp1.width != vp2.width) return (vp1.width < vp2.width);
            if (vp1.height != vp2.height) return (vp1.height < vp2.height);

            if (vp1.minDepth != vp2.minDepth) return (vp1.minDepth < vp2.minDepth);
            if (vp1.maxDepth != vp2.maxDepth) return (vp1.maxDepth < vp2.maxDepth);

            return false;
        }
    };

} // namespace std

#ifdef __clang__
#pragma clang diagnostic pop
#endif