directx_math/
vector.rs

1#[allow(unused)] // TODO: cargo +nightly build --target aarch64-pc-windows-msvc -Zbuild-std --no-default-features
2use std::mem;
3
4use crate::*;
5
6#[cfg(_XM_NO_INTRINSICS_)]
7macro_rules! XMISNAN {
8    ($x:expr) => {
9       $x.is_nan()
10    }
11}
12
13#[cfg(_XM_NO_INTRINSICS_)]
14macro_rules! XMISINF {
15    ($x:expr) => {
16       $x.is_infinite()
17    }
18}
19
20// --
21
22#[cfg(_XM_SSE_INTRINSICS_)]
23macro_rules! XM3UNPACK3INTO4 {
24    ($l1:expr, $l2:expr, $l3:expr) => {
25       let V3: XMVECTOR = _mm_shuffle_ps($l2, $l3, _MM_SHUFFLE(0, 0, 3, 2));
26       let mut V2: XMVECTOR = _mm_shuffle_ps($l2, $l1, _MM_SHUFFLE(3, 3, 1, 0));
27       V2 = XM_PERMUTE_PS!(V2, _MM_SHUFFLE!(1, 1, 0, 2));
28       // NOTE: 'l3' here is 'L3' in the C macro. It seems to work by convention and the
29       //        fact that C macros don't have scope.
30       let V4: XMVECTOR = _mm_castsi128_ps(_mm_srli_si128(_mm_castps_si128($l3), 32 / 8));
31       // NOTE: The C macro defines these in scope, but we need to return in
32       //       the rust version due to scope
33       (V2, V3, V4)
34    }
35}
36
37#[cfg(_XM_SSE_INTRINSICS_)]
38macro_rules! XM3PACK4INTO3 {
39    ($V1:expr, $V2:expr, $V3:expr, $V4:expr) => {
40        let v2x: let = _mm_shuffle_ps(V2, V3, _MM_SHUFFLE(1, 0, 2, 1));
41        V2 = _mm_shuffle_ps(V2, V1, _MM_SHUFFLE(2, 2, 0, 0));
42        V1 = _mm_shuffle_ps(V1, V2, _MM_SHUFFLE(0, 2, 1, 0));
43        V3 = _mm_shuffle_ps(V3, V4, _MM_SHUFFLE(0, 0, 2, 2));
44        V3 = _mm_shuffle_ps(V3, V4, _MM_SHUFFLE(2, 1, 2, 0));
45        // NOTE: The C macro takes 'v2x' as input, but we need to return in
46        //       the rust version due to scope. 'V2' is never used after the
47        //       macro, so we omit returning it.
48        (v2x, V1, V3)
49    }
50}
51
52// --
53
54/// Creates the zero vector.
55///
56/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVectorZero>
57#[inline]
58pub fn XMVectorZero() -> XMVECTOR {
59    #[cfg(_XM_NO_INTRINSICS_)]
60    unsafe {
61        let vResult = XMVECTORF32 { f: [0.0, 0.0, 0.0, 0.0] };
62        return vResult.v;
63    }
64
65    #[cfg(_XM_ARM_NEON_INTRINSICS_)]
66    {
67        unimplemented!()
68    }
69
70    #[cfg(_XM_SSE_INTRINSICS_)]
71    unsafe {
72        return _mm_setzero_ps();
73    }
74}
75
76/// Creates a vector using four floating-point values.
77///
78/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVectorSet>
79#[inline]
80pub fn XMVectorSet(
81    x: f32,
82    y: f32,
83    z: f32,
84    w: f32,
85) -> XMVECTOR {
86    #[cfg(_XM_NO_INTRINSICS_)]
87    unsafe {
88        let vResult = XMVECTORF32 { f: [x, y, z, w] };
89        return vResult.v;
90    }
91
92    #[cfg(_XM_ARM_NEON_INTRINSICS_)]
93    {
94        unimplemented!()
95    }
96
97    #[cfg(_XM_SSE_INTRINSICS_)]
98    unsafe {
99        return _mm_set_ps(w, z, y, x);
100    }
101}
102
103/// Creates a vector with unsigned integer components.
104///
105/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVectorSetInt>
106#[inline]
107pub fn XMVectorSetInt(
108    x: u32,
109    y: u32,
110    z: u32,
111    w: u32,
112) -> XMVECTOR {
113    #[cfg(_XM_NO_INTRINSICS_)]
114    unsafe {
115        let vResult = XMVECTORU32 { u: [x, y, z, w] };
116        return vResult.v;
117    }
118
119    #[cfg(_XM_ARM_NEON_INTRINSICS_)]
120    {
121        unimplemented!()
122    }
123
124    #[cfg(_XM_SSE_INTRINSICS_)]
125    unsafe {
126        let V: __m128i = _mm_set_epi32(w as i32, z as i32, y as i32, x as i32);
127        return _mm_castsi128_ps(V);
128    }
129}
130
131/// Replicates a floating-point value into all four components of a vector.
132///
133/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVectorReplicate>
134#[inline]
135pub fn XMVectorReplicate(Value: f32) -> XMVECTOR {
136    #[cfg(_XM_NO_INTRINSICS_)]
137    unsafe {
138        let mut vResult: XMVECTORF32 = crate::undefined();
139        vResult.f[0] = Value;
140        vResult.f[1] = Value;
141        vResult.f[2] = Value;
142        vResult.f[3] = Value;
143        return vResult.v;
144    }
145
146    #[cfg(_XM_ARM_NEON_INTRINSICS_)]
147    {
148        unimplemented!()
149    }
150
151    #[cfg(_XM_SSE_INTRINSICS_)]
152    unsafe {
153        return _mm_set_ps1(Value);
154    }
155}
156
157/// Replicates a floating-point value referenced by pointer into all four components of a vector.
158///
159/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVectorReplicatePtr>
160#[inline]
161pub fn XMVectorReplicatePtr(pValue: &f32) -> XMVECTOR {
162    #[cfg(_XM_NO_INTRINSICS_)]
163    unsafe {
164        let mut vResult: XMVECTORF32 = crate::undefined();
165        let Value = *pValue;
166        vResult.f[0] = Value;
167        vResult.f[1] = Value;
168        vResult.f[2] = Value;
169        vResult.f[3] = Value;
170        return vResult.v;
171    }
172
173    #[cfg(_XM_ARM_NEON_INTRINSICS_)]
174    {
175        unimplemented!()
176    }
177
178    #[cfg(_XM_AVX_INTRINSICS_)]
179    unsafe {
180        return _mm_broadcast_ss(pValue);
181    }
182
183    #[cfg(all(_XM_SSE_INTRINSICS_, not(_XM_AVX_INTRINSICS_)))]
184    unsafe {
185        return _mm_load_ps1(pValue);
186    }
187}
188
189/// Replicates an integer value into all four components of a vector.
190///
191/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVectorReplicateInt>
192#[inline]
193pub fn XMVectorReplicateInt(Value: u32) -> XMVECTOR {
194    #[cfg(_XM_NO_INTRINSICS_)]
195    unsafe {
196        let mut vResult: XMVECTORU32 = crate::undefined();
197        vResult.u[0] = Value;
198        vResult.u[1] = Value;
199        vResult.u[2] = Value;
200        vResult.u[3] = Value;
201        return vResult.v;
202    }
203
204    #[cfg(_XM_ARM_NEON_INTRINSICS_)]
205    {
206        unimplemented!()
207    }
208
209    #[cfg(_XM_SSE_INTRINSICS_)]
210    unsafe {
211        let vTemp: __m128i = _mm_set1_epi32(Value as i32);
212        return _mm_castsi128_ps(vTemp);
213    }
214}
215
216// TODO: XMVectorReplicateIntPtr
217
218/// Returns a vector, each of whose components represents true (`0xFFFFFFFF`).
219///
220/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVectorTrueInt>
221#[inline]
222pub fn XMVectorTrueInt() -> XMVECTOR {
223    #[cfg(_XM_NO_INTRINSICS_)]
224    unsafe {
225        let vResult = XMVECTORU32 { u: [0xFFFFFFFFu32, 0xFFFFFFFFu32, 0xFFFFFFFFu32, 0xFFFFFFFFu32] };
226        return vResult.v;
227    }
228
229    #[cfg(_XM_ARM_NEON_INTRINSICS_)]
230    {
231        unimplemented!()
232    }
233
234    #[cfg(_XM_SSE_INTRINSICS_)]
235    unsafe {
236        let V: __m128i = _mm_set1_epi32(-1);
237        return _mm_castsi128_ps(V);
238    }
239}
240
241/// Returns the zero (false) vector.
242///
243/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVectorFalseInt>
244#[inline]
245pub fn XMVectorFalseInt() -> XMVECTOR {
246    #[cfg(_XM_NO_INTRINSICS_)]
247    unsafe {
248        let vResult = XMVECTORF32 { f: [0.0, 0.0, 0.0, 0.0] };
249        return vResult.v;
250    }
251
252    #[cfg(_XM_ARM_NEON_INTRINSICS_)]
253    {
254        unimplemented!()
255    }
256
257    #[cfg(_XM_SSE_INTRINSICS_)]
258    unsafe {
259        return _mm_setzero_ps();
260    }
261}
262
263/// Replicates the `x` component of a vector to all of the components.
264///
265/// ## Parameters
266///
267/// `V` Vector from which to select the `x` component.
268///
269/// ## Return value
270///
271/// Returns a vector, all of whose components are equal to the `x` component of `V`.
272///
273/// ## Reference
274///
275/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVectorSplatX>
276#[inline]
277pub fn XMVectorSplatX(V: FXMVECTOR) -> XMVECTOR {
278    #[cfg(_XM_NO_INTRINSICS_)]
279    unsafe {
280        let mut vResult: XMVECTORF32 = crate::undefined();
281        vResult.f[0] = V.vector4_f32[0];
282        vResult.f[1] = V.vector4_f32[0];
283        vResult.f[2] = V.vector4_f32[0];
284        vResult.f[3] = V.vector4_f32[0];
285        return vResult.v;
286    }
287
288    #[cfg(_XM_ARM_NEON_INTRINSICS_)]
289    {
290        unimplemented!()
291    }
292
293    #[cfg(all(_XM_AVX2_INTRINSICS_, _XM_FAVOR_INTEL_))]
294    unsafe {
295        return _mm_broadcastss_ps(V);
296    }
297
298    #[cfg(all(_XM_SSE_INTRINSICS_, not(all(_XM_AVX2_INTRINSICS_, _XM_FAVOR_INTEL_))))]
299    unsafe {
300        return XM_PERMUTE_PS!(V, _MM_SHUFFLE(0, 0, 0, 0));
301    }
302}
303
304/// Replicates the `y` component of a vector to all of the components.
305///
306/// ## Parameters
307///
308/// `V` Vector from which to select the `y` component.
309///
310/// ## Return value
311///
312/// Returns a vector, all of whose components are equal to the `y` component of `V`.
313///
314/// ## Reference
315///
316/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVectorSplatY>
317#[inline]
318pub fn XMVectorSplatY(V: FXMVECTOR) -> XMVECTOR {
319    #[cfg(_XM_NO_INTRINSICS_)]
320    unsafe {
321        let mut vResult: XMVECTORF32 = crate::undefined();
322        vResult.f[0] = V.vector4_f32[1];
323        vResult.f[1] = V.vector4_f32[1];
324        vResult.f[2] = V.vector4_f32[1];
325        vResult.f[3] = V.vector4_f32[1];
326        return vResult.v;
327    }
328
329    #[cfg(_XM_ARM_NEON_INTRINSICS_)]
330    {
331        unimplemented!()
332    }
333
334    #[cfg(_XM_SSE_INTRINSICS_)]
335    unsafe {
336        return XM_PERMUTE_PS!(V, _MM_SHUFFLE(1, 1, 1, 1));
337    }
338}
339
340/// Replicates the `z` component of a vector to all of the components.
341///
342/// ## Parameters
343///
344/// `V` Vector from which to select the `z` component.
345///
346/// ## Return value
347///
348/// Returns a vector, all of whose components are equal to the `z` component of `V`.
349///
350/// ## Reference
351///
352/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVectorSplatZ>
353#[inline]
354pub fn XMVectorSplatZ(V: FXMVECTOR) -> XMVECTOR {
355    #[cfg(_XM_NO_INTRINSICS_)]
356    unsafe {
357        let mut vResult: XMVECTORF32 = crate::undefined();
358        vResult.f[0] = V.vector4_f32[2];
359        vResult.f[1] = V.vector4_f32[2];
360        vResult.f[2] = V.vector4_f32[2];
361        vResult.f[3] = V.vector4_f32[2];
362        return vResult.v;
363    }
364
365    #[cfg(_XM_ARM_NEON_INTRINSICS_)]
366    {
367        unimplemented!()
368    }
369
370    #[cfg(_XM_SSE_INTRINSICS_)]
371    unsafe {
372        return XM_PERMUTE_PS!(V, _MM_SHUFFLE(2, 2, 2, 2));
373    }
374}
375
376/// Replicates the `w` component of a vector to all of the components.
377///
378/// ## Parameters
379///
380/// `V` Vector from which to select the `w` component.
381///
382/// ## Return value
383///
384/// Returns a vector, all of whose components are equal to the `w` component of `V`.
385///
386/// ## Reference
387///
388/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVectorSplatW>
389#[inline]
390pub fn XMVectorSplatW(V: FXMVECTOR) -> XMVECTOR {
391    #[cfg(_XM_NO_INTRINSICS_)]
392    unsafe {
393        let mut vResult: XMVECTORF32 = crate::undefined();
394        vResult.f[0] = V.vector4_f32[3];
395        vResult.f[1] = V.vector4_f32[3];
396        vResult.f[2] = V.vector4_f32[3];
397        vResult.f[3] = V.vector4_f32[3];
398        return vResult.v;
399    }
400
401    #[cfg(_XM_ARM_NEON_INTRINSICS_)]
402    {
403        unimplemented!()
404    }
405
406    #[cfg(_XM_SSE_INTRINSICS_)]
407    unsafe {
408        return XM_PERMUTE_PS!(V, _MM_SHUFFLE(3, 3, 3, 3));
409    }
410}
411
412/// Returns a vector, each of whose components are one.
413///
414/// ## Return value
415///
416/// Returns a vector, each of whose components is `1.0`.
417///
418/// ## Reference
419///
420/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVectorSplatOne>
421#[inline]
422pub fn XMVectorSplatOne() -> XMVECTOR {
423    #[cfg(_XM_NO_INTRINSICS_)]
424    unsafe {
425        let mut vResult: XMVECTORF32 = crate::undefined();
426        vResult.f[0] = 1.0;
427        vResult.f[1] = 1.0;
428        vResult.f[2] = 1.0;
429        vResult.f[3] = 1.0;
430        return vResult.v;
431    }
432
433    #[cfg(_XM_ARM_NEON_INTRINSICS_)]
434    {
435        unimplemented!()
436    }
437
438    #[cfg(_XM_SSE_INTRINSICS_)]
439    unsafe {
440        return g_XMOne.v;
441    }
442}
443
444/// Returns a vector, each of whose components are infinity (`0x7F800000`).
445///
446/// ## Return value
447///
448/// Returns a vector, each of whose components are infinity (`0x7F800000`).
449///
450/// ## Reference
451///
452/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVectorSplatInfinity>
453#[inline]
454pub fn XMVectorSplatInfinity() -> XMVECTOR {
455    #[cfg(_XM_NO_INTRINSICS_)]
456    unsafe {
457        let mut vResult: XMVECTORU32 = crate::undefined();
458        vResult.u[0] = 0x7F800000;
459        vResult.u[1] = 0x7F800000;
460        vResult.u[2] = 0x7F800000;
461        vResult.u[3] = 0x7F800000;
462        return vResult.v;
463    }
464
465    #[cfg(_XM_ARM_NEON_INTRINSICS_)]
466    {
467        unimplemented!()
468    }
469
470    #[cfg(_XM_SSE_INTRINSICS_)]
471    unsafe {
472        return g_XMInfinity.v;
473    }
474}
475
476/// Returns a vector, each of whose components are QNaN (`0x7CF00000`).
477///
478/// ## Return value
479///
480/// Returns a vector, each of whose components are `QNaN` (`0x7CF00000`)
481///
482/// ## Reference
483///
484/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVectorSplatQNaN>
485#[inline]
486pub fn XMVectorSplatQNaN() -> XMVECTOR {
487    #[cfg(_XM_NO_INTRINSICS_)]
488    unsafe {
489        let mut vResult: XMVECTORU32 = crate::undefined();
490        vResult.u[0] = 0x7FC00000;
491        vResult.u[1] = 0x7FC00000;
492        vResult.u[2] = 0x7FC00000;
493        vResult.u[3] = 0x7FC00000;
494        return vResult.v;
495    }
496
497    #[cfg(_XM_ARM_NEON_INTRINSICS_)]
498    {
499        unimplemented!()
500    }
501
502    #[cfg(_XM_SSE_INTRINSICS_)]
503    unsafe {
504        return g_XMQNaN.v;
505    }
506}
507
508/// Returns a vector, each of whose components are epsilon (`1.192092896e-7`).
509///
510/// ## Return value
511///
512/// Returns a vector, each of whose components is (`1.192092896e-7`).
513///
514/// ## Reference
515///
516/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVectorSplatEpsilon>
517#[inline]
518pub fn XMVectorSplatEpsilon() -> XMVECTOR {
519    #[cfg(_XM_NO_INTRINSICS_)]
520    unsafe {
521        let mut vResult: XMVECTORU32 = crate::undefined();
522        vResult.u[0] = 0x34000000;
523        vResult.u[1] = 0x34000000;
524        vResult.u[2] = 0x34000000;
525        vResult.u[3] = 0x34000000;
526        return vResult.v;
527    }
528
529    #[cfg(_XM_ARM_NEON_INTRINSICS_)]
530    {
531        unimplemented!()
532    }
533
534    #[cfg(_XM_SSE_INTRINSICS_)]
535    unsafe {
536        return g_XMEpsilon.v;
537    }
538}
539
540/// Returns a vector, each of whose components are the sign mask (`0x80000000`).
541///
542/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVectorSplatSignMask>
543#[inline]
544pub fn XMVectorSplatSignMask() -> XMVECTOR {
545    #[cfg(_XM_NO_INTRINSICS_)]
546    unsafe {
547        let mut vResult: XMVECTORU32 = crate::undefined();
548        vResult.u[0] = 0x80000000u32;
549        vResult.u[1] = 0x80000000u32;
550        vResult.u[2] = 0x80000000u32;
551        vResult.u[3] = 0x80000000u32;
552        return vResult.v;
553    }
554
555    #[cfg(_XM_ARM_NEON_INTRINSICS_)]
556    {
557        unimplemented!()
558    }
559
560    #[cfg(_XM_SSE_INTRINSICS_)]
561    unsafe {
562        let V: __m128i  = _mm_set1_epi32(0x80000000u32 as i32);
563        return _mm_castsi128_ps(V);
564    }
565}
566
567/// Retrieve the value of one of the four components of an XMVECTOR Data Type containing floating-point data by index.
568///
569/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVectorGetByIndex>
570#[inline]
571pub fn XMVectorGetByIndex(V: XMVECTOR, i: usize) -> f32 {
572    debug_assert!(i < 4);
573
574    #[cfg(_XM_NO_INTRINSICS_)]
575    unsafe {
576        return V.vector4_f32[i];
577    }
578
579    #[cfg(_XM_ARM_NEON_INTRINSICS_)]
580    {
581        unimplemented!()
582    }
583
584    #[cfg(_XM_SSE_INTRINSICS_)]
585    unsafe {
586        let mut U: XMVECTORF32 = crate::undefined();
587        U.v = V;
588        return U.f[i];
589    }
590}
591
592/// Retrieve the `x` component of an XMVECTOR Data Type.
593///
594/// ## Parameters
595///
596/// `V` A valid 4D vector storing floating-point data
597///
598/// ## Return value
599///
600/// The value in the `x` component of the 4D vector storing floating-point data `V`
601///
602/// ## Reference
603///
604/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVectorGetX>
605#[inline]
606pub fn XMVectorGetX(V: XMVECTOR) -> f32 {
607    #[cfg(_XM_NO_INTRINSICS_)]
608    unsafe {
609        return V.vector4_f32[0];
610    }
611
612    #[cfg(_XM_ARM_NEON_INTRINSICS_)]
613    {
614        unimplemented!()
615    }
616
617    #[cfg(_XM_SSE_INTRINSICS_)]
618    unsafe {
619        return _mm_cvtss_f32(V);
620    }
621}
622
623/// Retrieve the `y` component of an XMVECTOR Data Type.
624///
625/// ## Parameters
626///
627/// `V` A valid 4D vector storing floating-point data
628///
629/// ## Return value
630///
631/// The value in the `y` component of the 4D vector storing floating-point data `V`
632///
633/// ## Reference
634///
635/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVectorGetY>
636#[inline]
637pub fn XMVectorGetY(V: XMVECTOR) -> f32 {
638    #[cfg(_XM_NO_INTRINSICS_)]
639    unsafe {
640        return V.vector4_f32[1];
641    }
642
643    #[cfg(_XM_ARM_NEON_INTRINSICS_)]
644    {
645        unimplemented!()
646    }
647
648    #[cfg(_XM_SSE_INTRINSICS_)]
649    unsafe {
650        let vTemp: XMVECTOR = XM_PERMUTE_PS!(V, _MM_SHUFFLE(1, 1, 1, 1));
651        return _mm_cvtss_f32(vTemp);
652    }
653}
654
655/// Retrieve the `z` component of an XMVECTOR Data Type.
656///
657/// ## Parameters
658///
659/// `V` A valid 4D vector storing floating-point data
660///
661/// ## Return value
662///
663/// The value in the `z` component of the 4D vector storing floating-point data `V`
664///
665/// ## Reference
666///
667/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVectorGetZ>
668#[inline]
669pub fn XMVectorGetZ(V: XMVECTOR) -> f32 {
670    #[cfg(_XM_NO_INTRINSICS_)]
671    unsafe {
672        return V.vector4_f32[2];
673    }
674
675    #[cfg(_XM_ARM_NEON_INTRINSICS_)]
676    {
677        unimplemented!()
678    }
679
680    #[cfg(_XM_SSE_INTRINSICS_)]
681    unsafe {
682        let vTemp: XMVECTOR = XM_PERMUTE_PS!(V, _MM_SHUFFLE(2, 2, 2, 2));
683        return _mm_cvtss_f32(vTemp);
684    }
685}
686
687/// Retrieve the `w` component of an XMVECTOR Data Type.
688///
689/// ## Parameters
690///
691/// `V` A valid 4D vector storing floating-point data
692///
693/// ## Return value
694///
695/// The value in the `w` component of the 4D vector storing floating-point data `V`
696///
697/// ## Reference
698///
699/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVectorGetW>
700#[inline]
701pub fn XMVectorGetW(V: XMVECTOR) -> f32 {
702    #[cfg(_XM_NO_INTRINSICS_)]
703    unsafe {
704        return V.vector4_f32[3];
705    }
706
707    #[cfg(_XM_ARM_NEON_INTRINSICS_)]
708    {
709        unimplemented!()
710    }
711
712    #[cfg(_XM_SSE_INTRINSICS_)]
713    unsafe {
714        let vTemp: XMVECTOR = XM_PERMUTE_PS!(V, _MM_SHUFFLE(3, 3, 3, 3));
715        return _mm_cvtss_f32(vTemp);
716    }
717}
718
719// TODO: XMVectorGetByIndexPtr
720
721/// Retrieve the `x` component of an XMVECTOR Data Type containing floating-point data, and storing that
722/// component's value in an instance of float referred to by a pointer.
723///
724/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVectorGetXPtr>
725#[inline]
726pub fn XMVectorGetXPtr(
727    x: &mut f32,
728    V: FXMVECTOR,
729)
730{
731    #[cfg(_XM_NO_INTRINSICS_)]
732    unsafe {
733        *x = V.vector4_f32[0];
734    }
735
736    #[cfg(_XM_ARM_NEON_INTRINSICS_)]
737    {
738        unimplemented!()
739    }
740
741    #[cfg(_XM_SSE_INTRINSICS_)]
742    unsafe {
743        _mm_store_ss(x, V);
744    }
745}
746
747/// Retrieve the `y` component of an XMVECTOR Data Type containing floating-point data, and storing that
748/// component's value in an instance of float referred to by a pointer.
749///
750/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVectorGetYPtr>
751#[inline]
752pub fn XMVectorGetYPtr(
753    y: &mut f32,
754    V: FXMVECTOR,
755)
756{
757    #[cfg(_XM_NO_INTRINSICS_)]
758    unsafe {
759        *y = V.vector4_f32[1];
760    }
761
762    #[cfg(_XM_ARM_NEON_INTRINSICS_)]
763    {
764        unimplemented!()
765    }
766
767    #[cfg(_XM_SSE4_INTRINSICS_)]
768    unsafe {
769        *mem::transmute::<_, *mut i32>(y) = _mm_extract_ps(V, 1);
770    }
771
772    #[cfg(all(_XM_SSE_INTRINSICS_, not(_XM_SSE4_INTRINSICS_)))]
773    unsafe {
774        let vResult: XMVECTOR = XM_PERMUTE_PS!(V, _MM_SHUFFLE(1, 1, 1, 1));
775        _mm_store_ss(y, vResult);
776    }
777}
778
779/// Retrieve the `z` component of an XMVECTOR Data Type containing floating-point data, and storing that
780/// component's value in an instance of float referred to by a pointer.
781///
782/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVectorGetZPtr>
783#[inline]
784pub fn XMVectorGetZPtr(
785    z: &mut f32,
786    V: FXMVECTOR,
787)
788{
789    #[cfg(_XM_NO_INTRINSICS_)]
790    unsafe {
791        *z = V.vector4_f32[2];
792    }
793
794    #[cfg(_XM_ARM_NEON_INTRINSICS_)]
795    {
796        unimplemented!()
797    }
798
799    #[cfg(_XM_SSE4_INTRINSICS_)]
800    unsafe {
801        *mem::transmute::<_, *mut i32>(z) = _mm_extract_ps(V, 2);
802    }
803
804    #[cfg(all(_XM_SSE_INTRINSICS_, not(_XM_SSE4_INTRINSICS_)))]
805    unsafe {
806        let vResult: XMVECTOR = XM_PERMUTE_PS!(V, _MM_SHUFFLE(2, 2, 2, 2));
807        _mm_store_ss(z, vResult);
808    }
809}
810
811/// Retrieve the `w` component of an XMVECTOR Data Type containing floating-point data, and storing that
812/// component's value in an instance of float referred to by a pointer.
813///
814/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVectorGetWPtr>
815#[inline]
816pub fn XMVectorGetWPtr(
817    w: &mut f32,
818    V: FXMVECTOR,
819)
820{
821    #[cfg(_XM_NO_INTRINSICS_)]
822    unsafe {
823        *w = V.vector4_f32[3];
824    }
825
826    #[cfg(_XM_ARM_NEON_INTRINSICS_)]
827    {
828        unimplemented!()
829    }
830
831    #[cfg(_XM_SSE4_INTRINSICS_)]
832    unsafe {
833        *mem::transmute::<_, *mut i32>(w) = _mm_extract_ps(V, 3);
834    }
835
836    #[cfg(all(_XM_SSE_INTRINSICS_, not(_XM_SSE4_INTRINSICS_)))]
837    unsafe {
838        let vResult: XMVECTOR = XM_PERMUTE_PS!(V, _MM_SHUFFLE(3, 3, 3, 3));
839        _mm_store_ss(w, vResult);
840    }
841}
842
843/// Retrieve the value of one of the four components of an XMVECTOR Data Type containing integer data by index.
844///
845/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVectorGetIntByIndex>
846#[inline]
847pub fn XMVectorGetIntByIndex(V: XMVECTOR, i: usize) -> u32 {
848    debug_assert!(i < 4);
849
850    #[cfg(_XM_NO_INTRINSICS_)]
851    unsafe {
852        return V.vector4_u32[i];
853    }
854
855    #[cfg(_XM_ARM_NEON_INTRINSICS_)]
856    {
857        unimplemented!()
858    }
859
860    #[cfg(_XM_SSE_INTRINSICS_)]
861    unsafe {
862        let mut U: XMVECTORU32 = crate::undefined();
863        U.v = V;
864        return U.u[i];
865    }
866}
867
868/// Retrieve the `x` component of an XMVECTOR Data Type.
869///
870/// ## Parameters
871///
872/// `V` A valid 4D vector storing integer data.
873///
874/// ## Return value
875///
876/// The value in the `x` component of the 4D vector storing integer data `V`.
877///
878/// ## Reference
879///
880/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVectorGetIntX>
881#[inline]
882pub fn XMVectorGetIntX(V: XMVECTOR) -> u32 {
883    #[cfg(_XM_NO_INTRINSICS_)]
884    unsafe {
885        return V.vector4_u32[0];
886    }
887
888    #[cfg(_XM_ARM_NEON_INTRINSICS_)]
889    {
890        unimplemented!()
891    }
892
893    #[cfg(_XM_SSE_INTRINSICS_)]
894    unsafe {
895        return (_mm_cvtsi128_si32(_mm_castps_si128(V))) as u32;
896    }
897}
898
899/// Retrieve the `y` component of an XMVECTOR Data Type.
900///
901/// ## Parameters
902///
903/// `V` A valid 4D vector storing integer data.
904///
905/// ## Return value
906///
907/// The value in the `y` component of the 4D vector storing integer data `V`.
908///
909/// ## Reference
910///
911/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVectorGetIntY>
912#[inline]
913pub fn XMVectorGetIntY(V: XMVECTOR) -> u32 {
914    #[cfg(_XM_NO_INTRINSICS_)]
915    unsafe {
916        return V.vector4_u32[1];
917    }
918
919    #[cfg(_XM_ARM_NEON_INTRINSICS_)]
920    {
921        unimplemented!()
922    }
923
924    #[cfg(_XM_SSE4_INTRINSICS_)]
925    unsafe {
926        let V1: __m128i = _mm_castps_si128(V);
927        return (_mm_extract_epi32(V1, 1)) as u32;
928    }
929
930    #[cfg(all(not(_XM_SSE4_INTRINSICS_), _XM_SSE_INTRINSICS_))]
931    unsafe {
932        let vResulti: __m128i = _mm_shuffle_epi32(_mm_castps_si128(V), _MM_SHUFFLE(1, 1, 1, 1));
933        return (_mm_cvtsi128_si32(vResulti)) as u32;
934    }
935}
936
937/// Retrieve the `z` component of an XMVECTOR Data Type.
938///
939/// ## Parameters
940///
941/// `V` A valid 4D vector storing integer data.
942///
943/// ## Return value
944///
945/// The value in the `z` component of the 4D vector storing integer data `V`.
946///
947/// ## Reference
948///
949/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVectorGetIntZ>
950#[inline]
951pub fn XMVectorGetIntZ(V: XMVECTOR) -> u32 {
952    #[cfg(_XM_NO_INTRINSICS_)]
953    unsafe {
954        return V.vector4_u32[2];
955    }
956
957    #[cfg(_XM_ARM_NEON_INTRINSICS_)]
958    {
959        unimplemented!()
960    }
961
962    #[cfg(_XM_SSE4_INTRINSICS_)]
963    unsafe {
964        let V1: __m128i = _mm_castps_si128(V);
965        return (_mm_extract_epi32(V1, 2)) as u32;
966    }
967
968    #[cfg(all(not(_XM_SSE4_INTRINSICS_), _XM_SSE_INTRINSICS_))]
969    unsafe {
970        let vResulti: __m128i = _mm_shuffle_epi32(_mm_castps_si128(V), _MM_SHUFFLE(2, 2, 2, 2));
971        return (_mm_cvtsi128_si32(vResulti)) as u32;
972    }
973}
974
975/// Retrieve the `w` component of an XMVECTOR Data Type.
976///
977/// ## Parameters
978///
979/// `V` A valid 4D vector storing integer data.
980///
981/// ## Return value
982///
983/// The value in the `w` component of the 4D vector storing integer data `V`.
984///
985/// ## Reference
986///
987/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVectorGetIntW>
988#[inline]
989pub fn XMVectorGetIntW(V: XMVECTOR) -> u32 {
990    #[cfg(_XM_NO_INTRINSICS_)]
991    unsafe {
992        return V.vector4_u32[3];
993    }
994
995    #[cfg(_XM_ARM_NEON_INTRINSICS_)]
996    {
997        unimplemented!()
998    }
999
1000    #[cfg(_XM_SSE4_INTRINSICS_)]
1001    unsafe {
1002        let V1: __m128i = _mm_castps_si128(V);
1003        return (_mm_extract_epi32(V1, 3)) as u32;
1004    }
1005
1006    #[cfg(all(not(_XM_SSE4_INTRINSICS_), _XM_SSE_INTRINSICS_))]
1007    unsafe {
1008        let vResulti: __m128i = _mm_shuffle_epi32(_mm_castps_si128(V), _MM_SHUFFLE(3, 3, 3, 3));
1009        return (_mm_cvtsi128_si32(vResulti)) as u32;
1010    }
1011}
1012
1013// TODO: XMVectorGetIntByIndexPtr
1014// TODO: XMVectorGetIntXPtr
1015// TODO: XMVectorGetIntYPtr
1016// TODO: XMVectorGetIntZPtr
1017// TODO: XMVectorGetIntWPtr
1018
1019/// Use a floating-point object to set the value of one of the four components of an XMVECTOR Data Type containing integer data referenced by an index.
1020///
1021/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVectorSetByIndex>
1022#[inline]
1023pub fn XMVectorSetByIndex(V: XMVECTOR, f: f32, i: usize) -> XMVECTOR {
1024    debug_assert!(i < 4);
1025
1026    unsafe {
1027        let mut U: XMVECTORF32 = crate::undefined();
1028        U.v = V;
1029        U.f[i] = f;
1030        return U.v;
1031    }
1032}
1033
1034/// Set the value of the `x` component of an XMVECTOR Data Type.
1035///
1036/// ## Parameters
1037///
1038/// `V` A valid 4D vector storing floating-point data.
1039///
1040/// `x` A floating-point value to be assigned to `x` of `V`.
1041///
1042/// ## Return value
1043///
1044/// An instance of XMVECTOR Data Type whose `x` component has been set to the floating-point value provided
1045/// by the argument `x` to XMVectorSetX. All other components of the returned XMVECTOR Data Type instance
1046/// have the same value as those of the input vector `V`.
1047///
1048/// ## Reference
1049///
1050/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVectorSetX>
1051#[inline]
1052pub fn XMVectorSetX(V: XMVECTOR, x: f32) -> XMVECTOR {
1053    #[cfg(_XM_NO_INTRINSICS_)]
1054    unsafe {
1055        let U = XMVECTORF32 {
1056            f: [
1057                x,
1058                V.vector4_f32[1],
1059                V.vector4_f32[2],
1060                V.vector4_f32[3]
1061            ]
1062        };
1063        return U.v;
1064    }
1065
1066    #[cfg(_XM_ARM_NEON_INTRINSICS_)]
1067    {
1068        unimplemented!()
1069    }
1070
1071    #[cfg(_XM_SSE_INTRINSICS_)]
1072    unsafe {
1073        let mut vResult: XMVECTOR = _mm_set_ss(x);
1074        vResult = _mm_move_ss(V, vResult);
1075        return vResult;
1076    }
1077}
1078
1079/// Set the value of the `y` component of an XMVECTOR Data Type.
1080///
1081/// ## Parameters
1082///
1083/// `V` A valid 4D vector storing floating-point data.
1084///
1085/// `y` A floating-point value to be assigned to `y` of `V`.
1086///
1087/// ## Return value
1088///
1089/// An instance of XMVECTOR Data Type whose `y` component has been set to the floating-point value provided
1090/// by the argument `y` to XMVectorSetY. All other components of the returned XMVECTOR Data Type instance
1091/// have the same value as those of the input vector `V`.
1092///
1093/// ## Reference
1094///
1095/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVectorSetY>
1096#[inline]
1097pub fn XMVectorSetY(V: XMVECTOR, y: f32) -> XMVECTOR {
1098    #[cfg(_XM_NO_INTRINSICS_)]
1099    unsafe {
1100        let U = XMVECTORF32 {
1101            f: [
1102                V.vector4_f32[0],
1103                y,
1104                V.vector4_f32[2],
1105                V.vector4_f32[3]
1106            ]
1107        };
1108        return U.v;
1109    }
1110
1111    #[cfg(_XM_ARM_NEON_INTRINSICS_)]
1112    {
1113        unimplemented!()
1114    }
1115
1116    #[cfg(_XM_SSE4_INTRINSICS_)]
1117    unsafe {
1118        let mut vResult: XMVECTOR = _mm_set_ss(y);
1119        vResult = _mm_insert_ps(V, vResult, 0x10);
1120        return vResult;
1121    }
1122
1123    #[cfg(all(not(_XM_SSE4_INTRINSICS_), _XM_SSE_INTRINSICS_))]
1124    unsafe {
1125        // Swap y and x
1126        let mut vResult: XMVECTOR = XM_PERMUTE_PS!(V, _MM_SHUFFLE(3, 2, 0, 1));
1127        // Convert input to vector
1128        let vTemp: XMVECTOR = _mm_set_ss(y);
1129        // Replace the x component
1130        vResult = _mm_move_ss(vResult, vTemp);
1131        // Swap y and x again
1132        vResult = XM_PERMUTE_PS!(vResult, _MM_SHUFFLE(3, 2, 0, 1));
1133        return vResult;
1134    }
1135}
1136
1137/// Set the value of the `z` component of an XMVECTOR Data Type.
1138///
1139/// ## Parameters
1140///
1141/// `V` A valid 4D vector storing floating-point data.
1142///
1143/// `z` A floating-point value to be assigned to `z` of `V`.
1144///
1145/// ## Return value
1146///
1147/// An instance of XMVECTOR Data Type whose `z` component has been set to the floating-point value provided
1148/// by the argument `z` to XMVectorSetZ. All other components of the returned XMVECTOR Data Type instance
1149/// have the same value as those of the input vector `V`.
1150///
1151/// ## Reference
1152///
1153/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVectorSetZ>
1154#[inline]
1155pub fn XMVectorSetZ(V: XMVECTOR, z: f32) -> XMVECTOR {
1156    #[cfg(_XM_NO_INTRINSICS_)]
1157    unsafe {
1158        let U = XMVECTORF32 {
1159            f: [
1160                V.vector4_f32[0],
1161                V.vector4_f32[1],
1162                z,
1163                V.vector4_f32[3]
1164            ]
1165        };
1166        return U.v;
1167    }
1168
1169    #[cfg(_XM_ARM_NEON_INTRINSICS_)]
1170    {
1171        unimplemented!()
1172    }
1173
1174    #[cfg(_XM_SSE4_INTRINSICS_)]
1175    unsafe {
1176        let mut vResult: XMVECTOR = _mm_set_ss(z);
1177        vResult = _mm_insert_ps(V, vResult, 0x20);
1178        return vResult;
1179    }
1180
1181    #[cfg(all(not(_XM_SSE4_INTRINSICS_), _XM_SSE_INTRINSICS_))]
1182    unsafe {
1183        // Swap z and x
1184        let mut vResult: XMVECTOR = XM_PERMUTE_PS!(V, _MM_SHUFFLE(3, 0, 1, 2));
1185        // Convert input to vector
1186        let vTemp: XMVECTOR = _mm_set_ss(z);
1187        // Replace the x component
1188        vResult = _mm_move_ss(vResult, vTemp);
1189        // Swap z and x again
1190        vResult = XM_PERMUTE_PS!(vResult, _MM_SHUFFLE(3, 0, 1, 2));
1191        return vResult;
1192    }
1193}
1194
1195/// Set the value of the `w` component of an XMVECTOR Data Type.
1196///
1197/// ## Parameters
1198///
1199/// `V` A valid 4D vector storing floating-point data.
1200///
1201/// `w` A floating-point value to be assigned to `w` of `V`.
1202///
1203/// ## Return value
1204///
1205/// An instance of XMVECTOR Data Type whose `w` component has been set to the floating-point value provided
1206/// by the argument `w` to XMVectorSetW. All other components of the returned XMVECTOR Data Type instance
1207/// have the same value as those of the input vector `V`.
1208///
1209/// ## Reference
1210///
1211/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVectorSetW>
1212#[inline]
1213pub fn XMVectorSetW(V: XMVECTOR, w: f32) -> XMVECTOR {
1214    #[cfg(_XM_NO_INTRINSICS_)]
1215    unsafe {
1216        let U = XMVECTORF32 {
1217            f: [
1218                V.vector4_f32[0],
1219                V.vector4_f32[1],
1220                V.vector4_f32[2],
1221                w,
1222            ]
1223        };
1224        return U.v;
1225    }
1226
1227    #[cfg(_XM_ARM_NEON_INTRINSICS_)]
1228    {
1229        unimplemented!()
1230    }
1231
1232    #[cfg(_XM_SSE4_INTRINSICS_)]
1233    unsafe {
1234        let mut vResult: XMVECTOR = _mm_set_ss(w);
1235        vResult = _mm_insert_ps(V, vResult, 0x30);
1236        return vResult;
1237    }
1238
1239    #[cfg(all(not(_XM_SSE4_INTRINSICS_), _XM_SSE_INTRINSICS_))]
1240    unsafe {
1241        // Swap w and x
1242        let mut vResult: XMVECTOR = XM_PERMUTE_PS!(V, _MM_SHUFFLE(0, 2, 1, 3));
1243        // Convert input to vector
1244        let vTemp: XMVECTOR = _mm_set_ss(w);
1245        // Replace the x component
1246        vResult = _mm_move_ss(vResult, vTemp);
1247        // Swap w and x again
1248        vResult = XM_PERMUTE_PS!(vResult, _MM_SHUFFLE(0, 2, 1, 3));
1249        return vResult;
1250    }
1251}
1252
1253// TODO: XMVectorSetByIndexPtr
1254// TODO: XMVectorSetXPtr
1255// TODO: XMVectorSetYPtr
1256// TODO: XMVectorSetZPtr
1257// TODO: XMVectorSetWPtr
1258
1259/// Use an integer instance to set the value of one of the four components of an XMVECTOR Data Type containing integer data referenced by an index.
1260///
1261/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVectorSetIntByIndex>
1262#[inline]
1263pub fn XMVectorSetIntByIndex(V: XMVECTOR, x: u32, i: usize) -> XMVECTOR {
1264    // debug_assert!(i < 4);
1265
1266    unsafe {
1267        let mut U: XMVECTORU32 = crate::undefined();
1268        U.v = V;
1269        U.u[i] = x;
1270        return U.v;
1271    }
1272}
1273
1274/// Set the value of the `x` component of an XMVECTOR Data Type.
1275///
1276/// ## Parameters
1277///
1278/// `V` A valid 4D vector storing integer data.
1279///
1280/// `x` An integer value to be assigned to `x` of `V`.
1281///
1282/// ## Return value
1283///
1284/// ## Reference
1285///
1286/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVectorSetIntX>
1287#[inline]
1288pub fn XMVectorSetIntX(V: XMVECTOR, x: u32) -> XMVECTOR {
1289    #[cfg(_XM_NO_INTRINSICS_)]
1290    unsafe {
1291        let U = XMVECTORU32 {
1292            u: [
1293                x,
1294                V.vector4_u32[1],
1295                V.vector4_u32[2],
1296                V.vector4_u32[3]
1297            ]
1298        };
1299        return U.v;
1300    }
1301
1302    #[cfg(_XM_ARM_NEON_INTRINSICS_)]
1303    {
1304        unimplemented!()
1305    }
1306
1307    #[cfg(_XM_SSE_INTRINSICS_)]
1308    unsafe {
1309        let vTemp: __m128i = _mm_cvtsi32_si128(x as i32);
1310        let vResult: XMVECTOR = _mm_move_ss(V, _mm_castsi128_ps(vTemp));
1311        return vResult;
1312    }
1313}
1314
1315/// Set the value of the `y` component of an XMVECTOR Data Type.
1316///
1317/// ## Parameters
1318///
1319/// `V` A valid 4D vector storing integer data.
1320///
1321/// `y` An integer value to be assigned to `y` of `V`.
1322///
1323/// ## Return value
1324///
1325/// ## Reference
1326///
1327/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVectorSetIntY>
1328#[inline]
1329pub fn XMVectorSetIntY(V: XMVECTOR, y: u32) -> XMVECTOR {
1330    #[cfg(_XM_NO_INTRINSICS_)]
1331    unsafe {
1332        let U = XMVECTORU32 {
1333            u: [
1334                V.vector4_u32[0],
1335                y,
1336                V.vector4_u32[2],
1337                V.vector4_u32[3]
1338            ]
1339        };
1340        return U.v;
1341    }
1342
1343    #[cfg(_XM_ARM_NEON_INTRINSICS_)]
1344    {
1345        unimplemented!()
1346    }
1347
1348    #[cfg(_XM_SSE4_INTRINSICS_)]
1349    unsafe {
1350        let mut vResult: __m128i = _mm_castps_si128(V);
1351        vResult = _mm_insert_epi32(vResult, y as i32, 1);
1352        return _mm_castsi128_ps(vResult);
1353    }
1354
1355    #[cfg(all(not(_XM_SSE4_INTRINSICS_), _XM_SSE_INTRINSICS_))]
1356    unsafe {
1357        // Swap y and x
1358        let mut vResult: XMVECTOR = XM_PERMUTE_PS!(V, _MM_SHUFFLE(3, 2, 0, 1));
1359        // Convert input to vector
1360        let vTemp: __m128i = _mm_cvtsi32_si128(y as i32);
1361        // Replace the x component
1362        vResult = _mm_move_ss(vResult, _mm_castsi128_ps(vTemp));
1363        // Swap y and x again
1364        vResult = XM_PERMUTE_PS!(vResult, _MM_SHUFFLE(3, 2, 0, 1));
1365        return vResult;
1366    }
1367}
1368
1369/// Set the value of the `z` component of an XMVECTOR Data Type.
1370///
1371/// ## Parameters
1372///
1373/// `V` A valid 4D vector storing integer data.
1374///
1375/// `z` An integer value to be assigned to `z` of `V`.
1376///
1377/// ## Return value
1378///
1379/// ## Reference
1380///
1381/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVectorSetIntZ>
1382#[inline]
1383pub fn XMVectorSetIntZ(V: XMVECTOR, z: u32) -> XMVECTOR {
1384    #[cfg(_XM_NO_INTRINSICS_)]
1385    unsafe {
1386        let U = XMVECTORU32 {
1387            u: [
1388                V.vector4_u32[0],
1389                V.vector4_u32[1],
1390                z,
1391                V.vector4_u32[3]
1392            ]
1393        };
1394        return U.v;
1395    }
1396
1397    #[cfg(_XM_ARM_NEON_INTRINSICS_)]
1398    {
1399        unimplemented!()
1400    }
1401
1402    #[cfg(_XM_SSE4_INTRINSICS_)]
1403    unsafe {
1404        let mut vResult: __m128i = _mm_castps_si128(V);
1405        vResult = _mm_insert_epi32(vResult, z as i32, 2);
1406        return _mm_castsi128_ps(vResult);
1407    }
1408
1409    #[cfg(all(not(_XM_SSE4_INTRINSICS_), _XM_SSE_INTRINSICS_))]
1410    unsafe {
1411        // Swap z and x
1412        let mut vResult: XMVECTOR = XM_PERMUTE_PS!(V, _MM_SHUFFLE(3, 0, 1, 2));
1413        // Convert input to vector
1414        let vTemp: __m128i = _mm_cvtsi32_si128(z as i32);
1415        // Replace the x component
1416        vResult = _mm_move_ss(vResult, _mm_castsi128_ps(vTemp));
1417        // Swap z and x again
1418        vResult = XM_PERMUTE_PS!(vResult, _MM_SHUFFLE(3, 0, 1, 2));
1419        return vResult;
1420    }
1421}
1422
1423/// Set the value of the `w` component of an XMVECTOR Data Type.
1424///
1425/// ## Parameters
1426///
1427/// `V` A valid 4D vector storing integer data.
1428///
1429/// `w` An integer value to be assigned to `w` of `V`.
1430///
1431/// ## Return value
1432///
1433/// ## Reference
1434///
1435/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVectorSetIntW>
1436#[inline]
1437pub fn XMVectorSetIntW(V: XMVECTOR, w: u32) -> XMVECTOR {
1438    #[cfg(_XM_NO_INTRINSICS_)]
1439    unsafe {
1440        let U = XMVECTORU32 {
1441            u: [
1442                V.vector4_u32[0],
1443                V.vector4_u32[1],
1444                V.vector4_u32[2],
1445                w,
1446            ]
1447        };
1448        return U.v;
1449    }
1450
1451    #[cfg(_XM_ARM_NEON_INTRINSICS_)]
1452    {
1453        unimplemented!()
1454    }
1455
1456    #[cfg(_XM_SSE4_INTRINSICS_)]
1457    unsafe {
1458        let mut vResult: __m128i = _mm_castps_si128(V);
1459        vResult = _mm_insert_epi32(vResult, w as i32, 3);
1460        return _mm_castsi128_ps(vResult);
1461    }
1462
1463    #[cfg(all(not(_XM_SSE4_INTRINSICS_), _XM_SSE_INTRINSICS_))]
1464    unsafe {
1465        // Swap w and x
1466        let mut vResult: XMVECTOR = XM_PERMUTE_PS!(V, _MM_SHUFFLE(0, 2, 1, 3));
1467        // Convert input to vector
1468        let vTemp: __m128i = _mm_cvtsi32_si128(w as i32);
1469        // Replace the x component
1470        vResult = _mm_move_ss(vResult, _mm_castsi128_ps(vTemp));
1471        // Swap w and x again
1472        vResult = XM_PERMUTE_PS!(vResult, _MM_SHUFFLE(0, 2, 1, 3));
1473        return vResult;
1474    }
1475}
1476
1477// TODO: XMVectorSetIntByIndexPtr
1478// TODO: XMVectorSetIntXPtr
1479// TODO: XMVectorSetIntYPtr
1480// TODO: XMVectorSetIntZPtr
1481// TODO: XMVectorSetIntWPtr
1482
1483/// Swizzles a vector.
1484///
1485/// ## Parameters
1486///
1487/// `V` Vector to swizzle.
1488///
1489/// `E0` Index that describes which component of `V` to place in the `x-component` of the swizzled vector. A
1490/// value of `0` selects the `x-component`, `1` selects the `y-component`, `2` selects the `z-component`,
1491/// and `3` selects the `w-component`.
1492///
1493/// `E1` Index that describes which component of `V` to place in the `y-component` of the swizzled vector. A
1494/// value of `0` selects the `x-component`, `1` selects the `y-component`, `2` selects the `z-component`,
1495/// and `3` selects the `w-component`.
1496///
1497/// `E2` Index that describes which component of `V` to place in the `z-component` of the swizzled vector. A
1498/// value of `0` selects the `x-component`, `1` selects the `y-component`, `2` selects the `z-component`,
1499/// and `3` selects the `w-component`.
1500///
1501/// `E3` Index that describes which component of `V` to place in the `w-component` of the swizzled vector. A
1502/// value of `0` selects the `x-component`, `1` selects the `y-component`, `2` selects the `z-component`,
1503/// and `3` selects the `w-component`.
1504///
1505/// ## Return value
1506///
1507/// Returns the swizzled XMVECTOR.
1508///
1509/// ## Remarks
1510///
1511/// The following code demonstrates how this function might be used.
1512///
1513/// ```
1514/// # use directx_math::*;
1515/// let v = XMVectorSet(10.0, 20.0, 30.0, 40.0);
1516/// let result = XMVectorSwizzle(v, 3, 3, 0, 2);
1517/// ```
1518///
1519/// The swizzled vector (result) will be <`40.0`, `40.0`, `10.0`, `30.0`>.
1520///
1521/// `XM_SWIZZLE_X`, `XM_SWIZZLE_Y`, `XM_SWIZZLE_Z`, and `XM_SWIZZLE_W` are constants which evaluate to
1522/// `0`, `1`, `2`, and `3` respectively for use with XMVectorSwizzle. This is identical to `XM_PERMUTE_0X`,
1523/// `XM_PERMUTE_0Y`, `XM_PERMUTE_0Z`, and `XM_PERMUTE_0W`.
1524///
1525/// For the case of constant indices (`E0`, `E1`, `E2`, `E3`), it is much more efficent to use the template
1526/// form of [`XMVectorSwizzle`]:
1527///
1528/// ```
1529/// # use directx_math::*;
1530/// let v = XMVectorSet(10.0, 20.0, 30.0, 40.0);
1531/// let result = <(SwizzleW, SwizzleW, SwizzleX, SwizzleZ)>::XMVectorSwizzle(v);
1532/// ```
1533///
1534/// ## Reference
1535///
1536/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVectorSwizzle>
1537///
1538/// [`XMVectorSwizzle`]: trait@crate::XMVectorSwizzle
1539#[inline]
1540pub fn XMVectorSwizzle(
1541    V: FXMVECTOR,
1542    E0: u32,
1543    E1: u32,
1544    E2: u32,
1545    E3: u32
1546) -> XMVECTOR
1547{
1548    debug_assert!((E0 < 4) && (E1 < 4) && (E2 < 4) && (E3 < 4));
1549
1550    #[cfg(_XM_NO_INTRINSICS_)]
1551    unsafe {
1552        let U = XMVECTORF32 {
1553            f: [
1554                V.vector4_f32[E0 as usize],
1555                V.vector4_f32[E1 as usize],
1556                V.vector4_f32[E2 as usize],
1557                V.vector4_f32[E3 as usize],
1558            ]
1559        };
1560        return U.v;
1561    }
1562
1563    #[cfg(_XM_ARM_NEON_INTRINSICS_)]
1564    {
1565        unimplemented!()
1566    }
1567
1568    #[cfg(_XM_AVX_INTRINSICS_)]
1569    unsafe {
1570        let elem: [i32; 4] = [ E0 as i32, E1 as i32, E2 as i32, E3 as i32 ];
1571        let vControl: __m128i = _mm_loadu_si128(mem::transmute(&elem[0]));
1572        return _mm_permutevar_ps(V, vControl);
1573    }
1574
1575    #[cfg(all(not(_XM_AVX_INTRINSICS_), _XM_SSE_INTRINSICS_))]
1576    unsafe {
1577        let aPtr = mem::transmute::<_, *const u32>(&V);
1578
1579        let mut Result: XMVECTOR = crate::undefined();
1580
1581        let pWork = mem::transmute::<_, *mut u32>(&mut Result);
1582
1583        idx!(mut pWork[0]) = idx!(aPtr[E0]);
1584        idx!(mut pWork[1]) = idx!(aPtr[E1]);
1585        idx!(mut pWork[2]) = idx!(aPtr[E2]);
1586        idx!(mut pWork[3]) = idx!(aPtr[E3]);
1587
1588        return Result;
1589    }
1590}
1591
1592#[test]
1593fn test_XMVectorSwizzle() {
1594    let a = XMVectorSet(1.0, 2.0, 3.0, 4.0);
1595    let b = XMVectorSwizzle(a, 3, 2, 1, 0);
1596    let c = XMVectorSet(4.0, 3.0, 2.0, 1.0);
1597
1598    assert_eq!(XMVectorGetX(b), XMVectorGetX(c));
1599    assert_eq!(XMVectorGetY(b), XMVectorGetY(c));
1600    assert_eq!(XMVectorGetZ(b), XMVectorGetZ(c));
1601    assert_eq!(XMVectorGetW(b), XMVectorGetW(c));
1602}
1603
1604/// Permutes the components of two vectors to create a new vector.
1605///
1606/// ## Parameters
1607///
1608/// `V1` First vector.
1609///
1610/// `V2` Second vector.
1611///
1612/// `PermuteX` Index form `0-7` indicating where the `X` component of the new vector should be copied from.
1613///
1614/// `PermuteY` Index form `0-7` indicating where the `Y` component of the new vector should be copied from.
1615///
1616/// `PermuteZ` Index form `0-7` indicating where the `Z` component of the new vector should be copied from.
1617///
1618/// `PermuteW` Index form `0-7` indicating where the `W` component of the new vector should be copied from.
1619///
1620/// ## Return value
1621///
1622/// Returns the permuted vector that resulted from combining the source vectors.
1623///
1624/// ## Remarks
1625///
1626/// If all 4 indices reference only a single vector (i.e. they are all in the range `0-3` or all in the range `4-7`),
1627/// use `XMVectorSwizzle` instead for better performance.
1628///
1629/// The `XM_PERMUTE_` constants are provided to use as input values for `PermuteX`, `PermuteY`, `PermuteZ`, and `PermuteW`.
1630///
1631/// For constant PermuteX/Y/Z/W parameters, it may more efficent to use the template form of [`XMVectorPermute`]
1632///
1633/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVectorPermute>
1634///
1635/// [`XMVectorPermute`]: trait@crate::XMVectorPermute
1636#[inline]
1637pub fn XMVectorPermute(
1638    V1: FXMVECTOR,
1639    V2: FXMVECTOR,
1640    PermuteX: u32,
1641    PermuteY: u32,
1642    PermuteZ: u32,
1643    PermuteW: u32
1644) -> XMVECTOR
1645{
1646    debug_assert!(PermuteX <= 7 && PermuteY <= 7 && PermuteZ <= 7 && PermuteW <= 7);
1647
1648    #[cfg(_XM_ARM_NEON_INTRINSICS_)]
1649    {
1650        unimplemented!()
1651    }
1652
1653    #[cfg(_XM_AVX_INTRINSICS_)]
1654    unsafe {
1655        const three: XMVECTORU32 = XMVECTORU32 { u: [ 3, 3, 3, 3 ] };
1656
1657        let elem: Align16<[u32; 4]> = Align16([PermuteX, PermuteY, PermuteZ, PermuteW]);
1658        let mut vControl: __m128i = _mm_load_si128(mem::transmute::<_, *const __m128i>(&elem[0]));
1659
1660        let vSelect: __m128i = _mm_cmpgt_epi32(vControl, three.m128i());
1661        vControl = _mm_castps_si128(_mm_and_ps(_mm_castsi128_ps(vControl), three.v));
1662
1663        let shuffled1: __m128 = _mm_permutevar_ps(V1, vControl);
1664        let shuffled2: __m128 = _mm_permutevar_ps(V2, vControl);
1665
1666        let masked1: __m128 = _mm_andnot_ps(_mm_castsi128_ps(vSelect), shuffled1);
1667        let masked2: __m128 = _mm_and_ps(_mm_castsi128_ps(vSelect), shuffled2);
1668
1669        return _mm_or_ps(masked1, masked2);
1670    }
1671
1672    #[cfg(all(not(_XM_ARM_NEON_INTRINSICS_), not(_XM_AVX_INTRINSICS_)))]
1673    unsafe {
1674        let aPtr: &[*const u32; 2] = &[
1675            mem::transmute(&V1),
1676            mem::transmute(&V2),
1677        ];
1678
1679        let mut Result: XMVECTOR = crate::undefined();
1680
1681        let pWork = mem::transmute::<_, *mut u32>(&mut Result);
1682
1683        let i0: u32 = PermuteX & 3;
1684        let vi0: u32 = PermuteX >> 2;
1685        idx!(mut pWork[0]) = idx!(aPtr[vi0][i0]);
1686
1687        let i1: u32 = PermuteY & 3;
1688        let vi1: u32 = PermuteY >> 2;
1689        idx!(mut pWork[1]) = idx!(aPtr[vi1][i1]);
1690
1691        let i2: u32 = PermuteZ & 3;
1692        let vi2: u32 = PermuteZ >> 2;
1693        idx!(mut pWork[2]) = idx!(aPtr[vi2][i2]);
1694
1695        let i3: u32 = PermuteW & 3;
1696        let vi3: u32 = PermuteW >> 2;
1697        idx!(mut pWork[3]) = idx!(aPtr[vi3][i3]);
1698
1699        return Result;
1700    }
1701}
1702
1703#[test]
1704fn test_XMVectorPermute() {
1705    let a = XMVectorSet(1.0, 2.0, 3.0, 4.0);
1706    let b = XMVectorSet(5.0, 6.0, 7.0, 8.0);
1707
1708    let c = XMVectorPermute(a, b, 0, 2, 4, 6);
1709    let d = XMVectorSet(1.0, 3.0, 5.0, 7.0);
1710
1711    assert_eq!(XMVectorGetX(c), XMVectorGetX(d));
1712    assert_eq!(XMVectorGetY(c), XMVectorGetY(d));
1713    assert_eq!(XMVectorGetZ(c), XMVectorGetZ(d));
1714    assert_eq!(XMVectorGetW(c), XMVectorGetW(d));
1715
1716    let e = XMVectorPermute(a, b, 1, 3, 5, 7);
1717    let f = XMVectorSet(2.0, 4.0, 6.0, 8.0);
1718
1719    assert_eq!(XMVectorGetX(e), XMVectorGetX(f));
1720    assert_eq!(XMVectorGetY(e), XMVectorGetY(f));
1721    assert_eq!(XMVectorGetZ(e), XMVectorGetZ(f));
1722    assert_eq!(XMVectorGetW(e), XMVectorGetW(f));
1723}
1724
1725/// Defines a control vector for use in [XMVectorSelect].
1726///
1727/// ## Parameters
1728///
1729/// `VectorIndex0` Index that determines which vector in XMVectorSelect will be selected. If zero, the first vector's first
1730/// component will be selected. Otherwise, the second vector's component will be selected.
1731///
1732/// `VectorIndex1` Index that determines which vector in XMVectorSelect will be selected. If zero, the first vector's second
1733/// component will be selected. Otherwise, the second vector's component will be selected.
1734///
1735/// `VectorIndex2` Index that determines which vector in XMVectorSelect will be selected. If zero, the first vector's third
1736/// component will be selected. Otherwise, the second vector's component will be selected.
1737///
1738/// `VectorIndex3` Index that determines which vector in XMVectorSelect will be selected. If zero, the first vector's fourth
1739/// component will be selected. Otherwise, the second vector's component will be selected.
1740///
1741/// ## Return value
1742///
1743/// Returns the control vector.
1744///
1745/// ## Remarks
1746///
1747/// The following pseudocode demonstrates the operation of the function:
1748///
1749/// ```text
1750/// XMVECTOR    ControlVector;
1751/// const uint32_t  ControlElement[] =
1752///             {
1753///                 XM_SELECT_0,
1754///                 XM_SELECT_1
1755///             };
1756///
1757/// assert(VectorIndex0 < 2);
1758/// assert(VectorIndex1 < 2);
1759/// assert(VectorIndex2 < 2);
1760/// assert(VectorIndex3 < 2);
1761///
1762/// ControlVector.u[0] = ControlElement[VectorIndex0];
1763/// ControlVector.u[1] = ControlElement[VectorIndex1];
1764/// ControlVector.u[2] = ControlElement[VectorIndex2];
1765/// ControlVector.u[3] = ControlElement[VectorIndex3];
1766///
1767/// return ControlVector;
1768/// ```
1769///
1770/// ## Reference
1771///
1772/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVectorSelectControl>
1773#[inline]
1774pub fn XMVectorSelectControl(
1775    VectorIndex0: u32,
1776    VectorIndex1: u32,
1777    VectorIndex2: u32,
1778    VectorIndex3: u32,
1779) -> XMVECTOR
1780{
1781    #[cfg(_XM_SSE_INTRINSICS_)]
1782    unsafe {
1783        // x=Index0,y=Index1,z=Index2,w=Index3
1784        let mut vTemp: __m128i = _mm_set_epi32(VectorIndex3 as i32, VectorIndex2 as i32, VectorIndex1 as i32, VectorIndex0 as i32);
1785        // Any non-zero entries become 0xFFFFFFFF else 0
1786        vTemp = _mm_cmpgt_epi32(vTemp, g_XMZero.m128i());
1787        return _mm_castsi128_ps(vTemp);
1788    }
1789
1790    #[cfg(_XM_ARM_NEON_INTRINSICS_)]
1791    {
1792        unimplemented!()
1793    }
1794
1795    #[cfg(not(any(_XM_SSE_INTRINSICS_, _XM_ARM_NEON_INTRINSICS_)))]
1796    unsafe {
1797        let mut ControlVector: XMVECTOR = crate::undefined();
1798        let ControlElement: [u32; 2] = [
1799            XM_SELECT_0,
1800            XM_SELECT_1,
1801        ];
1802
1803        ControlVector.vector4_u32[0] = ControlElement[VectorIndex0 as usize];
1804        ControlVector.vector4_u32[1] = ControlElement[VectorIndex1 as usize];
1805        ControlVector.vector4_u32[2] = ControlElement[VectorIndex2 as usize];
1806        ControlVector.vector4_u32[3] = ControlElement[VectorIndex3 as usize];
1807
1808        return ControlVector;
1809    }
1810}
1811
1812/// Performs a per-component selection between two input vectors and returns the resulting vector.
1813///
1814/// ## Parameters
1815///
1816/// `V1` First vector to compare.
1817///
1818/// `V2` Second vector to compare.
1819///
1820/// `Control` Vector mask used to select a vector component from either `V1` or `V2`. If a component of Control is zero,
1821/// the returned vector's corresponding component will be the first vector's component. If a component of
1822/// Control is 0xFF, the returned vector's corresponding component will be the second vector's component.
1823/// For full details on how the vector mask works, see the "Remarks". Typically, the vector used for Control
1824/// will be either the output of a vector comparison function (such as [XMVectorEqual], [XMVectorLess], or [XMVectorGreater])
1825/// or it will be the output of [XMVectorSelectControl].
1826///
1827/// ## Return value
1828///
1829/// Returns the result of the per-component selection.
1830///
1831/// ## Remarks
1832///
1833/// If any given bit of Control is set, the corresponding bit from `V2` is used, otherwise, the corresponding
1834/// bit from `V1` is used. The following pseudocode demonstrates the operation of the function:
1835///
1836/// ```text
1837/// XMVECTOR Result;
1838///
1839/// Result.u[0] = (V1.u[0] & ~Control.u[0]) | (V2.u[0] & Control.u[0]);
1840/// Result.u[1] = (V1.u[1] & ~Control.u[1]) | (V2.u[1] & Control.u[1]);
1841/// Result.u[2] = (V1.u[2] & ~Control.u[2]) | (V2.u[2] & Control.u[2]);
1842/// Result.u[3] = (V1.u[3] & ~Control.u[3]) | (V2.u[3] & Control.u[3]);
1843///
1844/// return Result;
1845/// ```
1846///
1847/// Manual construction of a control vector is not necessary. There are two simple ways of constructing
1848/// an appropriate control vector:
1849///
1850/// * Using the XMVectorSelectControlfunction to construct a control vector.
1851/// See Using XMVectorSelect and XMVectorSelectControl for a demonstration of how this function can be used.
1852///
1853/// * The control vector can be constructed using the `XM_SELECT_[0,1]` constant (see DirectXMath Library
1854/// Constants). As an example, in pseudo-code, an instance of Control with the elements:
1855///
1856/// ```text
1857/// Control = { XM_SELECT_0, XM_SELECT_1, XM_SELECT_0, XM_SELECT_1 }
1858/// ```
1859///
1860/// would return a vector Result with the following components of `V1` and `V2`
1861///
1862/// ```text
1863/// Result = { V1.X,  V2.Y,   V1.Z,   V2.W }
1864/// ```
1865///
1866/// ## Reference
1867///
1868/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVectorSelect>
1869#[inline]
1870pub fn XMVectorSelect(
1871    V1: FXMVECTOR,
1872    V2: FXMVECTOR,
1873    Control: FXMVECTOR,
1874) -> XMVECTOR
1875{
1876    #[cfg(_XM_NO_INTRINSICS_)]
1877    unsafe {
1878        let Result = XMVECTORU32 {
1879            u: [
1880                (V1.vector4_u32[0] & !Control.vector4_u32[0]) | (V2.vector4_u32[0] & Control.vector4_u32[0]),
1881                (V1.vector4_u32[1] & !Control.vector4_u32[1]) | (V2.vector4_u32[1] & Control.vector4_u32[1]),
1882                (V1.vector4_u32[2] & !Control.vector4_u32[2]) | (V2.vector4_u32[2] & Control.vector4_u32[2]),
1883                (V1.vector4_u32[3] & !Control.vector4_u32[3]) | (V2.vector4_u32[3] & Control.vector4_u32[3]),
1884            ]
1885        };
1886        return Result.v;
1887    }
1888
1889    #[cfg(_XM_ARM_NEON_INTRINSICS_)]
1890    {
1891        unimplemented!()
1892    }
1893
1894    #[cfg(_XM_SSE_INTRINSICS_)]
1895    unsafe {
1896        let vTemp1: XMVECTOR = _mm_andnot_ps(Control, V1);
1897        let vTemp2: XMVECTOR = _mm_and_ps(V2, Control);
1898        return _mm_or_ps(vTemp1, vTemp2);
1899    }
1900}
1901
1902/// Creates a new vector by combining the `x` and `y`-components of two vectors.
1903///
1904/// ## Parameters
1905///
1906/// `V1` First vector.
1907///
1908/// `V2` Second vector.
1909///
1910/// ## Return value
1911///
1912/// Returns the merged vector.
1913///
1914/// ## Remarks
1915///
1916/// The following pseudocode demonstrates the operation of the function:
1917///
1918/// ```text
1919/// XMVECTOR Result;
1920///
1921/// Result.x = V1.x;
1922/// Result.y = V2.x;
1923/// Result.z = V1.y;
1924/// Result.w = V2.y;
1925///
1926/// return Result;
1927/// ```
1928///
1929/// ## Reference
1930///
1931/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVectorMergeXY>
1932#[inline]
1933pub fn XMVectorMergeXY(
1934    V1: FXMVECTOR,
1935    V2: FXMVECTOR,
1936) -> XMVECTOR
1937{
1938    #[cfg(_XM_NO_INTRINSICS_)]
1939    unsafe {
1940        let Result = XMVECTORU32 {
1941            u: [
1942                V1.vector4_u32[0],
1943                V2.vector4_u32[0],
1944                V1.vector4_u32[1],
1945                V2.vector4_u32[1],
1946            ]
1947        };
1948        return Result.v;
1949    }
1950
1951    #[cfg(_XM_ARM_NEON_INTRINSICS_)]
1952    {
1953        unimplemented!()
1954    }
1955
1956    #[cfg(_XM_SSE_INTRINSICS_)]
1957    unsafe {
1958        return _mm_unpacklo_ps(V1, V2);
1959    }
1960}
1961
1962/// Creates a new vector by combining the `z` and `w`-components of two vectors.
1963///
1964/// ## Parameters
1965///
1966/// `V1` First vector.
1967///
1968/// `V2` Second vector.
1969///
1970/// ## Return value
1971///
1972/// Returns the merged vector.
1973///
1974/// ## Remarks
1975///
1976/// The following pseudocode demonstrates the operation of the function:
1977///
1978/// ```text
1979/// XMVECTOR Result;
1980///
1981/// Result.x = V1.z;
1982/// Result.y = V2.z;
1983/// Result.z = V1.w;
1984/// Result.w = V2.w;
1985///
1986/// return Result;
1987/// ```
1988///
1989/// ## Reference
1990///
1991/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVectorMergeZW>
1992#[inline]
1993pub fn XMVectorMergeZW(
1994    V1: FXMVECTOR,
1995    V2: FXMVECTOR,
1996) -> XMVECTOR
1997{
1998    #[cfg(_XM_NO_INTRINSICS_)]
1999    unsafe {
2000        let Result = XMVECTORU32 {
2001            u: [
2002                V1.vector4_u32[2],
2003                V2.vector4_u32[2],
2004                V1.vector4_u32[3],
2005                V2.vector4_u32[3]
2006            ]
2007        };
2008        return Result.v;
2009    }
2010
2011    #[cfg(_XM_ARM_NEON_INTRINSICS_)]
2012    {
2013        unimplemented!()
2014    }
2015
2016    #[cfg(_XM_SSE_INTRINSICS_)]
2017    unsafe {
2018        return _mm_unpackhi_ps(V1, V2);
2019    }
2020}
2021
2022/// Shifts a vector left by a given number of 32-bit elements, filling the vacated elements with elements from a second vector.
2023///
2024/// ## Parameters
2025///
2026/// `V1` Vector to shift left.
2027///
2028/// `V2` Vector used to fill in the vacated components of `V1` after it is shifted left.
2029///
2030/// `Elements` Number of 32-bit elements by which to shift `V` left. This parameter must be 0, 1, 2, or 3.
2031///
2032/// ## Return value
2033///
2034/// Returns the shifted and filled in XMVECTOR.
2035///
2036/// ## Remarks
2037///
2038/// The following code demonstrates how this function might be used.
2039///
2040/// ```text
2041/// XMVECTOR v1 = XMVectorSet( 10.0f, 20.0f, 30.0f, 40.0f );
2042/// XMVECTOR v2 = XMVectorSet( 50.0f, 60.0f, 70.0f, 80.0f );
2043/// XMVECTOR result = XMVectorShiftLeft( v1, v2, 1 );
2044/// ```
2045///
2046/// The shifted vector (result) will be <`20.0`, `30.0`, `40.0`, `50.0`>.
2047///
2048/// In the case of a constant shift value, it is more efficent to use the template form of XMVectorShiftLeft:
2049///
2050/// ## Reference
2051///
2052/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVectorShiftLeft>
2053#[inline]
2054pub fn XMVectorShiftLeft(V1: FXMVECTOR, V2: FXMVECTOR, Elements: u32) -> XMVECTOR {
2055    debug_assert!(Elements < 4);
2056    return XMVectorPermute(V1, V2, Elements, ((Elements)+1), ((Elements)+2), ((Elements)+3));
2057}
2058
2059/// Rotates the vector left by a given number of 32-bit elements.
2060///
2061/// ## Parameters
2062///
2063/// `V` Vector to rotate left.
2064///
2065/// `Elements` Number of 32-bit elements by which to rotate `V` left. This parameter must be `0`, `1`, `2`, or `3`.
2066///
2067/// ## Return value
2068///
2069/// Returns the rotated XMVECTOR.
2070///
2071/// ## Remarks
2072///
2073/// The following code demonstrates how this function may be used.
2074///
2075/// ```text
2076/// XMVECTOR v = XMVectorSet( 10.0f, 20.0f, 30.0f, 40.0f );
2077/// XMVECTOR result = XMVectorRotateLeft( v, 1 );
2078/// ```
2079///
2080/// The rotated vector (result) will be <`40.0`, `10.0`, `20.0`, `30.0`>.
2081///
2082/// In the case of a constant rotate value, it is more efficient to use the template form of XMVectorRotateRight:
2083///
2084/// ## Reference
2085///
2086/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVectorRotateLeft>
2087#[inline]
2088pub fn XMVectorRotateLeft(V: FXMVECTOR, Elements: u32) -> XMVECTOR {
2089    debug_assert!(Elements < 4);
2090    return XMVectorSwizzle(V, Elements & 3, (Elements + 1) & 3, (Elements + 2) & 3, (Elements + 3) & 3);
2091}
2092
2093/// Rotates the vector right by a given number of 32-bit elements.
2094///
2095/// ## Parameters
2096///
2097/// `V` Vector to rotate right.
2098///
2099/// `Elements` Number of 32-bit elements by which to rotate `V` right. This parameter must be `0`, `1`, `2`, or `3`.
2100///
2101/// ## Return value
2102///
2103/// Returns the rotated XMVECTOR.
2104///
2105/// ## Remarks
2106///
2107/// The following code demonstrates how this function may be used.
2108///
2109/// ```text
2110/// XMVECTOR v = XMVectorSet( 10.0f, 20.0f, 30.0f, 40.0f );
2111/// XMVECTOR result = XMVectorRotateRight( v, 1 );
2112/// ```
2113///
2114/// The rotated vector (result) will be <`40.0`, `10.0`, `20.0`, `30.0`>.
2115///
2116/// In the case of a constant rotate value, it is more efficient to use the template form of XMVectorRotateRight:
2117///
2118/// ## Reference
2119///
2120/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVectorRotateRight>
2121#[inline]
2122pub fn XMVectorRotateRight(V: FXMVECTOR, Elements: u32) -> XMVECTOR {
2123    debug_assert!(Elements < 4);
2124    return XMVectorSwizzle(V, (4 - (Elements)) & 3, (5 - (Elements)) & 3, (6 - (Elements)) & 3, (7 - (Elements)) & 3);
2125}
2126
2127/// Rotates a vector left by a given number of 32-bit components and insert selected elements of that result into another vector.
2128///
2129/// ## Parameters
2130///
2131/// `VD` Vector to insert into.
2132///
2133/// `VS` Vector to rotate left.
2134///
2135/// `VSLeftRotateElements` Number of 32-bit components by which to rotate `VS` left.
2136///
2137/// `Select0` Either `0` or 1. If one, the `x`-component of the rotated vector will be inserted into the corresponding
2138/// component of VD. Otherwise, the `x`-component of `VD` is left alone.
2139///
2140/// `Select1` Either `0` or 1. If one, the `y`-component of the rotated vector will be inserted into the corresponding
2141/// component of VD. Otherwise, the `y`-component of `VD` is left alone.
2142///
2143/// `Select2` Either `0` or 1. If one, the `z`-component of the rotated vector will be inserted into the corresponding
2144/// component of VD. Otherwise, the `z`-component of `VD` is left alone.
2145///
2146/// `Select3` Either `0` or 1. If one, the `w`-component of the rotated vector will be inserted into the corresponding
2147/// component of VD. Otherwise, the `w`-component of `VD` is left alone.
2148///
2149/// ## Return value
2150///
2151/// Returns the XMVECTOR that results from the rotation and insertion.
2152///
2153/// ## Remarks
2154///
2155/// For best performance, the result of XMVectorInsertshould be assigned back to `VD`.
2156///
2157/// For cases with constant uint32_t parameters, it is more efficent to use the template form of XMVectorInsert:
2158///
2159/// ## Reference
2160///
2161/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVectorInsert>
2162#[inline]
2163pub fn XMVectorInsert(
2164    VD: FXMVECTOR,
2165    VS: FXMVECTOR,
2166    VSLeftRotateElements: u32,
2167    Select0: u32,
2168    Select1: u32,
2169    Select2: u32,
2170    Select3: u32,
2171) -> XMVECTOR {
2172    let Control: XMVECTOR = XMVectorSelectControl(Select0 & 1, Select1 & 1, Select2 & 1, Select3 & 1);
2173    return XMVectorSelect(VD, XMVectorRotateLeft(VS, VSLeftRotateElements), Control);
2174}
2175
2176/// Performs a per-component test for equality of two vectors.
2177///
2178/// ## Parameters
2179///
2180/// `V1` First vector to compare.
2181///
2182/// `V2` Second vector to compare.
2183///
2184/// ## Return value
2185///
2186/// Returns a vector containing the results of each component test.
2187///
2188/// ## Remarks
2189///
2190/// The following pseudocode demonstrates the operation of the function:
2191///
2192/// ```text
2193/// XMVECTOR Result;
2194///
2195/// Result.x = (V1.x == V2.x) ? 0xFFFFFFFF : 0;
2196/// Result.y = (V1.y == V2.y) ? 0xFFFFFFFF : 0;
2197/// Result.z = (V1.z == V2.z) ? 0xFFFFFFFF : 0;
2198/// Result.w = (V1.w == V2.w) ? 0xFFFFFFFF : 0;
2199///
2200/// return Result;
2201/// ```
2202///
2203/// ## Reference
2204///
2205/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVectorEqual>
2206#[inline]
2207pub fn XMVectorEqual(
2208    V1: FXMVECTOR,
2209    V2: FXMVECTOR,
2210) -> XMVECTOR {
2211    #[cfg(_XM_NO_INTRINSICS_)]
2212    unsafe {
2213        let Control = XMVECTORU32 {
2214            u: [
2215                if V1.vector4_f32[0] == V2.vector4_f32[0] { 0xFFFFFFFF } else { 0 },
2216                if V1.vector4_f32[1] == V2.vector4_f32[1] { 0xFFFFFFFF } else { 0 },
2217                if V1.vector4_f32[2] == V2.vector4_f32[2] { 0xFFFFFFFF } else { 0 },
2218                if V1.vector4_f32[3] == V2.vector4_f32[3] { 0xFFFFFFFF } else { 0 },
2219            ]
2220        };
2221        return Control.v;
2222    }
2223
2224    #[cfg(_XM_ARM_NEON_INTRINSICS_)]
2225    {
2226        unimplemented!()
2227    }
2228
2229    #[cfg(_XM_SSE_INTRINSICS_)]
2230    unsafe {
2231        return _mm_cmpeq_ps(V1, V2);
2232    }
2233}
2234
2235/// Performs a per-component test for equality of two vectors and sets a comparison value that can be examined using functions such as XMComparisonAllTrue.
2236///
2237/// ## Parameters
2238///
2239/// `pCR` Pointer to a uint32_t comparison value that can be examined using functions such as [`XMComparisonAllTrue`].
2240/// The XMComparisonXXXX functions may be used to further test the number of components that passed the
2241/// comparison.
2242///
2243/// `V1` First vector to compare.
2244///
2245/// `V2` Second vector to compare.
2246///
2247/// ## Return value
2248///
2249/// Returns a vector containing the results of each component test.
2250///
2251/// ## Reference
2252///
2253/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVectorEqualR>
2254///
2255/// [`XMComparisonAllTrue`]: function@crate::XMComparisonAllTrue
2256#[inline]
2257pub fn XMVectorEqualR(pCR: &mut u32, V1: FXMVECTOR, V2: FXMVECTOR) -> XMVECTOR {
2258    #[cfg(_XM_NO_INTRINSICS_)]
2259    unsafe {
2260        let ux = if V1.vector4_f32[0] == V2.vector4_f32[0] { 0xFFFFFFFFu32 } else { 0 };
2261        let uy = if V1.vector4_f32[1] == V2.vector4_f32[1] { 0xFFFFFFFFu32 } else { 0 };
2262        let uz = if V1.vector4_f32[2] == V2.vector4_f32[2] { 0xFFFFFFFFu32 } else { 0 };
2263        let uw = if V1.vector4_f32[3] == V2.vector4_f32[3] { 0xFFFFFFFFu32 } else { 0 };
2264        let mut CR = 0;
2265        if ubool(ux & uy & uz & uw) {
2266            // All elements are greater
2267            CR = XM_CRMASK_CR6TRUE;
2268        } else if !ubool(ux | uy | uz | uw) {
2269            // All elements are not greater
2270            CR = XM_CRMASK_CR6FALSE;
2271        }
2272        *pCR = CR;
2273
2274        let Control = XMVECTORU32 { u: [ ux, uy, uz, uw ]};
2275        return Control.v;
2276    }
2277
2278    #[cfg(_XM_ARM_NEON_INTRINSICS_)]
2279    {
2280        unimplemented!()
2281    }
2282
2283    #[cfg(_XM_SSE_INTRINSICS_)]
2284    unsafe {
2285        let vTemp: XMVECTOR = _mm_cmpeq_ps(V1, V2);
2286        let mut CR = 0;
2287        let iTest: i32 = _mm_movemask_ps(vTemp);
2288        if (iTest == 0xf)
2289        {
2290            // All elements are greater
2291            CR = XM_CRMASK_CR6TRUE;
2292        }
2293        else if !ibool(iTest)
2294        {
2295            // All elements are not greater
2296            CR = XM_CRMASK_CR6FALSE;
2297        }
2298        *pCR = CR;
2299        return vTemp;
2300    }
2301}
2302
2303#[test]
2304fn test_XMVectorEqualR() {
2305    let a = XMVectorSet(1.0, 2.0, 3.0, 4.0);
2306    let b = XMVectorSet(1.0, 2.0, 3.0, 4.0);
2307    let mut cr = 0;
2308    let r = XMVectorEqualR(&mut cr, a, b);
2309    assert!(XMComparisonAllTrue(cr));
2310    assert_eq!([true, true, true, true],  [XMVectorGetX(r).is_nan(), XMVectorGetY(r).is_nan(), XMVectorGetZ(r).is_nan(), XMVectorGetW(r).is_nan()]);
2311
2312    let a = XMVectorSet(0.0, 0.0, 0.0, 0.0);
2313    let b = XMVectorSplatOne();
2314    let r = XMVectorEqualR(&mut cr, a, b);
2315    assert!(XMComparisonAllFalse(cr));
2316    assert_eq!([false, false, false, false],  [XMVectorGetX(r).is_nan(), XMVectorGetY(r).is_nan(), XMVectorGetZ(r).is_nan(), XMVectorGetW(r).is_nan()]);
2317
2318    let a = XMVectorSet(1.0, 0.0, 1.0, 0.0);
2319    let b = XMVectorSplatOne();
2320    let r = XMVectorEqualR(&mut cr, a, b);
2321    assert!(XMComparisonAnyFalse(cr));
2322    assert!(XMComparisonAnyTrue(cr));
2323    assert_eq!([true, false, true, false],  [XMVectorGetX(r).is_nan(), XMVectorGetY(r).is_nan(), XMVectorGetZ(r).is_nan(), XMVectorGetW(r).is_nan()]);
2324}
2325
2326/// Performs a per-component test for the equality of two vectors, treating each component as an unsigned integer.
2327///
2328/// ## Parameters
2329///
2330/// `V1` First vector to compare.
2331///
2332/// `V2` Second vector to compare.
2333///
2334/// ## Return value
2335///
2336/// Returns a vector containing the results of each component test.
2337///
2338/// ## Remarks
2339///
2340/// The following pseudocode demonstrates the operation of the function:
2341///
2342/// ```text
2343/// XMVECTOR Result;
2344///
2345/// Result.x = (V1.x == V2.x) ? 0xFFFFFFFF : 0;
2346/// Result.y = (V1.y == V2.y) ? 0xFFFFFFFF : 0;
2347/// Result.z = (V1.z == V2.z) ? 0xFFFFFFFF : 0;
2348/// Result.w = (V1.w == V2.w) ? 0xFFFFFFFF : 0;
2349///
2350/// return Result;
2351/// ```
2352///
2353/// ## Reference
2354///
2355/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVectorEqualInt>
2356#[inline]
2357pub fn XMVectorEqualInt(V1: FXMVECTOR, V2: FXMVECTOR) -> XMVECTOR {
2358    #[cfg(_XM_NO_INTRINSICS_)]
2359    unsafe {
2360        let Control = XMVECTORU32 {
2361            u: [
2362                if V1.vector4_u32[0] == V2.vector4_u32[0] { 0xFFFFFFFF } else { 0 },
2363                if V1.vector4_u32[1] == V2.vector4_u32[1] { 0xFFFFFFFF } else { 0 },
2364                if V1.vector4_u32[2] == V2.vector4_u32[2] { 0xFFFFFFFF } else { 0 },
2365                if V1.vector4_u32[3] == V2.vector4_u32[3] { 0xFFFFFFFF } else { 0 },
2366            ]
2367        };
2368        return Control.v;
2369    }
2370
2371    #[cfg(_XM_ARM_NEON_INTRINSICS_)]
2372    {
2373        unimplemented!()
2374    }
2375
2376    #[cfg(_XM_SSE_INTRINSICS_)]
2377    unsafe {
2378        let V: __m128i = _mm_cmpeq_epi32(_mm_castps_si128(V1), _mm_castps_si128(V2));
2379        return _mm_castsi128_ps(V);
2380    }
2381}
2382
2383/// Performs a per-component test for equality of two vectors, treating each
2384/// component as an unsigned integer. In addition, this function sets a
2385/// comparison value that can be examined using functions such as XMComparisonAllTrue.
2386///
2387/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVectorEqualIntR>
2388#[inline]
2389pub fn XMVectorEqualIntR(pCR: &mut u32, V1: FXMVECTOR, V2: FXMVECTOR) -> XMVECTOR {
2390    #[cfg(_XM_NO_INTRINSICS_)]
2391    {
2392        let Control: XMVECTOR = XMVectorEqualInt(V1, V2);
2393
2394        *pCR = 0;
2395        if (XMVector4EqualInt(Control, XMVectorTrueInt()))
2396        {
2397            // All elements are equal
2398            *pCR |= XM_CRMASK_CR6TRUE;
2399        }
2400        else if (XMVector4EqualInt(Control, XMVectorFalseInt()))
2401        {
2402            // All elements are not equal
2403            *pCR |= XM_CRMASK_CR6FALSE;
2404        }
2405        return Control;
2406    }
2407
2408    #[cfg(_XM_ARM_NEON_INTRINSICS_)]
2409    {
2410        unimplemented!()
2411    }
2412
2413    #[cfg(_XM_SSE_INTRINSICS_)]
2414    unsafe {
2415        let V: __m128i = _mm_cmpeq_epi32(_mm_castps_si128(V1), _mm_castps_si128(V2));
2416        let iTemp: i32 = _mm_movemask_ps(_mm_castsi128_ps(V));
2417        let mut CR: u32 = 0;
2418        if (iTemp == 0x0F)
2419        {
2420            CR = XM_CRMASK_CR6TRUE;
2421        }
2422        else if !ibool(iTemp)
2423        {
2424            CR = XM_CRMASK_CR6FALSE;
2425        }
2426        *pCR = CR;
2427        return _mm_castsi128_ps(V);
2428    }
2429}
2430
2431/// Performs a per-component test for equality of two vectors within a given threshold.
2432///
2433/// ## Parameters
2434///
2435/// `V1` First vector to compare.
2436///
2437/// `V2` Second vector compare.
2438///
2439/// `Epsilon` Tolerance value used for judging equality.
2440///
2441/// ## Return value
2442///
2443/// Returns a vector containing the results of each component test.
2444///
2445/// ## Remarks
2446///
2447/// The following pseudocode demonstrates the operation of the function:
2448/// ```text
2449/// XMVECTOR Result;
2450///
2451/// Result.x = (abs(V1.x - V2.x) <= Epsilon) ? 0xFFFFFFFF : 0;
2452/// Result.y = (abs(V1.y - V2.y) <= Epsilon) ? 0xFFFFFFFF : 0;
2453/// Result.z = (abs(V1.z - V2.z) <= Epsilon) ? 0xFFFFFFFF : 0;
2454/// Result.w = (abs(V1.w - V2.w) <= Epsilon) ? 0xFFFFFFFF : 0;
2455///
2456/// return Result;
2457/// ```
2458/// ## Reference
2459///
2460/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVectorNearEqual>
2461#[inline]
2462pub fn XMVectorNearEqual(V1: FXMVECTOR, V2: FXMVECTOR, Epsilon: FXMVECTOR) -> XMVECTOR {
2463    #[cfg(_XM_NO_INTRINSICS_)]
2464    unsafe {
2465        let fDeltax: f32 = V1.vector4_f32[0] - V2.vector4_f32[0];
2466        let fDeltay: f32 = V1.vector4_f32[1] - V2.vector4_f32[1];
2467        let fDeltaz: f32 = V1.vector4_f32[2] - V2.vector4_f32[2];
2468        let fDeltaw: f32 = V1.vector4_f32[3] - V2.vector4_f32[3];
2469
2470        let fDeltax = fabsf(fDeltax);
2471        let fDeltay = fabsf(fDeltay);
2472        let fDeltaz = fabsf(fDeltaz);
2473        let fDeltaw = fabsf(fDeltaw);
2474
2475        let Control = XMVECTORU32 {
2476            u: [
2477                if fDeltax <= Epsilon.vector4_f32[0] { 0xFFFFFFFFu32 } else { 0 },
2478                if fDeltay <= Epsilon.vector4_f32[1] { 0xFFFFFFFFu32 } else { 0 },
2479                if fDeltaz <= Epsilon.vector4_f32[2] { 0xFFFFFFFFu32 } else { 0 },
2480                if fDeltaw <= Epsilon.vector4_f32[3] { 0xFFFFFFFFu32 } else { 0 },
2481            ]
2482        };
2483        return Control.v;
2484    }
2485
2486    #[cfg(_XM_ARM_NEON_INTRINSICS_)]
2487    {
2488        unimplemented!()
2489    }
2490
2491    #[cfg(_XM_SSE_INTRINSICS_)]
2492    unsafe {
2493        // Get the difference
2494        let vDelta: XMVECTOR = _mm_sub_ps(V1, V2);
2495        // Get the absolute value of the difference
2496        let mut vTemp: XMVECTOR = _mm_setzero_ps();
2497        vTemp = _mm_sub_ps(vTemp, vDelta);
2498        vTemp = _mm_max_ps(vTemp, vDelta);
2499        vTemp = _mm_cmple_ps(vTemp, Epsilon);
2500        return vTemp;
2501    }
2502}
2503
2504/// Performs a per-component test for the inequality of two vectors.
2505///
2506/// ## Parameters
2507///
2508/// `V1` First vector to compare.
2509///
2510/// `V2` Second vector to compare.
2511///
2512/// ## Return value
2513///
2514/// Returns a vector containing the results of each component test.
2515///
2516/// ## Remarks
2517///
2518/// The following pseudocode demonstrates the operation of the function:
2519///
2520/// ```text
2521/// XMVECTOR Result;
2522///
2523/// Result.x = (V1.x != V2.x) ? 0xFFFFFFFF : 0;
2524/// Result.y = (V1.y != V2.y) ? 0xFFFFFFFF : 0;
2525/// Result.z = (V1.z != V2.z) ? 0xFFFFFFFF : 0;
2526/// Result.w = (V1.w != V2.w) ? 0xFFFFFFFF : 0;
2527///
2528/// return Result;
2529/// ```
2530///
2531/// ## Reference
2532///
2533/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVectorNotEqual>
2534#[inline]
2535pub fn XMVectorNotEqual(V1: FXMVECTOR, V2: FXMVECTOR) -> XMVECTOR {
2536    #[cfg(_XM_NO_INTRINSICS_)]
2537    unsafe {
2538        let Control = XMVECTORU32 {
2539            u: [
2540                if V1.vector4_f32[0] != V2.vector4_f32[0] { 0xFFFFFFFF } else { 0 },
2541                if V1.vector4_f32[1] != V2.vector4_f32[1] { 0xFFFFFFFF } else { 0 },
2542                if V1.vector4_f32[2] != V2.vector4_f32[2] { 0xFFFFFFFF } else { 0 },
2543                if V1.vector4_f32[3] != V2.vector4_f32[3] { 0xFFFFFFFF } else { 0 },
2544            ]
2545        };
2546        return Control.v;
2547    }
2548
2549    #[cfg(_XM_ARM_NEON_INTRINSICS_)]
2550    {
2551        unimplemented!()
2552    }
2553
2554    #[cfg(_XM_SSE_INTRINSICS_)]
2555    unsafe {
2556        return _mm_cmpneq_ps(V1, V2);
2557    }
2558}
2559
2560/// Performs a per-component test for the inequality of two vectors, treating each component as an unsigned integer.
2561///
2562/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVectorNotEqualInt>
2563#[inline]
2564pub fn XMVectorNotEqualInt(V1: FXMVECTOR, V2: FXMVECTOR) -> XMVECTOR {
2565    #[cfg(_XM_NO_INTRINSICS_)]
2566    unsafe {
2567        let Control = XMVECTORU32 {
2568            u: [
2569                if V1.vector4_u32[0] != V2.vector4_u32[0] { 0xFFFFFFFF } else { 0 },
2570                if V1.vector4_u32[1] != V2.vector4_u32[1] { 0xFFFFFFFF } else { 0 },
2571                if V1.vector4_u32[2] != V2.vector4_u32[2] { 0xFFFFFFFF } else { 0 },
2572                if V1.vector4_u32[3] != V2.vector4_u32[3] { 0xFFFFFFFF } else { 0 },
2573            ]
2574        };
2575        return Control.v;
2576    }
2577
2578    #[cfg(_XM_ARM_NEON_INTRINSICS_)]
2579    {
2580        unimplemented!()
2581    }
2582
2583    #[cfg(_XM_SSE_INTRINSICS_)]
2584    unsafe {
2585        let V: __m128i = _mm_cmpeq_epi32(_mm_castps_si128(V1), _mm_castps_si128(V2));
2586        return _mm_xor_ps(_mm_castsi128_ps(V), g_XMNegOneMask.v);
2587    }
2588}
2589
2590/// Performs a per-component test for greater-than between two vectors.
2591///
2592/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVectorGreater>
2593#[inline]
2594pub fn XMVectorGreater(V1: FXMVECTOR, V2: FXMVECTOR) -> XMVECTOR {
2595    #[cfg(_XM_NO_INTRINSICS_)]
2596    unsafe {
2597        let Control = XMVECTORU32 {
2598            u: [
2599                if V1.vector4_f32[0] > V2.vector4_f32[0] { 0xFFFFFFFF } else { 0 },
2600                if V1.vector4_f32[1] > V2.vector4_f32[1] { 0xFFFFFFFF } else { 0 },
2601                if V1.vector4_f32[2] > V2.vector4_f32[2] { 0xFFFFFFFF } else { 0 },
2602                if V1.vector4_f32[3] > V2.vector4_f32[3] { 0xFFFFFFFF } else { 0 },
2603            ]
2604        };
2605        return Control.v;
2606    }
2607
2608    #[cfg(_XM_ARM_NEON_INTRINSICS_)]
2609    {
2610        unimplemented!()
2611    }
2612
2613    #[cfg(_XM_SSE_INTRINSICS_)]
2614    unsafe {
2615        return _mm_cmpgt_ps(V1, V2);
2616    }
2617}
2618
2619/// Performs a per-component test for greater-than between two vectors and sets a comparison value that can be examined using functions such as XMComparisonAllTrue.
2620///
2621/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVectorGreaterR>
2622#[inline]
2623pub fn XMVectorGreaterR(pCR: &mut u32, V1: FXMVECTOR, V2: FXMVECTOR) -> XMVECTOR {
2624    #[cfg(_XM_NO_INTRINSICS_)]
2625    unsafe {
2626        let ux = if V1.vector4_f32[0] > V2.vector4_f32[0] { 0xFFFFFFFFu32 } else { 0 };
2627        let uy = if V1.vector4_f32[1] > V2.vector4_f32[1] { 0xFFFFFFFFu32 } else { 0 };
2628        let uz = if V1.vector4_f32[2] > V2.vector4_f32[2] { 0xFFFFFFFFu32 } else { 0 };
2629        let uw = if V1.vector4_f32[3] > V2.vector4_f32[3] { 0xFFFFFFFFu32 } else { 0 };
2630        let mut CR = 0;
2631        if ubool(ux & uy & uz & uw) {
2632            // All elements are greater
2633            CR = XM_CRMASK_CR6TRUE;
2634        } else if !ubool(ux | uy | uz | uw) {
2635            // All elements are not greater
2636            CR = XM_CRMASK_CR6FALSE;
2637        }
2638        *pCR = CR;
2639
2640        let Control = XMVECTORU32 { u: [ ux, uy, uz, uw ]};
2641        return Control.v;
2642    }
2643
2644    #[cfg(_XM_ARM_NEON_INTRINSICS_)]
2645    {
2646        unimplemented!()
2647    }
2648
2649    #[cfg(_XM_SSE_INTRINSICS_)]
2650    unsafe {
2651        let vTemp: XMVECTOR = _mm_cmpgt_ps(V1, V2);
2652        let mut CR = 0;
2653        let iTest: i32 = _mm_movemask_ps(vTemp);
2654        if (iTest == 0xf)
2655        {
2656            // All elements are greater
2657            CR = XM_CRMASK_CR6TRUE;
2658        }
2659        else if !ibool(iTest)
2660        {
2661            // All elements are not greater
2662            CR = XM_CRMASK_CR6FALSE;
2663        }
2664        *pCR = CR;
2665        return vTemp;
2666    }
2667}
2668
2669/// Performs a per-component test for greater-than-or-equal between two vectors.
2670///
2671/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVectorGreaterOrEqual>
2672#[inline]
2673pub fn XMVectorGreaterOrEqual(V1: FXMVECTOR, V2: FXMVECTOR) -> XMVECTOR {
2674    #[cfg(_XM_NO_INTRINSICS_)]
2675    unsafe {
2676        let Control = XMVECTORU32 {
2677            u: [
2678                if V1.vector4_f32[0] >= V2.vector4_f32[0] { 0xFFFFFFFF } else { 0 },
2679                if V1.vector4_f32[1] >= V2.vector4_f32[1] { 0xFFFFFFFF } else { 0 },
2680                if V1.vector4_f32[2] >= V2.vector4_f32[2] { 0xFFFFFFFF } else { 0 },
2681                if V1.vector4_f32[3] >= V2.vector4_f32[3] { 0xFFFFFFFF } else { 0 },
2682            ]
2683        };
2684        return Control.v;
2685    }
2686
2687    #[cfg(_XM_ARM_NEON_INTRINSICS_)]
2688    {
2689        unimplemented!()
2690    }
2691
2692    #[cfg(_XM_SSE_INTRINSICS_)]
2693    unsafe {
2694        return _mm_cmpge_ps(V1, V2);
2695    }
2696}
2697
2698/// Performs a per-component test for greater-than-or-equal between two vectors and sets a comparison value that can be examined using functions such as XMComparisonAllTrue.
2699///
2700/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVectorGreaterOrEqualR>
2701#[inline]
2702pub fn XMVectorGreaterOrEqualR(pCR: &mut u32, V1: FXMVECTOR, V2: FXMVECTOR) -> XMVECTOR {
2703    #[cfg(_XM_NO_INTRINSICS_)]
2704    unsafe {
2705        let ux = if V1.vector4_f32[0] >= V2.vector4_f32[0] { 0xFFFFFFFFu32 } else { 0 };
2706        let uy = if V1.vector4_f32[1] >= V2.vector4_f32[1] { 0xFFFFFFFFu32 } else { 0 };
2707        let uz = if V1.vector4_f32[2] >= V2.vector4_f32[2] { 0xFFFFFFFFu32 } else { 0 };
2708        let uw = if V1.vector4_f32[3] >= V2.vector4_f32[3] { 0xFFFFFFFFu32 } else { 0 };
2709        let mut CR = 0;
2710        if ubool(ux & uy & uz & uw) {
2711            // All elements are greater
2712            CR = XM_CRMASK_CR6TRUE;
2713        } else if !ubool(ux | uy | uz | uw) {
2714            // All elements are not greater
2715            CR = XM_CRMASK_CR6FALSE;
2716        }
2717        *pCR = CR;
2718
2719        let Control = XMVECTORU32 { u: [ ux, uy, uz, uw ]};
2720        return Control.v;
2721    }
2722
2723    #[cfg(_XM_ARM_NEON_INTRINSICS_)]
2724    {
2725        unimplemented!()
2726    }
2727
2728    #[cfg(_XM_SSE_INTRINSICS_)]
2729    unsafe {
2730        let vTemp: XMVECTOR = _mm_cmpge_ps(V1, V2);
2731        let mut CR = 0;
2732        let iTest: i32 = _mm_movemask_ps(vTemp);
2733        if (iTest == 0xf)
2734        {
2735            // All elements are greater
2736            CR = XM_CRMASK_CR6TRUE;
2737        }
2738        else if !ibool(iTest)
2739        {
2740            // All elements are not greater
2741            CR = XM_CRMASK_CR6FALSE;
2742        }
2743        *pCR = CR;
2744        return vTemp;
2745    }
2746}
2747
2748/// Performs a per-component test for less-than between two vectors.
2749///
2750/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVectorLess>
2751#[inline]
2752pub fn XMVectorLess(V1: FXMVECTOR, V2: FXMVECTOR) -> XMVECTOR {
2753    #[cfg(_XM_NO_INTRINSICS_)]
2754    unsafe {
2755        let Control = XMVECTORU32 {
2756            u: [
2757                if V1.vector4_f32[0] < V2.vector4_f32[0] { 0xFFFFFFFF } else { 0 },
2758                if V1.vector4_f32[1] < V2.vector4_f32[1] { 0xFFFFFFFF } else { 0 },
2759                if V1.vector4_f32[2] < V2.vector4_f32[2] { 0xFFFFFFFF } else { 0 },
2760                if V1.vector4_f32[3] < V2.vector4_f32[3] { 0xFFFFFFFF } else { 0 },
2761            ]
2762        };
2763        return Control.v;
2764    }
2765
2766    #[cfg(_XM_ARM_NEON_INTRINSICS_)]
2767    {
2768        unimplemented!()
2769    }
2770
2771    #[cfg(_XM_SSE_INTRINSICS_)]
2772    unsafe {
2773        return _mm_cmplt_ps(V1, V2);
2774    }
2775}
2776
2777/// Performs a per-component test for less-than-or-equal between two vectors.
2778///
2779/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVectorLessOrEqual>
2780#[inline]
2781pub fn XMVectorLessOrEqual(V1: FXMVECTOR, V2: FXMVECTOR) -> XMVECTOR {
2782    #[cfg(_XM_NO_INTRINSICS_)]
2783    unsafe {
2784        let Control = XMVECTORU32 {
2785            u: [
2786                if V1.vector4_f32[0] <= V2.vector4_f32[0] { 0xFFFFFFFF } else { 0 },
2787                if V1.vector4_f32[1] <= V2.vector4_f32[1] { 0xFFFFFFFF } else { 0 },
2788                if V1.vector4_f32[2] <= V2.vector4_f32[2] { 0xFFFFFFFF } else { 0 },
2789                if V1.vector4_f32[3] <= V2.vector4_f32[3] { 0xFFFFFFFF } else { 0 },
2790            ]
2791        };
2792        return Control.v;
2793    }
2794
2795    #[cfg(_XM_ARM_NEON_INTRINSICS_)]
2796    {
2797        unimplemented!()
2798    }
2799
2800    #[cfg(_XM_SSE_INTRINSICS_)]
2801    unsafe {
2802        return _mm_cmple_ps(V1, V2);
2803    }
2804}
2805
2806/// Tests whether the components of a given vector are within set bounds.
2807///
2808/// ## Parameters
2809///
2810/// `V` Vector to test.
2811///
2812/// `Bounds` Vector that determines the bounds.
2813///
2814/// ## Return value
2815///
2816/// Returns a vector containing the results of each component test.
2817///
2818/// ## Remarks
2819///
2820/// The following pseudocode demonstrates the operation of the function:
2821///
2822/// ```text
2823/// XMVECTOR Control;
2824///
2825/// Control.x = (V.x <= Bounds.x && V.x >= -Bounds.x) ? 0xFFFFFFFF : 0;
2826/// Control.y = (V.y <= Bounds.y && V.y >= -Bounds.y) ? 0xFFFFFFFF : 0;
2827/// Control.z = (V.z <= Bounds.z && V.z >= -Bounds.z) ? 0xFFFFFFFF : 0;
2828/// Control.w = (V.w <= Bounds.w && V.w >= -Bounds.w) ? 0xFFFFFFFF : 0;
2829///
2830/// return Control;
2831/// ```
2832///
2833/// ## Reference
2834///
2835/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVectorInBounds>
2836#[inline]
2837pub fn XMVectorInBounds(V: FXMVECTOR, Bounds: FXMVECTOR) -> XMVECTOR {
2838    #[cfg(_XM_NO_INTRINSICS_)]
2839    unsafe {
2840        let Control = XMVECTORU32 {
2841            u: [
2842                if V.vector4_f32[0] <= Bounds.vector4_f32[0] && V.vector4_f32[0] >= -Bounds.vector4_f32[0] { 0xFFFFFFFF } else { 0 },
2843                if V.vector4_f32[1] <= Bounds.vector4_f32[1] && V.vector4_f32[1] >= -Bounds.vector4_f32[1] { 0xFFFFFFFF } else { 0 },
2844                if V.vector4_f32[2] <= Bounds.vector4_f32[2] && V.vector4_f32[2] >= -Bounds.vector4_f32[2] { 0xFFFFFFFF } else { 0 },
2845                if V.vector4_f32[3] <= Bounds.vector4_f32[3] && V.vector4_f32[3] >= -Bounds.vector4_f32[3] { 0xFFFFFFFF } else { 0 },
2846            ]
2847        };
2848        return Control.v;
2849    }
2850
2851    #[cfg(_XM_ARM_NEON_INTRINSICS_)]
2852    {
2853        unimplemented!()
2854    }
2855
2856    #[cfg(_XM_SSE_INTRINSICS_)]
2857    unsafe {
2858        // Test if less than or equal
2859        let mut vTemp1: XMVECTOR = _mm_cmple_ps(V, Bounds);
2860        // Negate the bounds
2861        let mut vTemp2: XMVECTOR = _mm_mul_ps(Bounds, g_XMNegativeOne.v);
2862        // Test if greater or equal (Reversed)
2863        vTemp2 = _mm_cmple_ps(vTemp2, V);
2864        // Blend answers
2865        vTemp1 = _mm_and_ps(vTemp1, vTemp2);
2866        return vTemp1;
2867    }
2868}
2869
2870/// Tests whether the components of a given vector are within certain bounds and sets a comparison value that can be examined using functions such as XMComparisonAllTrue.
2871///
2872/// ## Parameters
2873///
2874/// `pCR` Pointer to a uint32_t comparison value that can be examined using functions such as XMComparisonAllInBounds.
2875/// The XMComparisonXXXX functions may be used to further test the number of components that passed the
2876/// comparison.
2877///
2878/// `V` Vector to test.
2879///
2880/// `Bounds` Vector that determines the bounds.
2881///
2882/// ## Return value
2883///
2884/// Returns a vector containing the results of each component test.
2885///
2886/// ## Remarks
2887///
2888/// The following pseudocode demonstrates the comparison operation of the function:
2889///
2890/// ```text
2891/// XMVECTOR Control;
2892///
2893/// Control.x = (V.x <= Bounds.x && V.x >= -Bounds.x) ? 0xFFFFFFFF : 0;
2894/// Control.y = (V.y <= Bounds.y && V.y >= -Bounds.y) ? 0xFFFFFFFF : 0;
2895/// Control.z = (V.z <= Bounds.z && V.z >= -Bounds.z) ? 0xFFFFFFFF : 0;
2896/// Control.w = (V.w <= Bounds.w && V.w >= -Bounds.w) ? 0xFFFFFFFF : 0;
2897///
2898/// return Control;
2899/// ```
2900///
2901/// ## Reference
2902///
2903/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVectorInBoundsR>
2904#[inline]
2905pub fn XMVectorInBoundsR(pCR: &mut u32, V: FXMVECTOR, Bounds: FXMVECTOR) -> XMVECTOR {
2906    #[cfg(_XM_NO_INTRINSICS_)]
2907    unsafe {
2908        let ux = if V.vector4_f32[0] <= Bounds.vector4_f32[0] && V.vector4_f32[0] >= -Bounds.vector4_f32[0] { 0xFFFFFFFF } else { 0 };
2909        let uy = if V.vector4_f32[1] <= Bounds.vector4_f32[1] && V.vector4_f32[1] >= -Bounds.vector4_f32[1] { 0xFFFFFFFF } else { 0 };
2910        let uz = if V.vector4_f32[2] <= Bounds.vector4_f32[2] && V.vector4_f32[2] >= -Bounds.vector4_f32[2] { 0xFFFFFFFF } else { 0 };
2911        let uw = if V.vector4_f32[3] <= Bounds.vector4_f32[3] && V.vector4_f32[3] >= -Bounds.vector4_f32[3] { 0xFFFFFFFF } else { 0 };
2912
2913        let mut CR = 0;
2914        if ubool(ux & uy & uz & uw) {
2915            // All elements are in bounds
2916            CR = XM_CRMASK_CR6TRUE;
2917        }
2918        *pCR = CR;
2919
2920        let Control = XMVECTORU32 { u: [ ux, uy, uz, uw ]};
2921        return Control.v;
2922    }
2923
2924    #[cfg(_XM_ARM_NEON_INTRINSICS_)]
2925    {
2926        unimplemented!()
2927    }
2928
2929    #[cfg(_XM_SSE_INTRINSICS_)]
2930    unsafe {
2931        // Test if less than or equal
2932        let mut vTemp1: XMVECTOR = _mm_cmple_ps(V, Bounds);
2933        // Negate the bounds
2934        let mut vTemp2: XMVECTOR = _mm_mul_ps(Bounds, g_XMNegativeOne.v);
2935        // Test if greater or equal (Reversed)
2936        vTemp2 = _mm_cmple_ps(vTemp2, V);
2937        // Blend answers
2938        vTemp1 = _mm_and_ps(vTemp1, vTemp2);
2939
2940        let mut CR: u32 = 0;
2941        if (_mm_movemask_ps(vTemp1) == 0xf)
2942        {
2943            // All elements are in bounds
2944            CR = XM_CRMASK_CR6BOUNDS;
2945        }
2946        *pCR = CR;
2947        return vTemp1;
2948    }
2949}
2950
2951/// Performs a per-component NaN test on a vector.
2952///
2953/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVectorIsNaN>
2954#[inline]
2955pub fn XMVectorIsNaN(V: FXMVECTOR) -> XMVECTOR {
2956    #[cfg(_XM_NO_INTRINSICS_)]
2957    unsafe {
2958        let Control = XMVECTORU32 {
2959            u: [
2960                if XMISNAN!(V.vector4_f32[0]) { 0xFFFFFFFFu32 } else { 0 },
2961                if XMISNAN!(V.vector4_f32[1]) { 0xFFFFFFFFu32 } else { 0 },
2962                if XMISNAN!(V.vector4_f32[2]) { 0xFFFFFFFFu32 } else { 0 },
2963                if XMISNAN!(V.vector4_f32[3]) { 0xFFFFFFFFu32 } else { 0 },
2964            ]
2965        };
2966        return Control.v;
2967    }
2968
2969    #[cfg(_XM_ARM_NEON_INTRINSICS_)]
2970    {
2971        unimplemented!()
2972    }
2973
2974    #[cfg(_XM_SSE_INTRINSICS_)]
2975    unsafe {
2976        // Test against itself. NaN is always not equal
2977        return _mm_cmpneq_ps(V, V);
2978    }
2979}
2980
2981/// Performs a per-component test for +/- infinity on a vector.
2982///
2983/// ## Parameters
2984///
2985/// `V` Vector to test.
2986///
2987/// ## Return value
2988///
2989/// Returns a vector containing the results of each component test.
2990///
2991/// ## Remarks
2992///
2993/// The following pseudocode demonstrates the operation of the function:
2994///
2995/// ```text
2996/// XMVECTOR Result;
2997///
2998/// Result.x = (V.x == +infinity || V.x == -infinity) ? 0xFFFFFFFF : 0;
2999/// Result.y = (V.y == +infinity || V.y == -infinity) ? 0xFFFFFFFF : 0;
3000/// Result.z = (V.z == +infinity || V.z == -infinity) ? 0xFFFFFFFF : 0;
3001/// Result.w = (V.w == +infinity || V.w == -infinity) ? 0xFFFFFFFF : 0;
3002///
3003/// return Result;
3004/// ```
3005///
3006/// ## Reference
3007///
3008/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVectorIsInfinite>
3009#[inline]
3010pub fn XMVectorIsInfinite(V: FXMVECTOR) -> XMVECTOR {
3011    #[cfg(_XM_NO_INTRINSICS_)]
3012    unsafe {
3013        let Control = XMVECTORU32 {
3014            u: [
3015                if XMISINF!(V.vector4_f32[0]) { 0xFFFFFFFFu32 } else { 0 },
3016                if XMISINF!(V.vector4_f32[1]) { 0xFFFFFFFFu32 } else { 0 },
3017                if XMISINF!(V.vector4_f32[2]) { 0xFFFFFFFFu32 } else { 0 },
3018                if XMISINF!(V.vector4_f32[3]) { 0xFFFFFFFFu32 } else { 0 },
3019            ]
3020        };
3021        return Control.v;
3022    }
3023
3024    #[cfg(_XM_ARM_NEON_INTRINSICS_)]
3025    {
3026        unimplemented!()
3027    }
3028
3029    #[cfg(_XM_SSE_INTRINSICS_)]
3030    unsafe {
3031        // Mask off the sign bit
3032        let mut vTemp: __m128 = _mm_and_ps(V, g_XMAbsMask.v);
3033        // Compare to infinity
3034        vTemp = _mm_cmpeq_ps(vTemp, g_XMInfinity.v);
3035        // If any are infinity, the signs are true.
3036        return vTemp;
3037    }
3038}
3039
3040/// Makes a per-component comparison between two vectors, and returns a vector containing the smallest components.
3041///
3042/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVectorMin>
3043#[inline]
3044pub fn XMVectorMin(V1: FXMVECTOR, V2: FXMVECTOR) -> XMVECTOR {
3045    #[cfg(_XM_NO_INTRINSICS_)]
3046    unsafe {
3047        let Result = XMVECTORF32 {
3048            f: [
3049                if V1.vector4_f32[0] < V2.vector4_f32[0] { V1.vector4_f32[0] } else { V2.vector4_f32[0] },
3050                if V1.vector4_f32[1] < V2.vector4_f32[1] { V1.vector4_f32[1] } else { V2.vector4_f32[1] },
3051                if V1.vector4_f32[2] < V2.vector4_f32[2] { V1.vector4_f32[2] } else { V2.vector4_f32[2] },
3052                if V1.vector4_f32[3] < V2.vector4_f32[3] { V1.vector4_f32[3] } else { V2.vector4_f32[3] },
3053            ]
3054        };
3055        return Result.v;
3056    }
3057
3058    #[cfg(_XM_ARM_NEON_INTRINSICS_)]
3059    {
3060        unimplemented!()
3061    }
3062
3063    #[cfg(_XM_SSE_INTRINSICS_)]
3064    unsafe {
3065        return _mm_min_ps(V1, V2);
3066    }
3067}
3068
3069/// Makes a per-component comparison between two vectors, and returns a vector containing the largest components.
3070///
3071/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVectorMax>
3072#[inline]
3073pub fn XMVectorMax(V1: FXMVECTOR, V2: FXMVECTOR) -> XMVECTOR {
3074    #[cfg(_XM_NO_INTRINSICS_)]
3075    unsafe {
3076        let Result = XMVECTORF32 {
3077            f: [
3078                if V1.vector4_f32[0] > V2.vector4_f32[0] { V1.vector4_f32[0] } else { V2.vector4_f32[0] },
3079                if V1.vector4_f32[1] > V2.vector4_f32[1] { V1.vector4_f32[1] } else { V2.vector4_f32[1] },
3080                if V1.vector4_f32[2] > V2.vector4_f32[2] { V1.vector4_f32[2] } else { V2.vector4_f32[2] },
3081                if V1.vector4_f32[3] > V2.vector4_f32[3] { V1.vector4_f32[3] } else { V2.vector4_f32[3] },
3082            ]
3083        };
3084        return Result.v;
3085    }
3086
3087    #[cfg(_XM_ARM_NEON_INTRINSICS_)]
3088    {
3089        unimplemented!()
3090    }
3091
3092    #[cfg(_XM_SSE_INTRINSICS_)]
3093    unsafe {
3094        return _mm_max_ps(V1, V2);
3095    }
3096}
3097
3098// Round to nearest (even) a.k.a. banker's rounding
3099#[inline]
3100#[cfg(_XM_NO_INTRINSICS_)]
3101fn round_to_nearest(mut x: f32) -> f32 {
3102    let i = floorf(x);
3103    x -= i;
3104    if (x < 0.5) {
3105        return i;
3106    }
3107    if (x > 0.5) {
3108        return i + 1.0;
3109    }
3110
3111    let (_, int_part) = modff(i / 2.0);
3112    if ((2.0 * int_part) == i)
3113    {
3114        return i;
3115    }
3116
3117    return i + 1.0;
3118}
3119
3120#[test]
3121#[cfg(_XM_NO_INTRINSICS_)]
3122fn test_round_to_nearest() {
3123    assert_eq!(24.0, round_to_nearest(23.5));
3124    assert_eq!(24.0, round_to_nearest(24.5));
3125
3126    assert_eq!(-24.0, round_to_nearest(-23.5));
3127    assert_eq!(-24.0, round_to_nearest(-24.5));
3128}
3129
3130/// Rounds each component of a vector to the nearest even integer (known as "Bankers Rounding").
3131///
3132/// ## Parameters
3133///
3134/// `V` Vector whose components should be rounded.
3135///
3136/// ## Return value
3137///
3138/// Returns a vector, each of whose components are rounded to the nearest integer.
3139///
3140/// ## Remarks
3141///
3142/// Banker's Rounding is used because it is the native vector rounding intrinsic method for both SSE4 and
3143/// ARMv8 NEON.
3144///
3145/// ## Reference
3146///
3147/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVectorRound>
3148#[inline]
3149pub fn XMVectorRound(V: FXMVECTOR) -> XMVECTOR {
3150    #[cfg(_XM_NO_INTRINSICS_)]
3151    unsafe {
3152        let Result = XMVECTORF32 {
3153            f: [
3154                round_to_nearest(V.vector4_f32[0]),
3155                round_to_nearest(V.vector4_f32[0]),
3156                round_to_nearest(V.vector4_f32[0]),
3157                round_to_nearest(V.vector4_f32[0]),
3158            ]
3159        };
3160        return Result.v;
3161    }
3162
3163    #[cfg(_XM_ARM_NEON_INTRINSICS_)]
3164    {
3165        unimplemented!()
3166    }
3167
3168    #[cfg(_XM_SSE4_INTRINSICS_)]
3169    unsafe {
3170        return _mm_round_ps(V, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC);
3171    }
3172
3173    #[cfg(all(not(_XM_SSE4_INTRINSICS_), _XM_SSE_INTRINSICS_))]
3174    unsafe {
3175        let sign: __m128 = _mm_and_ps(V, g_XMNegativeZero.v);
3176        let sMagic: __m128 = _mm_or_ps(g_XMNoFraction.v, sign);
3177        let mut R1: __m128 = _mm_add_ps(V, sMagic);
3178        R1 = _mm_sub_ps(R1, sMagic);
3179        let mut R2:__m128 = _mm_and_ps(V, g_XMAbsMask.v);
3180        let mask: __m128 = _mm_cmple_ps(R2, g_XMNoFraction.v);
3181        R2 = _mm_andnot_ps(mask, V);
3182        R1 = _mm_and_ps(R1, mask);
3183        let vResult: XMVECTOR = _mm_xor_ps(R1, R2);
3184        return vResult;
3185    }
3186}
3187
3188/// Rounds each component of a vector to the nearest integer value in the direction of zero.
3189///
3190/// ## Parameters
3191///
3192/// `V` Vector whose components are to be truncated.
3193///
3194/// ## Return value
3195///
3196/// Returns a vector whose components are rounded to the nearest integer value in the direction of zero.
3197///
3198/// ## Remarks
3199///
3200/// The return value is computed based on the following logic, which preserves special values (INF,+INF,NaN,-NaN).
3201///
3202/// ```text
3203/// Result[0] = (fabsf(V[0]) < 8388608.0f) ? ((float)((int32_t)V[0])) : V[0];
3204/// Result[1] = (fabsf(V[1]) < 8388608.0f) ? ((float)((int32_t)V[1])) : V[1];
3205/// Result[2] = (fabsf(V[2]) < 8388608.0f) ? ((float)((int32_t)V[2])) : V[2];
3206/// Result[3] = (fabsf(V[3]) < 8388608.0f) ? ((float)((int32_t)V[3])) : V[3];
3207/// ```
3208///
3209/// ## Reference
3210///
3211/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVectorTruncate>
3212#[inline]
3213pub fn XMVectorTruncate(V: FXMVECTOR) -> XMVECTOR {
3214    #[cfg(_XM_NO_INTRINSICS_)]
3215    unsafe {
3216        let mut Result: XMVECTOR = crate::undefined();
3217
3218        for i in 0..4 {
3219            if (XMISNAN!(V.vector4_f32[i]))
3220            {
3221                Result.vector4_u32[i] = 0x7FC00000;
3222            }
3223            else if (fabsf(V.vector4_f32[i]) < 8388608.0)
3224            {
3225                Result.vector4_f32[i] = (V.vector4_f32[i] as i32) as f32;
3226            }
3227            else
3228            {
3229                Result.vector4_f32[i] = V.vector4_f32[i];
3230            }
3231        }
3232
3233        return Result;
3234    }
3235
3236    #[cfg(_XM_ARM_NEON_INTRINSICS_)]
3237    {
3238        unimplemented!()
3239    }
3240
3241    #[cfg(_XM_SSE4_INTRINSICS_)]
3242    unsafe {
3243        return _mm_round_ps(V, _MM_FROUND_TO_ZERO | _MM_FROUND_NO_EXC);
3244    }
3245
3246    #[cfg(all(not(_XM_SSE4_INTRINSICS_), _XM_SSE_INTRINSICS_))]
3247    unsafe {
3248        // To handle NAN, INF and numbers greater than 8388608, use masking
3249        // Get the abs value
3250        let mut vTest: __m128i  = _mm_and_si128(_mm_castps_si128(V), g_XMAbsMask.m128i());
3251        // Test for greater than 8388608 (All floats with NO fractionals, NAN and INF
3252        vTest = _mm_cmplt_epi32(vTest, g_XMNoFraction.m128i());
3253        // Convert to int and back to float for rounding with truncation
3254        let vInt: __m128i = _mm_cvttps_epi32(V);
3255        // Convert back to floats
3256        let mut vResult: XMVECTOR = _mm_cvtepi32_ps(vInt);
3257        // All numbers less than 8388608 will use the round to int
3258        vResult = _mm_and_ps(vResult, _mm_castsi128_ps(vTest));
3259        // All others, use the ORIGINAL value
3260        vTest = _mm_andnot_si128(vTest, _mm_castps_si128(V));
3261        vResult = _mm_or_ps(vResult, _mm_castsi128_ps(vTest));
3262        return vResult;
3263    }
3264}
3265
3266/// Computes the floor of each component of an XMVECTOR.
3267///
3268/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVectorFloor>
3269#[inline]
3270pub fn XMVectorFloor(V: FXMVECTOR) -> XMVECTOR {
3271    #[cfg(_XM_NO_INTRINSICS_)]
3272    unsafe {
3273        let Result = XMVECTORF32 {
3274            f: [
3275                floorf(V.vector4_f32[0]),
3276                floorf(V.vector4_f32[1]),
3277                floorf(V.vector4_f32[2]),
3278                floorf(V.vector4_f32[3])
3279            ]
3280        };
3281        return Result.v;
3282    }
3283
3284    #[cfg(_XM_ARM_NEON_INTRINSICS_)]
3285    {
3286        unimplemented!()
3287    }
3288
3289    #[cfg(_XM_SSE4_INTRINSICS_)]
3290    unsafe {
3291        return _mm_floor_ps(V);
3292    }
3293
3294    #[cfg(all(not(_XM_SSE4_INTRINSICS_), _XM_SSE_INTRINSICS_))]
3295    unsafe {
3296        // To handle NAN, INF and numbers greater than 8388608, use masking
3297        let mut vTest: __m128i = _mm_and_si128(_mm_castps_si128(V), g_XMAbsMask.m128i());
3298        vTest = _mm_cmplt_epi32(vTest, g_XMNoFraction.m128i());
3299        // Truncate
3300        let vInt: __m128i = _mm_cvttps_epi32(V);
3301        let mut vResult: XMVECTOR = _mm_cvtepi32_ps(vInt);
3302        let mut vLarger: __m128 = _mm_cmpgt_ps(vResult, V);
3303        // 0 -> 0, 0xffffffff -> -1.0f
3304        vLarger = _mm_cvtepi32_ps(_mm_castps_si128(vLarger));
3305        vResult = _mm_add_ps(vResult, vLarger);
3306        // All numbers less than 8388608 will use the round to int
3307        vResult = _mm_and_ps(vResult, _mm_castsi128_ps(vTest));
3308        // All others, use the ORIGINAL value
3309        vTest = _mm_andnot_si128(vTest, _mm_castps_si128(V));
3310        vResult = _mm_or_ps(vResult, _mm_castsi128_ps(vTest));
3311        return vResult;
3312    }
3313}
3314
3315/// Computes the ceiling of each component of an XMVECTOR.
3316///
3317/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVectorCeiling>
3318#[inline]
3319pub fn XMVectorCeiling(V: FXMVECTOR) -> XMVECTOR {
3320    #[cfg(_XM_NO_INTRINSICS_)]
3321    unsafe {
3322        let Result = XMVECTORF32 {
3323            f: [
3324                ceilf(V.vector4_f32[0]),
3325                ceilf(V.vector4_f32[1]),
3326                ceilf(V.vector4_f32[2]),
3327                ceilf(V.vector4_f32[3])
3328            ]
3329        };
3330        return Result.v;
3331    }
3332
3333    #[cfg(_XM_ARM_NEON_INTRINSICS_)]
3334    {
3335        unimplemented!()
3336    }
3337
3338    #[cfg(_XM_SSE4_INTRINSICS_)]
3339    unsafe {
3340        return _mm_ceil_ps(V);
3341    }
3342
3343    #[cfg(all(not(_XM_SSE4_INTRINSICS_), _XM_SSE_INTRINSICS_))]
3344    unsafe {
3345        // To handle NAN, INF and numbers greater than 8388608, use masking
3346        let mut vTest: __m128i = _mm_and_si128(_mm_castps_si128(V), g_XMAbsMask.m128i());
3347        vTest = _mm_cmplt_epi32(vTest, g_XMNoFraction.m128i());
3348        // Truncate
3349        let vInt: __m128i = _mm_cvttps_epi32(V);
3350        let mut vResult: XMVECTOR = _mm_cvtepi32_ps(vInt);
3351        let mut vSmaller: __m128 = _mm_cmplt_ps(vResult, V);
3352        // 0 -> 0, 0xffffffff -> -1.0f
3353        vSmaller = _mm_cvtepi32_ps(_mm_castps_si128(vSmaller));
3354        vResult = _mm_sub_ps(vResult, vSmaller);
3355        // All numbers less than 8388608 will use the round to int
3356        vResult = _mm_and_ps(vResult, _mm_castsi128_ps(vTest));
3357        // All others, use the ORIGINAL value
3358        vTest = _mm_andnot_si128(vTest, _mm_castps_si128(V));
3359        vResult = _mm_or_ps(vResult, _mm_castsi128_ps(vTest));
3360        return vResult;
3361    }
3362}
3363
3364/// Clamps the components of a vector to a specified minimum and maximum range.
3365///
3366/// ## Parameters
3367///
3368/// `V` Vector whose components are to be clamped.
3369///
3370/// `Min` Minimum range vector.
3371///
3372/// `Max` Maximum range vector.
3373///
3374/// ## Return value
3375///
3376/// Returns a vector whose components are clamped to the specified minimum and maximum values.
3377///
3378/// ## Remarks
3379///
3380/// The following pseudocode demonstrates the operation of the function:
3381///
3382/// ```text
3383/// XMVECTOR Result;
3384///
3385/// Result.x = min( max( V.x, Min.x ), Max.x );
3386/// Result.y = min( max( V.y, Min.y ), Max.y );
3387/// Result.z = min( max( V.z, Min.z ), Max.z );
3388/// Result.w = min( max( V.w, Min.w ), Max.w );
3389///
3390/// return Result;
3391/// ```
3392///
3393/// ## Reference
3394///
3395/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVectorClamp>
3396#[inline]
3397pub fn XMVectorClamp(
3398    V: FXMVECTOR,
3399    Min: FXMVECTOR,
3400    Max: FXMVECTOR
3401) -> XMVECTOR
3402{
3403    debug_assert!(XMVector4LessOrEqual(Min, Max));
3404
3405    #[cfg(_XM_NO_INTRINSICS_)]
3406    {
3407        let mut Result: XMVECTOR;
3408        Result = XMVectorMax(Min, V);
3409        Result = XMVectorMin(Max, Result);
3410        return Result;
3411    }
3412
3413    #[cfg(_XM_ARM_NEON_INTRINSICS_)]
3414    {
3415        unimplemented!()
3416    }
3417
3418    #[cfg(_XM_SSE_INTRINSICS_)]
3419    unsafe {
3420        let mut vResult: XMVECTOR;
3421        vResult = _mm_max_ps(Min, V);
3422        vResult = _mm_min_ps(Max, vResult);
3423        return vResult;
3424    }
3425}
3426
3427/// Saturates each component of a vector to the range 0.0f to 1.0f.
3428///
3429/// ## Parameters
3430///
3431/// `V` Vector to saturate.
3432///
3433/// ## Return value
3434///
3435/// Returns a vector, each of whose components are saturated.
3436///
3437/// ## Remarks
3438///
3439/// The following pseudocode demonstrates the operation of the function:
3440///
3441/// ```text
3442/// XMVECTOR Result;
3443///
3444/// Result.x = min(max(V1.x, 0.0f), 1.0f);
3445/// Result.y = min(max(V1.y, 0.0f), 1.0f);
3446/// Result.z = min(max(V1.z, 0.0f), 1.0f);
3447/// Result.w = min(max(V1.w, 0.0f), 1.0f);
3448///
3449/// return Result;
3450/// ```
3451///
3452/// ## Reference
3453///
3454/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVectorSaturate>
3455#[inline]
3456pub fn XMVectorSaturate(
3457    V: FXMVECTOR,
3458) -> XMVECTOR
3459{
3460    #[cfg(_XM_NO_INTRINSICS_)]
3461    unsafe {
3462        // const XMVECTOR Zero = XMVectorZero();
3463        return XMVectorClamp(V, g_XMZero.v, g_XMOne.v);
3464    }
3465
3466    #[cfg(_XM_ARM_NEON_INTRINSICS_)]
3467    {
3468        unimplemented!()
3469    }
3470
3471    #[cfg(_XM_SSE_INTRINSICS_)]
3472    unsafe {
3473        // Set <0 to 0
3474        let vResult: XMVECTOR = _mm_max_ps(V, g_XMZero.v);
3475        // Set>1 to 1
3476        return _mm_min_ps(vResult, g_XMOne.v);
3477    }
3478}
3479
3480/// Computes the logical AND of two vectors, treating each component as an unsigned integer.
3481///
3482/// ## Parameters
3483///
3484/// `V1` First vector.
3485///
3486/// `V2` Second vector.
3487///
3488/// ## Return value
3489///
3490/// Returns a vector each of whose components are the logical AND of the corresponding components of V1
3491/// and V2.
3492///
3493/// ## Remarks
3494///
3495/// The following pseudocode demonstrates the operation of the function:
3496///
3497/// ```text
3498/// XMVECTOR Result;
3499///
3500/// Result.x = V1.x & V2.x;
3501/// Result.y = V1.y & V2.y;
3502/// Result.z = V1.z & V2.z;
3503/// Result.w = V1.w & V2.w;
3504///
3505/// return Result;
3506/// ```
3507///
3508/// ## Reference
3509///
3510/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVectorAndInt>
3511#[inline]
3512pub fn XMVectorAndInt(
3513    V1: FXMVECTOR,
3514    V2: FXMVECTOR,
3515) -> XMVECTOR
3516{
3517    #[cfg(_XM_NO_INTRINSICS_)]
3518    unsafe {
3519        let Result = XMVECTORU32 {
3520            u: [
3521                V1.vector4_u32[0] & V2.vector4_u32[0],
3522                V1.vector4_u32[1] & V2.vector4_u32[1],
3523                V1.vector4_u32[2] & V2.vector4_u32[2],
3524                V1.vector4_u32[3] & V2.vector4_u32[3]
3525            ]
3526        };
3527        return Result.v;
3528    }
3529
3530    #[cfg(_XM_ARM_NEON_INTRINSICS_)]
3531    {
3532        unimplemented!()
3533    }
3534
3535    #[cfg(_XM_SSE_INTRINSICS_)]
3536    unsafe {
3537        return _mm_and_ps(V1, V2);
3538    }
3539}
3540
3541/// Computes the logical AND of one vector with the negation of a second vector, treating each component as an unsigned integer.
3542///
3543/// ## Parameters
3544///
3545/// `V1` First vector.
3546///
3547/// `V2` Second vector.
3548///
3549/// ## Return value
3550///
3551/// Returns a vector whose components are the logical AND of each of the components of `V1` with the negation
3552/// of the corresponding components of V2.
3553///
3554/// ## Remarks
3555///
3556/// The following pseudocode demonstrates the operation of the function:
3557///
3558/// ```text
3559/// XMVECTOR Result;
3560///
3561/// Result.x = V1.x & ~V2.x;
3562/// Result.y = V1.y & ~V2.y;
3563/// Result.z = V1.z & ~V2.z;
3564/// Result.w = V1.w & ~V2.w;
3565///
3566/// return Result;
3567/// ```
3568///
3569/// ## Reference
3570///
3571/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVectorAndCInt>
3572#[inline]
3573pub fn XMVectorAndCInt(
3574    V1: FXMVECTOR,
3575    V2: FXMVECTOR,
3576) -> XMVECTOR
3577{
3578    #[cfg(_XM_NO_INTRINSICS_)]
3579    unsafe {
3580        let Result = XMVECTORU32 {
3581            u: [
3582                V1.vector4_u32[0] & !V2.vector4_u32[0],
3583                V1.vector4_u32[1] & !V2.vector4_u32[1],
3584                V1.vector4_u32[2] & !V2.vector4_u32[2],
3585                V1.vector4_u32[3] & !V2.vector4_u32[3]
3586            ]
3587        };
3588        return Result.v;
3589    }
3590
3591    #[cfg(_XM_ARM_NEON_INTRINSICS_)]
3592    {
3593        unimplemented!()
3594    }
3595
3596    #[cfg(_XM_SSE_INTRINSICS_)]
3597    unsafe {
3598        let V: __m128i = _mm_andnot_si128(_mm_castps_si128(V2), _mm_castps_si128(V1));
3599        return _mm_castsi128_ps(V);
3600    }
3601}
3602
3603/// Computes the logical OR of two vectors, treating each component as an unsigned integer.
3604///
3605/// ## Parameters
3606///
3607/// `V1` First vector.
3608///
3609/// `V2` Second vector.
3610///
3611/// ## Return value
3612///
3613/// Returns a vector, each of whose components are the logical OR of the corresponding components of V1
3614/// and V2.
3615///
3616/// ## Remarks
3617///
3618/// The following pseudocode demonstrates the operation of the function:
3619///
3620/// ```text
3621/// XMVECTOR Result;
3622///
3623/// Result.x = V1.x | V2.x;
3624/// Result.y = V1.y | V2.y;
3625/// Result.z = V1.z | V2.z;
3626/// Result.w = V1.w | V2.w;
3627///
3628/// return Result;
3629/// ```
3630///
3631/// ## Reference
3632///
3633/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVectorOrInt>
3634#[inline]
3635pub fn XMVectorOrInt(
3636    V1: FXMVECTOR,
3637    V2: FXMVECTOR,
3638) -> XMVECTOR
3639{
3640    #[cfg(_XM_NO_INTRINSICS_)]
3641    unsafe {
3642        let Result = XMVECTORU32 {
3643            u: [
3644                V1.vector4_u32[0] | V2.vector4_u32[0],
3645                V1.vector4_u32[1] | V2.vector4_u32[1],
3646                V1.vector4_u32[2] | V2.vector4_u32[2],
3647                V1.vector4_u32[3] | V2.vector4_u32[3]
3648            ]
3649        };
3650        return Result.v;
3651    }
3652
3653    #[cfg(_XM_ARM_NEON_INTRINSICS_)]
3654    {
3655        unimplemented!()
3656    }
3657
3658    #[cfg(_XM_SSE_INTRINSICS_)]
3659    unsafe {
3660        let V: __m128i = _mm_or_si128(_mm_castps_si128(V1), _mm_castps_si128(V2));
3661        return _mm_castsi128_ps(V);
3662    }
3663}
3664
3665/// Computes the logical NOR of two vectors, treating each component as an unsigned integer.
3666///
3667/// ## Parameters
3668///
3669/// `V1` First vector.
3670///
3671/// `V2` Second vector.
3672///
3673/// ## Return value
3674///
3675/// Returns a vector, each of whose components are the logical NOR of the corresponding components of V1
3676/// and V2.
3677///
3678/// ## Remarks
3679///
3680/// The following pseudocode demonstrates the operation of the function:
3681///
3682/// ```text
3683/// XMVECTOR Result;
3684///
3685/// Result.x = ~(V1.x | V2.x);
3686/// Result.y = ~(V1.y | V2.y);
3687/// Result.z = ~(V1.z | V2.z);
3688/// Result.w = ~(V1.w | V2.w);
3689///
3690/// return Result;
3691/// ```
3692///
3693/// ## Reference
3694///
3695/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVectorNorInt>
3696#[inline]
3697pub fn XMVectorNorInt(
3698    V1: FXMVECTOR,
3699    V2: FXMVECTOR,
3700) -> XMVECTOR
3701{
3702    #[cfg(_XM_NO_INTRINSICS_)]
3703    unsafe {
3704        let Result = XMVECTORU32 {
3705            u: [
3706                !(V1.vector4_u32[0] | V2.vector4_u32[0]),
3707                !(V1.vector4_u32[1] | V2.vector4_u32[1]),
3708                !(V1.vector4_u32[2] | V2.vector4_u32[2]),
3709                !(V1.vector4_u32[3] | V2.vector4_u32[3])
3710            ]
3711        };
3712        return Result.v;
3713    }
3714
3715    #[cfg(_XM_ARM_NEON_INTRINSICS_)]
3716    {
3717        unimplemented!()
3718    }
3719
3720    #[cfg(_XM_SSE_INTRINSICS_)]
3721    unsafe {
3722        let mut Result: __m128i;
3723        Result = _mm_or_si128(_mm_castps_si128(V1), _mm_castps_si128(V2));
3724        Result = _mm_andnot_si128(Result, g_XMNegOneMask.m128i());
3725        return _mm_castsi128_ps(Result);
3726    }
3727}
3728
3729/// Computes the logical XOR of two vectors, treating each component as an unsigned integer.
3730///
3731/// ## Parameters
3732///
3733/// `V1` First vector.
3734///
3735/// `V2` Second vector.
3736///
3737/// ## Return value
3738///
3739/// Returns a vector, each of whose components are the logical XOR of the corresponding components of V1
3740/// and V2.
3741///
3742/// ## Remarks
3743///
3744/// The following pseudocode demonstrates the operation of the function:
3745///
3746/// ```text
3747/// XMVECTOR Result;
3748///
3749/// Result.x = V1.x ^ V2.x;
3750/// Result.y = V1.y ^ V2.y;
3751/// Result.z = V1.z ^ V2.z;
3752/// Result.w = V1.w ^ V2.w;
3753///
3754/// return Result;
3755/// ```
3756///
3757/// ## Reference
3758///
3759/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVectorXorInt>
3760#[inline]
3761pub fn XMVectorXorInt(
3762    V1: FXMVECTOR,
3763    V2: FXMVECTOR,
3764) -> XMVECTOR
3765{
3766    #[cfg(_XM_NO_INTRINSICS_)]
3767    unsafe {
3768        let Result = XMVECTORU32 {
3769            u: [
3770                V1.vector4_u32[0] ^ V2.vector4_u32[0],
3771                V1.vector4_u32[1] ^ V2.vector4_u32[1],
3772                V1.vector4_u32[2] ^ V2.vector4_u32[2],
3773                V1.vector4_u32[3] ^ V2.vector4_u32[3]
3774            ]
3775        };
3776        return Result.v;
3777    }
3778
3779    #[cfg(_XM_ARM_NEON_INTRINSICS_)]
3780    {
3781        unimplemented!()
3782    }
3783
3784    #[cfg(_XM_SSE_INTRINSICS_)]
3785    unsafe {
3786        let V: __m128i = _mm_xor_si128(_mm_castps_si128(V1), _mm_castps_si128(V2));
3787        return _mm_castsi128_ps(V);
3788    }
3789}
3790
3791/// Computes the negation of a vector.
3792///
3793/// ## Parameters
3794///
3795/// `V` Vector to negate.
3796///
3797/// ## Return value
3798///
3799/// Returns the negation of the vector.
3800///
3801/// ## Remarks
3802///
3803/// The following pseudocode demonstrates the operation of the function:
3804///
3805/// ```text
3806/// XMVECTOR result;
3807///
3808/// result.x = -V.x;
3809/// result.y = -V.y;
3810/// result.z = -V.z;
3811/// result.w = -V.w;
3812///
3813/// return result;
3814/// ```
3815///
3816/// ## Reference
3817///
3818/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVectorNegate>
3819#[inline]
3820pub fn XMVectorNegate(
3821    V: FXMVECTOR,
3822) -> XMVECTOR
3823{
3824    #[cfg(_XM_NO_INTRINSICS_)]
3825    unsafe {
3826        let Result = XMVECTORF32 {
3827            f: [
3828                -V.vector4_f32[0],
3829                -V.vector4_f32[1],
3830                -V.vector4_f32[2],
3831                -V.vector4_f32[3]
3832            ]
3833        };
3834        return Result.v;
3835    }
3836
3837    #[cfg(_XM_ARM_NEON_INTRINSICS_)]
3838    {
3839        unimplemented!()
3840    }
3841
3842    #[cfg(_XM_SSE_INTRINSICS_)]
3843    unsafe {
3844        let Z: XMVECTOR;
3845
3846        Z = _mm_setzero_ps();
3847
3848        return _mm_sub_ps(Z, V);
3849    }
3850}
3851
3852/// Computes the sum of two vectors.
3853///
3854/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVectorAdd>
3855#[inline]
3856pub fn XMVectorAdd(
3857    V1: FXMVECTOR,
3858    V2: FXMVECTOR
3859) -> XMVECTOR
3860{
3861    #[cfg(_XM_NO_INTRINSICS_)]
3862    unsafe {
3863        let Result = XMVECTORF32 {
3864            f: [
3865                V1.vector4_f32[0] + V2.vector4_f32[0],
3866                V1.vector4_f32[1] + V2.vector4_f32[1],
3867                V1.vector4_f32[2] + V2.vector4_f32[2],
3868                V1.vector4_f32[3] + V2.vector4_f32[3]
3869            ]
3870        };
3871        return Result.v;
3872    }
3873
3874    #[cfg(_XM_ARM_NEON_INTRINSICS_)]
3875    {
3876        unimplemented!()
3877    }
3878
3879    #[cfg(_XM_SSE_INTRINSICS_)]
3880    unsafe {
3881        return _mm_add_ps(V1, V2);
3882    }
3883}
3884
3885/// Computes the horizontal sum of the components of an XMVECTOR.
3886/// The horizontal sum is the result of adding each component in
3887/// the vector together.
3888///
3889/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVectorSum>
3890#[inline]
3891pub fn XMVectorSum(
3892    V: FXMVECTOR,
3893) -> XMVECTOR
3894{
3895    #[cfg(_XM_NO_INTRINSICS_)]
3896    unsafe {
3897        let sum = V.vector4_f32[0] + V.vector4_f32[1] + V.vector4_f32[2] + V.vector4_f32[3];
3898        let Result = XMVECTORF32 {
3899            f: [ sum, sum, sum, sum ]
3900        };
3901        return Result.v;
3902    }
3903
3904    #[cfg(_XM_ARM_NEON_INTRINSICS_)]
3905    {
3906        unimplemented!()
3907    }
3908
3909    #[cfg(_XM_SSE3_INTRINSICS_)]
3910    unsafe {
3911        let vTemp: XMVECTOR = _mm_hadd_ps(V, V);
3912        return _mm_hadd_ps(vTemp, vTemp);
3913    }
3914
3915    #[cfg(all(_XM_SSE_INTRINSICS_, not(_XM_SSE3_INTRINSICS_)))]
3916    unsafe {
3917        let mut vTemp: XMVECTOR = XM_PERMUTE_PS!(V, _MM_SHUFFLE(2, 3, 0, 1));
3918        let vTemp2: XMVECTOR = _mm_add_ps(V, vTemp);
3919        vTemp = XM_PERMUTE_PS!(vTemp2, _MM_SHUFFLE(1, 0, 3, 2));
3920        return _mm_add_ps(vTemp, vTemp2);
3921    }
3922}
3923
3924/// Adds two vectors representing angles.
3925///
3926/// ## Parameters
3927///
3928/// `V1` First vector of angles. Each angle must satisfy `-XM_PI` <= `V1` < `XM_PI`.
3929///
3930/// `V2` Second vector of angles. Each angle must satisfy -XM_2PI <= `V1` < `XM_2PI`.
3931///
3932/// ## Return value
3933///
3934/// Returns a vector whose components are the sums of the angles of the corresponding components. Each component
3935/// of the returned vector will be an angle less than `XM_PI` and greater than or equal to `-XM_PI`.
3936///
3937/// ## Reference
3938///
3939/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVectorAddAngles>
3940#[inline]
3941pub fn XMVectorAddAngles(
3942    V1: FXMVECTOR,
3943    V2: FXMVECTOR
3944) -> XMVECTOR
3945{
3946    #[cfg(_XM_NO_INTRINSICS_)]
3947    unsafe {
3948        //const XMVECTOR Zero = XMVectorZero();
3949        const Zero: XMVECTOR = unsafe { g_XMZero.v };
3950
3951        // Add the given angles together.  If the range of V1 is such
3952        // that -Pi <= V1 < Pi and the range of V2 is such that
3953        // -2Pi <= V2 <= 2Pi, then the range of the resulting angle
3954        // will be -Pi <= Result < Pi.
3955        let mut Result: XMVECTOR = XMVectorAdd(V1, V2);
3956
3957        let mut Mask: XMVECTOR = XMVectorLess(Result, g_XMNegativePi.v);
3958        let mut Offset: XMVECTOR = XMVectorSelect(Zero, g_XMTwoPi.v, Mask);
3959
3960        Mask = XMVectorGreaterOrEqual(Result, g_XMPi.v);
3961        Offset = XMVectorSelect(Offset, g_XMNegativeTwoPi.v, Mask);
3962
3963        Result = XMVectorAdd(Result, Offset);
3964
3965        return Result;
3966    }
3967
3968    #[cfg(_XM_ARM_NEON_INTRINSICS_)]
3969    {
3970        unimplemented!()
3971    }
3972
3973    #[cfg(_XM_SSE_INTRINSICS_)]
3974    unsafe {
3975        // Adjust the angles
3976        let mut vResult: XMVECTOR = _mm_add_ps(V1, V2);
3977        // Less than Pi?
3978        let mut vOffset: XMVECTOR = _mm_cmplt_ps(vResult, g_XMNegativePi.v);
3979        vOffset = _mm_and_ps(vOffset, g_XMTwoPi.v);
3980        // Add 2Pi to all entries less than -Pi
3981        vResult = _mm_add_ps(vResult, vOffset);
3982        // Greater than or equal to Pi?
3983        vOffset = _mm_cmpge_ps(vResult, g_XMPi.v);
3984        vOffset = _mm_and_ps(vOffset, g_XMTwoPi.v);
3985        // Sub 2Pi to all entries greater than Pi
3986        vResult = _mm_sub_ps(vResult, vOffset);
3987        return vResult;
3988    }
3989}
3990
3991/// Computes the difference of two vectors.
3992///
3993/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVectorSubtract>
3994#[inline]
3995pub fn XMVectorSubtract(
3996    V1: FXMVECTOR,
3997    V2: FXMVECTOR
3998) -> XMVECTOR
3999{
4000    #[cfg(_XM_NO_INTRINSICS_)]
4001    unsafe {
4002        let Result = XMVECTORF32 {
4003            f: [
4004                V1.vector4_f32[0] - V2.vector4_f32[0],
4005                V1.vector4_f32[1] - V2.vector4_f32[1],
4006                V1.vector4_f32[2] - V2.vector4_f32[2],
4007                V1.vector4_f32[3] - V2.vector4_f32[3]
4008            ]
4009        };
4010        return Result.v;
4011    }
4012
4013    #[cfg(_XM_ARM_NEON_INTRINSICS_)]
4014    {
4015        unimplemented!()
4016    }
4017
4018    #[cfg(_XM_SSE_INTRINSICS_)]
4019    unsafe {
4020        return _mm_sub_ps(V1, V2);
4021    }
4022}
4023
4024/// Subtracts two vectors representing angles.
4025///
4026/// ## Parameters
4027///
4028/// `V1` First vector of angles. Each angle must satisfy `-XM_PI` <= `V1` < `XM_PI`.
4029///
4030/// `V2` Second vector of angles. Each angle must satisfy `-XM_2PI` <= `V1` < `XM_2PI`.
4031///
4032/// ## Return value
4033///
4034/// Returns a vector whose components are the differences of the angles of the corresponding components.
4035/// Each component of the returned vector will be an angle less than `XM_PI` and greater than or equal to
4036/// `-XM_PI`.
4037///
4038/// ## Reference
4039///
4040/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVectorSubtractAngles>
4041#[inline]
4042pub fn XMVectorSubtractAngles(
4043    V1: FXMVECTOR,
4044    V2: FXMVECTOR
4045) -> XMVECTOR
4046{
4047    #[cfg(_XM_NO_INTRINSICS_)]
4048    unsafe {
4049        //const XMVECTOR Zero = XMVectorZero();
4050        const Zero: XMVECTOR = unsafe { g_XMZero.v };
4051
4052        // Subtract the given angles.  If the range of V1 is such
4053        // that -Pi <= V1 < Pi and the range of V2 is such that
4054        // -2Pi <= V2 <= 2Pi, then the range of the resulting angle
4055        // will be -Pi <= Result < Pi.
4056        let mut Result: XMVECTOR = XMVectorSubtract(V1, V2);
4057
4058        let mut Mask: XMVECTOR = XMVectorLess(Result, g_XMNegativePi.v);
4059        let mut Offset: XMVECTOR = XMVectorSelect(Zero, g_XMTwoPi.v, Mask);
4060
4061        Mask = XMVectorGreaterOrEqual(Result, g_XMPi.v);
4062        Offset = XMVectorSelect(Offset, g_XMNegativeTwoPi.v, Mask);
4063
4064        Result = XMVectorAdd(Result, Offset);
4065
4066        return Result;
4067    }
4068
4069    #[cfg(_XM_ARM_NEON_INTRINSICS_)]
4070    {
4071        unimplemented!()
4072    }
4073
4074    #[cfg(_XM_SSE_INTRINSICS_)]
4075    unsafe {
4076        // Adjust the angles
4077        let mut vResult: XMVECTOR = _mm_sub_ps(V1, V2);
4078        // Less than Pi?
4079        let mut vOffset: XMVECTOR = _mm_cmplt_ps(vResult, g_XMNegativePi.v);
4080        vOffset = _mm_and_ps(vOffset, g_XMTwoPi.v);
4081        // Add 2Pi to all entries less than -Pi
4082        vResult = _mm_add_ps(vResult, vOffset);
4083        // Greater than or equal to Pi?
4084        vOffset = _mm_cmpge_ps(vResult, g_XMPi.v);
4085        vOffset = _mm_and_ps(vOffset, g_XMTwoPi.v);
4086        // Sub 2Pi to all entries greater than Pi
4087        vResult = _mm_sub_ps(vResult, vOffset);
4088        return vResult;
4089    }
4090}
4091
4092
4093/// Computes the per-component product of two vectors.
4094///
4095/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVectorMultiply>
4096#[inline]
4097pub fn XMVectorMultiply(
4098    V1: FXMVECTOR,
4099    V2: FXMVECTOR
4100) -> XMVECTOR
4101{
4102    #[cfg(_XM_NO_INTRINSICS_)]
4103    unsafe {
4104        let Result = XMVECTORF32 {
4105            f: [
4106                V1.vector4_f32[0] * V2.vector4_f32[0],
4107                V1.vector4_f32[1] * V2.vector4_f32[1],
4108                V1.vector4_f32[2] * V2.vector4_f32[2],
4109                V1.vector4_f32[3] * V2.vector4_f32[3]
4110            ]
4111        };
4112        return Result.v;
4113    }
4114
4115    #[cfg(_XM_ARM_NEON_INTRINSICS_)]
4116    {
4117        unimplemented!()
4118    }
4119
4120    #[cfg(_XM_SSE_INTRINSICS_)]
4121    unsafe {
4122        return _mm_mul_ps(V1, V2);
4123    }
4124}
4125
4126/// Computes the product of the first two vectors added to the third vector.
4127///
4128/// ## Parameters
4129///
4130/// `V1` Vector multiplier.
4131///
4132/// `V2` Vector multiplicand.
4133///
4134/// `V3` Vector addend.
4135///
4136/// ## Return value
4137///
4138/// Returns the product-sum of the vectors.
4139///
4140/// ## Remarks
4141///
4142/// The following pseudocode demonstrates the operation of the function:
4143///
4144/// ```text
4145/// XMVECTOR Result;
4146///
4147/// Result.x = V1.x * V2.x + V3.x;
4148/// Result.y = V1.y * V2.y + V3.y;
4149/// Result.z = V1.z * V2.z + V3.z;
4150/// Result.w = V1.w * V2.w + V3.w;
4151///
4152/// return Result;
4153/// ```
4154///
4155/// ## Reference
4156///
4157/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVectorMultiplyAdd>
4158#[inline]
4159pub fn XMVectorMultiplyAdd(
4160    V1: FXMVECTOR,
4161    V2: FXMVECTOR,
4162    V3: FXMVECTOR
4163) -> XMVECTOR
4164{
4165    #[cfg(_XM_NO_INTRINSICS_)]
4166    unsafe {
4167        let Result = XMVECTORF32 {
4168            f: [
4169                V1.vector4_f32[0] * V2.vector4_f32[0] + V3.vector4_f32[0],
4170                V1.vector4_f32[1] * V2.vector4_f32[1] + V3.vector4_f32[1],
4171                V1.vector4_f32[2] * V2.vector4_f32[2] + V3.vector4_f32[2],
4172                V1.vector4_f32[3] * V2.vector4_f32[3] + V3.vector4_f32[3]
4173            ]
4174        };
4175        return Result.v;
4176    }
4177
4178    #[cfg(_XM_ARM_NEON_INTRINSICS_)]
4179    {
4180        unimplemented!()
4181    }
4182
4183    #[cfg(_XM_SSE_INTRINSICS_)]
4184    unsafe {
4185        return XM_FMADD_PS!(V1, V2, V3);
4186    }
4187}
4188
4189/// Divides one instance of XMVECTOR by a second instance, returning the result in a third instance.
4190///
4191/// ## Parameters
4192///
4193/// `V1` XMVECTOR instance whose components are the dividends of the division operation.
4194///
4195/// `V2` XMVECTOR instance whose components are the divisors of the division operation.
4196///
4197/// ## Return value
4198///
4199/// XMVECTOR instance whose components are the quotient of the division of each component of `V1` by each
4200/// corresponding component of V2.
4201///
4202/// ## Remarks
4203///
4204/// The following code is generally faster than calling XMVectorDivide if the loss of precision is tolerable.
4205///
4206/// ```text
4207/// XMVECTOR R = XMVectorReciprocalEst(V2)
4208/// XMVectorMultiply(V1,R)
4209/// ```
4210///
4211/// ## Reference
4212///
4213/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVectorDivide>
4214#[inline]
4215pub fn XMVectorDivide(
4216    V1: FXMVECTOR,
4217    V2: FXMVECTOR
4218) -> XMVECTOR
4219{
4220    #[cfg(_XM_NO_INTRINSICS_)]
4221    unsafe {
4222        let Result = XMVECTORF32 {
4223            f: [
4224                V1.vector4_f32[0] / V2.vector4_f32[0],
4225                V1.vector4_f32[1] / V2.vector4_f32[1],
4226                V1.vector4_f32[2] / V2.vector4_f32[2],
4227                V1.vector4_f32[3] / V2.vector4_f32[3]
4228            ]
4229        };
4230        return Result.v;
4231    }
4232
4233    #[cfg(_XM_ARM_NEON_INTRINSICS_)]
4234    {
4235        unimplemented!()
4236    }
4237
4238    #[cfg(_XM_SSE_INTRINSICS_)]
4239    unsafe {
4240        return _mm_div_ps(V1, V2);
4241    }
4242}
4243
4244/// Computes the difference of a third vector and the product of the first two vectors.
4245///
4246/// ## Parameters
4247///
4248/// `V1` Vector multiplier.
4249///
4250/// `V2` Vector multiplicand.
4251///
4252/// `V3` Vector subtrahend.
4253///
4254/// ## Return value
4255///
4256/// Returns the resulting vector. See the remarks.
4257///
4258/// ## Remarks
4259///
4260/// The following pseudocode demonstrates the operation of the function:
4261///
4262/// ```text
4263/// XMVECTOR result;
4264///
4265/// result.x = V3.x - V1.x * V2.x;
4266/// result.y = V3.y - V1.y * V2.y;
4267/// result.z = V3.z - V1.z * V2.z;
4268/// result.w = V3.w - V1.w * V2.w;
4269///
4270/// return result;
4271/// ```
4272///
4273/// ## Reference
4274///
4275/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVectorNegativeMultiplySubtract>
4276#[inline]
4277pub fn XMVectorNegativeMultiplySubtract(
4278    V1: FXMVECTOR,
4279    V2: FXMVECTOR,
4280    V3: FXMVECTOR
4281) -> XMVECTOR
4282{
4283    #[cfg(_XM_NO_INTRINSICS_)]
4284    unsafe {
4285        let Result = XMVECTORF32 {
4286            f: [
4287                V3.vector4_f32[0] - (V1.vector4_f32[0] * V2.vector4_f32[0]),
4288                V3.vector4_f32[1] - (V1.vector4_f32[1] * V2.vector4_f32[1]),
4289                V3.vector4_f32[2] - (V1.vector4_f32[2] * V2.vector4_f32[2]),
4290                V3.vector4_f32[3] - (V1.vector4_f32[3] * V2.vector4_f32[3])
4291            ]
4292        };
4293        return Result.v;
4294    }
4295
4296    #[cfg(_XM_ARM_NEON_INTRINSICS_)]
4297    {
4298        unimplemented!()
4299    }
4300
4301    #[cfg(_XM_SSE_INTRINSICS_)]
4302    unsafe {
4303        return XM_FNMADD_PS!(V1, V2, V3);
4304    }
4305}
4306
4307/// Scalar multiplies a vector by a floating-point value.
4308///
4309/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVectorScale>
4310#[inline]
4311pub fn XMVectorScale(
4312    V: FXMVECTOR,
4313    ScaleFactor: f32,
4314) -> XMVECTOR
4315{
4316    #[cfg(_XM_NO_INTRINSICS_)]
4317    unsafe {
4318        let Result = XMVECTORF32 {
4319            f: [
4320                V.vector4_f32[0] * ScaleFactor,
4321                V.vector4_f32[1] * ScaleFactor,
4322                V.vector4_f32[2] * ScaleFactor,
4323                V.vector4_f32[3] * ScaleFactor
4324            ]
4325        };
4326        return Result.v;
4327    }
4328
4329    #[cfg(_XM_ARM_NEON_INTRINSICS_)]
4330    {
4331        unimplemented!()
4332    }
4333
4334    #[cfg(_XM_SSE_INTRINSICS_)]
4335    unsafe {
4336        let vResult: XMVECTOR = _mm_set_ps1(ScaleFactor);
4337        return _mm_mul_ps(vResult, V);
4338    }
4339}
4340
4341/// Estimates the per-component reciprocal of a vector.
4342///
4343/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVectorReciprocalEst>
4344#[inline]
4345pub fn XMVectorReciprocalEst(
4346    V: FXMVECTOR,
4347) -> XMVECTOR
4348{
4349    #[cfg(_XM_NO_INTRINSICS_)]
4350    unsafe {
4351        let Result = XMVECTORF32 {
4352            f: [
4353                1.0 / V.vector4_f32[0],
4354                1.0 / V.vector4_f32[1],
4355                1.0 / V.vector4_f32[2],
4356                1.0 / V.vector4_f32[3]
4357            ]
4358        };
4359        return Result.v;
4360    }
4361
4362    #[cfg(_XM_ARM_NEON_INTRINSICS_)]
4363    {
4364        unimplemented!()
4365    }
4366
4367    #[cfg(_XM_SSE_INTRINSICS_)]
4368    unsafe {
4369        return _mm_rcp_ps(V);
4370    }
4371}
4372
4373/// Estimates the per-component reciprocal of a vector.
4374///
4375/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVectorReciprocal>
4376#[inline]
4377pub fn XMVectorReciprocal(
4378    V: FXMVECTOR,
4379) -> XMVECTOR
4380{
4381    #[cfg(_XM_NO_INTRINSICS_)]
4382    unsafe {
4383        let Result = XMVECTORF32 {
4384            f: [
4385                1.0 / V.vector4_f32[0],
4386                1.0 / V.vector4_f32[1],
4387                1.0 / V.vector4_f32[2],
4388                1.0 / V.vector4_f32[3]
4389            ]
4390        };
4391        return Result.v;
4392    }
4393
4394    #[cfg(_XM_ARM_NEON_INTRINSICS_)]
4395    {
4396        unimplemented!()
4397    }
4398
4399    #[cfg(_XM_SSE_INTRINSICS_)]
4400    unsafe {
4401        return _mm_div_ps(g_XMOne.v, V);
4402    }
4403}
4404
4405/// Estimates the per-component square root of a vector.
4406///
4407/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVectorSqrtEst>
4408#[inline]
4409pub fn XMVectorSqrtEst(
4410    V: FXMVECTOR,
4411) -> XMVECTOR
4412{
4413    #[cfg(_XM_NO_INTRINSICS_)]
4414    unsafe {
4415        let Result = XMVECTORF32 {
4416            f: [
4417                sqrtf(V.vector4_f32[0]),
4418                sqrtf(V.vector4_f32[1]),
4419                sqrtf(V.vector4_f32[2]),
4420                sqrtf(V.vector4_f32[3])
4421            ]
4422        };
4423        return Result.v;
4424    }
4425
4426    #[cfg(_XM_ARM_NEON_INTRINSICS_)]
4427    {
4428        unimplemented!()
4429    }
4430
4431    #[cfg(_XM_SSE_INTRINSICS_)]
4432    unsafe {
4433        return _mm_sqrt_ps(V);
4434    }
4435}
4436
4437/// Computes the per-component square root of a vector.
4438///
4439/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVectorSqrt>
4440#[inline]
4441pub fn XMVectorSqrt(
4442    V: FXMVECTOR,
4443) -> XMVECTOR
4444{
4445    #[cfg(_XM_NO_INTRINSICS_)]
4446    unsafe {
4447        let Result = XMVECTORF32 {
4448            f: [
4449                sqrtf(V.vector4_f32[0]),
4450                sqrtf(V.vector4_f32[1]),
4451                sqrtf(V.vector4_f32[2]),
4452                sqrtf(V.vector4_f32[3])
4453            ]
4454        };
4455        return Result.v;
4456    }
4457
4458    #[cfg(_XM_ARM_NEON_INTRINSICS_)]
4459    {
4460        unimplemented!()
4461    }
4462
4463    #[cfg(_XM_SSE_INTRINSICS_)]
4464    unsafe {
4465        return _mm_sqrt_ps(V);
4466    }
4467}
4468
4469/// Estimates the per-component reciprocal square root of a vector.
4470///
4471/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVectorReciprocalSqrtEst>
4472#[inline]
4473pub fn XMVectorReciprocalSqrtEst(
4474    V: FXMVECTOR,
4475) -> XMVECTOR
4476{
4477    #[cfg(_XM_NO_INTRINSICS_)]
4478    unsafe {
4479        let Result = XMVECTORF32 {
4480            f: [
4481                1.0 / sqrtf(V.vector4_f32[0]),
4482                1.0 / sqrtf(V.vector4_f32[1]),
4483                1.0 / sqrtf(V.vector4_f32[2]),
4484                1.0 / sqrtf(V.vector4_f32[3])
4485            ]
4486        };
4487        return Result.v;
4488    }
4489
4490    #[cfg(_XM_ARM_NEON_INTRINSICS_)]
4491    {
4492        unimplemented!()
4493    }
4494
4495    #[cfg(_XM_SSE_INTRINSICS_)]
4496    unsafe {
4497        return _mm_rsqrt_ps(V);
4498    }
4499}
4500
4501/// Computes the per-component reciprocal square root of a vector.
4502///
4503/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVectorReciprocalSqrt>
4504#[inline]
4505pub fn XMVectorReciprocalSqrt(
4506    V: FXMVECTOR,
4507) -> XMVECTOR
4508{
4509    #[cfg(_XM_NO_INTRINSICS_)]
4510    unsafe {
4511        let Result = XMVECTORF32 {
4512            f: [
4513                1.0 / sqrtf(V.vector4_f32[0]),
4514                1.0 / sqrtf(V.vector4_f32[1]),
4515                1.0 / sqrtf(V.vector4_f32[2]),
4516                1.0 / sqrtf(V.vector4_f32[3])
4517            ]
4518        };
4519        return Result.v;
4520    }
4521
4522    #[cfg(_XM_ARM_NEON_INTRINSICS_)]
4523    {
4524        unimplemented!()
4525    }
4526
4527    #[cfg(_XM_SSE_INTRINSICS_)]
4528    unsafe {
4529        let mut vResult: XMVECTOR = _mm_sqrt_ps(V);
4530        vResult = _mm_div_ps(g_XMOne.v, vResult);
4531        return vResult;
4532    }
4533}
4534
4535/// Computes two raised to the power for each component.
4536///
4537/// ## Parameters
4538///
4539/// `V` Vector used for the exponents of base two.
4540///
4541/// ## Return value
4542///
4543/// Returns a vector whose components are two raised to the power of the corresponding component of `V`.
4544///
4545/// ## Remarks
4546///
4547///
4548/// ```text
4549/// XMVECTOR Result;
4550///
4551/// Result.x = powf(2.0f, V.x);
4552/// Result.y = powf(2.0f, V.y);
4553/// Result.z = powf(2.0f, V.z);
4554/// Result.w = powf(2.0f, V.w);
4555///
4556/// return Result;
4557/// ```
4558///
4559/// ## Reference
4560///
4561/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVectorExp2>
4562#[inline]
4563pub fn XMVectorExp2(
4564    V: FXMVECTOR,
4565) -> XMVECTOR
4566{
4567    #[cfg(_XM_NO_INTRINSICS_)]
4568    unsafe {
4569        let Result = XMVECTORF32 {
4570            f: [
4571                powf(2.0, V.vector4_f32[0]),
4572                powf(2.0, V.vector4_f32[1]),
4573                powf(2.0, V.vector4_f32[2]),
4574                powf(2.0, V.vector4_f32[3])
4575            ]
4576        };
4577        return Result.v;
4578    }
4579
4580    #[cfg(_XM_ARM_NEON_INTRINSICS_)]
4581    {
4582        unimplemented!()
4583    }
4584
4585    #[cfg(_XM_SSE_INTRINSICS_)]
4586    unsafe {
4587        let itrunc: __m128i = _mm_cvttps_epi32(V);
4588        let ftrunc: __m128 = _mm_cvtepi32_ps(itrunc);
4589        let y: __m128 = _mm_sub_ps(V, ftrunc);
4590
4591        let mut poly: __m128 = XM_FMADD_PS!(g_XMExpEst7.v, y, g_XMExpEst6.v);
4592        poly = XM_FMADD_PS!(poly, y, g_XMExpEst5.v);
4593        poly = XM_FMADD_PS!(poly, y, g_XMExpEst4.v);
4594        poly = XM_FMADD_PS!(poly, y, g_XMExpEst3.v);
4595        poly = XM_FMADD_PS!(poly, y, g_XMExpEst2.v);
4596        poly = XM_FMADD_PS!(poly, y, g_XMExpEst1.v);
4597        poly = XM_FMADD_PS!(poly, y, g_XMOne.v);
4598
4599        let mut biased: __m128i = _mm_add_epi32(itrunc, g_XMExponentBias.m128i());
4600        biased = _mm_slli_epi32(biased, 23);
4601        let result0: __m128 = _mm_div_ps(_mm_castsi128_ps(biased), poly);
4602
4603        biased = _mm_add_epi32(itrunc, g_XM253.m128i());
4604        biased = _mm_slli_epi32(biased, 23);
4605        let mut result1: __m128 = _mm_div_ps(_mm_castsi128_ps(biased), poly);
4606        result1 = _mm_mul_ps(g_XMMinNormal.v, result1);
4607
4608        // Use selection to handle the cases
4609        //  if (V is NaN) -> QNaN;
4610        //  else if (V sign bit set)
4611        //      if (V > -150)
4612        //         if (V.exponent < -126) -> result1
4613        //         else -> result0
4614        //      else -> +0
4615        //  else
4616        //      if (V < 128) -> result0
4617        //      else -> +inf
4618
4619        let mut comp: __m128i = _mm_cmplt_epi32(_mm_castps_si128(V), g_XMBin128.m128i());
4620        let mut select0: __m128i = _mm_and_si128(comp, _mm_castps_si128(result0));
4621        let mut select1: __m128i = _mm_andnot_si128(comp, g_XMInfinity.m128i());
4622        let result2: __m128i = _mm_or_si128(select0, select1);
4623
4624        comp = _mm_cmplt_epi32(itrunc, g_XMSubnormalExponent.m128i());
4625        select1 = _mm_and_si128(comp, _mm_castps_si128(result1));
4626        select0 = _mm_andnot_si128(comp, _mm_castps_si128(result0));
4627        let result3: __m128i = _mm_or_si128(select0, select1);
4628
4629        comp = _mm_cmplt_epi32(_mm_castps_si128(V), g_XMBinNeg150.m128i());
4630        select0 = _mm_and_si128(comp, result3);
4631        select1 = _mm_andnot_si128(comp, g_XMZero.m128i());
4632        let result4: __m128i = _mm_or_si128(select0, select1);
4633
4634        let sign: __m128i = _mm_and_si128(_mm_castps_si128(V), g_XMNegativeZero.m128i());
4635        comp = _mm_cmpeq_epi32(sign, g_XMNegativeZero.m128i());
4636        select0 = _mm_and_si128(comp, result4);
4637        select1 = _mm_andnot_si128(comp, result2);
4638        let result5: __m128i = _mm_or_si128(select0, select1);
4639
4640        let mut t0: __m128i = _mm_and_si128(_mm_castps_si128(V), g_XMQNaNTest.m128i());
4641        let mut t1: __m128i = _mm_and_si128(_mm_castps_si128(V), g_XMInfinity.m128i());
4642        t0 = _mm_cmpeq_epi32(t0, g_XMZero.m128i());
4643        t1 = _mm_cmpeq_epi32(t1, g_XMInfinity.m128i());
4644        let isNaN: __m128i = _mm_andnot_si128(t0, t1);
4645
4646        select0 = _mm_and_si128(isNaN, g_XMQNaN.m128i());
4647        select1 = _mm_andnot_si128(isNaN, result5);
4648        let vResult: __m128i = _mm_or_si128(select0, select1);
4649
4650        return _mm_castsi128_ps(vResult);
4651    }
4652}
4653
4654// TODO: XMVectorExpE
4655
4656/// Computes two raised to the power for each component.
4657///
4658/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVectorExp>
4659#[inline]
4660pub fn XMVectorExp(
4661    V: FXMVECTOR,
4662) -> XMVECTOR {
4663    return XMVectorExp2(V);
4664}
4665
4666// TODO: Internal / multi_sll_epi32
4667// TODO: Internal / multi_srl_epi32
4668// TODO: Internal / GetLeadingBit __m128i
4669// TODO: Internal / GetLeadingBit int32x4_t
4670// TODO: XMVectorLog2
4671// TODO: XMVectorLogE
4672// TODO: XMVectorLog
4673
4674/// Computes V1 raised to the power of V2.
4675///
4676/// ## Parameters
4677///
4678/// `V1` First vector.
4679///
4680/// `V2` Second vector.
4681///
4682/// ## Return value
4683///
4684/// Returns a vector. Each component is the corresponding component of `V1` raised to the power of the corresponding
4685/// component in V2.
4686///
4687/// ## Remarks
4688///
4689/// The following pseudocode demonstrates the operation of the function:
4690///
4691/// ```text
4692/// XMVECTOR Result;
4693///
4694/// Result.x = pow(V1.x, V2.x);
4695/// Result.y = pow(V1.y, V2.y);
4696/// Result.z = pow(V1.z, V2.z);
4697/// Result.w = pow(V1.w, V2.w);
4698///
4699/// return Result;
4700/// ```
4701///
4702/// ## Reference
4703///
4704/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVectorPow>
4705#[inline]
4706pub fn XMVectorPow(
4707    V1: FXMVECTOR,
4708    V2: FXMVECTOR,
4709) -> XMVECTOR
4710{
4711    #[cfg(_XM_NO_INTRINSICS_)]
4712    unsafe {
4713        let Result = XMVECTORF32 {
4714            f: [
4715                powf(V1.vector4_f32[0], V2.vector4_f32[0]),
4716                powf(V1.vector4_f32[1], V2.vector4_f32[1]),
4717                powf(V1.vector4_f32[2], V2.vector4_f32[2]),
4718                powf(V1.vector4_f32[3], V2.vector4_f32[3])
4719            ]
4720        };
4721        return Result.v;
4722    }
4723
4724    #[cfg(_XM_ARM_NEON_INTRINSICS_)]
4725    {
4726        unimplemented!()
4727    }
4728
4729    #[cfg(_XM_SSE_INTRINSICS_)]
4730    unsafe {
4731        let mut a: Align16<[f32; 4]> = crate::undefined();
4732        let mut b: Align16<[f32; 4]> = crate::undefined();
4733        _mm_store_ps(a.as_mut_ptr(), V1);
4734        _mm_store_ps(b.as_mut_ptr(), V2);
4735        let vResult: XMVECTOR = _mm_setr_ps(
4736            powf(a[0], b[0]),
4737            powf(a[1], b[1]),
4738            powf(a[2], b[2]),
4739            powf(a[3], b[3]));
4740        return vResult;
4741    }
4742}
4743
4744/// Computes the absolute value of each component of an XMVECTOR.
4745///
4746/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVectorAbs>
4747#[inline]
4748pub fn XMVectorAbs(
4749    V: FXMVECTOR,
4750) -> XMVECTOR
4751{
4752    #[cfg(_XM_NO_INTRINSICS_)]
4753    unsafe {
4754        let Result = XMVECTORF32 {
4755            f: [
4756                fabsf(V.vector4_f32[0]),
4757                fabsf(V.vector4_f32[1]),
4758                fabsf(V.vector4_f32[2]),
4759                fabsf(V.vector4_f32[3])
4760            ]
4761        };
4762        return Result.v;
4763    }
4764
4765    #[cfg(_XM_ARM_NEON_INTRINSICS_)]
4766    {
4767        unimplemented!()
4768    }
4769
4770    #[cfg(_XM_SSE_INTRINSICS_)]
4771    unsafe {
4772        let mut vResult: XMVECTOR = _mm_setzero_ps();
4773        vResult = _mm_sub_ps(vResult, V);
4774        vResult = _mm_max_ps(vResult, V);
4775        return vResult;
4776    }
4777}
4778
4779/// Computes the per-component floating-point remainder of the quotient of two vectors.
4780///
4781/// ## Parameters
4782///
4783/// `V1` Vector dividend.
4784///
4785/// `V2` Vector divisor.
4786///
4787/// ## Return value
4788///
4789/// Returns a vector whose components are the floating-point remainders of the divisions.
4790///
4791/// ## Remarks
4792///
4793/// The following pseudocode demonstrates the operation of the function:
4794///
4795/// ```text
4796/// XMVECTOR Result;
4797///
4798/// Result.x = fmod(V1.x, V2.x);
4799/// Result.y = fmod(V1.y, V2.y);
4800/// Result.z = fmod(V1.z, V2.z);
4801/// Result.w = fmod(V1.w, V2.w);
4802///
4803/// return Result;
4804/// ```
4805///
4806/// ## Reference
4807///
4808/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVectorMod>
4809#[inline]
4810pub fn XMVectorMod(
4811    V1: FXMVECTOR,
4812    V2: FXMVECTOR,
4813) -> XMVECTOR
4814{
4815    // V1 % V2 = V1 - V2 * truncate(V1 / V2)
4816
4817    #[cfg(_XM_NO_INTRINSICS_)]
4818    {
4819        let mut Quotient: XMVECTOR = XMVectorDivide(V1, V2);
4820        Quotient = XMVectorTruncate(Quotient);
4821        let Result: XMVECTOR = XMVectorNegativeMultiplySubtract(V2, Quotient, V1);
4822        return Result;
4823    }
4824
4825    #[cfg(_XM_ARM_NEON_INTRINSICS_)]
4826    {
4827        unimplemented!()
4828    }
4829
4830    #[cfg(_XM_SSE_INTRINSICS_)]
4831    unsafe {
4832        let mut vResult: XMVECTOR = _mm_div_ps(V1, V2);
4833        vResult = XMVectorTruncate(vResult);
4834        return XM_FNMADD_PS!(vResult, V2, V1);
4835    }
4836}
4837
4838/// Computes the per-component angle modulo 2PI.
4839///
4840/// ## Parameters
4841///
4842/// `Angles` Vector of angle components.
4843///
4844/// ## Return value
4845///
4846/// Returns a vector whose components are the corresponding components of Angles modulo 2PI.
4847///
4848/// ## Remarks
4849///
4850/// The following pseudocode demonstrates the operation of the function:
4851///
4852/// ```text
4853/// XMVECTOR result;
4854///
4855/// result.x = Angles.x - XM_2PI * round( Angles.x / XM_2PI );
4856/// result.y = Angles.y - XM_2PI * round( Angles.y / XM_2PI );
4857/// result.z = Angles.z - XM_2PI * round( Angles.z / XM_2PI );
4858/// result.w = Angles.w - XM_2PI * round( Angles.w / XM_2PI );
4859///
4860/// return result;
4861/// ```
4862///
4863/// ## Reference
4864///
4865/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVectorModAngles>
4866#[inline]
4867pub fn XMVectorModAngles(
4868    Angles: FXMVECTOR,
4869) -> XMVECTOR
4870{
4871    // V1 % V2 = V1 - V2 * truncate(V1 / V2)
4872
4873    #[cfg(_XM_NO_INTRINSICS_)]
4874    unsafe {
4875        let mut V: XMVECTOR;
4876        let Result: XMVECTOR;
4877
4878        // Modulo the range of the given angles such that -XM_PI <= Angles < XM_PI
4879        V = XMVectorMultiply(Angles, g_XMReciprocalTwoPi.v);
4880        V = XMVectorRound(V);
4881        Result = XMVectorNegativeMultiplySubtract(g_XMTwoPi.v, V, Angles);
4882        return Result;
4883    }
4884
4885    #[cfg(_XM_ARM_NEON_INTRINSICS_)]
4886    {
4887        unimplemented!()
4888    }
4889
4890    #[cfg(_XM_SSE_INTRINSICS_)]
4891    unsafe {
4892        // Modulo the range of the given angles such that -XM_PI <= Angles < XM_PI
4893        let mut vResult: XMVECTOR = _mm_mul_ps(Angles, g_XMReciprocalTwoPi.v);
4894        // Use the inline function due to complexity for rounding
4895        vResult = XMVectorRound(vResult);
4896        return XM_FNMADD_PS!(vResult, g_XMTwoPi.v, Angles);
4897    }
4898}
4899
4900/// Computes the sine of each component of an XMVECTOR.
4901///
4902/// ## Parameters
4903///
4904/// `V` Vector for which to compute the sine.
4905///
4906/// ## Return value
4907///
4908/// Returns a vector. Each component is the sine of the corresponding component of `V`.
4909///
4910/// ## Remarks
4911///
4912/// This function uses a 11-degree minimax approximation.
4913///
4914/// ## Reference
4915///
4916/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVectorSin>
4917#[inline]
4918pub fn XMVectorSin(
4919    V: FXMVECTOR,
4920) -> XMVECTOR
4921{
4922    // 11-degree minimax approximation
4923
4924    #[cfg(_XM_NO_INTRINSICS_)]
4925    unsafe {
4926        let Result = XMVECTORF32 {
4927            f: [
4928                sinf(V.vector4_f32[0]),
4929                sinf(V.vector4_f32[1]),
4930                sinf(V.vector4_f32[2]),
4931                sinf(V.vector4_f32[3])
4932            ]
4933        };
4934        return Result.v;
4935    }
4936
4937    #[cfg(_XM_ARM_NEON_INTRINSICS_)]
4938    {
4939        unimplemented!()
4940    }
4941
4942    #[cfg(_XM_SSE_INTRINSICS_)]
4943    unsafe {
4944        // Force the value within the bounds of pi
4945        let mut x: XMVECTOR = XMVectorModAngles(V);
4946
4947        // Map in [-pi/2,pi/2] with sin(y) = sin(x).
4948        let sign: __m128 = _mm_and_ps(x, g_XMNegativeZero.v);
4949        let c: __m128 = _mm_or_ps(g_XMPi.v, sign);  // pi when x >= 0, -pi when x < 0
4950        let absx: __m128 = _mm_andnot_ps(sign, x);  // |x|
4951        let rflx: __m128 = _mm_sub_ps(c, x);
4952        let comp: __m128 = _mm_cmple_ps(absx, g_XMHalfPi.v);
4953        let select0: __m128 = _mm_and_ps(comp, x);
4954        let select1: __m128 = _mm_andnot_ps(comp, rflx);
4955        x = _mm_or_ps(select0, select1);
4956
4957        let x2: __m128 = _mm_mul_ps(x, x);
4958
4959        // Compute polynomial approximation
4960        const SC1: XMVECTOR = unsafe { g_XMSinCoefficients1.v };
4961        let vConstantsB: __m128 = XM_PERMUTE_PS!(SC1, _MM_SHUFFLE(0, 0, 0, 0));
4962        const SC0: XMVECTOR = unsafe { g_XMSinCoefficients0.v };
4963        let mut vConstants: __m128 = XM_PERMUTE_PS!(SC0, _MM_SHUFFLE(3, 3, 3, 3));
4964        let mut Result: __m128 = XM_FMADD_PS!(vConstantsB, x2, vConstants);
4965
4966        vConstants = XM_PERMUTE_PS!(SC0, _MM_SHUFFLE(2, 2, 2, 2));
4967        Result = XM_FMADD_PS!(Result, x2, vConstants);
4968
4969        vConstants = XM_PERMUTE_PS!(SC0, _MM_SHUFFLE(1, 1, 1, 1));
4970        Result = XM_FMADD_PS!(Result, x2, vConstants);
4971
4972        vConstants = XM_PERMUTE_PS!(SC0, _MM_SHUFFLE(0, 0, 0, 0));
4973        Result = XM_FMADD_PS!(Result, x2, vConstants);
4974
4975        Result = XM_FMADD_PS!(Result, x2, g_XMOne.v);
4976        Result = _mm_mul_ps(Result, x);
4977        return Result;
4978    }
4979}
4980
4981#[test]
4982fn test_XMVectorSin() {
4983    for angle in &[-XM_PI, -XM_PI/2.0, -XM_PI/3.0, -XM_PI/4.0, 0.0, XM_PI/4.0, XM_PI/3.0, XM_PI/2.0, XM_PI] {
4984        let scalar = angle.sin();
4985        let vector = XMVectorReplicate(*angle);
4986        let vector = XMVectorSin(vector);
4987        assert_approx_eq!(scalar, XMVectorGetX(vector));
4988        assert_approx_eq!(scalar, XMVectorGetY(vector));
4989        assert_approx_eq!(scalar, XMVectorGetZ(vector));
4990        assert_approx_eq!(scalar, XMVectorGetW(vector));
4991    }
4992}
4993
4994/// Computes the cosine of each component of an XMVECTOR.
4995///
4996/// ## Parameters
4997///
4998/// `V` Vector for which to compute the cosine.
4999///
5000/// ## Return value
5001///
5002/// Returns a vector. Each component is the cosine of the corresponding component of `V`.
5003///
5004/// ## Remarks
5005///
5006/// This function uses a 10-degree minimax approximation.
5007///
5008/// ## Reference
5009///
5010/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVectorCos>
5011#[inline]
5012pub fn XMVectorCos(
5013    V: FXMVECTOR,
5014) -> XMVECTOR
5015{
5016    // 10-degree minimax approximation
5017
5018    #[cfg(_XM_NO_INTRINSICS_)]
5019    unsafe {
5020        let Result = XMVECTORF32 {
5021            f: [
5022                cosf(V.vector4_f32[0]),
5023                cosf(V.vector4_f32[1]),
5024                cosf(V.vector4_f32[2]),
5025                cosf(V.vector4_f32[3])
5026            ]
5027        };
5028        return Result.v;
5029    }
5030
5031    #[cfg(_XM_ARM_NEON_INTRINSICS_)]
5032    {
5033        unimplemented!()
5034    }
5035
5036    #[cfg(_XM_SSE_INTRINSICS_)]
5037    unsafe {
5038        // Map V to x in [-pi,pi].
5039        let mut x: XMVECTOR = XMVectorModAngles(V);
5040
5041        // Map in [-pi/2,pi/2] with cos(y) = sign*cos(x).
5042        let mut sign: XMVECTOR = _mm_and_ps(x, g_XMNegativeZero.v);
5043        let c: __m128 = _mm_or_ps(g_XMPi.v, sign);  // pi when x >= 0, -pi when x < 0
5044        let absx: __m128 = _mm_andnot_ps(sign, x);  // |x|
5045        let rflx: __m128 = _mm_sub_ps(c, x);
5046        let comp: __m128  = _mm_cmple_ps(absx, g_XMHalfPi.v);
5047        let mut select0: __m128 = _mm_and_ps(comp, x);
5048        let mut select1: __m128 = _mm_andnot_ps(comp, rflx);
5049        x = _mm_or_ps(select0, select1);
5050        select0 = _mm_and_ps(comp, g_XMOne.v);
5051        select1 = _mm_andnot_ps(comp, g_XMNegativeOne.v);
5052        sign = _mm_or_ps(select0, select1);
5053
5054        let x2: __m128 = _mm_mul_ps(x, x);
5055
5056        // Compute polynomial approximation
5057        const CC1: XMVECTOR = unsafe { g_XMCosCoefficients1.v };
5058        let vConstantsB: __m128 = XM_PERMUTE_PS!(CC1, _MM_SHUFFLE(0, 0, 0, 0));
5059        const CC0: XMVECTOR = unsafe { g_XMCosCoefficients0.v };
5060        let mut vConstants: __m128 = XM_PERMUTE_PS!(CC0, _MM_SHUFFLE(3, 3, 3, 3));
5061        let mut Result: __m128 = XM_FMADD_PS!(vConstantsB, x2, vConstants);
5062
5063        vConstants = XM_PERMUTE_PS!(CC0, _MM_SHUFFLE(2, 2, 2, 2));
5064        Result = XM_FMADD_PS!(Result, x2, vConstants);
5065
5066        vConstants = XM_PERMUTE_PS!(CC0, _MM_SHUFFLE(1, 1, 1, 1));
5067        Result = XM_FMADD_PS!(Result, x2, vConstants);
5068
5069        vConstants = XM_PERMUTE_PS!(CC0, _MM_SHUFFLE(0, 0, 0, 0));
5070        Result = XM_FMADD_PS!(Result, x2, vConstants);
5071
5072        Result = XM_FMADD_PS!(Result, x2, g_XMOne.v);
5073        Result = _mm_mul_ps(Result, sign);
5074        return Result;
5075    }
5076}
5077
5078#[test]
5079fn test_XMVectorCos() {
5080    for angle in &[-XM_PI, -XM_PI/2.0, -XM_PI/3.0, -XM_PI/4.0, 0.0, XM_PI/4.0, XM_PI/3.0, XM_PI/2.0, XM_PI] {
5081        let scalar = angle.cos();
5082        let vector = XMVectorReplicate(*angle);
5083        let vector = XMVectorCos(vector);
5084        assert_approx_eq!(scalar, XMVectorGetX(vector));
5085        assert_approx_eq!(scalar, XMVectorGetY(vector));
5086        assert_approx_eq!(scalar, XMVectorGetZ(vector));
5087        assert_approx_eq!(scalar, XMVectorGetW(vector));
5088    }
5089}
5090
5091/// Computes the sine and cosine of each component of an XMVECTOR.
5092///
5093/// ## Parameters
5094///
5095/// `pSin` Address of a vector, each of whose components is the sine of the corresponding component of `V`.
5096///
5097/// `pCos` Address of a vector, each of whose components is the cosine of the corresponding component of `V`.
5098///
5099/// `V` Vector for which to compute the sine and cosine.
5100///
5101/// ## Return value
5102///
5103/// None.
5104///
5105/// ## Remarks
5106///
5107/// This function uses an 11-degree minimax approximation for sine, 10-degree for cosine.
5108///
5109/// ## Reference
5110///
5111/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVectorSinCos>
5112#[inline]
5113pub fn XMVectorSinCos(
5114    pSin: &mut XMVECTOR,
5115    pCos: &mut XMVECTOR,
5116    V: FXMVECTOR,
5117)
5118{
5119    // 11/10-degree minimax approximation
5120
5121    #[cfg(_XM_NO_INTRINSICS_)]
5122    unsafe {
5123        let Sin = XMVECTORF32 {
5124            f: [
5125                sinf(V.vector4_f32[0]),
5126                sinf(V.vector4_f32[1]),
5127                sinf(V.vector4_f32[2]),
5128                sinf(V.vector4_f32[3])
5129            ]
5130        };
5131        let Cos = XMVECTORF32 {
5132            f: [
5133                cosf(V.vector4_f32[0]),
5134                cosf(V.vector4_f32[1]),
5135                cosf(V.vector4_f32[2]),
5136                cosf(V.vector4_f32[3])
5137            ]
5138        };
5139        *pSin = Sin.v;
5140        *pCos = Cos.v;
5141    }
5142
5143    #[cfg(_XM_ARM_NEON_INTRINSICS_)]
5144    {
5145        unimplemented!()
5146    }
5147
5148    #[cfg(_XM_SSE_INTRINSICS_)]
5149    unsafe {
5150        // Force the value within the bounds of pi
5151        let mut x: XMVECTOR = XMVectorModAngles(V);
5152
5153        // Map in [-pi/2,pi/2] with sin(y) = sin(x), cos(y) = sign*cos(x).
5154        let mut sign: XMVECTOR = _mm_and_ps(x, g_XMNegativeZero.v);
5155        let c: __m128 = _mm_or_ps(g_XMPi.v, sign);  // pi when x >= 0, -pi when x < 0
5156        let absx: __m128 = _mm_andnot_ps(sign, x);  // |x|
5157        let rflx: __m128 = _mm_sub_ps(c, x);
5158        let comp: __m128 = _mm_cmple_ps(absx, g_XMHalfPi.v);
5159        let mut select0: __m128 = _mm_and_ps(comp, x);
5160        let mut select1: __m128 = _mm_andnot_ps(comp, rflx);
5161        x = _mm_or_ps(select0, select1);
5162        select0 = _mm_and_ps(comp, g_XMOne.v);
5163        select1 = _mm_andnot_ps(comp, g_XMNegativeOne.v);
5164        sign = _mm_or_ps(select0, select1);
5165
5166        let x2: __m128 = _mm_mul_ps(x, x);
5167
5168        // Compute polynomial approximation of sine
5169        const SC1: XMVECTOR = unsafe { g_XMSinCoefficients1.v };
5170        let mut vConstantsB: __m128 = XM_PERMUTE_PS!(SC1, _MM_SHUFFLE(0, 0, 0, 0));
5171        const SC0: XMVECTOR = unsafe { g_XMSinCoefficients0.v };
5172        let mut vConstants: __m128 = XM_PERMUTE_PS!(SC0, _MM_SHUFFLE(3, 3, 3, 3));
5173        let mut Result: __m128 = XM_FMADD_PS!(vConstantsB, x2, vConstants);
5174
5175        vConstants = XM_PERMUTE_PS!(SC0, _MM_SHUFFLE(2, 2, 2, 2));
5176        Result = XM_FMADD_PS!(Result, x2, vConstants);
5177
5178        vConstants = XM_PERMUTE_PS!(SC0, _MM_SHUFFLE(1, 1, 1, 1));
5179        Result = XM_FMADD_PS!(Result, x2, vConstants);
5180
5181        vConstants = XM_PERMUTE_PS!(SC0, _MM_SHUFFLE(0, 0, 0, 0));
5182        Result = XM_FMADD_PS!(Result, x2, vConstants);
5183
5184        Result = XM_FMADD_PS!(Result, x2, g_XMOne.v);
5185        Result = _mm_mul_ps(Result, x);
5186        *pSin = Result;
5187
5188        // Compute polynomial approximation of cosine
5189        const CC1: XMVECTOR = unsafe { g_XMCosCoefficients1.v };
5190        vConstantsB = XM_PERMUTE_PS!(CC1, _MM_SHUFFLE(0, 0, 0, 0));
5191        const CC0: XMVECTOR = unsafe { g_XMCosCoefficients0.v };
5192        vConstants = XM_PERMUTE_PS!(CC0, _MM_SHUFFLE(3, 3, 3, 3));
5193        Result = XM_FMADD_PS!(vConstantsB, x2, vConstants);
5194
5195        vConstants = XM_PERMUTE_PS!(CC0, _MM_SHUFFLE(2, 2, 2, 2));
5196        Result = XM_FMADD_PS!(Result, x2, vConstants);
5197
5198        vConstants = XM_PERMUTE_PS!(CC0, _MM_SHUFFLE(1, 1, 1, 1));
5199        Result = XM_FMADD_PS!(Result, x2, vConstants);
5200
5201        vConstants = XM_PERMUTE_PS!(CC0, _MM_SHUFFLE(0, 0, 0, 0));
5202        Result = XM_FMADD_PS!(Result, x2, vConstants);
5203
5204        Result = XM_FMADD_PS!(Result, x2, g_XMOne.v);
5205        Result = _mm_mul_ps(Result, sign);
5206        *pCos = Result;
5207    }
5208}
5209
5210/// Computes the tangent of each component of an XMVECTOR.
5211///
5212/// ## Parameters
5213///
5214/// `V` Vector for which to compute the tangent.
5215///
5216/// ## Return value
5217///
5218/// Returns a vector. Each component is the tangent of the corresponding component of `V`.
5219///
5220/// ## Reference
5221///
5222/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVectorTan>
5223#[inline]
5224pub fn XMVectorTan(
5225    V: FXMVECTOR,
5226) -> XMVECTOR
5227{
5228    // Cody and Waite algorithm to compute tangent.
5229
5230    #[cfg(_XM_NO_INTRINSICS_)]
5231    unsafe {
5232        let Result = XMVECTORF32 {
5233            f: [
5234                tanf(V.vector4_f32[0]),
5235                tanf(V.vector4_f32[1]),
5236                tanf(V.vector4_f32[2]),
5237                tanf(V.vector4_f32[3])
5238            ]
5239        };
5240        return Result.v;
5241    }
5242
5243    #[cfg(any(_XM_SSE_INTRINSICS_, _XM_ARM_NEON_INTRINSICS_))]
5244    unsafe {
5245        const TanCoefficients0: XMVECTORF32 = XMVECTORF32 { f: [1.0, -4.667168334e-1, 2.566383229e-2, -3.118153191e-4] };
5246        const TanCoefficients1: XMVECTORF32 = XMVECTORF32 { f: [4.981943399e-7, -1.333835001e-1, 3.424887824e-3, -1.786170734e-5] };
5247        const TanConstants: XMVECTORF32 = XMVECTORF32 { f: [1.570796371, 6.077100628e-11, 0.000244140625, 0.63661977228 /*2 / Pi*/ ] };
5248        const Mask: XMVECTORU32 = XMVECTORU32 { u: [0x1, 0x1, 0x1, 0x1] };
5249
5250        let TwoDivPi: XMVECTOR = XMVectorSplatW(TanConstants.v);
5251
5252        let Zero: XMVECTOR = XMVectorZero();
5253
5254        let C0: XMVECTOR = XMVectorSplatX(TanConstants.v);
5255        let C1: XMVECTOR = XMVectorSplatY(TanConstants.v);
5256        let Epsilon: XMVECTOR = XMVectorSplatZ(TanConstants.v);
5257
5258        let mut VA: XMVECTOR = XMVectorMultiply(V, TwoDivPi);
5259
5260        VA = XMVectorRound(VA);
5261
5262        let mut VC: XMVECTOR = XMVectorNegativeMultiplySubtract(VA, C0, V);
5263
5264        let mut VB: XMVECTOR = XMVectorAbs(VA);
5265
5266        VC = XMVectorNegativeMultiplySubtract(VA, C1, VC);
5267
5268        #[cfg(_XM_ARM_NEON_INTRINSICS_)]
5269        {
5270            // unimplemented!();
5271            // VB = vcvtq_u32_f32(VB);
5272        }
5273
5274        #[cfg(_XM_SSE_INTRINSICS_)]
5275        {
5276            VB = mem::transmute(_mm_cvttps_epi32(VB));
5277        }
5278
5279        // NOTE: This block does not appear to be reachable in the source
5280        //       and is not reachable here. It's left for reference only.
5281        #[cfg(all(not(_XM_SSE_INTRINSICS_), not(_XM_ARM_NEON_INTRINSICS_)))]
5282        {
5283            for i in 0..4 {
5284                VB.vector4_u32[i] = (VB.vector4_f32[i]) as i32 as u32;
5285            }
5286        }
5287
5288        let VC2: XMVECTOR = XMVectorMultiply(VC, VC);
5289
5290        let T7: XMVECTOR = XMVectorSplatW(TanCoefficients1.v);
5291        let T6: XMVECTOR = XMVectorSplatZ(TanCoefficients1.v);
5292        let T4: XMVECTOR = XMVectorSplatX(TanCoefficients1.v);
5293        let T3: XMVECTOR = XMVectorSplatW(TanCoefficients0.v);
5294        let T5: XMVECTOR = XMVectorSplatY(TanCoefficients1.v);
5295        let T2: XMVECTOR = XMVectorSplatZ(TanCoefficients0.v);
5296        let T1: XMVECTOR = XMVectorSplatY(TanCoefficients0.v);
5297        let T0: XMVECTOR = XMVectorSplatX(TanCoefficients0.v);
5298
5299        let mut VBIsEven: XMVECTOR = XMVectorAndInt(VB, Mask.v);
5300        VBIsEven = XMVectorEqualInt(VBIsEven, Zero);
5301
5302        let mut N: XMVECTOR = XMVectorMultiplyAdd(VC2, T7, T6);
5303        let mut D: XMVECTOR = XMVectorMultiplyAdd(VC2, T4, T3);
5304        N = XMVectorMultiplyAdd(VC2, N, T5);
5305        D = XMVectorMultiplyAdd(VC2, D, T2);
5306        N = XMVectorMultiply(VC2, N);
5307        D = XMVectorMultiplyAdd(VC2, D, T1);
5308        N = XMVectorMultiplyAdd(VC, N, VC);
5309        let VCNearZero: XMVECTOR = XMVectorInBounds(VC, Epsilon);
5310        D = XMVectorMultiplyAdd(VC2, D, T0);
5311
5312        N = XMVectorSelect(N, VC, VCNearZero);
5313        D = XMVectorSelect(D, g_XMOne.v, VCNearZero);
5314
5315        let mut R0: XMVECTOR = XMVectorNegate(N);
5316        let R1: XMVECTOR = XMVectorDivide(N, D);
5317        R0 = XMVectorDivide(D, R0);
5318
5319        let VIsZero: XMVECTOR = XMVectorEqual(V, Zero);
5320
5321        let mut Result: XMVECTOR = XMVectorSelect(R0, R1, VBIsEven);
5322
5323        Result = XMVectorSelect(Result, Zero, VIsZero);
5324
5325        return Result;
5326    }
5327}
5328
5329#[test]
5330fn test_XMVectorTan() {
5331    for angle in &[-XM_PI/3.0, -XM_PI/4.0, 0.0, XM_PI/4.0, XM_PI/3.0] {
5332        let scalar = angle.tan();
5333        let vector = XMVectorReplicate(*angle);
5334        let vector = XMVectorTan(vector);
5335        assert_approx_eq!(scalar, XMVectorGetX(vector));
5336        assert_approx_eq!(scalar, XMVectorGetY(vector));
5337        assert_approx_eq!(scalar, XMVectorGetZ(vector));
5338        assert_approx_eq!(scalar, XMVectorGetW(vector));
5339    }
5340}
5341
5342/// Computes the hyperbolic sine of each component of an XMVECTOR.
5343///
5344/// ## Parameters
5345///
5346/// `V` Vector for which to compute the hyperbolic sine.
5347///
5348/// ## Return value
5349///
5350/// Returns a vector. Each component is the hyperbolic sine of the corresponding component of `V`.
5351///
5352/// ## Reference
5353///
5354/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVectorSinH>
5355#[inline]
5356pub fn XMVectorSinH(
5357    V: FXMVECTOR,
5358) -> XMVECTOR
5359{
5360    // 7-degree minimax approximation
5361
5362    #[cfg(_XM_NO_INTRINSICS_)]
5363    unsafe {
5364        let Result = XMVECTORF32 {
5365            f: [
5366                sinh(V.vector4_f32[0]),
5367                sinh(V.vector4_f32[1]),
5368                sinh(V.vector4_f32[2]),
5369                sinh(V.vector4_f32[3])
5370            ]
5371        };
5372        return Result.v;
5373    }
5374
5375    #[cfg(_XM_ARM_NEON_INTRINSICS_)]
5376    {
5377        unimplemented!()
5378    }
5379
5380    #[cfg(_XM_SSE_INTRINSICS_)]
5381    unsafe {
5382        const Scale: XMVECTORF32 = XMVECTORF32 { f :[ 1.442695040888963, 1.442695040888963, 1.442695040888963, 1.442695040888963 ] }; // 1.0f / ln(2.0f)
5383
5384        let V1: XMVECTOR = XM_FMADD_PS!(V, Scale.v, g_XMNegativeOne.v);
5385        let V2: XMVECTOR = XM_FNMADD_PS!(V, Scale.v, g_XMNegativeOne.v);
5386        let E1: XMVECTOR = XMVectorExp(V1);
5387        let E2: XMVECTOR = XMVectorExp(V2);
5388
5389        return _mm_sub_ps(E1, E2);
5390    }
5391}
5392
5393/// Computes the hyperbolic cosine of each component of an XMVECTOR.
5394///
5395/// ## Parameters
5396///
5397/// `V` Vector for which to compute the hyperbolic cosine.
5398///
5399/// ## Return value
5400///
5401/// Returns a vector. Each component is the hyperbolic cosine of the corresponding component of `V`.
5402///
5403/// ## Reference
5404///
5405/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVectorCosH>
5406#[inline]
5407pub fn XMVectorCosH(
5408    V: FXMVECTOR,
5409) -> XMVECTOR
5410{
5411    #[cfg(_XM_NO_INTRINSICS_)]
5412    unsafe {
5413        let Result = XMVECTORF32 {
5414            f: [
5415                cosh(V.vector4_f32[0]),
5416                cosh(V.vector4_f32[1]),
5417                cosh(V.vector4_f32[2]),
5418                cosh(V.vector4_f32[3])
5419            ]
5420        };
5421        return Result.v;
5422    }
5423
5424    #[cfg(_XM_ARM_NEON_INTRINSICS_)]
5425    {
5426        unimplemented!()
5427    }
5428
5429    #[cfg(_XM_SSE_INTRINSICS_)]
5430    unsafe {
5431        const Scale: XMVECTORF32 = XMVECTORF32 { f :[ 1.442695040888963, 1.442695040888963, 1.442695040888963, 1.442695040888963 ] }; // 1.0f / ln(2.0f)
5432
5433        let V1: XMVECTOR = XM_FMADD_PS!(V, Scale.v, g_XMNegativeOne.v);
5434        let V2: XMVECTOR = XM_FNMADD_PS!(V, Scale.v, g_XMNegativeOne.v);
5435        let E1: XMVECTOR = XMVectorExp(V1);
5436        let E2: XMVECTOR = XMVectorExp(V2);
5437
5438        return _mm_add_ps(E1, E2);
5439    }
5440}
5441
5442/// Computes the hyperbolic tangent of each component of an XMVECTOR.
5443///
5444/// ## Parameters
5445///
5446/// `V` Vector for which to compute the hyperbolic tangent.
5447///
5448/// ## Return value
5449///
5450/// Returns a vector. Each component is the hyperbolic tangent of the corresponding component of `V`.
5451///
5452/// ## Reference
5453///
5454/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVectorTanH>
5455#[inline]
5456pub fn XMVectorTanH(
5457    V: FXMVECTOR,
5458) -> XMVECTOR
5459{
5460    #[cfg(_XM_NO_INTRINSICS_)]
5461    unsafe {
5462        let Result = XMVECTORF32 {
5463            f: [
5464                tanh(V.vector4_f32[0]),
5465                tanh(V.vector4_f32[1]),
5466                tanh(V.vector4_f32[2]),
5467                tanh(V.vector4_f32[3])
5468            ]
5469        };
5470        return Result.v;
5471    }
5472
5473    #[cfg(_XM_ARM_NEON_INTRINSICS_)]
5474    {
5475        unimplemented!()
5476    }
5477
5478    #[cfg(_XM_SSE_INTRINSICS_)]
5479    unsafe {
5480        const Scale: XMVECTORF32 = XMVECTORF32 { f :[ 2.8853900817779268, 2.8853900817779268, 2.8853900817779268, 2.8853900817779268 ] }; // 2.0f / ln(2.0f)
5481
5482        let mut E: XMVECTOR = _mm_mul_ps(V, Scale.v);
5483        E = XMVectorExp(E);
5484        E = XM_FMADD_PS!(E, g_XMOneHalf.v, g_XMOneHalf.v);
5485        E = _mm_div_ps(g_XMOne.v, E);
5486        return _mm_sub_ps(g_XMOne.v, E);
5487    }
5488}
5489
5490/// Computes the arcsine of each component of an XMVECTOR.
5491///
5492/// ## Parameters
5493///
5494/// `V` Vector for which to compute the arcsine. Each component should be between `-1.0` and `1.0`.
5495///
5496/// ## Return value
5497///
5498/// Returns a vector whose components are the arcsine of the corresponding components of `V`.
5499///
5500/// ## Remarks
5501///
5502/// This function uses a 7-degree minimax approximation.
5503///
5504/// ## Reference
5505///
5506/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVectorASin>
5507#[inline]
5508pub fn XMVectorASin(
5509    V: FXMVECTOR,
5510) -> XMVECTOR
5511{
5512    // 7-degree minimax approximation
5513
5514    #[cfg(_XM_NO_INTRINSICS_)]
5515    unsafe {
5516        let Result = XMVECTORF32 {
5517            f: [
5518                asinf(V.vector4_f32[0]),
5519                asinf(V.vector4_f32[1]),
5520                asinf(V.vector4_f32[2]),
5521                asinf(V.vector4_f32[3])
5522            ]
5523        };
5524        return Result.v;
5525    }
5526
5527    #[cfg(_XM_ARM_NEON_INTRINSICS_)]
5528    {
5529        unimplemented!()
5530    }
5531
5532    #[cfg(_XM_SSE_INTRINSICS_)]
5533    unsafe {
5534        let nonnegative: __m128 = _mm_cmpge_ps(V, g_XMZero.v);
5535        let mvalue: __m128 = _mm_sub_ps(g_XMZero.v, V);
5536        let x: __m128 = _mm_max_ps(V, mvalue);  // |V|
5537
5538        // Compute (1-|V|), clamp to zero to avoid sqrt of negative number.
5539        let oneMValue: __m128 = _mm_sub_ps(g_XMOne.v, x);
5540        let clampOneMValue: __m128 = _mm_max_ps(g_XMZero.v, oneMValue);
5541        let root: __m128 = _mm_sqrt_ps(clampOneMValue);  // sqrt(1-|V|)
5542
5543        // Compute polynomial approximation
5544        const AC1: XMVECTOR = unsafe { g_XMArcCoefficients1.v };
5545        let vConstantsB: __m128 = XM_PERMUTE_PS!(AC1, _MM_SHUFFLE(3, 3, 3, 3));
5546        let mut vConstants: __m128 = XM_PERMUTE_PS!(AC1, _MM_SHUFFLE(2, 2, 2, 2));
5547        let mut t0: __m128 = XM_FMADD_PS!(vConstantsB, x, vConstants);
5548
5549        vConstants = XM_PERMUTE_PS!(AC1, _MM_SHUFFLE(1, 1, 1, 1));
5550        t0 = XM_FMADD_PS!(t0, x, vConstants);
5551
5552        vConstants = XM_PERMUTE_PS!(AC1, _MM_SHUFFLE(0, 0, 0, 0));
5553        t0 = XM_FMADD_PS!(t0, x, vConstants);
5554
5555        const AC0: XMVECTOR = unsafe { g_XMArcCoefficients0.v };
5556        vConstants = XM_PERMUTE_PS!(AC0, _MM_SHUFFLE(3, 3, 3, 3));
5557        t0 = XM_FMADD_PS!(t0, x, vConstants);
5558
5559        vConstants = XM_PERMUTE_PS!(AC0, _MM_SHUFFLE(2, 2, 2, 2));
5560        t0 = XM_FMADD_PS!(t0, x, vConstants);
5561
5562        vConstants = XM_PERMUTE_PS!(AC0, _MM_SHUFFLE(1, 1, 1, 1));
5563        t0 = XM_FMADD_PS!(t0, x, vConstants);
5564
5565        vConstants = XM_PERMUTE_PS!(AC0, _MM_SHUFFLE(0, 0, 0, 0));
5566        t0 = XM_FMADD_PS!(t0, x, vConstants);
5567        t0 = _mm_mul_ps(t0, root);
5568
5569        let mut t1: __m128 = _mm_sub_ps(g_XMPi.v, t0);
5570        t0 = _mm_and_ps(nonnegative, t0);
5571        t1 = _mm_andnot_ps(nonnegative, t1);
5572        t0 = _mm_or_ps(t0, t1);
5573        t0 = _mm_sub_ps(g_XMHalfPi.v, t0);
5574        return t0;
5575    }
5576}
5577
5578/// Computes the arccosine of each component of an XMVECTOR.
5579///
5580/// ## Parameters
5581///
5582/// `V` Vector for which to compute the arccosine. Each component should be between `-1.0` and `1.0`.
5583///
5584/// ## Return value
5585///
5586/// Returns a vector whose components are the arccosine of the corresponding components of `V`.
5587///
5588/// ## Remarks
5589///
5590/// This function uses a 7-degree minimax approximation.
5591///
5592/// ## Reference
5593///
5594/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVectorACos>
5595#[inline]
5596pub fn XMVectorACos(
5597    V: FXMVECTOR,
5598) -> XMVECTOR
5599{
5600    // 7-degree minimax approximation
5601
5602    #[cfg(_XM_NO_INTRINSICS_)]
5603    unsafe {
5604        let Result = XMVECTORF32 {
5605            f: [
5606                acosf(V.vector4_f32[0]),
5607                acosf(V.vector4_f32[1]),
5608                acosf(V.vector4_f32[2]),
5609                acosf(V.vector4_f32[3])
5610            ]
5611        };
5612        return Result.v;
5613    }
5614
5615    #[cfg(_XM_ARM_NEON_INTRINSICS_)]
5616    {
5617        unimplemented!()
5618    }
5619
5620    #[cfg(_XM_SSE_INTRINSICS_)]
5621    unsafe {
5622        let nonnegative: __m128 = _mm_cmpge_ps(V, g_XMZero.v);
5623        let mvalue: __m128 = _mm_sub_ps(g_XMZero.v, V);
5624        let x: __m128 = _mm_max_ps(V, mvalue);  // |V|
5625
5626        // Compute (1-|V|), clamp to zero to avoid sqrt of negative number.
5627        let oneMValue: __m128 = _mm_sub_ps(g_XMOne.v, x);
5628        let clampOneMValue: __m128 = _mm_max_ps(g_XMZero.v, oneMValue);
5629        let root: __m128 = _mm_sqrt_ps(clampOneMValue);  // sqrt(1-|V|)
5630
5631        // Compute polynomial approximation
5632        const AC1: XMVECTOR = unsafe { g_XMArcCoefficients1.v };
5633        let vConstantsB: __m128 = XM_PERMUTE_PS!(AC1, _MM_SHUFFLE(3, 3, 3, 3));
5634        let mut vConstants: __m128 = XM_PERMUTE_PS!(AC1, _MM_SHUFFLE(2, 2, 2, 2));
5635        let mut t0: __m128 = XM_FMADD_PS!(vConstantsB, x, vConstants);
5636
5637        vConstants = XM_PERMUTE_PS!(AC1, _MM_SHUFFLE(1, 1, 1, 1));
5638        t0 = XM_FMADD_PS!(t0, x, vConstants);
5639
5640        vConstants = XM_PERMUTE_PS!(AC1, _MM_SHUFFLE(0, 0, 0, 0));
5641        t0 = XM_FMADD_PS!(t0, x, vConstants);
5642
5643        const AC0: XMVECTOR = unsafe { g_XMArcCoefficients0.v };
5644        vConstants = XM_PERMUTE_PS!(AC0, _MM_SHUFFLE(3, 3, 3, 3));
5645        t0 = XM_FMADD_PS!(t0, x, vConstants);
5646
5647        vConstants = XM_PERMUTE_PS!(AC0, _MM_SHUFFLE(2, 2, 2, 2));
5648        t0 = XM_FMADD_PS!(t0, x, vConstants);
5649
5650        vConstants = XM_PERMUTE_PS!(AC0, _MM_SHUFFLE(1, 1, 1, 1));
5651        t0 = XM_FMADD_PS!(t0, x, vConstants);
5652
5653        vConstants = XM_PERMUTE_PS!(AC0, _MM_SHUFFLE(0, 0, 0, 0));
5654        t0 = XM_FMADD_PS!(t0, x, vConstants);
5655        t0 = _mm_mul_ps(t0, root);
5656
5657        let mut t1: __m128 = _mm_sub_ps(g_XMPi.v, t0);
5658        t0 = _mm_and_ps(nonnegative, t0);
5659        t1 = _mm_andnot_ps(nonnegative, t1);
5660        t0 = _mm_or_ps(t0, t1);
5661        return t0;
5662    }
5663}
5664
5665/// Computes the arctangent of each component of an XMVECTOR.
5666///
5667/// ## Parameters
5668///
5669/// `V` Vector for which to compute the arctangent.
5670///
5671/// ## Return value
5672///
5673/// Returns a vector whose components are the arctangent of the corresponding components of `V`.
5674///
5675/// ## Remarks
5676///
5677/// This function uses a 17-degree minimax approximation.
5678///
5679/// ## Reference
5680///
5681/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVectorATan>
5682#[inline]
5683pub fn XMVectorATan(
5684    V: FXMVECTOR,
5685) -> XMVECTOR
5686{
5687    // 7-degree minimax approximation
5688
5689    #[cfg(_XM_NO_INTRINSICS_)]
5690    unsafe {
5691        let Result = XMVECTORF32 {
5692            f: [
5693                atanf(V.vector4_f32[0]),
5694                atanf(V.vector4_f32[1]),
5695                atanf(V.vector4_f32[2]),
5696                atanf(V.vector4_f32[3])
5697            ]
5698        };
5699        return Result.v;
5700    }
5701
5702    #[cfg(_XM_ARM_NEON_INTRINSICS_)]
5703    {
5704        unimplemented!()
5705    }
5706
5707    #[cfg(_XM_SSE_INTRINSICS_)]
5708    unsafe {
5709        let absV: __m128 = XMVectorAbs(V);
5710        let invV: __m128 = _mm_div_ps(g_XMOne.v, V);
5711        let mut comp: __m128 = _mm_cmpgt_ps(V, g_XMOne.v);
5712        let mut select0: __m128 = _mm_and_ps(comp, g_XMOne.v);
5713        let mut select1: __m128 = _mm_andnot_ps(comp, g_XMNegativeOne.v);
5714        let mut sign: __m128 = _mm_or_ps(select0, select1);
5715        comp = _mm_cmple_ps(absV, g_XMOne.v);
5716        select0 = _mm_and_ps(comp, g_XMZero.v);
5717        select1 = _mm_andnot_ps(comp, sign);
5718        sign = _mm_or_ps(select0, select1);
5719        select0 = _mm_and_ps(comp, V);
5720        select1 = _mm_andnot_ps(comp, invV);
5721        let x: __m128 = _mm_or_ps(select0, select1);
5722
5723        let x2: __m128 = _mm_mul_ps(x, x);
5724
5725        // Compute polynomial approximation
5726        const TC1: XMVECTOR = unsafe { g_XMATanCoefficients1.v };
5727        let vConstantsB: __m128 = XM_PERMUTE_PS!(TC1, _MM_SHUFFLE(3, 3, 3, 3));
5728        let mut vConstants: __m128 = XM_PERMUTE_PS!(TC1, _MM_SHUFFLE(2, 2, 2, 2));
5729        let mut Result: __m128 = XM_FMADD_PS!(vConstantsB, x2, vConstants);
5730
5731        vConstants = XM_PERMUTE_PS!(TC1, _MM_SHUFFLE(1, 1, 1, 1));
5732        Result = XM_FMADD_PS!(Result, x2, vConstants);
5733
5734        vConstants = XM_PERMUTE_PS!(TC1, _MM_SHUFFLE(0, 0, 0, 0));
5735        Result = XM_FMADD_PS!(Result, x2, vConstants);
5736
5737        const TC0: XMVECTOR = unsafe { g_XMATanCoefficients0.v };
5738        vConstants = XM_PERMUTE_PS!(TC0, _MM_SHUFFLE(3, 3, 3, 3));
5739        Result = XM_FMADD_PS!(Result, x2, vConstants);
5740
5741        vConstants = XM_PERMUTE_PS!(TC0, _MM_SHUFFLE(2, 2, 2, 2));
5742        Result = XM_FMADD_PS!(Result, x2, vConstants);
5743
5744        vConstants = XM_PERMUTE_PS!(TC0, _MM_SHUFFLE(1, 1, 1, 1));
5745        Result = XM_FMADD_PS!(Result, x2, vConstants);
5746
5747        vConstants = XM_PERMUTE_PS!(TC0, _MM_SHUFFLE(0, 0, 0, 0));
5748        Result = XM_FMADD_PS!(Result, x2, vConstants);
5749
5750        Result = XM_FMADD_PS!(Result, x2, g_XMOne.v);
5751
5752        Result = _mm_mul_ps(Result, x);
5753        let mut result1: __m128 = _mm_mul_ps(sign, g_XMHalfPi.v);
5754        result1 = _mm_sub_ps(result1, Result);
5755
5756        comp = _mm_cmpeq_ps(sign, g_XMZero.v);
5757        select0 = _mm_and_ps(comp, Result);
5758        select1 = _mm_andnot_ps(comp, result1);
5759        Result = _mm_or_ps(select0, select1);
5760        return Result;
5761    }
5762}
5763
5764
5765/// Computes the arctangent of Y/X.
5766///
5767/// ## Parameters
5768///
5769/// `Y` First vector.
5770///
5771/// `X` Second vector.
5772///
5773/// ## Return value
5774///
5775/// Returns a vector. Each component is the arctangent of the corresponding `Y` component divided by the corresponding
5776/// X component. Each component is in the range (-PI/2, PI/2).
5777/// XMVectorATan2 returns the following values for the specified special input values.
5778///
5779/// | Input Value | Return Value |
5780/// | --- | --- |
5781/// | Y == 0 and X < 0 | Pi with the same sign as Y |
5782/// | Y == 0 and X > 0 | 0 with the same sign as Y |
5783/// | Y != 0 and X == 0 | Pi / 2 with the same sign as Y |
5784/// | X == -Infinity and Y is finite | Pi with the same sign as Y |
5785/// | X == +Infinity and Y is finite | 0 with the same sign as Y |
5786/// | Y == Infinity and X is finite | Pi / 2 with the same sign as Y |
5787/// | Y == Infinity and X == -Infinity | 3Pi / 4 with the same sign as Y |
5788/// | Y == Infinity and X == +Infinity | Pi / 4 with the same sign as Y |
5789///
5790/// ## Remarks
5791///
5792/// This function uses a 17-degree minimax approximation.
5793///
5794/// ## Reference
5795///
5796/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVectorATan2>
5797#[inline]
5798pub fn XMVectorATan2(
5799    Y: FXMVECTOR,
5800    X: FXMVECTOR,
5801) -> XMVECTOR
5802{
5803    #[cfg(_XM_NO_INTRINSICS_)]
5804    unsafe {
5805        let Result = XMVECTORF32 {
5806            f: [
5807                atan2f(Y.vector4_f32[0], X.vector4_f32[0]),
5808                atan2f(Y.vector4_f32[1], X.vector4_f32[1]),
5809                atan2f(Y.vector4_f32[2], X.vector4_f32[2]),
5810                atan2f(Y.vector4_f32[3], X.vector4_f32[3])
5811            ]
5812        };
5813        return Result.v;
5814    }
5815
5816    #[cfg(not(_XM_NO_INTRINSICS_))]
5817    unsafe {
5818        // Return the inverse tangent of Y / X in the range of -Pi to Pi with the following exceptions:
5819
5820        //     Y == 0 and X is Negative         -> Pi with the sign of Y
5821        //     y == 0 and x is positive         -> 0 with the sign of y
5822        //     Y != 0 and X == 0                -> Pi / 2 with the sign of Y
5823        //     Y != 0 and X is Negative         -> atan(y/x) + (PI with the sign of Y)
5824        //     X == -Infinity and Finite Y      -> Pi with the sign of Y
5825        //     X == +Infinity and Finite Y      -> 0 with the sign of Y
5826        //     Y == Infinity and X is Finite    -> Pi / 2 with the sign of Y
5827        //     Y == Infinity and X == -Infinity -> 3Pi / 4 with the sign of Y
5828        //     Y == Infinity and X == +Infinity -> Pi / 4 with the sign of Y
5829
5830        const ATan2Constants: XMVECTORF32 = XMVECTORF32 { f: [ XM_PI, XM_PIDIV2, XM_PIDIV4, XM_PI * 3.0 / 4.0 ] };
5831
5832        let Zero: XMVECTOR = XMVectorZero();
5833        let mut ATanResultValid: XMVECTOR = XMVectorTrueInt();
5834
5835        let mut Pi: XMVECTOR = XMVectorSplatX(ATan2Constants.v);
5836        let mut PiOverTwo: XMVECTOR = XMVectorSplatY(ATan2Constants.v);
5837        let mut PiOverFour: XMVECTOR = XMVectorSplatZ(ATan2Constants.v);
5838        let mut ThreePiOverFour: XMVECTOR = XMVectorSplatW(ATan2Constants.v);
5839
5840        let YEqualsZero: XMVECTOR = XMVectorEqual(Y, Zero);
5841        let XEqualsZero: XMVECTOR = XMVectorEqual(X, Zero);
5842        let mut XIsPositive: XMVECTOR = XMVectorAndInt(X, g_XMNegativeZero.v);
5843        XIsPositive = XMVectorEqualInt(XIsPositive, Zero);
5844        let YEqualsInfinity: XMVECTOR = XMVectorIsInfinite(Y);
5845        let XEqualsInfinity: XMVECTOR = XMVectorIsInfinite(X);
5846
5847        let YSign: XMVECTOR = XMVectorAndInt(Y, g_XMNegativeZero.v);
5848        Pi = XMVectorOrInt(Pi, YSign);
5849        PiOverTwo = XMVectorOrInt(PiOverTwo, YSign);
5850        PiOverFour = XMVectorOrInt(PiOverFour, YSign);
5851        ThreePiOverFour = XMVectorOrInt(ThreePiOverFour, YSign);
5852
5853        let mut R1: XMVECTOR = XMVectorSelect(Pi, YSign, XIsPositive);
5854        let mut R2: XMVECTOR = XMVectorSelect(ATanResultValid, PiOverTwo, XEqualsZero);
5855        let R3: XMVECTOR = XMVectorSelect(R2, R1, YEqualsZero);
5856        let R4: XMVECTOR = XMVectorSelect(ThreePiOverFour, PiOverFour, XIsPositive);
5857        let R5: XMVECTOR = XMVectorSelect(PiOverTwo, R4, XEqualsInfinity);
5858        let Result: XMVECTOR = XMVectorSelect(R3, R5, YEqualsInfinity);
5859        ATanResultValid = XMVectorEqualInt(Result, ATanResultValid);
5860
5861        let V: XMVECTOR = XMVectorDivide(Y, X);
5862
5863        let R0: XMVECTOR = XMVectorATan(V);
5864
5865        R1 = XMVectorSelect(Pi, g_XMNegativeZero.v, XIsPositive);
5866        R2 = XMVectorAdd(R0, R1);
5867
5868        return XMVectorSelect(Result, R2, ATanResultValid);
5869    }
5870}
5871
5872
5873/// Estimates the sine of each component of an XMVECTOR.
5874///
5875/// ## Parameters
5876///
5877/// `V` Vector for which to compute the sine.
5878///
5879/// ## Return value
5880///
5881/// Returns a vector. Each component is an estimate of the sine of the corresponding component of `V`.
5882///
5883/// ## Remarks
5884///
5885/// `Est` functions offer increased performance at the expense of reduced accuracy. `Est` functions are appropriate
5886/// for non-critical calculations where accuracy can be sacrificed for speed. The exact amount of lost accuracy
5887/// and speed increase are platform dependent.
5888///
5889/// This function uses an 7-degree minimax approximation.
5890///
5891/// ## Reference
5892///
5893/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVectorSinEst>
5894#[inline]
5895pub fn XMVectorSinEst(
5896    V: FXMVECTOR,
5897) -> XMVECTOR
5898{
5899    // 7-degree minimax approximation
5900
5901    #[cfg(_XM_NO_INTRINSICS_)]
5902    unsafe {
5903        let Result = XMVECTORF32 {
5904            f: [
5905                sinf(V.vector4_f32[0]),
5906                sinf(V.vector4_f32[1]),
5907                sinf(V.vector4_f32[2]),
5908                sinf(V.vector4_f32[3])
5909            ]
5910        };
5911        return Result.v;
5912    }
5913
5914    #[cfg(_XM_ARM_NEON_INTRINSICS_)]
5915    {
5916        unimplemented!()
5917    }
5918
5919    #[cfg(_XM_SSE_INTRINSICS_)]
5920    unsafe {
5921        // Force the value within the bounds of pi
5922        let mut x: XMVECTOR = XMVectorModAngles(V);
5923
5924        // Map in [-pi/2,pi/2] with sin(y) = sin(x).
5925        let sign: __m128 = _mm_and_ps(x, g_XMNegativeZero.v);
5926        let c: __m128 = _mm_or_ps(g_XMPi.v, sign);  // pi when x >= 0, -pi when x < 0
5927        let absx: __m128 = _mm_andnot_ps(sign, x);  // |x|
5928        let rflx: __m128 = _mm_sub_ps(c, x);
5929        let comp: __m128 = _mm_cmple_ps(absx, g_XMHalfPi.v);
5930        let select0: __m128 = _mm_and_ps(comp, x);
5931        let select1: __m128 = _mm_andnot_ps(comp, rflx);
5932        x = _mm_or_ps(select0, select1);
5933
5934        let x2: __m128 = _mm_mul_ps(x, x);
5935
5936        // Compute polynomial approximation
5937        const SEC: XMVECTOR = unsafe { g_XMSinCoefficients1.v };
5938        let vConstantsB: __m128 = XM_PERMUTE_PS!(SEC, _MM_SHUFFLE(3, 3, 3, 3));
5939        let mut vConstants: __m128 = XM_PERMUTE_PS!(SEC, _MM_SHUFFLE(2, 2, 2, 2));
5940        let mut Result: __m128 = XM_FMADD_PS!(vConstantsB, x2, vConstants);
5941
5942        vConstants = XM_PERMUTE_PS!(SEC, _MM_SHUFFLE(1, 1, 1, 1));
5943        Result = XM_FMADD_PS!(Result, x2, vConstants);
5944        Result = XM_FMADD_PS!(Result, x2, g_XMOne.v);
5945        Result = _mm_mul_ps(Result, x);
5946        return Result;
5947    }
5948}
5949
5950
5951/// Estimates the cosine of each component of an XMVECTOR.
5952///
5953/// ## Parameters
5954///
5955/// `V` Vector for which to compute the cosine.
5956///
5957/// ## Return value
5958///
5959/// Returns a vector. Each component is an estimate of the cosine of the corresponding component of `V`.
5960///
5961/// ## Remarks
5962///
5963/// `Est` functions offer increased performance at the expense of reduced accuracy. `Est` functions are appropriate
5964/// for non-critical calculations where accuracy can be sacrificed for speed. The exact amount of lost accuracy
5965/// and speed increase are platform dependent.
5966///
5967/// This function uses a 7-degree minimax approximation.
5968///
5969/// ## Reference
5970///
5971/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVectorCosEst>
5972#[inline]
5973pub fn XMVectorCosEst(
5974    V: FXMVECTOR,
5975) -> XMVECTOR
5976{
5977    // 6-degree minimax approximation
5978
5979    #[cfg(_XM_NO_INTRINSICS_)]
5980    unsafe {
5981        let Result = XMVECTORF32 {
5982            f: [
5983                cosf(V.vector4_f32[0]),
5984                cosf(V.vector4_f32[1]),
5985                cosf(V.vector4_f32[2]),
5986                cosf(V.vector4_f32[3])
5987            ]
5988        };
5989        return Result.v;
5990    }
5991
5992    #[cfg(_XM_ARM_NEON_INTRINSICS_)]
5993    {
5994        unimplemented!()
5995    }
5996
5997    #[cfg(_XM_SSE_INTRINSICS_)]
5998    unsafe {
5999        // Map V to x in [-pi,pi].
6000        let mut x: XMVECTOR = XMVectorModAngles(V);
6001
6002        // Map in [-pi/2,pi/2] with cos(y) = sign*cos(x).
6003        let mut sign: XMVECTOR = _mm_and_ps(x, g_XMNegativeZero.v);
6004        let c: __m128 = _mm_or_ps(g_XMPi.v, sign);  // pi when x >= 0, -pi when x < 0
6005        let absx: __m128 = _mm_andnot_ps(sign, x);  // |x|
6006        let rflx: __m128 = _mm_sub_ps(c, x);
6007        let comp: __m128  = _mm_cmple_ps(absx, g_XMHalfPi.v);
6008        let mut select0: __m128 = _mm_and_ps(comp, x);
6009        let mut select1: __m128 = _mm_andnot_ps(comp, rflx);
6010        x = _mm_or_ps(select0, select1);
6011        select0 = _mm_and_ps(comp, g_XMOne.v);
6012        select1 = _mm_andnot_ps(comp, g_XMNegativeOne.v);
6013        sign = _mm_or_ps(select0, select1);
6014
6015        let x2: __m128 = _mm_mul_ps(x, x);
6016
6017        // Compute polynomial approximation
6018        const CEC: XMVECTOR = unsafe { g_XMCosCoefficients1.v };
6019        let vConstantsB: __m128 = XM_PERMUTE_PS!(CEC, _MM_SHUFFLE(3, 3, 3, 3));
6020        let mut vConstants: __m128 = XM_PERMUTE_PS!(CEC, _MM_SHUFFLE(2, 2, 2, 2));
6021        let mut Result: __m128 = XM_FMADD_PS!(vConstantsB, x2, vConstants);
6022
6023        vConstants = XM_PERMUTE_PS!(CEC, _MM_SHUFFLE(1, 1, 1, 1));
6024        Result = XM_FMADD_PS!(Result, x2, vConstants);
6025        Result = XM_FMADD_PS!(Result, x2, g_XMOne.v);
6026        Result = _mm_mul_ps(Result, sign);
6027        return Result;
6028    }
6029}
6030
6031
6032/// Estimates the sine and cosine of each component of an XMVECTOR.
6033///
6034/// ## Parameters
6035///
6036/// `pSin` Address of a vector, each of whose components is an estimate of the sine of the corresponding component
6037/// of `V`.
6038///
6039/// `pCos` Address of a vector, each of whose components is an estimate of the cosine of the corresponding component
6040/// of `V`.
6041///
6042/// `V` Vector for which to compute the sine and cosine.
6043///
6044/// ## Return value
6045///
6046/// None.
6047///
6048/// ## Remarks
6049///
6050/// `Est` functions offer increased performance at the expense of reduced accuracy. `Est` functions are appropriate
6051/// for non-critical calculations where accuracy can be sacrificed for speed. The exact amount of lost accuracy
6052/// and speed increase are platform dependent.
6053///
6054/// This function uses a 7-degree minimax approximation for sine, 6-degree for cosine.
6055///
6056/// ## Reference
6057///
6058/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVectorSinCosEst>
6059#[inline]
6060pub fn XMVectorSinCosEst(
6061    pSin: &mut XMVECTOR,
6062    pCos: &mut XMVECTOR,
6063    V: FXMVECTOR,
6064)
6065{
6066    // 7/6-degree minimax approximation
6067
6068    #[cfg(_XM_NO_INTRINSICS_)]
6069    unsafe {
6070        let Sin = XMVECTORF32 {
6071            f: [
6072                sinf(V.vector4_f32[0]),
6073                sinf(V.vector4_f32[1]),
6074                sinf(V.vector4_f32[2]),
6075                sinf(V.vector4_f32[3])
6076            ]
6077        };
6078        let Cos = XMVECTORF32 {
6079            f: [
6080                cosf(V.vector4_f32[0]),
6081                cosf(V.vector4_f32[1]),
6082                cosf(V.vector4_f32[2]),
6083                cosf(V.vector4_f32[3])
6084            ]
6085        };
6086        *pSin = Sin.v;
6087        *pCos = Cos.v;
6088    }
6089
6090    #[cfg(_XM_ARM_NEON_INTRINSICS_)]
6091    {
6092        unimplemented!()
6093    }
6094
6095    #[cfg(_XM_SSE_INTRINSICS_)]
6096    unsafe {
6097        // Force the value within the bounds of pi
6098        let mut x: XMVECTOR = XMVectorModAngles(V);
6099
6100        // Map in [-pi/2,pi/2] with sin(y) = sin(x), cos(y) = sign*cos(x).
6101        let mut sign: XMVECTOR = _mm_and_ps(x, g_XMNegativeZero.v);
6102        let c: __m128 = _mm_or_ps(g_XMPi.v, sign);  // pi when x >= 0, -pi when x < 0
6103        let absx: __m128 = _mm_andnot_ps(sign, x);  // |x|
6104        let rflx: __m128 = _mm_sub_ps(c, x);
6105        let comp: __m128 = _mm_cmple_ps(absx, g_XMHalfPi.v);
6106        let mut select0: __m128 = _mm_and_ps(comp, x);
6107        let mut select1: __m128 = _mm_andnot_ps(comp, rflx);
6108        x = _mm_or_ps(select0, select1);
6109        select0 = _mm_and_ps(comp, g_XMOne.v);
6110        select1 = _mm_andnot_ps(comp, g_XMNegativeOne.v);
6111        sign = _mm_or_ps(select0, select1);
6112
6113        let x2: __m128 = _mm_mul_ps(x, x);
6114
6115        // Compute polynomial approximation for sine
6116        const SEC: XMVECTOR = unsafe { g_XMSinCoefficients1.v };
6117        let mut vConstantsB: __m128 = XM_PERMUTE_PS!(SEC, _MM_SHUFFLE(3, 3, 3, 3));
6118        let mut vConstants: __m128 = XM_PERMUTE_PS!(SEC, _MM_SHUFFLE(2, 2, 2, 2));
6119        let mut Result: __m128 = XM_FMADD_PS!(vConstantsB, x2, vConstants);
6120
6121        vConstants = XM_PERMUTE_PS!(SEC, _MM_SHUFFLE(1, 1, 1, 1));
6122        Result = XM_FMADD_PS!(Result, x2, vConstants);
6123        Result = XM_FMADD_PS!(Result, x2, g_XMOne.v);
6124        Result = _mm_mul_ps(Result, x);
6125        *pSin = Result;
6126
6127        // Compute polynomial approximation for cosine
6128        const CEC: XMVECTOR = unsafe { g_XMCosCoefficients1.v };
6129        vConstantsB = XM_PERMUTE_PS!(CEC, _MM_SHUFFLE(3, 3, 3, 3));
6130        vConstants = XM_PERMUTE_PS!(CEC, _MM_SHUFFLE(2, 2, 2, 2));
6131        Result = XM_FMADD_PS!(vConstantsB, x2, vConstants);
6132
6133        vConstants = XM_PERMUTE_PS!(CEC, _MM_SHUFFLE(1, 1, 1, 1));
6134        Result = XM_FMADD_PS!(Result, x2, vConstants);
6135        Result = XM_FMADD_PS!(Result, x2, g_XMOne.v);
6136        Result = _mm_mul_ps(Result, sign);
6137        *pCos = Result;
6138    }
6139}
6140
6141/// Estimates the tangent of each component of an XMVECTOR.
6142///
6143/// ## Parameters
6144///
6145/// `V` Vector for which to compute the tangent.
6146///
6147/// ## Return value
6148///
6149/// Returns a vector. Each component is an estimate of the tangent of the corresponding component of `V`.
6150///
6151/// ## Remarks
6152///
6153/// `Est` functions offer increased performance at the expense of reduced accuracy. `Est` functions are appropriate
6154/// for non-critical calculations where accuracy can be sacrificed for speed. The exact amount of lost accuracy
6155/// and speed increase are platform dependent.
6156///
6157/// ## Reference
6158///
6159/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVectorTanEst>
6160#[inline]
6161pub fn XMVectorTanEst(
6162    V: FXMVECTOR,
6163) -> FXMVECTOR
6164{
6165    #[cfg(_XM_NO_INTRINSICS_)]
6166    unsafe {
6167        let Result = XMVECTORF32 {
6168            f: [
6169                tanf(V.vector4_f32[0]),
6170                tanf(V.vector4_f32[1]),
6171                tanf(V.vector4_f32[2]),
6172                tanf(V.vector4_f32[3])
6173            ]
6174        };
6175        return Result.v;
6176    }
6177
6178    #[cfg(_XM_ARM_NEON_INTRINSICS_)]
6179    {
6180        unimplemented!()
6181    }
6182
6183    #[cfg(_XM_SSE_INTRINSICS_)]
6184    unsafe {
6185        let OneOverPi: XMVECTOR = XMVectorSplatW(g_XMTanEstCoefficients.v);
6186
6187        let mut V1: XMVECTOR = XMVectorMultiply(V, OneOverPi);
6188        V1 = XMVectorRound(V1);
6189
6190        V1 = XMVectorNegativeMultiplySubtract(g_XMPi.v, V1, V);
6191
6192        let T0: XMVECTOR = XMVectorSplatX(g_XMTanEstCoefficients.v);
6193        let T1: XMVECTOR = XMVectorSplatY(g_XMTanEstCoefficients.v);
6194        let T2: XMVECTOR = XMVectorSplatZ(g_XMTanEstCoefficients.v);
6195
6196        let V2T2: XMVECTOR = XMVectorNegativeMultiplySubtract(V1, V1, T2);
6197        let V2: XMVECTOR = XMVectorMultiply(V1, V1);
6198        let V1T0: XMVECTOR = XMVectorMultiply(V1, T0);
6199        let V1T1: XMVECTOR = XMVectorMultiply(V1, T1);
6200
6201        let D: XMVECTOR = XMVectorReciprocalEst(V2T2);
6202        let N: XMVECTOR = XMVectorMultiplyAdd(V2, V1T1, V1T0);
6203
6204        return XMVectorMultiply(N, D);
6205    }
6206}
6207
6208/// Estimates the arcsine of each component of an XMVECTOR.
6209///
6210/// ## Parameters
6211///
6212/// `V` Vector for which to compute the arcsine. Each component should be between `-1.0` and `1.0`.
6213///
6214/// ## Return value
6215///
6216/// Returns a vector whose components are estimates of the arcsine of the corresponding components of `V`.
6217///
6218/// ## Remarks
6219///
6220/// `Est` functions offer increased performance at the expense of reduced accuracy. `Est` functions are appropriate
6221/// for non-critical calculations where accuracy can be sacrificed for speed. The exact amount of lost accuracy
6222/// and speed increase are platform dependent.
6223///
6224/// This function uses an 3-term minimax approximation.
6225///
6226/// ## Reference
6227///
6228/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVectorASinEst>
6229#[inline]
6230pub fn XMVectorASinEst(
6231    V: FXMVECTOR,
6232) -> FXMVECTOR
6233{
6234    #[cfg(_XM_NO_INTRINSICS_)]
6235    unsafe {
6236        let Result = XMVECTORF32 {
6237            f: [
6238                asinf(V.vector4_f32[0]),
6239                asinf(V.vector4_f32[1]),
6240                asinf(V.vector4_f32[2]),
6241                asinf(V.vector4_f32[3])
6242            ]
6243        };
6244        return Result.v;
6245    }
6246
6247    #[cfg(_XM_ARM_NEON_INTRINSICS_)]
6248    {
6249        unimplemented!()
6250    }
6251
6252    #[cfg(_XM_SSE_INTRINSICS_)]
6253    unsafe {
6254        let nonnegative: __m128 = _mm_cmpge_ps(V, g_XMZero.v);
6255        let mvalue: __m128 = _mm_sub_ps(g_XMZero.v, V);
6256        let x: __m128 = _mm_max_ps(V, mvalue);  // |V|
6257
6258        // Compute (1-|V|), clamp to zero to avoid sqrt of negative number.
6259        let oneMValue: __m128 = _mm_sub_ps(g_XMOne.v, x);
6260        let clampOneMValue: __m128 = _mm_max_ps(g_XMZero.v, oneMValue);
6261        let root: __m128 = _mm_sqrt_ps(clampOneMValue);  // sqrt(1-|V|)
6262
6263        // Compute polynomial approximation
6264        const AEC: XMVECTOR = unsafe { g_XMArcEstCoefficients.v };
6265        let vConstantsB: __m128 = XM_PERMUTE_PS!(AEC, _MM_SHUFFLE(3, 3, 3, 3));
6266        let mut vConstants: __m128 = XM_PERMUTE_PS!(AEC, _MM_SHUFFLE(2, 2, 2, 2));
6267        let mut t0: __m128 = XM_FMADD_PS!(vConstantsB, x, vConstants);
6268
6269        vConstants = XM_PERMUTE_PS!(AEC, _MM_SHUFFLE(1, 1, 1, 1));
6270        t0 = XM_FMADD_PS!(t0, x, vConstants);
6271
6272        vConstants = XM_PERMUTE_PS!(AEC, _MM_SHUFFLE(0, 0, 0, 0));
6273        t0 = XM_FMADD_PS!(t0, x, vConstants);
6274        t0 = _mm_mul_ps(t0, root);
6275
6276        let mut t1: __m128 = _mm_sub_ps(g_XMPi.v, t0);
6277        t0 = _mm_and_ps(nonnegative, t0);
6278        t1 = _mm_andnot_ps(nonnegative, t1);
6279        t0 = _mm_or_ps(t0, t1);
6280        t0 = _mm_sub_ps(g_XMHalfPi.v, t0);
6281        return t0;
6282    }
6283}
6284
6285/// Estimates the arccosine of each component of an XMVECTOR.
6286///
6287/// ## Parameters
6288///
6289/// `V` Vector for which to compute the arccosine. Each component should be between `-1.0` and `1.0`.
6290///
6291/// ## Return value
6292///
6293/// Returns a vector whose components are estimates of the arccosine of the corresponding components of
6294/// V.
6295///
6296/// ## Remarks
6297///
6298/// `Est` functions offer increased performance at the expense of reduced accuracy. `Est` functions are appropriate
6299/// for non-critical calculations where accuracy can be sacrificed for speed. The exact amount of lost accuracy
6300/// and speed increase are platform dependent.
6301///
6302/// This function uses a 3-degree minimax approximation.
6303///
6304/// ## Reference
6305///
6306/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVectorACosEst>
6307#[inline]
6308pub fn XMVectorACosEst(
6309    V: FXMVECTOR,
6310) -> FXMVECTOR
6311{
6312    #[cfg(_XM_NO_INTRINSICS_)]
6313    unsafe {
6314        let Result = XMVECTORF32 {
6315            f: [
6316                acosf(V.vector4_f32[0]),
6317                acosf(V.vector4_f32[1]),
6318                acosf(V.vector4_f32[2]),
6319                acosf(V.vector4_f32[3])
6320            ]
6321        };
6322        return Result.v;
6323    }
6324
6325    #[cfg(_XM_ARM_NEON_INTRINSICS_)]
6326    {
6327        unimplemented!()
6328    }
6329
6330    #[cfg(_XM_SSE_INTRINSICS_)]
6331    unsafe {
6332        let nonnegative: __m128 = _mm_cmpge_ps(V, g_XMZero.v);
6333        let mvalue: __m128 = _mm_sub_ps(g_XMZero.v, V);
6334        let x: __m128 = _mm_max_ps(V, mvalue);  // |V|
6335
6336        // Compute (1-|V|), clamp to zero to avoid sqrt of negative number.
6337        let oneMValue: __m128 = _mm_sub_ps(g_XMOne.v, x);
6338        let clampOneMValue: __m128 = _mm_max_ps(g_XMZero.v, oneMValue);
6339        let root: __m128 = _mm_sqrt_ps(clampOneMValue);  // sqrt(1-|V|)
6340
6341        // Compute polynomial approximation
6342        const AEC: XMVECTOR = unsafe { g_XMArcEstCoefficients.v };
6343        let vConstantsB: __m128 = XM_PERMUTE_PS!(AEC, _MM_SHUFFLE(3, 3, 3, 3));
6344        let mut vConstants: __m128 = XM_PERMUTE_PS!(AEC, _MM_SHUFFLE(2, 2, 2, 2));
6345        let mut t0: __m128 = XM_FMADD_PS!(vConstantsB, x, vConstants);
6346
6347        vConstants = XM_PERMUTE_PS!(AEC, _MM_SHUFFLE(1, 1, 1, 1));
6348        t0 = XM_FMADD_PS!(t0, x, vConstants);
6349
6350        vConstants = XM_PERMUTE_PS!(AEC, _MM_SHUFFLE(0, 0, 0, 0));
6351        t0 = XM_FMADD_PS!(t0, x, vConstants);
6352        t0 = _mm_mul_ps(t0, root);
6353
6354        let mut t1: __m128 = _mm_sub_ps(g_XMPi.v, t0);
6355        t0 = _mm_and_ps(nonnegative, t0);
6356        t1 = _mm_andnot_ps(nonnegative, t1);
6357        t0 = _mm_or_ps(t0, t1);
6358        return t0;
6359    }
6360}
6361
6362/// Estimates the arctangent of each component of an XMVECTOR.
6363///
6364/// ## Parameters
6365///
6366/// `V` Vector for which to compute the arctangent.
6367///
6368/// ## Return value
6369///
6370/// Returns a vector whose components are estimates of the arctangent of the corresponding components of
6371/// V.
6372///
6373/// ## Remarks
6374///
6375/// `Est` functions offer increased performance at the expense of reduced accuracy. `Est` functions are appropriate
6376/// for non-critical calculations where accuracy can be sacrificed for speed. The exact amount of lost accuracy
6377/// and speed increase are platform dependent.
6378///
6379/// This function uses a 9-degree minimax approximation.
6380///
6381/// ## Reference
6382///
6383/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVectorATanEst>
6384#[inline]
6385pub fn XMVectorATanEst(
6386    V: FXMVECTOR,
6387) -> FXMVECTOR
6388{
6389    #[cfg(_XM_NO_INTRINSICS_)]
6390    unsafe {
6391        let Result = XMVECTORF32 {
6392            f: [
6393                atanf(V.vector4_f32[0]),
6394                atanf(V.vector4_f32[1]),
6395                atanf(V.vector4_f32[2]),
6396                atanf(V.vector4_f32[3])
6397            ]
6398        };
6399        return Result.v;
6400    }
6401
6402    #[cfg(_XM_ARM_NEON_INTRINSICS_)]
6403    {
6404        unimplemented!()
6405    }
6406
6407    #[cfg(_XM_SSE_INTRINSICS_)]
6408    unsafe {
6409        let absV: __m128 = XMVectorAbs(V);
6410        let invV: __m128 = _mm_div_ps(g_XMOne.v, V);
6411        let mut comp: __m128 = _mm_cmpgt_ps(V, g_XMOne.v);
6412        let mut select0: __m128 = _mm_and_ps(comp, g_XMOne.v);
6413        let mut select1: __m128 = _mm_andnot_ps(comp, g_XMNegativeOne.v);
6414        let mut sign: __m128 = _mm_or_ps(select0, select1);
6415        comp = _mm_cmple_ps(absV, g_XMOne.v);
6416        select0 = _mm_and_ps(comp, g_XMZero.v);
6417        select1 = _mm_andnot_ps(comp, sign);
6418        sign = _mm_or_ps(select0, select1);
6419        select0 = _mm_and_ps(comp, V);
6420        select1 = _mm_andnot_ps(comp, invV);
6421        let x: __m128 = _mm_or_ps(select0, select1);
6422
6423        let x2: __m128 = _mm_mul_ps(x, x);
6424
6425        // Compute polynomial approximation
6426        const AEC: XMVECTOR = unsafe { g_XMATanEstCoefficients1.v };
6427        let vConstantsB: __m128 = XM_PERMUTE_PS!(AEC, _MM_SHUFFLE(3, 3, 3, 3));
6428        let mut vConstants: __m128 = XM_PERMUTE_PS!(AEC, _MM_SHUFFLE(2, 2, 2, 2));
6429        let mut Result: __m128 = XM_FMADD_PS!(vConstantsB, x2, vConstants);
6430
6431        vConstants = XM_PERMUTE_PS!(AEC, _MM_SHUFFLE(1, 1, 1, 1));
6432        Result = XM_FMADD_PS!(Result, x2, vConstants);
6433
6434        vConstants = XM_PERMUTE_PS!(AEC, _MM_SHUFFLE(0, 0, 0, 0));
6435        Result = XM_FMADD_PS!(Result, x2, vConstants);
6436        // ATanEstCoefficients0 is already splatted
6437        Result = XM_FMADD_PS!(Result, x2, g_XMATanEstCoefficients0.v);
6438        Result = _mm_mul_ps(Result, x);
6439        let mut result1: __m128 = _mm_mul_ps(sign, g_XMHalfPi.v);
6440        result1 = _mm_sub_ps(result1, Result);
6441
6442        comp = _mm_cmpeq_ps(sign, g_XMZero.v);
6443        select0 = _mm_and_ps(comp, Result);
6444        select1 = _mm_andnot_ps(comp, result1);
6445        Result = _mm_or_ps(select0, select1);
6446        return Result;
6447    }
6448}
6449
6450
6451/// Estimates the arctangent of Y/X.
6452///
6453/// ## Parameters
6454///
6455/// `Y` First vector.
6456///
6457/// `X` Second vector.
6458///
6459/// ## Return value
6460///
6461/// Returns a vector. Each component is an estimate of the arctangent of the corresponding `Y` component divided
6462/// by the corresponding `X` component. Each component is in the range (`-PI/2`, `PI/2`).
6463/// XMVectorATan2Est returns the following values for the specified special input values.
6464///
6465/// | Input Value | Return Value |
6466/// | --- | --- |
6467/// | Y == 0 and X < 0 | Pi with the same sign as Y |
6468/// | Y == 0 and X > 0 | 0 with the same sign as Y |
6469/// | Y != 0 and X == 0 | Pi / 2 with the same sign as Y |
6470/// | X == -Infinity and Y is finite | Pi with the same sign as Y |
6471/// | X == +Infinity and Y is finite | 0 with the same sign as Y |
6472/// | Y == Infinity and X is finite | Pi / 2 with the same sign as Y |
6473/// | Y == Infinity and X == -Infinity | 3Pi / 4 with the same sign as Y |
6474/// | Y == Infinity and X == +Infinity | Pi / 4 with the same sign as Y |
6475///
6476/// ## Remarks
6477///
6478/// `Est` functions offer increased performance at the expense of reduced accuracy. `Est` functions are appropriate
6479/// for non-critical calculations where accuracy can be sacrificed for speed. The exact amount of lost accuracy
6480/// and speed increase are platform dependent.
6481///
6482/// This function uses a 9-degree minimax approximation.
6483///
6484/// ## Reference
6485///
6486/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVectorATan2Est>
6487#[inline]
6488pub fn XMVectorATan2Est(
6489    Y: FXMVECTOR,
6490    X: FXMVECTOR,
6491) -> XMVECTOR
6492{
6493    #[cfg(_XM_NO_INTRINSICS_)]
6494    unsafe {
6495        let Result = XMVECTORF32 {
6496            f: [
6497                atan2f(Y.vector4_f32[0], X.vector4_f32[0]),
6498                atan2f(Y.vector4_f32[1], X.vector4_f32[1]),
6499                atan2f(Y.vector4_f32[2], X.vector4_f32[2]),
6500                atan2f(Y.vector4_f32[3], X.vector4_f32[3])
6501            ]
6502        };
6503        return Result.v;
6504    }
6505
6506    #[cfg(not(_XM_NO_INTRINSICS_))]
6507    unsafe {
6508        const ATan2Constants: XMVECTORF32 = XMVECTORF32 { f: [ XM_PI, XM_PIDIV2, XM_PIDIV4, XM_PI * 3.0 / 4.0 ] };
6509
6510        let Zero: XMVECTOR = XMVectorZero();
6511        let mut ATanResultValid: XMVECTOR = XMVectorTrueInt();
6512
6513        let mut Pi: XMVECTOR = XMVectorSplatX(ATan2Constants.v);
6514        let mut PiOverTwo: XMVECTOR = XMVectorSplatY(ATan2Constants.v);
6515        let mut PiOverFour: XMVECTOR = XMVectorSplatZ(ATan2Constants.v);
6516        let mut ThreePiOverFour: XMVECTOR = XMVectorSplatW(ATan2Constants.v);
6517
6518        let YEqualsZero: XMVECTOR = XMVectorEqual(Y, Zero);
6519        let XEqualsZero: XMVECTOR = XMVectorEqual(X, Zero);
6520        let mut XIsPositive: XMVECTOR = XMVectorAndInt(X, g_XMNegativeZero.v);
6521        XIsPositive = XMVectorEqualInt(XIsPositive, Zero);
6522        let YEqualsInfinity: XMVECTOR = XMVectorIsInfinite(Y);
6523        let XEqualsInfinity: XMVECTOR = XMVectorIsInfinite(X);
6524
6525        let YSign: XMVECTOR = XMVectorAndInt(Y, g_XMNegativeZero.v);
6526        Pi = XMVectorOrInt(Pi, YSign);
6527        PiOverTwo = XMVectorOrInt(PiOverTwo, YSign);
6528        PiOverFour = XMVectorOrInt(PiOverFour, YSign);
6529        ThreePiOverFour = XMVectorOrInt(ThreePiOverFour, YSign);
6530
6531        let mut R1: XMVECTOR = XMVectorSelect(Pi, YSign, XIsPositive);
6532        let mut R2: XMVECTOR = XMVectorSelect(ATanResultValid, PiOverTwo, XEqualsZero);
6533        let R3: XMVECTOR = XMVectorSelect(R2, R1, YEqualsZero);
6534        let R4: XMVECTOR = XMVectorSelect(ThreePiOverFour, PiOverFour, XIsPositive);
6535        let R5: XMVECTOR = XMVectorSelect(PiOverTwo, R4, XEqualsInfinity);
6536        let Result: XMVECTOR = XMVectorSelect(R3, R5, YEqualsInfinity);
6537        ATanResultValid = XMVectorEqualInt(Result, ATanResultValid);
6538
6539        let Reciprocal: XMVECTOR = XMVectorReciprocalEst(X);
6540        let V: XMVECTOR = XMVectorMultiply(Y, Reciprocal);
6541        let R0: XMVECTOR = XMVectorATanEst(V);
6542
6543        R1 = XMVectorSelect(Pi, g_XMNegativeZero.v, XIsPositive);
6544        R2 = XMVectorAdd(R0, R1);
6545
6546        return XMVectorSelect(Result, R2, ATanResultValid);
6547    }
6548}
6549
6550
6551/// Performs a linear interpolation between two vectors.
6552///
6553/// ## Parameters
6554///
6555/// `V0` First vector to interpolate from.
6556///
6557/// `V1` Second vector to interpolate from.
6558///
6559/// `t` Interpolation control factor.
6560///
6561/// ## Return value
6562///
6563/// Returns a vector containing the interpolation.
6564///
6565/// ## Remarks
6566///
6567/// The following pseudocode demonstrates the operation of the function:
6568///
6569/// ```text
6570/// XMVECTOR Result;
6571///
6572/// Result.x = V0.x + t * (V1.x - V0.x);
6573/// Result.y = V0.y + t * (V1.y - V0.y);
6574/// Result.z = V0.z + t * (V1.z - V0.z);
6575/// Result.w = V0.w + t * (V1.w - V0.w);
6576///
6577/// return Result;
6578/// ```
6579///
6580/// Note it is fairly simple to use this function for doing a cubic interpolation instead of a linear interpolation
6581/// as follows:
6582///
6583/// ```text
6584/// XMVECTOR SmoothStep( XMVECTOR V0, XMVECTOR V1, float t )
6585/// {
6586///     t = (t > 1.0f) ? 1.0f : ((t < 0.0f) ? 0.0f : t);  // Clamp value to 0 to 1
6587///     t = t*t*(3.f - 2.f*t);
6588///     return XMVectorLerp( V0, V1, t );
6589/// }
6590/// ```
6591///
6592/// ## Reference
6593///
6594/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVectorLerp>
6595#[inline]
6596pub fn XMVectorLerp(
6597    V0: FXMVECTOR,
6598    V1: FXMVECTOR,
6599    t: f32,
6600) -> XMVECTOR
6601{
6602    // V0 + t * (V1 - V0)
6603
6604    #[cfg(_XM_NO_INTRINSICS_)]
6605    {
6606        let Scale: XMVECTOR = XMVectorReplicate(t);
6607        let Length: XMVECTOR = XMVectorSubtract(V1, V0);
6608        return XMVectorMultiplyAdd(Length, Scale, V0);
6609    }
6610
6611    #[cfg(_XM_ARM_NEON_INTRINSICS_)]
6612    {
6613        unimplemented!()
6614    }
6615
6616    #[cfg(_XM_SSE_INTRINSICS_)]
6617    unsafe {
6618        let L: XMVECTOR = _mm_sub_ps(V1, V0);
6619        let S: XMVECTOR = _mm_set_ps1(t);
6620        return XM_FMADD_PS!(L, S, V0);
6621    }
6622}
6623
6624/// Performs a linear interpolation between two vectors.
6625///
6626/// ## Parameters
6627///
6628/// `V0` First vector to interpolate from.
6629///
6630/// `V1` Second vector to interpolate from.
6631///
6632/// `T` Interpolating control factor for the corresponding components of the position.
6633///
6634/// ## Return value
6635///
6636/// Returns a vector containing the interpolation.
6637///
6638/// ## Remarks
6639///
6640/// The following pseudocode demonstrates the operation of the function:
6641///
6642/// ```text
6643/// XMVECTOR Result;
6644///
6645/// Result.x = V0.x + T.x * (V1.x - V0.x);
6646/// Result.y = V0.y + T.y * (V1.y - V0.y);
6647/// Result.z = V0.z + T.z * (V1.z - V0.z);
6648/// Result.w = V0.w + T.w * (V1.w - V0.w);
6649///
6650/// return Result;
6651/// ```
6652///
6653/// ## Reference
6654///
6655/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVectorLerpV>
6656#[inline]
6657pub fn XMVectorLerpV(
6658    V0: FXMVECTOR,
6659    V1: FXMVECTOR,
6660    T: FXMVECTOR,
6661) -> XMVECTOR
6662{
6663    // V0 + T * (V1 - V0)
6664
6665    #[cfg(_XM_NO_INTRINSICS_)]
6666    {
6667        let Length: XMVECTOR = XMVectorSubtract(V1, V0);
6668        return XMVectorMultiplyAdd(Length, T, V0);
6669    }
6670
6671    #[cfg(_XM_ARM_NEON_INTRINSICS_)]
6672    {
6673        unimplemented!()
6674    }
6675
6676    #[cfg(_XM_SSE_INTRINSICS_)]
6677    unsafe {
6678        let Length: XMVECTOR = _mm_sub_ps(V1, V0);
6679        return XM_FMADD_PS!(Length, T, V0);
6680    }
6681}
6682
6683/// Performs a Hermite spline interpolation, using the specified vectors.
6684///
6685/// ## Parameters
6686///
6687/// `Position0` First position to interpolate from.
6688///
6689/// `Tangent0` Tangent vector for the first position.
6690///
6691/// `Position1` Second position to interpolate from.
6692///
6693/// `Tangent1` Tangent vector for the second position.
6694///
6695/// `t` Interpolation control factor.
6696///
6697/// ## Return value
6698///
6699/// Returns a vector containing the interpolation.
6700///
6701/// ## Remarks
6702///
6703/// The following pseudocode demonstrates the operation of the function:
6704///
6705/// ```text
6706/// XMVECTOR Result;
6707///
6708/// float t2 = t * t;
6709/// float t3 = t2* t;
6710///
6711/// float P0 = 2.0f * t3 - 3.0f * t2 + 1.0f;
6712/// float T0 = t3 - 2.0f * t2 + t;
6713/// float P1 = -2.0f * t3 + 3.0f * t2;
6714/// float T1 = t3 - t2;
6715///
6716/// Result.x = P0 * Position0.x + T0 * Tangent0.x + P1 * Position1.x + T1 * Tangent1.x;
6717/// Result.y = P0 * Position0.y + T0 * Tangent0.y + P1 * Position1.y + T1 * Tangent1.y;
6718/// Result.z = P0 * Position0.z + T0 * Tangent0.z + P1 * Position1.z + T1 * Tangent1.z;
6719/// Result.w = P0 * Position0.w + T0 * Tangent0.w + P1 * Position1.w + T1 * Tangent1.w;
6720///
6721/// return Result;
6722/// ```
6723///
6724/// Hermite splines are useful for controlling animation because the curve runs through all of the
6725/// control points. Also, because the position and tangent are explicitly specified at the ends of
6726/// each segment, it is easy to create a continuous curve, provided that the starting position
6727/// and tangent match the ending values of the last segment.
6728///
6729/// ## Reference
6730///
6731/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVectorHermite>
6732#[inline]
6733pub fn XMVectorHermite(
6734    Position0: FXMVECTOR,
6735    Tangent0: FXMVECTOR,
6736    Position1: FXMVECTOR,
6737    Tangent1: GXMVECTOR,
6738    t: f32,
6739) -> XMVECTOR
6740{
6741    // Result = (2 * t^3 - 3 * t^2 + 1) * Position0 +
6742    //          (t^3 - 2 * t^2 + t) * Tangent0 +
6743    //          (-2 * t^3 + 3 * t^2) * Position1 +
6744    //          (t^3 - t^2) * Tangent1
6745
6746    #[cfg(_XM_NO_INTRINSICS_)]
6747    {
6748        let t2: f32 = t * t;
6749        let t3: f32 = t * t2;
6750
6751        let P0: XMVECTOR = XMVectorReplicate(2.0 * t3 - 3.0 * t2 + 1.0);
6752        let T0: XMVECTOR = XMVectorReplicate(t3 - 2.0 * t2 + t);
6753        let P1: XMVECTOR = XMVectorReplicate(-2.0 * t3 + 3.0 * t2);
6754        let T1: XMVECTOR = XMVectorReplicate(t3 - t2);
6755
6756        let mut Result: XMVECTOR = XMVectorMultiply(P0, Position0);
6757        Result = XMVectorMultiplyAdd(T0, Tangent0, Result);
6758        Result = XMVectorMultiplyAdd(P1, Position1, Result);
6759        Result = XMVectorMultiplyAdd(T1, Tangent1, Result);
6760
6761        return Result;
6762    }
6763
6764    #[cfg(_XM_ARM_NEON_INTRINSICS_)]
6765    {
6766        unimplemented!()
6767    }
6768
6769    #[cfg(_XM_SSE_INTRINSICS_)]
6770    unsafe {
6771        let t2: f32 = t * t;
6772        let t3: f32 = t * t2;
6773
6774        let P0: XMVECTOR = _mm_set_ps1(2.0 * t3 - 3.0 * t2 + 1.0);
6775        let T0: XMVECTOR = _mm_set_ps1(t3 - 2.0 * t2 + t);
6776        let P1: XMVECTOR = _mm_set_ps1(-2.0 * t3 + 3.0 * t2);
6777        let T1: XMVECTOR = _mm_set_ps1(t3 - t2);
6778
6779        let mut vResult: XMVECTOR = _mm_mul_ps(P0, Position0);
6780        vResult = XM_FMADD_PS!(Tangent0, T0, vResult);
6781        vResult = XM_FMADD_PS!(Position1, P1, vResult);
6782        vResult = XM_FMADD_PS!(Tangent1, T1, vResult);
6783        return vResult;
6784    }
6785}
6786
6787/// Performs a Hermite spline interpolation, using the specified vectors.
6788///
6789/// ## Parameters
6790///
6791/// `Position0` First position to interpolate from.
6792///
6793/// `Tangent0` Tangent vector for the first position.
6794///
6795/// `Position1` Second position to interpolate from.
6796///
6797/// `Tangent1` Tangent vector for the second position.
6798///
6799/// `T` Interpolating control factor with each component corresponding to a term of the Hermite equation.
6800///
6801/// ## Return value
6802///
6803/// Returns a vector containing the interpolation.
6804///
6805/// ## Remarks
6806///
6807/// This function is identical to [`XMVectorHermite`] except that independent weighting factors may be supplied
6808/// in `T`. As an example, you might want to calculate two sets of Hermite spline interpolation, using the
6809/// x and `y`-components of the position vectors for one set of `2D` positions and the `z` and `w`-components of
6810/// the position vectors for the other set of 2D positions. The `x` and `y`-components of `T` would determine
6811/// the interpolation factors for the first Hermite spline interpolation. Similarly, the `z` and `w`-components
6812/// of `T` would determine the interpolation factors for the second Hermite spline interpolation.
6813///
6814/// The following pseudocode demonstrates the operation of the function:
6815///
6816/// ```text
6817/// Result[i] = (2*(T.x)^3 - 3*(T.x)^2 + 1) * Position0.[i]
6818///           + ((T.y)^3 - 2*(T.y)^2 + (T.y)) * Tangent0.[i]
6819///           + (-2*(T.z)^3 + 3*(T.z)^2) * Position1.[i]
6820///           + ((T.w)^3 - *(T.w)^2) * Tangent1.[i]
6821/// ```
6822///
6823/// ## Reference
6824///
6825/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVectorHermiteV>
6826#[inline]
6827pub fn XMVectorHermiteV(
6828    Position0: FXMVECTOR,
6829    Tangent0: FXMVECTOR,
6830    Position1: FXMVECTOR,
6831    Tangent1: GXMVECTOR,
6832    T: HXMVECTOR,
6833) -> XMVECTOR
6834{
6835    // Result = (2 * t^3 - 3 * t^2 + 1) * Position0 +
6836    //          (t^3 - 2 * t^2 + t) * Tangent0 +
6837    //          (-2 * t^3 + 3 * t^2) * Position1 +
6838    //          (t^3 - t^2) * Tangent1
6839
6840    #[cfg(_XM_NO_INTRINSICS_)]
6841    unsafe {
6842        let T2: XMVECTOR = XMVectorMultiply(T, T);
6843        let T3: XMVECTOR = XMVectorMultiply(T, T2);
6844
6845        let P0: XMVECTOR = XMVectorReplicate(2.0 * T3.vector4_f32[0] - 3.0 * T2.vector4_f32[0] + 1.0);
6846        let T0: XMVECTOR = XMVectorReplicate(T3.vector4_f32[1] - 2.0 * T2.vector4_f32[1] + T.vector4_f32[1]);
6847        let P1: XMVECTOR = XMVectorReplicate(-2.0 * T3.vector4_f32[2] + 3.0 * T2.vector4_f32[2]);
6848        let T1: XMVECTOR = XMVectorReplicate(T3.vector4_f32[3] - T2.vector4_f32[3]);
6849
6850        let mut Result: XMVECTOR = XMVectorMultiply(P0, Position0);
6851        Result = XMVectorMultiplyAdd(T0, Tangent0, Result);
6852        Result = XMVectorMultiplyAdd(P1, Position1, Result);
6853        Result = XMVectorMultiplyAdd(T1, Tangent1, Result);
6854
6855        return Result;
6856    }
6857
6858    #[cfg(_XM_ARM_NEON_INTRINSICS_)]
6859    {
6860        unimplemented!()
6861    }
6862
6863    #[cfg(_XM_SSE_INTRINSICS_)]
6864    unsafe {
6865        const CatMulT2: XMVECTORF32 = XMVECTORF32 { f: [ -3.0, -2.0, 3.0, -1.0 ] };
6866        const CatMulT3: XMVECTORF32 = XMVECTORF32 { f: [ 2.0, 1.0, -2.0, 1.0 ] };
6867
6868        let mut T2: XMVECTOR = _mm_mul_ps(T, T);
6869        let mut T3: XMVECTOR = _mm_mul_ps(T, T2);
6870        // Mul by the constants against t^2
6871        T2 = _mm_mul_ps(T2, CatMulT2.v);
6872        // Mul by the constants against t^3
6873        T3 = XM_FMADD_PS!(T3, CatMulT3.v, T2);
6874        // T3 now has the pre-result.
6875        // I need to add t.y only
6876        T2 = _mm_and_ps(T, g_XMMaskY.v);
6877        T3 = _mm_add_ps(T3, T2);
6878        // Add 1.0f to x
6879        T3 = _mm_add_ps(T3, g_XMIdentityR0.v);
6880        // Now, I have the constants created
6881        // Mul the x constant to Position0
6882        let mut vResult: XMVECTOR = XM_PERMUTE_PS!(T3, _MM_SHUFFLE(0, 0, 0, 0));
6883        vResult = _mm_mul_ps(vResult, Position0);
6884        // Mul the y constant to Tangent0
6885        T2 = XM_PERMUTE_PS!(T3, _MM_SHUFFLE(1, 1, 1, 1));
6886        vResult = XM_FMADD_PS!(T2, Tangent0, vResult);
6887        // Mul the z constant to Position1
6888        T2 = XM_PERMUTE_PS!(T3, _MM_SHUFFLE(2, 2, 2, 2));
6889        vResult = XM_FMADD_PS!(T2, Position1, vResult);
6890        // Mul the w constant to Tangent1
6891        T3 = XM_PERMUTE_PS!(T3, _MM_SHUFFLE(3, 3, 3, 3));
6892        vResult = XM_FMADD_PS!(T3, Tangent1, vResult);
6893        return vResult;
6894    }
6895}
6896
6897/// Performs a Catmull-Rom interpolation, using the specified position vectors.
6898///
6899/// ## Parameters
6900///
6901/// `Position0` First position.
6902///
6903/// `Position1` Second position.
6904///
6905/// `Position2` Third position.
6906///
6907/// `Position3` Fourth position.
6908///
6909/// `t` Interpolating control factor.
6910///
6911/// ## Return value
6912///
6913/// Returns the results of the Catmull-Rom interpolation.
6914///
6915/// The following pseudocode demonstrates the operation of the function:
6916///
6917/// ```text
6918/// XMVECTOR Result;
6919///
6920/// float t2 = t * t;
6921/// float t3 = t2* t;
6922///
6923/// float P0 = -t3 + 2.0f * t2 - t;
6924/// float P1 = 3.0f * t3 - 5.0f * t2 + 2.0f;
6925/// float P2 = -3.0f * t3 + 4.0f * t2 + t;
6926/// float P3 = t3 - t2;
6927///
6928/// Result.x = (P0 * Position0.x + P1 * Position1.x + P2 * Position2.x + P3 * Position3.x) * 0.5f;
6929/// Result.y = (P0 * Position0.y + P1 * Position1.y + P2 * Position2.y + P3 * Position3.y) * 0.5f;
6930/// Result.z = (P0 * Position0.z + P1 * Position1.z + P2 * Position2.z + P3 * Position3.z) * 0.5f;
6931/// Result.w = (P0 * Position0.w + P1 * Position1.w + P2 * Position2.w + P3 * Position3.w) * 0.5f;
6932///
6933/// return Result;
6934/// ```
6935///
6936/// ## Reference
6937///
6938/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVectorCatmullRom>
6939#[inline]
6940pub fn XMVectorCatmullRom(
6941    Position0: FXMVECTOR,
6942    Position1: FXMVECTOR,
6943    Position2: FXMVECTOR,
6944    Position3: GXMVECTOR,
6945    t: f32,
6946) -> XMVECTOR
6947{
6948    // Result = ((-t^3 + 2 * t^2 - t) * Position0 +
6949    //           (3 * t^3 - 5 * t^2 + 2) * Position1 +
6950    //           (-3 * t^3 + 4 * t^2 + t) * Position2 +
6951    //           (t^3 - t^2) * Position3) * 0.5
6952
6953    #[cfg(_XM_NO_INTRINSICS_)]
6954    {
6955        let t2: f32 = t * t;
6956        let t3: f32 = t * t2;
6957
6958        let P0: XMVECTOR = XMVectorReplicate((-t3 + 2.0 * t2 - t) * 0.5);
6959        let P1: XMVECTOR = XMVectorReplicate((3.0 * t3 - 5.0 * t2 + 2.0) * 0.5);
6960        let P2: XMVECTOR = XMVectorReplicate((-3.0 * t3 + 4.0 * t2 + t) * 0.5);
6961        let P3: XMVECTOR = XMVectorReplicate((t3 - t2) * 0.5);
6962
6963        let mut Result: XMVECTOR = XMVectorMultiply(P0, Position0);
6964        Result = XMVectorMultiplyAdd(P1, Position1, Result);
6965        Result = XMVectorMultiplyAdd(P2, Position2, Result);
6966        Result = XMVectorMultiplyAdd(P3, Position3, Result);
6967
6968        return Result;
6969    }
6970
6971    #[cfg(_XM_ARM_NEON_INTRINSICS_)]
6972    {
6973        unimplemented!()
6974    }
6975
6976    #[cfg(_XM_SSE_INTRINSICS_)]
6977    unsafe {
6978        let t2: f32 = t * t;
6979        let t3: f32 = t * t2;
6980
6981        let mut P0: XMVECTOR = _mm_set_ps1((-t3 + 2.0 * t2 - t) * 0.5);
6982        let mut P1: XMVECTOR = _mm_set_ps1((3.0 * t3 - 5.0 * t2 + 2.0) * 0.5);
6983        let mut P2: XMVECTOR = _mm_set_ps1((-3.0 * t3 + 4.0 * t2 + t) * 0.5);
6984        let mut P3: XMVECTOR = _mm_set_ps1((t3 - t2) * 0.5);
6985
6986        P1 = _mm_mul_ps(Position1, P1);
6987        P0 = XM_FMADD_PS!(Position0, P0, P1);
6988        P3 = _mm_mul_ps(Position3, P3);
6989        P2 = XM_FMADD_PS!(Position2, P2, P3);
6990        P0 = _mm_add_ps(P0, P2);
6991        return P0;
6992    }
6993}
6994
6995/// Performs a Catmull-Rom interpolation, using the specified position vectors.
6996///
6997/// ## Parameters
6998///
6999/// `Position0` First position.
7000///
7001/// `Position1` Second position.
7002///
7003/// `Position2` Third position.
7004///
7005/// `Position3` Fourth position.
7006///
7007/// `T` Interpolating control factor for the corresponding components of the position.
7008///
7009/// ## Return value
7010///
7011/// Returns the results of the Catmull-Rom interpolation.
7012///
7013/// ## Remarks
7014///
7015/// This function is identical to [`XMVectorCatmullRom`] except that independent weighting factors may supplied
7016/// in `T`. As an example, you might want to calculate two sets of Catmull-Rom interpolation, using the `x`
7017/// and `y`-components of the position vectors for one set of `2D` positions and the `z` and `w`-components of the
7018/// position vectors for the other set of `2D` positions. The `x` and `y`-components of `T` would determine the
7019/// interpolation factors for the first Catmull-Rom interpolation. Similarly, the `z` and `w`-components of
7020/// `T` would determine the interpolation factors for the second Catmull-Rom interpolation.
7021///
7022/// ## Reference
7023///
7024/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVectorCatmullRomV>
7025#[inline]
7026pub fn XMVectorCatmullRomV(
7027    Position0: FXMVECTOR,
7028    Position1: FXMVECTOR,
7029    Position2: FXMVECTOR,
7030    Position3: GXMVECTOR,
7031    T: HXMVECTOR,
7032) -> XMVECTOR
7033{
7034    // Result = ((-t^3 + 2 * t^2 - t) * Position0 +
7035    //           (3 * t^3 - 5 * t^2 + 2) * Position1 +
7036    //           (-3 * t^3 + 4 * t^2 + t) * Position2 +
7037    //           (t^3 - t^2) * Position3) * 0.5
7038
7039    #[cfg(_XM_NO_INTRINSICS_)]
7040    unsafe {
7041        let fx: f32 = T.vector4_f32[0];
7042        let fy: f32 = T.vector4_f32[1];
7043        let fz: f32 = T.vector4_f32[2];
7044        let fw: f32 = T.vector4_f32[3];
7045        let vResult = XMVECTORF32 { f: [
7046            0.5 * ((-fx * fx * fx + 2.0 * fx * fx - fx) * Position0.vector4_f32[0]
7047            + (3.0 * fx * fx * fx - 5.0 * fx * fx + 2.0) * Position1.vector4_f32[0]
7048            + (-3.0 * fx * fx * fx + 4.0 * fx * fx + fx) * Position2.vector4_f32[0]
7049            + (fx * fx * fx - fx * fx) * Position3.vector4_f32[0]),
7050
7051            0.5 * ((-fy * fy * fy + 2.0 * fy * fy - fy) * Position0.vector4_f32[1]
7052            + (3.0 * fy * fy * fy - 5.0 * fy * fy + 2.0) * Position1.vector4_f32[1]
7053            + (-3.0 * fy * fy * fy + 4.0 * fy * fy + fy) * Position2.vector4_f32[1]
7054            + (fy * fy * fy - fy * fy) * Position3.vector4_f32[1]),
7055
7056            0.5 * ((-fz * fz * fz + 2.0 * fz * fz - fz) * Position0.vector4_f32[2]
7057            + (3.0 * fz * fz * fz - 5.0 * fz * fz + 2.0) * Position1.vector4_f32[2]
7058            + (-3.0 * fz * fz * fz + 4.0 * fz * fz + fz) * Position2.vector4_f32[2]
7059            + (fz * fz * fz - fz * fz) * Position3.vector4_f32[2]),
7060
7061            0.5 * ((-fw * fw * fw + 2.0 * fw * fw - fw) * Position0.vector4_f32[3]
7062            + (3.0 * fw * fw * fw - 5.0 * fw * fw + 2.0) * Position1.vector4_f32[3]
7063            + (-3.0 * fw * fw * fw + 4.0 * fw * fw + fw) * Position2.vector4_f32[3]
7064            + (fw * fw * fw - fw * fw) * Position3.vector4_f32[3])
7065         ] };
7066        return vResult.v;
7067    }
7068
7069    #[cfg(_XM_ARM_NEON_INTRINSICS_)]
7070    {
7071        unimplemented!()
7072    }
7073
7074    #[cfg(_XM_SSE_INTRINSICS_)]
7075    unsafe {
7076        const Catmul2: XMVECTORF32 = XMVECTORF32 { f: [ 2.0, 2.0, 2.0, 2.0 ] };
7077        const Catmul3: XMVECTORF32 = XMVECTORF32 { f: [ 3.0, 3.0, 3.0, 3.0 ] };
7078        const Catmul4: XMVECTORF32 = XMVECTORF32 { f :[ 4.0, 4.0, 4.0, 4.0 ] };
7079        const Catmul5: XMVECTORF32 = XMVECTORF32 { f: [5.0, 5.0, 5.0, 5.0 ] };
7080        // Cache T^2 and T^3
7081        let T2: XMVECTOR = _mm_mul_ps(T, T);
7082        let mut T3: XMVECTOR = _mm_mul_ps(T, T2);
7083        // Perform the Position0 term
7084        let mut vResult: XMVECTOR = _mm_add_ps(T2, T2);
7085        vResult = _mm_sub_ps(vResult, T);
7086        vResult = _mm_sub_ps(vResult, T3);
7087        vResult = _mm_mul_ps(vResult, Position0);
7088        // Perform the Position1 term and add
7089        let mut vTemp: XMVECTOR = _mm_mul_ps(T3, Catmul3.v);
7090        vTemp = XM_FNMADD_PS!(T2, Catmul5.v, vTemp);
7091        vTemp = _mm_add_ps(vTemp, Catmul2.v);
7092        vResult = XM_FMADD_PS!(vTemp, Position1, vResult);
7093        // Perform the Position2 term and add
7094        vTemp = _mm_mul_ps(T2, Catmul4.v);
7095        vTemp = XM_FNMADD_PS!(T3, Catmul3.v, vTemp);
7096        vTemp = _mm_add_ps(vTemp, T);
7097        vResult = XM_FMADD_PS!(vTemp, Position2, vResult);
7098        // Position3 is the last term
7099        T3 = _mm_sub_ps(T3, T2);
7100        vResult = XM_FMADD_PS!(T3, Position3, vResult);
7101        // Multiply by 0.5f and exit
7102        vResult = _mm_mul_ps(vResult, g_XMOneHalf.v);
7103        return vResult;
7104    }
7105}
7106
7107/// Returns a point in Barycentric coordinates, using the specified position vectors.
7108///
7109/// ## Parameters
7110///
7111/// `Position0` First position.
7112///
7113/// `Position1` Second position.
7114///
7115/// `Position2` Third position.
7116///
7117/// `f` Weighting factor. See the remarks.
7118///
7119/// `g` Weighting factor. See the remarks.
7120///
7121/// ## Return value
7122///
7123/// Returns the Barycentric coordinates.
7124///
7125/// ## Remarks
7126///
7127/// This function provides a way to understand points in and around a triangle, independent of where the
7128/// triangle is located. This function returns the resulting point by using the following equation:
7129///
7130/// ```text
7131/// Position0 + f * (Position1 - Position0) + g * (Position2 - Position0)
7132/// ```
7133///
7134/// Any point in the plane `Position0Position1Position2` can be represented by the Barycentric coordinate
7135/// `(f, g)`, where `f` controls how much `Position1` gets weighted into the result, and `g` controls how much
7136/// `Position2` gets weighted into the result. Lastly, `1-f-g` controls how much `Position0` gets weighted
7137/// into the result.
7138///
7139/// Note the following relations.
7140///
7141/// * If `(f>=0 && g>=0 && 1-f-g>=0)`, the point is inside the triangle `Position0Position1Position2`.
7142/// * If `(f==0 && g>=0 && 1-f-g>=0)`, the point is on the line `Position0Position2`.
7143/// * If `(f>=0 && g==0 && 1-f-g>=0)`, the point is on the line `Position0Position1`.
7144/// * If `(f>=0 && g>=0 && 1-f-g==0)`, the point is on the line `Position1Position2`.
7145///
7146/// Barycentric coordinates are a form of general coordinates. In this context, using Barycentric coordinates
7147/// represents a change in coordinate systems. What holds `true` for Cartesian coordinates holds `true` for
7148/// Barycentric coordinates.
7149///
7150/// ## Reference
7151///
7152/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVectorBaryCentric>
7153#[inline]
7154pub fn XMVectorBaryCentric(
7155    Position0: FXMVECTOR,
7156    Position1: FXMVECTOR,
7157    Position2: FXMVECTOR,
7158    f: f32,
7159    g: f32,
7160) -> XMVECTOR
7161{
7162    // Result = Position0 + f * (Position1 - Position0) + g * (Position2 - Position0)
7163
7164    #[cfg(_XM_NO_INTRINSICS_)]
7165    {
7166        let P10: XMVECTOR = XMVectorSubtract(Position1, Position0);
7167        let ScaleF: XMVECTOR = XMVectorReplicate(f);
7168
7169        let P20: XMVECTOR = XMVectorSubtract(Position2, Position0);
7170        let ScaleG: XMVECTOR = XMVectorReplicate(g);
7171
7172        let mut Result: XMVECTOR = XMVectorMultiplyAdd(P10, ScaleF, Position0);
7173        Result = XMVectorMultiplyAdd(P20, ScaleG, Result);
7174
7175        return Result;
7176    }
7177
7178    #[cfg(_XM_ARM_NEON_INTRINSICS_)]
7179    {
7180        unimplemented!()
7181    }
7182
7183    #[cfg(_XM_SSE_INTRINSICS_)]
7184    unsafe {
7185        let mut R1: XMVECTOR = _mm_sub_ps(Position1, Position0);
7186        let R2: XMVECTOR = _mm_sub_ps(Position2, Position0);
7187        let SF: XMVECTOR = _mm_set_ps1(f);
7188        R1 = XM_FMADD_PS!(R1, SF, Position0);
7189        let SG: XMVECTOR = _mm_set_ps1(g);
7190        return XM_FMADD_PS!(R2, SG, R1);
7191    }
7192}
7193
7194/// Returns a point in Barycentric coordinates, using the specified position vectors.
7195///
7196/// ## Parameters
7197///
7198/// `Position0` First position.
7199///
7200/// `Position1` Second position.
7201///
7202/// `Position2` Third position.
7203///
7204/// `F` Weighting factors for the corresponding components of the position.
7205///
7206/// `G` Weighting factors for the corresponding components of the position.
7207///
7208/// ## Return value
7209///
7210/// Returns the Barycentric coordinates.
7211///
7212/// This function is identical to [`XMVectorBaryCentric`] except that independent weighting factors may supplied
7213/// in `F` and `G`. As an example, you might want to calculate two sets of 2D Barycentric coordinates, using
7214/// the `x` and `y`-components of the position vectors for one set of `2D` positions and the `z` and `w`-components
7215/// of the position vectors for the other set of `2D` positions. The `x` and `y`-components of `F` and `G` would determine
7216/// the weighting factors for the first set of Barycentric coordinates. Similarly, the `z` and `w`-components
7217/// of `F` and `G` would determine the weighting factors for the second set of Barycentric coordinates.
7218///
7219/// ## Reference
7220///
7221/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVectorBaryCentricV>
7222///
7223/// [`XMVectorBaryCentric`]: function@XMVectorBaryCentric
7224#[inline]
7225pub fn XMVectorBaryCentricV(
7226    Position0: FXMVECTOR,
7227    Position1: FXMVECTOR,
7228    Position2: FXMVECTOR,
7229    F: GXMVECTOR,
7230    G: HXMVECTOR,
7231) -> XMVECTOR
7232{
7233    // Result = Position0 + f * (Position1 - Position0) + g * (Position2 - Position0)
7234
7235    #[cfg(_XM_NO_INTRINSICS_)]
7236    {
7237        let P10: XMVECTOR = XMVectorSubtract(Position1, Position0);
7238        let P20: XMVECTOR = XMVectorSubtract(Position2, Position0);
7239
7240        let mut Result: XMVECTOR = XMVectorMultiplyAdd(P10, F, Position0);
7241        Result = XMVectorMultiplyAdd(P20, G, Result);
7242
7243        return Result;
7244    }
7245
7246    #[cfg(_XM_ARM_NEON_INTRINSICS_)]
7247    {
7248        unimplemented!()
7249    }
7250
7251    #[cfg(_XM_SSE_INTRINSICS_)]
7252    unsafe {
7253        let mut R1: XMVECTOR = _mm_sub_ps(Position1, Position0);
7254        let R2: XMVECTOR = _mm_sub_ps(Position2, Position0);
7255        R1 = XM_FMADD_PS!(R1, F, Position0);
7256        return XM_FMADD_PS!(R2, G, R1);
7257    }
7258}
7259
7260// 2D Vector
7261
7262/// Tests whether two 2D vectors are equal.
7263///
7264/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVector2Equal>
7265#[inline]
7266pub fn XMVector2Equal(
7267    V1: FXMVECTOR,
7268    V2: FXMVECTOR,
7269) -> bool
7270{
7271    #[cfg(_XM_NO_INTRINSICS_)]
7272    unsafe {
7273        return (((V1.vector4_f32[0] == V2.vector4_f32[0]) && (V1.vector4_f32[1] == V2.vector4_f32[1])) != false);
7274    }
7275
7276    #[cfg(_XM_ARM_NEON_INTRINSICS_)]
7277    {
7278        unimplemented!()
7279    }
7280
7281    #[cfg(_XM_SSE_INTRINSICS_)]
7282    unsafe {
7283        let vTemp: XMVECTOR = _mm_cmpeq_ps(V1, V2);
7284        // z and w are don't care
7285        return (((_mm_movemask_ps(vTemp) & 3) == 3) != false);
7286    }
7287}
7288
7289/// Tests whether two 2D vectors are equal. In addition, this function returns a comparison value that can be examined using functions such as XMComparisonAllTrue.
7290///
7291/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVector2EqualR>
7292#[inline]
7293pub fn XMVector2EqualR(
7294    V1: FXMVECTOR,
7295    V2: FXMVECTOR,
7296) -> u32
7297{
7298    #[cfg(_XM_NO_INTRINSICS_)]
7299    unsafe {
7300        let mut CR: u32 = 0;
7301        if ((V1.vector4_f32[0] == V2.vector4_f32[0]) &&
7302            (V1.vector4_f32[1] == V2.vector4_f32[1]))
7303        {
7304            CR = XM_CRMASK_CR6TRUE;
7305        }
7306        else if ((V1.vector4_f32[0] != V2.vector4_f32[0]) &&
7307            (V1.vector4_f32[1] != V2.vector4_f32[1]))
7308        {
7309            CR = XM_CRMASK_CR6FALSE;
7310        }
7311        return CR;
7312    }
7313
7314    #[cfg(_XM_ARM_NEON_INTRINSICS_)]
7315    {
7316        unimplemented!()
7317    }
7318
7319    #[cfg(all(_XM_SSE_INTRINSICS_))]
7320    unsafe {
7321        let vTemp: XMVECTOR = _mm_cmpeq_ps(V1, V2);
7322        // z and w are don't care
7323        let iTest: i32 = _mm_movemask_ps(vTemp) & 3;
7324        let mut CR = 0;
7325        if (iTest == 3)
7326        {
7327            CR = XM_CRMASK_CR6TRUE;
7328        }
7329        else if (!ibool(iTest))
7330        {
7331            CR = XM_CRMASK_CR6FALSE;
7332        }
7333        return CR;
7334    }
7335}
7336
7337/// Tests whether two 2D vectors are equal, treating each component as an unsigned integer.
7338///
7339/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVector2EqualInt>
7340#[inline]
7341pub fn XMVector2EqualInt(
7342    V1: FXMVECTOR,
7343    V2: FXMVECTOR,
7344) -> bool
7345{
7346    #[cfg(_XM_NO_INTRINSICS_)]
7347    unsafe {
7348        return (((V1.vector4_u32[0] == V2.vector4_u32[0]) && (V1.vector4_u32[1] == V2.vector4_u32[1])) != false);
7349    }
7350
7351    #[cfg(_XM_ARM_NEON_INTRINSICS_)]
7352    {
7353        unimplemented!()
7354    }
7355
7356    #[cfg(_XM_SSE_INTRINSICS_)]
7357    unsafe {
7358        let vTemp: __m128i = _mm_cmpeq_epi32(_mm_castps_si128(V1), _mm_castps_si128(V2));
7359        return (((_mm_movemask_ps(_mm_castsi128_ps(vTemp)) & 3) == 3) != false);
7360    }
7361}
7362
7363/// Tests whether two 2D vectors are equal, treating each component as an unsigned integer. In addition, this function returns a comparison value that can be examined using functions such as XMComparisonAllTrue.
7364///
7365/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVector2EqualIntR>
7366#[inline]
7367pub fn XMVector2EqualIntR(
7368    V1: FXMVECTOR,
7369    V2: FXMVECTOR,
7370) -> u32
7371{
7372    #[cfg(_XM_NO_INTRINSICS_)]
7373    unsafe {
7374        let mut CR: u32 = 0;
7375        if ((V1.vector4_u32[0] == V2.vector4_u32[0]) &&
7376            (V1.vector4_u32[1] == V2.vector4_u32[1]))
7377        {
7378            CR = XM_CRMASK_CR6TRUE;
7379        }
7380        else if ((V1.vector4_u32[0] != V2.vector4_u32[0]) &&
7381            (V1.vector4_u32[1] != V2.vector4_u32[1]))
7382        {
7383            CR = XM_CRMASK_CR6FALSE;
7384        }
7385        return CR;
7386    }
7387
7388    #[cfg(_XM_ARM_NEON_INTRINSICS_)]
7389    {
7390        unimplemented!()
7391    }
7392
7393    #[cfg(all(_XM_SSE_INTRINSICS_))]
7394    unsafe {
7395        let vTemp: __m128i = _mm_cmpeq_epi32(_mm_castps_si128(V1), _mm_castps_si128(V2));
7396        let iTest: i32 = _mm_movemask_ps(_mm_castsi128_ps(vTemp)) & 3;
7397        let mut CR: u32 = 0;
7398        if (iTest == 3)
7399        {
7400            CR = XM_CRMASK_CR6TRUE;
7401        }
7402        else if (!ibool(iTest))
7403        {
7404            CR = XM_CRMASK_CR6FALSE;
7405        }
7406        return CR;
7407    }
7408}
7409
7410/// Tests whether one 2D vector is near another 2D vector.
7411///
7412/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVector2NearEqual>
7413#[inline]
7414pub fn XMVector2NearEqual(
7415    V1: FXMVECTOR,
7416    V2: FXMVECTOR,
7417    Epsilon: FXMVECTOR,
7418) -> bool
7419{
7420    #[cfg(_XM_NO_INTRINSICS_)]
7421    unsafe {
7422        let dx: f32 = fabsf(V1.vector4_f32[0] - V2.vector4_f32[0]);
7423        let dy: f32 = fabsf(V1.vector4_f32[1] - V2.vector4_f32[1]);
7424        return ((dx <= Epsilon.vector4_f32[0]) &&
7425            (dy <= Epsilon.vector4_f32[1]));
7426    }
7427
7428    #[cfg(_XM_ARM_NEON_INTRINSICS_)]
7429    {
7430        unimplemented!()
7431    }
7432
7433    #[cfg(all(_XM_SSE_INTRINSICS_))]
7434    unsafe {
7435        // Get the difference
7436        let vDelta: XMVECTOR = _mm_sub_ps(V1, V2);
7437        // Get the absolute value of the difference
7438        let mut vTemp: XMVECTOR = _mm_setzero_ps();
7439        vTemp = _mm_sub_ps(vTemp, vDelta);
7440        vTemp = _mm_max_ps(vTemp, vDelta);
7441        vTemp = _mm_cmple_ps(vTemp, Epsilon);
7442        // z and w are don't care
7443        return (((_mm_movemask_ps(vTemp) & 3) == 0x3) != false);
7444    }
7445}
7446
7447
7448/// Tests whether two 2D vectors are not equal.
7449///
7450/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVector2NotEqual>
7451#[inline]
7452pub fn XMVector2NotEqual(
7453    V1: FXMVECTOR,
7454    V2: FXMVECTOR,
7455) -> bool
7456{
7457    #[cfg(_XM_NO_INTRINSICS_)]
7458    unsafe {
7459        return (((V1.vector4_f32[0] != V2.vector4_f32[0]) || (V1.vector4_f32[1] != V2.vector4_f32[1])) != false);
7460    }
7461
7462    #[cfg(_XM_ARM_NEON_INTRINSICS_)]
7463    {
7464        unimplemented!()
7465    }
7466
7467    #[cfg(all(_XM_SSE_INTRINSICS_))]
7468    unsafe {
7469        let vTemp: XMVECTOR = _mm_cmpeq_ps(V1, V2);
7470        // z and w are don't care
7471        return (((_mm_movemask_ps(vTemp) & 3) != 3) != false);
7472    }
7473}
7474
7475/// Test whether two vectors are not equal, treating each component as an unsigned integer.
7476///
7477/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVector2NotEqualInt>
7478#[inline]
7479pub fn XMVector2NotEqualInt(
7480    V1: FXMVECTOR,
7481    V2: FXMVECTOR,
7482) -> bool
7483{
7484    #[cfg(_XM_NO_INTRINSICS_)]
7485    unsafe {
7486        return (((V1.vector4_u32[0] != V2.vector4_u32[0]) || (V1.vector4_u32[1] != V2.vector4_u32[1])) != false);
7487    }
7488
7489    #[cfg(_XM_ARM_NEON_INTRINSICS_)]
7490    {
7491        unimplemented!()
7492    }
7493
7494    #[cfg(all(_XM_SSE_INTRINSICS_))]
7495    unsafe {
7496        let vTemp: __m128i = _mm_cmpeq_epi32(_mm_castps_si128(V1), _mm_castps_si128(V2));
7497        return (((_mm_movemask_ps(_mm_castsi128_ps(vTemp)) & 3) != 3) != false);
7498    }
7499}
7500
7501/// Tests whether one 2D vector is greater than another 2D vector.
7502///
7503/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVector2Greater>
7504#[inline]
7505pub fn XMVector2Greater(
7506    V1: FXMVECTOR,
7507    V2: FXMVECTOR,
7508) -> bool
7509{
7510    #[cfg(_XM_NO_INTRINSICS_)]
7511    unsafe {
7512        return (((V1.vector4_f32[0] > V2.vector4_f32[0]) && (V1.vector4_f32[1] > V2.vector4_f32[1])) != false);
7513    }
7514
7515    #[cfg(_XM_ARM_NEON_INTRINSICS_)]
7516    {
7517        unimplemented!()
7518    }
7519
7520    #[cfg(all(_XM_SSE_INTRINSICS_))]
7521    unsafe {
7522        let vTemp: XMVECTOR = _mm_cmpgt_ps(V1, V2);
7523        // z and w are don't care
7524        return (((_mm_movemask_ps(vTemp) & 3) == 3) != false);
7525    }
7526}
7527
7528/// Tests whether one 2D vector is greater than another 2D vector and returns a comparison value that can be examined using functions such as XMComparisonAllTrue.
7529///
7530/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVector2GreaterR>
7531#[inline]
7532pub fn XMVector2GreaterR(
7533    V1: FXMVECTOR,
7534    V2: FXMVECTOR,
7535) -> u32
7536{
7537    #[cfg(_XM_NO_INTRINSICS_)]
7538    unsafe {
7539        let mut CR = 0;
7540        if ((V1.vector4_f32[0] > V2.vector4_f32[0]) &&
7541            (V1.vector4_f32[1] > V2.vector4_f32[1]))
7542        {
7543            CR = XM_CRMASK_CR6TRUE;
7544        }
7545        else if ((V1.vector4_f32[0] <= V2.vector4_f32[0]) &&
7546            (V1.vector4_f32[1] <= V2.vector4_f32[1]))
7547        {
7548            CR = XM_CRMASK_CR6FALSE;
7549        }
7550        return CR;
7551    }
7552
7553    #[cfg(_XM_ARM_NEON_INTRINSICS_)]
7554    {
7555        unimplemented!()
7556    }
7557
7558    #[cfg(_XM_SSE_INTRINSICS_)]
7559    unsafe {
7560        let vTemp: XMVECTOR = _mm_cmpgt_ps(V1, V2);
7561        let iTest: i32 = _mm_movemask_ps(vTemp) & 3;
7562        let mut CR = 0;
7563        if (iTest == 3)
7564        {
7565            CR = XM_CRMASK_CR6TRUE;
7566        }
7567        else if (!ibool(iTest))
7568        {
7569            CR = XM_CRMASK_CR6FALSE;
7570        }
7571        return CR;
7572    }
7573}
7574
7575/// Tests whether one 2D vector is greater-than-or-equal-to another 2D vector.
7576///
7577/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVector2GreaterOrEqual>
7578#[inline]
7579pub fn XMVector2GreaterOrEqual(
7580    V1: FXMVECTOR,
7581    V2: FXMVECTOR,
7582) -> bool
7583{
7584    #[cfg(_XM_NO_INTRINSICS_)]
7585    unsafe {
7586        return (((V1.vector4_f32[0] >= V2.vector4_f32[0]) && (V1.vector4_f32[1] >= V2.vector4_f32[1])) != false);
7587    }
7588
7589    #[cfg(_XM_ARM_NEON_INTRINSICS_)]
7590    {
7591        unimplemented!()
7592    }
7593
7594    #[cfg(all(_XM_SSE_INTRINSICS_))]
7595    unsafe {
7596        let vTemp: XMVECTOR = _mm_cmpge_ps(V1, V2);
7597        return (((_mm_movemask_ps(vTemp) & 3) == 3) != false);
7598    }
7599}
7600
7601/// Tests whether one 2D vector is greater-than-or-equal-to another 2D vector and returns a comparison value that can be examined using functions such as XMComparisonAllTrue.
7602///
7603/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVector2GreaterOrEqualR>
7604#[inline]
7605pub fn XMVector2GreaterOrEqualR(
7606    V1: FXMVECTOR,
7607    V2: FXMVECTOR,
7608) -> u32
7609{
7610    #[cfg(_XM_NO_INTRINSICS_)]
7611    unsafe {
7612        let mut CR = 0;
7613        if ((V1.vector4_f32[0] >= V2.vector4_f32[0]) &&
7614            (V1.vector4_f32[1] >= V2.vector4_f32[1]))
7615        {
7616            CR = XM_CRMASK_CR6TRUE;
7617        }
7618        else if ((V1.vector4_f32[0] < V2.vector4_f32[0]) &&
7619            (V1.vector4_f32[1] < V2.vector4_f32[1]))
7620        {
7621            CR = XM_CRMASK_CR6FALSE;
7622        }
7623        return CR;
7624    }
7625
7626    #[cfg(_XM_ARM_NEON_INTRINSICS_)]
7627    {
7628        unimplemented!()
7629    }
7630
7631    #[cfg(_XM_SSE_INTRINSICS_)]
7632    unsafe {
7633        let vTemp: XMVECTOR = _mm_cmpge_ps(V1, V2);
7634        let iTest: i32 = _mm_movemask_ps(vTemp) & 3;
7635        let mut CR: u32 = 0;
7636        if (iTest == 3)
7637        {
7638            CR = XM_CRMASK_CR6TRUE;
7639        }
7640        else if (!ibool(iTest))
7641        {
7642            CR = XM_CRMASK_CR6FALSE;
7643        }
7644        return CR;
7645    }
7646}
7647
7648/// Tests whether one 2D vector is less than another 2D vector.
7649///
7650/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVector2Less>
7651#[inline]
7652pub fn XMVector2Less(
7653    V1: FXMVECTOR,
7654    V2: FXMVECTOR,
7655) -> bool
7656{
7657    #[cfg(_XM_NO_INTRINSICS_)]
7658    unsafe {
7659        return (((V1.vector4_f32[0] < V2.vector4_f32[0]) && (V1.vector4_f32[1] < V2.vector4_f32[1])) != false);
7660    }
7661
7662    #[cfg(_XM_ARM_NEON_INTRINSICS_)]
7663    {
7664        unimplemented!()
7665    }
7666
7667    #[cfg(all(_XM_SSE_INTRINSICS_))]
7668    unsafe {
7669        let vTemp: XMVECTOR = _mm_cmplt_ps(V1, V2);
7670        return (((_mm_movemask_ps(vTemp) & 3) == 3) != false);
7671    }
7672}
7673
7674/// Tests whether one 2D vector is less-than-or-equal-to another 2D vector.
7675///
7676/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVector2LessOrEqual>
7677#[inline]
7678pub fn XMVector2LessOrEqual(
7679    V1: FXMVECTOR,
7680    V2: FXMVECTOR,
7681) -> bool
7682{
7683    #[cfg(_XM_NO_INTRINSICS_)]
7684    unsafe {
7685        return (((V1.vector4_f32[0] <= V2.vector4_f32[0]) && (V1.vector4_f32[1] <= V2.vector4_f32[1])) != false);
7686    }
7687
7688    #[cfg(_XM_ARM_NEON_INTRINSICS_)]
7689    {
7690        unimplemented!()
7691    }
7692
7693    #[cfg(all(_XM_SSE_INTRINSICS_))]
7694    unsafe {
7695        let vTemp: XMVECTOR = _mm_cmple_ps(V1, V2);
7696        return (((_mm_movemask_ps(vTemp) & 3) == 3) != false);
7697    }
7698}
7699
7700/// Tests whether the components of a 2D vector are within set bounds.
7701///
7702/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVector2InBounds>
7703#[inline]
7704pub fn XMVector2InBounds(
7705    V: FXMVECTOR,
7706    Bounds: FXMVECTOR,
7707) -> bool
7708{
7709    #[cfg(_XM_NO_INTRINSICS_)]
7710    unsafe {
7711        return (((V.vector4_f32[0] <= Bounds.vector4_f32[0] && V.vector4_f32[0] >= -Bounds.vector4_f32[0]) &&
7712            (V.vector4_f32[1] <= Bounds.vector4_f32[1] && V.vector4_f32[1] >= -Bounds.vector4_f32[1])) != false);
7713    }
7714
7715    #[cfg(_XM_ARM_NEON_INTRINSICS_)]
7716    {
7717        unimplemented!()
7718    }
7719
7720    #[cfg(all(_XM_SSE_INTRINSICS_))]
7721    unsafe {
7722        // Test if less than or equal
7723        let mut vTemp1: XMVECTOR = _mm_cmple_ps(V, Bounds);
7724        // Negate the bounds
7725        let mut vTemp2: XMVECTOR = _mm_mul_ps(Bounds, g_XMNegativeOne.v);
7726        // Test if greater or equal (Reversed)
7727        vTemp2 = _mm_cmple_ps(vTemp2, V);
7728        // Blend answers
7729        vTemp1 = _mm_and_ps(vTemp1, vTemp2);
7730        // x and y in bounds? (z and w are don't care)
7731        return (((_mm_movemask_ps(vTemp1) & 0x3) == 0x3) != false);
7732    }
7733}
7734
7735/// Tests whether any component of a 2D vector is a NaN.
7736///
7737/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVector2IsNaN>
7738#[inline]
7739pub fn XMVector2IsNaN(
7740    V: FXMVECTOR,
7741) -> bool
7742{
7743    #[cfg(_XM_NO_INTRINSICS_)]
7744    unsafe {
7745        return (XMISNAN!(V.vector4_f32[0]) ||
7746            XMISNAN!(V.vector4_f32[1]));
7747    }
7748
7749    #[cfg(_XM_ARM_NEON_INTRINSICS_)]
7750    {
7751        unimplemented!()
7752    }
7753
7754    #[cfg(all(_XM_SSE_INTRINSICS_))]
7755    unsafe {
7756        // Test against itself. NaN is always not equal
7757        let vTempNan: XMVECTOR = _mm_cmpneq_ps(V, V);
7758        // If x or y are NaN, the mask is non-zero
7759        return ((_mm_movemask_ps(vTempNan) & 3) != 0);
7760    }
7761}
7762
7763/// Tests whether any component of a 2D vector is positive or negative infinity.
7764///
7765/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVector2IsInfinite>
7766#[inline]
7767pub fn XMVector2IsInfinite(
7768    V: FXMVECTOR,
7769) -> bool
7770{
7771    #[cfg(_XM_NO_INTRINSICS_)]
7772    unsafe {
7773        return (XMISINF!(V.vector4_f32[0]) ||
7774            XMISINF!(V.vector4_f32[1]));
7775    }
7776
7777    #[cfg(_XM_ARM_NEON_INTRINSICS_)]
7778    {
7779        unimplemented!()
7780    }
7781
7782    #[cfg(all(_XM_SSE_INTRINSICS_))]
7783    unsafe {
7784        // Mask off the sign bit
7785        let mut vTemp: __m128 = _mm_and_ps(V, g_XMAbsMask.v);
7786        // Compare to infinity
7787        vTemp = _mm_cmpeq_ps(vTemp, g_XMInfinity.v);
7788        // If x or z are infinity, the signs are true.
7789        return ((_mm_movemask_ps(vTemp) & 3) != 0);
7790    }
7791}
7792
7793/// Computes the dot product between 2D vectors.
7794///
7795/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVector2Dot>
7796#[inline]
7797pub fn XMVector2Dot(
7798    V1: FXMVECTOR,
7799    V2: FXMVECTOR,
7800) -> XMVECTOR
7801{
7802    #[cfg(_XM_NO_INTRINSICS_)]
7803    unsafe {
7804        let fDot: f32 = V1.vector4_f32[0] * V2.vector4_f32[0] + V1.vector4_f32[1] * V2.vector4_f32[1];
7805        let mut Result: XMVECTORF32 = crate::undefined();
7806        Result.f[0] = fDot;
7807        Result.f[1] = fDot;
7808        Result.f[2] = fDot;
7809        Result.f[3] = fDot;
7810        return Result.v;
7811    }
7812
7813    #[cfg(_XM_ARM_NEON_INTRINSICS_)]
7814    {
7815        unimplemented!()
7816    }
7817
7818    #[cfg(all(_XM_SSE_INTRINSICS_))]
7819    unsafe {
7820        // Perform the dot product on x and y
7821        let mut vLengthSq: XMVECTOR = _mm_mul_ps(V1, V2);
7822        // vTemp has y splatted
7823        let vTemp: XMVECTOR = XM_PERMUTE_PS!(vLengthSq, _MM_SHUFFLE(1, 1, 1, 1));
7824        // x+y
7825        vLengthSq = _mm_add_ss(vLengthSq, vTemp);
7826        vLengthSq = XM_PERMUTE_PS!(vLengthSq, _MM_SHUFFLE(0, 0, 0, 0));
7827        return vLengthSq;
7828    }
7829}
7830
7831/// Computes the 2D cross product.
7832///
7833/// ## Parameters
7834///
7835/// `V1` 2D vector.
7836///
7837/// `V2` 2D vector.
7838///
7839/// ## Return value
7840///
7841/// Returns a vector. The 2D cross product is replicated into each component.
7842///
7843/// ## Remarks
7844///
7845/// The following pseudocode demonstrates the operation of the function:
7846///
7847/// ```text
7848/// XMVECTOR Result;
7849///
7850/// Result.x = V1.x * V2.y - v1.y * V2.x;
7851/// Result.y = V1.x * V2.y - v1.y * V2.x;
7852/// Result.z = V1.x * V2.y - v1.y * V2.x;
7853/// Result.w = V1.x * V2.y - v1.y * V2.x;
7854///
7855/// return Result;
7856/// ```
7857///
7858/// Note that a 'cross-product' in 2D is not well-defined. This function computes a geometric cross-product
7859/// often used in 2D graphics. XMVector2Orthogonal is another possible interpretation of a 'cross-product'
7860/// in 2D.
7861///
7862/// ## Reference
7863///
7864/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVector2Cross>
7865#[inline]
7866pub fn XMVector2Cross(
7867    V1: FXMVECTOR,
7868    V2: FXMVECTOR,
7869) -> XMVECTOR
7870{
7871    #[cfg(_XM_NO_INTRINSICS_)]
7872    unsafe {
7873        let fCross: f32 = (V1.vector4_f32[0] * V2.vector4_f32[1]) - (V1.vector4_f32[1] * V2.vector4_f32[0]);
7874        let mut Result: XMVECTORF32 = crate::undefined();
7875        Result.f[0] = fCross;
7876        Result.f[1] = fCross;
7877        Result.f[2] = fCross;
7878        Result.f[3] = fCross;
7879        return Result.v;
7880    }
7881
7882    #[cfg(_XM_ARM_NEON_INTRINSICS_)]
7883    {
7884        unimplemented!()
7885    }
7886
7887    #[cfg(all(_XM_SSE_INTRINSICS_))]
7888    unsafe {
7889        // Swap x and y
7890        let mut vResult: XMVECTOR = XM_PERMUTE_PS!(V2, _MM_SHUFFLE(0, 1, 0, 1));
7891        // Perform the muls
7892        vResult = _mm_mul_ps(vResult, V1);
7893        // Splat y
7894        let vTemp: XMVECTOR = XM_PERMUTE_PS!(vResult, _MM_SHUFFLE(1, 1, 1, 1));
7895        // Sub the values
7896        vResult = _mm_sub_ss(vResult, vTemp);
7897        // Splat the cross product
7898        vResult = XM_PERMUTE_PS!(vResult, _MM_SHUFFLE(0, 0, 0, 0));
7899        return vResult;
7900    }
7901}
7902
7903/// Computes the square of the length of a 2D vector.
7904///
7905/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVector2LengthSq>
7906#[inline]
7907pub fn XMVector2LengthSq(
7908    V: FXMVECTOR,
7909) -> XMVECTOR
7910{
7911    return XMVector2Dot(V, V);
7912}
7913
7914/// Estimates the reciprocal of the length of a 2D vector.
7915///
7916/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVector2ReciprocalLengthEst>
7917#[inline]
7918pub fn XMVector2ReciprocalLengthEst(
7919    V: FXMVECTOR,
7920) -> XMVECTOR
7921{
7922    #[cfg(_XM_NO_INTRINSICS_)]
7923    {
7924        let mut Result: XMVECTOR;
7925        Result = XMVector2LengthSq(V);
7926        Result = XMVectorReciprocalSqrtEst(Result);
7927        return Result;
7928    }
7929
7930    #[cfg(_XM_ARM_NEON_INTRINSICS_)]
7931    {
7932        unimplemented!()
7933    }
7934
7935    #[cfg(all(_XM_SSE4_INTRINSICS_))]
7936    unsafe {
7937        let vTemp: XMVECTOR = _mm_dp_ps(V, V, 0x3f);
7938        return _mm_rsqrt_ps(vTemp);
7939    }
7940
7941    #[cfg(all(_XM_SSE3_INTRINSICS_, not(_XM_SSE4_INTRINSICS_)))]
7942    unsafe {
7943        let mut vLengthSq: XMVECTOR = _mm_mul_ps(V, V);
7944        let vTemp: XMVECTOR = _mm_hadd_ps(vLengthSq, vLengthSq);
7945        vLengthSq = _mm_rsqrt_ss(vTemp);
7946        vLengthSq = XM_PERMUTE_PS!(vLengthSq, _MM_SHUFFLE(0, 0, 0, 0));
7947        return vLengthSq;
7948    }
7949
7950    #[cfg(all(_XM_SSE_INTRINSICS_, not(_XM_SSE3_INTRINSICS_), not(_XM_SSE4_INTRINSICS_)))]
7951    unsafe {
7952        // Perform the dot product on x and y
7953        let mut vLengthSq: XMVECTOR = _mm_mul_ps(V, V);
7954        // vTemp has y splatted
7955        let vTemp: XMVECTOR = XM_PERMUTE_PS!(vLengthSq, _MM_SHUFFLE(1, 1, 1, 1));
7956        // x+y
7957        vLengthSq = _mm_add_ss(vLengthSq, vTemp);
7958        vLengthSq = _mm_rsqrt_ss(vLengthSq);
7959        vLengthSq = XM_PERMUTE_PS!(vLengthSq, _MM_SHUFFLE(0, 0, 0, 0));
7960        return vLengthSq;
7961    }
7962}
7963
7964/// Computes the reciprocal of the length of a 2D vector.
7965///
7966/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVector2ReciprocalLength>
7967#[inline]
7968pub fn XMVector2ReciprocalLength(
7969    V: FXMVECTOR,
7970) -> XMVECTOR
7971{
7972    #[cfg(_XM_NO_INTRINSICS_)]
7973    {
7974        let mut Result: XMVECTOR;
7975        Result = XMVector2LengthSq(V);
7976        Result = XMVectorReciprocalSqrt(Result);
7977        return Result;
7978    }
7979
7980    #[cfg(_XM_ARM_NEON_INTRINSICS_)]
7981    {
7982        unimplemented!()
7983    }
7984
7985    #[cfg(all(_XM_SSE4_INTRINSICS_))]
7986    unsafe {
7987        let vTemp: XMVECTOR = _mm_dp_ps(V, V, 0x3f);
7988        let vLengthSq: XMVECTOR = _mm_sqrt_ps(vTemp);
7989        return _mm_div_ps(g_XMOne.v, vLengthSq);
7990    }
7991
7992    #[cfg(all(_XM_SSE3_INTRINSICS_, not(_XM_SSE4_INTRINSICS_)))]
7993    unsafe {
7994        let mut vLengthSq: XMVECTOR = _mm_mul_ps(V, V);
7995        let vTemp: XMVECTOR = _mm_hadd_ps(vLengthSq, vLengthSq);
7996        vLengthSq = _mm_sqrt_ss(vTemp);
7997        vLengthSq = _mm_div_ss(g_XMOne.v, vLengthSq);
7998        vLengthSq = XM_PERMUTE_PS!(vLengthSq, _MM_SHUFFLE(0, 0, 0, 0));
7999        return vLengthSq;
8000    }
8001
8002    #[cfg(all(_XM_SSE_INTRINSICS_, not(_XM_SSE3_INTRINSICS_), not(_XM_SSE4_INTRINSICS_)))]
8003    unsafe {
8004        // Perform the dot product on x and y
8005        let mut vLengthSq: XMVECTOR = _mm_mul_ps(V, V);
8006        // vTemp has y splatted
8007        let vTemp: XMVECTOR = XM_PERMUTE_PS!(vLengthSq, _MM_SHUFFLE(1, 1, 1, 1));
8008        // x+y
8009        vLengthSq = _mm_add_ss(vLengthSq, vTemp);
8010        vLengthSq = _mm_sqrt_ss(vLengthSq);
8011        vLengthSq = _mm_div_ss(g_XMOne.v, vLengthSq);
8012        vLengthSq = XM_PERMUTE_PS!(vLengthSq, _MM_SHUFFLE(0, 0, 0, 0));
8013        return vLengthSq;
8014    }
8015}
8016
8017/// Estimates the length of a 2D vector.
8018///
8019/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVector2LengthEst>
8020#[inline]
8021pub fn XMVector2LengthEst(
8022    V: FXMVECTOR,
8023) -> XMVECTOR
8024{
8025    #[cfg(_XM_NO_INTRINSICS_)]
8026    {
8027        let mut Result: XMVECTOR;
8028        Result = XMVector2LengthSq(V);
8029        Result = XMVectorSqrtEst(Result);
8030        return Result;
8031    }
8032
8033    #[cfg(_XM_ARM_NEON_INTRINSICS_)]
8034    {
8035        unimplemented!()
8036    }
8037
8038    #[cfg(all(_XM_SSE4_INTRINSICS_))]
8039    unsafe {
8040        let vTemp: XMVECTOR = _mm_dp_ps(V, V, 0x3f);
8041        return _mm_sqrt_ps(vTemp);
8042    }
8043
8044    #[cfg(all(_XM_SSE3_INTRINSICS_, not(_XM_SSE4_INTRINSICS_)))]
8045    unsafe {
8046        let mut vLengthSq: XMVECTOR = _mm_mul_ps(V, V);
8047        let vTemp: XMVECTOR = _mm_hadd_ps(vLengthSq, vLengthSq);
8048        vLengthSq = _mm_sqrt_ss(vTemp);
8049        vLengthSq = XM_PERMUTE_PS!(vLengthSq, _MM_SHUFFLE(0, 0, 0, 0));
8050        return vLengthSq;
8051    }
8052
8053    #[cfg(all(_XM_SSE_INTRINSICS_, not(_XM_SSE3_INTRINSICS_), not(_XM_SSE4_INTRINSICS_)))]
8054    unsafe {
8055        // Perform the dot product on x and y
8056        let mut vLengthSq: XMVECTOR = _mm_mul_ps(V, V);
8057        // vTemp has y splatted
8058        let vTemp: XMVECTOR = XM_PERMUTE_PS!(vLengthSq, _MM_SHUFFLE(1, 1, 1, 1));
8059        // x+y
8060        vLengthSq = _mm_add_ss(vLengthSq, vTemp);
8061        vLengthSq = _mm_sqrt_ss(vLengthSq);
8062        vLengthSq = XM_PERMUTE_PS!(vLengthSq, _MM_SHUFFLE(0, 0, 0, 0));
8063        return vLengthSq;
8064    }
8065}
8066
8067/// Computes the length of a 2D vector.
8068///
8069/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVector2Length>
8070#[inline]
8071pub fn XMVector2Length(
8072    V: FXMVECTOR,
8073) -> XMVECTOR
8074{
8075    #[cfg(_XM_NO_INTRINSICS_)]
8076    {
8077        let mut Result: XMVECTOR;
8078        Result = XMVector2LengthSq(V);
8079        Result = XMVectorSqrt(Result);
8080        return Result;
8081    }
8082
8083    #[cfg(_XM_ARM_NEON_INTRINSICS_)]
8084    {
8085        unimplemented!()
8086    }
8087
8088    #[cfg(all(_XM_SSE4_INTRINSICS_))]
8089    unsafe {
8090        let vTemp: XMVECTOR = _mm_dp_ps(V, V, 0x3f);
8091        return _mm_sqrt_ps(vTemp);
8092    }
8093
8094    #[cfg(all(_XM_SSE3_INTRINSICS_, not(_XM_SSE4_INTRINSICS_)))]
8095    unsafe {
8096        let mut vLengthSq: XMVECTOR = _mm_mul_ps(V, V);
8097        let vTemp: XMVECTOR = _mm_hadd_ps(vLengthSq, vLengthSq);
8098        vLengthSq = _mm_sqrt_ss(vTemp);
8099        vLengthSq = XM_PERMUTE_PS!(vLengthSq, _MM_SHUFFLE(0, 0, 0, 0));
8100        return vLengthSq;
8101    }
8102
8103    #[cfg(all(_XM_SSE_INTRINSICS_, not(_XM_SSE3_INTRINSICS_), not(_XM_SSE4_INTRINSICS_)))]
8104    unsafe {
8105        // Perform the dot product on x and y
8106        let mut vLengthSq: XMVECTOR = _mm_mul_ps(V, V);
8107        // vTemp has y splatted
8108        let vTemp: XMVECTOR = XM_PERMUTE_PS!(vLengthSq, _MM_SHUFFLE(1, 1, 1, 1));
8109        // x+y
8110        vLengthSq = _mm_add_ss(vLengthSq, vTemp);
8111        vLengthSq = XM_PERMUTE_PS!(vLengthSq, _MM_SHUFFLE(0, 0, 0, 0));
8112        vLengthSq = _mm_sqrt_ps(vLengthSq);
8113        return vLengthSq;
8114    }
8115}
8116
8117/// Estimates the normalized version of a 2D vector.
8118///
8119/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVector2NormalizeEst>
8120#[inline]
8121pub fn XMVector2NormalizeEst(
8122    V: FXMVECTOR,
8123) -> XMVECTOR
8124{
8125    #[cfg(_XM_NO_INTRINSICS_)]
8126    {
8127        let mut Result: XMVECTOR;
8128        Result = XMVector2ReciprocalLength(V);
8129        Result = XMVectorMultiply(V, Result);
8130        return Result;
8131    }
8132
8133    #[cfg(_XM_ARM_NEON_INTRINSICS_)]
8134    {
8135        unimplemented!()
8136    }
8137
8138    #[cfg(all(_XM_SSE4_INTRINSICS_))]
8139    unsafe {
8140        let vTemp: XMVECTOR = _mm_dp_ps(V, V, 0x3f);
8141        let vResult: XMVECTOR = _mm_rsqrt_ps(vTemp);
8142        return _mm_mul_ps(vResult, V);
8143    }
8144
8145    #[cfg(all(_XM_SSE3_INTRINSICS_, not(_XM_SSE4_INTRINSICS_)))]
8146    unsafe {
8147        // Perform the dot product on x and y
8148        let mut vLengthSq: XMVECTOR = _mm_mul_ps(V, V);
8149        // vTemp has y splatted
8150        let vTemp: XMVECTOR = XM_PERMUTE_PS!(vLengthSq, _MM_SHUFFLE(1, 1, 1, 1));
8151        // x+y
8152        vLengthSq = _mm_add_ss(vLengthSq, vTemp);
8153        vLengthSq = _mm_rsqrt_ss(vLengthSq);
8154        vLengthSq = XM_PERMUTE_PS!(vLengthSq, _MM_SHUFFLE(0, 0, 0, 0));
8155        vLengthSq = _mm_mul_ps(vLengthSq, V);
8156        return vLengthSq;
8157    }
8158
8159    #[cfg(all(_XM_SSE_INTRINSICS_, not(_XM_SSE3_INTRINSICS_), not(_XM_SSE4_INTRINSICS_)))]
8160    unsafe {
8161        // Perform the dot product on x and y only
8162        let mut vLengthSq: XMVECTOR = _mm_mul_ps(V, V);
8163        let vTemp: XMVECTOR = XM_PERMUTE_PS!(vLengthSq, _MM_SHUFFLE(1, 1, 1, 1));
8164        vLengthSq = _mm_add_ss(vLengthSq, vTemp);
8165        vLengthSq = XM_PERMUTE_PS!(vLengthSq, _MM_SHUFFLE(0, 0, 0, 0));
8166        // Prepare for the division
8167        let mut vResult: XMVECTOR = _mm_sqrt_ps(vLengthSq);
8168        // Create zero with a single instruction
8169        let mut vZeroMask: XMVECTOR = _mm_setzero_ps();
8170        // Test for a divide by zero (Must be FP to detect -0.0)
8171        vZeroMask = _mm_cmpneq_ps(vZeroMask, vResult);
8172        // Failsafe on zero (Or epsilon) length planes
8173        // If the length is infinity, set the elements to zero
8174        vLengthSq = _mm_cmpneq_ps(vLengthSq, g_XMInfinity.v);
8175        // Reciprocal mul to perform the normalization
8176        vResult = _mm_div_ps(V, vResult);
8177        // Any that are infinity, set to zero
8178        vResult = _mm_and_ps(vResult, vZeroMask);
8179        // Select qnan or result based on infinite length
8180        let vTemp1: XMVECTOR = _mm_andnot_ps(vLengthSq, g_XMQNaN.v);
8181        let vTemp2: XMVECTOR = _mm_and_ps(vResult, vLengthSq);
8182        vResult = _mm_or_ps(vTemp1, vTemp2);
8183        return vResult;
8184    }
8185}
8186
8187/// Returns the normalized version of a 2D vector.
8188///
8189/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVector2Normalize>
8190#[inline]
8191pub fn XMVector2Normalize(
8192    V: FXMVECTOR,
8193) -> XMVECTOR
8194{
8195    #[cfg(_XM_NO_INTRINSICS_)]
8196    unsafe {
8197        let mut vResult: XMVECTOR = XMVector2Length(V);
8198        let mut fLength: f32 = vResult.vector4_f32[0];
8199
8200        // Prevent divide by zero
8201        if (fLength > 0.0)
8202        {
8203            fLength = 1.0 / fLength;
8204        }
8205
8206        vResult.vector4_f32[0] = V.vector4_f32[0] * fLength;
8207        vResult.vector4_f32[1] = V.vector4_f32[1] * fLength;
8208        vResult.vector4_f32[2] = V.vector4_f32[2] * fLength;
8209        vResult.vector4_f32[3] = V.vector4_f32[3] * fLength;
8210        return vResult;
8211    }
8212
8213    #[cfg(_XM_ARM_NEON_INTRINSICS_)]
8214    {
8215        unimplemented!()
8216    }
8217
8218    #[cfg(all(_XM_SSE4_INTRINSICS_))]
8219    unsafe {
8220        let mut vLengthSq: XMVECTOR = _mm_dp_ps(V, V, 0x3f);
8221        // Prepare for the division
8222        let mut vResult: XMVECTOR = _mm_sqrt_ps(vLengthSq);
8223        // Create zero with a single instruction
8224        let mut vZeroMask: XMVECTOR = _mm_setzero_ps();
8225        // Test for a divide by zero (Must be FP to detect -0.0)
8226        vZeroMask = _mm_cmpneq_ps(vZeroMask, vResult);
8227        // Failsafe on zero (Or epsilon) length planes
8228        // If the length is infinity, set the elements to zero
8229        vLengthSq = _mm_cmpneq_ps(vLengthSq, g_XMInfinity.v);
8230        // Reciprocal mul to perform the normalization
8231        vResult = _mm_div_ps(V, vResult);
8232        // Any that are infinity, set to zero
8233        vResult = _mm_and_ps(vResult, vZeroMask);
8234        // Select qnan or result based on infinite length
8235        let vTemp1: XMVECTOR = _mm_andnot_ps(vLengthSq, g_XMQNaN.v);
8236        let vTemp2: XMVECTOR = _mm_and_ps(vResult, vLengthSq);
8237        vResult = _mm_or_ps(vTemp1, vTemp2);
8238        return vResult;
8239    }
8240
8241    #[cfg(all(_XM_SSE3_INTRINSICS_, not(_XM_SSE4_INTRINSICS_)))]
8242    unsafe {
8243        // Perform the dot product on x and y only
8244        let mut vLengthSq: XMVECTOR = _mm_mul_ps(V, V);
8245        vLengthSq = _mm_hadd_ps(vLengthSq, vLengthSq);
8246        vLengthSq = _mm_moveldup_ps(vLengthSq);
8247        // Prepare for the division
8248        let mut vResult: XMVECTOR = _mm_sqrt_ps(vLengthSq);
8249        // Create zero with a single instruction
8250        let mut vZeroMask: XMVECTOR = _mm_setzero_ps();
8251        // Test for a divide by zero (Must be FP to detect -0.0)
8252        vZeroMask = _mm_cmpneq_ps(vZeroMask, vResult);
8253        // Failsafe on zero (Or epsilon) length planes
8254        // If the length is infinity, set the elements to zero
8255        vLengthSq = _mm_cmpneq_ps(vLengthSq, g_XMInfinity.v);
8256        // Reciprocal mul to perform the normalization
8257        vResult = _mm_div_ps(V, vResult);
8258        // Any that are infinity, set to zero
8259        vResult = _mm_and_ps(vResult, vZeroMask);
8260        // Select qnan or result based on infinite length
8261        let vTemp1: XMVECTOR = _mm_andnot_ps(vLengthSq, g_XMQNaN.v);
8262        let vTemp2: XMVECTOR = _mm_and_ps(vResult, vLengthSq);
8263        vResult = _mm_or_ps(vTemp1, vTemp2);
8264        return vResult;
8265    }
8266
8267    #[cfg(all(_XM_SSE_INTRINSICS_, not(_XM_SSE3_INTRINSICS_), not(_XM_SSE4_INTRINSICS_)))]
8268    unsafe {
8269        // Perform the dot product on x and y only
8270        let mut vLengthSq: XMVECTOR = _mm_mul_ps(V, V);
8271        let vTemp: XMVECTOR = XM_PERMUTE_PS!(vLengthSq, _MM_SHUFFLE(1, 1, 1, 1));
8272        vLengthSq = _mm_add_ss(vLengthSq, vTemp);
8273        vLengthSq = XM_PERMUTE_PS!(vLengthSq, _MM_SHUFFLE(0, 0, 0, 0));
8274        // Prepare for the division
8275        let mut vResult: XMVECTOR = _mm_sqrt_ps(vLengthSq);
8276        // Create zero with a single instruction
8277        let mut vZeroMask: XMVECTOR = _mm_setzero_ps();
8278        // Test for a divide by zero (Must be FP to detect -0.0)
8279        vZeroMask = _mm_cmpneq_ps(vZeroMask, vResult);
8280        // Failsafe on zero (Or epsilon) length planes
8281        // If the length is infinity, set the elements to zero
8282        vLengthSq = _mm_cmpneq_ps(vLengthSq, g_XMInfinity.v);
8283        // Reciprocal mul to perform the normalization
8284        vResult = _mm_div_ps(V, vResult);
8285        // Any that are infinity, set to zero
8286        vResult = _mm_and_ps(vResult, vZeroMask);
8287        // Select qnan or result based on infinite length
8288        let vTemp1: XMVECTOR = _mm_andnot_ps(vLengthSq, g_XMQNaN.v);
8289        let vTemp2: XMVECTOR = _mm_and_ps(vResult, vLengthSq);
8290        vResult = _mm_or_ps(vTemp1, vTemp2);
8291        return vResult;
8292    }
8293}
8294
8295/// Clamps the length of a 2D vector to a given range.
8296///
8297/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVector2ClampLength>
8298#[inline]
8299pub fn XMVector2ClampLength(
8300    V: FXMVECTOR,
8301    LengthMin: f32,
8302    LengthMax: f32,
8303) -> XMVECTOR
8304{
8305    let ClampMax: XMVECTOR = XMVectorReplicate(LengthMax);
8306    let ClampMin: XMVECTOR = XMVectorReplicate(LengthMin);
8307    return XMVector2ClampLengthV(V, ClampMin, ClampMax);
8308}
8309
8310/// Clamps the length of a 2D vector to a given range.
8311///
8312/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVector2ClampLengthV>
8313#[inline]
8314pub fn XMVector2ClampLengthV(
8315    V: FXMVECTOR,
8316    LengthMin: FXMVECTOR,
8317    LengthMax: FXMVECTOR,
8318) -> XMVECTOR
8319{
8320    unsafe {
8321        debug_assert!((XMVectorGetY(LengthMin) == XMVectorGetX(LengthMin)));
8322        debug_assert!((XMVectorGetY(LengthMax) == XMVectorGetX(LengthMax)));
8323        debug_assert!(XMVector2GreaterOrEqual(LengthMin, g_XMZero.v));
8324        debug_assert!(XMVector2GreaterOrEqual(LengthMax, g_XMZero.v));
8325        debug_assert!(XMVector2GreaterOrEqual(LengthMax, LengthMin));
8326
8327        let LengthSq: XMVECTOR = XMVector2LengthSq(V);
8328
8329        // const
8330        let Zero: XMVECTOR = XMVectorZero();
8331
8332        let RcpLength: XMVECTOR = XMVectorReciprocalSqrt(LengthSq);
8333
8334        let InfiniteLength: XMVECTOR = XMVectorEqualInt(LengthSq, g_XMInfinity.v);
8335        let ZeroLength: XMVECTOR = XMVectorEqual(LengthSq, Zero);
8336
8337        let mut Length: XMVECTOR = XMVectorMultiply(LengthSq, RcpLength);
8338
8339        let mut Normal: XMVECTOR = XMVectorMultiply(V, RcpLength);
8340
8341        let Select: XMVECTOR = XMVectorEqualInt(InfiniteLength, ZeroLength);
8342        Length = XMVectorSelect(LengthSq, Length, Select);
8343        Normal = XMVectorSelect(LengthSq, Normal, Select);
8344
8345        let ControlMax: XMVECTOR = XMVectorGreater(Length, LengthMax);
8346        let ControlMin: XMVECTOR = XMVectorLess(Length, LengthMin);
8347
8348        let mut ClampLength: XMVECTOR = XMVectorSelect(Length, LengthMax, ControlMax);
8349        ClampLength = XMVectorSelect(ClampLength, LengthMin, ControlMin);
8350
8351        let mut Result: XMVECTOR = XMVectorMultiply(Normal, ClampLength);
8352
8353        // Preserve the original vector (with no precision loss) if the length falls within the given range
8354        let Control: XMVECTOR = XMVectorEqualInt(ControlMax, ControlMin);
8355        Result = XMVectorSelect(Result, V, Control);
8356
8357        return Result;
8358    }
8359}
8360
8361/// Reflects an incident 2D vector across a 2D normal vector.
8362///
8363/// ## Parameters
8364///
8365/// `Incident` 2D incident vector to reflect.
8366///
8367/// `Normal` 2D normal vector to reflect the incident vector across.
8368///
8369/// ## Return value
8370///
8371/// Returns the reflected incident angle.
8372///
8373/// ## Remarks
8374///
8375/// The following pseudocode demonstrates the operation of the function:
8376///
8377/// ```text
8378/// XMVECTOR Result;
8379///
8380/// float s = 2.0f * (Incident.x * Normal.x + Incident.y * Normal.y);    // 2.0 * dot(Incident, Normal);
8381///
8382/// Result.x = Incident.x - s * Normal.x;
8383/// Result.y = Incident.y - s * Normal.y;
8384/// Result.z = undefined;
8385/// Result.w = undefined;
8386///
8387/// return Result;
8388/// ```
8389///
8390/// ## Reference
8391///
8392/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVector2Reflect>
8393#[inline]
8394pub fn XMVector2Reflect(
8395    Incident: FXMVECTOR,
8396    Normal: FXMVECTOR,
8397) -> XMVECTOR
8398{
8399    // Result = Incident - (2 * dot(Incident, Normal)) * Normal
8400
8401    let mut Result: XMVECTOR;
8402    Result = XMVector2Dot(Incident, Normal);
8403    Result = XMVectorAdd(Result, Result);
8404    Result = XMVectorNegativeMultiplySubtract(Result, Normal, Incident);
8405    return Result;
8406}
8407
8408/// Refracts an incident 2D vector across a 2D normal vector.
8409///
8410/// ## Parameters
8411///
8412/// `Incident` 2D incident vector to refract.
8413///
8414/// `Normal` 2D normal vector to refract the incident vector through.
8415///
8416/// `RefractionIndex` Index of refraction. See remarks.
8417///
8418/// ## Return value
8419///
8420/// Returns the refracted incident vector. If the refraction index and the angle between the incident vector
8421/// and the normal are such that the result is a total internal reflection, the function will return a vector
8422/// of the form < `0.0`, `0.0`, undefined, undefined >.
8423///
8424/// ## Remarks
8425///
8426/// The following pseudocode demonstrates the operation of the function:
8427///
8428/// ```text
8429/// XMVECTOR Result;
8430///
8431/// float t = (Incident.x * Normal.x + Incident.y * Normal.y); // dot(Incident, Normal);
8432/// float r = 1.0f - RefractionIndex * RefractionIndex * (1.0f - t * t);
8433///
8434/// if (r < 0.0f) // Total internal reflection
8435/// {
8436///     Result.x = 0.0f;
8437///     Result.y = 0.0f;
8438/// }
8439/// else
8440/// {
8441///     float s = RefractionIndex * t + sqrt(r);
8442///     Result.x = RefractionIndex * Incident.x - s * Normal.x;
8443///     Result.y = RefractionIndex * Incident.y - s * Normal.y;
8444/// }
8445///
8446/// Result.z = undefined;
8447/// Result.w = undefined;
8448///
8449/// return Result;
8450/// ```
8451///
8452/// The index of refraction is the ratio of the index of refraction of the medium containing the incident
8453/// vector to the index of refraction of the medium being entered (where the index of refraction of a medium
8454/// is itself the ratio of the speed of light in a vacuum to the speed of light in the medium).
8455///
8456/// ## Reference
8457///
8458/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVector2Refract>
8459#[inline]
8460pub fn XMVector2Refract(
8461    Incident: FXMVECTOR,
8462    Normal: FXMVECTOR,
8463    RefractionIndex: f32,
8464) -> XMVECTOR
8465{
8466    let Index: XMVECTOR = XMVectorReplicate(RefractionIndex);
8467    return XMVector2RefractV(Incident, Normal, Index);
8468}
8469
8470/// Refracts an incident 2D vector across a 2D normal vector.
8471///
8472/// ## Parameters
8473///
8474/// `Incident` 2D incident vector to refract.
8475///
8476/// `Normal` 2D normal vector to refract the incident vector through.
8477///
8478/// `RefractionIndex` 2D vector whose `x` and `y`-components are both equal to the index of refraction.
8479///
8480/// ## Return value
8481///
8482/// Returns the refracted incident vector. If the refraction index and the angle between the incident vector
8483/// and the normal are such that the result is a total internal reflection, the function will return a vector
8484/// of the form < `0.0`, `0.0`, undefined, undefined >.
8485///
8486/// ## Remarks
8487///
8488/// This function is identical to XMVector2Refract except that the RefractionIndex is supplied using a 2D
8489/// vector instead of a float value.
8490///
8491/// ## Reference
8492///
8493/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVector2RefractV>
8494#[inline]
8495pub fn XMVector2RefractV(
8496    Incident: FXMVECTOR,
8497    Normal: FXMVECTOR,
8498    RefractionIndex: FXMVECTOR,
8499) -> XMVECTOR
8500{
8501    // Result = RefractionIndex * Incident - Normal * (RefractionIndex * dot(Incident, Normal) +
8502    // sqrt(1 - RefractionIndex * RefractionIndex * (1 - dot(Incident, Normal) * dot(Incident, Normal))))
8503
8504    #[cfg(_XM_NO_INTRINSICS_)]
8505    unsafe {
8506        let IDotN: f32 = (Incident.vector4_f32[0] * Normal.vector4_f32[0]) + (Incident.vector4_f32[1] * Normal.vector4_f32[1]);
8507        // R = 1.0f - RefractionIndex * RefractionIndex * (1.0f - IDotN * IDotN)
8508        let mut RY: f32 = 1.0 - (IDotN * IDotN);
8509        let mut RX: f32 = 1.0 - (RY * RefractionIndex.vector4_f32[0] * RefractionIndex.vector4_f32[0]);
8510        RY = 1.0 - (RY * RefractionIndex.vector4_f32[1] * RefractionIndex.vector4_f32[1]);
8511        if (RX >= 0.0)
8512        {
8513            RX = (RefractionIndex.vector4_f32[0] * Incident.vector4_f32[0]) - (Normal.vector4_f32[0] * ((RefractionIndex.vector4_f32[0] * IDotN) + sqrtf(RX)));
8514        }
8515        else
8516        {
8517            RX = 0.0;
8518        }
8519        if (RY >= 0.0)
8520        {
8521            RY = (RefractionIndex.vector4_f32[1] * Incident.vector4_f32[1]) - (Normal.vector4_f32[1] * ((RefractionIndex.vector4_f32[1] * IDotN) + sqrtf(RY)));
8522        }
8523        else
8524        {
8525            RY = 0.0;
8526        }
8527
8528        let mut vResult: XMVECTOR = crate::undefined();
8529        vResult.vector4_f32[0] = RX;
8530        vResult.vector4_f32[1] = RY;
8531        vResult.vector4_f32[2] = 0.0;
8532        vResult.vector4_f32[3] = 0.0;
8533        return vResult;
8534    }
8535
8536    #[cfg(_XM_ARM_NEON_INTRINSICS_)]
8537    {
8538        unimplemented!()
8539    }
8540
8541    #[cfg(_XM_SSE_INTRINSICS_)]
8542    unsafe {
8543        // Result = RefractionIndex * Incident - Normal * (RefractionIndex * dot(Incident, Normal) +
8544        // sqrt(1 - RefractionIndex * RefractionIndex * (1 - dot(Incident, Normal) * dot(Incident, Normal))))
8545        // Get the 2D Dot product of Incident-Normal
8546        let IDotN: XMVECTOR = XMVector2Dot(Incident, Normal);
8547        // vTemp = 1.0f - RefractionIndex * RefractionIndex * (1.0f - IDotN * IDotN)
8548        let mut vTemp: XMVECTOR = XM_FNMADD_PS!(IDotN, IDotN, g_XMOne.v);
8549        vTemp = _mm_mul_ps(vTemp, RefractionIndex);
8550        vTemp = XM_FNMADD_PS!(vTemp, RefractionIndex, g_XMOne.v);
8551        // If any terms are <=0, sqrt() will fail, punt to zero
8552        let vMask: XMVECTOR = _mm_cmpgt_ps(vTemp, g_XMZero.v);
8553        // R = RefractionIndex * IDotN + sqrt(R)
8554        vTemp = _mm_sqrt_ps(vTemp);
8555        vTemp = XM_FMADD_PS!(RefractionIndex, IDotN, vTemp);
8556        // Result = RefractionIndex * Incident - Normal * R
8557        let mut vResult: XMVECTOR = _mm_mul_ps(RefractionIndex, Incident);
8558        vResult = XM_FNMADD_PS!(vTemp, Normal, vResult);
8559        vResult = _mm_and_ps(vResult, vMask);
8560        return vResult;
8561    }
8562}
8563
8564/// Computes a vector perpendicular to a 2D vector.
8565///
8566/// ## Parameters
8567///
8568/// `V` 2D vector.
8569///
8570/// ## Return value
8571///
8572/// Returns the 2D vector orthogonal to `V`.
8573///
8574/// ## Remarks
8575///
8576/// Note that a 'cross-product' in 2D is not well-defined. This function computes a generalized cross-product
8577/// in 2D. XMVector2Cross is another possible interpretation of a 'cross-product' in 2D.
8578///
8579/// The following pseudocode demonstrates the operation of the function:
8580///
8581/// ```text
8582/// XMVECTOR Result;
8583///
8584/// Result.x = -V.y;
8585/// Result.y = V.x;
8586/// Result.z = 0;
8587/// Result.w = 0;
8588///
8589/// return Result;
8590/// ```
8591///
8592/// ## Reference
8593///
8594/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVector2Orthogonal>
8595#[inline]
8596pub fn XMVector2Orthogonal(
8597    V: FXMVECTOR,
8598) -> XMVECTOR
8599{
8600    #[cfg(_XM_NO_INTRINSICS_)]
8601    unsafe {
8602        let Result: XMVECTORF32 = XMVECTORF32 { f: [
8603            -V.vector4_f32[1],
8604            V.vector4_f32[0],
8605            0.0,
8606            0.0
8607        ]};
8608        return Result.v;
8609    }
8610
8611    #[cfg(_XM_ARM_NEON_INTRINSICS_)]
8612    {
8613        unimplemented!()
8614    }
8615
8616    #[cfg(all(_XM_SSE_INTRINSICS_))]
8617    unsafe {
8618        let mut vResult: XMVECTOR = XM_PERMUTE_PS!(V, _MM_SHUFFLE(3, 2, 0, 1));
8619        vResult = _mm_mul_ps(vResult, g_XMNegateX.v);
8620        return vResult;
8621    }
8622}
8623
8624/// Estimates the radian angle between two normalized 2D vectors.
8625///
8626/// ## Parameters
8627///
8628/// `N1` Normalized 2D vector.
8629///
8630/// `N2` Normalized 2D vector.
8631///
8632/// ## Return value
8633///
8634/// Returns a vector. The estimate of the radian angle (between `N1` and `N2`) is replicated to each of the
8635/// components.
8636///
8637/// ## Remarks
8638///
8639/// `Est` functions offer increased performance at the expense of reduced accuracy. `Est` functions are appropriate
8640/// for non-critical calculations where accuracy can be sacrificed for speed. The exact amount of lost accuracy
8641/// and speed increase are platform dependent.
8642///
8643/// ## Reference
8644///
8645/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVector2AngleBetweenNormalsEst>
8646#[inline]
8647pub fn XMVector2AngleBetweenNormalsEst(
8648    N1: FXMVECTOR,
8649    N2: FXMVECTOR,
8650) -> XMVECTOR
8651{
8652    unsafe {
8653        let mut Result: XMVECTOR = XMVector2Dot(N1, N2);
8654        Result = XMVectorClamp(Result, g_XMNegativeOne.v, g_XMOne.v);
8655        Result = XMVectorACosEst(Result);
8656        return Result;
8657    }
8658}
8659
8660/// Computes the radian angle between two normalized 2D vectors.
8661///
8662/// ## Parameters
8663///
8664/// `N1` Normalized 2D vector.
8665///
8666/// `N2` Normalized 2D vector.
8667///
8668/// ## Return value
8669///
8670/// Returns a vector. The radian angle between `N1` and `N2` is replicated to each of the components.
8671///
8672/// ## Reference
8673///
8674/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVector2AngleBetweenNormals>
8675#[inline]
8676pub fn XMVector2AngleBetweenNormals(
8677    N1: FXMVECTOR,
8678    N2: FXMVECTOR,
8679) -> XMVECTOR
8680{
8681    unsafe {
8682        let mut Result: XMVECTOR = XMVector2Dot(N1, N2);
8683        Result = XMVectorClamp(Result, g_XMNegativeOne.v, g_XMOne.v);
8684        Result = XMVectorACos(Result);
8685        return Result;
8686    }
8687}
8688
8689/// Computes the radian angle between two 2D vectors.
8690///
8691/// ## Parameters
8692///
8693/// `V1` 2D vector.
8694///
8695/// `V2` 2D vector.
8696///
8697/// ## Return value
8698///
8699/// Returns a vector. The radian angle between `V1` and `V2` is replicated to each of the components.
8700///
8701/// ## Remarks
8702///
8703/// If `V1` and `V2` are normalized 2D vectors, it is faster to use XMVector2AngleBetweenNormals.
8704///
8705/// ## Reference
8706///
8707/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVector2AngleBetweenVectors>
8708#[inline]
8709pub fn XMVector2AngleBetweenVectors(
8710    V1: FXMVECTOR,
8711    V2: FXMVECTOR,
8712) -> XMVECTOR
8713{
8714    unsafe {
8715        let mut L1: XMVECTOR = XMVector2ReciprocalLength(V1);
8716        let L2: XMVECTOR = XMVector2ReciprocalLength(V2);
8717
8718        let Dot: XMVECTOR = XMVector2Dot(V1, V2);
8719
8720        L1 = XMVectorMultiply(L1, L2);
8721
8722        let mut CosAngle: XMVECTOR = XMVectorMultiply(Dot, L1);
8723        CosAngle = XMVectorClamp(CosAngle, g_XMNegativeOne.v, g_XMOne.v);
8724
8725        return XMVectorACos(CosAngle);
8726    }
8727}
8728
8729/// Computes the minimum distance between a line and a point.
8730///
8731/// ## Parameters
8732///
8733/// `LinePoint1` 2D vector describing a point on the line.
8734///
8735/// `LinePoint2` 2D vector describing a point on the line.
8736///
8737/// `Point` 2D vector describing the reference point.
8738///
8739/// ## Return value
8740///
8741/// Returns a vector. The minimum distance between the line and the point is replicated to each of the components.
8742///
8743/// ## Reference
8744///
8745/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVector2LinePointDistance>
8746#[inline]
8747pub fn XMVector2LinePointDistance(
8748    LinePoint1: FXMVECTOR,
8749    LinePoint2: FXMVECTOR,
8750    Point: FXMVECTOR,
8751) -> XMVECTOR
8752{
8753    // Given a vector PointVector from LinePoint1 to Point and a vector
8754    // LineVector from LinePoint1 to LinePoint2, the scaled distance
8755    // PointProjectionScale from LinePoint1 to the perpendicular projection
8756    // of PointVector onto the line is defined as:
8757    //
8758    //     PointProjectionScale = dot(PointVector, LineVector) / LengthSq(LineVector)
8759
8760    let PointVector: XMVECTOR = XMVectorSubtract(Point, LinePoint1);
8761    let LineVector: XMVECTOR = XMVectorSubtract(LinePoint2, LinePoint1);
8762
8763    let LengthSq: XMVECTOR = XMVector2LengthSq(LineVector);
8764
8765    let mut PointProjectionScale: XMVECTOR = XMVector2Dot(PointVector, LineVector);
8766    PointProjectionScale = XMVectorDivide(PointProjectionScale, LengthSq);
8767
8768    let mut DistanceVector: XMVECTOR = XMVectorMultiply(LineVector, PointProjectionScale);
8769    DistanceVector = XMVectorSubtract(PointVector, DistanceVector);
8770
8771    return XMVector2Length(DistanceVector);
8772}
8773
8774/// Finds the intersection of two lines.
8775///
8776/// ## Parameters
8777///
8778/// `Line1Point1` 2D vector describing the first point on the first line.
8779///
8780/// `Line1Point2` 2D vector describing a second point on the first line.
8781///
8782/// `Line2Point1` 2D vector describing the first point on the second line.
8783///
8784/// `Line2Point2` 2D vector describing a second point on the second line.
8785///
8786/// ## Return value
8787///
8788/// Returns the intersection point. If the lines are parallel, the returned vector will be a `NaN`. If the
8789/// two lines are coincident, the returned vector will be positive infinity.
8790///
8791/// ## Reference
8792///
8793/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVector2IntersectLine>
8794#[inline]
8795pub fn XMVector2IntersectLine(
8796    Line1Point1: FXMVECTOR,
8797    Line1Point2: FXMVECTOR,
8798    Line2Point1: FXMVECTOR,
8799    Line2Point2: FXMVECTOR,
8800) -> XMVECTOR
8801{
8802    #[cfg(_XM_NO_INTRINSICS_)]
8803    unsafe {
8804        let V1: XMVECTOR = XMVectorSubtract(Line1Point2, Line1Point1);
8805        let V2: XMVECTOR = XMVectorSubtract(Line2Point2, Line2Point1);
8806        let V3: XMVECTOR = XMVectorSubtract(Line1Point1, Line2Point1);
8807
8808        let C1: XMVECTOR = XMVector2Cross(V1, V2);
8809        let C2: XMVECTOR = XMVector2Cross(V2, V3);
8810
8811        let Result: XMVECTOR;
8812        // const let Zero: XMVECTOR = XMVectorZero();
8813        const Zero: XMVECTOR = unsafe { g_XMZero.v };
8814        if (XMVector2NearEqual(C1, Zero, g_XMEpsilon.v))
8815        {
8816            if (XMVector2NearEqual(C2, Zero, g_XMEpsilon.v))
8817            {
8818                // Coincident
8819                Result = g_XMInfinity.v;
8820            }
8821            else
8822            {
8823                // Parallel
8824                Result = g_XMQNaN.v;
8825            }
8826        }
8827        else
8828        {
8829            // let point: Intersection = Line1Point1 + V1 * (C2 / C1)
8830            let mut Scale: XMVECTOR = XMVectorReciprocal(C1);
8831            Scale = XMVectorMultiply(C2, Scale);
8832            Result = XMVectorMultiplyAdd(V1, Scale, Line1Point1);
8833        }
8834
8835        return Result;
8836    }
8837
8838    #[cfg(_XM_ARM_NEON_INTRINSICS_)]
8839    {
8840        unimplemented!()
8841    }
8842
8843    #[cfg(all(_XM_SSE_INTRINSICS_))]
8844    unsafe {
8845        let V1: XMVECTOR = _mm_sub_ps(Line1Point2, Line1Point1);
8846        let V2: XMVECTOR = _mm_sub_ps(Line2Point2, Line2Point1);
8847        let V3: XMVECTOR = _mm_sub_ps(Line1Point1, Line2Point1);
8848        // Generate the cross products
8849        let C1: XMVECTOR = XMVector2Cross(V1, V2);
8850        let C2: XMVECTOR = XMVector2Cross(V2, V3);
8851        // If C1 is not close to epsilon, use the calculated value
8852        let mut vResultMask: XMVECTOR = _mm_setzero_ps();
8853        vResultMask = _mm_sub_ps(vResultMask, C1);
8854        vResultMask = _mm_max_ps(vResultMask, C1);
8855        // 0xFFFFFFFF if the calculated value is to be used
8856        vResultMask = _mm_cmpgt_ps(vResultMask, g_XMEpsilon.v);
8857        // If C1 is close to epsilon, which fail type is it? INFINITY or NAN?
8858        let mut vFailMask: XMVECTOR = _mm_setzero_ps();
8859        vFailMask = _mm_sub_ps(vFailMask, C2);
8860        vFailMask = _mm_max_ps(vFailMask, C2);
8861        vFailMask = _mm_cmple_ps(vFailMask, g_XMEpsilon.v);
8862        let mut vFail: XMVECTOR = _mm_and_ps(vFailMask, g_XMInfinity.v);
8863        vFailMask = _mm_andnot_ps(vFailMask, g_XMQNaN.v);
8864        // vFail is NAN or INF
8865        vFail = _mm_or_ps(vFail, vFailMask);
8866        // let point: Intersection = Line1Point1 + V1 * (C2 / C1)
8867        let mut vResult: XMVECTOR = _mm_div_ps(C2, C1);
8868        vResult = XM_FMADD_PS!(vResult, V1, Line1Point1);
8869        // Use result, or failure value
8870        vResult = _mm_and_ps(vResult, vResultMask);
8871        vResultMask = _mm_andnot_ps(vResultMask, vFail);
8872        vResult = _mm_or_ps(vResult, vResultMask);
8873        return vResult;
8874    }
8875}
8876
8877/// Transforms a 2D vector by a matrix.
8878///
8879/// ## Parameters
8880///
8881/// `V` 2D vector.
8882///
8883/// `M` Transformation matrix.
8884///
8885/// ## Return value
8886///
8887/// Returns the transformed vector.
8888///
8889/// ## Remarks
8890///
8891/// [`XMVector2Transform`] performs transformations by using the input matrix rows `0` and `1` for
8892/// rotation and scaling, and row `3` for translation (effectively assuming row `2` is `0`). The
8893/// `w` component of the input vector is assumed to be `0`. The `z` component of the output
8894/// vector should be ignored and its `w` component may be non-homogeneous (`!= 1.0`).
8895///
8896/// ## Reference
8897///
8898/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVector2Transform>
8899///
8900/// [`XMVector2Transform`]: XMVector2Transform
8901#[inline]
8902pub fn XMVector2Transform(
8903    V: FXMVECTOR,
8904    M: FXMMATRIX,
8905) -> FXMVECTOR
8906{
8907    #[cfg(_XM_NO_INTRINSICS_)]
8908    unsafe {
8909        let Y: XMVECTOR = XMVectorSplatY(V);
8910        let X: XMVECTOR = XMVectorSplatX(V);
8911
8912        let mut Result: XMVECTOR = XMVectorMultiplyAdd(Y, M.r[1], M.r[3]);
8913        Result = XMVectorMultiplyAdd(X, M.r[0], Result);
8914
8915        return Result;
8916    }
8917
8918    #[cfg(_XM_ARM_NEON_INTRINSICS_)]
8919    {
8920        unimplemented!()
8921    }
8922
8923    #[cfg(_XM_SSE_INTRINSICS_)]
8924    unsafe {
8925        let mut vResult: XMVECTOR = XM_PERMUTE_PS!(V, _MM_SHUFFLE(1, 1, 1, 1)); // Y
8926        vResult = XM_FMADD_PS!(vResult, M.r[1], M.r[3]);
8927        let vTemp: XMVECTOR = XM_PERMUTE_PS!(V, _MM_SHUFFLE(0, 0, 0, 0)); // X
8928        vResult = XM_FMADD_PS!(vTemp, M.r[0], vResult);
8929        return vResult;
8930    }
8931}
8932
8933// TODO: XMVector2TransformStream
8934
8935/// Transforms a 2D vector by a given matrix, projecting the result back into `w = 1`.
8936///
8937/// ## Parameters
8938///
8939/// `V` 2D vector.
8940///
8941/// `M` Transformation matrix.
8942///
8943/// ## Return value
8944///
8945/// Returns the transformed vector.
8946///
8947/// ## Remarks
8948///
8949/// [`XMVector2TransformCoord`] performs transformations by using the input matrix row `0` and row `1` for
8950/// rotation and scaling, and row `3` for translation (effectively assuming row `2` is `0`). The `w`
8951/// component of the input vector is assumed to be `1.0`. The `z` component of the returned vector
8952/// should be ignored and its `w` component will have a value of `1.0`.
8953///
8954/// ## Reference
8955///
8956/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVector2TransformCoord>
8957///
8958/// [`XMVector2TransformCoord`]: XMVector2TransformCoord
8959#[inline]
8960pub fn XMVector2TransformCoord(
8961    V: FXMVECTOR,
8962    M: FXMMATRIX,
8963) -> FXMVECTOR {
8964    unsafe {
8965        let Y: XMVECTOR = XMVectorSplatY(V);
8966        let X: XMVECTOR = XMVectorSplatX(V);
8967
8968        let mut Result: XMVECTOR = XMVectorMultiplyAdd(Y, M.r[1], M.r[3]);
8969        Result = XMVectorMultiplyAdd(X, M.r[0], Result);
8970
8971        let W: XMVECTOR = XMVectorSplatW(Result);
8972        return XMVectorDivide(Result, W);
8973    }
8974}
8975
8976// TODO: XMVector2TransformCoordStream
8977
8978/// Transforms a 2D vector by a matrix.
8979///
8980/// ## Parameters
8981///
8982/// `V` 2D normal vector.
8983///
8984/// `M` Transformation matrix.
8985///
8986/// ## Return value
8987///
8988/// Returns the transformed vector.
8989///
8990/// ## Remarks
8991///
8992/// [`XMVector2TransformNormal`] uses row `0` and `1` of the input transformation matrix for
8993/// rotation and scaling. Rows `2` and `3` are ignored.
8994///
8995/// ## Reference
8996///
8997/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVector2TransformNormal>
8998#[inline]
8999pub fn XMVector2TransformNormal(
9000    V: FXMVECTOR,
9001    M: FXMMATRIX,
9002) -> FXMVECTOR
9003{
9004    #[cfg(_XM_NO_INTRINSICS_)]
9005    unsafe {
9006        let Y: XMVECTOR = XMVectorSplatY(V);
9007        let X: XMVECTOR = XMVectorSplatX(V);
9008
9009        let mut Result: XMVECTOR = XMVectorMultiply(Y, M.r[1]);
9010        Result = XMVectorMultiplyAdd(X, M.r[0], Result);
9011
9012        return Result;
9013    }
9014
9015    #[cfg(_XM_ARM_NEON_INTRINSICS_)]
9016    {
9017        unimplemented!()
9018    }
9019
9020    #[cfg(_XM_SSE_INTRINSICS_)]
9021    unsafe {
9022        let mut vResult: XMVECTOR = XM_PERMUTE_PS!(V, _MM_SHUFFLE(1, 1, 1, 1)); // Y
9023        vResult = _mm_mul_ps(vResult, M.r[1]);
9024        let vTemp: XMVECTOR = XM_PERMUTE_PS!(V, _MM_SHUFFLE(0, 0, 0, 0)); // X
9025        vResult = XM_FMADD_PS!(vTemp, M.r[0], vResult);
9026        return vResult;
9027    }
9028}
9029
9030// TODO: XMVector2TransformNormalStream
9031
9032// 3D Vector
9033
9034/// Tests whether two 3D vectors are equal.
9035///
9036/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVector3Equal>
9037#[inline]
9038pub fn XMVector3Equal(
9039    V1: FXMVECTOR,
9040    V2: FXMVECTOR,
9041) -> bool
9042{
9043    #[cfg(_XM_NO_INTRINSICS_)]
9044    unsafe {
9045        return (((V1.vector4_f32[0] == V2.vector4_f32[0]) && (V1.vector4_f32[1] == V2.vector4_f32[1]) && (V1.vector4_f32[2] == V2.vector4_f32[2])) != false);
9046    }
9047
9048    #[cfg(_XM_ARM_NEON_INTRINSICS_)]
9049    {
9050        unimplemented!()
9051    }
9052
9053    #[cfg(_XM_SSE_INTRINSICS_)]
9054    unsafe {
9055        let vTemp: XMVECTOR = _mm_cmpeq_ps(V1, V2);
9056        return (((_mm_movemask_ps(vTemp) & 7) == 7) != false);
9057    }
9058}
9059
9060#[test]
9061fn test_XMVector3Equal() {
9062    let a = XMVectorReplicate(1.0);
9063    let b = XMVectorReplicate(1.0);
9064
9065    assert!(XMVector3Equal(a, b));
9066    assert!(XMVector3Equal(a, XMVectorSetW(b, 2.0)));
9067
9068    assert!(!XMVector3Equal(a, XMVectorSetX(b, 2.0)));
9069    assert!(!XMVector3Equal(a, XMVectorSetY(b, 2.0)));
9070    assert!(!XMVector3Equal(a, XMVectorSetZ(b, 2.0)));
9071}
9072
9073/// Tests whether two 3D vectors are equal. In addition, this function returns
9074/// a comparison value that can be examined using functions such as XMComparisonAllTrue.
9075///
9076/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVector3EqualR>
9077#[inline]
9078pub fn XMVector3EqualR(
9079    V1: FXMVECTOR,
9080    V2: FXMVECTOR,
9081) -> u32
9082{
9083    #[cfg(_XM_NO_INTRINSICS_)]
9084    unsafe {
9085        let mut CR: u32 = 0;
9086        if ((V1.vector4_f32[0] == V2.vector4_f32[0]) &&
9087            (V1.vector4_f32[1] == V2.vector4_f32[1]) &&
9088            (V1.vector4_f32[2] == V2.vector4_f32[2]))
9089        {
9090            CR = XM_CRMASK_CR6TRUE;
9091        }
9092        else if ((V1.vector4_f32[0] != V2.vector4_f32[0]) &&
9093            (V1.vector4_f32[1] != V2.vector4_f32[1]) &&
9094            (V1.vector4_f32[2] != V2.vector4_f32[2]))
9095        {
9096            CR = XM_CRMASK_CR6FALSE;
9097        }
9098        return CR;
9099    }
9100
9101    #[cfg(_XM_ARM_NEON_INTRINSICS_)]
9102    {
9103        unimplemented!()
9104    }
9105
9106    #[cfg(_XM_SSE_INTRINSICS_)]
9107    unsafe {
9108        let vTemp: XMVECTOR = _mm_cmpeq_ps(V1, V2);
9109        let iTest: i32 = _mm_movemask_ps(vTemp) & 7;
9110        let mut CR: u32 = 0;
9111        if (iTest == 7)
9112        {
9113            CR = XM_CRMASK_CR6TRUE;
9114        }
9115        else if !ibool(iTest)
9116        {
9117            CR = XM_CRMASK_CR6FALSE;
9118        }
9119        return CR;
9120    }
9121}
9122
9123#[test]
9124fn test_XMVector3EqualR() {
9125    let a = XMVectorReplicate(1.0);
9126    let b = XMVectorReplicate(1.0);
9127
9128    let r = XMVector3EqualR(a, b);
9129    assert!(XMComparisonAnyTrue(r));
9130    assert!(!XMComparisonAnyFalse(r));
9131    assert!(XMComparisonAllTrue(r));
9132    assert!(!XMComparisonAllFalse(r));
9133
9134    let r = XMVector3EqualR(a, XMVectorReplicate(2.0));
9135    assert!(!XMComparisonAnyTrue(r));
9136    assert!(XMComparisonAnyFalse(r));
9137    assert!(!XMComparisonAllTrue(r));
9138    assert!(XMComparisonAllFalse(r));
9139
9140    let r = XMVector3EqualR(a, XMVectorSetX(b, 2.0));
9141    assert!(XMComparisonAnyTrue(r));
9142    assert!(XMComparisonAnyFalse(r));
9143    assert!(!XMComparisonAllTrue(r));
9144    assert!(!XMComparisonAllFalse(r));
9145}
9146
9147/// Tests whether two 3D vectors are equal, treating each component as an unsigned integer.
9148///
9149/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVector3EqualInt>
9150#[inline]
9151pub fn XMVector3EqualInt(
9152    V1: FXMVECTOR,
9153    V2: FXMVECTOR,
9154) -> bool
9155{
9156    #[cfg(_XM_NO_INTRINSICS_)]
9157    unsafe {
9158        return (((V1.vector4_u32[0] == V2.vector4_u32[0]) && (V1.vector4_u32[1] == V2.vector4_u32[1]) && (V1.vector4_u32[2] == V2.vector4_u32[2])) != false);
9159    }
9160
9161    #[cfg(_XM_ARM_NEON_INTRINSICS_)]
9162    {
9163        unimplemented!()
9164    }
9165
9166    #[cfg(_XM_SSE_INTRINSICS_)]
9167    unsafe {
9168        let vTemp: __m128i = _mm_cmpeq_epi32(_mm_castps_si128(V1), _mm_castps_si128(V2));
9169        return (((_mm_movemask_ps(_mm_castsi128_ps(vTemp)) & 7) == 7) != false);
9170    }
9171}
9172
9173/// Tests whether two 3D vectors are equal, treating each component as an
9174/// unsigned integer. In addition, this function returns a comparison value
9175/// that can be examined using functions such as XMComparisonAllTrue.
9176///
9177/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVector3EqualIntR>
9178#[inline]
9179pub fn XMVector3EqualIntR(
9180    V1: FXMVECTOR,
9181    V2: FXMVECTOR,
9182) -> u32
9183{
9184    #[cfg(_XM_NO_INTRINSICS_)]
9185    unsafe {
9186        let mut CR: u32 = 0;
9187        if ((V1.vector4_u32[0] == V2.vector4_u32[0]) &&
9188            (V1.vector4_u32[1] == V2.vector4_u32[1]) &&
9189            (V1.vector4_u32[2] == V2.vector4_u32[2]))
9190        {
9191            CR = XM_CRMASK_CR6TRUE;
9192        }
9193        else if ((V1.vector4_u32[0] != V2.vector4_u32[0]) &&
9194            (V1.vector4_u32[1] != V2.vector4_u32[1]) &&
9195            (V1.vector4_u32[2] != V2.vector4_u32[2]))
9196        {
9197            CR = XM_CRMASK_CR6FALSE;
9198        }
9199        return CR;
9200    }
9201
9202    #[cfg(_XM_ARM_NEON_INTRINSICS_)]
9203    {
9204        unimplemented!()
9205    }
9206
9207    #[cfg(_XM_SSE_INTRINSICS_)]
9208    unsafe {
9209        let vTemp: __m128i = _mm_cmpeq_epi32(_mm_castps_si128(V1), _mm_castps_si128(V2));
9210        let iTemp: i32 = _mm_movemask_ps(_mm_castsi128_ps(vTemp)) & 7;
9211        let mut CR: u32 = 0;
9212        if (iTemp == 7)
9213        {
9214            CR = XM_CRMASK_CR6TRUE;
9215        }
9216        else if !ibool(iTemp)
9217        {
9218            CR = XM_CRMASK_CR6FALSE;
9219        }
9220        return CR;
9221    }
9222}
9223
9224/// Tests whether one 3D vector is near another 3D vector.
9225///
9226/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVector3NearEqual>
9227#[inline]
9228pub fn XMVector3NearEqual(
9229    V1: FXMVECTOR,
9230    V2: FXMVECTOR,
9231    Epsilon: FXMVECTOR,
9232) -> bool
9233{
9234    #[cfg(_XM_NO_INTRINSICS_)]
9235    unsafe {
9236        let (dx, dy, dz): (f32, f32, f32);
9237
9238        dx = fabsf(V1.vector4_f32[0] - V2.vector4_f32[0]);
9239        dy = fabsf(V1.vector4_f32[1] - V2.vector4_f32[1]);
9240        dz = fabsf(V1.vector4_f32[2] - V2.vector4_f32[2]);
9241        return (((dx <= Epsilon.vector4_f32[0]) &&
9242            (dy <= Epsilon.vector4_f32[1]) &&
9243            (dz <= Epsilon.vector4_f32[2])) != false);
9244    }
9245
9246    #[cfg(_XM_ARM_NEON_INTRINSICS_)]
9247    {
9248        unimplemented!()
9249    }
9250
9251    #[cfg(_XM_SSE_INTRINSICS_)]
9252    unsafe {
9253        // Get the difference
9254        let vDelta: XMVECTOR = _mm_sub_ps(V1, V2);
9255        // Get the absolute value of the difference
9256        let mut vTemp: XMVECTOR = _mm_setzero_ps();
9257        vTemp = _mm_sub_ps(vTemp, vDelta);
9258        vTemp = _mm_max_ps(vTemp, vDelta);
9259        vTemp = _mm_cmple_ps(vTemp, Epsilon);
9260        // w is don't care
9261        return (((_mm_movemask_ps(vTemp) & 7) == 0x7) != false);
9262    }
9263}
9264
9265/// Tests whether two 3D vectors are not equal.
9266///
9267/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVector3NotEqual>
9268#[inline]
9269pub fn XMVector3NotEqual(
9270    V1: FXMVECTOR,
9271    V2: FXMVECTOR,
9272) -> bool
9273{
9274    #[cfg(_XM_NO_INTRINSICS_)]
9275    unsafe {
9276        return (((V1.vector4_f32[0] != V2.vector4_f32[0]) || (V1.vector4_f32[1] != V2.vector4_f32[1]) || (V1.vector4_f32[2] != V2.vector4_f32[2])) != false);
9277    }
9278
9279    #[cfg(_XM_ARM_NEON_INTRINSICS_)]
9280    {
9281        unimplemented!()
9282    }
9283
9284    #[cfg(_XM_SSE_INTRINSICS_)]
9285    unsafe {
9286        let vTemp: XMVECTOR = _mm_cmpeq_ps(V1, V2);
9287        return (((_mm_movemask_ps(vTemp) & 7) != 7) != false);
9288    }
9289}
9290
9291/// Test whether two 3D vectors are not equal, treating each component as an unsigned integer.
9292///
9293/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVector3NotEqualInt>
9294#[inline]
9295pub fn XMVector3NotEqualInt(
9296    V1: FXMVECTOR,
9297    V2: FXMVECTOR,
9298) -> bool
9299{
9300    #[cfg(_XM_NO_INTRINSICS_)]
9301    unsafe {
9302        return (((V1.vector4_u32[0] != V2.vector4_u32[0]) || (V1.vector4_u32[1] != V2.vector4_u32[1]) || (V1.vector4_u32[2] != V2.vector4_u32[2])) != false);
9303    }
9304
9305    #[cfg(_XM_ARM_NEON_INTRINSICS_)]
9306    {
9307        unimplemented!()
9308    }
9309
9310    #[cfg(_XM_SSE_INTRINSICS_)]
9311    unsafe {
9312        let vTemp: __m128i = _mm_cmpeq_epi32(_mm_castps_si128(V1), _mm_castps_si128(V2));
9313        return (((_mm_movemask_ps(_mm_castsi128_ps(vTemp)) & 7) != 7) != false);
9314    }
9315}
9316
9317/// Tests whether one 3D vector is greater than another 3D vector.
9318///
9319/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVector3Greater>
9320#[inline]
9321pub fn XMVector3Greater(
9322    V1: FXMVECTOR,
9323    V2: FXMVECTOR,
9324) -> bool
9325{
9326    #[cfg(_XM_NO_INTRINSICS_)]
9327    unsafe {
9328        return (((V1.vector4_f32[0] > V2.vector4_f32[0]) && (V1.vector4_f32[1] > V2.vector4_f32[1]) && (V1.vector4_f32[2] > V2.vector4_f32[2])) != false);
9329    }
9330
9331    #[cfg(_XM_ARM_NEON_INTRINSICS_)]
9332    {
9333        unimplemented!()
9334    }
9335
9336    #[cfg(_XM_SSE_INTRINSICS_)]
9337    unsafe {
9338        let vTemp: XMVECTOR = _mm_cmpgt_ps(V1, V2);
9339        return (((_mm_movemask_ps(vTemp) & 7) == 7) != false);
9340    }
9341}
9342
9343/// Tests whether one 3D vector is greater than another 3D vector and returns a
9344/// comparison value that can be examined using functions such as XMComparisonAllTrue.
9345///
9346/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVector3GreaterR>
9347#[inline]
9348pub fn XMVector3GreaterR(
9349    V1: FXMVECTOR,
9350    V2: FXMVECTOR,
9351) -> u32
9352{
9353    #[cfg(_XM_NO_INTRINSICS_)]
9354    unsafe {
9355        let mut CR: u32 = 0;
9356        if ((V1.vector4_f32[0] > V2.vector4_f32[0]) &&
9357            (V1.vector4_f32[1] > V2.vector4_f32[1]) &&
9358            (V1.vector4_f32[2] > V2.vector4_f32[2]))
9359        {
9360            CR = XM_CRMASK_CR6TRUE;
9361        }
9362        else if ((V1.vector4_f32[0] <= V2.vector4_f32[0]) &&
9363            (V1.vector4_f32[1] <= V2.vector4_f32[1]) &&
9364            (V1.vector4_f32[2] <= V2.vector4_f32[2]))
9365        {
9366            CR = XM_CRMASK_CR6FALSE;
9367        }
9368        return CR;
9369    }
9370
9371    #[cfg(_XM_ARM_NEON_INTRINSICS_)]
9372    {
9373        unimplemented!()
9374    }
9375
9376    #[cfg(_XM_SSE_INTRINSICS_)]
9377    unsafe {
9378        let vTemp: XMVECTOR = _mm_cmpgt_ps(V1, V2);
9379        let mut CR: u32 = 0;
9380        let iTest: i32 = _mm_movemask_ps(vTemp) & 7;
9381        if (iTest == 7)
9382        {
9383            CR = XM_CRMASK_CR6TRUE;
9384        }
9385        else if !ibool(iTest)
9386        {
9387            CR = XM_CRMASK_CR6FALSE;
9388        }
9389        return CR;
9390    }
9391}
9392
9393/// Tests whether one 3D vector is greater-than-or-equal-to another 3D vector.
9394///
9395/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVector3GreaterOrEqual>
9396#[inline]
9397pub fn XMVector3GreaterOrEqual(
9398    V1: FXMVECTOR,
9399    V2: FXMVECTOR,
9400) -> bool
9401{
9402    #[cfg(_XM_NO_INTRINSICS_)]
9403    unsafe {
9404        return (((V1.vector4_f32[0] >= V2.vector4_f32[0]) && (V1.vector4_f32[1] >= V2.vector4_f32[1]) && (V1.vector4_f32[2] >= V2.vector4_f32[2])) != false);
9405    }
9406
9407    #[cfg(_XM_ARM_NEON_INTRINSICS_)]
9408    {
9409        unimplemented!()
9410    }
9411
9412    #[cfg(_XM_SSE_INTRINSICS_)]
9413    unsafe {
9414        let vTemp: XMVECTOR = _mm_cmpge_ps(V1, V2);
9415        return (((_mm_movemask_ps(vTemp) & 7) == 7) != false);
9416    }
9417}
9418
9419/// Tests whether one 3D vector is greater-than-or-equal-to another 3D vector and returns a
9420/// comparison value that can be examined using functions such as XMComparisonAllTrue.
9421///
9422/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVector3GreaterOrEqualR>
9423#[inline]
9424pub fn XMVector3GreaterOrEqualR(
9425    V1: FXMVECTOR,
9426    V2: FXMVECTOR,
9427) -> u32
9428{
9429    #[cfg(_XM_NO_INTRINSICS_)]
9430    unsafe {
9431        let mut CR: u32 = 0;
9432        if ((V1.vector4_f32[0] >= V2.vector4_f32[0]) &&
9433            (V1.vector4_f32[1] >= V2.vector4_f32[1]) &&
9434            (V1.vector4_f32[2] >= V2.vector4_f32[2]))
9435        {
9436            CR = XM_CRMASK_CR6TRUE;
9437        }
9438        else if ((V1.vector4_f32[0] < V2.vector4_f32[0]) &&
9439            (V1.vector4_f32[1] < V2.vector4_f32[1]) &&
9440            (V1.vector4_f32[2] < V2.vector4_f32[2]))
9441        {
9442            CR = XM_CRMASK_CR6FALSE;
9443        }
9444        return CR;
9445    }
9446
9447    #[cfg(_XM_ARM_NEON_INTRINSICS_)]
9448    {
9449        unimplemented!()
9450    }
9451
9452    #[cfg(_XM_SSE_INTRINSICS_)]
9453    unsafe {
9454        let vTemp: XMVECTOR = _mm_cmpge_ps(V1, V2);
9455        let mut CR: u32 = 0;
9456        let iTest: i32 = _mm_movemask_ps(vTemp) & 7;
9457        if (iTest == 7)
9458        {
9459            CR = XM_CRMASK_CR6TRUE;
9460        }
9461        else if !ibool(iTest)
9462        {
9463            CR = XM_CRMASK_CR6FALSE;
9464        }
9465        return CR;
9466    }
9467}
9468
9469/// Tests whether one 3D vector is less than another 3D vector.
9470///
9471/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVector3Less>
9472#[inline]
9473pub fn XMVector3Less(
9474    V1: FXMVECTOR,
9475    V2: FXMVECTOR,
9476) -> bool
9477{
9478    #[cfg(_XM_NO_INTRINSICS_)]
9479    unsafe {
9480        return (((V1.vector4_f32[0] < V2.vector4_f32[0]) && (V1.vector4_f32[1] < V2.vector4_f32[1]) && (V1.vector4_f32[2] < V2.vector4_f32[2])) != false);
9481    }
9482
9483    #[cfg(_XM_ARM_NEON_INTRINSICS_)]
9484    {
9485        unimplemented!()
9486    }
9487
9488    #[cfg(_XM_SSE_INTRINSICS_)]
9489    unsafe {
9490        let vTemp: XMVECTOR = _mm_cmplt_ps(V1, V2);
9491        return (((_mm_movemask_ps(vTemp) & 7) == 7) != false);
9492    }
9493}
9494
9495
9496/// Tests whether one 3D vector is less than or equal to another 3D vector.
9497///
9498/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVector3LessOrEqual>
9499#[inline]
9500pub fn XMVector3LessOrEqual(
9501    V1: FXMVECTOR,
9502    V2: FXMVECTOR,
9503) -> bool
9504{
9505    #[cfg(_XM_NO_INTRINSICS_)]
9506    unsafe {
9507        return (((V1.vector4_f32[0] <= V2.vector4_f32[0]) && (V1.vector4_f32[1] <= V2.vector4_f32[1]) && (V1.vector4_f32[2] <= V2.vector4_f32[2])) != false);
9508    }
9509
9510    #[cfg(_XM_ARM_NEON_INTRINSICS_)]
9511    {
9512        unimplemented!()
9513    }
9514
9515    #[cfg(_XM_SSE_INTRINSICS_)]
9516    unsafe {
9517        let vTemp: XMVECTOR = _mm_cmple_ps(V1, V2);
9518        return (((_mm_movemask_ps(vTemp) & 7) == 7) != false);
9519    }
9520}
9521
9522/// Tests whether the components of a 3D vector are within set bounds.
9523///
9524/// ## Parameters
9525///
9526/// `V` 3D vector to test.
9527///
9528/// `Bounds` 3D vector that determines the bounds.
9529///
9530/// ## Return value
9531///
9532/// Returns `true` if both the `x`, `y`, and `z-component`s of `V` are within the set bounds, and `false` otherwise.
9533///
9534/// ## Remarks
9535///
9536/// The following pseudocode demonstrates the operation of the function:
9537///
9538/// ```text
9539// return (V.x <= Bounds.x && V.x >= -Bounds.x) &&
9540//        (V.y <= Bounds.y && V.y >= -Bounds.y) &&
9541//        (V.z <= Bounds.z && V.z >= -Bounds.z);
9542/// ```
9543///
9544/// ## Reference
9545///
9546/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVector3InBounds>
9547#[inline]
9548pub fn XMVector3InBounds(
9549    V: FXMVECTOR,
9550    Bounds: FXMVECTOR,
9551) -> bool
9552{
9553    #[cfg(_XM_NO_INTRINSICS_)]
9554    unsafe {
9555        return (((V.vector4_f32[0] <= Bounds.vector4_f32[0] && V.vector4_f32[0] >= -Bounds.vector4_f32[0]) &&
9556            (V.vector4_f32[1] <= Bounds.vector4_f32[1] && V.vector4_f32[1] >= -Bounds.vector4_f32[1]) &&
9557            (V.vector4_f32[2] <= Bounds.vector4_f32[2] && V.vector4_f32[2] >= -Bounds.vector4_f32[2])) != false);
9558    }
9559
9560    #[cfg(_XM_ARM_NEON_INTRINSICS_)]
9561    {
9562        unimplemented!()
9563    }
9564
9565    #[cfg(_XM_SSE_INTRINSICS_)]
9566    unsafe {
9567        // Test if less than or equal
9568        let mut vTemp1: XMVECTOR = _mm_cmple_ps(V, Bounds);
9569        // Negate the bounds
9570        let mut vTemp2: XMVECTOR = _mm_mul_ps(Bounds, g_XMNegativeOne.v);
9571        // Test if greater or equal (Reversed)
9572        vTemp2 = _mm_cmple_ps(vTemp2, V);
9573        // Blend answers
9574        vTemp1 = _mm_and_ps(vTemp1, vTemp2);
9575        // x,y and z in bounds? (w is don't care)
9576        return (((_mm_movemask_ps(vTemp1) & 0x7) == 0x7) != false);
9577    }
9578
9579    // NOTE: The source contains a fallback that does not seem to be reachable.
9580    // return XMComparisonAllInBounds(XMVector3InBoundsR(V, Bounds));
9581}
9582
9583/// Tests whether any component of a 3D vector is a NaN.
9584///
9585/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVector3IsNaN>
9586#[inline]
9587pub fn XMVector3IsNaN(
9588    V: FXMVECTOR,
9589) -> bool
9590{
9591    #[cfg(_XM_NO_INTRINSICS_)]
9592    unsafe {
9593        return (XMISNAN!(V.vector4_f32[0]) ||
9594            XMISNAN!(V.vector4_f32[1]) ||
9595            XMISNAN!(V.vector4_f32[2]));
9596    }
9597
9598    #[cfg(_XM_ARM_NEON_INTRINSICS_)]
9599    {
9600        unimplemented!()
9601    }
9602
9603    #[cfg(_XM_SSE_INTRINSICS_)]
9604    unsafe {
9605        // Test against itself. NaN is always not equal
9606        let vTempNan: XMVECTOR = _mm_cmpneq_ps(V, V);
9607        // If x or y or z are NaN, the mask is non-zero
9608        return ((_mm_movemask_ps(vTempNan) & 7) != 0);
9609    }
9610}
9611
9612/// Tests whether any component of a 3D vector is positive or negative infinity.
9613///
9614/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVector3IsInfinite>
9615#[inline]
9616pub fn XMVector3IsInfinite(
9617    V: FXMVECTOR,
9618) -> bool
9619{
9620    #[cfg(_XM_NO_INTRINSICS_)]
9621    unsafe {
9622        return (XMISINF!(V.vector4_f32[0]) ||
9623            XMISINF!(V.vector4_f32[1]) ||
9624            XMISINF!(V.vector4_f32[2]));
9625    }
9626
9627    #[cfg(_XM_ARM_NEON_INTRINSICS_)]
9628    {
9629        unimplemented!()
9630    }
9631
9632    #[cfg(_XM_SSE_INTRINSICS_)]
9633    unsafe {
9634        // Mask off the sign bit
9635        let mut vTemp: __m128 = _mm_and_ps(V, g_XMAbsMask.v);
9636        // Compare to infinity
9637        vTemp = _mm_cmpeq_ps(vTemp, g_XMInfinity.v);
9638        // If x,y or z are infinity, the signs are true.
9639        return ((_mm_movemask_ps(vTemp) & 7) != 0);
9640    }
9641}
9642
9643/// Computes the dot product between 3D vectors.
9644///
9645/// ## Parameters
9646///
9647/// `V1` 3D vector.
9648///
9649/// `V2` 3D vector.
9650///
9651/// ## Return value
9652///
9653/// Returns a vector. The dot product between `V1` and `V2` is replicated into each component.
9654///
9655/// ## Reference
9656///
9657/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVector3Dot>
9658#[inline]
9659pub fn XMVector3Dot(
9660    V1: FXMVECTOR,
9661    V2: FXMVECTOR,
9662) -> FXMVECTOR
9663{
9664    #[cfg(_XM_NO_INTRINSICS_)]
9665    unsafe {
9666        let fValue: f32 = V1.vector4_f32[0] * V2.vector4_f32[0] + V1.vector4_f32[1] * V2.vector4_f32[1] + V1.vector4_f32[2] * V2.vector4_f32[2];
9667        let mut vResult: XMVECTORF32 = crate::undefined();
9668        vResult.f[0] = fValue;
9669        vResult.f[1] = fValue;
9670        vResult.f[2] = fValue;
9671        vResult.f[3] = fValue;
9672        return vResult.v;
9673    }
9674
9675    #[cfg(_XM_ARM_NEON_INTRINSICS_)]
9676    {
9677        unimplemented!()
9678    }
9679
9680    #[cfg(_XM_SSE4_INTRINSICS_)]
9681    unsafe {
9682        return _mm_dp_ps(V1, V2, 0x7f);
9683    }
9684
9685    // Using `bench_BoundingOrientedBox_Intersects_BoundingOrientedBox` as a measure, the SSE3
9686    // intrinsics actually perform worse. We'll add it for completeness, but disabled for now.
9687    // #[cfg(all(_XM_SSE3_INTRINSICS_, not(_XM_SSE4_INTRINSICS_)))]
9688    // unsafe {
9689    //     let mut vTemp: XMVECTOR = _mm_mul_ps(V1, V2);
9690    //     vTemp = _mm_and_ps(vTemp, g_XMMask3.v);
9691    //     vTemp = _mm_hadd_ps(vTemp, vTemp);
9692    //     return _mm_hadd_ps(vTemp, vTemp);
9693    // }
9694    //
9695    // #[cfg(all(_XM_SSE_INTRINSICS_, not(_XM_SSE3_INTRINSICS_), not(_XM_SSE4_INTRINSICS_)))]
9696
9697    #[cfg(all(_XM_SSE_INTRINSICS_, not(_XM_SSE4_INTRINSICS_)))]
9698    unsafe {
9699        // Perform the dot product
9700        let mut vDot: XMVECTOR = _mm_mul_ps(V1, V2);
9701        // x=Dot.vector4_f32[1], y=Dot.vector4_f32[2]
9702        let mut vTemp: XMVECTOR = XM_PERMUTE_PS!(vDot, _MM_SHUFFLE(2, 1, 2, 1));
9703        // Result.vector4_f32[0] = x+y
9704        vDot = _mm_add_ss(vDot, vTemp);
9705        // x=Dot.vector4_f32[2]
9706        vTemp = XM_PERMUTE_PS!(vTemp, _MM_SHUFFLE(1, 1, 1, 1));
9707        // Result.vector4_f32[0] = (x+y)+z
9708        vDot = _mm_add_ss(vDot, vTemp);
9709        // Splat x
9710        return XM_PERMUTE_PS!(vDot, _MM_SHUFFLE(0, 0, 0, 0));
9711    }
9712}
9713
9714/// Computes the cross product between 3D vectors.
9715///
9716/// ## Parameters
9717///
9718/// `V1` 3D vector.
9719///
9720/// `V2` 3D vector.
9721///
9722/// ## Return value
9723///
9724/// Returns the cross product of `V1` and V2.
9725///
9726/// ## Remarks
9727///
9728/// The following pseudocode demonstrates the operation of the function:
9729///
9730/// ```text
9731/// XMVECTOR Result;
9732/// Result.x = (V1.y * V2.z) - (V1.z * V2.y);
9733/// Result.y = (V1.z * V2.x) - (V1.x * V2.z);
9734/// Result.z = (V1.x * V2.y) - (V1.y * V2.x);
9735/// Result.w = 0;
9736/// return Result;
9737/// ```
9738///
9739/// ## Reference
9740///
9741/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVector3Cross>
9742#[inline]
9743pub fn XMVector3Cross(
9744    V1: FXMVECTOR,
9745    V2: FXMVECTOR,
9746) -> FXMVECTOR
9747{
9748    #[cfg(_XM_NO_INTRINSICS_)]
9749    unsafe {
9750        let vResult = XMVECTORF32 {
9751            f: [
9752                (V1.vector4_f32[1] * V2.vector4_f32[2]) - (V1.vector4_f32[2] * V2.vector4_f32[1]),
9753                (V1.vector4_f32[2] * V2.vector4_f32[0]) - (V1.vector4_f32[0] * V2.vector4_f32[2]),
9754                (V1.vector4_f32[0] * V2.vector4_f32[1]) - (V1.vector4_f32[1] * V2.vector4_f32[0]),
9755                0.0
9756            ]
9757        };
9758        return vResult.v;
9759    }
9760
9761    #[cfg(_XM_ARM_NEON_INTRINSICS_)]
9762    {
9763        unimplemented!()
9764    }
9765
9766    #[cfg(_XM_SSE_INTRINSICS_)]
9767    unsafe {
9768        // y1,z1,x1,w1
9769        let mut vTemp1: XMVECTOR = XM_PERMUTE_PS!(V1, _MM_SHUFFLE(3, 0, 2, 1));
9770        // z2,x2,y2,w2
9771        let mut vTemp2: XMVECTOR = XM_PERMUTE_PS!(V2, _MM_SHUFFLE(3, 1, 0, 2));
9772        // Perform the left operation
9773        let mut vResult: XMVECTOR = _mm_mul_ps(vTemp1, vTemp2);
9774        // z1,x1,y1,w1
9775        vTemp1 = XM_PERMUTE_PS!(vTemp1, _MM_SHUFFLE(3, 0, 2, 1));
9776        // y2,z2,x2,w2
9777        vTemp2 = XM_PERMUTE_PS!(vTemp2, _MM_SHUFFLE(3, 1, 0, 2));
9778        // Perform the right operation
9779        vResult = XM_FNMADD_PS!(vTemp1, vTemp2, vResult);
9780        // Set w to zero
9781        return _mm_and_ps(vResult, g_XMMask3.v);
9782    }
9783}
9784
9785/// Computes the square of the length of a 3D vector.
9786///
9787/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVector3LengthSq>
9788#[inline]
9789pub fn XMVector3LengthSq(
9790    V: FXMVECTOR,
9791) -> FXMVECTOR
9792{
9793    return XMVector3Dot(V, V);
9794}
9795
9796/// Estimates the reciprocal of the length of a 3D vector.
9797///
9798/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVector3ReciprocalLengthEst>
9799#[inline]
9800pub fn XMVector3ReciprocalLengthEst(
9801    V: FXMVECTOR,
9802) -> FXMVECTOR
9803{
9804    #[cfg(_XM_NO_INTRINSICS_)]
9805    {
9806        let mut Result: XMVECTOR;
9807
9808        Result = XMVector3LengthSq(V);
9809        Result = XMVectorReciprocalSqrtEst(Result);
9810
9811        return Result;
9812    }
9813
9814    #[cfg(_XM_ARM_NEON_INTRINSICS_)]
9815    {
9816        unimplemented!()
9817    }
9818
9819    #[cfg(_XM_SSE4_INTRINSICS_)]
9820    unsafe {
9821        let vTemp: XMVECTOR = _mm_dp_ps(V, V, 0x7f);
9822        return _mm_rsqrt_ps(vTemp);
9823    }
9824
9825    #[cfg(all(_XM_SSE_INTRINSICS_, not(_XM_SSE4_INTRINSICS_)))]
9826    unsafe {
9827        // Perform the dot product on x,y and z
9828        let mut vLengthSq: XMVECTOR = _mm_mul_ps(V, V);
9829        // vTemp has z and y
9830        let mut vTemp: XMVECTOR = XM_PERMUTE_PS!(vLengthSq, _MM_SHUFFLE(1, 2, 1, 2));
9831        // x+z, y
9832        vLengthSq = _mm_add_ss(vLengthSq, vTemp);
9833        // y,y,y,y
9834        vTemp = XM_PERMUTE_PS!(vTemp, _MM_SHUFFLE(1, 1, 1, 1));
9835        // x+z+y,??,??,??
9836        vLengthSq = _mm_add_ss(vLengthSq, vTemp);
9837        // Splat the length squared
9838        vLengthSq = XM_PERMUTE_PS!(vLengthSq, _MM_SHUFFLE(0, 0, 0, 0));
9839        // Get the reciprocal
9840        vLengthSq = _mm_rsqrt_ps(vLengthSq);
9841        return vLengthSq;
9842    }
9843}
9844
9845/// Computes the reciprocal of the length of a 3D vector.
9846///
9847/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVector3ReciprocalLength>
9848#[inline]
9849pub fn XMVector3ReciprocalLength(
9850    V: FXMVECTOR,
9851) -> FXMVECTOR
9852{
9853    #[cfg(_XM_NO_INTRINSICS_)]
9854    {
9855        let mut Result: XMVECTOR;
9856
9857        Result = XMVector3LengthSq(V);
9858        Result = XMVectorReciprocalSqrt(Result);
9859
9860        return Result;
9861    }
9862
9863    #[cfg(_XM_ARM_NEON_INTRINSICS_)]
9864    {
9865        unimplemented!()
9866    }
9867
9868    #[cfg(_XM_SSE4_INTRINSICS_)]
9869    unsafe {
9870        let vTemp: XMVECTOR = _mm_dp_ps(V, V, 0x7f);
9871        let vLengthSq: XMVECTOR = _mm_sqrt_ps(vTemp);
9872        return _mm_div_ps(g_XMOne.v, vLengthSq);
9873    }
9874
9875    #[cfg(all(_XM_SSE3_INTRINSICS_, not(_XM_SSE4_INTRINSICS_)))]
9876    unsafe {
9877        let mut vDot: XMVECTOR = _mm_mul_ps(V, V);
9878        vDot = _mm_and_ps(vDot, g_XMMask3.v);
9879        vDot = _mm_hadd_ps(vDot, vDot);
9880        vDot = _mm_hadd_ps(vDot, vDot);
9881        vDot = _mm_sqrt_ps(vDot);
9882        vDot = _mm_div_ps(g_XMOne.v, vDot);
9883        return vDot
9884    }
9885
9886    #[cfg(all(_XM_SSE_INTRINSICS_, not(_XM_SSE3_INTRINSICS_), not(_XM_SSE4_INTRINSICS_)))]
9887    unsafe {
9888        // Perform the dot product
9889        let mut vDot: XMVECTOR = _mm_mul_ps(V, V);
9890        // x=Dot.y, y=Dot.z
9891        let mut vTemp: XMVECTOR = XM_PERMUTE_PS!(vDot, _MM_SHUFFLE(2, 1, 2, 1));
9892        // Result.x = x+y
9893        vDot = _mm_add_ss(vDot, vTemp);
9894        // x=Dot.z
9895        vTemp = XM_PERMUTE_PS!(vTemp, _MM_SHUFFLE(1, 1, 1, 1));
9896        // Result.x = (x+y)+z
9897        vDot = _mm_add_ss(vDot, vTemp);
9898        // Splat x
9899        vDot = XM_PERMUTE_PS!(vDot, _MM_SHUFFLE(0, 0, 0, 0));
9900        // Get the reciprocal
9901        vDot = _mm_sqrt_ps(vDot);
9902        // Get the reciprocal
9903        vDot = _mm_div_ps(g_XMOne.v, vDot);
9904        return vDot;
9905    }
9906}
9907
9908/// Estimates the length of a 3D vector.
9909///
9910/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVector3LengthEst>
9911#[inline]
9912pub fn XMVector3LengthEst(
9913    V: FXMVECTOR,
9914) -> FXMVECTOR
9915{
9916    #[cfg(_XM_NO_INTRINSICS_)]
9917    {
9918        let mut Result: XMVECTOR;
9919
9920        Result = XMVector3LengthSq(V);
9921        Result = XMVectorSqrtEst(Result);
9922
9923        return Result;
9924    }
9925
9926    #[cfg(_XM_ARM_NEON_INTRINSICS_)]
9927    {
9928        unimplemented!()
9929    }
9930
9931    #[cfg(_XM_SSE4_INTRINSICS_)]
9932    unsafe {
9933        let vTemp: XMVECTOR = _mm_dp_ps(V, V, 0x7f);
9934        return _mm_sqrt_ps(vTemp);
9935    }
9936
9937    #[cfg(all(_XM_SSE3_INTRINSICS_, not(_XM_SSE4_INTRINSICS_)))]
9938    unsafe {
9939        let mut vLengthSq: XMVECTOR = _mm_mul_ps(V, V);
9940        vLengthSq = _mm_and_ps(vLengthSq, g_XMMask3.v);
9941        vLengthSq = _mm_hadd_ps(vLengthSq, vLengthSq);
9942        vLengthSq = _mm_hadd_ps(vLengthSq, vLengthSq);
9943        vLengthSq = _mm_sqrt_ps(vLengthSq);
9944        return vLengthSq;
9945    }
9946
9947    #[cfg(all(_XM_SSE_INTRINSICS_, not(_XM_SSE3_INTRINSICS_), not(_XM_SSE4_INTRINSICS_)))]
9948    unsafe {
9949        // Perform the dot product on x,y and z
9950        let mut vLengthSq: XMVECTOR = _mm_mul_ps(V, V);
9951        // vTemp has z and y
9952        let mut vTemp: XMVECTOR = XM_PERMUTE_PS!(vLengthSq, _MM_SHUFFLE(1, 2, 1, 2));
9953        // x+z, y
9954        vLengthSq = _mm_add_ss(vLengthSq, vTemp);
9955        // y,y,y,y
9956        vTemp = XM_PERMUTE_PS!(vTemp, _MM_SHUFFLE(1, 1, 1, 1));
9957        // x+z+y,??,??,??
9958        vLengthSq = _mm_add_ss(vLengthSq, vTemp);
9959        // Splat the length squared
9960        vLengthSq = XM_PERMUTE_PS!(vLengthSq, _MM_SHUFFLE(0, 0, 0, 0));
9961        // Get the length
9962        vLengthSq = _mm_sqrt_ps(vLengthSq);
9963        return vLengthSq;
9964    }
9965}
9966
9967/// Computes the length of a 3D vector.
9968///
9969/// ## Parameters
9970///
9971/// `V` 3D vector.
9972///
9973/// ## Return value
9974///
9975/// Returns a vector. The length of `V` is replicated into each component.
9976///
9977/// ## Reference
9978///
9979/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVector3Length>
9980#[inline]
9981pub fn XMVector3Length(
9982    V: FXMVECTOR,
9983) -> FXMVECTOR
9984{
9985    #[cfg(_XM_NO_INTRINSICS_)]
9986    {
9987        let mut Result: XMVECTOR;
9988
9989        Result = XMVector3LengthSq(V);
9990        Result = XMVectorSqrt(Result);
9991
9992        return Result;
9993    }
9994
9995    #[cfg(_XM_ARM_NEON_INTRINSICS_)]
9996    {
9997        unimplemented!()
9998    }
9999
10000    #[cfg(_XM_SSE4_INTRINSICS_)]
10001    unsafe {
10002        let vTemp: XMVECTOR = _mm_dp_ps(V, V, 0x7f);
10003        return _mm_sqrt_ps(vTemp);
10004    }
10005
10006    #[cfg(all(_XM_SSE3_INTRINSICS_, not(_XM_SSE4_INTRINSICS_)))]
10007    unsafe {
10008        let mut vLengthSq: XMVECTOR = _mm_mul_ps(V, V);
10009        vLengthSq = _mm_and_ps(vLengthSq, g_XMMask3.v);
10010        vLengthSq = _mm_hadd_ps(vLengthSq, vLengthSq);
10011        vLengthSq = _mm_hadd_ps(vLengthSq, vLengthSq);
10012        vLengthSq = _mm_sqrt_ps(vLengthSq);
10013        return vLengthSq;
10014    }
10015
10016    #[cfg(all(_XM_SSE_INTRINSICS_, not(_XM_SSE3_INTRINSICS_), not(_XM_SSE4_INTRINSICS_)))]
10017    unsafe {
10018        // Perform the dot product on x,y and z
10019        let mut vLengthSq: XMVECTOR = _mm_mul_ps(V, V);
10020        // vTemp has z and y
10021        let mut vTemp: XMVECTOR = XM_PERMUTE_PS!(vLengthSq, _MM_SHUFFLE(1, 2, 1, 2));
10022        // x+z, y
10023        vLengthSq = _mm_add_ss(vLengthSq, vTemp);
10024        // y,y,y,y
10025        vTemp = XM_PERMUTE_PS!(vTemp, _MM_SHUFFLE(1, 1, 1, 1));
10026        // x+z+y,??,??,??
10027        vLengthSq = _mm_add_ss(vLengthSq, vTemp);
10028        // Splat the length squared
10029        vLengthSq = XM_PERMUTE_PS!(vLengthSq, _MM_SHUFFLE(0, 0, 0, 0));
10030        // Get the length
10031        vLengthSq = _mm_sqrt_ps(vLengthSq);
10032        return vLengthSq;
10033    }
10034}
10035
10036/// Estimates the normalized version of a 3D vector.
10037///
10038/// ## Parameters
10039///
10040/// `V` 3D vector.
10041///
10042/// ## Return value
10043///
10044/// Returns an estimate of the normalized version of `V`.
10045///
10046/// ## Remarks
10047///
10048/// For a vector with `0` length or infinite length, this function returns a vector of `QNaN`.
10049///
10050/// `Est` functions offer increased performance at the expense of reduced accuracy. `Est` functions are appropriate
10051/// for non-critical calculations where accuracy can be sacrificed for speed. The exact amount of lost accuracy
10052/// and speed increase are platform dependent.
10053///
10054/// ## Reference
10055///
10056/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVector3NormalizeEst>
10057#[inline]
10058pub fn XMVector3NormalizeEst(
10059    V: FXMVECTOR,
10060) -> FXMVECTOR
10061{
10062    #[cfg(_XM_NO_INTRINSICS_)]
10063    {
10064        let mut Result: XMVECTOR;
10065
10066        Result = XMVector3ReciprocalLength(V);
10067        Result = XMVectorMultiply(V, Result);
10068
10069        return Result;
10070    }
10071
10072    #[cfg(_XM_ARM_NEON_INTRINSICS_)]
10073    {
10074        unimplemented!()
10075    }
10076
10077    #[cfg(_XM_SSE4_INTRINSICS_)]
10078    unsafe {
10079        let vTemp: XMVECTOR = _mm_dp_ps(V, V, 0x7f);
10080        let vResult: XMVECTOR = _mm_rsqrt_ps(vTemp);
10081        return _mm_mul_ps(vResult, V);
10082    }
10083
10084    #[cfg(all(_XM_SSE3_INTRINSICS_, not(_XM_SSE4_INTRINSICS_)))]
10085    unsafe {
10086        let mut vDot: XMVECTOR = _mm_mul_ps(V, V);
10087        vDot = _mm_and_ps(vDot, g_XMMask3.v);
10088        vDot = _mm_hadd_ps(vDot, vDot);
10089        vDot = _mm_hadd_ps(vDot, vDot);
10090        vDot = _mm_rsqrt_ps(vDot);
10091        vDot = _mm_mul_ps(vDot, V);
10092        return vDot;
10093    }
10094
10095    #[cfg(all(_XM_SSE_INTRINSICS_, not(_XM_SSE3_INTRINSICS_), not(_XM_SSE4_INTRINSICS_)))]
10096    unsafe {
10097        // Perform the dot product
10098        let mut vDot: XMVECTOR = _mm_mul_ps(V, V);
10099        // x=Dot.y, y=Dot.z
10100        let mut vTemp: XMVECTOR = XM_PERMUTE_PS!(vDot, _MM_SHUFFLE(2, 1, 2, 1));
10101        // Result.x = x+y
10102        vDot = _mm_add_ss(vDot, vTemp);
10103        // x=Dot.z
10104        vTemp = XM_PERMUTE_PS!(vTemp, _MM_SHUFFLE(1, 1, 1, 1));
10105        // Result.x = (x+y)+z
10106        vDot = _mm_add_ss(vDot, vTemp);
10107        // Splat x
10108        vDot = XM_PERMUTE_PS!(vDot, _MM_SHUFFLE(0, 0, 0, 0));
10109        // Get the reciprocal
10110        vDot = _mm_rsqrt_ps(vDot);
10111        // Perform the normalization
10112        vDot = _mm_mul_ps(vDot, V);
10113        return vDot;
10114    }
10115}
10116
10117/// Returns the normalized version of a 3D vector.
10118///
10119/// ## Parameters
10120///
10121/// `V` 3D vector.
10122///
10123/// ## Return value
10124///
10125/// Returns the normalized version of `V`.
10126///
10127/// ## Remarks
10128///
10129/// For a vector of length `0`, this function returns a zero vector. For a vector with infinite length, it
10130/// returns a vector of `QNaN`.
10131///
10132/// Note that for most graphics applications, ensuring the vectors have well-defined lengths that don't
10133/// cause problems for normalization is common practice. However, if you need a robust normalization that
10134/// works for all floating-point inputs, you can use the following code instead:
10135///
10136/// ```text
10137/// inline XMVECTOR XMVector3NormalizeRobust( FXMVECTOR V )
10138/// {
10139///     // Compute the maximum absolute value component.
10140///     XMVECTOR vAbs = XMVectorAbs(V);
10141///     XMVECTOR max0 = XMVectorSplatX(vAbs);
10142///     XMVECTOR max1 = XMVectorSplatY(vAbs);
10143///     XMVECTOR max2 = XMVectorSplatZ(vAbs);
10144///     max0 = XMVectorMax(max0, max1);
10145///     max0 = XMVectorMax(max0, max2);
10146///
10147///     // Divide by the maximum absolute component.
10148///     XMVECTOR normalized = XMVectorDivide(V, max0);
10149///
10150///     // Set to zero when the original length is zero.
10151///     XMVECTOR mask = XMVectorNotEqual(g_XMZero, max0);
10152///     normalized = XMVectorAndInt(normalized, mask);
10153///
10154///     XMVECTOR t0 = XMVector3LengthSq(normalized);
10155///     XMVECTOR length = XMVectorSqrt(t0);
10156///
10157///     // Divide by the length to normalize.
10158///     normalized = XMVectorDivide(normalized, length);
10159///
10160///     // Set to zero when the original length is zero or infinity.  In the
10161///     // latter case, this is considered to be an unexpected condition.
10162///     normalized = XMVectorAndInt(normalized, mask);
10163///     return normalized;
10164/// }
10165/// ```
10166///
10167/// ## Reference
10168///
10169/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVector3Normalize>
10170#[inline]
10171pub fn XMVector3Normalize(
10172    V: FXMVECTOR,
10173) -> FXMVECTOR
10174{
10175    #[cfg(_XM_NO_INTRINSICS_)]
10176    unsafe {
10177        let mut fLength: f32;
10178        let mut vResult: XMVECTOR;
10179
10180        vResult = XMVector3Length(V);
10181        fLength = vResult.vector4_f32[0];
10182
10183        // Prevent divide by zero
10184        if (fLength > 0.0)
10185        {
10186            fLength = 1.0 / fLength;
10187        }
10188
10189        vResult.vector4_f32[0] = V.vector4_f32[0] * fLength;
10190        vResult.vector4_f32[1] = V.vector4_f32[1] * fLength;
10191        vResult.vector4_f32[2] = V.vector4_f32[2] * fLength;
10192        vResult.vector4_f32[3] = V.vector4_f32[3] * fLength;
10193
10194        return vResult;
10195    }
10196
10197    #[cfg(_XM_ARM_NEON_INTRINSICS_)]
10198    {
10199        unimplemented!()
10200    }
10201
10202    #[cfg(_XM_SSE4_INTRINSICS_)]
10203    unsafe {
10204        let mut vLengthSq: XMVECTOR = _mm_dp_ps(V, V, 0x7f);
10205        // Prepare for the division
10206        let mut vResult: XMVECTOR = _mm_sqrt_ps(vLengthSq);
10207        // Create zero with a single instruction
10208        let mut vZeroMask: XMVECTOR = _mm_setzero_ps();
10209        // Test for a divide by zero (Must be FP to detect -0.0)
10210        vZeroMask = _mm_cmpneq_ps(vZeroMask, vResult);
10211        // Failsafe on zero (Or epsilon) length planes
10212        // If the length is infinity, set the elements to zero
10213        vLengthSq = _mm_cmpneq_ps(vLengthSq, g_XMInfinity.v);
10214        // Divide to perform the normalization
10215        vResult = _mm_div_ps(V, vResult);
10216        // Any that are infinity, set to zero
10217        vResult = _mm_and_ps(vResult, vZeroMask);
10218        // Select qnan or result based on infinite length
10219        let vTemp1: XMVECTOR = _mm_andnot_ps(vLengthSq, g_XMQNaN.v);
10220        let vTemp2: XMVECTOR = _mm_and_ps(vResult, vLengthSq);
10221        vResult = _mm_or_ps(vTemp1, vTemp2);
10222        return vResult;
10223    }
10224
10225    #[cfg(all(_XM_SSE3_INTRINSICS_, not(_XM_SSE4_INTRINSICS_)))]
10226    unsafe {
10227        // Perform the dot product on x,y and z only
10228        let mut vLengthSq: XMVECTOR = _mm_mul_ps(V, V);
10229        vLengthSq = _mm_and_ps(vLengthSq, g_XMMask3.v);
10230        vLengthSq = _mm_hadd_ps(vLengthSq, vLengthSq);
10231        vLengthSq = _mm_hadd_ps(vLengthSq, vLengthSq);
10232        // Prepare for the division
10233        let mut vResult: XMVECTOR = _mm_sqrt_ps(vLengthSq);
10234        // Create zero with a single instruction
10235        let mut vZeroMask: XMVECTOR = _mm_setzero_ps();
10236        // Test for a divide by zero (Must be FP to detect -0.0)
10237        vZeroMask = _mm_cmpneq_ps(vZeroMask, vResult);
10238        // Failsafe on zero (Or epsilon) length planes
10239        // If the length is infinity, set the elements to zero
10240        vLengthSq = _mm_cmpneq_ps(vLengthSq, g_XMInfinity.v);
10241        // Divide to perform the normalization
10242        vResult = _mm_div_ps(V, vResult);
10243        // Any that are infinity, set to zero
10244        vResult = _mm_and_ps(vResult, vZeroMask);
10245        // Select qnan or result based on infinite length
10246        let vTemp1: XMVECTOR = _mm_andnot_ps(vLengthSq, g_XMQNaN.v);
10247        let vTemp2: XMVECTOR = _mm_and_ps(vResult, vLengthSq);
10248        vResult = _mm_or_ps(vTemp1, vTemp2);
10249        return vResult;
10250    }
10251
10252    #[cfg(all(_XM_SSE_INTRINSICS_, not(_XM_SSE3_INTRINSICS_), not(_XM_SSE4_INTRINSICS_)))]
10253    unsafe {
10254        // Perform the dot product on x,y and z only
10255        let mut vLengthSq: XMVECTOR = _mm_mul_ps(V, V);
10256        let mut vTemp: XMVECTOR = XM_PERMUTE_PS!(vLengthSq, _MM_SHUFFLE(2, 1, 2, 1));
10257        vLengthSq = _mm_add_ss(vLengthSq, vTemp);
10258        vTemp = XM_PERMUTE_PS!(vTemp, _MM_SHUFFLE(1, 1, 1, 1));
10259        vLengthSq = _mm_add_ss(vLengthSq, vTemp);
10260        vLengthSq = XM_PERMUTE_PS!(vLengthSq, _MM_SHUFFLE(0, 0, 0, 0));
10261        // Prepare for the division
10262        let mut vResult: XMVECTOR = _mm_sqrt_ps(vLengthSq);
10263        // Create zero with a single instruction
10264        let mut vZeroMask: XMVECTOR = _mm_setzero_ps();
10265        // Test for a divide by zero (Must be FP to detect -0.0)
10266        vZeroMask = _mm_cmpneq_ps(vZeroMask, vResult);
10267        // Failsafe on zero (Or epsilon) length planes
10268        // If the length is infinity, set the elements to zero
10269        vLengthSq = _mm_cmpneq_ps(vLengthSq, g_XMInfinity.v);
10270        // Divide to perform the normalization
10271        vResult = _mm_div_ps(V, vResult);
10272        // Any that are infinity, set to zero
10273        vResult = _mm_and_ps(vResult, vZeroMask);
10274        // Select qnan or result based on infinite length
10275        let vTemp1: XMVECTOR = _mm_andnot_ps(vLengthSq, g_XMQNaN.v);
10276        let vTemp2: XMVECTOR = _mm_and_ps(vResult, vLengthSq);
10277        vResult = _mm_or_ps(vTemp1, vTemp2);
10278        return vResult;
10279    }
10280}
10281
10282/// Clamps the length of a 3D vector to a given range.
10283///
10284/// ## Parameters
10285///
10286/// `V` 3D vector to clamp.
10287///
10288/// `LengthMin` 3D vector whose `x`, `y`, and `z`-components are equal to the minimum clamp length. The `x`, `y`, and
10289/// `z`-components must be greater-than-or-equal to zero.
10290///
10291/// `LengthMax` 3D vector whose `x`, `y`, and `z`-components are equal to the minimum clamp length. The `x`, `y`, and
10292/// `z`-components must be greater-than-or-equal to zero.
10293///
10294/// ## Return value
10295///
10296/// Returns a 3D vector whose length is clamped to the specified minimum and maximum.
10297///
10298/// ## Remarks
10299///
10300/// This function is identical to XMVector3ClampLength except that LengthMin and LengthMax are supplied
10301/// using 3D vectors instead of float values.
10302///
10303/// ## Reference
10304///
10305/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVector3ClampLength>
10306#[inline]
10307pub fn XMVector3ClampLength(
10308    V: FXMVECTOR,
10309    LengthMin: f32,
10310    LengthMax: f32,
10311) -> FXMVECTOR
10312{
10313    let ClampMax: XMVECTOR = XMVectorReplicate(LengthMax);
10314    let ClampMin: XMVECTOR = XMVectorReplicate(LengthMin);
10315
10316    return XMVector3ClampLengthV(V, ClampMin, ClampMax);
10317}
10318
10319/// Clamps the length of a 3D vector to a given range.
10320///
10321/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVector3ClampLengthV>
10322#[inline]
10323pub fn XMVector3ClampLengthV(
10324    V: FXMVECTOR,
10325    LengthMin: FXMVECTOR,
10326    LengthMax: FXMVECTOR,
10327) -> FXMVECTOR
10328{
10329    let LengthSq: XMVECTOR = XMVector3LengthSq(V);
10330
10331    // const Zero: XMVECTOR = XMVectorZero();
10332
10333    let RcpLength: XMVECTOR = XMVectorReciprocalSqrt(LengthSq);
10334
10335    let InfiniteLength: XMVECTOR = XMVectorEqualInt(LengthSq, unsafe { g_XMInfinity.v });
10336    let ZeroLength: XMVECTOR = XMVectorEqual(LengthSq, unsafe { g_XMZero.v });
10337
10338    let mut Normal: XMVECTOR = XMVectorMultiply(V, RcpLength);
10339
10340    let mut Length: XMVECTOR = XMVectorMultiply(LengthSq, RcpLength);
10341
10342    let Select: XMVECTOR = XMVectorEqualInt(InfiniteLength, ZeroLength);
10343    Length = XMVectorSelect(LengthSq, Length, Select);
10344    Normal = XMVectorSelect(LengthSq, Normal, Select);
10345
10346    let ControlMax: XMVECTOR = XMVectorGreater(Length, LengthMax);
10347    let ControlMin: XMVECTOR = XMVectorLess(Length, LengthMin);
10348
10349    let mut ClampLength: XMVECTOR = XMVectorSelect(Length, LengthMax, ControlMax);
10350    ClampLength = XMVectorSelect(ClampLength, LengthMin, ControlMin);
10351
10352    let mut Result: XMVECTOR = XMVectorMultiply(Normal, ClampLength);
10353
10354    // Preserve the original vector (with no precision loss) if the length falls within the given range
10355    let Control: XMVECTOR = XMVectorEqualInt(ControlMax, ControlMin);
10356    Result = XMVectorSelect(Result, V, Control);
10357
10358    return Result;
10359}
10360
10361/// Reflects an incident 3D vector across a 3D normal vector.
10362///
10363/// ## Parameters
10364///
10365/// `Incident` 3D incident vector to reflect.
10366///
10367/// `Normal` 3D normal vector to reflect the incident vector across.
10368///
10369/// ## Return value
10370///
10371/// Returns the reflected incident angle.
10372///
10373/// ## Remarks
10374///
10375/// The following pseudocode demonstrates the operation of the function:
10376///
10377/// ```text
10378/// XMVECTOR Result;
10379///
10380/// float s = 2.0f * ( Incident.x * Normal.x + Incident.y * Normal.y + Incident.z * Normal.z );
10381///
10382/// Result.x = Incident.x - s * Normal.x;
10383/// Result.y = Incident.y - s * Normal.y;
10384/// Result.z = Incident.z - s * Normal.z;
10385/// Result.w = undefined;
10386///
10387/// return Result;
10388/// ```
10389/// ## Reference
10390///
10391/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVector3Reflect>
10392#[inline]
10393pub fn XMVector3Reflect(
10394    Incident: FXMVECTOR,
10395    Normal: FXMVECTOR
10396) -> FXMVECTOR
10397{
10398    // Result = Incident - (2 * dot(Incident, Normal)) * Normal
10399
10400    let mut Result: XMVECTOR = XMVector3Dot(Incident, Normal);
10401    Result = XMVectorAdd(Result, Result);
10402    Result = XMVectorNegativeMultiplySubtract(Result, Normal, Incident);
10403
10404    return Result;
10405}
10406
10407/// Refracts an incident 3D vector across a 3D normal vector.
10408///
10409/// ## Parameters
10410///
10411/// `Incident` 3D incident vector to refract.
10412///
10413/// `Normal` 3D normal vector to refract the incident vector through.
10414///
10415/// `RefractionIndex` Index of refraction. See remarks.
10416///
10417/// ## Return value
10418///
10419/// Returns the refracted incident vector. If the refraction index and the angle between the incident vector
10420/// and the normal are such that the result is a total internal reflection, the function will return a vector
10421/// of the form < `0.0`, `0.0`, `0.0`, undefined >.
10422///
10423/// ## Remarks
10424///
10425/// The following pseudocode demonstrates the operation of the function:
10426///
10427/// ```text
10428/// XMVECTOR Result;
10429///
10430/// float t = ( Incident.x * Normal.x + Incident.y * Normal.y + Incident.z * Normal.z );
10431/// float r = 1.0f - RefractionIndex * RefractionIndex * (1.0f - t * t);
10432///
10433/// if (r < 0.0f) // Total internal reflection
10434/// {
10435///     Result.x = 0.0f;
10436///     Result.y = 0.0f;
10437///     Result.z = 0.0f;
10438/// }
10439/// else
10440/// {
10441///     float s = RefractionIndex * t + sqrt(r);
10442///     Result.x = RefractionIndex * Incident.x - s * Normal.x;
10443///     Result.y = RefractionIndex * Incident.y - s * Normal.y;
10444///     Result.z = RefractionIndex * Incident.z - s * Normal.z;
10445/// }
10446///
10447/// Result.w = undefined;
10448///
10449/// return Result;
10450/// ```
10451///
10452/// The index of refraction is the ratio of the index of refraction of the medium containing the incident
10453/// vector to the index of refraction of the medium being entered (where the index of refraction of a medium
10454/// is itself the ratio of the speed of light in a vacuum to the speed of light in the medium).
10455///
10456/// ## Reference
10457///
10458/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVector3Refract>
10459#[inline]
10460pub fn XMVector3Refract(
10461    Incident: FXMVECTOR,
10462    Normal: FXMVECTOR,
10463    RefractionIndex: f32,
10464) -> FXMVECTOR
10465{
10466    let Index: XMVECTOR = XMVectorReplicate(RefractionIndex);
10467    return XMVector3RefractV(Incident, Normal, Index);
10468}
10469
10470/// Refracts an incident 3D vector across a 3D normal vector.
10471///
10472/// ## Parameters
10473///
10474/// `Incident` 3D incident vector to refract.
10475///
10476/// `Normal` 3D normal vector to refract the incident vector through.
10477///
10478/// `RefractionIndex` 3D vector whose `x`, `y`, and `z-component`s are equal to the index of refraction.
10479///
10480/// ## Return value
10481///
10482/// Returns the refracted incident vector. If the refraction index and the angle between the incident vector
10483/// and the normal are such that the result is a total internal reflection, the function will return a vector
10484/// of the form < `0.0`, `0.0`, `0.0`, undefined >.
10485///
10486/// ## Remarks
10487///
10488/// This function is identical to XMVector3Refract except that the RefractionIndex is supplied using a 3D
10489/// vector instead of a float value.
10490///
10491/// ## Reference
10492///
10493/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVector3RefractV>
10494#[inline]
10495pub fn XMVector3RefractV(
10496    Incident: FXMVECTOR,
10497    Normal: FXMVECTOR,
10498    RefractionIndex: FXMVECTOR,
10499) -> FXMVECTOR
10500{
10501    // Result = RefractionIndex * Incident - Normal * (RefractionIndex * dot(Incident, Normal) +
10502    // sqrt(1 - RefractionIndex * RefractionIndex * (1 - dot(Incident, Normal) * dot(Incident, Normal))))
10503
10504    #[cfg(_XM_NO_INTRINSICS_)]
10505    unsafe {
10506        const Zero: XMVECTOR = unsafe { g_XMZero.v };
10507
10508        let IDotN: XMVECTOR = XMVector3Dot(Incident, Normal);
10509
10510        // R = 1.0f - RefractionIndex * RefractionIndex * (1.0f - IDotN * IDotN)
10511        let mut R: XMVECTOR = XMVectorNegativeMultiplySubtract(IDotN, IDotN, g_XMOne.v);
10512        R = XMVectorMultiply(R, RefractionIndex);
10513        R = XMVectorNegativeMultiplySubtract(R, RefractionIndex, g_XMOne.v);
10514
10515        if (XMVector4LessOrEqual(R, Zero))
10516        {
10517            // Total internal reflection
10518            return Zero;
10519        }
10520        else
10521        {
10522            // R = RefractionIndex * IDotN + sqrt(R)
10523            R = XMVectorSqrt(R);
10524            R = XMVectorMultiplyAdd(RefractionIndex, IDotN, R);
10525
10526            // Result = RefractionIndex * Incident - Normal * R
10527            let mut Result: XMVECTOR = XMVectorMultiply(RefractionIndex, Incident);
10528            Result = XMVectorNegativeMultiplySubtract(Normal, R, Result);
10529
10530            return Result;
10531        }
10532    }
10533
10534    #[cfg(_XM_ARM_NEON_INTRINSICS_)]
10535    {
10536        unimplemented!()
10537    }
10538
10539    #[cfg(_XM_SSE_INTRINSICS_)]
10540    unsafe {
10541        // Result = RefractionIndex * Incident - Normal * (RefractionIndex * dot(Incident, Normal) +
10542        // sqrt(1 - RefractionIndex * RefractionIndex * (1 - dot(Incident, Normal) * dot(Incident, Normal))))
10543        let IDotN: XMVECTOR = XMVector3Dot(Incident, Normal);
10544        // R = 1.0f - RefractionIndex * RefractionIndex * (1.0f - IDotN * IDotN)
10545        let mut R: XMVECTOR = XM_FNMADD_PS!(IDotN, IDotN, g_XMOne.v);
10546        let R2: XMVECTOR = _mm_mul_ps(RefractionIndex, RefractionIndex);
10547        R = XM_FNMADD_PS!(R, R2, g_XMOne.v);
10548
10549        let mut vResult: XMVECTOR = _mm_cmple_ps(R, g_XMZero.v);
10550        if (_mm_movemask_ps(vResult) == 0x0f)
10551        {
10552            // Total internal reflection
10553            vResult = g_XMZero.v;
10554        }
10555        else
10556        {
10557            // R = RefractionIndex * IDotN + sqrt(R)
10558            R = _mm_sqrt_ps(R);
10559            R = XM_FMADD_PS!(RefractionIndex, IDotN, R);
10560            // Result = RefractionIndex * Incident - Normal * R
10561            vResult = _mm_mul_ps(RefractionIndex, Incident);
10562            vResult = XM_FNMADD_PS!(R, Normal, vResult);
10563        }
10564        return vResult;
10565    }
10566}
10567
10568/// Computes a vector perpendicular to a 3D vector.
10569///
10570/// ## Parameters
10571///
10572/// `V` 3D vector.
10573///
10574/// ## Return value
10575///
10576/// Returns a 3D vector orthogonal to `V`.
10577///
10578/// ## Reference
10579///
10580/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVector3Orthogonal>
10581#[inline]
10582pub fn XMVector3Orthogonal(
10583    V: FXMVECTOR,
10584) -> FXMVECTOR
10585{
10586    let Zero: XMVECTOR = XMVectorZero();
10587    let Z: XMVECTOR = XMVectorSplatZ(V);
10588    // NOTE: (PERFORMANCE) The fast-path XMVectorSwizzle template functions are not yet implemented.
10589    // let YZYY: XMVECTOR = XMVectorSwizzle(V, XM_SWIZZLE_Y, XM_SWIZZLE_Z, XM_SWIZZLE_Y, XM_SWIZZLE_Y);
10590
10591    // TODO: Delete note above after benchmarking
10592    let YZYY: XMVECTOR = <(XM_SWIZZLE_Y, XM_SWIZZLE_Z, XM_SWIZZLE_Y, XM_SWIZZLE_Y)>::XMVectorSwizzle(V);
10593
10594    let NegativeV: XMVECTOR = XMVectorSubtract(Zero, V);
10595
10596    let ZIsNegative: XMVECTOR = XMVectorLess(Z, Zero);
10597    let YZYYIsNegative: XMVECTOR = XMVectorLess(YZYY, Zero);
10598
10599    let S: XMVECTOR = XMVectorAdd(YZYY, Z);
10600    let D: XMVECTOR = XMVectorSubtract(YZYY, Z);
10601
10602    let Select: XMVECTOR = XMVectorEqualInt(ZIsNegative, YZYYIsNegative);
10603
10604    // NOTE: (PERFORMANCE) The fast-path XMVectorPermute template functions are not yet implemented.
10605    // let R0: XMVECTOR = XMVectorPermute(NegativeV, S, XM_PERMUTE_1X, XM_PERMUTE_0X, XM_PERMUTE_0X, XM_PERMUTE_0X);
10606    // let R1: XMVECTOR = XMVectorPermute(V, D, XM_PERMUTE_1X, XM_PERMUTE_0X, XM_PERMUTE_0X, XM_PERMUTE_0X);
10607
10608    // TODO: Delete note above after benchmarking
10609    let R0: XMVECTOR = <(XM_PERMUTE_1X, XM_PERMUTE_0X, XM_PERMUTE_0X, XM_PERMUTE_0X)>::XMVectorPermute(NegativeV, S);
10610    let R1: XMVECTOR = <(XM_PERMUTE_1X, XM_PERMUTE_0X, XM_PERMUTE_0X, XM_PERMUTE_0X)>::XMVectorPermute(V, D);
10611
10612    return XMVectorSelect(R1, R0, Select);
10613}
10614
10615/// Estimates the radian angle between two normalized 3D vectors.
10616///
10617/// ## Parameters
10618///
10619/// `N1` Normalized 3D vector.
10620///
10621/// `N2` Normalized 3D vector.
10622///
10623/// ## Return value
10624///
10625/// Returns a vector. The estimate of the radian angle (between `N1` and `N2`) is replicated to each of the
10626/// components.
10627///
10628/// ## Remarks
10629///
10630/// `Est` functions offer increased performance at the expense of reduced accuracy. `Est` functions are appropriate
10631/// for non-critical calculations where accuracy can be sacrificed for speed. The exact amount of lost accuracy
10632/// and speed increase are platform dependent.
10633///
10634/// ## Reference
10635///
10636/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVector3AngleBetweenNormalsEst>
10637#[inline]
10638pub fn XMVector3AngleBetweenNormalsEst(
10639    N1: FXMVECTOR,
10640    N2: FXMVECTOR,
10641) -> FXMVECTOR
10642{
10643    unsafe {
10644        let mut Result: XMVECTOR = XMVector3Dot(N1, N2);
10645        Result = XMVectorClamp(Result, g_XMNegativeOne.v, g_XMOne.v);
10646        Result = XMVectorACosEst(Result);
10647        return Result;
10648    }
10649}
10650
10651/// Computes the radian angle between two normalized 3D vectors.
10652///
10653/// ## Parameters
10654///
10655/// `N1` Normalized 3D vector.
10656///
10657/// `N2` Normalized 3D vector.
10658///
10659/// ## Return value
10660///
10661/// Returns a vector. The radian angle between `N1` and `N2` is replicated to each of the components.
10662///
10663/// ## Reference
10664///
10665/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVector3AngleBetweenNormals>
10666#[inline]
10667pub fn XMVector3AngleBetweenNormals(
10668    N1: FXMVECTOR,
10669    N2: FXMVECTOR,
10670) -> FXMVECTOR
10671{
10672    unsafe {
10673        let mut Result: XMVECTOR = XMVector3Dot(N1, N2);
10674        Result = XMVectorClamp(Result, g_XMNegativeOne.v, g_XMOne.v);
10675        Result = XMVectorACos(Result);
10676        return Result;
10677    }
10678}
10679
10680/// Computes the radian angle between two 3D vectors.
10681///
10682/// ## Parameters
10683///
10684/// `V1` 3D vector.
10685///
10686/// `V2` 3D vector.
10687///
10688/// ## Return value
10689///
10690/// Returns a vector. The radian angle between `V1` and `V2` is replicated to each of the components.
10691///
10692/// ## Remarks
10693///
10694/// If `V1` and `V2` are normalized 3D vectors, it is faster to use XMVector3AngleBetweenNormals.
10695///
10696/// ## Reference
10697///
10698/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVector3AngleBetweenVectors>
10699#[inline]
10700pub fn XMVector3AngleBetweenVectors(
10701    V1: FXMVECTOR,
10702    V2: FXMVECTOR,
10703) -> FXMVECTOR
10704{
10705    unsafe {
10706        let mut L1: XMVECTOR = XMVector3ReciprocalLength(V1);
10707        let L2: XMVECTOR = XMVector3ReciprocalLength(V2);
10708
10709        let Dot: XMVECTOR = XMVector3Dot(V1, V2);
10710
10711        L1 = XMVectorMultiply(L1, L2);
10712
10713        let mut CosAngle: XMVECTOR = XMVectorMultiply(Dot, L1);
10714        CosAngle = XMVectorClamp(CosAngle, g_XMNegativeOne.v, g_XMOne.v);
10715
10716        return XMVectorACos(CosAngle);
10717    }
10718}
10719
10720/// Computes the minimum distance between a line and a point.
10721///
10722/// ## Parameters
10723///
10724/// `LinePoint1` 3D vector describing a point on the line.
10725///
10726/// `LinePoint2` 3D vector describing a point on the line.
10727///
10728/// `Point` 3D vector describing the reference point.
10729///
10730/// ## Return value
10731///
10732/// Returns a vector. The minimum distance between the line and the point is replicated to each of the components.
10733///
10734/// ## Reference
10735///
10736/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVector3LinePointDistance>
10737#[inline]
10738pub fn XMVector3LinePointDistance(
10739    LinePoint1: FXMVECTOR,
10740    LinePoint2: FXMVECTOR,
10741    Point: FXMVECTOR
10742) -> FXMVECTOR
10743{
10744    // Given a vector PointVector from LinePoint1 to Point and a vector
10745    // LineVector from LinePoint1 to LinePoint2, the scaled distance
10746    // PointProjectionScale from LinePoint1 to the perpendicular projection
10747    // of PointVector onto the line is defined as:
10748    //
10749    //     PointProjectionScale = dot(PointVector, LineVector) / LengthSq(LineVector)
10750
10751    let PointVector: XMVECTOR = XMVectorSubtract(Point, LinePoint1);
10752    let LineVector: XMVECTOR = XMVectorSubtract(LinePoint2, LinePoint1);
10753
10754    let LengthSq: XMVECTOR = XMVector3LengthSq(LineVector);
10755
10756    let mut PointProjectionScale: XMVECTOR = XMVector3Dot(PointVector, LineVector);
10757    PointProjectionScale = XMVectorDivide(PointProjectionScale, LengthSq);
10758
10759    let mut DistanceVector: XMVECTOR = XMVectorMultiply(LineVector, PointProjectionScale);
10760    DistanceVector = XMVectorSubtract(PointVector, DistanceVector);
10761
10762    return XMVector3Length(DistanceVector);
10763}
10764
10765/// Using a reference normal vector, splits a 3D vector into components that are parallel and perpendicular to the normal.
10766///
10767/// ## Parameters
10768///
10769/// `pParallel` Address of the component of `V` that is parallel to Normal.
10770///
10771/// `pPerpendicular` Address of the component of `V` that is perpendicular to Normal.
10772///
10773/// `V` 3D vector to break into components.
10774///
10775/// `Normal` 3D reference normal vector.
10776///
10777/// ## Return value
10778///
10779/// None.
10780///
10781/// ## Reference
10782///
10783/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVector3ComponentsFromNormal>
10784#[inline]
10785pub fn XMVector3ComponentsFromNormal(
10786    pParallel: &mut XMVECTOR,
10787    pPerpendicular: &mut XMVECTOR,
10788    V: FXMVECTOR,
10789    Normal: FXMVECTOR
10790)
10791{
10792    let Scale: XMVECTOR = XMVector3Dot(V, Normal);
10793
10794    let Parallel: XMVECTOR = XMVectorMultiply(Normal, Scale);
10795
10796    *pParallel = Parallel;
10797    *pPerpendicular = XMVectorSubtract(V, Parallel);
10798}
10799
10800
10801/// Rotates a 3D vector using a quaternion.
10802///
10803/// ## Parameters
10804///
10805/// `V` 3D vector to rotate.
10806///
10807/// `RotationQuaternion` Quaternion that describes the rotation to apply to the vector.
10808///
10809/// ## Return value
10810///
10811/// Returns the rotated 3D vector.
10812///
10813/// ## Reference
10814///
10815/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVector3Rotate>
10816#[inline]
10817pub fn XMVector3Rotate(
10818    V: FXMVECTOR,
10819    RotationQuaternion: FXMVECTOR,
10820) -> XMVECTOR
10821{
10822    unsafe {
10823        let A: XMVECTOR = XMVectorSelect(g_XMSelect1110.v, V, g_XMSelect1110.v);
10824        let Q: XMVECTOR = XMQuaternionConjugate(RotationQuaternion);
10825        let Result: XMVECTOR = XMQuaternionMultiply(Q, A);
10826        return XMQuaternionMultiply(Result, RotationQuaternion);
10827    }
10828}
10829
10830
10831/// Rotates a 3D vector using the inverse of a quaternion.
10832///
10833/// ## Parameters
10834///
10835/// `V` 3D vector to rotate.
10836///
10837/// `RotationQuaternion` Quaternion that describes the inverse of the rotation to apply to the vector.
10838///
10839/// ## Return value
10840///
10841/// Returns the rotated 3D vector.
10842///
10843/// ## Reference
10844///
10845/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVector3InverseRotate>
10846#[inline]
10847pub fn XMVector3InverseRotate(
10848    V: FXMVECTOR,
10849    RotationQuaternion: FXMVECTOR,
10850) -> XMVECTOR
10851{
10852    unsafe {
10853        let A: XMVECTOR = XMVectorSelect(g_XMSelect1110.v, V, g_XMSelect1110.v);
10854        let Result: XMVECTOR = XMQuaternionMultiply(RotationQuaternion, A);
10855        let Q: XMVECTOR = XMQuaternionConjugate(RotationQuaternion);
10856        return XMQuaternionMultiply(Result, Q);
10857    }
10858}
10859
10860/// Transforms a 3D vector by a matrix.
10861///
10862/// ## Parameters
10863///
10864/// `V` 3D vector.
10865///
10866/// `M` Transformation matrix.
10867///
10868/// ## Return value
10869///
10870/// Returns the transformed vector.
10871///
10872/// ## Remarks
10873///
10874/// [`XMVector3Transform`] ignores the `w` component of the input vector, and uses
10875/// a value of `1` instead. The `w` component of the returned vector may be
10876/// non-homogeneous (`!= 1.0`).
10877///
10878/// ## Reference
10879///
10880/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVector3Transform>
10881///
10882/// [`XMVector3Transform`]: XMVector3Transform
10883#[inline]
10884pub fn XMVector3Transform(
10885    V: FXMVECTOR,
10886    M: FXMMATRIX,
10887) -> FXMVECTOR
10888{
10889    #[cfg(_XM_NO_INTRINSICS_)]
10890    unsafe {
10891        let Z: XMVECTOR = XMVectorSplatZ(V);
10892        let Y: XMVECTOR = XMVectorSplatY(V);
10893        let X: XMVECTOR = XMVectorSplatX(V);
10894
10895        let mut Result: XMVECTOR = XMVectorMultiplyAdd(Z, M.r[2], M.r[3]);
10896        Result = XMVectorMultiplyAdd(Y, M.r[1], Result);
10897        Result = XMVectorMultiplyAdd(X, M.r[0], Result);
10898
10899        return Result;
10900    }
10901
10902    #[cfg(_XM_ARM_NEON_INTRINSICS_)]
10903    {
10904        unimplemented!()
10905    }
10906
10907    #[cfg(_XM_SSE_INTRINSICS_)]
10908    unsafe {
10909        let mut vResult: XMVECTOR = XM_PERMUTE_PS!(V, _MM_SHUFFLE(2, 2, 2, 2)); // Z
10910        vResult = XM_FMADD_PS!(vResult, M.r[2], M.r[3]);
10911        let mut vTemp: XMVECTOR = XM_PERMUTE_PS!(V, _MM_SHUFFLE(1, 1, 1, 1)); // Y
10912        vResult = XM_FMADD_PS!(vTemp, M.r[1], vResult);
10913        vTemp = XM_PERMUTE_PS!(V, _MM_SHUFFLE(0, 0, 0, 0)); // X
10914        vResult = XM_FMADD_PS!(vTemp, M.r[0], vResult);
10915        return vResult;
10916    }
10917}
10918
10919/// Transforms a 3D vector by a given matrix, projecting the result back into `w = 1`.
10920///
10921/// ## Parameters
10922///
10923/// `V` 3D vector.
10924///
10925/// `M` Transformation matrix.
10926///
10927/// ## Return value
10928///
10929/// Returns the transformed vector.
10930///
10931/// ## Remarks
10932///
10933/// [`XMVector3TransformCoord`] ignores the `w` component of the input vector,
10934/// and uses a value of `1.0` instead. The `w` component of the returned vector
10935/// will always be `1.0`.
10936///
10937/// ## Reference
10938///
10939/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVector3TransformCoord>
10940///
10941/// [`XMVector3TransformCoord`]: XMVector3TransformCoord
10942#[inline]
10943pub fn XMVector3TransformCoord(
10944    V: FXMVECTOR,
10945    M: FXMMATRIX,
10946) -> FXMVECTOR
10947{
10948    unsafe {
10949        let Z: XMVECTOR = XMVectorSplatZ(V);
10950        let Y: XMVECTOR = XMVectorSplatY(V);
10951        let X: XMVECTOR = XMVectorSplatX(V);
10952
10953        let mut Result: XMVECTOR = XMVectorMultiplyAdd(Z, M.r[2], M.r[3]);
10954        Result = XMVectorMultiplyAdd(Y, M.r[1], Result);
10955        Result = XMVectorMultiplyAdd(X, M.r[0], Result);
10956
10957        let W: XMVECTOR = XMVectorSplatW(Result);
10958        return XMVectorDivide(Result, W);
10959    }
10960}
10961
10962// TODO: XMVector3TransformCoordStream
10963
10964
10965/// Transforms the 3D vector normal by the given matrix.
10966///
10967/// ## Parameters
10968///
10969/// `V` 3D normal vector.
10970///
10971/// `M` Transformation matrix.
10972///
10973/// ## Return value
10974///
10975/// Returns the transformed vector.
10976///
10977/// ## Remarks
10978///
10979/// [`XMVector3TransformNormal`] performs transformations using the input matrix rows `0`, `1`,
10980/// and `2` for rotation and scaling, and ignores row `3`.
10981///
10982/// ## Reference
10983///
10984/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVector3TransformNormal>
10985///
10986/// [`XMVector3TransformNormal`]: XMVector3TransformNormal
10987#[inline]
10988pub fn XMVector3TransformNormal(
10989    V: FXMVECTOR,
10990    M: FXMMATRIX,
10991) -> FXMVECTOR
10992{
10993    #[cfg(_XM_NO_INTRINSICS_)]
10994    unsafe {
10995        let Z: XMVECTOR = XMVectorSplatZ(V);
10996        let Y: XMVECTOR = XMVectorSplatY(V);
10997        let X: XMVECTOR = XMVectorSplatX(V);
10998
10999        let mut Result: XMVECTOR = XMVectorMultiply(Z, M.r[2]);
11000        Result = XMVectorMultiplyAdd(Y, M.r[1], Result);
11001        Result = XMVectorMultiplyAdd(X, M.r[0], Result);
11002
11003        return Result;
11004    }
11005
11006    #[cfg(_XM_ARM_NEON_INTRINSICS_)]
11007    {
11008        unimplemented!()
11009    }
11010
11011    #[cfg(_XM_SSE_INTRINSICS_)]
11012    unsafe {
11013        let mut vResult: XMVECTOR = XM_PERMUTE_PS!(V, _MM_SHUFFLE(2, 2, 2, 2)); // Z
11014        vResult = _mm_mul_ps(vResult, M.r[2]);
11015        let mut vTemp: XMVECTOR = XM_PERMUTE_PS!(V, _MM_SHUFFLE(1, 1, 1, 1)); // Y
11016        vResult = XM_FMADD_PS!(vTemp, M.r[1], vResult);
11017        vTemp = XM_PERMUTE_PS!(V, _MM_SHUFFLE(0, 0, 0, 0)); // X
11018        vResult = XM_FMADD_PS!(vTemp, M.r[0], vResult);
11019        return vResult;
11020    }
11021}
11022
11023// TODO: XMVector3TransformNormalStream
11024
11025
11026/// Project a 3D vector from object space into screen space.
11027///
11028/// ## Parameters
11029///
11030/// `V` 3D vector in object space that will be projected into screen space.
11031///
11032/// `ViewportX` Pixel coordinate of the upper-left corner of the viewport. Unless you want to render to a subset of
11033/// the surface, this parameter can be set to 0.
11034///
11035/// `ViewportY` Pixel coordinate of the upper-left corner of the viewport on the render-target surface. Unless you want
11036/// to render to a subset of the surface, this parameter can be set to `0`.
11037///
11038/// `ViewportWidth` Width dimension of the clip volume, in pixels. Unless you are rendering only to a subset of the surface,
11039/// this parameter should be set to the width dimension of the render-target surface.
11040///
11041/// `ViewportHeight` Height dimension of the clip volume, in pixels. Unless you are rendering only to a subset of the surface,
11042/// this parameter should be set to the height dimension of the render-target surface.
11043///
11044/// `ViewportMinZ` Together with `ViewportMaxZ`, value describing the range of depth values into which a scene is to be
11045/// rendered, the minimum and maximum values of the clip volume. Most applications set this value to `0.0`.
11046/// Clipping is performed after applying the projection matrix.
11047///
11048/// `ViewportMaxZ` Together with `MinZ`, value describing the range of depth values into which a scene is to be rendered,
11049/// the minimum and maximum values of the clip volume. Most applications set this value to `1.0`. Clipping
11050/// is performed after applying the projection matrix.
11051///
11052/// `Projection` Projection matrix.
11053///
11054/// `View` View matrix.
11055///
11056/// `World` World matrix.
11057///
11058/// ## Return value
11059///
11060/// Returns a vector in screen space.
11061///
11062/// ## Remarks
11063///
11064/// The `ViewportX`, `ViewportY`, `ViewportWidth`, and `ViewportHeight` parameters describe the position and dimensions
11065/// of the viewport on the render-target surface. `Usually`, applications render to the entire target surface;
11066/// when rendering on a `640*480` surface, these parameters should be `0`, `0`, `640`, and `480`, respectively. The
11067/// `ViewportMinZ` and `ViewportMaxZ` are typically set to `0.0` and `1.0` but can be set to other values to achieve
11068/// specific effects.
11069///
11070/// ## Reference
11071///
11072/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVector3Project>
11073#[inline]
11074pub fn XMVector3Project(
11075    V: FXMVECTOR,
11076    ViewportX: f32,
11077    ViewportY: f32,
11078    ViewportWidth: f32,
11079    ViewportHeight: f32,
11080    ViewportMinZ: f32,
11081    ViewportMaxZ: f32,
11082    Projection: FXMMATRIX,
11083    View: CXMMATRIX,
11084    World: CXMMATRIX,
11085) -> FXMVECTOR
11086{
11087    let HalfViewportWidth: f32 = ViewportWidth * 0.5;
11088    let HalfViewportHeight: f32 = ViewportHeight * 0.5;
11089
11090    let Scale: XMVECTOR = XMVectorSet(HalfViewportWidth, -HalfViewportHeight, ViewportMaxZ - ViewportMinZ, 0.0);
11091    let Offset: XMVECTOR = XMVectorSet(ViewportX + HalfViewportWidth, ViewportY + HalfViewportHeight, ViewportMinZ, 0.0);
11092
11093    let mut Transform: XMMATRIX = XMMatrixMultiply(*World, View);
11094    Transform = XMMatrixMultiply(Transform, &Projection);
11095
11096    let mut Result: XMVECTOR = XMVector3TransformCoord(V, Transform);
11097
11098    Result = XMVectorMultiplyAdd(Result, Scale, Offset);
11099
11100    return Result;
11101}
11102
11103// TODO: XMVector3ProjectStream
11104
11105/// Projects a 3D vector from screen space into object space.
11106///
11107/// ## Parameters
11108///
11109/// `V` 3D vector in screen space that will be projected into object space. `X` and `Y` are in pixels, while
11110/// `Z` is `0.0` (at ViewportMinZ) to `1.0` (at `ViewportMaxZ`).
11111///
11112/// `ViewportX` Pixel coordinate of the upper-left corner of the viewport. Unless you want to render to a subset of
11113/// the surface, this parameter can be set to `0`.
11114///
11115/// `ViewportY` Pixel coordinate of the upper-left corner of the viewport on the render-target surface. Unless you want
11116/// to render to a subset of the surface, this parameter can be set to `0`.
11117///
11118/// `ViewportWidth` Width dimension of the clip volume, in pixels. Unless you are rendering only to a subset of the surface,
11119/// this parameter should be set to the width dimension of the render-target surface.
11120///
11121/// `ViewportHeight` Height dimension of the clip volume, in pixels. Unless you are rendering only to a subset of the surface,
11122/// this parameter should be set to the height dimension of the render-target surface.
11123///
11124/// `ViewportMinZ` Together with `ViewportMaxZ`, value describing the range of depth values into which a scene is to be
11125/// rendered, the minimum and maximum values of the clip volume. Most applications set this value to `0.0`.
11126/// Clipping is performed after applying the projection matrix.
11127///
11128/// `ViewportMaxZ` Together with `MinZ`, value describing the range of depth values into which a scene is to be rendered,
11129/// the minimum and maximum values of the clip volume. Most applications set this value to `1.0`. Clipping
11130/// is performed after applying the projection matrix.
11131///
11132/// `Projection` Projection matrix.
11133///
11134/// `View` View matrix.
11135///
11136/// `World` World matrix.
11137///
11138/// ## Return value
11139///
11140/// Returns a vector in object space.
11141///
11142/// ## Remarks
11143///
11144/// The `ViewportX`, `ViewportY`, `ViewportWidth`, and `ViewportHeight` parameters describe the position and dimensions
11145/// of the viewport on the render-target surface. Usually`, applications render to the entire target surface;
11146/// when rendering on a `640*480` surface, these parameters should be `0`, `0`, `640`, and `480`, respectively. The
11147/// `ViewportMinZ` and `ViewportMaxZ` are typically set to `0.0` and `1.0` but can be set to other values to achieve
11148/// specific effects.
11149///
11150/// ## Reference
11151///
11152/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVector3Unproject>
11153#[inline]
11154pub fn XMVector3Unproject(
11155    V: FXMVECTOR,
11156    ViewportX: f32,
11157    ViewportY: f32,
11158    ViewportWidth: f32,
11159    ViewportHeight: f32,
11160    ViewportMinZ: f32,
11161    ViewportMaxZ: f32,
11162    Projection: FXMMATRIX,
11163    View: CXMMATRIX,
11164    World: CXMMATRIX,
11165) -> FXMVECTOR
11166{
11167    const D: XMVECTORF32 = XMVECTORF32 { f: [ -1.0, 1.0, 0.0, 0.0] };
11168
11169    let mut Scale: XMVECTOR = XMVectorSet(ViewportWidth * 0.5, -ViewportHeight * 0.5, ViewportMaxZ - ViewportMinZ, 1.0);
11170    Scale = XMVectorReciprocal(Scale);
11171
11172    let mut Offset: XMVECTOR = XMVectorSet(-ViewportX, -ViewportY, -ViewportMinZ, 0.0);
11173    Offset = XMVectorMultiplyAdd(Scale, Offset, unsafe { D.v });
11174
11175    let mut Transform: XMMATRIX = XMMatrixMultiply(*World, View);
11176    Transform = XMMatrixMultiply(Transform, &Projection);
11177    let mut det = unsafe { crate::undefined() };
11178    Transform = XMMatrixInverse(Some(&mut det), Transform);
11179
11180    let Result: XMVECTOR = XMVectorMultiplyAdd(V, Scale, Offset);
11181
11182    return XMVector3TransformCoord(Result, Transform);
11183}
11184
11185// TODO: XMVector3UnprojectStream
11186
11187
11188// 4D Vector
11189
11190/// Tests whether two 4D vectors are equal.
11191///
11192/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVector4Equal>
11193#[inline]
11194pub fn XMVector4Equal(
11195    V1: FXMVECTOR,
11196    V2: FXMVECTOR,
11197) -> bool
11198{
11199    #[cfg(_XM_NO_INTRINSICS_)]
11200    unsafe {
11201        return (((V1.vector4_f32[0] == V2.vector4_f32[0]) && (V1.vector4_f32[1] == V2.vector4_f32[1]) && (V1.vector4_f32[2] == V2.vector4_f32[2]) && (V1.vector4_f32[3] == V2.vector4_f32[3])) != false);
11202    }
11203
11204    #[cfg(_XM_ARM_NEON_INTRINSICS_)]
11205    {
11206        unimplemented!()
11207    }
11208
11209    #[cfg(_XM_SSE_INTRINSICS_)]
11210    unsafe {
11211        let vTemp: XMVECTOR = _mm_cmpeq_ps(V1, V2);
11212        return ((_mm_movemask_ps(vTemp) == 0x0f) != false);
11213    }
11214
11215    // NOTE: The source contains a fallback that does not seem reachable
11216    // return XMComparisonAllTrue(XMVector4EqualR(V1, V2));
11217}
11218
11219/// Tests whether two 4D vectors are equal. In addition, this function returns a comparison value that can be examined using functions such as XMComparisonAllTrue.
11220///
11221/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVector4EqualR>
11222#[inline]
11223pub fn XMVector4EqualR(
11224    V1: FXMVECTOR,
11225    V2: FXMVECTOR,
11226) -> u32
11227{
11228    #[cfg(_XM_NO_INTRINSICS_)]
11229    unsafe {
11230        let mut CR: u32 = 0;
11231
11232        if ((V1.vector4_f32[0] == V2.vector4_f32[0]) &&
11233            (V1.vector4_f32[1] == V2.vector4_f32[1]) &&
11234            (V1.vector4_f32[2] == V2.vector4_f32[2]) &&
11235            (V1.vector4_f32[3] == V2.vector4_f32[3]))
11236        {
11237            CR = XM_CRMASK_CR6TRUE;
11238        }
11239        else if ((V1.vector4_f32[0] != V2.vector4_f32[0]) &&
11240            (V1.vector4_f32[1] != V2.vector4_f32[1]) &&
11241            (V1.vector4_f32[2] != V2.vector4_f32[2]) &&
11242            (V1.vector4_f32[3] != V2.vector4_f32[3]))
11243        {
11244            CR = XM_CRMASK_CR6FALSE;
11245        }
11246        return CR;
11247    }
11248
11249    #[cfg(_XM_ARM_NEON_INTRINSICS_)]
11250    {
11251        unimplemented!()
11252    }
11253
11254    #[cfg(_XM_SSE_INTRINSICS_)]
11255    unsafe {
11256        let vTemp: XMVECTOR = _mm_cmpeq_ps(V1, V2);
11257        let iTest: i32 = _mm_movemask_ps(vTemp);
11258        let mut CR: u32 = 0;
11259        if (iTest == 0xf)     // All equal?
11260        {
11261            CR = XM_CRMASK_CR6TRUE;
11262        }
11263        else if (iTest == 0)  // All not equal?
11264        {
11265            CR = XM_CRMASK_CR6FALSE;
11266        }
11267        return CR;
11268    }
11269}
11270
11271/// Tests whether two 4D vectors are equal, treating each component as an unsigned integer.
11272///
11273/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVector4EqualInt>
11274#[inline]
11275pub fn XMVector4EqualInt(
11276    V1: FXMVECTOR,
11277    V2: FXMVECTOR,
11278) -> bool
11279{
11280    #[cfg(_XM_NO_INTRINSICS_)]
11281    unsafe {
11282        return (((V1.vector4_u32[0] == V2.vector4_u32[0]) && (V1.vector4_u32[1] == V2.vector4_u32[1]) && (V1.vector4_u32[2] == V2.vector4_u32[2]) && (V1.vector4_u32[3] == V2.vector4_u32[3])) != false);
11283    }
11284
11285    #[cfg(_XM_ARM_NEON_INTRINSICS_)]
11286    {
11287        unimplemented!()
11288    }
11289
11290    #[cfg(_XM_SSE_INTRINSICS_)]
11291    unsafe {
11292        let vTemp: __m128i = _mm_cmpeq_epi32(_mm_castps_si128(V1), _mm_castps_si128(V2));
11293        return ((_mm_movemask_ps(_mm_castsi128_ps(vTemp)) == 0xf) != false);
11294    }
11295
11296    // NOTE: The source has a fallback that does not seem reachable
11297    // return return XMComparisonAllTrue(XMVector4EqualIntR(V1, V2));
11298}
11299
11300/// Tests whether two 4D vectors are equal, treating each component as an
11301/// unsigned integer. In addition, this function returns a comparison value
11302/// that can be examined using functions such as XMComparisonAllTrue.
11303///
11304/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVector4EqualIntR>
11305#[inline]
11306pub fn XMVector4EqualIntR(
11307    V1: FXMVECTOR,
11308    V2: FXMVECTOR,
11309) -> u32
11310{
11311    #[cfg(_XM_NO_INTRINSICS_)]
11312    unsafe {
11313        let mut CR: u32 = 0;
11314        if (V1.vector4_u32[0] == V2.vector4_u32[0] &&
11315            V1.vector4_u32[1] == V2.vector4_u32[1] &&
11316            V1.vector4_u32[2] == V2.vector4_u32[2] &&
11317            V1.vector4_u32[3] == V2.vector4_u32[3])
11318        {
11319            CR = XM_CRMASK_CR6TRUE;
11320        }
11321        else if (V1.vector4_u32[0] != V2.vector4_u32[0] &&
11322            V1.vector4_u32[1] != V2.vector4_u32[1] &&
11323            V1.vector4_u32[2] != V2.vector4_u32[2] &&
11324            V1.vector4_u32[3] != V2.vector4_u32[3])
11325        {
11326            CR = XM_CRMASK_CR6FALSE;
11327        }
11328        return CR;
11329    }
11330
11331    #[cfg(_XM_ARM_NEON_INTRINSICS_)]
11332    {
11333        unimplemented!()
11334    }
11335
11336    #[cfg(_XM_SSE_INTRINSICS_)]
11337    unsafe {
11338        let vTemp: __m128i = _mm_cmpeq_epi32(_mm_castps_si128(V1), _mm_castps_si128(V2));
11339        let iTest: i32 = _mm_movemask_ps(_mm_castsi128_ps(vTemp));
11340        let mut CR: u32 = 0;
11341        if (iTest == 0xf)     // All equal?
11342        {
11343            CR = XM_CRMASK_CR6TRUE;
11344        }
11345        else if (iTest == 0)  // All not equal?
11346        {
11347            CR = XM_CRMASK_CR6FALSE;
11348        }
11349        return CR;
11350    }
11351}
11352
11353/// Tests whether one 4D vector is near another 4D vector.
11354///
11355/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVector4NearEqual>
11356#[inline]
11357pub fn XMVector4NearEqual(
11358    V1: FXMVECTOR,
11359    V2: FXMVECTOR,
11360    Epsilon: FXMVECTOR,
11361) -> bool
11362{
11363    #[cfg(_XM_NO_INTRINSICS_)]
11364    unsafe {
11365        let dx: f32 = fabsf(V1.vector4_f32[0] - V2.vector4_f32[0]);
11366        let dy: f32 = fabsf(V1.vector4_f32[1] - V2.vector4_f32[1]);
11367        let dz: f32 = fabsf(V1.vector4_f32[2] - V2.vector4_f32[2]);
11368        let dw: f32 = fabsf(V1.vector4_f32[3] - V2.vector4_f32[3]);
11369
11370        return (((dx <= Epsilon.vector4_f32[0]) &&
11371            (dy <= Epsilon.vector4_f32[1]) &&
11372            (dz <= Epsilon.vector4_f32[2]) &&
11373            (dw <= Epsilon.vector4_f32[3])) != false);
11374    }
11375
11376    #[cfg(_XM_ARM_NEON_INTRINSICS_)]
11377    {
11378        unimplemented!()
11379    }
11380
11381    #[cfg(_XM_SSE_INTRINSICS_)]
11382    unsafe {
11383        // Get the difference
11384        let vDelta: XMVECTOR = _mm_sub_ps(V1, V2);
11385        // Get the absolute value of the difference
11386        let mut vTemp: XMVECTOR = _mm_setzero_ps();
11387        vTemp = _mm_sub_ps(vTemp, vDelta);
11388        vTemp = _mm_max_ps(vTemp, vDelta);
11389        vTemp = _mm_cmple_ps(vTemp, Epsilon);
11390        return ((_mm_movemask_ps(vTemp) == 0xf) != false);
11391    }
11392}
11393
11394/// Tests whether two 4D vectors are not equal.
11395///
11396/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVector4NotEqual>
11397#[inline]
11398pub fn XMVector4NotEqual(
11399    V1: FXMVECTOR,
11400    V2: FXMVECTOR,
11401) -> bool
11402{
11403    #[cfg(_XM_NO_INTRINSICS_)]
11404    unsafe {
11405        return (((V1.vector4_f32[0] != V2.vector4_f32[0]) || (V1.vector4_f32[1] != V2.vector4_f32[1]) || (V1.vector4_f32[2] != V2.vector4_f32[2]) || (V1.vector4_f32[3] != V2.vector4_f32[3])) != false);
11406    }
11407
11408    #[cfg(_XM_ARM_NEON_INTRINSICS_)]
11409    {
11410        unimplemented!()
11411    }
11412
11413    #[cfg(_XM_SSE_INTRINSICS_)]
11414    unsafe {
11415        let vTemp: XMVECTOR = _mm_cmpneq_ps(V1, V2);
11416        return ((_mm_movemask_ps(vTemp)) != 0);
11417    }
11418
11419    // NOTE: The source contains a fallback that does not seem reachable
11420    // return XMComparisonAnyFalse(XMVector4EqualR(V1, V2));
11421}
11422
11423/// Test whether two 4D vectors are not equal, treating each component as an unsigned integer.
11424///
11425/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVector4NotEqualInt>
11426#[inline]
11427pub fn XMVector4NotEqualInt(
11428    V1: FXMVECTOR,
11429    V2: FXMVECTOR,
11430) -> bool
11431{
11432    #[cfg(_XM_NO_INTRINSICS_)]
11433    unsafe {
11434        return (((V1.vector4_u32[0] != V2.vector4_u32[0]) || (V1.vector4_u32[1] != V2.vector4_u32[1]) || (V1.vector4_u32[2] != V2.vector4_u32[2]) || (V1.vector4_u32[3] != V2.vector4_u32[3])) != false);
11435    }
11436
11437    #[cfg(_XM_ARM_NEON_INTRINSICS_)]
11438    {
11439        unimplemented!()
11440    }
11441
11442    #[cfg(_XM_SSE_INTRINSICS_)]
11443    unsafe {
11444        let vTemp: __m128i = _mm_cmpeq_epi32(_mm_castps_si128(V1), _mm_castps_si128(V2));
11445        return ((_mm_movemask_ps(_mm_castsi128_ps(vTemp)) != 0xF) != false);
11446    }
11447
11448    // NOTE: The source contains a fallback that does not seem reachable
11449    // return XMComparisonAnyFalse(XMVector4EqualIntR(V1, V2));
11450}
11451
11452/// Tests whether one 4D vector is greater than another 4D vector.
11453///
11454/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVector4Greater>
11455#[inline]
11456pub fn XMVector4Greater(
11457    V1: FXMVECTOR,
11458    V2: FXMVECTOR,
11459) -> bool
11460{
11461    #[cfg(_XM_NO_INTRINSICS_)]
11462    unsafe {
11463        return (((V1.vector4_f32[0] > V2.vector4_f32[0]) && (V1.vector4_f32[1] > V2.vector4_f32[1]) && (V1.vector4_f32[2] > V2.vector4_f32[2]) && (V1.vector4_f32[3] > V2.vector4_f32[3])) != false);
11464    }
11465
11466    #[cfg(_XM_ARM_NEON_INTRINSICS_)]
11467    {
11468        unimplemented!()
11469    }
11470
11471    #[cfg(_XM_SSE_INTRINSICS_)]
11472    unsafe {
11473        let vTemp: XMVECTOR = _mm_cmpgt_ps(V1, V2);
11474        return ((_mm_movemask_ps(vTemp) == 0x0f) != false);
11475    }
11476
11477    // NOTE: The source contains a fallback that does not seem reachable
11478    // return XMComparisonAllTrue(XMVector4GreaterR(V1, V2));
11479}
11480
11481/// Tests whether one 4D vector is greater than another 4D vector and returns a comparison value that can be examined using functions such as XMComparisonAllTrue.
11482///
11483/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVector4GreaterR>
11484#[inline]
11485pub fn XMVector4GreaterR(
11486    V1: FXMVECTOR,
11487    V2: FXMVECTOR,
11488) -> u32
11489{
11490    #[cfg(_XM_NO_INTRINSICS_)]
11491    unsafe {
11492        let mut CR: u32 = 0;
11493        if (V1.vector4_f32[0] > V2.vector4_f32[0] &&
11494            V1.vector4_f32[1] > V2.vector4_f32[1] &&
11495            V1.vector4_f32[2] > V2.vector4_f32[2] &&
11496            V1.vector4_f32[3] > V2.vector4_f32[3])
11497        {
11498            CR = XM_CRMASK_CR6TRUE;
11499        }
11500        else if (V1.vector4_f32[0] <= V2.vector4_f32[0] &&
11501            V1.vector4_f32[1] <= V2.vector4_f32[1] &&
11502            V1.vector4_f32[2] <= V2.vector4_f32[2] &&
11503            V1.vector4_f32[3] <= V2.vector4_f32[3])
11504        {
11505            CR = XM_CRMASK_CR6FALSE;
11506        }
11507        return CR;
11508    }
11509
11510    #[cfg(_XM_ARM_NEON_INTRINSICS_)]
11511    {
11512        unimplemented!()
11513    }
11514
11515    #[cfg(_XM_SSE_INTRINSICS_)]
11516    unsafe {
11517        let mut CR: u32 = 0;
11518        let vTemp: XMVECTOR = _mm_cmpgt_ps(V1, V2);
11519        let iTest: i32 = _mm_movemask_ps(vTemp);
11520        if (iTest == 0xf)
11521        {
11522            CR = XM_CRMASK_CR6TRUE;
11523        }
11524        else if (!ibool(iTest))
11525        {
11526            CR = XM_CRMASK_CR6FALSE;
11527        }
11528        return CR;
11529    }
11530}
11531
11532/// Tests whether one 4D vector is greater-than-or-equal-to another 4D vector.
11533///
11534/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVector4GreaterOrEqual>
11535#[inline]
11536pub fn XMVector4GreaterOrEqual(
11537    V1: FXMVECTOR,
11538    V2: FXMVECTOR,
11539) -> bool
11540{
11541    #[cfg(_XM_NO_INTRINSICS_)]
11542    unsafe {
11543        return (((V1.vector4_f32[0] >= V2.vector4_f32[0]) && (V1.vector4_f32[1] >= V2.vector4_f32[1]) && (V1.vector4_f32[2] >= V2.vector4_f32[2]) && (V1.vector4_f32[3] >= V2.vector4_f32[3])) != false);
11544    }
11545
11546    #[cfg(_XM_ARM_NEON_INTRINSICS_)]
11547    {
11548        unimplemented!()
11549    }
11550
11551    #[cfg(_XM_SSE_INTRINSICS_)]
11552    unsafe {
11553        let vTemp: XMVECTOR = _mm_cmpge_ps(V1, V2);
11554        return ((_mm_movemask_ps(vTemp) == 0x0f) != false);
11555    }
11556
11557    // NOTE: The source contains a fallback that does not seem reachable
11558    // return XMComparisonAllTrue(XMVector4GreaterOrEqualR(V1, V2));
11559}
11560
11561
11562/// Tests whether one 4D vector is greater-than-or-equal-to another 4D vector and returns a comparison value that can be examined using functions such as XMComparisonAllTrue.
11563///
11564/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVector4GreaterOrEqualR>
11565#[inline]
11566pub fn XMVector4GreaterOrEqualR(
11567    V1: FXMVECTOR,
11568    V2: FXMVECTOR,
11569) -> u32
11570{
11571    #[cfg(_XM_NO_INTRINSICS_)]
11572    unsafe {
11573        let mut CR: u32 = 0;
11574        if ((V1.vector4_f32[0] >= V2.vector4_f32[0]) &&
11575            (V1.vector4_f32[1] >= V2.vector4_f32[1]) &&
11576            (V1.vector4_f32[2] >= V2.vector4_f32[2]) &&
11577            (V1.vector4_f32[3] >= V2.vector4_f32[3]))
11578        {
11579            CR = XM_CRMASK_CR6TRUE;
11580        }
11581        else if ((V1.vector4_f32[0] < V2.vector4_f32[0]) &&
11582            (V1.vector4_f32[1] < V2.vector4_f32[1]) &&
11583            (V1.vector4_f32[2] < V2.vector4_f32[2]) &&
11584            (V1.vector4_f32[3] < V2.vector4_f32[3]))
11585        {
11586            CR = XM_CRMASK_CR6FALSE;
11587        }
11588        return CR;
11589    }
11590
11591    #[cfg(_XM_ARM_NEON_INTRINSICS_)]
11592    {
11593        unimplemented!()
11594    }
11595
11596    #[cfg(_XM_SSE_INTRINSICS_)]
11597    unsafe {
11598        let mut CR: u32 = 0;
11599        let vTemp: XMVECTOR = _mm_cmpge_ps(V1, V2);
11600        let iTest: i32 = _mm_movemask_ps(vTemp);
11601        if (iTest == 0x0f)
11602        {
11603            CR = XM_CRMASK_CR6TRUE;
11604        }
11605        else if (!ibool(iTest))
11606        {
11607            CR = XM_CRMASK_CR6FALSE;
11608        }
11609        return CR;
11610    }
11611}
11612
11613/// Tests whether one 4D vector is less than another 4D vector.
11614///
11615/// ## Parameters
11616///
11617/// `V1` 4D vector.
11618///
11619/// `V2` 4D vector.
11620///
11621/// ## Return value
11622///
11623/// Returns `true` if `V1` is less than `V2` and `false` otherwise. See the remarks section.
11624///
11625/// ## Remarks
11626///
11627/// The following pseudocode demonstrates the operation of the function:
11628///
11629/// ```text
11630/// return ( V1.x < V2.x && V1.y < V2.y &&
11631///          V1.z < V2.z && V1.w < V2.w );
11632/// ```
11633///
11634/// ## Reference
11635///
11636/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVector4Less>
11637#[inline]
11638pub fn XMVector4Less(
11639    V1: FXMVECTOR,
11640    V2: FXMVECTOR,
11641) -> bool
11642{
11643    #[cfg(_XM_NO_INTRINSICS_)]
11644    unsafe {
11645        return (((V1.vector4_f32[0] < V2.vector4_f32[0]) && (V1.vector4_f32[1] < V2.vector4_f32[1]) && (V1.vector4_f32[2] < V2.vector4_f32[2]) && (V1.vector4_f32[3] < V2.vector4_f32[3])) != false);
11646    }
11647
11648    #[cfg(_XM_ARM_NEON_INTRINSICS_)]
11649    {
11650        unimplemented!()
11651    }
11652
11653    #[cfg(_XM_SSE_INTRINSICS_)]
11654    unsafe {
11655        let vTemp: XMVECTOR = _mm_cmplt_ps(V1, V2);
11656        return ((_mm_movemask_ps(vTemp) == 0x0f) != false);
11657    }
11658
11659    // NOTE: The source contains a fallback that does not seem reachable
11660    // return XMComparisonAllTrue(XMVector4GreaterR(V2, V1));
11661}
11662
11663/// Tests whether one 4D vector is less than or equal to another 4D vector.
11664///
11665/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVector4LessOrEqual>
11666#[inline]
11667pub fn XMVector4LessOrEqual(
11668    V1: FXMVECTOR,
11669    V2: FXMVECTOR,
11670) -> bool
11671{
11672    #[cfg(_XM_NO_INTRINSICS_)]
11673    unsafe {
11674        return (((V1.vector4_f32[0] <= V2.vector4_f32[0]) && (V1.vector4_f32[1] <= V2.vector4_f32[1]) && (V1.vector4_f32[2] <= V2.vector4_f32[2]) && (V1.vector4_f32[3] <= V2.vector4_f32[3])) != false);
11675    }
11676
11677    #[cfg(_XM_ARM_NEON_INTRINSICS_)]
11678    {
11679        unimplemented!()
11680    }
11681
11682    #[cfg(_XM_SSE_INTRINSICS_)]
11683    unsafe {
11684        let vTemp: XMVECTOR = _mm_cmple_ps(V1, V2);
11685        return ((_mm_movemask_ps(vTemp) == 0x0f) != false);
11686    }
11687
11688    // NOTE: The source contains a fallback that does not seem reachable
11689    // return XMComparisonAllTrue(XMVector4GreaterOrEqualR(V2, V1));
11690}
11691
11692/// Tests whether the components of a 4D vector are within set bounds.
11693///
11694/// ## Parameters
11695///
11696/// `V` 4D vector to test.
11697///
11698/// `Bounds` 4D vector that determines the bounds.
11699///
11700/// ## Return value
11701///
11702/// Returns `true` if all of the components of `V` are within the set bounds, and `false` otherwise.
11703///
11704/// ## Remarks
11705///
11706/// The following pseudocode demonstrates the operation of the function:
11707///
11708/// ```text
11709/// return (V.x <= Bounds.x && V.x >= -Bounds.x) &&
11710///        (V.y <= Bounds.y && V.y >= -Bounds.y) &&
11711///        (V.z <= Bounds.z && V.z >= -Bounds.z) &&
11712///        (V.w <= Bounds.w && V.w >= -Bounds.w);
11713/// ```
11714///
11715/// ## Reference
11716///
11717/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVector4InBounds>
11718#[inline]
11719pub fn XMVector4InBounds(
11720    V: FXMVECTOR,
11721    Bounds: FXMVECTOR,
11722) -> bool
11723{
11724    #[cfg(_XM_NO_INTRINSICS_)]
11725    unsafe {
11726        return (((V.vector4_f32[0] <= Bounds.vector4_f32[0] && V.vector4_f32[0] >= -Bounds.vector4_f32[0]) &&
11727            (V.vector4_f32[1] <= Bounds.vector4_f32[1] && V.vector4_f32[1] >= -Bounds.vector4_f32[1]) &&
11728            (V.vector4_f32[2] <= Bounds.vector4_f32[2] && V.vector4_f32[2] >= -Bounds.vector4_f32[2]) &&
11729            (V.vector4_f32[3] <= Bounds.vector4_f32[3] && V.vector4_f32[3] >= -Bounds.vector4_f32[3])) != false);
11730    }
11731
11732    #[cfg(_XM_ARM_NEON_INTRINSICS_)]
11733    {
11734        unimplemented!()
11735    }
11736
11737    #[cfg(_XM_SSE_INTRINSICS_)]
11738    unsafe {
11739        // Test if less than or equal
11740        let mut vTemp1: XMVECTOR = _mm_cmple_ps(V, Bounds);
11741        // Negate the bounds
11742        let mut vTemp2: XMVECTOR = _mm_mul_ps(Bounds, g_XMNegativeOne.v);
11743        // Test if greater or equal (Reversed)
11744        vTemp2 = _mm_cmple_ps(vTemp2, V);
11745        // Blend answers
11746        vTemp1 = _mm_and_ps(vTemp1, vTemp2);
11747        // All in bounds?
11748        return ((_mm_movemask_ps(vTemp1) == 0x0f) != false);
11749    }
11750
11751    // NOTE: The source contains a fallback that does not seem reachable
11752    // return XMComparisonAllInBounds(XMVector4InBoundsR(V, Bounds));
11753}
11754
11755/// Tests whether any component of a 4D vector is a NaN.
11756///
11757/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVector4IsNaN>
11758#[inline]
11759pub fn XMVector4IsNaN(
11760    V: FXMVECTOR,
11761) -> bool
11762{
11763    #[cfg(_XM_NO_INTRINSICS_)]
11764    unsafe {
11765        return (XMISNAN!(V.vector4_f32[0]) ||
11766            XMISNAN!(V.vector4_f32[1]) ||
11767            XMISNAN!(V.vector4_f32[2]) ||
11768            XMISNAN!(V.vector4_f32[3]));
11769    }
11770
11771    #[cfg(_XM_ARM_NEON_INTRINSICS_)]
11772    {
11773        unimplemented!()
11774    }
11775
11776    #[cfg(_XM_SSE_INTRINSICS_)]
11777    unsafe {
11778        // Test against itself. NaN is always not equal
11779        let vTempNan: XMVECTOR = _mm_cmpneq_ps(V, V);
11780        // If any are NaN, the mask is non-zero
11781        return (_mm_movemask_ps(vTempNan) != 0);
11782    }
11783
11784    // NOTE: The source contains a fallback that does not seem reachable
11785    // return XMComparisonAllInBounds(XMVector4InBoundsR(V, Bounds));
11786}
11787
11788/// Tests whether any component of a 4D vector is a NaN.
11789///
11790/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVector4IsInfinite>
11791#[inline]
11792pub fn XMVector4IsInfinite(
11793    V: FXMVECTOR,
11794) -> bool
11795{
11796    #[cfg(_XM_NO_INTRINSICS_)]
11797    unsafe {
11798        return (XMISINF!(V.vector4_f32[0]) ||
11799            XMISINF!(V.vector4_f32[1]) ||
11800            XMISINF!(V.vector4_f32[2]) ||
11801            XMISINF!(V.vector4_f32[3]));
11802    }
11803
11804    #[cfg(_XM_ARM_NEON_INTRINSICS_)]
11805    {
11806        unimplemented!()
11807    }
11808
11809    #[cfg(_XM_SSE_INTRINSICS_)]
11810    unsafe {
11811        // Mask off the sign bit
11812        let mut vTemp: XMVECTOR = _mm_and_ps(V, g_XMAbsMask.v);
11813        // Compare to infinity
11814        vTemp = _mm_cmpeq_ps(vTemp, g_XMInfinity.v);
11815        // If any are infinity, the signs are true.
11816        return (_mm_movemask_ps(vTemp) != 0);
11817    }
11818}
11819
11820
11821/// Computes the dot product between 4D vectors.
11822///
11823/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVector4Dot>
11824#[inline]
11825pub fn XMVector4Dot(
11826    V1: FXMVECTOR,
11827    V2: FXMVECTOR,
11828) -> FXMVECTOR
11829{
11830    #[cfg(_XM_NO_INTRINSICS_)]
11831    unsafe {
11832        let Value = V1.vector4_f32[0] * V2.vector4_f32[0] + V1.vector4_f32[1] * V2.vector4_f32[1] + V1.vector4_f32[2] * V2.vector4_f32[2] + V1.vector4_f32[3] * V2.vector4_f32[3];
11833        let mut vResult: XMVECTORF32 = crate::undefined();
11834        vResult.f[0] = Value;
11835        vResult.f[1] = Value;
11836        vResult.f[2] = Value;
11837        vResult.f[3] = Value;
11838        return vResult.v;
11839    }
11840
11841    #[cfg(_XM_ARM_NEON_INTRINSICS_)]
11842    {
11843        unimplemented!()
11844    }
11845
11846    #[cfg(_XM_SSE4_INTRINSICS_)]
11847    unsafe {
11848        return _mm_dp_ps(V1, V2, 0xff);
11849    }
11850
11851    #[cfg(all(_XM_SSE3_INTRINSICS_, not(_XM_SSE4_INTRINSICS_)))]
11852    unsafe {
11853        let mut vTemp: XMVECTOR = _mm_mul_ps(V1, V2);
11854        vTemp = _mm_hadd_ps(vTemp, vTemp);
11855        return _mm_hadd_ps(vTemp, vTemp);
11856    }
11857
11858    #[cfg(all(_XM_SSE_INTRINSICS_, not(_XM_SSE3_INTRINSICS_), not(_XM_SSE4_INTRINSICS_)))]
11859    unsafe {
11860        let mut vTemp2: XMVECTOR = V2;
11861        let mut vTemp: XMVECTOR = _mm_mul_ps(V1, vTemp2);
11862        vTemp2 = _mm_shuffle_ps(vTemp2, vTemp, _MM_SHUFFLE(1, 0, 0, 0)); // Copy X to the Z position and Y to the W position
11863        vTemp2 = _mm_add_ps(vTemp2, vTemp);          // Add Z = X+Z; W = Y+W;
11864        vTemp = _mm_shuffle_ps(vTemp, vTemp2, _MM_SHUFFLE(0, 3, 0, 0));  // Copy W to the Z position
11865        vTemp = _mm_add_ps(vTemp, vTemp2);           // Add Z and W together
11866        return XM_PERMUTE_PS!(vTemp, _MM_SHUFFLE(2, 2, 2, 2));    // Splat Z and return
11867    }
11868}
11869
11870
11871/// Computes the cross product between 4D vectors.
11872///
11873/// ## Parameters
11874///
11875/// `V1` 4D vector.
11876///
11877/// `V2` 4D vector.
11878///
11879/// `V3` 4D vector.
11880///
11881/// ## Return value
11882///
11883/// Returns the 4D cross product of V1, V2, and V3.
11884///
11885/// ## Remarks
11886///
11887/// A 4D cross-product is not well-defined. This function computes a geometric analog to the 3D cross product.
11888/// XMVector4Orthogonal is another generalized 'cross-product' for 4D vectors.
11889///
11890/// The following pseudocode demonstrates the operation of the function:
11891///
11892/// ```text
11893/// XMVECTOR Result;
11894///
11895/// Result.x = V1.y * (V2.z * V3.w - V3.z * V2.w)
11896///            -  V1.z * (V2.y * V3.w - V3.y * V2.w )
11897///            +  V1.w * (V2.y * V3.z - V3.y * V2.z);
11898///
11899/// Result.y = V1.x * (V3.z * V2.w - V2.z * V3.w)
11900///            - V1.z * (V3.x * V2.w - V2.x * V3.w)
11901///            + V1.w * (V3.x * V2.z - V2.x * V3.z);
11902///
11903/// Result.z = V1.x * (V2.y * V3.w - V3.y * V2.w)
11904///            - V1.y * (V2.x * V3.w - V3.x * V2.w)
11905///            + V1.w * (V2.x * V3.y - V3.x * V2.y);
11906///
11907/// Result.w = V1.x * (V3.y * V2.z - V2.y * V3.z)
11908///            - V1.y * (V3.x * V2.z - V2.x * V3.z)
11909///            + V1.z * (V3.x * V2.y - V2.x * V3.y);
11910///
11911/// return Result;
11912/// ```
11913///
11914/// ## Reference
11915///
11916/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVector4Cross>
11917#[inline]
11918pub fn XMVector4Cross(
11919    V1: FXMVECTOR,
11920    V2: FXMVECTOR,
11921    V3: FXMVECTOR,
11922) -> FXMVECTOR
11923{
11924    // [ ((v2.z*v3.w-v2.w*v3.z)*v1.y)-((v2.y*v3.w-v2.w*v3.y)*v1.z)+((v2.y*v3.z-v2.z*v3.y)*v1.w),
11925    //   ((v2.w*v3.z-v2.z*v3.w)*v1.x)-((v2.w*v3.x-v2.x*v3.w)*v1.z)+((v2.z*v3.x-v2.x*v3.z)*v1.w),
11926    //   ((v2.y*v3.w-v2.w*v3.y)*v1.x)-((v2.x*v3.w-v2.w*v3.x)*v1.y)+((v2.x*v3.y-v2.y*v3.x)*v1.w),
11927    //   ((v2.z*v3.y-v2.y*v3.z)*v1.x)-((v2.z*v3.x-v2.x*v3.z)*v1.y)+((v2.y*v3.x-v2.x*v3.y)*v1.z) ]
11928
11929    #[cfg(_XM_NO_INTRINSICS_)]
11930    unsafe {
11931        let vResult: XMVECTORF32 = XMVECTORF32 {
11932            f: [
11933                (((V2.vector4_f32[2] * V3.vector4_f32[3]) - (V2.vector4_f32[3] * V3.vector4_f32[2])) * V1.vector4_f32[1]) - (((V2.vector4_f32[1] * V3.vector4_f32[3]) - (V2.vector4_f32[3] * V3.vector4_f32[1])) * V1.vector4_f32[2]) + (((V2.vector4_f32[1] * V3.vector4_f32[2]) - (V2.vector4_f32[2] * V3.vector4_f32[1])) * V1.vector4_f32[3]),
11934                (((V2.vector4_f32[3] * V3.vector4_f32[2]) - (V2.vector4_f32[2] * V3.vector4_f32[3])) * V1.vector4_f32[0]) - (((V2.vector4_f32[3] * V3.vector4_f32[0]) - (V2.vector4_f32[0] * V3.vector4_f32[3])) * V1.vector4_f32[2]) + (((V2.vector4_f32[2] * V3.vector4_f32[0]) - (V2.vector4_f32[0] * V3.vector4_f32[2])) * V1.vector4_f32[3]),
11935                (((V2.vector4_f32[1] * V3.vector4_f32[3]) - (V2.vector4_f32[3] * V3.vector4_f32[1])) * V1.vector4_f32[0]) - (((V2.vector4_f32[0] * V3.vector4_f32[3]) - (V2.vector4_f32[3] * V3.vector4_f32[0])) * V1.vector4_f32[1]) + (((V2.vector4_f32[0] * V3.vector4_f32[1]) - (V2.vector4_f32[1] * V3.vector4_f32[0])) * V1.vector4_f32[3]),
11936                (((V2.vector4_f32[2] * V3.vector4_f32[1]) - (V2.vector4_f32[1] * V3.vector4_f32[2])) * V1.vector4_f32[0]) - (((V2.vector4_f32[2] * V3.vector4_f32[0]) - (V2.vector4_f32[0] * V3.vector4_f32[2])) * V1.vector4_f32[1]) + (((V2.vector4_f32[1] * V3.vector4_f32[0]) - (V2.vector4_f32[0] * V3.vector4_f32[1])) * V1.vector4_f32[2]),
11937            ]
11938        };
11939        return vResult.v;
11940    }
11941
11942    #[cfg(_XM_ARM_NEON_INTRINSICS_)]
11943    {
11944        unimplemented!()
11945    }
11946
11947    #[cfg(_XM_SSE_INTRINSICS_)]
11948    unsafe {
11949        // V2zwyz * V3wzwy
11950        let mut vResult: XMVECTOR = XM_PERMUTE_PS!(V2, _MM_SHUFFLE(2, 1, 3, 2));
11951        let mut vTemp3: XMVECTOR = XM_PERMUTE_PS!(V3, _MM_SHUFFLE(1, 3, 2, 3));
11952        vResult = _mm_mul_ps(vResult, vTemp3);
11953        // - V2wzwy * V3zwyz
11954        let mut vTemp2: XMVECTOR = XM_PERMUTE_PS!(V2, _MM_SHUFFLE(1, 3, 2, 3));
11955        vTemp3 = XM_PERMUTE_PS!(vTemp3, _MM_SHUFFLE(1, 3, 0, 1));
11956        vResult = XM_FNMADD_PS!(vTemp2, vTemp3, vResult);
11957        // term1 * V1yxxx
11958        let mut vTemp1: XMVECTOR = XM_PERMUTE_PS!(V1, _MM_SHUFFLE(0, 0, 0, 1));
11959        vResult = _mm_mul_ps(vResult, vTemp1);
11960
11961        // V2ywxz * V3wxwx
11962        vTemp2 = XM_PERMUTE_PS!(V2, _MM_SHUFFLE(2, 0, 3, 1));
11963        vTemp3 = XM_PERMUTE_PS!(V3, _MM_SHUFFLE(0, 3, 0, 3));
11964        vTemp3 = _mm_mul_ps(vTemp3, vTemp2);
11965        // - V2wxwx * V3ywxz
11966        vTemp2 = XM_PERMUTE_PS!(vTemp2, _MM_SHUFFLE(2, 1, 2, 1));
11967        vTemp1 = XM_PERMUTE_PS!(V3, _MM_SHUFFLE(2, 0, 3, 1));
11968        vTemp3 = XM_FNMADD_PS!(vTemp2, vTemp1, vTemp3);
11969        // vResult - temp * V1zzyy
11970        vTemp1 = XM_PERMUTE_PS!(V1, _MM_SHUFFLE(1, 1, 2, 2));
11971        vResult = XM_FNMADD_PS!(vTemp1, vTemp3, vResult);
11972
11973        // V2yzxy * V3zxyx
11974        vTemp2 = XM_PERMUTE_PS!(V2, _MM_SHUFFLE(1, 0, 2, 1));
11975        vTemp3 = XM_PERMUTE_PS!(V3, _MM_SHUFFLE(0, 1, 0, 2));
11976        vTemp3 = _mm_mul_ps(vTemp3, vTemp2);
11977        // - V2zxyx * V3yzxy
11978        vTemp2 = XM_PERMUTE_PS!(vTemp2, _MM_SHUFFLE(2, 0, 2, 1));
11979        vTemp1 = XM_PERMUTE_PS!(V3, _MM_SHUFFLE(1, 0, 2, 1));
11980        vTemp3 = XM_FNMADD_PS!(vTemp1, vTemp2, vTemp3);
11981        // vResult + term * V1wwwz
11982        vTemp1 = XM_PERMUTE_PS!(V1, _MM_SHUFFLE(2, 3, 3, 3));
11983        vResult = XM_FMADD_PS!(vTemp3, vTemp1, vResult);
11984        return vResult;
11985    }
11986}
11987
11988/// Computes the square of the length of a 4D vector.
11989///
11990/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVector4LengthSq>
11991#[inline]
11992pub fn XMVector4LengthSq(
11993    V: FXMVECTOR,
11994) -> FXMVECTOR
11995{
11996    return XMVector4Dot(V, V);
11997}
11998
11999/// Estimates the reciprocal of the length of a 4D vector.
12000///
12001/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVector4ReciprocalLengthEst>
12002#[inline]
12003pub fn XMVector4ReciprocalLengthEst(
12004    V: FXMVECTOR,
12005) -> FXMVECTOR
12006{
12007    #[cfg(_XM_NO_INTRINSICS_)]
12008    {
12009        let mut Result: XMVECTOR;
12010
12011        Result = XMVector4LengthSq(V);
12012        Result = XMVectorReciprocalSqrtEst(Result);
12013
12014        return Result;
12015    }
12016
12017    #[cfg(_XM_ARM_NEON_INTRINSICS_)]
12018    {
12019        unimplemented!()
12020    }
12021
12022    #[cfg(_XM_SSE4_INTRINSICS_)]
12023    unsafe {
12024        let vTemp: XMVECTOR = _mm_dp_ps(V, V, 0xff);
12025        return _mm_rsqrt_ps(vTemp);
12026    }
12027
12028    #[cfg(all(_XM_SSE3_INTRINSICS_, not(_XM_SSE4_INTRINSICS_)))]
12029    unsafe {
12030        let mut vLengthSq: XMVECTOR = _mm_mul_ps(V, V);
12031        vLengthSq = _mm_hadd_ps(vLengthSq, vLengthSq);
12032        vLengthSq = _mm_hadd_ps(vLengthSq, vLengthSq);
12033        vLengthSq = _mm_rsqrt_ps(vLengthSq);
12034        return vLengthSq;
12035    }
12036
12037    #[cfg(all(_XM_SSE_INTRINSICS_, not(_XM_SSE3_INTRINSICS_), not(_XM_SSE4_INTRINSICS_)))]
12038    unsafe {
12039        // Perform the dot product on x,y,z and w
12040        let mut vLengthSq: XMVECTOR = _mm_mul_ps(V, V);
12041        // vTemp has z and w
12042        let mut vTemp: XMVECTOR = XM_PERMUTE_PS!(vLengthSq, _MM_SHUFFLE(3, 2, 3, 2));
12043        // x+z, y+w
12044        vLengthSq = _mm_add_ps(vLengthSq, vTemp);
12045        // x+z,x+z,x+z,y+w
12046        vLengthSq = XM_PERMUTE_PS!(vLengthSq, _MM_SHUFFLE(1, 0, 0, 0));
12047        // ??,??,y+w,y+w
12048        vTemp = _mm_shuffle_ps(vTemp, vLengthSq, _MM_SHUFFLE(3, 3, 0, 0));
12049        // ??,??,x+z+y+w,??
12050        vLengthSq = _mm_add_ps(vLengthSq, vTemp);
12051        // Splat the length
12052        vLengthSq = XM_PERMUTE_PS!(vLengthSq, _MM_SHUFFLE(2, 2, 2, 2));
12053        // Get the reciprocal
12054        vLengthSq = _mm_rsqrt_ps(vLengthSq);
12055        return vLengthSq;
12056    }
12057}
12058
12059/// Computes the reciprocal of the length of a 4D vector.
12060///
12061/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVector4ReciprocalLength>
12062#[inline]
12063pub fn XMVector4ReciprocalLength(
12064    V: FXMVECTOR,
12065) -> FXMVECTOR
12066{
12067    #[cfg(_XM_NO_INTRINSICS_)]
12068    {
12069        let mut Result: XMVECTOR;
12070
12071        Result = XMVector4LengthSq(V);
12072        Result = XMVectorReciprocalSqrt(Result);
12073
12074        return Result;
12075    }
12076
12077    #[cfg(_XM_ARM_NEON_INTRINSICS_)]
12078    {
12079        unimplemented!()
12080    }
12081
12082    #[cfg(_XM_SSE4_INTRINSICS_)]
12083    unsafe {
12084        let vTemp: XMVECTOR = _mm_dp_ps(V, V, 0xff);
12085        let vLengthSq: XMVECTOR = _mm_sqrt_ps(vTemp);
12086        return _mm_div_ps(g_XMOne.v, vLengthSq);
12087    }
12088
12089    #[cfg(all(_XM_SSE3_INTRINSICS_, not(_XM_SSE4_INTRINSICS_)))]
12090    unsafe {
12091        let mut vLengthSq: XMVECTOR = _mm_mul_ps(V, V);
12092        vLengthSq = _mm_hadd_ps(vLengthSq, vLengthSq);
12093        vLengthSq = _mm_hadd_ps(vLengthSq, vLengthSq);
12094        vLengthSq = _mm_sqrt_ps(vLengthSq);
12095        vLengthSq = _mm_div_ps(g_XMOne.v, vLengthSq);
12096        return vLengthSq;
12097    }
12098
12099    #[cfg(all(_XM_SSE_INTRINSICS_, not(_XM_SSE3_INTRINSICS_), not(_XM_SSE4_INTRINSICS_)))]
12100    unsafe {
12101        // Perform the dot product on x,y,z and w
12102        let mut vLengthSq: XMVECTOR = _mm_mul_ps(V, V);
12103        // vTemp has z and w
12104        let mut vTemp: XMVECTOR = XM_PERMUTE_PS!(vLengthSq, _MM_SHUFFLE(3, 2, 3, 2));
12105        // x+z, y+w
12106        vLengthSq = _mm_add_ps(vLengthSq, vTemp);
12107        // x+z,x+z,x+z,y+w
12108        vLengthSq = XM_PERMUTE_PS!(vLengthSq, _MM_SHUFFLE(1, 0, 0, 0));
12109        // ??,??,y+w,y+w
12110        vTemp = _mm_shuffle_ps(vTemp, vLengthSq, _MM_SHUFFLE(3, 3, 0, 0));
12111        // ??,??,x+z+y+w,??
12112        vLengthSq = _mm_add_ps(vLengthSq, vTemp);
12113        // Splat the length
12114        vLengthSq = XM_PERMUTE_PS!(vLengthSq, _MM_SHUFFLE(2, 2, 2, 2));
12115        // Get the reciprocal
12116        vLengthSq = _mm_sqrt_ps(vLengthSq);
12117        // Accurate!
12118        vLengthSq = _mm_div_ps(g_XMOne.v, vLengthSq);
12119        return vLengthSq;
12120    }
12121}
12122
12123/// Estimates the length of a 4D vector.
12124///
12125/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVector4LengthEst>
12126#[inline]
12127pub fn XMVector4LengthEst(
12128    V: FXMVECTOR,
12129) -> FXMVECTOR
12130{
12131    #[cfg(_XM_NO_INTRINSICS_)]
12132    {
12133        let mut Result: XMVECTOR;
12134
12135        Result = XMVector4LengthSq(V);
12136        Result = XMVectorSqrtEst(Result);
12137
12138        return Result;
12139    }
12140
12141    #[cfg(_XM_ARM_NEON_INTRINSICS_)]
12142    {
12143        unimplemented!()
12144    }
12145
12146    #[cfg(_XM_SSE4_INTRINSICS_)]
12147    unsafe {
12148        let vTemp: XMVECTOR = _mm_dp_ps(V, V, 0xff);
12149        return _mm_sqrt_ps(vTemp);
12150    }
12151
12152    #[cfg(all(_XM_SSE3_INTRINSICS_, not(_XM_SSE4_INTRINSICS_)))]
12153    unsafe {
12154        let mut vLengthSq: XMVECTOR = _mm_mul_ps(V, V);
12155        vLengthSq = _mm_hadd_ps(vLengthSq, vLengthSq);
12156        vLengthSq = _mm_hadd_ps(vLengthSq, vLengthSq);
12157        vLengthSq = _mm_sqrt_ps(vLengthSq);
12158        return vLengthSq;
12159    }
12160
12161    #[cfg(all(_XM_SSE_INTRINSICS_, not(_XM_SSE3_INTRINSICS_), not(_XM_SSE4_INTRINSICS_)))]
12162    unsafe {
12163        // Perform the dot product on x,y,z and w
12164        let mut vLengthSq: XMVECTOR = _mm_mul_ps(V, V);
12165        // vTemp has z and w
12166        let mut vTemp: XMVECTOR = XM_PERMUTE_PS!(vLengthSq, _MM_SHUFFLE(3, 2, 3, 2));
12167        // x+z, y+w
12168        vLengthSq = _mm_add_ps(vLengthSq, vTemp);
12169        // x+z,x+z,x+z,y+w
12170        vLengthSq = XM_PERMUTE_PS!(vLengthSq, _MM_SHUFFLE(1, 0, 0, 0));
12171        // ??,??,y+w,y+w
12172        vTemp = _mm_shuffle_ps(vTemp, vLengthSq, _MM_SHUFFLE(3, 3, 0, 0));
12173        // ??,??,x+z+y+w,??
12174        vLengthSq = _mm_add_ps(vLengthSq, vTemp);
12175        // Splat the length
12176        vLengthSq = XM_PERMUTE_PS!(vLengthSq, _MM_SHUFFLE(2, 2, 2, 2));
12177        // Get the length
12178        vLengthSq = _mm_sqrt_ps(vLengthSq);
12179        return vLengthSq;
12180    }
12181}
12182
12183
12184/// Computes the length of a 4D vector.
12185///
12186/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVector4Length>
12187#[inline]
12188pub fn XMVector4Length(
12189    V: FXMVECTOR,
12190) -> FXMVECTOR
12191{
12192    #[cfg(_XM_NO_INTRINSICS_)]
12193    {
12194        let mut Result: XMVECTOR;
12195
12196        Result = XMVector4LengthSq(V);
12197        Result = XMVectorSqrt(Result);
12198
12199        return Result;
12200    }
12201
12202    #[cfg(_XM_ARM_NEON_INTRINSICS_)]
12203    {
12204        unimplemented!()
12205    }
12206
12207    #[cfg(_XM_SSE4_INTRINSICS_)]
12208    unsafe {
12209        let vTemp: XMVECTOR = _mm_dp_ps(V, V, 0xff);
12210        return _mm_sqrt_ps(vTemp);
12211    }
12212
12213    #[cfg(all(_XM_SSE3_INTRINSICS_, not(_XM_SSE4_INTRINSICS_)))]
12214    unsafe {
12215        let mut vLengthSq: XMVECTOR = _mm_mul_ps(V, V);
12216        vLengthSq = _mm_hadd_ps(vLengthSq, vLengthSq);
12217        vLengthSq = _mm_hadd_ps(vLengthSq, vLengthSq);
12218        vLengthSq = _mm_sqrt_ps(vLengthSq);
12219        return vLengthSq;
12220    }
12221
12222    #[cfg(all(_XM_SSE_INTRINSICS_, not(_XM_SSE3_INTRINSICS_), not(_XM_SSE4_INTRINSICS_)))]
12223    unsafe {
12224        // Perform the dot product on x,y,z and w
12225        let mut vLengthSq: XMVECTOR = _mm_mul_ps(V, V);
12226        // vTemp has z and w
12227        let mut vTemp: XMVECTOR = XM_PERMUTE_PS!(vLengthSq, _MM_SHUFFLE(3, 2, 3, 2));
12228        // x+z, y+w
12229        vLengthSq = _mm_add_ps(vLengthSq, vTemp);
12230        // x+z,x+z,x+z,y+w
12231        vLengthSq = XM_PERMUTE_PS!(vLengthSq, _MM_SHUFFLE(1, 0, 0, 0));
12232        // ??,??,y+w,y+w
12233        vTemp = _mm_shuffle_ps(vTemp, vLengthSq, _MM_SHUFFLE(3, 3, 0, 0));
12234        // ??,??,x+z+y+w,??
12235        vLengthSq = _mm_add_ps(vLengthSq, vTemp);
12236        // Splat the length
12237        vLengthSq = XM_PERMUTE_PS!(vLengthSq, _MM_SHUFFLE(2, 2, 2, 2));
12238        // Get the length
12239        vLengthSq = _mm_sqrt_ps(vLengthSq);
12240        return vLengthSq;
12241    }
12242}
12243
12244/// Estimates the normalized version of a 4D vector.
12245///
12246/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVector4NormalizeEst>
12247#[inline]
12248pub fn XMVector4NormalizeEst(
12249    V: FXMVECTOR,
12250) -> FXMVECTOR
12251{
12252    #[cfg(_XM_NO_INTRINSICS_)]
12253    {
12254        let mut Result: XMVECTOR;
12255
12256        Result = XMVector4ReciprocalLength(V);
12257        Result = XMVectorMultiply(V, Result);
12258
12259        return Result;
12260    }
12261
12262    #[cfg(_XM_ARM_NEON_INTRINSICS_)]
12263    {
12264        unimplemented!()
12265    }
12266
12267    #[cfg(_XM_SSE4_INTRINSICS_)]
12268    unsafe {
12269        let vTemp: XMVECTOR = _mm_dp_ps(V, V, 0xff);
12270        let vResult: XMVECTOR = _mm_rsqrt_ps(vTemp);
12271        return _mm_mul_ps(vResult, V);
12272    }
12273
12274    #[cfg(all(_XM_SSE3_INTRINSICS_, not(_XM_SSE4_INTRINSICS_)))]
12275    unsafe {
12276        let mut vDot: XMVECTOR = _mm_mul_ps(V, V);
12277        vDot = _mm_hadd_ps(vDot, vDot);
12278        vDot = _mm_hadd_ps(vDot, vDot);
12279        vDot = _mm_rsqrt_ps(vDot);
12280        vDot = _mm_mul_ps(vDot, V);
12281        return vDot;
12282    }
12283
12284    #[cfg(all(_XM_SSE_INTRINSICS_, not(_XM_SSE3_INTRINSICS_), not(_XM_SSE4_INTRINSICS_)))]
12285    unsafe {
12286        // Perform the dot product on x,y,z and w
12287        let mut vLengthSq: XMVECTOR = _mm_mul_ps(V, V);
12288        // vTemp has z and w
12289        let mut vTemp: XMVECTOR = XM_PERMUTE_PS!(vLengthSq, _MM_SHUFFLE(3, 2, 3, 2));
12290        // x+z, y+w
12291        vLengthSq = _mm_add_ps(vLengthSq, vTemp);
12292        // x+z,x+z,x+z,y+w
12293        vLengthSq = XM_PERMUTE_PS!(vLengthSq, _MM_SHUFFLE(1, 0, 0, 0));
12294        // ??,??,y+w,y+w
12295        vTemp = _mm_shuffle_ps(vTemp, vLengthSq, _MM_SHUFFLE(3, 3, 0, 0));
12296        // ??,??,x+z+y+w,??
12297        vLengthSq = _mm_add_ps(vLengthSq, vTemp);
12298        // Splat the length
12299        vLengthSq = XM_PERMUTE_PS!(vLengthSq, _MM_SHUFFLE(2, 2, 2, 2));
12300        // Get the reciprocal
12301        let mut vResult: XMVECTOR = _mm_rsqrt_ps(vLengthSq);
12302        // Reciprocal mul to perform the normalization
12303        vResult = _mm_mul_ps(vResult, V);
12304        return vResult;
12305    }
12306}
12307
12308/// Computes the normalized version of a 4D vector.
12309///
12310/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVector4Normalize>
12311#[inline]
12312pub fn XMVector4Normalize(
12313    V: FXMVECTOR,
12314) -> FXMVECTOR
12315{
12316    #[cfg(_XM_NO_INTRINSICS_)]
12317    unsafe {
12318        let mut fLength: f32;
12319        let mut vResult: XMVECTOR;
12320
12321        vResult = XMVector4Length(V);
12322        fLength = vResult.vector4_f32[0];
12323
12324        // Prevent divide by zero
12325        if (fLength > 0.0)
12326        {
12327            fLength = 1.0 / fLength;
12328        }
12329
12330        vResult.vector4_f32[0] = V.vector4_f32[0] * fLength;
12331        vResult.vector4_f32[1] = V.vector4_f32[1] * fLength;
12332        vResult.vector4_f32[2] = V.vector4_f32[2] * fLength;
12333        vResult.vector4_f32[3] = V.vector4_f32[3] * fLength;
12334        return vResult;
12335    }
12336
12337    #[cfg(_XM_ARM_NEON_INTRINSICS_)]
12338    {
12339        unimplemented!()
12340    }
12341
12342    #[cfg(_XM_SSE4_INTRINSICS_)]
12343    unsafe {
12344        let mut vLengthSq: XMVECTOR = _mm_dp_ps(V, V, 0xff);
12345        // Prepare for the division
12346        let mut vResult: XMVECTOR = _mm_sqrt_ps(vLengthSq);
12347        // Create zero with a single instruction
12348        let mut vZeroMask: XMVECTOR = _mm_setzero_ps();
12349        // Test for a divide by zero (Must be FP to detect -0.0)
12350        vZeroMask = _mm_cmpneq_ps(vZeroMask, vResult);
12351        // Failsafe on zero (Or epsilon) length planes
12352        // If the length is infinity, set the elements to zero
12353        vLengthSq = _mm_cmpneq_ps(vLengthSq, g_XMInfinity.v);
12354        // Divide to perform the normalization
12355        vResult = _mm_div_ps(V, vResult);
12356        // Any that are infinity, set to zero
12357        vResult = _mm_and_ps(vResult, vZeroMask);
12358        // Select qnan or result based on infinite length
12359        let vTemp1: XMVECTOR = _mm_andnot_ps(vLengthSq, g_XMQNaN.v);
12360        let vTemp2: XMVECTOR = _mm_and_ps(vResult, vLengthSq);
12361        vResult = _mm_or_ps(vTemp1, vTemp2);
12362        return vResult;
12363    }
12364
12365    #[cfg(all(_XM_SSE3_INTRINSICS_, not(_XM_SSE4_INTRINSICS_)))]
12366    unsafe {
12367        // Perform the dot product on x,y,z and w
12368        let mut vLengthSq: XMVECTOR = _mm_mul_ps(V, V);
12369        vLengthSq = _mm_hadd_ps(vLengthSq, vLengthSq);
12370        vLengthSq = _mm_hadd_ps(vLengthSq, vLengthSq);
12371        // Prepare for the division
12372        let mut vResult: XMVECTOR = _mm_sqrt_ps(vLengthSq);
12373        // Create zero with a single instruction
12374        let mut vZeroMask: XMVECTOR = _mm_setzero_ps();
12375        // Test for a divide by zero (Must be FP to detect -0.0)
12376        vZeroMask = _mm_cmpneq_ps(vZeroMask, vResult);
12377        // Failsafe on zero (Or epsilon) length planes
12378        // If the length is infinity, set the elements to zero
12379        vLengthSq = _mm_cmpneq_ps(vLengthSq, g_XMInfinity.v);
12380        // Divide to perform the normalization
12381        vResult = _mm_div_ps(V, vResult);
12382        // Any that are infinity, set to zero
12383        vResult = _mm_and_ps(vResult, vZeroMask);
12384        // Select qnan or result based on infinite length
12385        let vTemp1: XMVECTOR = _mm_andnot_ps(vLengthSq, g_XMQNaN.v);
12386        let vTemp2: XMVECTOR = _mm_and_ps(vResult, vLengthSq);
12387        vResult = _mm_or_ps(vTemp1, vTemp2);
12388        return vResult;
12389    }
12390
12391    #[cfg(all(_XM_SSE_INTRINSICS_, not(_XM_SSE3_INTRINSICS_), not(_XM_SSE4_INTRINSICS_)))]
12392    unsafe {
12393        // Perform the dot product on x,y,z and w
12394        let mut vLengthSq: XMVECTOR = _mm_mul_ps(V, V);
12395        // vTemp has z and w
12396        let mut vTemp: XMVECTOR = XM_PERMUTE_PS!(vLengthSq, _MM_SHUFFLE(3, 2, 3, 2));
12397        // x+z, y+w
12398        vLengthSq = _mm_add_ps(vLengthSq, vTemp);
12399        // x+z,x+z,x+z,y+w
12400        vLengthSq = XM_PERMUTE_PS!(vLengthSq, _MM_SHUFFLE(1, 0, 0, 0));
12401        // ??,??,y+w,y+w
12402        vTemp = _mm_shuffle_ps(vTemp, vLengthSq, _MM_SHUFFLE(3, 3, 0, 0));
12403        // ??,??,x+z+y+w,??
12404        vLengthSq = _mm_add_ps(vLengthSq, vTemp);
12405        // Splat the length
12406        vLengthSq = XM_PERMUTE_PS!(vLengthSq, _MM_SHUFFLE(2, 2, 2, 2));
12407        // Prepare for the division
12408        let mut vResult: XMVECTOR = _mm_sqrt_ps(vLengthSq);
12409        // Create zero with a single instruction
12410        let mut vZeroMask: XMVECTOR = _mm_setzero_ps();
12411        // Test for a divide by zero (Must be FP to detect -0.0)
12412        vZeroMask = _mm_cmpneq_ps(vZeroMask, vResult);
12413        // Failsafe on zero (Or epsilon) length planes
12414        // If the length is infinity, set the elements to zero
12415        vLengthSq = _mm_cmpneq_ps(vLengthSq, g_XMInfinity.v);
12416        // Divide to perform the normalization
12417        vResult = _mm_div_ps(V, vResult);
12418        // Any that are infinity, set to zero
12419        vResult = _mm_and_ps(vResult, vZeroMask);
12420        // Select qnan or result based on infinite length
12421        let vTemp1: XMVECTOR = _mm_andnot_ps(vLengthSq, g_XMQNaN.v);
12422        let vTemp2: XMVECTOR = _mm_and_ps(vResult, vLengthSq);
12423        vResult = _mm_or_ps(vTemp1, vTemp2);
12424        return vResult;
12425    }
12426}
12427
12428/// Clamps the length of a 4D vector to a given range.
12429///
12430/// ## Parameters
12431///
12432/// `V` 4D vector.
12433///
12434/// `LengthMin` Minimum clamp length.
12435///
12436/// `LengthMax` Maximum clamp length.
12437///
12438/// ## Return value
12439///
12440/// Returns a 4D vector whose length is clamped to the specified minimum and maximum.
12441///
12442/// ## Reference
12443///
12444/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVector4ClampLength>
12445#[inline]
12446pub fn XMVector4ClampLength(
12447    V: FXMVECTOR,
12448    LengthMin: f32,
12449    LengthMax: f32,
12450) -> XMVECTOR
12451{
12452    let ClampMax: XMVECTOR = XMVectorReplicate(LengthMax);
12453    let ClampMin: XMVECTOR = XMVectorReplicate(LengthMin);
12454
12455    return XMVector4ClampLengthV(V, ClampMin, ClampMax);
12456}
12457
12458
12459/// Clamps the length of a 4D vector to a given range.
12460///
12461/// ## Parameters
12462///
12463/// `V` 4D vector to clamp.
12464///
12465/// `LengthMin` 4D vector, all of whose components are equal to the minimum clamp length. The components must be greater-than-or-equal
12466/// to zero.
12467///
12468/// `LengthMax` 4D vector, all of whose components are equal to the maximum clamp length. The components must be greater-than-or-equal
12469/// to zero.
12470///
12471/// ## Return value
12472///
12473/// Returns a 4D vector whose length is clamped to the specified minimum and maximum.
12474///
12475/// ## Remarks
12476///
12477/// This function is identical to XMVector4ClampLength except that `LengthMin` and `LengthMax` are supplied
12478/// using 4D vectors instead of float values.
12479///
12480/// ## Reference
12481///
12482/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVector4ClampLengthV>
12483#[inline]
12484pub fn XMVector4ClampLengthV(
12485    V: FXMVECTOR,
12486    LengthMin: FXMVECTOR,
12487    LengthMax: FXMVECTOR,
12488) -> XMVECTOR
12489{
12490    unsafe {
12491        debug_assert!((XMVectorGetY(LengthMin) == XMVectorGetX(LengthMin)) && (XMVectorGetZ(LengthMin) == XMVectorGetX(LengthMin)) && (XMVectorGetW(LengthMin) == XMVectorGetX(LengthMin)));
12492        debug_assert!((XMVectorGetY(LengthMax) == XMVectorGetX(LengthMax)) && (XMVectorGetZ(LengthMax) == XMVectorGetX(LengthMax)) && (XMVectorGetW(LengthMax) == XMVectorGetX(LengthMax)));
12493        debug_assert!(XMVector4GreaterOrEqual(LengthMin, XMVectorZero()));
12494        debug_assert!(XMVector4GreaterOrEqual(LengthMax, XMVectorZero()));
12495        debug_assert!(XMVector4GreaterOrEqual(LengthMax, LengthMin));
12496
12497        let LengthSq: XMVECTOR = XMVector4LengthSq(V);
12498
12499        const Zero: XMVECTOR = unsafe { g_XMZero.v };
12500
12501        let RcpLength: XMVECTOR = XMVectorReciprocalSqrt(LengthSq);
12502
12503        let InfiniteLength: XMVECTOR = XMVectorEqualInt(LengthSq, g_XMInfinity.v);
12504        let ZeroLength: XMVECTOR = XMVectorEqual(LengthSq, Zero);
12505
12506        let mut Normal: XMVECTOR = XMVectorMultiply(V, RcpLength);
12507
12508        let mut Length: XMVECTOR = XMVectorMultiply(LengthSq, RcpLength);
12509
12510        let Select: XMVECTOR = XMVectorEqualInt(InfiniteLength, ZeroLength);
12511        Length = XMVectorSelect(LengthSq, Length, Select);
12512        Normal = XMVectorSelect(LengthSq, Normal, Select);
12513
12514        let ControlMax: XMVECTOR = XMVectorGreater(Length, LengthMax);
12515        let ControlMin: XMVECTOR = XMVectorLess(Length, LengthMin);
12516
12517        let mut ClampLength: XMVECTOR = XMVectorSelect(Length, LengthMax, ControlMax);
12518        ClampLength = XMVectorSelect(ClampLength, LengthMin, ControlMin);
12519
12520        let mut Result: XMVECTOR = XMVectorMultiply(Normal, ClampLength);
12521
12522        // Preserve the original vector (with no precision loss) if the length falls within the given range
12523        let Control: XMVECTOR = XMVectorEqualInt(ControlMax, ControlMin);
12524        Result = XMVectorSelect(Result, V, Control);
12525
12526        return Result;
12527    }
12528}
12529
12530/// Reflects an incident 4D vector across a 4D normal vector.
12531///
12532/// ## Parameters
12533///
12534/// `Incident` 4D incident vector to reflect.
12535///
12536/// `Normal` 4D normal vector to reflect the incident vector across.
12537///
12538/// ## Return value
12539///
12540/// Returns the reflected incident angle.
12541///
12542/// ## Remarks
12543///
12544/// The following pseudocode demonstrates the operation of the function:
12545///
12546/// ```text
12547/// MVECTOR Result;
12548///
12549/// float s = 2.0f * dot(Incident, Normal);
12550///
12551/// Result.x = Incident.x - s * Normal.x;
12552/// Result.y = Incident.y - s * Normal.y;
12553/// Result.z = Incident.z - s * Normal.z;
12554/// Result.w = Incident.w - s * Normal.w;
12555///
12556/// return Result;
12557/// ```
12558///
12559/// ## Reference
12560///
12561/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVector4Reflect>
12562#[inline]
12563pub fn XMVector4Reflect(
12564    Incident: FXMVECTOR,
12565    Normal: FXMVECTOR,
12566) -> XMVECTOR
12567{
12568    // Result = Incident - (2 * dot(Incident, Normal)) * Normal
12569
12570    let mut Result: XMVECTOR = XMVector4Dot(Incident, Normal);
12571    Result = XMVectorAdd(Result, Result);
12572    Result = XMVectorNegativeMultiplySubtract(Result, Normal, Incident);
12573
12574    return Result;
12575}
12576
12577/// Reflects an incident 4D vector across a 4D normal vector.
12578///
12579/// ## Parameters
12580///
12581/// `Incident` 4D incident vector to refract.
12582///
12583/// `Normal` 4D normal vector to refract the incident vector through.
12584///
12585/// `RefractionIndex` Index of refraction. See remarks.
12586///
12587/// ## Return value
12588///
12589/// Returns the refracted incident vector. If the refraction index and the angle between the incident vector
12590/// and the normal are such that the result is a total internal reflection, the function will return a vector
12591/// of the form < `0.0`, `0.0`, `0.0`, `0.0` >.
12592///
12593/// ## Remarks
12594///
12595/// The following pseudocode demonstrates the operation of the function:
12596///
12597/// ```text
12598/// XMVECTOR Result;
12599///
12600/// float t = dot(Incident, Normal);
12601/// float r = 1.0f - RefractionIndex * RefractionIndex * (1.0f - t * t);
12602///
12603/// if (r < 0.0f) // Total internal reflection
12604/// {
12605///     Result.x = 0.0f;
12606///     Result.y = 0.0f;
12607///     Result.z = 0.0f;
12608///     Result.w = 0.0f;
12609/// }
12610/// else
12611/// {
12612///     float s = RefractionIndex * t + sqrt(r);
12613///     Result.x = RefractionIndex * Incident.x - s * Normal.x;
12614///     Result.y = RefractionIndex * Incident.y - s * Normal.y;
12615///     Result.z = RefractionIndex * Incident.z - s * Normal.z;
12616///     Result.w = RefractionIndex * Incident.w - s * Normal.w;
12617/// }
12618///
12619/// return Result;
12620/// ```
12621///
12622/// The index of refraction is the ratio of the index of refraction of the medium containing the incident
12623/// vector to the index of refraction of the medium being entered (where the index of refraction of a medium
12624/// is itself the ratio of the speed of light in a vacuum to the speed of light in the medium).
12625///
12626/// ## Reference
12627///
12628/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVector4Refract>
12629#[inline]
12630pub fn XMVector4Refract(
12631    Incident: FXMVECTOR,
12632    Normal: FXMVECTOR,
12633    RefractionIndex: f32,
12634) -> XMVECTOR
12635{
12636    let Index: XMVECTOR = XMVectorReplicate(RefractionIndex);
12637    return XMVector4RefractV(Incident, Normal, Index);
12638}
12639
12640/// Computes a vector perpendicular to a 4D vector.
12641///
12642/// ## Parameters
12643///
12644/// `Incident` 4D incident vector to refract.
12645///
12646/// `Normal` 4D normal vector to refract the incident vector through.
12647///
12648/// `RefractionIndex` 4D vector, all of whose components are equal to the index of refraction.
12649///
12650/// ## Return value
12651///
12652/// Returns the refracted incident vector. If the refraction index and the angle between the incident vector
12653/// and the normal are such that the result is a total internal reflection, the function will return a vector
12654/// of the form < `0.0`, `0.0`, `0.0`, `0.0` >.
12655///
12656/// ## Remarks
12657///
12658/// This function is identical to XMVector4Refract except that the RefractionIndex is supplied using a 4D
12659/// vector instead of a float value.
12660///
12661/// ## Reference
12662///
12663/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVector4RefractV>
12664#[inline]
12665pub fn XMVector4RefractV(
12666    Incident: FXMVECTOR,
12667    Normal: FXMVECTOR,
12668    RefractionIndex: FXMVECTOR,
12669) -> XMVECTOR
12670{
12671    #[cfg(_XM_NO_INTRINSICS_)]
12672    unsafe {
12673        let IDotN: XMVECTOR;
12674        let mut R: XMVECTOR;
12675        const Zero: XMVECTOR = unsafe { g_XMZero.v };
12676
12677        // Result = RefractionIndex * Incident - Normal * (RefractionIndex * dot(Incident, Normal) +
12678        // sqrt(1 - RefractionIndex * RefractionIndex * (1 - dot(Incident, Normal) * dot(Incident, Normal))))
12679
12680        IDotN = XMVector4Dot(Incident, Normal);
12681
12682        // R = 1.0f - RefractionIndex * RefractionIndex * (1.0f - IDotN * IDotN)
12683        R = XMVectorNegativeMultiplySubtract(IDotN, IDotN, g_XMOne.v);
12684        R = XMVectorMultiply(R, RefractionIndex);
12685        R = XMVectorNegativeMultiplySubtract(R, RefractionIndex, g_XMOne.v);
12686
12687        if (XMVector4LessOrEqual(R, Zero))
12688        {
12689            // Total internal reflection
12690            return Zero;
12691        }
12692        else
12693        {
12694            let mut Result: XMVECTOR;
12695
12696            // R = RefractionIndex * IDotN + sqrt(R)
12697            R = XMVectorSqrt(R);
12698            R = XMVectorMultiplyAdd(RefractionIndex, IDotN, R);
12699
12700            // Result = RefractionIndex * Incident - Normal * R
12701            Result = XMVectorMultiply(RefractionIndex, Incident);
12702            Result = XMVectorNegativeMultiplySubtract(Normal, R, Result);
12703
12704            return Result;
12705        }
12706    }
12707
12708    #[cfg(_XM_ARM_NEON_INTRINSICS_)]
12709    {
12710        unimplemented!()
12711    }
12712
12713    #[cfg(_XM_SSE_INTRINSICS_)]
12714    unsafe {
12715        let IDotN: XMVECTOR = XMVector4Dot(Incident, Normal);
12716
12717        // R = 1.0f - RefractionIndex * RefractionIndex * (1.0f - IDotN * IDotN)
12718        let mut R: XMVECTOR = XM_FNMADD_PS!(IDotN, IDotN, g_XMOne.v);
12719        let R2: XMVECTOR = _mm_mul_ps(RefractionIndex, RefractionIndex);
12720        R = XM_FNMADD_PS!(R, R2, g_XMOne.v);
12721
12722        let mut vResult: XMVECTOR = _mm_cmple_ps(R, g_XMZero.v);
12723        if (_mm_movemask_ps(vResult) == 0x0f)
12724        {
12725            // Total internal reflection
12726            vResult = g_XMZero.v;
12727        }
12728        else
12729        {
12730            // R = RefractionIndex * IDotN + sqrt(R)
12731            R = _mm_sqrt_ps(R);
12732            R = XM_FMADD_PS!(RefractionIndex, IDotN, R);
12733            // Result = RefractionIndex * Incident - Normal * R
12734            vResult = _mm_mul_ps(RefractionIndex, Incident);
12735            vResult = XM_FNMADD_PS!(R, Normal, vResult);
12736        }
12737        return vResult;
12738    }
12739}
12740
12741
12742/// Computes a vector perpendicular to a 4D vector.
12743///
12744/// ## Parameters
12745///
12746/// `V` 4D vector.
12747///
12748/// ## Return value
12749///
12750/// Returns the 4D vector orthogonal to `V`.
12751///
12752/// ## Remarks
12753///
12754/// A 4D cross-product is not well-defined. This function computes a generalized 'cross-product' for 4D
12755/// vectors. XMVector4Cross is another geometric 'cross-product' for 4D vectors.
12756///
12757/// The following pseudocode demonstrates the operation of the function:
12758///
12759/// ```text
12760/// XMVECTOR Result;
12761///
12762/// Result.x = V.z;
12763/// Result.y = V.w;
12764/// Result.z = -V.x;
12765/// Result.w = -V.y;
12766///
12767/// return Result;
12768/// ```
12769///
12770/// ## Reference
12771///
12772/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVector4Orthogonal>
12773#[inline]
12774pub fn XMVector4Orthogonal(
12775    V: FXMVECTOR,
12776) -> XMVECTOR
12777{
12778    #[cfg(_XM_NO_INTRINSICS_)]
12779    unsafe {
12780        let Result = XMVECTORF32 { f: [
12781            V.vector4_f32[2],
12782            V.vector4_f32[3],
12783            -V.vector4_f32[0],
12784            -V.vector4_f32[1]
12785        ]};
12786        return Result.v;
12787    }
12788
12789    #[cfg(_XM_ARM_NEON_INTRINSICS_)]
12790    {
12791        unimplemented!()
12792    }
12793
12794    #[cfg(_XM_SSE_INTRINSICS_)]
12795    unsafe {
12796        const FlipZW: XMVECTORF32 = XMVECTORF32 { f: [ 1.0, 1.0, -1.0, -1.0 ] };
12797        let mut vResult: XMVECTOR = XM_PERMUTE_PS!(V, _MM_SHUFFLE(1, 0, 3, 2));
12798        vResult = _mm_mul_ps(vResult, FlipZW.v);
12799        return vResult;
12800    }
12801}
12802
12803/// Estimates the radian angle between two normalized 4D vectors.
12804///
12805/// ## Parameters
12806///
12807/// `N1` Normalized 4D vector.
12808///
12809/// `N2` Normalized 4D vector.
12810///
12811/// ## Return value
12812///
12813/// Returns a vector. The estimate of the radian angle (between `N1` and `N2`) is replicated to each of the
12814/// components.
12815///
12816/// ## Remarks
12817///
12818/// `Est` functions offer increased performance at the expense of reduced accuracy. `Est` functions are appropriate
12819/// for non-critical calculations where accuracy can be sacrificed for speed. The exact amount of lost accuracy
12820/// and speed increase are platform dependent.
12821///
12822/// ## Reference
12823///
12824/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVector4AngleBetweenNormalsEst>
12825#[inline]
12826pub fn XMVector4AngleBetweenNormalsEst(
12827    N1: FXMVECTOR,
12828    N2: FXMVECTOR,
12829) -> XMVECTOR
12830{
12831    unsafe {
12832        let mut Result: XMVECTOR = XMVector4Dot(N1, N2);
12833        Result = XMVectorClamp(Result, g_XMNegativeOne.v, g_XMOne.v);
12834        Result = XMVectorACosEst(Result);
12835        return Result;
12836    }
12837}
12838
12839/// Computes the radian angle between two normalized 4D vectors.
12840///
12841/// ## Parameters
12842///
12843/// `N1` Normalized 4D vector.
12844///
12845/// `N2` Normalized 4D vector.
12846///
12847/// ## Return value
12848///
12849/// Returns a vector. The radian angle between N1 and N2 is replicated to each of the components.
12850///
12851/// ## Reference
12852///
12853/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVector4AngleBetweenNormals>
12854#[inline]
12855pub fn XMVector4AngleBetweenNormals(
12856    N1: FXMVECTOR,
12857    N2: FXMVECTOR,
12858) -> XMVECTOR
12859{
12860    unsafe {
12861        let mut Result: XMVECTOR = XMVector4Dot(N1, N2);
12862        Result = XMVectorClamp(Result, g_XMNegativeOne.v, g_XMOne.v);
12863        Result = XMVectorACos(Result);
12864        return Result;
12865    }
12866}
12867
12868/// Compute the radian angle between two 4D vectors.
12869///
12870/// ## Parameters
12871///
12872/// `V1` 4D vector.
12873///
12874/// `V2` 4D vector.
12875///
12876/// ## Return value
12877///
12878/// Returns a vector. The radian angle between `V1` and `V2` is replicated to each of the components.
12879///
12880/// ## Remarks
12881///
12882/// If `V1` and `V2` are normalized 4D vectors, it is faster to use XMVector4AngleBetweenNormals.
12883///
12884/// ## Reference
12885///
12886/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVector4AngleBetweenVectors>
12887#[inline]
12888pub fn XMVector4AngleBetweenVectors(
12889    V1: FXMVECTOR,
12890    V2: FXMVECTOR,
12891) -> XMVECTOR
12892{
12893    unsafe {
12894        let mut L1: XMVECTOR = XMVector4ReciprocalLength(V1);
12895        let L2: XMVECTOR = XMVector4ReciprocalLength(V2);
12896
12897        let Dot: XMVECTOR = XMVector4Dot(V1, V2);
12898
12899        L1 = XMVectorMultiply(L1, L2);
12900
12901        let mut CosAngle: XMVECTOR = XMVectorMultiply(Dot, L1);
12902        CosAngle = XMVectorClamp(CosAngle, g_XMNegativeOne.v, g_XMOne.v);
12903
12904        return XMVectorACos(CosAngle);
12905    }
12906}
12907
12908/// Transforms a 4D vector by a matrix.
12909///
12910/// ## Parameters
12911///
12912/// `V` 4D vector.
12913///
12914/// `M` Transformation matrix.
12915///
12916/// ## Return value
12917///
12918/// Returns the transformed vector.
12919///
12920/// ## Reference
12921///
12922/// <https://docs.microsoft.com/en-us/windows/win32/api/directxmath/nf-directxmath-XMVector4Transform>
12923#[inline]
12924pub fn XMVector4Transform(
12925    V: FXMVECTOR,
12926    M: XMMATRIX,
12927) -> XMVECTOR
12928{
12929    #[cfg(_XM_NO_INTRINSICS_)]
12930    unsafe {
12931        let fX: f32 = (M.m[0][0] * V.vector4_f32[0]) + (M.m[1][0] * V.vector4_f32[1]) + (M.m[2][0] * V.vector4_f32[2]) + (M.m[3][0] * V.vector4_f32[3]);
12932        let fY: f32 = (M.m[0][1] * V.vector4_f32[0]) + (M.m[1][1] * V.vector4_f32[1]) + (M.m[2][1] * V.vector4_f32[2]) + (M.m[3][1] * V.vector4_f32[3]);
12933        let fZ: f32 = (M.m[0][2] * V.vector4_f32[0]) + (M.m[1][2] * V.vector4_f32[1]) + (M.m[2][2] * V.vector4_f32[2]) + (M.m[3][2] * V.vector4_f32[3]);
12934        let fW: f32 = (M.m[0][3] * V.vector4_f32[0]) + (M.m[1][3] * V.vector4_f32[1]) + (M.m[2][3] * V.vector4_f32[2]) + (M.m[3][3] * V.vector4_f32[3]);
12935        let vResult = XMVECTORF32 { f: [ fX, fY, fZ, fW ] };
12936        return vResult.v;
12937    }
12938
12939    #[cfg(_XM_ARM_NEON_INTRINSICS_)]
12940    {
12941        unimplemented!()
12942    }
12943
12944    #[cfg(_XM_SSE_INTRINSICS_)]
12945    unsafe {
12946        let mut vResult: XMVECTOR = XM_PERMUTE_PS!(V, _MM_SHUFFLE(3, 3, 3, 3)); // W
12947        vResult = _mm_mul_ps(vResult, M.r[3]);
12948        let mut vTemp: XMVECTOR = XM_PERMUTE_PS!(V, _MM_SHUFFLE(2, 2, 2, 2)); // Z
12949        vResult = XM_FMADD_PS!(vTemp, M.r[2], vResult);
12950        vTemp = XM_PERMUTE_PS!(V, _MM_SHUFFLE(1, 1, 1, 1)); // Y
12951        vResult = XM_FMADD_PS!(vTemp, M.r[1], vResult);
12952        vTemp = XM_PERMUTE_PS!(V, _MM_SHUFFLE(0, 0, 0, 0)); // X
12953        vResult = XM_FMADD_PS!(vTemp, M.r[0], vResult);
12954        return vResult;
12955    }
12956}
12957
12958// TODO: XMVector4TransformStream
12959
12960impl From<&[f32; 4]> for XMVector {
12961    #[inline]
12962    fn from(v: &[f32; 4]) -> XMVector {
12963        XMVector(XMLoadFloat4(v.into()))
12964    }
12965}
12966
12967impl std::ops::Deref for XMVector {
12968    type Target = XMVECTOR;
12969    #[inline(always)]
12970    fn deref(&self) -> &Self::Target {
12971        &self.0
12972    }
12973}
12974
12975impl std::ops::DerefMut for XMVector {
12976    #[inline(always)]
12977    fn deref_mut(&mut self) -> &mut Self::Target {
12978        &mut self.0
12979    }
12980}
12981
12982impl XMVector {
12983    #[inline(always)]
12984    pub fn set(x: f32, y: f32, z: f32, w: f32) -> XMVector {
12985        XMVector(XMVectorSet(x, y, z, w))
12986    }
12987}
12988
12989impl std::ops::Add for XMVector {
12990    type Output = XMVector;
12991    #[inline]
12992    fn add(self, V2: XMVector) -> Self::Output {
12993        XMVector(XMVectorAdd(self.0, V2.0))
12994    }
12995}
12996
12997impl std::ops::AddAssign for XMVector {
12998    #[inline]
12999    fn add_assign(&mut self, V2: XMVector) {
13000        self.0 = XMVectorAdd(self.0, V2.0);
13001    }
13002}
13003
13004impl std::ops::Sub for XMVector {
13005    type Output = XMVector;
13006    #[inline]
13007    fn sub(self, V2: XMVector) -> Self::Output {
13008        XMVector(XMVectorSubtract(self.0, V2.0))
13009    }
13010}
13011
13012impl std::ops::SubAssign for XMVector {
13013    #[inline]
13014    fn sub_assign(&mut self, V2: XMVector) {
13015        self.0 = XMVectorSubtract(self.0, V2.0);
13016    }
13017}
13018
13019impl std::ops::Mul for XMVector {
13020    type Output = XMVector;
13021    #[inline]
13022    fn mul(self, V2: XMVector) -> Self::Output {
13023        XMVector(XMVectorMultiply(self.0, V2.0))
13024    }
13025}
13026
13027impl std::ops::MulAssign for XMVector {
13028    #[inline]
13029    fn mul_assign(&mut self, V2: XMVector) {
13030        self.0 = XMVectorMultiply(self.0, V2.0);
13031    }
13032}
13033
13034impl std::ops::Div for XMVector {
13035    type Output = XMVector;
13036    #[inline]
13037    fn div(self, V2: XMVector) -> Self::Output {
13038        XMVector(XMVectorDivide(self.0, V2.0))
13039    }
13040}
13041
13042impl std::ops::DivAssign for XMVector {
13043    #[inline]
13044    fn div_assign(&mut self, V2: XMVector) {
13045        self.0 = XMVectorDivide(self.0, V2.0);
13046    }
13047}
13048
13049impl std::ops::Mul<XMVector> for f32 {
13050    type Output = XMVector;
13051    #[inline]
13052    fn mul(self, V: XMVector) -> Self::Output {
13053        let S = self;
13054        XMVector(XMVectorScale(V.0, S))
13055    }
13056}
13057
13058impl std::ops::Mul<f32> for XMVector {
13059    type Output = XMVector;
13060    #[inline]
13061    fn mul(self, S: f32) -> Self::Output {
13062        XMVector(XMVectorScale(self.0, S))
13063    }
13064}
13065
13066impl std::ops::MulAssign<f32> for XMVector {
13067    #[inline]
13068    fn mul_assign(&mut self, S: f32) {
13069        self.0 = XMVectorScale(self.0, S);
13070    }
13071}
13072
13073impl std::ops::Div<f32> for XMVector {
13074    type Output = XMVector;
13075    #[inline]
13076    fn div(self, S: f32) -> Self::Output {
13077        let vS = XMVectorReplicate(S);
13078        XMVector(XMVectorDivide(self.0, vS))
13079    }
13080}
13081
13082impl std::ops::DivAssign<f32> for XMVector {
13083    #[inline]
13084    fn div_assign(&mut self, S: f32) {
13085        let vS = XMVectorReplicate(S);
13086        self.0 = XMVectorDivide(self.0, vS);
13087    }
13088}
13089
13090impl std::ops::Neg for XMVector {
13091    type Output = XMVector;
13092    #[inline]
13093    fn neg(self) -> Self::Output {
13094        XMVector(XMVectorNegate(*self))
13095    }
13096}
13097
13098impl std::cmp::PartialEq for XMVector {
13099    #[inline]
13100    fn eq(&self, rhs: &Self) -> bool {
13101        XMVector4Equal(self.0, rhs.0)
13102    }
13103}
13104
13105impl std::fmt::Debug for XMVector {
13106    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
13107        f.debug_list()
13108            .entry(&XMVectorGetX(self.0))
13109            .entry(&XMVectorGetY(self.0))
13110            .entry(&XMVectorGetZ(self.0))
13111            .entry(&XMVectorGetW(self.0))
13112            .finish()
13113    }
13114}
13115
13116
13117#[test]
13118fn test_debug() {
13119    #[rustfmt::skip]
13120    let m = XMVector::from(&[1.0, 2.0, 3.0, 4.0]);
13121    let s = format!("{:?}", m);
13122    assert_eq!("[1.0, 2.0, 3.0, 4.0]", s);
13123}