From 826b0ffdca99dc3c43789b7d21862e593fe1c094 Mon Sep 17 00:00:00 2001 From: Discreater Date: Sun, 11 Jun 2023 15:42:40 +0800 Subject: [PATCH 1/3] add XMMatrixOrthographicOffCenter{L,R}H --- src/matrix.rs | 234 +++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 232 insertions(+), 2 deletions(-) diff --git a/src/matrix.rs b/src/matrix.rs index 99ef2ee..3823f78 100644 --- a/src/matrix.rs +++ b/src/matrix.rs @@ -3463,8 +3463,238 @@ pub fn XMMatrixOrthographicRH( } } -// TODO: XMMatrixOrthographicOffCenterLH -// TODO: XMMatrixOrthographicOffCenterRH +/// Builds a custom version of a left-handed perspective projection matrix. +/// +/// ## Parameters +/// +/// `ViewLeft` The x-coordinate of the left side of the clipping frustum at the near clipping plane. +/// +/// `ViewRight` The x-coordinate of the right side of the clipping frustum at the near clipping plane. +/// +/// `ViewBottom` The y-coordinate of the bottom side of the clipping frustum at the near clipping plane. +/// +/// `ViewTop` The y-coordinate of the top side of the clipping frustum at the near clipping plane. +/// +/// `NearZ` Distance to the near clipping plane. Must be greater than zero. +/// +/// `FarZ` Distance to the far clipping plane. Must be greater than zero. +/// +/// ## Return Values +/// +/// Returns the custom perspective projection matrix. +/// +/// ## Remarks +/// +/// For typical usage, NearZ is less than FarZ. However, if you flip these values so FarZ is less than NearZ, +/// the result is an inverted z buffer (also known as a "reverse z buffer") which can provide increased floating-point precision. +/// +/// NearZ and FarZ cannot be the same value and must be greater than 0. +/// +/// ## Reference +/// +/// +#[inline] +pub fn XMMatrixPerspectiveOffCenterLH( + ViewLeft: f32, + ViewRight: f32, + ViewBottom: f32, + ViewTop: f32, + NearZ: f32, + FarZ: f32, +) -> XMMATRIX { + debug_assert!(NearZ > 0.0 && FarZ > 0.0); + debug_assert!(!XMScalarNearEqual(ViewRight, ViewLeft, 0.00001)); + debug_assert!(!XMScalarNearEqual(ViewTop, ViewBottom, 0.00001)); + debug_assert!(!XMScalarNearEqual(FarZ, NearZ, 0.00001)); + + #[cfg(_XM_NO_INTRINSICS_)] + unsafe { + let TwoNearZ = NearZ + NearZ; + let ReciprocalWidth = 1.0 / (ViewRight - ViewLeft); + let ReciprocalHeight = 1.0 / (ViewTop - ViewBottom); + let fRange = FarZ / (FarZ - NearZ); + + let mut M: XMMATRIX = crate::undefined(); + M.m[0][0] = TwoNearZ * ReciprocalWidth; + M.m[0][1] = 0.0; + M.m[0][2] = 0.0; + M.m[0][3] = 0.0; + + M.m[1][0] = 0.0; + M.m[1][1] = TwoNearZ * ReciprocalHeight; + M.m[1][2] = 0.0; + M.m[1][3] = 0.0; + + M.m[2][0] = -(ViewLeft + ViewRight) * ReciprocalWidth; + M.m[2][1] = -(ViewTop + ViewBottom) * ReciprocalHeight; + M.m[2][2] = fRange; + M.m[2][3] = 1.0; + + M.m[3][0] = 0.0; + M.m[3][1] = 0.0; + M.m[3][2] = -fRange * NearZ; + M.m[3][3] = 0.0; + return M; + } + + #[cfg(_XM_ARM_NEON_INTRINSICS_)] + { + unimplemented!() + } + + #[cfg(_XM_SSE_INTRINSICS_)] + unsafe { + let mut M: XMMATRIX = crate::undefined(); + let TwoNearZ = NearZ + NearZ; + let ReciprocalWidth = 1.0 / (ViewRight - ViewLeft); + let ReciprocalHeight = 1.0 / (ViewTop - ViewBottom); + let fRange = FarZ / (FarZ - NearZ); + // Note: This is recorded on the stack + let rMem: XMVECTORF32 = XMVECTORF32 { f: [ + TwoNearZ * ReciprocalWidth, + TwoNearZ * ReciprocalHeight, + -fRange, + 0.0, + ]}; + // Copy from memory to SSE register + let mut vValues: XMVECTOR = rMem.v; + let mut vTemp: XMVECTOR = _mm_setzero_ps(); + // Copy x only + vTemp = _mm_move_ss(vTemp, vValues); + // TwoNearZ * ReciprocalWidth,0,0,0 + M.r[0] = vTemp; + // 0,TwoNearZ * ReciprocalHeight,0,0 + vTemp = vValues; + vTemp = _mm_and_ps(vTemp, *g_XMMaskY); + M.r[1] = vTemp; + // 0,0,fRange,1.0f + M.r[2] = XMVectorSet(-(ViewLeft + ViewRight) * ReciprocalWidth, + -(ViewTop + ViewBottom) * ReciprocalHeight, + fRange, + 1.0); + // 0,0,-fRange * NearZ,0.0f + vValues = _mm_and_ps(vValues, *g_XMMaskZ); + M.r[3] = vValues; + return M; + } +} + + +/// Builds a custom version of a right-handed perspective projection matrix. +/// +/// ## Parameters +/// +/// `ViewLeft` The x-coordinate of the left side of the clipping frustum at the near clipping plane. +/// +/// `ViewRight` The x-coordinate of the right side of the clipping frustum at the near clipping plane. +/// +/// `ViewBottom` The y-coordinate of the bottom side of the clipping frustum at the near clipping plane. +/// +/// `ViewTop` The y-coordinate of the top side of the clipping frustum at the near clipping plane. +/// +/// `NearZ` Distance to the near clipping plane. Must be greater than zero. +/// +/// `FarZ` Distance to the far clipping plane. Must be greater than zero. +/// +/// ## Return value +/// +/// Returns the custom perspective projection matrix. +/// +/// ## Remarks +/// +/// For typical usage, NearZ is less than FarZ. However, if you flip these values so FarZ is less than NearZ, +/// the result is an inverted z buffer (also known as a "reverse z buffer") which can provide increased floating-point precision. +/// +/// NearZ and FarZ cannot be the same value and must be greater than 0. +/// +/// ## Reference +/// +/// +#[inline] +pub fn XMMatrixPerspectiveOffCenterRH( + ViewLeft: f32, + ViewRight: f32, + ViewBottom: f32, + ViewTop: f32, + NearZ: f32, + FarZ: f32, +) -> XMMATRIX { + debug_assert!(NearZ > 0.0 && FarZ > 0.0); + debug_assert!(!XMScalarNearEqual(ViewRight, ViewLeft, 0.00001)); + debug_assert!(!XMScalarNearEqual(ViewTop, ViewBottom, 0.00001)); + debug_assert!(!XMScalarNearEqual(FarZ, NearZ, 0.00001)); + + #[cfg(_XM_NO_INTRINSICS_)] + unsafe { + let TwoNearZ = NearZ + NearZ; + let ReciprocalWidth = 1.0 / (ViewRight - ViewLeft); + let ReciprocalHeight = 1.0 / (ViewTop - ViewBottom); + let fRange = FarZ / (NearZ - FarZ); + + let mut M: XMMATRIX = crate::undefined(); + M.m[0][0] = TwoNearZ * ReciprocalWidth; + M.m[0][1] = 0.0; + M.m[0][2] = 0.0; + M.m[0][3] = 0.0; + + M.m[1][0] = 0.0; + M.m[1][1] = TwoNearZ * ReciprocalHeight; + M.m[1][2] = 0.0; + M.m[1][3] = 0.0; + + M.m[2][0] = (ViewLeft + ViewRight) * ReciprocalWidth; + M.m[2][1] = (ViewTop + ViewBottom) * ReciprocalHeight; + M.m[2][2] = fRange; + M.m[2][3] = -1.0; + + M.m[3][0] = 0.0; + M.m[3][1] = 0.0; + M.m[3][2] = fRange * NearZ; + M.m[3][3] = 0.0; + return M; + } + + #[cfg(_XM_ARM_NEON_INTRINSICS_)] + { + unimplemented!() + } + + #[cfg(_XM_SSE_INTRINSICS_)] + unsafe { + let mut M: XMMATRIX = crate::undefined(); + let TwoNearZ = NearZ + NearZ; + let ReciprocalWidth = 1.0 / (ViewRight - ViewLeft); + let ReciprocalHeight = 1.0 / (ViewTop - ViewBottom); + let fRange = FarZ / (NearZ - FarZ); + // Note: This is recorded on the stack + let rMem: XMVECTORF32 = XMVECTORF32 { f: [ + TwoNearZ * ReciprocalWidth, + TwoNearZ * ReciprocalHeight, + fRange * NearZ, + 0.0, + ]}; + // Copy from memory to SSE register + let mut vValues: XMVECTOR = rMem.v; + let mut vTemp: XMVECTOR = _mm_setzero_ps(); + // Copy x only + vTemp = _mm_move_ss(vTemp, vValues); + // TwoNearZ*ReciprocalWidth,0,0,0 + M.r[0] = vTemp; + // 0,TwoNearZ*ReciprocalHeight,0,0 + vTemp = vValues; + vTemp = _mm_and_ps(vTemp, *g_XMMaskY); + M.r[1] = vTemp; + // 0,0,fRange,1.0f + M.r[2] = XMVectorSet((ViewLeft + ViewRight) * ReciprocalWidth, + (ViewTop + ViewBottom) * ReciprocalHeight, + fRange, + -1.0); + // 0,0,-fRange * NearZ,0.0f + vValues = _mm_and_ps(vValues, *g_XMMaskZ); + M.r[3] = vValues; + return M; + } +} impl std::ops::Deref for XMMatrix { type Target = XMMATRIX; From 1430a26f7b6d98559cb006e3d9afa6519f2d71a2 Mon Sep 17 00:00:00 2001 From: Arthur Brainville Date: Mon, 30 Oct 2023 15:25:23 +0100 Subject: [PATCH 2/3] XMMatrixPerspectiveOffCenterLH : Fix math error in SSE path (#1) * XMMatrixPerspectiveOffCenterLH : Fix math error in SSE path * delete now completed todo items --- src/matrix.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/matrix.rs b/src/matrix.rs index 3823f78..d77924c 100644 --- a/src/matrix.rs +++ b/src/matrix.rs @@ -3258,9 +3258,6 @@ pub fn XMMatrixPerspectiveFovRH( } } -// TODO: XMMatrixPerspectiveOffCenterLH -// TODO: XMMatrixPerspectiveOffCenterRH - /// Builds an orthogonal projection matrix for a left-handed coordinate system. /// /// ## Parameters @@ -3553,7 +3550,7 @@ pub fn XMMatrixPerspectiveOffCenterLH( let rMem: XMVECTORF32 = XMVECTORF32 { f: [ TwoNearZ * ReciprocalWidth, TwoNearZ * ReciprocalHeight, - -fRange, + -fRange * NearZ, 0.0, ]}; // Copy from memory to SSE register From e588f21a5709d0f66f1d8d4b4c5b4c9b5d952bde Mon Sep 17 00:00:00 2001 From: Discreater Date: Mon, 30 Oct 2023 22:36:31 +0800 Subject: [PATCH 3/3] move `perspective off center` to correct place --- src/lib.rs | 4 +- src/matrix.rs | 407 +++++++++++++++++++++++++------------------------- 2 files changed, 207 insertions(+), 204 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 3facff3..b66a5af 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -649,8 +649,8 @@ mod doc { pub use crate::matrix::XMMatrixPerspectiveFovLH; pub use crate::matrix::XMMatrixPerspectiveFovRH; pub use crate::matrix::XMMatrixPerspectiveLH; - // TODO: pub use crate::matrix::XMMatrixPerspectiveOffCenterLH; - // TODO: pub use crate::matrix::XMMatrixPerspectiveOffCenterRH; + pub use crate::matrix::XMMatrixPerspectiveOffCenterLH; + pub use crate::matrix::XMMatrixPerspectiveOffCenterRH; pub use crate::matrix::XMMatrixPerspectiveRH; pub use crate::matrix::XMMatrixReflect; pub use crate::matrix::XMMatrixRotationAxis; diff --git a/src/matrix.rs b/src/matrix.rs index d77924c..4c78e25 100644 --- a/src/matrix.rs +++ b/src/matrix.rs @@ -3258,208 +3258,6 @@ pub fn XMMatrixPerspectiveFovRH( } } -/// Builds an orthogonal projection matrix for a left-handed coordinate system. -/// -/// ## Parameters -/// -/// `ViewWidth` Width of the frustum at the near clipping plane. -/// -/// `ViewHeight` Height of the frustum at the near clipping plane. -/// -/// `NearZ` Distance to the near clipping plane. -/// -/// `FarZ` Distance to the far clipping plane. -/// -/// ## Return value -/// -/// Returns the orthogonal projection matrix. -/// -/// ## Remarks -/// -/// All the parameters of XMMatrixOrthographicLH are distances in camera space. -/// -/// ## Reference -/// -/// -#[inline] -pub fn XMMatrixOrthographicLH( - ViewWidth: f32, - ViewHeight: f32, - NearZ: f32, - FarZ: f32 -) -> XMMATRIX -{ - debug_assert!(!XMScalarNearEqual(ViewWidth, 0.0, 0.00001)); - debug_assert!(!XMScalarNearEqual(ViewHeight, 0.0, 0.00001)); - debug_assert!(!XMScalarNearEqual(FarZ, NearZ, 0.00001)); - - #[cfg(_XM_NO_INTRINSICS_)] - unsafe { - let fRange: f32 = 1.0 / (FarZ - NearZ); - let mut M: XMMATRIX = crate::undefined(); - M.m[0][0] = 2.0 / ViewWidth; - M.m[0][1] = 0.0; - M.m[0][2] = 0.0; - M.m[0][3] = 0.0; - - M.m[1][0] = 0.0; - M.m[1][1] = 2.0 / ViewHeight; - M.m[1][2] = 0.0; - M.m[1][3] = 0.0; - - M.m[2][0] = 0.0; - M.m[2][1] = 0.0; - M.m[2][2] = fRange; - M.m[2][3] = 0.0; - - M.m[3][0] = 0.0; - M.m[3][1] = 0.0; - M.m[3][2] = -fRange * NearZ; - M.m[3][3] = 1.0; - return M; - } - - #[cfg(_XM_ARM_NEON_INTRINSICS_)] - { - unimplemented!() - } - - #[cfg(_XM_SSE_INTRINSICS_)] - unsafe { - let mut M: XMMATRIX = crate::undefined(); - let fRange: f32 = 1.0 / (FarZ - NearZ); - // Note: This is recorded on the stack - let rMem: XMVECTORF32 = XMVECTORF32 { f: [ - 2.0 / ViewWidth, - 2.0 / ViewHeight, - fRange, - -fRange * NearZ - ]}; - // Copy from memory to SSE register - let mut vValues: XMVECTOR = rMem.v; - let mut vTemp: XMVECTOR = _mm_setzero_ps(); - // Copy x only - vTemp = _mm_move_ss(vTemp, vValues); - // 2.0f / ViewWidth,0,0,0 - M.r[0] = vTemp; - // 0,2.0f / ViewHeight,0,0 - vTemp = vValues; - vTemp = _mm_and_ps(vTemp, *g_XMMaskY); - M.r[1] = vTemp; - // x=fRange,y=-fRange * NearZ,0,1.0f - vTemp = _mm_setzero_ps(); - vValues = _mm_shuffle_ps(vValues, *g_XMIdentityR3, _MM_SHUFFLE(3, 2, 3, 2)); - // 0,0,fRange,0.0f - vTemp = _mm_shuffle_ps(vTemp, vValues, _MM_SHUFFLE(2, 0, 0, 0)); - M.r[2] = vTemp; - // 0,0,-fRange * NearZ,1.0f - vTemp = _mm_shuffle_ps(vTemp, vValues, _MM_SHUFFLE(3, 1, 0, 0)); - M.r[3] = vTemp; - return M; - } -} - -/// Builds an orthogonal projection matrix for a right-handed coordinate system. -/// -/// ## Parameters -/// -/// `ViewWidth` Width of the frustum at the near clipping plane. -/// -/// `ViewHeight` Height of the frustum at the near clipping plane. -/// -/// `NearZ` Distance to the near clipping plane. -/// -/// `FarZ` Distance to the far clipping plane. -/// -/// ## Return value -/// -/// Returns the orthogonal projection matrix. -/// -/// ## Remarks -/// -/// All the parameters of XMMatrixOrthographicRH are distances in camera space. -/// -/// ## Reference -/// -/// -#[inline] -pub fn XMMatrixOrthographicRH( - ViewWidth: f32, - ViewHeight: f32, - NearZ: f32, - FarZ: f32 -) -> XMMATRIX -{ - debug_assert!(!XMScalarNearEqual(ViewWidth, 0.0, 0.00001)); - debug_assert!(!XMScalarNearEqual(ViewHeight, 0.0, 0.00001)); - debug_assert!(!XMScalarNearEqual(FarZ, NearZ, 0.00001)); - - #[cfg(_XM_NO_INTRINSICS_)] - unsafe { - let fRange: f32 = 1.0 / (NearZ - FarZ); - let mut M: XMMATRIX = crate::undefined(); - M.m[0][0] = 2.0 / ViewWidth; - M.m[0][1] = 0.0; - M.m[0][2] = 0.0; - M.m[0][3] = 0.0; - - M.m[1][0] = 0.0; - M.m[1][1] = 2.0 / ViewHeight; - M.m[1][2] = 0.0; - M.m[1][3] = 0.0; - - M.m[2][0] = 0.0; - M.m[2][1] = 0.0; - M.m[2][2] = fRange; - M.m[2][3] = 0.0; - - M.m[3][0] = 0.0; - M.m[3][1] = 0.0; - M.m[3][2] = fRange * NearZ; - M.m[3][3] = 1.0; - return M; - } - - #[cfg(_XM_ARM_NEON_INTRINSICS_)] - { - unimplemented!() - } - - #[cfg(_XM_SSE_INTRINSICS_)] - unsafe { - let mut M: XMMATRIX = crate::undefined(); - let fRange: f32 = 1.0 / (NearZ - FarZ); - // Note: This is recorded on the stack - let rMem: XMVECTORF32 = XMVECTORF32 { f: [ - 2.0 / ViewWidth, - 2.0 / ViewHeight, - fRange, - fRange * NearZ - ]}; - // Copy from memory to SSE register - let mut vValues: XMVECTOR = rMem.v; - let mut vTemp: XMVECTOR = _mm_setzero_ps(); - // Copy x only - vTemp = _mm_move_ss(vTemp, vValues); - // 2.0f / ViewWidth,0,0,0 - M.r[0] = vTemp; - // 0,2.0f / ViewHeight,0,0 - vTemp = vValues; - vTemp = _mm_and_ps(vTemp, *g_XMMaskY); - M.r[1] = vTemp; - // x=fRange,y=fRange * NearZ,0,1.0f - vTemp = _mm_setzero_ps(); - vValues = _mm_shuffle_ps(vValues, *g_XMIdentityR3, _MM_SHUFFLE(3, 2, 3, 2)); - // 0,0,fRange,0.0f - vTemp = _mm_shuffle_ps(vTemp, vValues, _MM_SHUFFLE(2, 0, 0, 0)); - M.r[2] = vTemp; - // 0,0,fRange * NearZ,1.0f - vTemp = _mm_shuffle_ps(vTemp, vValues, _MM_SHUFFLE(3, 1, 0, 0)); - M.r[3] = vTemp; - return M; - } -} - /// Builds a custom version of a left-handed perspective projection matrix. /// /// ## Parameters @@ -3693,6 +3491,211 @@ pub fn XMMatrixPerspectiveOffCenterRH( } } +/// Builds an orthogonal projection matrix for a left-handed coordinate system. +/// +/// ## Parameters +/// +/// `ViewWidth` Width of the frustum at the near clipping plane. +/// +/// `ViewHeight` Height of the frustum at the near clipping plane. +/// +/// `NearZ` Distance to the near clipping plane. +/// +/// `FarZ` Distance to the far clipping plane. +/// +/// ## Return value +/// +/// Returns the orthogonal projection matrix. +/// +/// ## Remarks +/// +/// All the parameters of XMMatrixOrthographicLH are distances in camera space. +/// +/// ## Reference +/// +/// +#[inline] +pub fn XMMatrixOrthographicLH( + ViewWidth: f32, + ViewHeight: f32, + NearZ: f32, + FarZ: f32 +) -> XMMATRIX +{ + debug_assert!(!XMScalarNearEqual(ViewWidth, 0.0, 0.00001)); + debug_assert!(!XMScalarNearEqual(ViewHeight, 0.0, 0.00001)); + debug_assert!(!XMScalarNearEqual(FarZ, NearZ, 0.00001)); + + #[cfg(_XM_NO_INTRINSICS_)] + unsafe { + let fRange: f32 = 1.0 / (FarZ - NearZ); + let mut M: XMMATRIX = crate::undefined(); + M.m[0][0] = 2.0 / ViewWidth; + M.m[0][1] = 0.0; + M.m[0][2] = 0.0; + M.m[0][3] = 0.0; + + M.m[1][0] = 0.0; + M.m[1][1] = 2.0 / ViewHeight; + M.m[1][2] = 0.0; + M.m[1][3] = 0.0; + + M.m[2][0] = 0.0; + M.m[2][1] = 0.0; + M.m[2][2] = fRange; + M.m[2][3] = 0.0; + + M.m[3][0] = 0.0; + M.m[3][1] = 0.0; + M.m[3][2] = -fRange * NearZ; + M.m[3][3] = 1.0; + return M; + } + + #[cfg(_XM_ARM_NEON_INTRINSICS_)] + { + unimplemented!() + } + + #[cfg(_XM_SSE_INTRINSICS_)] + unsafe { + let mut M: XMMATRIX = crate::undefined(); + let fRange: f32 = 1.0 / (FarZ - NearZ); + // Note: This is recorded on the stack + let rMem: XMVECTORF32 = XMVECTORF32 { f: [ + 2.0 / ViewWidth, + 2.0 / ViewHeight, + fRange, + -fRange * NearZ + ]}; + // Copy from memory to SSE register + let mut vValues: XMVECTOR = rMem.v; + let mut vTemp: XMVECTOR = _mm_setzero_ps(); + // Copy x only + vTemp = _mm_move_ss(vTemp, vValues); + // 2.0f / ViewWidth,0,0,0 + M.r[0] = vTemp; + // 0,2.0f / ViewHeight,0,0 + vTemp = vValues; + vTemp = _mm_and_ps(vTemp, *g_XMMaskY); + M.r[1] = vTemp; + // x=fRange,y=-fRange * NearZ,0,1.0f + vTemp = _mm_setzero_ps(); + vValues = _mm_shuffle_ps(vValues, *g_XMIdentityR3, _MM_SHUFFLE(3, 2, 3, 2)); + // 0,0,fRange,0.0f + vTemp = _mm_shuffle_ps(vTemp, vValues, _MM_SHUFFLE(2, 0, 0, 0)); + M.r[2] = vTemp; + // 0,0,-fRange * NearZ,1.0f + vTemp = _mm_shuffle_ps(vTemp, vValues, _MM_SHUFFLE(3, 1, 0, 0)); + M.r[3] = vTemp; + return M; + } +} + +/// Builds an orthogonal projection matrix for a right-handed coordinate system. +/// +/// ## Parameters +/// +/// `ViewWidth` Width of the frustum at the near clipping plane. +/// +/// `ViewHeight` Height of the frustum at the near clipping plane. +/// +/// `NearZ` Distance to the near clipping plane. +/// +/// `FarZ` Distance to the far clipping plane. +/// +/// ## Return value +/// +/// Returns the orthogonal projection matrix. +/// +/// ## Remarks +/// +/// All the parameters of XMMatrixOrthographicRH are distances in camera space. +/// +/// ## Reference +/// +/// +#[inline] +pub fn XMMatrixOrthographicRH( + ViewWidth: f32, + ViewHeight: f32, + NearZ: f32, + FarZ: f32 +) -> XMMATRIX +{ + debug_assert!(!XMScalarNearEqual(ViewWidth, 0.0, 0.00001)); + debug_assert!(!XMScalarNearEqual(ViewHeight, 0.0, 0.00001)); + debug_assert!(!XMScalarNearEqual(FarZ, NearZ, 0.00001)); + + #[cfg(_XM_NO_INTRINSICS_)] + unsafe { + let fRange: f32 = 1.0 / (NearZ - FarZ); + let mut M: XMMATRIX = crate::undefined(); + M.m[0][0] = 2.0 / ViewWidth; + M.m[0][1] = 0.0; + M.m[0][2] = 0.0; + M.m[0][3] = 0.0; + + M.m[1][0] = 0.0; + M.m[1][1] = 2.0 / ViewHeight; + M.m[1][2] = 0.0; + M.m[1][3] = 0.0; + + M.m[2][0] = 0.0; + M.m[2][1] = 0.0; + M.m[2][2] = fRange; + M.m[2][3] = 0.0; + + M.m[3][0] = 0.0; + M.m[3][1] = 0.0; + M.m[3][2] = fRange * NearZ; + M.m[3][3] = 1.0; + return M; + } + + #[cfg(_XM_ARM_NEON_INTRINSICS_)] + { + unimplemented!() + } + + #[cfg(_XM_SSE_INTRINSICS_)] + unsafe { + let mut M: XMMATRIX = crate::undefined(); + let fRange: f32 = 1.0 / (NearZ - FarZ); + // Note: This is recorded on the stack + let rMem: XMVECTORF32 = XMVECTORF32 { f: [ + 2.0 / ViewWidth, + 2.0 / ViewHeight, + fRange, + fRange * NearZ + ]}; + // Copy from memory to SSE register + let mut vValues: XMVECTOR = rMem.v; + let mut vTemp: XMVECTOR = _mm_setzero_ps(); + // Copy x only + vTemp = _mm_move_ss(vTemp, vValues); + // 2.0f / ViewWidth,0,0,0 + M.r[0] = vTemp; + // 0,2.0f / ViewHeight,0,0 + vTemp = vValues; + vTemp = _mm_and_ps(vTemp, *g_XMMaskY); + M.r[1] = vTemp; + // x=fRange,y=fRange * NearZ,0,1.0f + vTemp = _mm_setzero_ps(); + vValues = _mm_shuffle_ps(vValues, *g_XMIdentityR3, _MM_SHUFFLE(3, 2, 3, 2)); + // 0,0,fRange,0.0f + vTemp = _mm_shuffle_ps(vTemp, vValues, _MM_SHUFFLE(2, 0, 0, 0)); + M.r[2] = vTemp; + // 0,0,fRange * NearZ,1.0f + vTemp = _mm_shuffle_ps(vTemp, vValues, _MM_SHUFFLE(3, 1, 0, 0)); + M.r[3] = vTemp; + return M; + } +} + +// TODO: XMMatrixOrthographicOffCenterLH +// TODO: XMMatrixOrthographicOffCenterRH + impl std::ops::Deref for XMMatrix { type Target = XMMATRIX; #[inline(always)]