directx_math/misc.rs
1use crate::*;
2
3/// Tests whether two quaternions are equal.
4///
5/// ## Parameters
6///
7/// `Q1` First quaternion to test.
8///
9/// `Q2` Second quaternion to test.
10///
11/// ## Return value
12///
13/// Returns `true` if the quaternions are equal and `false` otherwise.
14///
15/// ## Remarks
16///
17/// The DirectXMath quaternion functions use an XMVECTOR 4-vector to represent quaternions, where the `X`,
18/// `Y`, and `Z` components are the vector part and the `W` component is the scalar part.
19///
20/// ## Reference
21///
22/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMQuaternionEqual>
23#[inline]
24pub fn XMQuaternionEqual(
25 Q1: FXMVECTOR,
26 Q2: FXMVECTOR,
27) -> bool
28{
29 return XMVector4Equal(Q1, Q2);
30}
31
32/// Tests whether two quaternions are not equal.
33///
34/// ## Parameters
35///
36/// `Q1` First quaternion to test.
37///
38/// `Q2` Second quaternion to test.
39///
40/// ## Return value
41///
42/// Returns `true` if the quaternions are unequal and `false` otherwise.
43///
44/// ## Remarks
45///
46/// The DirectXMath quaternion functions use an XMVECTOR 4-vector to represent quaternions, where the `X`,
47/// `Y`, and `Z` components are the vector part and the `W` component is the scalar part.
48///
49/// ## Reference
50///
51/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMQuaternionNotEqual>
52#[inline]
53pub fn XMQuaternionNotEqual(
54 Q1: FXMVECTOR,
55 Q2: FXMVECTOR,
56) -> bool
57{
58 return XMVector4NotEqual(Q1, Q2);
59}
60
61/// Test whether any component of a quaternion is a NaN.
62///
63/// ## Parameters
64///
65/// `Q` Quaternion to test.
66///
67/// ## Return value
68///
69/// Returns `true` if any component of `Q` is a `NaN`, and `false` otherwise.
70///
71/// ## Remarks
72///
73/// The DirectXMath quaternion functions use an XMVECTOR 4-vector to represent quaternions, where the `X`,
74/// `Y`, and `Z` components are the vector part and the `W` component is the scalar part.
75///
76/// ## Reference
77///
78/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMQuaternionIsNaN>
79#[inline]
80pub fn XMQuaternionIsNaN(
81 Q: FXMVECTOR,
82) -> bool
83{
84 return XMVector4IsNaN(Q);
85}
86
87/// Test whether any component of a quaternion is either positive or negative infinity.
88///
89/// ## Parameters
90///
91/// `Q` Quaternion to test.
92///
93/// ## Return value
94///
95/// Returns `true` if any component of `Q` is positive or negative infinity, and `false` otherwise.
96///
97/// ## Remarks
98///
99/// The DirectXMath quaternion functions use an XMVECTOR 4-vector to represent quaternions, where the `X`,
100/// `Y`, and `Z` components are the vector part and the `W` component is the scalar part.
101///
102/// ## Reference
103///
104/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMQuaternionIsInfinite>
105#[inline]
106pub fn XMQuaternionIsInfinite(
107 Q: FXMVECTOR,
108) -> bool
109{
110 return XMVector4IsInfinite(Q);
111}
112
113/// Tests whether a specific quaternion is the identity quaternion.
114///
115/// ## Parameters
116///
117/// `Q` Quaternion to test.
118///
119/// ## Return value
120///
121/// Returns `true` if `Q` is the identity quaternion, or `false` otherwise.
122///
123/// ## Remarks
124///
125/// The DirectXMath quaternion functions use an XMVECTOR 4-vector to represent quaternions, where the `X`,
126/// `Y`, and `Z` components are the vector part and the `W` component is the scalar part.
127///
128/// ## Reference
129///
130/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMQuaternionIsIdentity>
131#[inline]
132pub fn XMQuaternionIsIdentity(
133 Q: FXMVECTOR,
134) -> bool
135{
136 unsafe {
137 return XMVector4Equal(Q, g_XMIdentityR3.v);
138 }
139}
140
141/// Computes the dot product of two quaternions.
142///
143/// ## Parameters
144///
145/// `Q1` First quaternion
146///
147/// `Q2` Second quaternion.
148///
149/// ## Return value
150///
151/// Returns a vector. The dot product between `Q1` and `Q2` is replicated into each component.
152///
153/// ## Remarks
154///
155/// The DirectXMath quaternion functions use an XMVECTOR 4-vector to represent quaternions, where
156/// the `X`, `Y`, and `Z` components are the vector part and the `W` component is the scalar part.
157///
158/// ## Reference
159///
160/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMQuaternionDot>
161#[inline]
162pub fn XMQuaternionDot(
163 Q1: FXMVECTOR,
164 Q2: FXMVECTOR,
165) -> FXMVECTOR
166{
167 return XMVector4Dot(Q1, Q2);
168}
169
170/// Computes the product of two quaternions.
171///
172/// ## Parameters
173///
174/// `Q1` First quaternion.
175///
176/// `Q2` Second quaternion.
177///
178/// ## Return Value
179///
180/// Returns the product of two quaternions as `Q2*Q1`.
181///
182/// ## Remarks
183///
184/// The DirectXMath quaternion functions use an XMVECTOR 4-vector to represent
185/// quaternions, where the `X`, `Y`, and `Z` components are the vector part and
186/// the `W` component is the scalar part.
187///
188/// The result represents the rotation `Q1` followed by the rotation `Q2` to be
189/// consistent with [`XMMatrixMultiply`] concatenation since this function is
190/// typically used to concatenate quaternions that represent rotations
191/// (i.e. it returns `Q2*Q1`).
192///
193/// This function computes the equivalent to the following pseduo-code:
194///
195/// ```text
196/// XMVECTOR Result;
197/// Result.x = (Q2.w * Q1.x) + (Q2.x * Q1.w) + (Q2.y * Q1.z) - (Q2.z * Q1.y);
198/// Result.y = (Q2.w * Q1.y) - (Q2.x * Q1.z) + (Q2.y * Q1.w) + (Q2.z * Q1.x);
199/// Result.z = (Q2.w * Q1.z) + (Q2.x * Q1.y) - (Q2.y * Q1.x) + (Q2.z * Q1.w);
200/// Result.w = (Q2.w * Q1.w) - (Q2.x * Q1.x) - (Q2.y * Q1.y) - (Q2.z * Q1.z);
201/// return Result;
202/// ```
203///
204/// ## Reference
205///
206/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMQuaternionMultiply>
207///
208/// [`XMMatrixMultiply`]: crate::matrix::XMMatrixMultiply
209#[inline]
210pub fn XMQuaternionMultiply(
211 Q1: FXMVECTOR,
212 Q2: FXMVECTOR,
213) -> FXMVECTOR
214{
215 #[cfg(_XM_NO_INTRINSICS_)]
216 unsafe {
217 let Result = XMVECTORF32 {
218 f: [
219 (Q2.vector4_f32[3] * Q1.vector4_f32[0]) + (Q2.vector4_f32[0] * Q1.vector4_f32[3]) + (Q2.vector4_f32[1] * Q1.vector4_f32[2]) - (Q2.vector4_f32[2] * Q1.vector4_f32[1]),
220 (Q2.vector4_f32[3] * Q1.vector4_f32[1]) - (Q2.vector4_f32[0] * Q1.vector4_f32[2]) + (Q2.vector4_f32[1] * Q1.vector4_f32[3]) + (Q2.vector4_f32[2] * Q1.vector4_f32[0]),
221 (Q2.vector4_f32[3] * Q1.vector4_f32[2]) + (Q2.vector4_f32[0] * Q1.vector4_f32[1]) - (Q2.vector4_f32[1] * Q1.vector4_f32[0]) + (Q2.vector4_f32[2] * Q1.vector4_f32[3]),
222 (Q2.vector4_f32[3] * Q1.vector4_f32[3]) - (Q2.vector4_f32[0] * Q1.vector4_f32[0]) - (Q2.vector4_f32[1] * Q1.vector4_f32[1]) - (Q2.vector4_f32[2] * Q1.vector4_f32[2])
223 ]
224 };
225 return Result.v;
226 }
227
228 #[cfg(_XM_ARM_NEON_INTRINSICS_)]
229 {
230 unimplemented!()
231 }
232
233 #[cfg(_XM_SSE_INTRINSICS_)]
234 unsafe {
235 // TODO: (PERFORMANCE) These are defined as static const. Does it matter?
236 const ControlWZYX: XMVECTORF32 = XMVECTORF32 { f: [ 1.0, -1.0, 1.0, -1.0 ] };
237 const ControlZWXY: XMVECTORF32 = XMVECTORF32 { f: [ 1.0, 1.0, -1.0, -1.0 ] };
238 const ControlYXWZ: XMVECTORF32 = XMVECTORF32 { f: [ -1.0, 1.0, 1.0, -1.0 ] };
239 // Copy to SSE registers and use as few as possible for x86
240 let mut Q2X: XMVECTOR = Q2;
241 let mut Q2Y: XMVECTOR = Q2;
242 let mut Q2Z: XMVECTOR = Q2;
243 let mut vResult: XMVECTOR = Q2;
244 // Splat with one instruction
245 vResult = XM_PERMUTE_PS!(vResult, _MM_SHUFFLE(3, 3, 3, 3));
246 Q2X = XM_PERMUTE_PS!(Q2X, _MM_SHUFFLE(0, 0, 0, 0));
247 Q2Y = XM_PERMUTE_PS!(Q2Y, _MM_SHUFFLE(1, 1, 1, 1));
248 Q2Z = XM_PERMUTE_PS!(Q2Z, _MM_SHUFFLE(2, 2, 2, 2));
249 // Retire Q1 and perform Q1*Q2W
250 vResult = _mm_mul_ps(vResult, Q1);
251 let mut Q1Shuffle: XMVECTOR = Q1;
252 // Shuffle the copies of Q1
253 Q1Shuffle = XM_PERMUTE_PS!(Q1Shuffle, _MM_SHUFFLE(0, 1, 2, 3));
254 // Mul by Q1WZYX
255 Q2X = _mm_mul_ps(Q2X, Q1Shuffle);
256 Q1Shuffle = XM_PERMUTE_PS!(Q1Shuffle, _MM_SHUFFLE(2, 3, 0, 1));
257 // Flip the signs on y and z
258 vResult = XM_FMADD_PS!(Q2X, ControlWZYX.v, vResult);
259 // Mul by Q1ZWXY
260 Q2Y = _mm_mul_ps(Q2Y, Q1Shuffle);
261 Q1Shuffle = XM_PERMUTE_PS!(Q1Shuffle, _MM_SHUFFLE(0, 1, 2, 3));
262 // Flip the signs on z and w
263 Q2Y = _mm_mul_ps(Q2Y, ControlZWXY.v);
264 // Mul by Q1YXWZ
265 Q2Z = _mm_mul_ps(Q2Z, Q1Shuffle);
266 // Flip the signs on x and w
267 Q2Y = XM_FMADD_PS!(Q2Z, ControlYXWZ.v, Q2Y);
268 vResult = _mm_add_ps(vResult, Q2Y);
269 return vResult;
270 }
271}
272
273/// Computes the square of the magnitude of a quaternion.
274///
275/// ## Parameters
276///
277/// `Q` Quaternion to measure.
278///
279/// ## Return value
280///
281/// Returns a vector. The square of the magnitude of `Q` is replicated into each component.
282///
283/// ## Remarks
284///
285/// The DirectXMath quaternion functions use an XMVECTOR 4-vector to represent quaternions, where
286/// the `X`, `Y`, and `Z` components are the vector part and the `W` component is the scalar part.
287///
288/// ## Reference
289///
290/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMQuaternionLengthSq>
291#[inline]
292pub fn XMQuaternionLengthSq(
293 Q: FXMVECTOR,
294) -> FXMVECTOR
295{
296 return XMVector4LengthSq(Q);
297}
298
299/// Computes the reciprocal of the magnitude of a quaternion.
300///
301/// ## Parameters
302///
303/// `Q` Quaternion to measure.
304///
305/// ## Return value
306///
307/// Returns the reciprocal of the magnitude of `Q`.
308///
309/// ## Remarks
310///
311/// The DirectXMath quaternion functions use an XMVECTOR 4-vector to represent quaternions, where the `X`,
312/// `Y`, and `Z` components are the vector part and the `W` component is the scalar part.
313///
314/// ## Reference
315///
316/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMQuaternionReciprocalLength>
317#[inline]
318pub fn XMQuaternionReciprocalLength(
319 Q: FXMVECTOR,
320) -> FXMVECTOR
321{
322 return XMVector4ReciprocalLength(Q);
323}
324
325/// Computes the magnitude of a quaternion.
326///
327/// ## Parameters
328///
329/// `Q` Quaternion to measure.
330///
331/// ## Return value
332///
333/// Returns a vector. The magnitude of `Q` is replicated into each component.
334///
335/// ## Remarks
336///
337/// The DirectXMath quaternion functions use an XMVECTOR 4-vector to represent quaternions, where
338/// the `X`, `Y`, and `Z` components are the vector part and the `W` component is the scalar part.
339///
340/// ## Reference
341///
342/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMQuaternionLength>
343#[inline]
344pub fn XMQuaternionLength(
345 Q: FXMVECTOR,
346) -> FXMVECTOR
347{
348 return XMVector4Length(Q);
349}
350
351/// Estimates the normalized version of a quaternion.
352///
353/// ## Parameters
354///
355/// `Q` A quaternion for which to estimate the normalized version.
356///
357/// ## Return value
358///
359/// An XMVECTOR union that is the estimate of the normalized version of a quaternion.
360///
361/// ## Remarks
362///
363/// The DirectXMath quaternion functions use an XMVECTOR 4-vector to represent quaternions, where the `X`,
364/// `Y`, and `Z` components are the vector part and the `W` component is the scalar part.
365///
366/// This function internally calls the XMVector4NormalizeEstfunction.
367///
368/// `Est` functions offer increased performance at the expense of reduced accuracy. `Est` functions are appropriate
369/// for non-critical calculations where accuracy can be sacrificed for speed. The exact amount of lost accuracy
370/// and speed increase are platform dependent.
371///
372/// ## Reference
373///
374/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMQuaternionNormalizeEst>
375#[inline]
376pub fn XMQuaternionNormalizeEst(
377 Q: FXMVECTOR,
378) -> FXMVECTOR
379{
380 return XMVector4NormalizeEst(Q);
381}
382
383/// Computes the normalized version of a quaternion.
384///
385/// ## Parameters
386///
387/// `Q` Quaternion to normalize.
388///
389/// ## Return value
390///
391/// Returns the normalized form of `Q`.
392///
393/// ## Remarks
394///
395/// The DirectXMath quaternion functions use an XMVECTOR 4-vector to represent quaternions, where the `X`,
396/// `Y`, and `Z` components are the vector part and the `W` component is the scalar part.
397///
398/// ## Reference
399///
400/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMQuaternionNormalize>
401#[inline]
402pub fn XMQuaternionNormalize(
403 Q: FXMVECTOR,
404) -> FXMVECTOR
405{
406 return XMVector4Normalize(Q);
407}
408
409/// Computes the conjugate of a quaternion.
410///
411/// ## Parameters
412///
413/// `Q` The quaternion to conjugate.
414///
415/// ## Return value
416///
417/// Returns the conjugate of `Q`.
418///
419/// ## Remarks
420///
421/// The DirectXMath quaternion functions use an XMVECTOR 4-vector to represent quaternions, where
422/// the `X`, `Y`, and `Z` components are the vector part and the `W` component is the scalar part.
423///
424/// Given a quaternion (`x`, `y`, `z`, `w`), the [`XMQuaternionConjugate`] function returns the
425/// quaternion (`-x`, `-y`, `-z`, `w`).
426///
427/// Use the [`XMQuaternionNormalize`] function for any quaternion input that is not already normalized.
428///
429/// ## Reference
430///
431/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMQuaternionConjugate>
432///
433/// [`XMQuaternionConjugate`]: crate::quaternion::XMQuaternionConjugate
434#[inline]
435pub fn XMQuaternionConjugate(
436 Q: FXMVECTOR,
437) -> FXMVECTOR
438{
439 #[cfg(_XM_NO_INTRINSICS_)]
440 unsafe {
441 let Result = XMVECTORF32 {
442 f: [
443 -Q.vector4_f32[0],
444 -Q.vector4_f32[1],
445 -Q.vector4_f32[2],
446 Q.vector4_f32[3]
447 ]
448 };
449 return Result.v;
450 }
451
452 #[cfg(_XM_ARM_NEON_INTRINSICS_)]
453 {
454 unimplemented!()
455 }
456
457 #[cfg(_XM_SSE_INTRINSICS_)]
458 unsafe {
459 // TODO: (PERFORMANCE) This is defined as static const
460 const NegativeOne3: XMVECTORF32 = XMVECTORF32 { f: [-1.0, -1.0, -1.0, 1.0 ] };
461 return _mm_mul_ps(Q, NegativeOne3.v)
462 }
463}
464
465/// Computes the inverse of a quaternion.
466///
467/// ## Parameters
468///
469/// `Q` Quaternion to invert.
470///
471/// ## Return value
472///
473/// Returns the inverse of `Q`.
474///
475/// ## Remarks
476///
477/// The DirectXMath quaternion functions use an XMVECTOR 4-vector to represent quaternions, where
478/// the `X`, `Y`, and `Z` components are the vector part and the `W` component is the scalar part.
479///
480/// The following pseudocode demonstrates the operation of the function:
481///
482/// ```text
483/// XMVECTOR Result;
484///
485/// float LengthSq = Q.x * Q.x + Q.y * Q.y + Q.z * Q.z + Q.w * Q.w;
486///
487/// Result.x = -Q.x / LengthSq;
488/// Result.y = -Q.y / LengthSq;
489/// Result.z = -Q.z / LengthSq;
490/// Result.w = Q.w / LengthSq;
491///
492/// return Result;
493/// ```
494///
495/// ## Reference
496///
497/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMQuaternionInverse>
498#[inline]
499pub fn XMQuaternionInverse(
500 Q: FXMVECTOR,
501) -> FXMVECTOR
502{
503 unsafe {
504 // const Zero: XMVECTOR = XMVectorZero();
505 const Zero: XMVECTOR = unsafe { g_XMZero.v };
506
507 let L: XMVECTOR = XMVector4LengthSq(Q);
508 let Conjugate: XMVECTOR = XMQuaternionConjugate(Q);
509
510 let Control: XMVECTOR = XMVectorLessOrEqual(L, g_XMEpsilon.v);
511
512 let mut Result: XMVECTOR = XMVectorDivide(Conjugate, L);
513
514 Result = XMVectorSelect(Result, Zero, Control);
515
516 return Result;
517 }
518}
519
520/// Computes the natural logarithm of a given unit quaternion.
521///
522/// ## Parameters
523///
524/// `Q` Unit quaternion for which to calculate the natural logarithm. If `Q` is not a unit quaternion, the returned
525/// value is undefined.
526///
527/// ## Return value
528///
529/// Returns the natural logarithm of `Q`.
530///
531/// ## Remarks
532///
533/// The DirectXMath quaternion functions use an XMVECTOR 4-vector to represent quaternions, where the `X`,
534/// `Y`, and `Z` components are the vector part and the `W` component is the scalar part.
535///
536/// ## Reference
537///
538/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMQuaternionLn>
539#[inline]
540pub fn XMQuaternionLn(
541 Q: FXMVECTOR,
542) -> FXMVECTOR
543{
544 unsafe {
545 // TODO: PERFORMANCE static const
546 const OneMinusEpsilon: XMVECTOR = unsafe { XMVECTORF32 { f: [1.0 - 0.00001, 1.0 - 0.00001, 1.0 - 0.00001, 1.0 - 0.00001] }.v };
547
548 let QW: XMVECTOR = XMVectorSplatW(Q);
549 let Q0: XMVECTOR = XMVectorSelect(g_XMSelect1110.v, Q, g_XMSelect1110.v);
550
551 let ControlW: XMVECTOR = XMVectorInBounds(QW, OneMinusEpsilon);
552
553 let Theta: XMVECTOR = XMVectorACos(QW);
554 let SinTheta: XMVECTOR = XMVectorSin(Theta);
555
556 let S: XMVECTOR = XMVectorDivide(Theta, SinTheta);
557
558 let mut Result: XMVECTOR = XMVectorMultiply(Q0, S);
559 Result = XMVectorSelect(Q0, Result, ControlW);
560
561 return Result;
562 }
563}
564
565/// Computes the exponential of a given pure quaternion.
566///
567/// ## Parameters
568///
569/// `Q` Pure quaternion for which to compute the exponential. The `w`-component of the input
570/// quaternion is ignored in the calculation.
571///
572/// ## Return value
573///
574/// Returns the exponential of `Q`.
575///
576/// ## Remarks
577///
578/// The DirectXMath quaternion functions use an XMVECTOR 4-vector to represent quaternions, where
579/// the `X`, `Y`, and `Z` components are the vector part and the `W` component is the scalar part.
580///
581/// ## Reference
582///
583/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMQuaternionExp>
584#[inline]
585pub fn XMQuaternionExp(
586 Q: FXMVECTOR,
587) -> FXMVECTOR
588{
589 unsafe {
590 let Theta: XMVECTOR = XMVector3Length(Q);
591
592 let mut SinTheta: XMVECTOR = crate::undefined();
593 let mut CosTheta: XMVECTOR = crate::undefined();
594 XMVectorSinCos(&mut SinTheta, &mut CosTheta, Theta);
595
596 let S: XMVECTOR = XMVectorDivide(SinTheta, Theta);
597
598 let mut Result: XMVECTOR = XMVectorMultiply(Q, S);
599
600 //const let Zero: XMVECTOR = XMVectorZero();
601 const Zero: XMVECTOR = unsafe { g_XMZero.v };
602 let Control: XMVECTOR = XMVectorNearEqual(Theta, Zero, g_XMEpsilon.v);
603 Result = XMVectorSelect(Result, Q, Control);
604
605 Result = XMVectorSelect(CosTheta, Result, g_XMSelect1110.v);
606
607 return Result;
608 }
609}
610
611
612/// Interpolates between two unit quaternions, using spherical linear interpolation.
613///
614/// ## Parameters
615///
616/// `Q0` Unit quaternion to interpolate from.
617///
618/// `Q` Unit quaternion to interpolate to.
619///
620/// `t` Interpolation control factor.
621///
622/// ## Return value
623///
624/// Returns the interpolated quaternion. If `Q0` and `Q1` are not unit quaternions, the resulting
625/// interpolation is undefined.
626///
627/// ## Remarks
628///
629/// The DirectXMath quaternion functions use an XMVECTOR 4-vector to represent quaternions, where
630/// the `X`, `Y`, and `Z` components are the vector part and the `W` component is the scalar part.
631///
632/// When `t` is `0.0`, the function returns `Q0`. When `t` is `1.0`, the function returns `Q1`.
633///
634/// ## Reference
635///
636/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMQuaternionSlerp>
637#[inline]
638pub fn XMQuaternionSlerp(
639 Q0: FXMVECTOR,
640 Q1: FXMVECTOR,
641 t: f32,
642) -> FXMVECTOR
643{
644 let T: XMVECTOR = XMVectorReplicate(t);
645 return XMQuaternionSlerpV(Q0, Q1, T);
646}
647
648/// Interpolates between two unit quaternions, using spherical linear interpolation.
649///
650/// ## Parameters
651///
652/// `Q0` Unit quaternion to interpolate from.
653///
654/// `Q1` Unit quaternion to interpolate to.
655///
656/// `T` Interpolation control factor. All components of this vector must be the same.
657///
658/// ## Return value
659///
660/// Returns the interpolated quaternion. If `Q0` and `Q1` are not unit quaternions, the resulting interpolation
661/// is undefined.
662///
663/// ## Remarks
664///
665/// The DirectXMath quaternion functions use an XMVECTOR 4-vector to represent quaternions, where the `X`,
666/// `Y`, and `Z` components are the vector part and the `W` component is the scalar part.
667///
668/// This function is identical to [`XMQuaternionSlerp`] except that `T` is supplied using a 4D vector instead
669/// of a **float** value.
670///
671/// ## Reference
672///
673/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMQuaternionSlerpV>
674///
675/// [`XMQuaternionSlerp`]: crate::quaternion::XMQuaternionSlerp
676#[inline]
677pub fn XMQuaternionSlerpV(
678 Q0: FXMVECTOR,
679 Q1: FXMVECTOR,
680 T: FXMVECTOR,
681) -> FXMVECTOR
682{
683 debug_assert!((XMVectorGetY(T) == XMVectorGetX(T)) && (XMVectorGetZ(T) == XMVectorGetX(T)) && (XMVectorGetW(T) == XMVectorGetX(T)));
684
685 #[cfg(any(_XM_NO_INTRINSICS_, _XM_ARM_NEON_INTRINSICS_))]
686 unsafe {
687 // TODO: PERFORMANCE These are defined as static const
688 const OneMinusEpsilon: XMVECTORF32 = XMVECTORF32 { f: [ 1.0 - 0.00001, 1.0 - 0.00001, 1.0 - 0.00001, 1.0 - 0.00001 ] };
689
690 let mut CosOmega: XMVECTOR = XMQuaternionDot(Q0, Q1);
691
692 // const let mut Zero: XMVECTOR = XMVectorZero();
693 const Zero: XMVECTOR = unsafe { g_XMZero.v };
694 let mut Control: XMVECTOR = XMVectorLess(CosOmega, Zero);
695 let Sign: XMVECTOR = XMVectorSelect(g_XMOne.v, g_XMNegativeOne.v, Control);
696
697 CosOmega = XMVectorMultiply(CosOmega, Sign);
698
699 Control = XMVectorLess(CosOmega, OneMinusEpsilon.v);
700
701 let mut SinOmega: XMVECTOR = XMVectorNegativeMultiplySubtract(CosOmega, CosOmega, g_XMOne.v);
702 SinOmega = XMVectorSqrt(SinOmega);
703
704 let Omega: XMVECTOR = XMVectorATan2(SinOmega, CosOmega);
705
706 let mut SignMask: XMVECTOR = XMVectorSplatSignMask();
707 let mut V01: XMVECTOR = XMVectorShiftLeft(T, Zero, 2);
708 SignMask = XMVectorShiftLeft(SignMask, Zero, 3);
709 V01 = XMVectorXorInt(V01, SignMask);
710 V01 = XMVectorAdd(g_XMIdentityR0.v, V01);
711
712 let InvSinOmega: XMVECTOR = XMVectorReciprocal(SinOmega);
713
714 let mut S0: XMVECTOR = XMVectorMultiply(V01, Omega);
715 S0 = XMVectorSin(S0);
716 S0 = XMVectorMultiply(S0, InvSinOmega);
717
718 S0 = XMVectorSelect(V01, S0, Control);
719
720 let mut S1: XMVECTOR = XMVectorSplatY(S0);
721 S0 = XMVectorSplatX(S0);
722
723 S1 = XMVectorMultiply(S1, Sign);
724
725 let mut Result: XMVECTOR = XMVectorMultiply(Q0, S0);
726 Result = XMVectorMultiplyAdd(Q1, S1, Result);
727
728 return Result;
729 }
730
731 #[cfg(_XM_SSE_INTRINSICS_)]
732 unsafe {
733 // TODO: PERFORMANCE These are defined as static const
734 const OneMinusEpsilon: XMVECTORF32 = XMVECTORF32 { f: [ 1.0 - 0.00001, 1.0 - 0.00001, 1.0 - 0.00001, 1.0 - 0.00001 ] };
735 const SignMask2: XMVECTORU32 = XMVECTORU32 { u: [ 0x80000000, 0x00000000, 0x00000000, 0x00000000 ] };
736
737 let mut CosOmega: XMVECTOR = XMQuaternionDot(Q0, Q1);
738
739 // const let mut Zero: XMVECTOR = XMVectorZero();
740 const Zero: XMVECTOR = unsafe { g_XMZero.v };
741
742 let mut Control: XMVECTOR = XMVectorLess(CosOmega, Zero);
743 let Sign: XMVECTOR = XMVectorSelect(g_XMOne.v, g_XMNegativeOne.v, Control);
744
745 CosOmega = _mm_mul_ps(CosOmega, Sign);
746
747 Control = XMVectorLess(CosOmega, OneMinusEpsilon.v);
748
749 let mut SinOmega: XMVECTOR = _mm_mul_ps(CosOmega, CosOmega);
750 SinOmega = _mm_sub_ps(g_XMOne.v, SinOmega);
751 SinOmega = _mm_sqrt_ps(SinOmega);
752
753 let Omega: XMVECTOR = XMVectorATan2(SinOmega, CosOmega);
754
755 let mut V01: XMVECTOR = XM_PERMUTE_PS!(T, _MM_SHUFFLE(2, 3, 0, 1));
756 V01 = _mm_and_ps(V01, g_XMMaskXY.v);
757 V01 = _mm_xor_ps(V01, SignMask2.v);
758 V01 = _mm_add_ps(g_XMIdentityR0.v, V01);
759
760 let mut S0: XMVECTOR = _mm_mul_ps(V01, Omega);
761 S0 = XMVectorSin(S0);
762 S0 = _mm_div_ps(S0, SinOmega);
763
764 S0 = XMVectorSelect(V01, S0, Control);
765
766 let mut S1: XMVECTOR = XMVectorSplatY(S0);
767 S0 = XMVectorSplatX(S0);
768
769 S1 = _mm_mul_ps(S1, Sign);
770 let mut Result: XMVECTOR = _mm_mul_ps(Q0, S0);
771 S1 = _mm_mul_ps(S1, Q1);
772 Result = _mm_add_ps(Result, S1);
773 return Result;
774 }
775}
776
777/// Interpolates between four unit quaternions, using spherical quadrangle interpolation.
778///
779/// ## Parameters
780///
781/// `Q0` First unit quaternion.
782///
783/// `Q1` Second unit quaternion.
784///
785/// `Q2` Third unit quaternion.
786///
787/// `Q3` Fourth unit quaternion.
788///
789/// `t` Interpolation control factor.
790///
791/// ## Return value
792///
793/// Returns the interpolated quaternion. If `Q0`, `Q1`, `Q2`, and `Q3` are not
794/// all unit quaternions, the returned quaternion is undefined.
795///
796/// ## Remarks
797///
798/// The DirectXMath quaternion functions use an XMVECTOR 4-vector to represent
799/// quaternions, where the `X`, `Y`, and `Z` components are the vector part and the
800/// `W` component is the scalar part.
801///
802/// The use of this method requires some setup before its use. See [`XMQuaternionSquadSetup`] for details.
803///
804/// This method uses the following sequence of spherical linear interpolation operations.
805///
806/// ```text
807/// Slerp(Slerp(q1, c, t), Slerp(a, b, t), 2t(1 - t))
808/// ```
809///
810/// ## Reference
811///
812/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMQuaternionSquad>
813///
814/// <https://docs.microsoft.com/en-us/previous-versions/windows/desktop/bb281656(v=vs.85)>
815///
816/// [`XMQuaternionSquadSetup`]: crate::quaternion::XMQuaternionSquadSetup
817#[inline]
818pub fn XMQuaternionSquad(
819 Q0: FXMVECTOR,
820 Q1: FXMVECTOR,
821 Q2: FXMVECTOR,
822 Q3: GXMVECTOR,
823 t: f32,
824) -> FXMVECTOR
825{
826 let T: XMVECTOR = XMVectorReplicate(t);
827 return XMQuaternionSquadV(Q0, Q1, Q2, Q3, T);
828}
829
830/// Interpolates between four unit quaternions, using spherical quadrangle interpolation.
831///
832/// ## Parameters
833///
834/// `Q0` First unit quaternion.
835///
836/// `Q1` Second unit quaternion.
837///
838/// `Q2` Third unit quaternion.
839///
840/// `Q3` Fourth unit quaternion.
841///
842/// `T` Interpolation control factor. All components of this vector must be the same.
843///
844/// ## Return value
845///
846/// Returns the interpolated quaternion. If Q0, Q1, Q2, and Q3 are not unit quaternions, the resulting interpolation
847/// is undefined.
848///
849/// ## Remarks
850///
851/// The DirectXMath quaternion functions use an XMVECTOR 4-vector to represent quaternions, where the `X`,
852/// `Y`, and `Z` components are the vector part and the `W` component is the scalar part.
853///
854/// This function is identical to [`XMQuaternionSquad`] except that `T` is supplied using a 4D vector instead
855/// of a **float** value.
856///
857/// ## Reference
858///
859/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMQuaternionSquadV>
860///
861/// <https://docs.microsoft.com/en-us/previous-versions/windows/desktop/bb281657(v=vs.85)>
862///
863/// [`XMQuaternionSquad`]: crate::quaternion::XMQuaternionSquad
864#[inline]
865pub fn XMQuaternionSquadV(
866 Q0: FXMVECTOR,
867 Q1: FXMVECTOR,
868 Q2: FXMVECTOR,
869 Q3: GXMVECTOR,
870 T: XMVECTOR,
871) -> FXMVECTOR
872{
873 debug_assert!((XMVectorGetY(T) == XMVectorGetX(T)) && (XMVectorGetZ(T) == XMVectorGetX(T)) && (XMVectorGetW(T) == XMVectorGetX(T)));
874
875 let mut TP: XMVECTOR = T;
876
877 let Two: XMVECTOR = XMVectorSplatConstant(2, 0);
878
879 let Q03: XMVECTOR = XMQuaternionSlerpV(Q0, Q3, T);
880 let Q12: XMVECTOR = XMQuaternionSlerpV(Q1, Q2, T);
881
882 TP = XMVectorNegativeMultiplySubtract(TP, TP, TP);
883 TP = XMVectorMultiply(TP, Two);
884
885 let Result: XMVECTOR = XMQuaternionSlerpV(Q03, Q12, TP);
886
887 return Result;
888}
889
890/// Provides addresses of setup control points for spherical quadrangle interpolation.
891///
892/// ## Parameters
893///
894/// `pA` Address of first setup quaternion.
895///
896/// `pB` Address of first setup quaternion.
897///
898/// `pC` Address of first setup quaternion.
899///
900/// `Q0` First quaternion.
901///
902/// `Q1` Second quaternion.
903///
904/// `Q2` Third quaternion.
905///
906/// `Q3` Fourth quaternion.
907///
908/// ## Remarks
909///
910/// The DirectXMath quaternion functions use an XMVECTOR 4-vector to represent
911/// quaternions, where the `X`, `Y`, and `Z` components are the vector part and the
912/// `W` component is the scalar part.
913///
914/// The results returned in `pA`, `pB`, and `pC` are used as the inputs to the
915/// `Q1`, `Q2`, and `Q3` parameters of [`XMQuaternionSquad`].
916///
917/// This method takes four control points, which are supplied to the inputs `Q0`, `Q1`, `Q2`, and
918/// `Q3`, and alters their values to find a curve that flows along the shortest path. The values of
919/// `Q0`, `Q2`, and `Q3` are calculated as shown below.
920///
921/// ```text
922/// q0 = |q0 + q1| < |q0 - q1| ? -q0 : q0
923/// q2 = |q1 + q2| < |q1 - q2| ? -q2 : q2
924/// q3 = |q2 + q3| < |q2 - q3| ? -q3 : q3
925/// ```
926///
927/// Having calculated the new `q` values, the values for `outA`, `outB`, and `outC` are calculated
928/// as shown below.
929///
930/// ```text
931/// outA = q1 * exp[-0.25 *( Ln[Exp(q1)*q2] + Ln[Exp(q1)*q0] ) ]
932/// outB = q2 * exp[-0.25 *( Ln[Exp(q2)*q3] + Ln[Exp(q2)*q1] ) ]
933/// outC = q2
934/// ```
935///
936/// Where `Ln` and `Exp` are [`XMQuaternionLn`] and [`XMQuaternionExp`].
937///
938/// ## Example
939///
940/// The following example shows how to use a set of quaternion keys (`Q0`, `Q1`, `Q2`, `Q3`) to
941/// compute the inner quadrangle points (`A`, `B`, `C`). This ensures that the tangents are
942/// continuous across adjacent segments.
943///
944/// ```text
945/// A B
946/// Q0 Q1 Q2 Q3
947/// ```
948///
949/// The following example shows how you can interpolate between `Q1` and `Q2`.
950///
951/// ```rust
952/// # use directx_math::*;
953/// let q0 = XMVectorSet(0.0, 0.0, 0.707, -0.707);
954/// let q1 = XMVectorSet(0.0, 0.0, 0.0, 1.0);
955/// let q2 = XMVectorSet(0.0, 0.0, 0.707, 0.707);
956/// let q3 = XMVectorSet(0.0, 0.0, 1.0, 0.0);
957///
958/// let mut a = XMVectorZero();
959/// let mut b = XMVectorZero();
960/// let mut c = XMVectorZero();
961///
962/// let time = 0.5;
963///
964/// XMQuaternionSquadSetup(&mut a, &mut b, &mut c, q0, q1, q2, q3);
965/// let result = XMQuaternionSquad(q1, a, b, c, time);
966/// ```
967///
968/// Note that `c` is `+/-` `q2` depending on the result of the fuction. The result is a rotation of
969/// `45` degrees around the `z`-axis for `time = 0.5`.
970///
971/// ## Reference
972///
973/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMQuaternionSquadSetup>
974///
975/// <https://docs.microsoft.com/en-us/previous-versions/windows/desktop/bb281657(v=vs.85)>
976///
977/// [`XMQuaternionSquad`]: crate::quaternion::XMQuaternionSquad
978/// [`XMQuaternionLn`]: crate::quaternion::XMQuaternionLn
979/// [`XMQuaternionExp`]: crate::quaternion::XMQuaternionExp
980#[inline]
981pub fn XMQuaternionSquadSetup(
982 pA: &mut XMVECTOR,
983 pB: &mut XMVECTOR,
984 pC: &mut XMVECTOR,
985 Q0: FXMVECTOR,
986 Q1: FXMVECTOR,
987 Q2: FXMVECTOR,
988 Q3: GXMVECTOR
989)
990{
991 let LS12: XMVECTOR = XMQuaternionLengthSq(XMVectorAdd(Q1, Q2));
992 let LD12: XMVECTOR = XMQuaternionLengthSq(XMVectorSubtract(Q1, Q2));
993 let mut SQ2: XMVECTOR = XMVectorNegate(Q2);
994
995 let Control1: XMVECTOR = XMVectorLess(LS12, LD12);
996 SQ2 = XMVectorSelect(Q2, SQ2, Control1);
997
998 let LS01: XMVECTOR = XMQuaternionLengthSq(XMVectorAdd(Q0, Q1));
999 let LD01: XMVECTOR = XMQuaternionLengthSq(XMVectorSubtract(Q0, Q1));
1000 let mut SQ0: XMVECTOR = XMVectorNegate(Q0);
1001
1002 let LS23: XMVECTOR = XMQuaternionLengthSq(XMVectorAdd(SQ2, Q3));
1003 let LD23: XMVECTOR = XMQuaternionLengthSq(XMVectorSubtract(SQ2, Q3));
1004 let mut SQ3: XMVECTOR = XMVectorNegate(Q3);
1005
1006 let Control0: XMVECTOR = XMVectorLess(LS01, LD01);
1007 let Control2: XMVECTOR = XMVectorLess(LS23, LD23);
1008
1009 SQ0 = XMVectorSelect(Q0, SQ0, Control0);
1010 SQ3 = XMVectorSelect(Q3, SQ3, Control2);
1011
1012 let InvQ1: XMVECTOR = XMQuaternionInverse(Q1);
1013 let InvQ2: XMVECTOR = XMQuaternionInverse(SQ2);
1014
1015 let LnQ0: XMVECTOR = XMQuaternionLn(XMQuaternionMultiply(InvQ1, SQ0));
1016 let LnQ2: XMVECTOR = XMQuaternionLn(XMQuaternionMultiply(InvQ1, SQ2));
1017 let LnQ1: XMVECTOR = XMQuaternionLn(XMQuaternionMultiply(InvQ2, Q1));
1018 let LnQ3: XMVECTOR = XMQuaternionLn(XMQuaternionMultiply(InvQ2, SQ3));
1019
1020 let NegativeOneQuarter: XMVECTOR = XMVectorSplatConstant(-1, 2);
1021
1022 let mut ExpQ02: XMVECTOR = XMVectorMultiply(XMVectorAdd(LnQ0, LnQ2), NegativeOneQuarter);
1023 let mut ExpQ13: XMVECTOR = XMVectorMultiply(XMVectorAdd(LnQ1, LnQ3), NegativeOneQuarter);
1024 ExpQ02 = XMQuaternionExp(ExpQ02);
1025 ExpQ13 = XMQuaternionExp(ExpQ13);
1026
1027 *pA = XMQuaternionMultiply(Q1, ExpQ02);
1028 *pB = XMQuaternionMultiply(SQ2, ExpQ13);
1029 *pC = SQ2;
1030}
1031
1032/// Returns a point in barycentric coordinates, using the specified quaternions.
1033///
1034/// ## Parameters
1035///
1036/// `Q0` First quaternion in the triangle.
1037///
1038/// `Q1` Second quaternion in the triangle.
1039///
1040/// `Q2` Third quaternion in the triangle.
1041///
1042/// `f` Weighting factor. See the remarks.
1043///
1044/// `g` Weighting factor. See the remarks.
1045///
1046/// ## Return value
1047///
1048/// Returns a quaternion in barycentric coordinates.
1049///
1050/// ## Remarks
1051///
1052/// The following pseudocode demonstrates the operation of the function.
1053///
1054/// ```text
1055/// XMVECTOR Result;
1056/// XMVECTOR QA, QB;
1057/// float s = f + g;
1058///
1059/// if (s != 0.0f)
1060/// {
1061/// QA = XMQuaternionSlerp(Q0, Q1, s);
1062/// QB = XMQuaternionSlerp(Q0, Q2, s);
1063/// Result = XMQuaternionSlerp(QA, QB, g / s);
1064/// }
1065/// else
1066/// {
1067/// Result.x = Q0.x;
1068/// Result.y = Q0.y;
1069/// Result.z = Q0.z;
1070/// Result.w = Q0.w;
1071/// }
1072///
1073/// return Result;
1074/// ```
1075///
1076/// Note that Barycentric coordinates work for 'flat' surfaces but not for 'curved' ones.
1077/// This function is therefore a bit of a work-around. An alternative method for blending
1078/// 3 quanterions is given by the following code:
1079///
1080/// ```text
1081/// inline XMVECTOR XMQuaternionBlend(
1082/// FXMVECTOR Q0,
1083/// FXMVECTOR Q1,
1084/// FXMVECTOR Q2,
1085/// float w1,
1086/// float w2
1087/// )
1088/// {
1089/// // Note if you choose one of the three weights to be zero, you get a blend of two
1090/// // quaternions. This does not give you slerp of those quaternions.
1091/// float w0 = 1.0f - w1 - w2;
1092/// XMVECTOR Result = XMVector4Normalize(
1093/// XMVectorScale(Q0, w0) +
1094/// XMVectorScale(Q1, w1) +
1095/// XMVectorScale(Q2, w2));
1096/// return Result;
1097/// }
1098/// ```
1099///
1100/// ## Reference
1101///
1102/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMQuaternionBaryCentric>
1103#[inline]
1104pub fn XMQuaternionBaryCentric(
1105 Q0: FXMVECTOR,
1106 Q1: FXMVECTOR,
1107 Q2: FXMVECTOR,
1108 f: f32,
1109 g: f32,
1110) -> XMVECTOR
1111{
1112 let s = f + g;
1113
1114 let Result: XMVECTOR;
1115 if ((s < 0.00001) && (s > -0.00001))
1116 {
1117 Result = Q0;
1118 }
1119 else
1120 {
1121 let Q01: XMVECTOR = XMQuaternionSlerp(Q0, Q1, s);
1122 let Q02: XMVECTOR = XMQuaternionSlerp(Q0, Q2, s);
1123
1124 Result = XMQuaternionSlerp(Q01, Q02, g / s);
1125 }
1126
1127 return Result;
1128}
1129
1130/// Returns a point in barycentric coordinates, using the specified quaternions.
1131///
1132/// ## Parameters
1133///
1134/// `Q0` First quaternion in the triangle.
1135///
1136/// `Q1` Second quaternion in the triangle.
1137///
1138/// `Q2` Third quaternion in the triangle.
1139///
1140/// `F` Weighting factor. All components of this vector must be the same.
1141///
1142/// `G` Weighting factor. All components of this vector must be the same.
1143///
1144/// ## Return value
1145///
1146/// Returns a quaternion in barycentric coordinates.
1147///
1148/// ## Remarks
1149///
1150/// The DirectXMath quaternion functions use an XMVECTOR 4-vector to represent quaternions, where
1151/// the `X`, `Y`, and `Z` components are the vector part and the `W` component is the scalar part.
1152///
1153/// This function is identical to [`XMQuaternionBaryCentric`] except that `F` and `G` are supplied using
1154/// a 4D vector instead of a **float** value.
1155///
1156/// ## Reference
1157///
1158/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMQuaternionBaryCentricV>
1159///
1160/// [`XMQuaternionBaryCentric`]: crate::quaternion::XMQuaternionBaryCentric
1161#[inline]
1162pub fn XMQuaternionBaryCentricV(
1163 Q0: FXMVECTOR,
1164 Q1: FXMVECTOR,
1165 Q2: FXMVECTOR,
1166 F: FXMVECTOR,
1167 G: FXMVECTOR,
1168) -> XMVECTOR
1169{
1170 debug_assert!((XMVectorGetY(F) == XMVectorGetX(F)) && (XMVectorGetZ(F) == XMVectorGetX(F)) && (XMVectorGetW(F) == XMVectorGetX(F)));
1171 debug_assert!((XMVectorGetY(G) == XMVectorGetX(G)) && (XMVectorGetZ(G) == XMVectorGetX(G)) && (XMVectorGetW(G) == XMVectorGetX(G)));
1172
1173 // PERFORMANCE: const
1174 let Epsilon: XMVECTOR = XMVectorSplatConstant(1, 16);
1175
1176 let S: XMVECTOR = XMVectorAdd(F, G);
1177
1178 let Result: XMVECTOR;
1179 if (XMVector4InBounds(S, Epsilon))
1180 {
1181 Result = Q0;
1182 }
1183 else
1184 {
1185 let Q01: XMVECTOR = XMQuaternionSlerpV(Q0, Q1, S);
1186 let Q02: XMVECTOR = XMQuaternionSlerpV(Q0, Q2, S);
1187 let mut GS: XMVECTOR = XMVectorReciprocal(S);
1188 GS = XMVectorMultiply(G, GS);
1189
1190 Result = XMQuaternionSlerpV(Q01, Q02, GS);
1191 }
1192
1193 return Result;
1194}
1195
1196/// Returns the identity quaternion.
1197///
1198/// ## Return value
1199///
1200/// An XMVECTOR that is the identity quaternion.
1201///
1202/// ## Remarks
1203///
1204/// The DirectXMath quaternion functions use an XMVECTOR 4-vector to represent quaternions, where
1205/// the `X`, `Y`, and `Z` components are the vector part and the `W` component is the scalar part.
1206///
1207/// Given a quaternion (`x`, `y`, `z`, `w`), the [`XMQuaternionIdentity`] function will return the
1208/// quaternion (`0`, `0`, `0`, `1`).
1209///
1210/// ## Reference
1211///
1212/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMQuaternionIdentity>
1213///
1214/// [`XMQuaternionIdentity`]: crate::quaternion::XMQuaternionIdentity
1215#[inline]
1216pub fn XMQuaternionIdentity() -> FXMVECTOR
1217{
1218 unsafe {
1219 return g_XMIdentityR3.v;
1220 }
1221}
1222
1223
1224/// Computes a rotation quaternion based on the `pitch`, `yaw`, and `roll` (Euler angles).
1225///
1226/// ## Parameters
1227///
1228/// `Pitch` Angle of rotation around the `x-axis`, in radians.
1229///
1230/// `Yaw` Angle of rotation around the `y-axis`, in radians.
1231///
1232/// `Roll` Angle of rotation around the `z-axis`, in radians.
1233///
1234/// ## Return value
1235///
1236/// Returns the rotation quaternion.
1237///
1238/// ## Remarks
1239///
1240/// The DirectXMath quaternion functions use an XMVECTOR 4-vector to represent quaternions, where the `X`,
1241/// `Y`, and `Z` components are the vector part and the `W` component is the scalar part.
1242///
1243/// Angles are measured clockwise when looking along the rotation axis toward the origin. **This is a left-handed
1244/// coordinate system. To use right-handed coordinates, negate all three angles.**
1245///
1246/// The order of transformations is `roll` first, then `pitch`, then `yaw`. The rotations are all applied in the
1247/// global coordinate frame.
1248///
1249/// ## Reference
1250///
1251/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMQuaternionRotationRollPitchYaw>
1252#[inline]
1253pub fn XMQuaternionRotationRollPitchYaw(
1254 Pitch: f32,
1255 Yaw: f32,
1256 Roll: f32,
1257) -> FXMVECTOR
1258{
1259 let Angles: XMVECTOR = XMVectorSet(Pitch, Yaw, Roll, 0.0);
1260 let Q: XMVECTOR = XMQuaternionRotationRollPitchYawFromVector(Angles);
1261 return Q;
1262}
1263
1264/// Computes a rotation quaternion based on a vector containing the Euler angles (`pitch`, `yaw`, and `roll`).
1265///
1266/// ## Parameters
1267///
1268/// `Angles` 3D vector containing the Euler angles in the order `pitch`, `yaw`, `roll`.
1269///
1270/// ## Return value
1271///
1272/// Returns the rotation quaternion.
1273///
1274/// ## Remarks
1275///
1276/// The DirectXMath quaternion functions use an XMVECTOR 4-vector to represent quaternions, where the `X`,
1277/// `Y`, and `Z` components are the vector part and the `W` component is the scalar part.
1278///
1279/// Angles are measured clockwise when looking along the rotation axis toward the origin. **This is a left-handed
1280/// coordinate system. To use right-handed coordinates, negate all three angles.**
1281///
1282/// The order of transformations is `roll` first, then `pitch`, then `yaw`. The rotations are all applied in the
1283/// global coordinate frame.
1284///
1285/// ## Reference
1286///
1287/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMQuaternionRotationRollPitchYawFromVector>
1288#[inline]
1289pub fn XMQuaternionRotationRollPitchYawFromVector(
1290 Angles: XMVECTOR, // <Pitch, Yaw, Roll, 0>
1291) -> FXMVECTOR
1292{
1293 unsafe {
1294 // TODO: This is defined as a static const
1295 const Sign: XMVECTORF32 = XMVECTORF32 { f: [1.0, -1.0, -1.0, 1.0 ] };
1296
1297 let HalfAngles: XMVECTOR = XMVectorMultiply(Angles, g_XMOneHalf.v);
1298
1299 let mut SinAngles: XMVECTOR = crate::undefined();
1300 let mut CosAngles: XMVECTOR = crate::undefined();
1301 XMVectorSinCos(&mut SinAngles, &mut CosAngles, HalfAngles);
1302
1303 // TODO: PERFORMANCE XMVectorPermute
1304 // let P0: XMVECTOR = XMVectorPermute(SinAngles, CosAngles, XM_PERMUTE_0X, XM_PERMUTE_1X, XM_PERMUTE_1X, XM_PERMUTE_1X);
1305 // let Y0: XMVECTOR = XMVectorPermute(SinAngles, CosAngles, XM_PERMUTE_1Y, XM_PERMUTE_0Y, XM_PERMUTE_1Y, XM_PERMUTE_1Y);
1306 // let R0: XMVECTOR = XMVectorPermute(SinAngles, CosAngles, XM_PERMUTE_1Z, XM_PERMUTE_1Z, XM_PERMUTE_0Z, XM_PERMUTE_1Z);
1307 // let P1: XMVECTOR = XMVectorPermute(CosAngles, SinAngles, XM_PERMUTE_0X, XM_PERMUTE_1X, XM_PERMUTE_1X, XM_PERMUTE_1X);
1308 // let Y1: XMVECTOR = XMVectorPermute(CosAngles, SinAngles, XM_PERMUTE_1Y, XM_PERMUTE_0Y, XM_PERMUTE_1Y, XM_PERMUTE_1Y);
1309 // let R1: XMVECTOR = XMVectorPermute(CosAngles, SinAngles, XM_PERMUTE_1Z, XM_PERMUTE_1Z, XM_PERMUTE_0Z, XM_PERMUTE_1Z);
1310
1311 // TODO: Delete note above after benchmarking
1312 let P0: XMVECTOR = <(XM_PERMUTE_0X, XM_PERMUTE_1X, XM_PERMUTE_1X, XM_PERMUTE_1X)>::XMVectorPermute(SinAngles, CosAngles);
1313 let Y0: XMVECTOR = <(XM_PERMUTE_1Y, XM_PERMUTE_0Y, XM_PERMUTE_1Y, XM_PERMUTE_1Y)>::XMVectorPermute(SinAngles, CosAngles);
1314 let R0: XMVECTOR = <(XM_PERMUTE_1Z, XM_PERMUTE_1Z, XM_PERMUTE_0Z, XM_PERMUTE_1Z)>::XMVectorPermute(SinAngles, CosAngles);
1315 let P1: XMVECTOR = <(XM_PERMUTE_0X, XM_PERMUTE_1X, XM_PERMUTE_1X, XM_PERMUTE_1X)>::XMVectorPermute(CosAngles, SinAngles);
1316 let Y1: XMVECTOR = <(XM_PERMUTE_1Y, XM_PERMUTE_0Y, XM_PERMUTE_1Y, XM_PERMUTE_1Y)>::XMVectorPermute(CosAngles, SinAngles);
1317 let R1: XMVECTOR = <(XM_PERMUTE_1Z, XM_PERMUTE_1Z, XM_PERMUTE_0Z, XM_PERMUTE_1Z)>::XMVectorPermute(CosAngles, SinAngles);
1318
1319 let mut Q1: XMVECTOR = XMVectorMultiply(P1, Sign.v);
1320 let mut Q0: XMVECTOR = XMVectorMultiply(P0, Y0);
1321 Q1 = XMVectorMultiply(Q1, Y1);
1322 Q0 = XMVectorMultiply(Q0, R0);
1323 let Q: XMVECTOR = XMVectorMultiplyAdd(Q1, R1, Q0);
1324
1325 return Q;
1326 }
1327}
1328
1329/// Computes the rotation quaternion about a normal vector.
1330///
1331/// ## Parameters
1332///
1333/// `NormalAxis` Normal vector describing the axis of rotation.
1334///
1335/// `Angle` Angle of rotation in radians. Angles are measured clockwise when
1336/// looking along the rotation axis toward the origin.
1337///
1338/// ## Return value
1339///
1340/// Returns the rotation quaternion.
1341///
1342/// ## Remarks
1343///
1344/// The DirectXMath quaternion functions use an XMVECTOR 4-vector to represent quaternions, where
1345/// the `X`, `Y`, and `Z` components are the vector part and the `W` component is the scalar part.
1346///
1347/// ## Reference
1348///
1349/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMQuaternionRotationNormal>
1350#[inline]
1351pub fn XMQuaternionRotationNormal(
1352 NormalAxis: XMVECTOR,
1353 Angle: f32,
1354) -> FXMVECTOR
1355{
1356 #[cfg(any(_XM_NO_INTRINSICS_, _XM_ARM_NEON_INTRINSICS_))]
1357 unsafe {
1358 let N: XMVECTOR = XMVectorSelect(g_XMOne.v, NormalAxis, g_XMSelect1110.v);
1359
1360 let mut SinV: f32 = 0.0;
1361 let mut CosV: f32 = 0.0;
1362 XMScalarSinCos(&mut SinV, &mut CosV, 0.5 * Angle);
1363
1364 let Scale: XMVECTOR = XMVectorSet(SinV, SinV, SinV, CosV);
1365 return XMVectorMultiply(N, Scale);
1366 }
1367
1368 #[cfg(_XM_SSE_INTRINSICS_)]
1369 unsafe {
1370 let mut N: XMVECTOR = _mm_and_ps(NormalAxis, g_XMMask3.v);
1371 N = _mm_or_ps(N, g_XMIdentityR3.v);
1372 let mut Scale: XMVECTOR = _mm_set_ps1(0.5 * Angle);
1373 let mut vSine: XMVECTOR = crate::undefined();
1374 let mut vCosine: XMVECTOR = crate::undefined();
1375 XMVectorSinCos(&mut vSine, &mut vCosine, Scale);
1376 Scale = _mm_and_ps(vSine, g_XMMask3.v);
1377 vCosine = _mm_and_ps(vCosine, g_XMMaskW.v);
1378 Scale = _mm_or_ps(Scale, vCosine);
1379 N = _mm_mul_ps(N, Scale);
1380 return N;
1381 }
1382}
1383
1384/// Computes a rotation quaternion about an axis.
1385///
1386/// ## Parameters
1387///
1388/// `Axis` 3D vector describing the axis of rotation.
1389///
1390/// `Angle` Angle of rotation in radians. Angles are measured clockwise when
1391/// looking along the rotation axis toward the origin.
1392///
1393/// ## Return value
1394///
1395/// Returns the rotation quaternion.
1396///
1397/// ## Remarks
1398///
1399/// The DirectXMath quaternion functions use an XMVECTOR 4-vector to represent quaternions, where
1400/// the `X`, `Y`, and `Z` components are the vector part and the `W` component is the scalar part.
1401///
1402/// If Axis is a normalized vector, it is faster to use [`XMQuaternionRotationNormal`]
1403///
1404/// ## Reference
1405///
1406/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMQuaternionRotationAxis>
1407///
1408/// [`XMQuaternionRotationNormal`]: crate::quaternion::XMQuaternionRotationNormal
1409#[inline]
1410pub fn XMQuaternionRotationAxis(
1411 Axis: XMVECTOR,
1412 Angle: f32,
1413) -> FXMVECTOR
1414{
1415 debug_assert!(!XMVector3Equal(Axis, XMVectorZero()));
1416 debug_assert!(!XMVector3IsInfinite(Axis));
1417
1418 let Normal: XMVECTOR = XMVector3Normalize(Axis);
1419 let Q: XMVECTOR = XMQuaternionRotationNormal(Normal, Angle);
1420 return Q;
1421}
1422
1423
1424/// Computes a rotation quaternion from a rotation matrix.
1425///
1426/// ## Parameters
1427///
1428/// `M` Rotation matrix.
1429///
1430/// ## Return value
1431///
1432/// Returns the rotation quaternion.
1433///
1434/// ## Remarks
1435///
1436/// This function only uses the upper 3x3 portion of the XMMATRIX. Note if the input matrix contains scales,
1437/// shears, or other non-rotation transformations in the upper 3x3 matrix, then the output of this function
1438/// is ill-defined.
1439///
1440/// The DirectXMath quaternion functions use an XMVECTOR 4-vector to represent quaternions, where the `X`,
1441/// `Y`, and `Z` components are the vector part and the `W` component is the scalar part.
1442///
1443/// ## Reference
1444///
1445/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMQuaternionRotationMatrix>
1446#[inline]
1447pub fn XMQuaternionRotationMatrix(
1448 M: XMMATRIX,
1449) -> FXMVECTOR
1450{
1451 #[cfg(_XM_NO_INTRINSICS_)]
1452 unsafe {
1453 let mut q: XMVECTORF32 = crate::undefined();
1454 let r22: f32 = M.m[2][2];
1455 if (r22 <= 0.0) // x^2 + y^2 >= z^2 + w^2
1456 {
1457 let dif10: f32 = M.m[1][1] - M.m[0][0];
1458 let omr22: f32 = 1.0 - r22;
1459 if (dif10 <= 0.0) // x^2 >= y^2
1460 {
1461 let fourXSqr: f32 = omr22 - dif10;
1462 let inv4x: f32 = 0.5 / sqrtf(fourXSqr);
1463 q.f[0] = fourXSqr * inv4x;
1464 q.f[1] = (M.m[0][1] + M.m[1][0]) * inv4x;
1465 q.f[2] = (M.m[0][2] + M.m[2][0]) * inv4x;
1466 q.f[3] = (M.m[1][2] - M.m[2][1]) * inv4x;
1467 }
1468 else // y^2 >= x^2
1469 {
1470 let fourYSqr: f32 = omr22 + dif10;
1471 let inv4y: f32 = 0.5 / sqrtf(fourYSqr);
1472 q.f[0] = (M.m[0][1] + M.m[1][0]) * inv4y;
1473 q.f[1] = fourYSqr * inv4y;
1474 q.f[2] = (M.m[1][2] + M.m[2][1]) * inv4y;
1475 q.f[3] = (M.m[2][0] - M.m[0][2]) * inv4y;
1476 }
1477 }
1478 else // z^2 + w^2 >= x^2 + y^2
1479 {
1480 let sum10: f32 = M.m[1][1] + M.m[0][0];
1481 let opr22: f32 = 1.0 + r22;
1482 if (sum10 <= 0.0) // z^2 >= w^2
1483 {
1484 let fourZSqr: f32 = opr22 - sum10;
1485 let inv4z: f32 = 0.5 / sqrtf(fourZSqr);
1486 q.f[0] = (M.m[0][2] + M.m[2][0]) * inv4z;
1487 q.f[1] = (M.m[1][2] + M.m[2][1]) * inv4z;
1488 q.f[2] = fourZSqr * inv4z;
1489 q.f[3] = (M.m[0][1] - M.m[1][0]) * inv4z;
1490 }
1491 else // w^2 >= z^2
1492 {
1493 let fourWSqr: f32 = opr22 + sum10;
1494 let inv4w: f32 = 0.5 / sqrtf(fourWSqr);
1495 q.f[0] = (M.m[1][2] - M.m[2][1]) * inv4w;
1496 q.f[1] = (M.m[2][0] - M.m[0][2]) * inv4w;
1497 q.f[2] = (M.m[0][1] - M.m[1][0]) * inv4w;
1498 q.f[3] = fourWSqr * inv4w;
1499 }
1500 }
1501 return q.v;
1502 }
1503
1504 #[cfg(_XM_ARM_NEON_INTRINSICS_)]
1505 {
1506 unimplemented!()
1507 }
1508
1509 #[cfg(_XM_SSE_INTRINSICS_)]
1510 unsafe {
1511 const XMPMMP: XMVECTORF32 = XMVECTORF32 { f: [ 1.0, -1.0, -1.0, 1.0 ] };
1512 const XMMPMP: XMVECTORF32 = XMVECTORF32 { f: [ -1.0, 1.0, -1.0, 1.0 ] };
1513 const XMMMPP: XMVECTORF32 = XMVECTORF32 { f: [ -1.0, -1.0, 1.0, 1.0 ] };
1514
1515 let r0: XMVECTOR = M.r[0]; // (r00, r01, r02, 0)
1516 let r1: XMVECTOR = M.r[1]; // (r10, r11, r12, 0)
1517 let r2: XMVECTOR = M.r[2]; // (r20, r21, r22, 0)
1518
1519 // (r00, r00, r00, r00)
1520 let r00: XMVECTOR = XM_PERMUTE_PS!(r0, _MM_SHUFFLE(0, 0, 0, 0));
1521 // (r11, r11, r11, r11)
1522 let r11: XMVECTOR = XM_PERMUTE_PS!(r1, _MM_SHUFFLE(1, 1, 1, 1));
1523 // (r22, r22, r22, r22)
1524 let r22: XMVECTOR = XM_PERMUTE_PS!(r2, _MM_SHUFFLE(2, 2, 2, 2));
1525
1526 // x^2 >= y^2 equivalent to r11 - r00 <= 0
1527 // (r11 - r00, r11 - r00, r11 - r00, r11 - r00)
1528 let r11mr00: XMVECTOR = _mm_sub_ps(r11, r00);
1529 let x2gey2: XMVECTOR = _mm_cmple_ps(r11mr00, g_XMZero.v);
1530
1531 // z^2 >= w^2 equivalent to r11 + r00 <= 0
1532 // (r11 + r00, r11 + r00, r11 + r00, r11 + r00)
1533 let r11pr00: XMVECTOR = _mm_add_ps(r11, r00);
1534 let z2gew2: XMVECTOR = _mm_cmple_ps(r11pr00, g_XMZero.v);
1535
1536 // x^2 + y^2 >= z^2 + w^2 equivalent to r22 <= 0
1537 let x2py2gez2pw2: XMVECTOR = _mm_cmple_ps(r22, g_XMZero.v);
1538
1539 // (4*x^2, 4*y^2, 4*z^2, 4*w^2)
1540 let mut t0: XMVECTOR = XM_FMADD_PS!(XMPMMP.v, r00, g_XMOne.v);
1541 let mut t1: XMVECTOR = _mm_mul_ps(XMMPMP.v, r11);
1542 let mut t2: XMVECTOR = XM_FMADD_PS!(XMMMPP.v, r22, t0);
1543 let x2y2z2w2: XMVECTOR = _mm_add_ps(t1, t2);
1544
1545 // (r01, r02, r12, r11)
1546 t0 = _mm_shuffle_ps(r0, r1, _MM_SHUFFLE(1, 2, 2, 1));
1547 // (r10, r10, r20, r21)
1548 t1 = _mm_shuffle_ps(r1, r2, _MM_SHUFFLE(1, 0, 0, 0));
1549 // (r10, r20, r21, r10)
1550 t1 = XM_PERMUTE_PS!(t1, _MM_SHUFFLE(1, 3, 2, 0));
1551 // (4*x*y, 4*x*z, 4*y*z, unused)
1552 let xyxzyz: XMVECTOR = _mm_add_ps(t0, t1);
1553
1554 // (r21, r20, r10, r10)
1555 t0 = _mm_shuffle_ps(r2, r1, _MM_SHUFFLE(0, 0, 0, 1));
1556 // (r12, r12, r02, r01)
1557 t1 = _mm_shuffle_ps(r1, r0, _MM_SHUFFLE(1, 2, 2, 2));
1558 // (r12, r02, r01, r12)
1559 t1 = XM_PERMUTE_PS!(t1, _MM_SHUFFLE(1, 3, 2, 0));
1560 // (4*x*w, 4*y*w, 4*z*w, unused)
1561 let mut xwywzw: XMVECTOR = _mm_sub_ps(t0, t1);
1562 xwywzw = _mm_mul_ps(XMMPMP.v, xwywzw);
1563
1564 // (4*x^2, 4*y^2, 4*x*y, unused)
1565 t0 = _mm_shuffle_ps(x2y2z2w2, xyxzyz, _MM_SHUFFLE(0, 0, 1, 0));
1566 // (4*z^2, 4*w^2, 4*z*w, unused)
1567 t1 = _mm_shuffle_ps(x2y2z2w2, xwywzw, _MM_SHUFFLE(0, 2, 3, 2));
1568 // (4*x*z, 4*y*z, 4*x*w, 4*y*w)
1569 t2 = _mm_shuffle_ps(xyxzyz, xwywzw, _MM_SHUFFLE(1, 0, 2, 1));
1570
1571 // (4*x*x, 4*x*y, 4*x*z, 4*x*w)
1572 let tensor0: XMVECTOR = _mm_shuffle_ps(t0, t2, _MM_SHUFFLE(2, 0, 2, 0));
1573 // (4*y*x, 4*y*y, 4*y*z, 4*y*w)
1574 let tensor1: XMVECTOR = _mm_shuffle_ps(t0, t2, _MM_SHUFFLE(3, 1, 1, 2));
1575 // (4*z*x, 4*z*y, 4*z*z, 4*z*w)
1576 let tensor2: XMVECTOR = _mm_shuffle_ps(t2, t1, _MM_SHUFFLE(2, 0, 1, 0));
1577 // (4*w*x, 4*w*y, 4*w*z, 4*w*w)
1578 let tensor3: XMVECTOR = _mm_shuffle_ps(t2, t1, _MM_SHUFFLE(1, 2, 3, 2));
1579
1580 // Select the row of the tensor-product matrix that has the largest
1581 // magnitude.
1582 t0 = _mm_and_ps(x2gey2, tensor0);
1583 t1 = _mm_andnot_ps(x2gey2, tensor1);
1584 t0 = _mm_or_ps(t0, t1);
1585 t1 = _mm_and_ps(z2gew2, tensor2);
1586 t2 = _mm_andnot_ps(z2gew2, tensor3);
1587 t1 = _mm_or_ps(t1, t2);
1588 t0 = _mm_and_ps(x2py2gez2pw2, t0);
1589 t1 = _mm_andnot_ps(x2py2gez2pw2, t1);
1590 t2 = _mm_or_ps(t0, t1);
1591
1592 // Normalize the row. No division by zero is possible because the
1593 // quaternion is unit-length (and the row is a nonzero multiple of
1594 // the quaternion).
1595 t0 = XMVector4Length(t2);
1596 return _mm_div_ps(t2, t0);
1597 }
1598}
1599
1600/// Computes an axis and angle of rotation about that axis for a given quaternion.
1601///
1602/// ## Parameters
1603///
1604/// `pAxis` Address of a 3D vector describing the axis of rotation for the quaternion `Q`.
1605///
1606/// `pAngle` Address of float describing the radian angle of rotation for the quaternion `Q`.
1607///
1608/// `Q` Quaternion to measure.
1609///
1610/// ## Return value
1611///
1612/// None.
1613///
1614/// ## Remarks
1615///
1616/// The DirectXMath quaternion functions use an XMVECTOR 4-vector to represent quaternions, where the `X`,
1617/// `Y`, and `Z` components are the vector part and the `W` component is the scalar part.
1618///
1619/// ## Reference
1620///
1621/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMQuaternionToAxisAngle>
1622#[inline]
1623pub fn XMQuaternionToAxisAngle(
1624 pAxis: &mut FXMVECTOR,
1625 pAngle: &mut f32,
1626 Q: FXMVECTOR,
1627)
1628{
1629 *pAxis = Q;
1630 *pAngle = 2.0 * XMScalarACos(XMVectorGetW(Q));
1631}
1632
1633/// Determines if two planes are equal.
1634///
1635/// ## Parameters
1636///
1637/// `P1` XMVECTOR describing the plane coefficients (`A`, `B`, `C`, `D`) for the plane equation `Ax+By+Cz+D=0`.
1638///
1639/// `P2` XMVECTOR describing the plane coefficients (`A`, `B`, `C`, `D`) for the plane equation `Ax+By+Cz+D=0`.
1640///
1641/// ## Return value
1642///
1643/// Returns `true` if the two planes are equal and `false` otherwise.
1644///
1645/// ## Remarks
1646///
1647/// The following pseudocode demonstrates the operation of the function.
1648///
1649/// ```text
1650/// return (P1.x == P2.x && P1.y == P2.y && P1.z == P2.z && P1.w == P2.w);
1651/// ```
1652///
1653/// ## Reference
1654///
1655/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMPlaneEqual>
1656#[inline]
1657pub fn XMPlaneEqual(
1658 P1: FXMVECTOR,
1659 P2: FXMVECTOR,
1660) -> bool
1661{
1662 return XMVector4Equal(P1, P2);
1663}
1664
1665
1666/// Determines whether two planes are nearly equal.
1667///
1668/// ## Parameters
1669///
1670/// `P1` XMVECTOR describing the plane coefficients (`A`, `B`, `C`, `D`) for the plane equation `Ax+By+Cz+D=0`.
1671///
1672/// `P2` XMVECTOR describing the plane coefficients (`A`, `B`, `C`, `D`) for the plane equation `Ax+By+Cz+D=0`.
1673///
1674/// `Epsilon` An XMVECTOR that gives the component-wise tolerance to use when comparing `P1` and `P2`.
1675///
1676/// ## Return value
1677///
1678/// Returns `true` if `P1` is nearly equal to `P2` and `false` otherwise.
1679///
1680/// ## Remarks
1681///
1682/// The XMPlaneNearEqual function normalizes the `P1` and `P2` parameters before passing them, and the `Epsilon`
1683/// parameter, to the [`XMVector4NearEqual`] function. For more information about how the calculation is performed,
1684/// see the [`XMVector4NearEqual`] function.
1685///
1686/// ## Reference
1687///
1688/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMPlaneNearEqual>
1689///
1690/// [`XMVector4NearEqual`]: crate::XMVector4NearEqual
1691#[inline]
1692pub fn XMPlaneNearEqual(
1693 P1: FXMVECTOR,
1694 P2: FXMVECTOR,
1695 Epsilon: FXMVECTOR,
1696) -> bool
1697{
1698 let NP1: XMVECTOR = XMPlaneNormalize(P1);
1699 let NP2: XMVECTOR = XMPlaneNormalize(P2);
1700 return XMVector4NearEqual(NP1, NP2, Epsilon);
1701}
1702
1703/// Determines if two planes are equal.
1704///
1705/// ## Parameters
1706///
1707/// `P1` XMVECTOR describing the plane coefficients (`A`, `B`, `C`, `D`) for the plane equation `Ax+By+Cz+D=0`.
1708///
1709/// `P2` XMVECTOR describing the plane coefficients (`A`, `B`, `C`, `D`) for the plane equation `Ax+By+Cz+D=0`.
1710///
1711/// ## Return value
1712///
1713/// Returns `true` if the two planes are unequal and `false` otherwise.
1714///
1715/// ## Remarks
1716///
1717/// The following pseudocode demonstrates the operation of the function.
1718///
1719/// ```text
1720/// return (P1.x != P2.x || P1.y != P2.y || P1.z != P2.z || P1.w != P2.w);
1721/// ```
1722///
1723/// ## Reference
1724///
1725/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMPlaneNotEqual>
1726#[inline]
1727pub fn XMPlaneNotEqual(
1728 P1: FXMVECTOR,
1729 P2: FXMVECTOR,
1730) -> bool
1731{
1732 return XMVector4NotEqual(P1, P2);
1733}
1734
1735/// Tests whether any of the coefficients of a plane is a NaN.
1736///
1737/// ## Parameters
1738///
1739/// `P` XMVECTOR describing the plane coefficients (`A`, `B`, `C`, `D`) for the plane equation `Ax+By+Cz+D=0`.
1740///
1741/// ## Return value
1742///
1743/// Returns `true` if any of the coefficients of the plane is a `NaN`, and `false` otherwise.
1744///
1745/// ## Reference
1746///
1747/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMPlaneIsNaN>
1748#[inline]
1749pub fn XMPlaneIsNaN(
1750 P: FXMVECTOR,
1751) -> bool
1752{
1753 return XMVector4IsNaN(P);
1754}
1755
1756/// Tests whether any of the coefficients of a plane is positive or negative infinity.
1757///
1758/// ## Parameters
1759///
1760/// `P` XMVECTOR describing the plane coefficients (`A`, `B`, `C`, `D`) for the plane equation `Ax+By+Cz+D=0`.
1761///
1762/// ## Return value
1763///
1764/// Returns `true` if any of the coefficients of the plane is positive or negative infinity, and `false` otherwise.
1765///
1766/// ## Reference
1767///
1768/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMPlaneIsInfinite>
1769#[inline]
1770pub fn XMPlaneIsInfinite(
1771 P: FXMVECTOR,
1772) -> bool
1773{
1774 return XMVector4IsInfinite(P);
1775}
1776
1777/// Calculates the dot product between an input plane and a 4D vector.
1778///
1779/// ## Parameters
1780///
1781/// `P` XMVECTOR describing the plane coefficients (`A`, `B`, `C`, `D`) for the plane equation `Ax+By+Cz+D=0`.
1782///
1783/// `V` 4D vector to use in the dot product.
1784///
1785/// ## Return value
1786///
1787/// Returns the dot product of `P` and `V` replicated into each of the four components of the returned XMVECTOR.
1788///
1789/// ## Remarks
1790///
1791/// The XMPlaneDot function is useful for determining the plane's relationship with a homogeneous coordinate.
1792/// For example, this function can be used to determine if a particular coordinate is on a particular plane,
1793/// or on which side of a particular plane a particular coordinate lies.
1794///
1795/// ## Reference
1796///
1797/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMPlaneDot>
1798#[inline]
1799pub fn XMPlaneDot(
1800 P: FXMVECTOR,
1801 V: FXMVECTOR,
1802) -> XMVECTOR
1803{
1804 return XMVector4Dot(P, V);
1805}
1806
1807/// Calculates the dot product between an input plane and a 3D vector.
1808///
1809/// ## Parameters
1810///
1811/// `P` XMVECTOR describing the plane coefficients (`A`, `B`, `C`, `D`) for the plane equation `Ax+By+Cz+D=0`.
1812///
1813/// `V` 3D vector to use in the dot product. The `w` component of `V` is always treated as if is `1.0`.
1814///
1815/// ## Return value
1816///
1817/// Returns the dot product between `P` and `V` replicated into each of the four components of the returned
1818/// XMVECTOR.
1819///
1820/// ## Remarks
1821///
1822/// This function can be useful in finding the signed distance from a point to a plane. The following pseudocode
1823/// demonstrates the operation of the function.
1824///
1825/// ```text
1826/// XMVECTOR vectorOut;
1827///
1828/// vectorOut.x = P.x * V.x + P.y * V.y + P.z * V.z + P.w * 1.0f;
1829/// vectorOut.y = P.x * V.x + P.y * V.y + P.z * V.z + P.w * 1.0f;
1830/// vectorOut.z = P.x * V.x + P.y * V.y + P.z * V.z + P.w * 1.0f;
1831/// vectorOut.w = P.x * V.x + P.y * V.y + P.z * V.z + P.w * 1.0f;
1832///
1833/// return vectorOut;
1834/// ```
1835///
1836/// ## Reference
1837///
1838/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMPlaneDotCoord>
1839#[inline]
1840pub fn XMPlaneDotCoord(
1841 P: FXMVECTOR,
1842 V: FXMVECTOR,
1843) -> XMVECTOR
1844{
1845 // Result = P[0] * V[0] + P[1] * V[1] + P[2] * V[2] + P[3]
1846
1847 unsafe {
1848 let V3: XMVECTOR = XMVectorSelect(g_XMOne.v, V, g_XMSelect1110.v);
1849 let Result: XMVECTOR = XMVector4Dot(P, V3);
1850 return Result;
1851 }
1852}
1853
1854
1855/// Calculates the dot product between the normal vector of a plane and a 3D vector.
1856///
1857/// ## Parameters
1858///
1859/// `P` XMVECTOR describing the plane coefficients (`A`, `B`, `C`, `D`) for the plane equation `Ax+By+Cz+D=0`.
1860///
1861/// `V` 3D vector to use in the dot product. The `w` component of `V` is always treated as if is `0.0`.
1862///
1863/// ## Return value
1864///
1865/// Returns the dot product between the normal vector of the plane and `V` replicated into each of the four
1866/// components of the returned XMVECTOR.
1867///
1868/// ## Remarks
1869///
1870/// This function is useful for calculating the angle between the normal vector of the plane, and another
1871/// normal vector. The following pseudocode demonstrates the operation of the function.
1872///
1873/// ```text
1874/// XMVECTOR vectorOut;
1875///
1876/// vectorOut.x = P.x * V.x + P.y * V.y + P.z * V.z;
1877/// vectorOut.y = P.x * V.x + P.y * V.y + P.z * V.z;
1878/// vectorOut.z = P.x * V.x + P.y * V.y + P.z * V.z;
1879/// vectorOut.w = P.x * V.x + P.y * V.y + P.z * V.z;
1880///
1881/// return vectorOut;
1882/// ```
1883///
1884/// ## Reference
1885///
1886/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMPlaneDotNormal>
1887#[inline]
1888pub fn XMPlaneDotNormal(
1889 P: FXMVECTOR,
1890 V: FXMVECTOR,
1891) -> XMVECTOR
1892{
1893 return XMVector3Dot(P, V);
1894}
1895
1896/// Estimates the coefficients of a plane so that coefficients of x, y, and z form a unit normal vector.
1897///
1898/// ## Parameters
1899///
1900/// `P` XMVECTOR describing the plane coefficients (`A`, `B`, `C`, `D`) for the plane equation `Ax+By+Cz+D=0`.
1901///
1902/// ## Return value
1903///
1904/// Returns an estimation of the normalized plane as a 4D vector whose components are the plane coefficients
1905/// (`A`, `B`, `C`, `D`) for the plane equation `Ax+By+Cz+D=0`.
1906///
1907/// ## Remarks
1908///
1909/// `Est` functions offer increased performance at the expense of reduced accuracy. `Est` functions are appropriate
1910/// for non-critical calculations where accuracy can be sacrificed for speed. The exact amount of lost accuracy
1911/// and speed increase are platform dependent.
1912///
1913/// ## Reference
1914///
1915/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMPlaneNormalizeEst>
1916#[inline]
1917pub fn XMPlaneNormalizeEst(
1918 P: FXMVECTOR,
1919) -> XMVECTOR
1920{
1921 #[cfg(_XM_NO_INTRINSICS_)]
1922 {
1923 let Result: XMVECTOR = XMVector3ReciprocalLengthEst(P);
1924 return XMVectorMultiply(P, Result);
1925 }
1926
1927 #[cfg(_XM_ARM_NEON_INTRINSICS_)]
1928 {
1929 unimplemented!()
1930 }
1931
1932 #[cfg(_XM_SSE_INTRINSICS_)]
1933 unsafe {
1934 // Perform the dot product
1935 let mut vDot: XMVECTOR = _mm_mul_ps(P, P);
1936 // x=Dot.y, y=Dot.z
1937 let mut vTemp: XMVECTOR = XM_PERMUTE_PS!(vDot, _MM_SHUFFLE(2, 1, 2, 1));
1938 // Result.x = x+y
1939 vDot = _mm_add_ss(vDot, vTemp);
1940 // x=Dot.z
1941 vTemp = XM_PERMUTE_PS!(vTemp, _MM_SHUFFLE(1, 1, 1, 1));
1942 // Result.x = (x+y)+z
1943 vDot = _mm_add_ss(vDot, vTemp);
1944 // Splat x
1945 vDot = XM_PERMUTE_PS!(vDot, _MM_SHUFFLE(0, 0, 0, 0));
1946 // Get the reciprocal
1947 vDot = _mm_rsqrt_ps(vDot);
1948 // Get the reciprocal
1949 vDot = _mm_mul_ps(vDot, P);
1950 return vDot;
1951 }
1952}
1953
1954/// Normalizes the coefficients of a plane so that coefficients of x, y, and z form a unit normal vector.
1955///
1956/// ## Parameters
1957///
1958/// `P` XMVECTOR describing the plane coefficients (`A`, `B`, `C`, `D`) for the plane equation `Ax+By+Cz+D=0`.
1959///
1960/// ## Return value
1961///
1962/// Returns the normalized plane as a 4D vector whose components are the plane coefficients (`A`, `B`, `C`, `D`)
1963/// for the plane equation `Ax+By+Cz+D=0`.
1964///
1965/// ## Remarks
1966///
1967/// The following pseudocode demonstrates the operation of the function:
1968///
1969/// ```text
1970/// XMVECTOR Result;
1971///
1972/// float LengthSq = P.x * P.x + P.y * P.y + P.z * P.z;
1973///
1974/// float ReciprocalLength = 1.0f / sqrt(LengthSq);
1975/// Result.x = P.x * ReciprocalLength;
1976/// Result.y = P.y * ReciprocalLength;
1977/// Result.z = P.z * ReciprocalLength;
1978/// Result.w = P.w * ReciprocalLength;
1979///
1980/// return Result;
1981/// ```
1982///
1983/// ## Reference
1984///
1985/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMPlaneNormalize>
1986#[inline]
1987pub fn XMPlaneNormalize(
1988 P: FXMVECTOR,
1989) -> XMVECTOR
1990{
1991 #[cfg(_XM_NO_INTRINSICS_)]
1992 unsafe {
1993 let mut fLengthSq: f32 = sqrtf((P.vector4_f32[0] * P.vector4_f32[0]) + (P.vector4_f32[1] * P.vector4_f32[1]) + (P.vector4_f32[2] * P.vector4_f32[2]));
1994 // Prevent divide by zero
1995 if (fLengthSq > 0.0)
1996 {
1997 fLengthSq = 1.0 / fLengthSq;
1998 }
1999 let vResult = XMVECTORF32 { f: [
2000 P.vector4_f32[0] * fLengthSq,
2001 P.vector4_f32[1] * fLengthSq,
2002 P.vector4_f32[2] * fLengthSq,
2003 P.vector4_f32[3] * fLengthSq
2004 ] };
2005 return vResult.v;
2006 }
2007
2008 #[cfg(_XM_ARM_NEON_INTRINSICS_)]
2009 unsafe {
2010 unimplemented!()
2011 }
2012
2013 #[cfg(_XM_SSE4_INTRINSICS_)]
2014 unsafe {
2015 let mut vLengthSq: XMVECTOR = _mm_dp_ps(P, P, 0x7f);
2016 // Prepare for the division
2017 let mut vResult: XMVECTOR = _mm_sqrt_ps(vLengthSq);
2018 // Failsafe on zero (Or epsilon) length planes
2019 // If the length is infinity, set the elements to zero
2020 vLengthSq = _mm_cmpneq_ps(vLengthSq, g_XMInfinity.v);
2021 // Reciprocal mul to perform the normalization
2022 vResult = _mm_div_ps(P, vResult);
2023 // Any that are infinity, set to zero
2024 vResult = _mm_and_ps(vResult, vLengthSq);
2025 return vResult;
2026 }
2027
2028 #[cfg(all(_XM_SSE_INTRINSICS_, not(_XM_SSE4_INTRINSICS_)))]
2029 unsafe {
2030 let mut vLengthSq: XMVECTOR = _mm_dp_ps(P, P, 0x7f);
2031 // Prepare for the division
2032 let mut vResult: XMVECTOR = _mm_sqrt_ps(vLengthSq);
2033 // Failsafe on zero (Or epsilon) length planes
2034 // If the length is infinity, set the elements to zero
2035 vLengthSq = _mm_cmpneq_ps(vLengthSq, g_XMInfinity.v);
2036 // Reciprocal mul to perform the normalization
2037 vResult = _mm_div_ps(P, vResult);
2038 // Any that are infinity, set to zero
2039 vResult = _mm_and_ps(vResult, vLengthSq);
2040 return vResult;
2041 }
2042}
2043
2044/// Finds the intersection between a plane and a line.
2045///
2046/// ## Parameters
2047///
2048/// `P` XMVECTOR describing the plane coefficients (`A`, `B`, `C`, `D`) for the plane equation `Ax+By+Cz+D=0`.
2049///
2050/// `LinePoint1` 3D vector describing the first point on the line.
2051///
2052/// `LinePoint2` 3D vector describing the second point on the line.
2053///
2054/// ## Return value
2055///
2056/// Returns the intersection of the plane P and the line defined by `LinePoint1` and `LinePoint2`. If the line
2057/// is parallel to the plane, all components of the returned vector are equal to `QNaN`.
2058///
2059/// ## Reference
2060///
2061/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMPlaneIntersectLine>
2062#[inline]
2063pub fn XMPlaneIntersectLine(
2064 P: FXMVECTOR,
2065 LinePoint1: FXMVECTOR,
2066 LinePoint2: FXMVECTOR,
2067) -> XMVECTOR
2068{
2069 unsafe {
2070 let V1: XMVECTOR = XMVector3Dot(P, LinePoint1);
2071 let V2: XMVECTOR = XMVector3Dot(P, LinePoint2);
2072 let D: XMVECTOR = XMVectorSubtract(V1, V2);
2073
2074 let mut VT: XMVECTOR = XMPlaneDotCoord(P, LinePoint1);
2075 VT = XMVectorDivide(VT, D);
2076
2077 let mut Point: XMVECTOR = XMVectorSubtract(LinePoint2, LinePoint1);
2078 Point = XMVectorMultiplyAdd(Point, VT, LinePoint1);
2079
2080 // const
2081 let Zero: XMVECTOR = XMVectorZero();
2082 let Control: XMVECTOR = XMVectorNearEqual(D, Zero, g_XMEpsilon.v);
2083
2084 return XMVectorSelect(Point, g_XMQNaN.v, Control);
2085 }
2086}
2087
2088/// Finds the intersection of two planes.
2089///
2090/// ## Parameters
2091///
2092/// `pLinePoint1` Address of a 3D vector describing one point on the line of intersection. See remarks.
2093///
2094/// `pLinePoint2` Address of a 3D vector describing a second point on the line of intersection. See remarks.
2095///
2096/// `P1` XMVECTOR describing the plane coefficients (`A`, `B`, `C`, `D`) for the plane equation `Ax+By+Cz+D=0`.
2097///
2098/// `P2` XMVECTOR describing the plane coefficients (`A`, `B`, `C`, `D`) for the plane equation `Ax+By+Cz+D=0`.
2099///
2100/// ## Return value
2101///
2102/// None.
2103///
2104/// ## Remarks
2105///
2106/// If the planes are parallel to one another, all components of the returned point vectors are equal to
2107/// QNaN.
2108///
2109/// ## Reference
2110///
2111/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMPlaneIntersectPlane>
2112#[inline]
2113pub fn XMPlaneIntersectPlane(
2114 pLinePoint1: &mut FXMVECTOR,
2115 pLinePoint2: &mut FXMVECTOR,
2116 P1: FXMVECTOR,
2117 P2: FXMVECTOR,
2118)
2119{
2120 unsafe {
2121 let V1: XMVECTOR = XMVector3Cross(P2, P1);
2122
2123 let LengthSq: XMVECTOR = XMVector3LengthSq(V1);
2124
2125 let V2: XMVECTOR = XMVector3Cross(P2, V1);
2126
2127 let P1W: XMVECTOR = XMVectorSplatW(P1);
2128 let mut Point: XMVECTOR = XMVectorMultiply(V2, P1W);
2129
2130 let V3: XMVECTOR = XMVector3Cross(V1, P1);
2131
2132 let P2W: XMVECTOR = XMVectorSplatW(P2);
2133 Point = XMVectorMultiplyAdd(V3, P2W, Point);
2134
2135 let LinePoint1: XMVECTOR = XMVectorDivide(Point, LengthSq);
2136
2137 let LinePoint2: XMVECTOR = XMVectorAdd(LinePoint1, V1);
2138
2139 let Control: XMVECTOR = XMVectorLessOrEqual(LengthSq, g_XMEpsilon.v);
2140 *pLinePoint1 = XMVectorSelect(LinePoint1, g_XMQNaN.v, Control);
2141 *pLinePoint2 = XMVectorSelect(LinePoint2, g_XMQNaN.v, Control);
2142 }
2143}
2144
2145/// Transforms a plane by a given matrix.
2146///
2147/// ## Parameters
2148///
2149/// `P` XMVECTOR describing the plane coefficients (`A`, `B`, `C`, `D`) for the plane equation `Ax+By+Cz+D=0`.
2150///
2151/// `M` Transformation matrix.
2152///
2153/// ## Return value
2154///
2155/// Returns the transformed plane as a 4D vector whose components are the plane coefficients (`A`, `B`, `C`, `D`)
2156/// for the plane equation `Ax+By+Cz+D=0`.
2157///
2158/// ## Reference
2159///
2160/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMPlaneTransform>
2161#[inline]
2162pub fn XMPlaneTransform(
2163 P: FXMVECTOR,
2164 M: FXMMATRIX,
2165) -> XMVECTOR
2166{
2167 unsafe {
2168 let W: XMVECTOR = XMVectorSplatW(P);
2169 let Z: XMVECTOR = XMVectorSplatZ(P);
2170 let Y: XMVECTOR = XMVectorSplatY(P);
2171 let X: XMVECTOR = XMVectorSplatX(P);
2172
2173 let mut Result: XMVECTOR = XMVectorMultiply(W, M.r[3]);
2174 Result = XMVectorMultiplyAdd(Z, M.r[2], Result);
2175 Result = XMVectorMultiplyAdd(Y, M.r[1], Result);
2176 Result = XMVectorMultiplyAdd(X, M.r[0], Result);
2177 return Result;
2178 }
2179}
2180
2181// TODO: XMPlaneTransformStream
2182
2183/// Computes the equation of a plane constructed from a point in the plane and a normal vector.
2184///
2185/// ## Parameters
2186///
2187/// `Point` 3D vector describing a point in the plane.
2188///
2189/// `Normal` 3D vector normal to the plane.
2190///
2191/// ## Return value
2192///
2193/// Returns a vector whose components are the coefficients of the plane (`A`, `B`, `C`, `D`) for the plane equation
2194/// `Ax+By+Cz+D=0`.
2195///
2196/// ## Remarks
2197///
2198/// The following pseudocode demonstrates the operation of the function:
2199///
2200/// ```text
2201/// XMVECTOR Result;
2202///
2203/// Result.x = Normal.x;
2204/// Result.y = Normal.y;
2205/// Result.z = Normal.z;
2206/// Result.w = -(Point.x * Normal.x + Point.y * Normal.y + Point.z * Normal.z);
2207///
2208/// return Result;
2209/// ```
2210///
2211/// ## Reference
2212///
2213/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMPlaneFromPointNormal>
2214#[inline]
2215pub fn XMPlaneFromPointNormal(
2216 Point: FXMVECTOR,
2217 Normal: FXMVECTOR,
2218) -> XMVECTOR
2219{
2220 unsafe {
2221 let mut W: XMVECTOR = XMVector3Dot(Point, Normal);
2222 W = XMVectorNegate(W);
2223 return XMVectorSelect(W, Normal, g_XMSelect1110.v);
2224 }
2225}
2226
2227/// Computes the equation of a plane constructed from three points in the plane.
2228///
2229/// ## Parameters
2230///
2231/// `Point1` 3D vector describing a point in the plane.
2232///
2233/// `Point2` 3D vector describing a point in the plane.
2234///
2235/// `Point3` 3D vector describing a point in the plane.
2236///
2237/// ## Return value
2238///
2239/// Returns a vector whose components are the coefficients of the plane (`A`, `B`, `C`, `D`) for the plane equation
2240/// `Ax+By+Cz+D=0`.
2241///
2242/// ## Remarks
2243///
2244/// The following pseudocode demonstrates the operation of the function:
2245///
2246/// ```text
2247/// XMVECTOR Result;
2248/// XMVECTOR N;
2249/// XMVECTOR D;
2250///
2251/// XMVECTOR V21 = XMVectorSubtract(Point1, Point2);
2252/// XMVECTOR V31 = XMVectorSubtract(Point1, Point3);
2253///
2254/// N = XMVector3Cross(V21, V31);
2255/// N = XMVector3Normalize(N);
2256///
2257/// D = XMPlaneDotNormal(N, Point1);
2258///
2259/// Result.x = N.x;
2260/// Result.y = N.y;
2261/// Result.z = N.z;
2262/// Result.w = -D.w;
2263///
2264/// return Result;
2265/// ```
2266///
2267/// ## Reference
2268///
2269/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMPlaneFromPoints>
2270#[inline]
2271pub fn XMPlaneFromPoints(
2272 Point1: FXMVECTOR,
2273 Point2: FXMVECTOR,
2274 Point3: FXMVECTOR,
2275) -> XMVECTOR
2276{
2277 unsafe {
2278 let V21: XMVECTOR = XMVectorSubtract(Point1, Point2);
2279 let V31: XMVECTOR = XMVectorSubtract(Point1, Point3);
2280
2281 let mut N: XMVECTOR = XMVector3Cross(V21, V31);
2282 N = XMVector3Normalize(N);
2283
2284 let mut D: XMVECTOR = XMPlaneDotNormal(N, Point1);
2285 D = XMVectorNegate(D);
2286
2287 let Result: XMVECTOR = XMVectorSelect(D, N, g_XMSelect1110.v);
2288
2289 return Result;
2290 }
2291}
2292
2293// TODO: XMColorEqual
2294// TODO: XMColorNotEqual
2295// TODO: XMColorGreater
2296// TODO: XMColorGreaterOrEqual
2297// TODO: XMColorLess
2298// TODO: XMColorLessOrEqual
2299// TODO: XMColorIsNaN
2300// TODO: XMColorIsInfinite
2301// TODO: XMColorNegative
2302// TODO: XMColorModulate
2303// TODO: XMColorAdjustSaturation
2304// TODO: XMColorAdjustContrast
2305// TODO: XMColorRGBToHSL
2306// TODO: XMColorHue2Clr
2307// TODO: XMColorHSLToRGB
2308// TODO: XMColorRGBToHSV
2309// TODO: XMColorHSVToRGB
2310// TODO: XMColorRGBToYUV
2311// TODO: XMColorYUVToRGB
2312// TODO: XMColorRGBToYUV_HD
2313// TODO: XMColorYUVToRGB_HD
2314// TODO: XMColorRGBToXYZ
2315// TODO: XMColorXYZToRGB
2316// TODO: XMColorXYZToSRGB
2317// TODO: XMColorSRGBToXYZ
2318// TODO: XMColorRGBToSRGB
2319// TODO: XMColorSRGBToRGB
2320
2321// TODO: XMVerifyCPUSupport (NOTE: __cpuid)
2322
2323/// Calculates the Fresnel term for unpolarized light.
2324///
2325/// ## Parameters
2326///
2327/// `CosIncidentAngle` Vector consisting of the cosines of the incident angles.
2328///
2329/// `RefractionIndex` Vector consisting of the refraction indices of the materials corresponding to the incident angles.
2330///
2331/// ## Return value
2332///
2333/// Returns a vector containing the Fresnel term of each component.
2334///
2335/// ## Reference
2336///
2337/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMFresnelTerm>
2338#[inline]
2339pub fn XMFresnelTerm(
2340 CosIncidentAngle: FXMVECTOR,
2341 RefractionIndex: FXMVECTOR,
2342) -> FXMVECTOR
2343{
2344 debug_assert!(!XMVector4IsInfinite(CosIncidentAngle));
2345
2346 // Result = 0.5f * (g - c)^2 / (g + c)^2 * ((c * (g + c) - 1)^2 / (c * (g - c) + 1)^2 + 1) where
2347 // c = CosIncidentAngle
2348 // g = sqrt(c^2 + RefractionIndex^2 - 1)
2349
2350 #[cfg(_XM_NO_INTRINSICS_)]
2351 unsafe {
2352 let mut G: XMVECTOR = XMVectorMultiplyAdd(RefractionIndex, RefractionIndex, g_XMNegativeOne.v);
2353 G = XMVectorMultiplyAdd(CosIncidentAngle, CosIncidentAngle, G);
2354 G = XMVectorAbs(G);
2355 G = XMVectorSqrt(G);
2356
2357 let S: XMVECTOR = XMVectorAdd(G, CosIncidentAngle);
2358 let D: XMVECTOR = XMVectorSubtract(G, CosIncidentAngle);
2359
2360 let mut V0: XMVECTOR = XMVectorMultiply(D, D);
2361 let mut V1: XMVECTOR = XMVectorMultiply(S, S);
2362 V1 = XMVectorReciprocal(V1);
2363 V0 = XMVectorMultiply(g_XMOneHalf.v, V0);
2364 V0 = XMVectorMultiply(V0, V1);
2365
2366 let mut V2: XMVECTOR = XMVectorMultiplyAdd(CosIncidentAngle, S, g_XMNegativeOne.v);
2367 let mut V3: XMVECTOR = XMVectorMultiplyAdd(CosIncidentAngle, D, g_XMOne.v);
2368 V2 = XMVectorMultiply(V2, V2);
2369 V3 = XMVectorMultiply(V3, V3);
2370 V3 = XMVectorReciprocal(V3);
2371 V2 = XMVectorMultiplyAdd(V2, V3, g_XMOne.v);
2372
2373 let mut Result: XMVECTOR = XMVectorMultiply(V0, V2);
2374
2375 Result = XMVectorSaturate(Result);
2376
2377 return Result;
2378 }
2379
2380 #[cfg(_XM_ARM_NEON_INTRINSICS_)]
2381 {
2382 unimplemented!()
2383 }
2384
2385 #[cfg(_XM_SSE_INTRINSICS_)]
2386 unsafe {
2387 // G = sqrt(abs((RefractionIndex^2-1) + CosIncidentAngle^2))
2388 let mut G: XMVECTOR = _mm_mul_ps(RefractionIndex, RefractionIndex);
2389 let mut vTemp: XMVECTOR = _mm_mul_ps(CosIncidentAngle, CosIncidentAngle);
2390 G = _mm_sub_ps(G, g_XMOne.v);
2391 vTemp = _mm_add_ps(vTemp, G);
2392 // max((0-vTemp),vTemp) == abs(vTemp)
2393 // The abs is needed to deal with refraction and cosine being zero
2394 G = _mm_setzero_ps();
2395 G = _mm_sub_ps(G, vTemp);
2396 G = _mm_max_ps(G, vTemp);
2397 // Last operation, the sqrt()
2398 G = _mm_sqrt_ps(G);
2399
2400 // Calc G-C and G+C
2401 let mut GAddC: XMVECTOR = _mm_add_ps(G, CosIncidentAngle);
2402 let mut GSubC: XMVECTOR = _mm_sub_ps(G, CosIncidentAngle);
2403 // Perform the term (0.5f *(g - c)^2) / (g + c)^2
2404 let mut vResult: XMVECTOR = _mm_mul_ps(GSubC, GSubC);
2405 vTemp = _mm_mul_ps(GAddC, GAddC);
2406 vResult = _mm_mul_ps(vResult, g_XMOneHalf.v);
2407 vResult = _mm_div_ps(vResult, vTemp);
2408 // Perform the term ((c * (g + c) - 1)^2 / (c * (g - c) + 1)^2 + 1)
2409 GAddC = _mm_mul_ps(GAddC, CosIncidentAngle);
2410 GSubC = _mm_mul_ps(GSubC, CosIncidentAngle);
2411 GAddC = _mm_sub_ps(GAddC, g_XMOne.v);
2412 GSubC = _mm_add_ps(GSubC, g_XMOne.v);
2413 GAddC = _mm_mul_ps(GAddC, GAddC);
2414 GSubC = _mm_mul_ps(GSubC, GSubC);
2415 GAddC = _mm_div_ps(GAddC, GSubC);
2416 GAddC = _mm_add_ps(GAddC, g_XMOne.v);
2417 // Multiply the two term parts
2418 vResult = _mm_mul_ps(vResult, GAddC);
2419 // Clamp to 0.0 - 1.0f
2420 vResult = _mm_max_ps(vResult, g_XMZero.v);
2421 vResult = _mm_min_ps(vResult, g_XMOne.v);
2422 return vResult;
2423 }
2424}
2425
2426/// Determines if two floating-point values are nearly equal.
2427///
2428/// ## Parameters
2429///
2430/// `S1` First floating-point value to compare.
2431///
2432/// `S2` Second floating-point value to compare.
2433///
2434/// `Epsilon` Tolerance to use when comparing `S1` and `S2`.
2435///
2436/// ## Return value
2437///
2438/// Returns `true` if the absolute value of the difference between `S1` and `S2` is less than or equal to `Epsilon`.
2439/// Returns `false` otherwise.
2440///
2441/// ## Reference
2442///
2443/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMScalarNearEqual>
2444#[inline]
2445pub fn XMScalarNearEqual(
2446 S1: f32,
2447 S2: f32,
2448 Epsilon: f32
2449) -> bool
2450{
2451 let Delta: f32 = S1 - S2;
2452 return (fabsf(Delta) <= Epsilon);
2453}
2454
2455/// Computes an angle between `-XM_PI` and `XM_PI`.
2456///
2457/// ## Parameters
2458///
2459/// `Value` float value describing the radian angle.
2460///
2461/// ## Return value
2462///
2463/// Returns an angle greater than or equal to `-XM_PI` and less than `XM_PI` that is congruent to `Value` modulo
2464/// `2 PI`.
2465///
2466///
2467/// ## Reference
2468///
2469/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMScalarModAngle>
2470#[inline]
2471pub fn XMScalarModAngle(
2472 Angle: f32
2473) -> f32
2474{
2475 // Note: The modulo is performed with unsigned math only to work
2476 // around a precision error on numbers that are close to PI
2477
2478 // Normalize the range from 0.0f to XM_2PI
2479 let Angle = Angle + XM_PI;
2480 // Perform the modulo, unsigned
2481 let mut fTemp: f32 = fabsf(Angle);
2482 fTemp = fTemp - (XM_2PI * ((fTemp / XM_2PI) as i32) as f32);
2483 // Restore the number to the range of -XM_PI to XM_PI-epsilon
2484 fTemp = fTemp - XM_PI;
2485 // If the modulo'd value was negative, restore negation
2486 if (Angle < 0.0)
2487 {
2488 fTemp = -fTemp;
2489 }
2490 return fTemp;
2491}
2492
2493/// Computes the sine of a radian angle.
2494///
2495/// # Remarks
2496///
2497/// This function uses a 11-degree minimax approximation.
2498///
2499/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMScalarSin>
2500#[inline]
2501pub fn XMScalarSin(
2502 Value: f32
2503) -> f32
2504{
2505 // Map Value to y in [-pi,pi], x = 2*pi*quotient + remainder.
2506 let mut quotient: f32 = XM_1DIV2PI * Value;
2507 if (Value >= 0.0)
2508 {
2509 quotient = ((quotient + 0.5) as i32) as f32;
2510 }
2511 else
2512 {
2513 quotient = ((quotient - 0.5) as i32) as f32;
2514 }
2515 let mut y: f32 = Value - XM_2PI * quotient;
2516
2517 // Map y to [-pi/2,pi/2] with sin(y) = sin(Value).
2518 if (y > XM_PIDIV2)
2519 {
2520 y = XM_PI - y;
2521 }
2522 else if (y < -XM_PIDIV2)
2523 {
2524 y = -XM_PI - y;
2525 }
2526
2527 // 11-degree minimax approximation
2528 let y2: f32 = y * y;
2529 return (((((-2.3889859e-08 * y2 + 2.7525562e-06) * y2 - 0.00019840874) * y2 + 0.0083333310) * y2 - 0.16666667) * y2 + 1.0) * y;
2530}
2531
2532/// Estimates the sine of a radian angle.
2533///
2534/// # Remarks
2535///
2536/// This function uses a 7-degree minimax approximation.
2537///
2538/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMScalarSinEst>
2539#[inline]
2540pub fn XMScalarSinEst(
2541 Value: f32
2542) -> f32
2543{
2544 // Map Value to y in [-pi,pi], x = 2*pi*quotient + remainder.
2545 let mut quotient: f32 = XM_1DIV2PI * Value;
2546 if (Value >= 0.0)
2547 {
2548 quotient = ((quotient + 0.5) as i32) as f32;
2549 }
2550 else
2551 {
2552 quotient = ((quotient - 0.5) as i32) as f32;
2553 }
2554 let mut y: f32 = Value - XM_2PI * quotient;
2555
2556 // Map y to [-pi/2,pi/2] with sin(y) = sin(Value).
2557 if (y > XM_PIDIV2)
2558 {
2559 y = XM_PI - y;
2560 }
2561 else if (y < -XM_PIDIV2)
2562 {
2563 y = -XM_PI - y;
2564 }
2565
2566 // 7-degree minimax approximation
2567 let y2: f32 = y * y;
2568 return (((-0.00018524670 * y2 + 0.0083139502) * y2 - 0.16665852) * y2 + 1.0) * y;
2569}
2570
2571/// Computes the cosine of a radian angle.
2572///
2573/// # Remarks
2574///
2575/// This function uses a 10-degree minimax approximation.
2576///
2577/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMScalarCos>
2578#[inline]
2579pub fn XMScalarCos(
2580 Value: f32
2581) -> f32
2582{
2583 // Map Value to y in [-pi,pi], x = 2*pi*quotient + remainder.
2584 let mut quotient: f32 = XM_1DIV2PI * Value;
2585 if (Value >= 0.0)
2586 {
2587 quotient = ((quotient + 0.5) as i32) as f32;
2588 }
2589 else
2590 {
2591 quotient = ((quotient - 0.5) as i32) as f32;
2592 }
2593 let mut y: f32 = Value - XM_2PI * quotient;
2594
2595 // Map y to [-pi/2,pi/2] with cos(y) = sign*cos(x).
2596 let sign: f32;
2597 if (y > XM_PIDIV2)
2598 {
2599 y = XM_PI - y;
2600 sign = -1.0;
2601 }
2602 else if (y < -XM_PIDIV2)
2603 {
2604 y = -XM_PI - y;
2605 sign = -1.0;
2606 }
2607 else
2608 {
2609 sign = 1.0;
2610 }
2611
2612 // 10-degree minimax approximation
2613 let y2: f32 = y * y;
2614 let p: f32 = ((((-2.6051615e-07 * y2 + 2.4760495e-05) * y2 - 0.0013888378) * y2 + 0.041666638) * y2 - 0.5) * y2 + 1.0;
2615 return sign * p;
2616}
2617
2618/// Estimates the cosine of a radian angle.
2619///
2620/// ## Parameters
2621///
2622/// `Value` float value describing the radian angle.
2623///
2624/// ## Return value
2625///
2626/// Returns the cosine of Value.
2627///
2628/// ## Remarks
2629///
2630/// `Est` functions offer increased performance at the expense of reduced accuracy. `Est` functions are appropriate
2631/// for non-critical calculations where accuracy can be sacrificed for speed. The exact amount of lost accuracy
2632/// and speed increase are platform dependent.
2633///
2634/// This function uses a 6-degree minimax approximation.
2635///
2636/// ## Reference
2637///
2638/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMScalarCosEst>
2639#[inline]
2640pub fn XMScalarCosEst(
2641 Value: f32
2642) -> f32
2643{
2644 // Map Value to y in [-pi,pi], x = 2*pi*quotient + remainder.
2645 let mut quotient: f32 = XM_1DIV2PI * Value;
2646 if (Value >= 0.0)
2647 {
2648 quotient = ((quotient + 0.5) as i32) as f32;
2649 }
2650 else
2651 {
2652 quotient = ((quotient - 0.5) as i32) as f32;
2653 }
2654 let mut y: f32 = Value - XM_2PI * quotient;
2655
2656 // Map y to [-pi/2,pi/2] with cos(y) = sign*cos(x).
2657 let sign: f32;
2658 if (y > XM_PIDIV2)
2659 {
2660 y = XM_PI - y;
2661 sign = -1.0;
2662 }
2663 else if (y < -XM_PIDIV2)
2664 {
2665 y = -XM_PI - y;
2666 sign = -1.0;
2667 }
2668 else
2669 {
2670 sign = 1.0;
2671 }
2672
2673 // 6-degree minimax approximation
2674 let y2: f32 = y * y;
2675 let p: f32 = ((-0.0012712436 * y2 + 0.041493919) * y2 - 0.49992746) * y2 + 1.0;
2676 return sign * p;
2677}
2678
2679/// Computes both the sine and cosine of a radian angle.
2680///
2681/// ## Parameters
2682///
2683/// `pSin` Address of a float that will contain the result of the sine of Value.
2684///
2685/// `pCos` Address of a float that will contain the result of the cosine of Value.
2686///
2687/// `Value` float value describing the radian angle.
2688///
2689/// ## Return value
2690///
2691/// None
2692///
2693/// ## Remarks
2694///
2695/// This function uses a 11-degree minimax approximation for sine; 10-degree for cosine.
2696///
2697/// ## Reference
2698///
2699/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMScalarSinCos>
2700#[inline]
2701pub fn XMScalarSinCos(
2702 pSin: &mut f32,
2703 pCos: &mut f32,
2704 Value: f32,
2705)
2706{
2707 // assert(pSin);
2708 // assert(pCos);
2709
2710 // Map Value to y in [-pi,pi], x = 2*pi*quotient + remainder.
2711 let mut quotient: f32 = XM_1DIV2PI * Value;
2712 if (Value >= 0.0)
2713 {
2714 quotient = ((quotient + 0.5) as i32) as f32;
2715 }
2716 else
2717 {
2718 quotient = ((quotient - 0.5) as i32) as f32;
2719 }
2720 let mut y: f32 = Value - XM_2PI * quotient;
2721
2722 // Map y to [-pi/2,pi/2] with sin(y) = sin(Value).
2723 let sign: f32;
2724 if (y > XM_PIDIV2)
2725 {
2726 y = XM_PI - y;
2727 sign = -1.0;
2728 }
2729 else if (y < -XM_PIDIV2)
2730 {
2731 y = -XM_PI - y;
2732 sign = -1.0;
2733 }
2734 else
2735 {
2736 sign = 1.0; // +1.0
2737 }
2738
2739 let y2: f32 = y * y;
2740
2741 // 11-degree minimax approximation
2742 *pSin = (((((-2.3889859e-08 * y2 + 2.7525562e-06) * y2 - 0.00019840874) * y2 + 0.0083333310) * y2 - 0.16666667) * y2 + 1.0) * y;
2743
2744 // 10-degree minimax approximation
2745 let p: f32 = ((((-2.6051615e-07 * y2 + 2.4760495e-05) * y2 - 0.0013888378) * y2 + 0.041666638) * y2 - 0.5) * y2 + 1.0;
2746 *pCos = sign * p;
2747}
2748
2749/// Estimates both the sine and cosine of a radian angle.
2750///
2751/// ## Parameters
2752///
2753/// `pSin` Address of a float that will contain the result of the sine of Value.
2754///
2755/// `pCos` Address of a float that will contain the result of the cosine of Value.
2756///
2757/// `Value` float value describing the radian angle.
2758///
2759/// ## Return value
2760///
2761/// None
2762///
2763/// ## Remarks
2764///
2765/// `Est` functions offer increased performance at the expense of reduced accuracy. `Est` functions are appropriate
2766/// for non-critical calculations where accuracy can be sacrificed for speed. The exact amount of lost accuracy
2767/// and speed increase are platform dependent.
2768///
2769/// This function uses a 7-degree minimax approximation for sine; 6-degree for cosine.
2770///
2771/// ## Reference
2772///
2773/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMScalarSinCosEst>
2774#[inline]
2775pub fn XMScalarSinCosEst(
2776 pSin: &mut f32,
2777 pCos: &mut f32,
2778 Value: f32,
2779)
2780{
2781 // assert(pSin);
2782 // assert(pCos);
2783
2784 // Map Value to y in [-pi,pi], x = 2*pi*quotient + remainder.
2785 let mut quotient: f32 = XM_1DIV2PI * Value;
2786 if (Value >= 0.0)
2787 {
2788 quotient = ((quotient + 0.5) as i32) as f32;
2789 }
2790 else
2791 {
2792 quotient = ((quotient - 0.5) as i32) as f32;
2793 }
2794 let mut y: f32 = Value - XM_2PI * quotient;
2795
2796 // Map y to [-pi/2,pi/2] with sin(y) = sin(Value).
2797 let sign: f32;
2798 if (y > XM_PIDIV2)
2799 {
2800 y = XM_PI - y;
2801 sign = -1.0;
2802 }
2803 else if (y < -XM_PIDIV2)
2804 {
2805 y = -XM_PI - y;
2806 sign = -1.0;
2807 }
2808 else
2809 {
2810 sign = 1.0;
2811 }
2812
2813 let y2: f32 = y * y;
2814
2815 // 7-degree minimax approximation
2816 *pSin = (((-0.00018524670 * y2 + 0.0083139502) * y2 - 0.16665852) * y2 + 1.0) * y;
2817
2818 // 6-degree minimax approximation
2819 let p: f32 = ((-0.0012712436 * y2 + 0.041493919) * y2 - 0.49992746) * y2 + 1.0;
2820 *pCos = sign * p;
2821}
2822
2823/// Computes the arcsine of a floating-point number.
2824///
2825/// ## Parameters
2826///
2827/// `Value` float value between `-1.0` and `1.0`.
2828///
2829/// ## Return value
2830///
2831/// Returns the inverse sine of Value.
2832///
2833/// ## Remarks
2834///
2835/// This function uses a 7-degree minimax approximation
2836///
2837/// ## Reference
2838///
2839/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMScalarASin>
2840#[inline]
2841pub fn XMScalarASin(
2842 Value: f32,
2843) -> f32
2844{
2845 // Clamp input to [-1,1].
2846 let nonnegative: bool = (Value >= 0.0);
2847 let x: f32 = fabsf(Value);
2848 let mut omx: f32 = 1.0 - x;
2849 if (omx < 0.0)
2850 {
2851 omx = 0.0;
2852 }
2853 let root: f32 = sqrtf(omx);
2854
2855 // 7-degree minimax approximation
2856 let mut result: f32 = ((((((-0.0012624911 * x + 0.0066700901) * x - 0.0170881256) * x + 0.0308918810) * x - 0.0501743046) * x + 0.0889789874) * x - 0.2145988016) * x + 1.5707963050;
2857 result *= root; // acos(|x|)
2858
2859 // acos(x) = pi - acos(-x) when x < 0, asin(x) = pi/2 - acos(x)
2860 return (if nonnegative { XM_PIDIV2 - result } else { result - XM_PIDIV2 });
2861}
2862
2863
2864/// Estimates the arcsine of a floating-point number.
2865///
2866/// ## Parameters
2867///
2868/// `Value` float value between `-1.0` and `1.0`.
2869///
2870/// ## Return value
2871///
2872/// Returns the inverse sine of Value.
2873///
2874/// ## Remarks
2875///
2876/// `Est` functions offer increased performance at the expense of reduced accuracy. `Est` functions are appropriate
2877/// for non-critical calculations where accuracy can be sacrificed for speed. The exact amount of lost accuracy
2878/// and speed increase are platform dependent.
2879///
2880/// This function uses a 3-degree minimax approximation.
2881///
2882/// ## Reference
2883///
2884///
2885/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMScalarASinEst>
2886#[inline]
2887pub fn XMScalarASinEst(
2888 Value: f32,
2889) -> f32
2890{
2891 // Clamp input to [-1,1].
2892 let nonnegative: bool = (Value >= 0.0);
2893 let x: f32 = fabsf(Value);
2894 let mut omx: f32 = 1.0 - x;
2895 if (omx < 0.0)
2896 {
2897 omx = 0.0;
2898 }
2899 let root: f32 = sqrtf(omx);
2900
2901 // 3-degree minimax approximation
2902 let mut result: f32 = ((-0.0187293 * x + 0.0742610) * x - 0.2121144) * x + 1.5707288;
2903 result *= root; // acos(|x|)
2904
2905 // acos(x) = pi - acos(-x) when x < 0, asin(x) = pi/2 - acos(x)
2906 return (if nonnegative { XM_PIDIV2 - result } else { result - XM_PIDIV2 });
2907}
2908
2909
2910/// Computes the arccosine of a floating-point number.
2911///
2912/// ## Parameters
2913///
2914/// `Value` float value between `-1.0` and `1.0`.
2915///
2916/// ## Return value
2917///
2918/// Returns the inverse cosine of Value.
2919///
2920/// ## Remarks
2921///
2922/// This function uses a 7-degree minimax approximation.
2923///
2924/// ## Reference
2925///
2926/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMScalarACos>
2927#[inline]
2928pub fn XMScalarACos(
2929 Value: f32,
2930) -> f32
2931{
2932 // Clamp input to [-1,1].
2933 let nonnegative: bool = (Value >= 0.0);
2934 let x: f32 = fabsf(Value);
2935 let mut omx: f32 = 1.0 - x;
2936 if (omx < 0.0)
2937 {
2938 omx = 0.0;
2939 }
2940 let root: f32 = sqrtf(omx);
2941
2942 // 7-degree minimax approximation
2943 let mut result: f32 = ((((((-0.0012624911 * x + 0.0066700901) * x - 0.0170881256) * x + 0.0308918810) * x - 0.0501743046) * x + 0.0889789874) * x - 0.2145988016) * x + 1.5707963050;
2944 result *= root;
2945
2946 // acos(x) = pi - acos(-x) when x < 0
2947 return (if nonnegative { result } else { XM_PI - result });
2948}
2949
2950/// Estimates the arccosine of a floating-point number.
2951///
2952/// ## Parameters
2953///
2954/// `Value` float value between `-1.0` and `1.0`.
2955///
2956/// ## Return value
2957///
2958/// Returns the inverse cosine of Value.
2959///
2960/// ## Remarks
2961///
2962/// `Est` functions offer increased performance at the expense of reduced accuracy. `Est` functions are appropriate
2963/// for non-critical calculations where accuracy can be sacrificed for speed. The exact amount of lost accuracy
2964/// and speed increase are platform dependent.
2965///
2966/// This function uses a 3-degree minimax approximation.
2967///
2968/// ## Reference
2969///
2970/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMScalarACosEst>
2971#[inline]
2972pub fn XMScalarACosEst(
2973 Value: f32,
2974) -> f32
2975{
2976 // Clamp input to [-1,1].
2977 let nonnegative: bool = (Value >= 0.0);
2978 let x: f32 = fabsf(Value);
2979 let mut omx: f32 = 1.0 - x;
2980 if (omx < 0.0)
2981 {
2982 omx = 0.0;
2983 }
2984 let root: f32 = sqrtf(omx);
2985
2986 // 3-degree minimax approximation
2987 let mut result: f32 = ((-0.0187293 * x + 0.0742610) * x - 0.2121144) * x + 1.5707288;
2988 result *= root;
2989
2990 // acos(x) = pi - acos(-x) when x < 0
2991 return (if nonnegative { result } else { XM_PI - result });
2992}