RavEngine
Loading...
Searching...
No Matches
PxUnixSse2InlineAoS.h
1// Redistribution and use in source and binary forms, with or without
2// modification, are permitted provided that the following conditions
3// are met:
4// * Redistributions of source code must retain the above copyright
5// notice, this list of conditions and the following disclaimer.
6// * Redistributions in binary form must reproduce the above copyright
7// notice, this list of conditions and the following disclaimer in the
8// documentation and/or other materials provided with the distribution.
9// * Neither the name of NVIDIA CORPORATION nor the names of its
10// contributors may be used to endorse or promote products derived
11// from this software without specific prior written permission.
12//
13// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY
14// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
17// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21// OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24//
25// Copyright (c) 2008-2022 NVIDIA Corporation. All rights reserved.
26// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
27// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
28
29#ifndef PXFOUNDATION_PXUNIXSSE2INLINEAOS_H
30#define PXFOUNDATION_PXUNIXSSE2INLINEAOS_H
31
32#if !COMPILE_VECTOR_INTRINSICS
33#error Vector intrinsics should not be included when using scalar implementation.
34#endif
35
36#ifdef __SSE4_2__
37#include "smmintrin.h"
38#endif
39
40#include "../../PxVecMathSSE.h"
41
42namespace physx
43{
44namespace aos
45{
46
47#define PX_FPCLASS_SNAN 0x0001 /* signaling NaN */
48#define PX_FPCLASS_QNAN 0x0002 /* quiet NaN */
49#define PX_FPCLASS_NINF 0x0004 /* negative infinity */
50#define PX_FPCLASS_PINF 0x0200 /* positive infinity */
51
52PX_FORCE_INLINE __m128 m128_I2F(__m128i n)
53{
54 return _mm_castsi128_ps(n);
55}
56PX_FORCE_INLINE __m128i m128_F2I(__m128 n)
57{
58 return _mm_castps_si128(n);
59}
60
62//Test that Vec3V and FloatV are legal
64
65#define FLOAT_COMPONENTS_EQUAL_THRESHOLD 0.01f
66PX_FORCE_INLINE static bool isValidFloatV(const FloatV a)
67{
68 const PxF32 x = V4ReadX(a);
69 const PxF32 y = V4ReadY(a);
70 const PxF32 z = V4ReadZ(a);
71 const PxF32 w = V4ReadW(a);
72
73 return (x == y && x == z && x == w);
74
75 /*if (
76 (PxAbs(x - y) < FLOAT_COMPONENTS_EQUAL_THRESHOLD) &&
77 (PxAbs(x - z) < FLOAT_COMPONENTS_EQUAL_THRESHOLD) &&
78 (PxAbs(x - w) < FLOAT_COMPONENTS_EQUAL_THRESHOLD)
79 )
80 {
81 return true;
82 }
83
84 if (
85 (PxAbs((x - y) / x) < FLOAT_COMPONENTS_EQUAL_THRESHOLD) &&
86 (PxAbs((x - z) / x) < FLOAT_COMPONENTS_EQUAL_THRESHOLD) &&
87 (PxAbs((x - w) / x) < FLOAT_COMPONENTS_EQUAL_THRESHOLD)
88 )
89 {
90 return true;
91 }
92
93 return false;*/
94}
95
96PX_FORCE_INLINE bool isValidVec3V(const Vec3V a)
97{
98 PX_ALIGN(16, PxF32 f[4]);
99 V4StoreA(a, f);
100 return (f[3] == 0.0f);
101}
102
103PX_FORCE_INLINE bool isFiniteLength(const Vec3V a)
104{
105 return !FAllEq(V4LengthSq(a), FZero());
106}
107
108PX_FORCE_INLINE bool isAligned16(void* a)
109{
110 return(0 == (size_t(a) & 0x0f));
111}
112
113//ASSERT_FINITELENGTH is deactivated because there is a lot of code that calls a simd normalisation function with zero length but then ignores the result.
114
115#if PX_DEBUG
116#define ASSERT_ISVALIDVEC3V(a) PX_ASSERT(isValidVec3V(a))
117#define ASSERT_ISVALIDFLOATV(a) PX_ASSERT(isValidFloatV(a))
118#define ASSERT_ISALIGNED16(a) PX_ASSERT(isAligned16(reinterpret_cast<void*>(a)))
119#define ASSERT_ISFINITELENGTH(a) //PX_ASSERT(isFiniteLength(a))
120#else
121#define ASSERT_ISVALIDVEC3V(a)
122#define ASSERT_ISVALIDFLOATV(a)
123#define ASSERT_ISALIGNED16(a)
124#define ASSERT_ISFINITELENGTH(a)
125#endif
126
127
128namespace internalUnitSSE2Simd
129{
130PX_FORCE_INLINE PxU32 BAllTrue4_R(const BoolV a)
131{
132 const PxI32 moveMask = _mm_movemask_ps(a);
133 return PxU32(moveMask == 0xf);
134}
135
136PX_FORCE_INLINE PxU32 BAllTrue3_R(const BoolV a)
137{
138 const PxI32 moveMask = _mm_movemask_ps(a);
139 return PxU32((moveMask & 0x7) == 0x7);
140}
141
142PX_FORCE_INLINE PxU32 BAnyTrue4_R(const BoolV a)
143{
144 const PxI32 moveMask = _mm_movemask_ps(a);
145 return PxU32(moveMask != 0x0);
146}
147
148PX_FORCE_INLINE PxU32 BAnyTrue3_R(const BoolV a)
149{
150 const PxI32 moveMask = _mm_movemask_ps(a);
151 return PxU32((moveMask & 0x7) != 0x0);
152}
153
154PX_FORCE_INLINE PxU32 FiniteTestEq(const Vec4V a, const Vec4V b)
155{
156 // This is a bit of a bodge.
157 //_mm_comieq_ss returns 1 if either value is nan so we need to re-cast a and b with true encoded as a non-nan
158 // number.
159 // There must be a better way of doing this in sse.
160 const BoolV one = FOne();
161 const BoolV zero = FZero();
162 const BoolV a1 = V4Sel(a, one, zero);
163 const BoolV b1 = V4Sel(b, one, zero);
164 return (
165 _mm_comieq_ss(a1, b1) &&
166 _mm_comieq_ss(_mm_shuffle_ps(a1, a1, _MM_SHUFFLE(1, 1, 1, 1)), _mm_shuffle_ps(b1, b1, _MM_SHUFFLE(1, 1, 1, 1))) &&
167 _mm_comieq_ss(_mm_shuffle_ps(a1, a1, _MM_SHUFFLE(2, 2, 2, 2)), _mm_shuffle_ps(b1, b1, _MM_SHUFFLE(2, 2, 2, 2))) &&
168 _mm_comieq_ss(_mm_shuffle_ps(a1, a1, _MM_SHUFFLE(3, 3, 3, 3)), _mm_shuffle_ps(b1, b1, _MM_SHUFFLE(3, 3, 3, 3))));
169}
170
171#if !PX_EMSCRIPTEN
172#if PX_CLANG
173#if PX_LINUX
174#pragma clang diagnostic push
175#pragma clang diagnostic ignored "-Wglobal-constructors"
176#endif
177#endif
178const PX_ALIGN(16, PxF32 gMaskXYZ[4]) = { physx::PxUnionCast<PxF32>(0xffffffff), physx::PxUnionCast<PxF32>(0xffffffff),
179 physx::PxUnionCast<PxF32>(0xffffffff), 0 };
180#if PX_CLANG
181#if PX_LINUX
182#pragma clang diagnostic pop
183#endif
184#endif
185#else
186// emscripten doesn't like the PxUnionCast data structure
187// the following is what windows and xbox does -- using these for emscripten
188const PX_ALIGN(16, PxU32 gMaskXYZ[4]) = { 0xffffffff, 0xffffffff, 0xffffffff, 0 };
189#endif
190}
191
192namespace vecMathTests
193{
194// PT: this function returns an invalid Vec3V (W!=0.0f) just for unit-testing 'isValidVec3V'
195PX_FORCE_INLINE Vec3V getInvalidVec3V()
196{
197 const float f = 1.0f;
198 return _mm_load1_ps(&f);
199}
200
201PX_FORCE_INLINE bool allElementsEqualFloatV(const FloatV a, const FloatV b)
202{
203 ASSERT_ISVALIDFLOATV(a);
204 ASSERT_ISVALIDFLOATV(b);
205 return _mm_comieq_ss(a, b) != 0;
206}
207
208PX_FORCE_INLINE bool allElementsEqualVec3V(const Vec3V a, const Vec3V b)
209{
210 return V3AllEq(a, b) != 0;
211}
212
213PX_FORCE_INLINE bool allElementsEqualVec4V(const Vec4V a, const Vec4V b)
214{
215 return V4AllEq(a, b) != 0;
216}
217
218PX_FORCE_INLINE bool allElementsEqualBoolV(const BoolV a, const BoolV b)
219{
220 return internalUnitSSE2Simd::BAllTrue4_R(VecI32V_IsEq(m128_F2I(a), m128_F2I(b))) != 0;
221}
222
223PX_FORCE_INLINE bool allElementsEqualVecU32V(const VecU32V a, const VecU32V b)
224{
225 return internalUnitSSE2Simd::BAllTrue4_R(V4IsEqU32(a, b)) != 0;
226}
227
228PX_FORCE_INLINE bool allElementsEqualVecI32V(const VecI32V a, const VecI32V b)
229{
230 BoolV c = m128_I2F(_mm_cmpeq_epi32(a, b));
231 return internalUnitSSE2Simd::BAllTrue4_R(c) != 0;
232}
233
234#define VECMATH_AOS_EPSILON (1e-3f)
235
236PX_FORCE_INLINE bool allElementsNearEqualFloatV(const FloatV a, const FloatV b)
237{
238 ASSERT_ISVALIDFLOATV(a);
239 ASSERT_ISVALIDFLOATV(b);
240 const FloatV c = FSub(a, b);
241 const FloatV minError = FLoad(-VECMATH_AOS_EPSILON);
242 const FloatV maxError = FLoad(VECMATH_AOS_EPSILON);
243 return _mm_comigt_ss(c, minError) && _mm_comilt_ss(c, maxError);
244}
245
246PX_FORCE_INLINE bool allElementsNearEqualVec3V(const Vec3V a, const Vec3V b)
247{
248 const Vec3V c = V3Sub(a, b);
249 const Vec3V minError = V3Load(-VECMATH_AOS_EPSILON);
250 const Vec3V maxError = V3Load(VECMATH_AOS_EPSILON);
251 return (_mm_comigt_ss(_mm_shuffle_ps(c, c, _MM_SHUFFLE(0, 0, 0, 0)), minError) &&
252 _mm_comilt_ss(_mm_shuffle_ps(c, c, _MM_SHUFFLE(0, 0, 0, 0)), maxError) &&
253 _mm_comigt_ss(_mm_shuffle_ps(c, c, _MM_SHUFFLE(1, 1, 1, 1)), minError) &&
254 _mm_comilt_ss(_mm_shuffle_ps(c, c, _MM_SHUFFLE(1, 1, 1, 1)), maxError) &&
255 _mm_comigt_ss(_mm_shuffle_ps(c, c, _MM_SHUFFLE(2, 2, 2, 2)), minError) &&
256 _mm_comilt_ss(_mm_shuffle_ps(c, c, _MM_SHUFFLE(2, 2, 2, 2)), maxError));
257}
258
259PX_FORCE_INLINE bool allElementsNearEqualVec4V(const Vec4V a, const Vec4V b)
260{
261 const Vec4V c = V4Sub(a, b);
262 const Vec4V minError = V4Load(-VECMATH_AOS_EPSILON);
263 const Vec4V maxError = V4Load(VECMATH_AOS_EPSILON);
264 return (_mm_comigt_ss(_mm_shuffle_ps(c, c, _MM_SHUFFLE(0, 0, 0, 0)), minError) &&
265 _mm_comilt_ss(_mm_shuffle_ps(c, c, _MM_SHUFFLE(0, 0, 0, 0)), maxError) &&
266 _mm_comigt_ss(_mm_shuffle_ps(c, c, _MM_SHUFFLE(1, 1, 1, 1)), minError) &&
267 _mm_comilt_ss(_mm_shuffle_ps(c, c, _MM_SHUFFLE(1, 1, 1, 1)), maxError) &&
268 _mm_comigt_ss(_mm_shuffle_ps(c, c, _MM_SHUFFLE(2, 2, 2, 2)), minError) &&
269 _mm_comilt_ss(_mm_shuffle_ps(c, c, _MM_SHUFFLE(2, 2, 2, 2)), maxError) &&
270 _mm_comigt_ss(_mm_shuffle_ps(c, c, _MM_SHUFFLE(3, 3, 3, 3)), minError) &&
271 _mm_comilt_ss(_mm_shuffle_ps(c, c, _MM_SHUFFLE(3, 3, 3, 3)), maxError));
272}
273}
274
278
279PX_FORCE_INLINE bool isFiniteFloatV(const FloatV a)
280{
281 PxF32 badNumber =
282 physx::PxUnionCast<PxF32, PxU32>(PX_FPCLASS_SNAN | PX_FPCLASS_QNAN | PX_FPCLASS_NINF | PX_FPCLASS_PINF);
283 const FloatV vBadNum = FLoad(badNumber);
284 const BoolV vMask = BAnd(vBadNum, a);
285 return internalUnitSSE2Simd::FiniteTestEq(vMask, BFFFF()) == 1;
286}
287
288PX_FORCE_INLINE bool isFiniteVec3V(const Vec3V a)
289{
290 PxF32 badNumber =
291 physx::PxUnionCast<PxF32, PxU32>(PX_FPCLASS_SNAN | PX_FPCLASS_QNAN | PX_FPCLASS_NINF | PX_FPCLASS_PINF);
292 const Vec3V vBadNum = V3Load(badNumber);
293 const BoolV vMask = BAnd(BAnd(vBadNum, a), BTTTF());
294 return internalUnitSSE2Simd::FiniteTestEq(vMask, BFFFF()) == 1;
295}
296
297PX_FORCE_INLINE bool isFiniteVec4V(const Vec4V a)
298{
299 /*Vec4V a;
300 PX_ALIGN(16, PxF32 f[4]);
301 F32Array_Aligned_From_Vec4V(a, f);
302 return PxIsFinite(f[0])
303 && PxIsFinite(f[1])
304 && PxIsFinite(f[2])
305 && PxIsFinite(f[3]);*/
306
307 PxF32 badNumber =
308 physx::PxUnionCast<PxF32, PxU32>(PX_FPCLASS_SNAN | PX_FPCLASS_QNAN | PX_FPCLASS_NINF | PX_FPCLASS_PINF);
309 const Vec4V vBadNum = V4Load(badNumber);
310 const BoolV vMask = BAnd(vBadNum, a);
311
312 return internalUnitSSE2Simd::FiniteTestEq(vMask, BFFFF()) == 1;
313}
314
315PX_FORCE_INLINE bool hasZeroElementinFloatV(const FloatV a)
316{
317 ASSERT_ISVALIDFLOATV(a);
318 return _mm_comieq_ss(_mm_shuffle_ps(a, a, _MM_SHUFFLE(0, 0, 0, 0)), FZero()) ? true : false;
319}
320
321PX_FORCE_INLINE bool hasZeroElementInVec3V(const Vec3V a)
322{
323 return (_mm_comieq_ss(_mm_shuffle_ps(a, a, _MM_SHUFFLE(0, 0, 0, 0)), FZero()) ||
324 _mm_comieq_ss(_mm_shuffle_ps(a, a, _MM_SHUFFLE(1, 1, 1, 1)), FZero()) ||
325 _mm_comieq_ss(_mm_shuffle_ps(a, a, _MM_SHUFFLE(2, 2, 2, 2)), FZero()));
326}
327
328PX_FORCE_INLINE bool hasZeroElementInVec4V(const Vec4V a)
329{
330 return (_mm_comieq_ss(_mm_shuffle_ps(a, a, _MM_SHUFFLE(0, 0, 0, 0)), FZero()) ||
331 _mm_comieq_ss(_mm_shuffle_ps(a, a, _MM_SHUFFLE(1, 1, 1, 1)), FZero()) ||
332 _mm_comieq_ss(_mm_shuffle_ps(a, a, _MM_SHUFFLE(2, 2, 2, 2)), FZero()) ||
333 _mm_comieq_ss(_mm_shuffle_ps(a, a, _MM_SHUFFLE(3, 3, 3, 3)), FZero()));
334}
335
339
340PX_FORCE_INLINE FloatV FLoad(const PxF32 f)
341{
342 return _mm_load1_ps(&f);
343}
344
345PX_FORCE_INLINE Vec3V V3Load(const PxF32 f)
346{
347 return _mm_set_ps(0.0f, f, f, f);
348}
349
350PX_FORCE_INLINE Vec4V V4Load(const PxF32 f)
351{
352 return _mm_load1_ps(&f);
353}
354
355PX_FORCE_INLINE BoolV BLoad(const bool f)
356{
357 const PxU32 i = PxU32(-PxI32(f));
358 return _mm_load1_ps(reinterpret_cast<const float*>(&i));
359}
360
361PX_FORCE_INLINE Vec3V V3LoadA(const PxVec3& f)
362{
363 ASSERT_ISALIGNED16(const_cast<PxVec3*>(&f));
364#if !PX_EMSCRIPTEN
365 return _mm_and_ps(reinterpret_cast<const Vec3V&>(f), V4LoadA(internalUnitSSE2Simd::gMaskXYZ));
366#else
367 return _mm_and_ps((Vec3V&)f, (VecI32V&)internalUnitSSE2Simd::gMaskXYZ);
368#endif
369}
370
371PX_FORCE_INLINE Vec3V V3LoadU(const PxVec3& f)
372{
373 return _mm_set_ps(0.0f, f.z, f.y, f.x);
374}
375
376PX_FORCE_INLINE Vec3V V3LoadUnsafeA(const PxVec3& f)
377{
378 ASSERT_ISALIGNED16(const_cast<PxVec3*>(&f));
379 return _mm_set_ps(0.0f, f.z, f.y, f.x);
380}
381
382PX_FORCE_INLINE Vec3V V3LoadA(const PxF32* const f)
383{
384 ASSERT_ISALIGNED16(const_cast<PxF32*>(f));
385#if !PX_EMSCRIPTEN
386 return _mm_and_ps(V4LoadA(f), V4LoadA(internalUnitSSE2Simd::gMaskXYZ));
387#else
388 return _mm_and_ps((Vec3V&)*f, (VecI32V&)internalUnitSSE2Simd::gMaskXYZ);
389#endif
390}
391
392PX_FORCE_INLINE Vec3V V3LoadU(const PxF32* const i)
393{
394 return _mm_set_ps(0.0f, i[2], i[1], i[0]);
395}
396
397PX_FORCE_INLINE Vec3V Vec3V_From_Vec4V(Vec4V v)
398{
399 return V4ClearW(v);
400}
401
402PX_FORCE_INLINE Vec3V Vec3V_From_Vec4V_WUndefined(const Vec4V v)
403{
404 return v;
405}
406
407PX_FORCE_INLINE Vec4V Vec4V_From_Vec3V(Vec3V f)
408{
409 ASSERT_ISVALIDVEC3V(f);
410 return f; // ok if it is implemented as the same type.
411}
412
413PX_FORCE_INLINE Vec4V Vec4V_From_PxVec3_WUndefined(const PxVec3& f)
414{
415 return _mm_set_ps(0.0f, f.z, f.y, f.x);
416}
417
418PX_FORCE_INLINE Vec4V Vec4V_From_FloatV(FloatV f)
419{
420 return f;
421}
422
423PX_FORCE_INLINE Vec3V Vec3V_From_FloatV(FloatV f)
424{
425 ASSERT_ISVALIDFLOATV(f);
426 return Vec3V_From_Vec4V(Vec4V_From_FloatV(f));
427}
428
429PX_FORCE_INLINE Vec3V Vec3V_From_FloatV_WUndefined(FloatV f)
430{
431 ASSERT_ISVALIDVEC3V(f);
432 return Vec3V_From_Vec4V_WUndefined(Vec4V_From_FloatV(f));
433}
434
435PX_FORCE_INLINE Mat33V Mat33V_From_PxMat33(const PxMat33& m)
436{
437 return Mat33V(V3LoadU(m.column0), V3LoadU(m.column1), V3LoadU(m.column2));
438}
439
440PX_FORCE_INLINE void PxMat33_From_Mat33V(const Mat33V& m, PxMat33& out)
441{
442 V3StoreU(m.col0, out.column0);
443 V3StoreU(m.col1, out.column1);
444 V3StoreU(m.col2, out.column2);
445}
446
447PX_FORCE_INLINE Vec4V V4LoadA(const PxF32* const f)
448{
449 ASSERT_ISALIGNED16(const_cast<PxF32*>(f));
450 return _mm_load_ps(f);
451}
452
453PX_FORCE_INLINE void V4StoreA(Vec4V a, PxF32* f)
454{
455 ASSERT_ISALIGNED16(f);
456 _mm_store_ps(f, a);
457}
458
459PX_FORCE_INLINE void V4StoreU(const Vec4V a, PxF32* f)
460{
461 _mm_storeu_ps(f, a);
462}
463
464PX_FORCE_INLINE void BStoreA(const BoolV a, PxU32* f)
465{
466 ASSERT_ISALIGNED16(f);
467 _mm_store_ps(reinterpret_cast<PxF32*>(f), a);
468}
469
470PX_FORCE_INLINE void U4StoreA(const VecU32V uv, PxU32* u)
471{
472 ASSERT_ISALIGNED16(u);
473 _mm_store_ps(reinterpret_cast<float*>(u), uv);
474}
475
476PX_FORCE_INLINE VecI32V I4LoadXYZW(const PxI32& x, const PxI32& y, const PxI32& z, const PxI32& w)
477{
478 return _mm_set_epi32(w, z, y, x);
479}
480
481PX_FORCE_INLINE void I4StoreA(const VecI32V iv, PxI32* i)
482{
483 ASSERT_ISALIGNED16(i);
484 _mm_store_ps(reinterpret_cast<float*>(i), m128_I2F(iv));
485}
486
487PX_FORCE_INLINE Vec4V V4LoadU(const PxF32* const f)
488{
489 return _mm_loadu_ps(f);
490}
491
492PX_FORCE_INLINE BoolV BLoad(const bool* const f)
493{
494 const PX_ALIGN(16, PxI32) b[4] = { -PxI32(f[0]), -PxI32(f[1]), -PxI32(f[2]), -PxI32(f[3]) };
495 return _mm_load_ps(reinterpret_cast<const float*>(&b));
496}
497
498PX_FORCE_INLINE void FStore(const FloatV a, PxF32* PX_RESTRICT f)
499{
500 ASSERT_ISVALIDFLOATV(a);
501 _mm_store_ss(f, a);
502}
503
504PX_FORCE_INLINE void V3StoreA(const Vec3V a, PxVec3& f)
505{
506 ASSERT_ISALIGNED16(&f);
507 PX_ALIGN(16, PxF32) f2[4];
508 _mm_store_ps(f2, a);
509 f = PxVec3(f2[0], f2[1], f2[2]);
510}
511
512PX_FORCE_INLINE void V3StoreU(const Vec3V a, PxVec3& f)
513{
514 PX_ALIGN(16, PxF32) f2[4];
515 _mm_store_ps(f2, a);
516 f = PxVec3(f2[0], f2[1], f2[2]);
517}
518
519PX_FORCE_INLINE void Store_From_BoolV(const BoolV b, PxU32* b2)
520{
521 _mm_store_ss(reinterpret_cast<PxF32*>(b2), b);
522}
523
524PX_FORCE_INLINE VecU32V U4Load(const PxU32 i)
525{
526 return _mm_load1_ps(reinterpret_cast<const PxF32*>(&i));
527}
528
529PX_FORCE_INLINE VecU32V U4LoadU(const PxU32* i)
530{
531 return _mm_loadu_ps(reinterpret_cast<const PxF32*>(i));
532}
533
534PX_FORCE_INLINE VecU32V U4LoadA(const PxU32* i)
535{
536 ASSERT_ISALIGNED16(const_cast<PxU32*>(i));
537 return _mm_load_ps(reinterpret_cast<const PxF32*>(i));
538}
539
541// FLOATV
543
544PX_FORCE_INLINE FloatV FZero()
545{
546 return FLoad(0.0f);
547}
548
549PX_FORCE_INLINE FloatV FOne()
550{
551 return FLoad(1.0f);
552}
553
554PX_FORCE_INLINE FloatV FHalf()
555{
556 return FLoad(0.5f);
557}
558
559PX_FORCE_INLINE FloatV FEps()
560{
561 return FLoad(PX_EPS_REAL);
562}
563
564PX_FORCE_INLINE FloatV FEps6()
565{
566 return FLoad(1e-6f);
567}
568
569PX_FORCE_INLINE FloatV FMax()
570{
571 return FLoad(PX_MAX_REAL);
572}
573
574PX_FORCE_INLINE FloatV FNegMax()
575{
576 return FLoad(-PX_MAX_REAL);
577}
578
579PX_FORCE_INLINE FloatV IZero()
580{
581 const PxU32 zero = 0;
582 return _mm_load1_ps(reinterpret_cast<const PxF32*>(&zero));
583}
584
585PX_FORCE_INLINE FloatV IOne()
586{
587 const PxU32 one = 1;
588 return _mm_load1_ps(reinterpret_cast<const PxF32*>(&one));
589}
590
591PX_FORCE_INLINE FloatV ITwo()
592{
593 const PxU32 two = 2;
594 return _mm_load1_ps(reinterpret_cast<const PxF32*>(&two));
595}
596
597PX_FORCE_INLINE FloatV IThree()
598{
599 const PxU32 three = 3;
600 return _mm_load1_ps(reinterpret_cast<const PxF32*>(&three));
601}
602
603PX_FORCE_INLINE FloatV IFour()
604{
605 PxU32 four = 4;
606 return _mm_load1_ps(reinterpret_cast<const PxF32*>(&four));
607}
608
609PX_FORCE_INLINE FloatV FNeg(const FloatV f)
610{
611 ASSERT_ISVALIDFLOATV(f);
612 return _mm_sub_ps(_mm_setzero_ps(), f);
613}
614
615PX_FORCE_INLINE FloatV FAdd(const FloatV a, const FloatV b)
616{
617 ASSERT_ISVALIDFLOATV(a);
618 ASSERT_ISVALIDFLOATV(b);
619/*
620 if(!isValidFloatV(a))
621 {
622assert(false);
623 }
624 if(!isValidFloatV(b))
625 {
626assert(false);
627 }
628*/
629 return _mm_add_ps(a, b);
630}
631
632PX_FORCE_INLINE FloatV FSub(const FloatV a, const FloatV b)
633{
634 ASSERT_ISVALIDFLOATV(a);
635 ASSERT_ISVALIDFLOATV(b);
636 return _mm_sub_ps(a, b);
637}
638
639PX_FORCE_INLINE FloatV FMul(const FloatV a, const FloatV b)
640{
641 ASSERT_ISVALIDFLOATV(a);
642 ASSERT_ISVALIDFLOATV(b);
643 return _mm_mul_ps(a, b);
644}
645
646PX_FORCE_INLINE FloatV FDiv(const FloatV a, const FloatV b)
647{
648 ASSERT_ISVALIDFLOATV(a);
649 ASSERT_ISVALIDFLOATV(b);
650 return _mm_div_ps(a, b);
651}
652
653PX_FORCE_INLINE FloatV FDivFast(const FloatV a, const FloatV b)
654{
655 ASSERT_ISVALIDFLOATV(a);
656 ASSERT_ISVALIDFLOATV(b);
657 return _mm_mul_ps(a, _mm_rcp_ps(b));
658}
659
660PX_FORCE_INLINE FloatV FRecip(const FloatV a)
661{
662 ASSERT_ISVALIDFLOATV(a);
663 return _mm_div_ps(FOne(), a);
664}
665
666PX_FORCE_INLINE FloatV FRecipFast(const FloatV a)
667{
668 ASSERT_ISVALIDFLOATV(a);
669 return _mm_rcp_ps(a);
670}
671
672PX_FORCE_INLINE FloatV FRsqrt(const FloatV a)
673{
674 ASSERT_ISVALIDFLOATV(a);
675 return _mm_div_ps(FOne(), _mm_sqrt_ps(a));
676}
677
678PX_FORCE_INLINE FloatV FSqrt(const FloatV a)
679{
680 ASSERT_ISVALIDFLOATV(a);
681 return _mm_sqrt_ps(a);
682}
683
684PX_FORCE_INLINE FloatV FRsqrtFast(const FloatV a)
685{
686 ASSERT_ISVALIDFLOATV(a);
687 return _mm_rsqrt_ps(a);
688}
689
690PX_FORCE_INLINE FloatV FScaleAdd(const FloatV a, const FloatV b, const FloatV c)
691{
692 ASSERT_ISVALIDFLOATV(a);
693 ASSERT_ISVALIDFLOATV(b);
694 ASSERT_ISVALIDFLOATV(c);
695 return FAdd(FMul(a, b), c);
696}
697
698PX_FORCE_INLINE FloatV FNegScaleSub(const FloatV a, const FloatV b, const FloatV c)
699{
700 ASSERT_ISVALIDFLOATV(a);
701 ASSERT_ISVALIDFLOATV(b);
702 ASSERT_ISVALIDFLOATV(c);
703 return FSub(c, FMul(a, b));
704}
705
706PX_FORCE_INLINE FloatV FAbs(const FloatV a)
707{
708 ASSERT_ISVALIDFLOATV(a);
709 PX_ALIGN(16, const PxU32) absMask[4] = { 0x7fFFffFF, 0x7fFFffFF, 0x7fFFffFF, 0x7fFFffFF };
710 return _mm_and_ps(a, _mm_load_ps(reinterpret_cast<const PxF32*>(absMask)));
711}
712
713PX_FORCE_INLINE FloatV FSel(const BoolV c, const FloatV a, const FloatV b)
714{
715 PX_ASSERT(vecMathTests::allElementsEqualBoolV(c,BTTTT()) ||
716 vecMathTests::allElementsEqualBoolV(c,BFFFF()));
717 ASSERT_ISVALIDFLOATV(_mm_or_ps(_mm_andnot_ps(c, b), _mm_and_ps(c, a)));
718 return _mm_or_ps(_mm_andnot_ps(c, b), _mm_and_ps(c, a));
719}
720
721PX_FORCE_INLINE BoolV FIsGrtr(const FloatV a, const FloatV b)
722{
723 ASSERT_ISVALIDFLOATV(a);
724 ASSERT_ISVALIDFLOATV(b);
725 return _mm_cmpgt_ps(a, b);
726}
727
728PX_FORCE_INLINE BoolV FIsGrtrOrEq(const FloatV a, const FloatV b)
729{
730 ASSERT_ISVALIDFLOATV(a);
731 ASSERT_ISVALIDFLOATV(b);
732 return _mm_cmpge_ps(a, b);
733}
734
735PX_FORCE_INLINE BoolV FIsEq(const FloatV a, const FloatV b)
736{
737 ASSERT_ISVALIDFLOATV(a);
738 ASSERT_ISVALIDFLOATV(b);
739 return _mm_cmpeq_ps(a, b);
740}
741
742PX_FORCE_INLINE FloatV FMax(const FloatV a, const FloatV b)
743{
744 ASSERT_ISVALIDFLOATV(a);
745 ASSERT_ISVALIDFLOATV(b);
746 return _mm_max_ps(a, b);
747}
748
749PX_FORCE_INLINE FloatV FMin(const FloatV a, const FloatV b)
750{
751 ASSERT_ISVALIDFLOATV(a);
752 ASSERT_ISVALIDFLOATV(b);
753 return _mm_min_ps(a, b);
754}
755
756PX_FORCE_INLINE FloatV FClamp(const FloatV a, const FloatV minV, const FloatV maxV)
757{
758 ASSERT_ISVALIDFLOATV(minV);
759 ASSERT_ISVALIDFLOATV(maxV);
760 return _mm_max_ps(_mm_min_ps(a, maxV), minV);
761}
762
763PX_FORCE_INLINE PxU32 FAllGrtr(const FloatV a, const FloatV b)
764{
765 ASSERT_ISVALIDFLOATV(a);
766 ASSERT_ISVALIDFLOATV(b);
767 return PxU32(_mm_comigt_ss(a, b));
768}
769
770PX_FORCE_INLINE PxU32 FAllGrtrOrEq(const FloatV a, const FloatV b)
771{
772 ASSERT_ISVALIDFLOATV(a);
773 ASSERT_ISVALIDFLOATV(b);
774 return PxU32(_mm_comige_ss(a, b));
775}
776
777PX_FORCE_INLINE PxU32 FAllEq(const FloatV a, const FloatV b)
778{
779 ASSERT_ISVALIDFLOATV(a);
780 ASSERT_ISVALIDFLOATV(b);
781 return PxU32(_mm_comieq_ss(a, b));
782}
783
784PX_FORCE_INLINE FloatV FRound(const FloatV a)
785{
786 ASSERT_ISVALIDFLOATV(a);
787#ifdef __SSE4_2__
788 return _mm_round_ps(a, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC);
789#else
790 // return _mm_round_ps(a, 0x0);
791 const FloatV half = FLoad(0.5f);
792 const __m128 signBit = _mm_cvtepi32_ps(_mm_srli_epi32(_mm_cvtps_epi32(a), 31));
793 const FloatV aRound = FSub(FAdd(a, half), signBit);
794 __m128i tmp = _mm_cvttps_epi32(aRound);
795 return _mm_cvtepi32_ps(tmp);
796#endif
797}
798
799PX_FORCE_INLINE FloatV FSin(const FloatV a)
800{
801 ASSERT_ISVALIDFLOATV(a);
802
803 // Modulo the range of the given angles such that -XM_2PI <= Angles < XM_2PI
804 const FloatV recipTwoPi = V4LoadA(g_PXReciprocalTwoPi.f);
805 const FloatV twoPi = V4LoadA(g_PXTwoPi.f);
806 const FloatV tmp = FMul(a, recipTwoPi);
807 const FloatV b = FRound(tmp);
808 const FloatV V1 = FNegScaleSub(twoPi, b, a);
809
810 // sin(V) ~= V - V^3 / 3! + V^5 / 5! - V^7 / 7! + V^9 / 9! - V^11 / 11! + V^13 / 13! -
811 // V^15 / 15! + V^17 / 17! - V^19 / 19! + V^21 / 21! - V^23 / 23! (for -PI <= V < PI)
812 const FloatV V2 = FMul(V1, V1);
813 const FloatV V3 = FMul(V2, V1);
814 const FloatV V5 = FMul(V3, V2);
815 const FloatV V7 = FMul(V5, V2);
816 const FloatV V9 = FMul(V7, V2);
817 const FloatV V11 = FMul(V9, V2);
818 const FloatV V13 = FMul(V11, V2);
819 const FloatV V15 = FMul(V13, V2);
820 const FloatV V17 = FMul(V15, V2);
821 const FloatV V19 = FMul(V17, V2);
822 const FloatV V21 = FMul(V19, V2);
823 const FloatV V23 = FMul(V21, V2);
824
825 const Vec4V sinCoefficients0 = V4LoadA(g_PXSinCoefficients0.f);
826 const Vec4V sinCoefficients1 = V4LoadA(g_PXSinCoefficients1.f);
827 const Vec4V sinCoefficients2 = V4LoadA(g_PXSinCoefficients2.f);
828
829 const FloatV S1 = V4GetY(sinCoefficients0);
830 const FloatV S2 = V4GetZ(sinCoefficients0);
831 const FloatV S3 = V4GetW(sinCoefficients0);
832 const FloatV S4 = V4GetX(sinCoefficients1);
833 const FloatV S5 = V4GetY(sinCoefficients1);
834 const FloatV S6 = V4GetZ(sinCoefficients1);
835 const FloatV S7 = V4GetW(sinCoefficients1);
836 const FloatV S8 = V4GetX(sinCoefficients2);
837 const FloatV S9 = V4GetY(sinCoefficients2);
838 const FloatV S10 = V4GetZ(sinCoefficients2);
839 const FloatV S11 = V4GetW(sinCoefficients2);
840
841 FloatV Result;
842 Result = FScaleAdd(S1, V3, V1);
843 Result = FScaleAdd(S2, V5, Result);
844 Result = FScaleAdd(S3, V7, Result);
845 Result = FScaleAdd(S4, V9, Result);
846 Result = FScaleAdd(S5, V11, Result);
847 Result = FScaleAdd(S6, V13, Result);
848 Result = FScaleAdd(S7, V15, Result);
849 Result = FScaleAdd(S8, V17, Result);
850 Result = FScaleAdd(S9, V19, Result);
851 Result = FScaleAdd(S10, V21, Result);
852 Result = FScaleAdd(S11, V23, Result);
853
854 return Result;
855}
856
857PX_FORCE_INLINE FloatV FCos(const FloatV a)
858{
859 ASSERT_ISVALIDFLOATV(a);
860
861 // Modulo the range of the given angles such that -XM_2PI <= Angles < XM_2PI
862 const FloatV recipTwoPi = V4LoadA(g_PXReciprocalTwoPi.f);
863 const FloatV twoPi = V4LoadA(g_PXTwoPi.f);
864 const FloatV tmp = FMul(a, recipTwoPi);
865 const FloatV b = FRound(tmp);
866 const FloatV V1 = FNegScaleSub(twoPi, b, a);
867
868 // cos(V) ~= 1 - V^2 / 2! + V^4 / 4! - V^6 / 6! + V^8 / 8! - V^10 / 10! + V^12 / 12! -
869 // V^14 / 14! + V^16 / 16! - V^18 / 18! + V^20 / 20! - V^22 / 22! (for -PI <= V < PI)
870 const FloatV V2 = FMul(V1, V1);
871 const FloatV V4 = FMul(V2, V2);
872 const FloatV V6 = FMul(V4, V2);
873 const FloatV V8 = FMul(V4, V4);
874 const FloatV V10 = FMul(V6, V4);
875 const FloatV V12 = FMul(V6, V6);
876 const FloatV V14 = FMul(V8, V6);
877 const FloatV V16 = FMul(V8, V8);
878 const FloatV V18 = FMul(V10, V8);
879 const FloatV V20 = FMul(V10, V10);
880 const FloatV V22 = FMul(V12, V10);
881
882 const Vec4V cosCoefficients0 = V4LoadA(g_PXCosCoefficients0.f);
883 const Vec4V cosCoefficients1 = V4LoadA(g_PXCosCoefficients1.f);
884 const Vec4V cosCoefficients2 = V4LoadA(g_PXCosCoefficients2.f);
885
886 const FloatV C1 = V4GetY(cosCoefficients0);
887 const FloatV C2 = V4GetZ(cosCoefficients0);
888 const FloatV C3 = V4GetW(cosCoefficients0);
889 const FloatV C4 = V4GetX(cosCoefficients1);
890 const FloatV C5 = V4GetY(cosCoefficients1);
891 const FloatV C6 = V4GetZ(cosCoefficients1);
892 const FloatV C7 = V4GetW(cosCoefficients1);
893 const FloatV C8 = V4GetX(cosCoefficients2);
894 const FloatV C9 = V4GetY(cosCoefficients2);
895 const FloatV C10 = V4GetZ(cosCoefficients2);
896 const FloatV C11 = V4GetW(cosCoefficients2);
897
898 FloatV Result;
899 Result = FScaleAdd(C1, V2, V4One());
900 Result = FScaleAdd(C2, V4, Result);
901 Result = FScaleAdd(C3, V6, Result);
902 Result = FScaleAdd(C4, V8, Result);
903 Result = FScaleAdd(C5, V10, Result);
904 Result = FScaleAdd(C6, V12, Result);
905 Result = FScaleAdd(C7, V14, Result);
906 Result = FScaleAdd(C8, V16, Result);
907 Result = FScaleAdd(C9, V18, Result);
908 Result = FScaleAdd(C10, V20, Result);
909 Result = FScaleAdd(C11, V22, Result);
910
911 return Result;
912}
913
914PX_FORCE_INLINE PxU32 FOutOfBounds(const FloatV a, const FloatV min, const FloatV max)
915{
916 ASSERT_ISVALIDFLOATV(a);
917 ASSERT_ISVALIDFLOATV(min);
918 ASSERT_ISVALIDFLOATV(max);
919 const BoolV c = BOr(FIsGrtr(a, max), FIsGrtr(min, a));
920 return !BAllEqFFFF(c);
921}
922
923PX_FORCE_INLINE PxU32 FInBounds(const FloatV a, const FloatV min, const FloatV max)
924{
925 ASSERT_ISVALIDFLOATV(a);
926 ASSERT_ISVALIDFLOATV(min);
927 ASSERT_ISVALIDFLOATV(max)
928 const BoolV c = BAnd(FIsGrtrOrEq(a, min), FIsGrtrOrEq(max, a));
929 return BAllEqTTTT(c);
930}
931
932PX_FORCE_INLINE PxU32 FOutOfBounds(const FloatV a, const FloatV bounds)
933{
934 ASSERT_ISVALIDFLOATV(a);
935 ASSERT_ISVALIDFLOATV(bounds);
936 return FOutOfBounds(a, FNeg(bounds), bounds);
937}
938
939PX_FORCE_INLINE PxU32 FInBounds(const FloatV a, const FloatV bounds)
940{
941 ASSERT_ISVALIDFLOATV(a);
942 ASSERT_ISVALIDFLOATV(bounds);
943 return FInBounds(a, FNeg(bounds), bounds);
944}
945
947// VEC3V
949
950PX_FORCE_INLINE Vec3V V3Splat(const FloatV f)
951{
952 ASSERT_ISVALIDFLOATV(f);
953 const __m128 zero = FZero();
954 const __m128 fff0 = _mm_move_ss(f, zero);
955 return _mm_shuffle_ps(fff0, fff0, _MM_SHUFFLE(0, 1, 2, 3));
956}
957
958PX_FORCE_INLINE Vec3V V3Merge(const FloatVArg x, const FloatVArg y, const FloatVArg z)
959{
960 ASSERT_ISVALIDFLOATV(x);
961 ASSERT_ISVALIDFLOATV(y);
962 ASSERT_ISVALIDFLOATV(z);
963 // static on zero causes compiler crash on x64 debug_opt
964 const __m128 zero = FZero();
965 const __m128 xy = _mm_move_ss(x, y);
966 const __m128 z0 = _mm_move_ss(zero, z);
967
968 return _mm_shuffle_ps(xy, z0, _MM_SHUFFLE(1, 0, 0, 1));
969}
970
971PX_FORCE_INLINE Vec3V V3UnitX()
972{
973 const PX_ALIGN(16, PxF32) x[4] = { 1.0f, 0.0f, 0.0f, 0.0f };
974 const __m128 x128 = _mm_load_ps(x);
975 return x128;
976}
977
978PX_FORCE_INLINE Vec3V V3UnitY()
979{
980 const PX_ALIGN(16, PxF32) y[4] = { 0.0f, 1.0f, 0.0f, 0.0f };
981 const __m128 y128 = _mm_load_ps(y);
982 return y128;
983}
984
985PX_FORCE_INLINE Vec3V V3UnitZ()
986{
987 const PX_ALIGN(16, PxF32) z[4] = { 0.0f, 0.0f, 1.0f, 0.0f };
988 const __m128 z128 = _mm_load_ps(z);
989 return z128;
990}
991
992PX_FORCE_INLINE FloatV V3GetX(const Vec3V f)
993{
994 ASSERT_ISVALIDVEC3V(f);
995 return _mm_shuffle_ps(f, f, _MM_SHUFFLE(0, 0, 0, 0));
996}
997
998PX_FORCE_INLINE FloatV V3GetY(const Vec3V f)
999{
1000 ASSERT_ISVALIDVEC3V(f)
1001 return _mm_shuffle_ps(f, f, _MM_SHUFFLE(1, 1, 1, 1));
1002}
1003
1004PX_FORCE_INLINE FloatV V3GetZ(const Vec3V f)
1005{
1006 ASSERT_ISVALIDVEC3V(f);
1007 return _mm_shuffle_ps(f, f, _MM_SHUFFLE(2, 2, 2, 2));
1008}
1009
1010PX_FORCE_INLINE Vec3V V3SetX(const Vec3V v, const FloatV f)
1011{
1012 ASSERT_ISVALIDVEC3V(v);
1013 ASSERT_ISVALIDFLOATV(f);
1014 return V4Sel(BFTTT(), v, f);
1015}
1016
1017PX_FORCE_INLINE Vec3V V3SetY(const Vec3V v, const FloatV f)
1018{
1019 ASSERT_ISVALIDVEC3V(v);
1020 ASSERT_ISVALIDFLOATV(f);
1021 return V4Sel(BTFTT(), v, f);
1022}
1023
1024PX_FORCE_INLINE Vec3V V3SetZ(const Vec3V v, const FloatV f)
1025{
1026 ASSERT_ISVALIDVEC3V(v);
1027 ASSERT_ISVALIDFLOATV(f);
1028 return V4Sel(BTTFT(), v, f);
1029}
1030
1031PX_FORCE_INLINE Vec3V V3ColX(const Vec3V a, const Vec3V b, const Vec3V c)
1032{
1033 ASSERT_ISVALIDVEC3V(a);
1034 ASSERT_ISVALIDVEC3V(b);
1035 ASSERT_ISVALIDVEC3V(c);
1036 Vec3V r = _mm_shuffle_ps(a, c, _MM_SHUFFLE(3, 0, 3, 0));
1037 return V3SetY(r, V3GetX(b));
1038}
1039
1040PX_FORCE_INLINE Vec3V V3ColY(const Vec3V a, const Vec3V b, const Vec3V c)
1041{
1042 ASSERT_ISVALIDVEC3V(a);
1043 ASSERT_ISVALIDVEC3V(b);
1044 ASSERT_ISVALIDVEC3V(c)
1045 Vec3V r = _mm_shuffle_ps(a, c, _MM_SHUFFLE(3, 1, 3, 1));
1046 return V3SetY(r, V3GetY(b));
1047}
1048
1049PX_FORCE_INLINE Vec3V V3ColZ(const Vec3V a, const Vec3V b, const Vec3V c)
1050{
1051 ASSERT_ISVALIDVEC3V(a);
1052 ASSERT_ISVALIDVEC3V(b);
1053 ASSERT_ISVALIDVEC3V(c);
1054 Vec3V r = _mm_shuffle_ps(a, c, _MM_SHUFFLE(3, 2, 3, 2));
1055 return V3SetY(r, V3GetZ(b));
1056}
1057
1058PX_FORCE_INLINE Vec3V V3Zero()
1059{
1060 return V3Load(0.0f);
1061}
1062
1063PX_FORCE_INLINE Vec3V V3Eps()
1064{
1065 return V3Load(PX_EPS_REAL);
1066}
1067PX_FORCE_INLINE Vec3V V3One()
1068{
1069 return V3Load(1.0f);
1070}
1071
1072PX_FORCE_INLINE Vec3V V3Neg(const Vec3V f)
1073{
1074 ASSERT_ISVALIDVEC3V(f);
1075 return _mm_sub_ps(_mm_setzero_ps(), f);
1076}
1077
1078PX_FORCE_INLINE Vec3V V3Add(const Vec3V a, const Vec3V b)
1079{
1080 ASSERT_ISVALIDVEC3V(a);
1081 ASSERT_ISVALIDVEC3V(b);
1082 return _mm_add_ps(a, b);
1083}
1084
1085PX_FORCE_INLINE Vec3V V3Sub(const Vec3V a, const Vec3V b)
1086{
1087 ASSERT_ISVALIDVEC3V(a);
1088 ASSERT_ISVALIDVEC3V(b);
1089 return _mm_sub_ps(a, b);
1090}
1091
1092PX_FORCE_INLINE Vec3V V3Scale(const Vec3V a, const FloatV b)
1093{
1094 ASSERT_ISVALIDVEC3V(a);
1095 ASSERT_ISVALIDFLOATV(b);
1096 return _mm_mul_ps(a, b);
1097}
1098
1099PX_FORCE_INLINE Vec3V V3Mul(const Vec3V a, const Vec3V b)
1100{
1101 ASSERT_ISVALIDVEC3V(a);
1102 ASSERT_ISVALIDVEC3V(b);
1103 return _mm_mul_ps(a, b);
1104}
1105
1106PX_FORCE_INLINE Vec3V V3ScaleInv(const Vec3V a, const FloatV b)
1107{
1108 ASSERT_ISVALIDVEC3V(a);
1109 ASSERT_ISVALIDFLOATV(b);
1110 return _mm_div_ps(a, b);
1111}
1112
1113PX_FORCE_INLINE Vec3V V3Div(const Vec3V a, const Vec3V b)
1114{
1115 ASSERT_ISVALIDVEC3V(a);
1116 ASSERT_ISVALIDVEC3V(b);
1117 return V4ClearW(_mm_div_ps(a, b));
1118}
1119
1120PX_FORCE_INLINE Vec3V V3ScaleInvFast(const Vec3V a, const FloatV b)
1121{
1122 ASSERT_ISVALIDVEC3V(a);
1123 ASSERT_ISVALIDFLOATV(b);
1124 return _mm_mul_ps(a, _mm_rcp_ps(b));
1125}
1126
1127PX_FORCE_INLINE Vec3V V3DivFast(const Vec3V a, const Vec3V b)
1128{
1129 ASSERT_ISVALIDVEC3V(a);
1130 ASSERT_ISVALIDVEC3V(b);
1131 return V4ClearW(_mm_mul_ps(a, _mm_rcp_ps(b)));
1132}
1133
1134PX_FORCE_INLINE Vec3V V3Recip(const Vec3V a)
1135{
1136 ASSERT_ISVALIDVEC3V(a);
1137 const __m128 zero = V3Zero();
1138 const __m128 tttf = BTTTF();
1139 const __m128 recipA = _mm_div_ps(V3One(), a);
1140 return V4Sel(tttf, recipA, zero);
1141}
1142
1143PX_FORCE_INLINE Vec3V V3RecipFast(const Vec3V a)
1144{
1145 ASSERT_ISVALIDVEC3V(a);
1146 const __m128 zero = V3Zero();
1147 const __m128 tttf = BTTTF();
1148 const __m128 recipA = _mm_rcp_ps(a);
1149 return V4Sel(tttf, recipA, zero);
1150}
1151
1152PX_FORCE_INLINE Vec3V V3Rsqrt(const Vec3V a)
1153{
1154 ASSERT_ISVALIDVEC3V(a);
1155 const __m128 zero = V3Zero();
1156 const __m128 tttf = BTTTF();
1157 const __m128 recipA = _mm_div_ps(V3One(), _mm_sqrt_ps(a));
1158 return V4Sel(tttf, recipA, zero);
1159}
1160
1161PX_FORCE_INLINE Vec3V V3RsqrtFast(const Vec3V a)
1162{
1163 ASSERT_ISVALIDVEC3V(a);
1164 const __m128 zero = V3Zero();
1165 const __m128 tttf = BTTTF();
1166 const __m128 recipA = _mm_rsqrt_ps(a);
1167 return V4Sel(tttf, recipA, zero);
1168}
1169
1170PX_FORCE_INLINE Vec3V V3ScaleAdd(const Vec3V a, const FloatV b, const Vec3V c)
1171{
1172 ASSERT_ISVALIDVEC3V(a);
1173 ASSERT_ISVALIDFLOATV(b);
1174 ASSERT_ISVALIDVEC3V(c);
1175 return V3Add(V3Scale(a, b), c);
1176}
1177
1178PX_FORCE_INLINE Vec3V V3NegScaleSub(const Vec3V a, const FloatV b, const Vec3V c)
1179{
1180 ASSERT_ISVALIDVEC3V(a);
1181 ASSERT_ISVALIDFLOATV(b);
1182 ASSERT_ISVALIDVEC3V(c);
1183 return V3Sub(c, V3Scale(a, b));
1184}
1185
1186PX_FORCE_INLINE Vec3V V3MulAdd(const Vec3V a, const Vec3V b, const Vec3V c)
1187{
1188 ASSERT_ISVALIDVEC3V(a);
1189 ASSERT_ISVALIDVEC3V(b);
1190 ASSERT_ISVALIDVEC3V(c);
1191 return V3Add(V3Mul(a, b), c);
1192}
1193
1194PX_FORCE_INLINE Vec3V V3NegMulSub(const Vec3V a, const Vec3V b, const Vec3V c)
1195{
1196 ASSERT_ISVALIDVEC3V(a);
1197 ASSERT_ISVALIDVEC3V(b);
1198 ASSERT_ISVALIDVEC3V(c);
1199 return V3Sub(c, V3Mul(a, b));
1200}
1201
1202PX_FORCE_INLINE Vec3V V3Abs(const Vec3V a)
1203{
1204 ASSERT_ISVALIDVEC3V(a);
1205 return V3Max(a, V3Neg(a));
1206}
1207
1208PX_FORCE_INLINE FloatV V3Dot(const Vec3V a, const Vec3V b)
1209{
1210 ASSERT_ISVALIDVEC3V(a);
1211 ASSERT_ISVALIDVEC3V(b);
1212#ifdef __SSE4_2__
1213 return _mm_dp_ps(a, b, 0x7f);
1214#else
1215 const __m128 t0 = _mm_mul_ps(a, b); // aw*bw | az*bz | ay*by | ax*bx
1216 const __m128 t1 = _mm_shuffle_ps(t0, t0, _MM_SHUFFLE(1,0,3,2)); // ay*by | ax*bx | aw*bw | az*bz
1217 const __m128 t2 = _mm_add_ps(t0, t1); // ay*by + aw*bw | ax*bx + az*bz | aw*bw + ay*by | az*bz + ax*bx
1218 const __m128 t3 = _mm_shuffle_ps(t2, t2, _MM_SHUFFLE(2,3,0,1)); // ax*bx + az*bz | ay*by + aw*bw | az*bz + ax*bx | aw*bw + ay*by
1219 return _mm_add_ps(t3, t2); // ax*bx + az*bz + ay*by + aw*bw
1220 // ay*by + aw*bw + ax*bx + az*bz
1221 // az*bz + ax*bx + aw*bw + ay*by
1222 // aw*bw + ay*by + az*bz + ax*bx
1223#endif
1224}
1225
1226PX_FORCE_INLINE Vec3V V3Cross(const Vec3V a, const Vec3V b)
1227{
1228 ASSERT_ISVALIDVEC3V(a);
1229 ASSERT_ISVALIDVEC3V(b);
1230 const __m128 r1 = _mm_shuffle_ps(a, a, _MM_SHUFFLE(3, 1, 0, 2)); // z,x,y,w
1231 const __m128 r2 = _mm_shuffle_ps(b, b, _MM_SHUFFLE(3, 0, 2, 1)); // y,z,x,w
1232 const __m128 l1 = _mm_shuffle_ps(a, a, _MM_SHUFFLE(3, 0, 2, 1)); // y,z,x,w
1233 const __m128 l2 = _mm_shuffle_ps(b, b, _MM_SHUFFLE(3, 1, 0, 2)); // z,x,y,w
1234 return _mm_sub_ps(_mm_mul_ps(l1, l2), _mm_mul_ps(r1, r2));
1235}
1236
1237PX_FORCE_INLINE VecCrossV V3PrepareCross(const Vec3V a)
1238{
1239 ASSERT_ISVALIDVEC3V(a);
1240 VecCrossV v;
1241 v.mR1 = _mm_shuffle_ps(a, a, _MM_SHUFFLE(3, 1, 0, 2)); // z,x,y,w
1242 v.mL1 = _mm_shuffle_ps(a, a, _MM_SHUFFLE(3, 0, 2, 1)); // y,z,x,w
1243 return v;
1244}
1245
1246PX_FORCE_INLINE Vec3V V3Cross(const VecCrossV& a, const Vec3V b)
1247{
1248 ASSERT_ISVALIDVEC3V(b);
1249 const __m128 r2 = _mm_shuffle_ps(b, b, _MM_SHUFFLE(3, 0, 2, 1)); // y,z,x,w
1250 const __m128 l2 = _mm_shuffle_ps(b, b, _MM_SHUFFLE(3, 1, 0, 2)); // z,x,y,w
1251 return _mm_sub_ps(_mm_mul_ps(a.mL1, l2), _mm_mul_ps(a.mR1, r2));
1252}
1253
1254PX_FORCE_INLINE Vec3V V3Cross(const Vec3V a, const VecCrossV& b)
1255{
1256 ASSERT_ISVALIDVEC3V(a);
1257 const __m128 r2 = _mm_shuffle_ps(a, a, _MM_SHUFFLE(3, 0, 2, 1)); // y,z,x,w
1258 const __m128 l2 = _mm_shuffle_ps(a, a, _MM_SHUFFLE(3, 1, 0, 2)); // z,x,y,w
1259 return _mm_sub_ps(_mm_mul_ps(b.mR1, r2), _mm_mul_ps(b.mL1, l2));
1260}
1261
1262PX_FORCE_INLINE Vec3V V3Cross(const VecCrossV& a, const VecCrossV& b)
1263{
1264 return _mm_sub_ps(_mm_mul_ps(a.mL1, b.mR1), _mm_mul_ps(a.mR1, b.mL1));
1265}
1266
1267PX_FORCE_INLINE FloatV V3Length(const Vec3V a)
1268{
1269 ASSERT_ISVALIDVEC3V(a);
1270 return _mm_sqrt_ps(V3Dot(a, a));
1271}
1272
1273PX_FORCE_INLINE FloatV V3LengthSq(const Vec3V a)
1274{
1275 ASSERT_ISVALIDVEC3V(a);
1276 return V3Dot(a, a);
1277}
1278
1279PX_FORCE_INLINE Vec3V V3Normalize(const Vec3V a)
1280{
1281 ASSERT_ISVALIDVEC3V(a);
1282 ASSERT_ISFINITELENGTH(a);
1283 return V3ScaleInv(a, _mm_sqrt_ps(V3Dot(a, a)));
1284}
1285
1286PX_FORCE_INLINE Vec3V V3NormalizeFast(const Vec3V a)
1287{
1288 ASSERT_ISVALIDVEC3V(a);
1289 ASSERT_ISFINITELENGTH(a);
1290 return V3Scale(a, _mm_rsqrt_ps(V3Dot(a, a)));
1291}
1292
1293PX_FORCE_INLINE Vec3V V3NormalizeSafe(const Vec3V a, const Vec3V unsafeReturnValue)
1294{
1295 ASSERT_ISVALIDVEC3V(a);
1296 const __m128 eps = V4Eps();
1297 const __m128 length = V3Length(a);
1298 const __m128 isGreaterThanZero = FIsGrtr(length, eps);
1299 return V3Sel(isGreaterThanZero, V3ScaleInv(a, length), unsafeReturnValue);
1300}
1301
1302PX_FORCE_INLINE Vec3V V3Sel(const BoolV c, const Vec3V a, const Vec3V b)
1303{
1304 ASSERT_ISVALIDVEC3V(_mm_or_ps(_mm_andnot_ps(c, b), _mm_and_ps(c, a)));
1305 return _mm_or_ps(_mm_andnot_ps(c, b), _mm_and_ps(c, a));
1306}
1307
1308PX_FORCE_INLINE BoolV V3IsGrtr(const Vec3V a, const Vec3V b)
1309{
1310 ASSERT_ISVALIDVEC3V(a);
1311 ASSERT_ISVALIDVEC3V(b);
1312 return _mm_cmpgt_ps(a, b);
1313}
1314
1315PX_FORCE_INLINE BoolV V3IsGrtrOrEq(const Vec3V a, const Vec3V b)
1316{
1317 ASSERT_ISVALIDVEC3V(a);
1318 ASSERT_ISVALIDVEC3V(b);
1319 return _mm_cmpge_ps(a, b);
1320}
1321
1322PX_FORCE_INLINE BoolV V3IsEq(const Vec3V a, const Vec3V b)
1323{
1324 ASSERT_ISVALIDVEC3V(a);
1325 ASSERT_ISVALIDVEC3V(b);
1326 return _mm_cmpeq_ps(a, b);
1327}
1328
1329PX_FORCE_INLINE Vec3V V3Max(const Vec3V a, const Vec3V b)
1330{
1331 ASSERT_ISVALIDVEC3V(a);
1332 ASSERT_ISVALIDVEC3V(b);
1333 return _mm_max_ps(a, b);
1334}
1335
1336PX_FORCE_INLINE Vec3V V3Min(const Vec3V a, const Vec3V b)
1337{
1338 ASSERT_ISVALIDVEC3V(a);
1339 ASSERT_ISVALIDVEC3V(b);
1340 return _mm_min_ps(a, b);
1341}
1342
1343PX_FORCE_INLINE FloatV V3ExtractMax(const Vec3V a)
1344{
1345 ASSERT_ISVALIDVEC3V(a);
1346 const __m128 shuf1 = _mm_shuffle_ps(a, a, _MM_SHUFFLE(0, 0, 0, 0));
1347 const __m128 shuf2 = _mm_shuffle_ps(a, a, _MM_SHUFFLE(1, 1, 1, 1));
1348 const __m128 shuf3 = _mm_shuffle_ps(a, a, _MM_SHUFFLE(2, 2, 2, 2));
1349
1350 return _mm_max_ps(_mm_max_ps(shuf1, shuf2), shuf3);
1351}
1352
1353PX_FORCE_INLINE FloatV V3ExtractMin(const Vec3V a)
1354{
1355 ASSERT_ISVALIDVEC3V(a);
1356
1357 const __m128 shuf1 = _mm_shuffle_ps(a, a, _MM_SHUFFLE(0, 0, 0, 0));
1358 const __m128 shuf2 = _mm_shuffle_ps(a, a, _MM_SHUFFLE(1, 1, 1, 1));
1359 const __m128 shuf3 = _mm_shuffle_ps(a, a, _MM_SHUFFLE(2, 2, 2, 2));
1360
1361 return _mm_min_ps(_mm_min_ps(shuf1, shuf2), shuf3);
1362}
1363
1364// return (a >= 0.0f) ? 1.0f : -1.0f;
1365PX_FORCE_INLINE Vec3V V3Sign(const Vec3V a)
1366{
1367 ASSERT_ISVALIDVEC3V(a);
1368 const __m128 zero = V3Zero();
1369 const __m128 one = V3One();
1370 const __m128 none = V3Neg(one);
1371 return V3Sel(V3IsGrtrOrEq(a, zero), one, none);
1372}
1373
1374PX_FORCE_INLINE Vec3V V3Clamp(const Vec3V a, const Vec3V minV, const Vec3V maxV)
1375{
1376 ASSERT_ISVALIDVEC3V(maxV);
1377 ASSERT_ISVALIDVEC3V(minV);
1378 return V3Max(V3Min(a, maxV), minV);
1379}
1380
1381PX_FORCE_INLINE PxU32 V3AllGrtr(const Vec3V a, const Vec3V b)
1382{
1383 ASSERT_ISVALIDVEC3V(a);
1384 ASSERT_ISVALIDVEC3V(b);
1385 return internalUnitSSE2Simd::BAllTrue3_R(V4IsGrtr(a, b));
1386}
1387
1388PX_FORCE_INLINE PxU32 V3AllGrtrOrEq(const Vec3V a, const Vec3V b)
1389{
1390 ASSERT_ISVALIDVEC3V(a);
1391 ASSERT_ISVALIDVEC3V(b);
1392 return internalUnitSSE2Simd::BAllTrue3_R(V4IsGrtrOrEq(a, b));
1393}
1394
1395PX_FORCE_INLINE PxU32 V3AllEq(const Vec3V a, const Vec3V b)
1396{
1397 ASSERT_ISVALIDVEC3V(a);
1398 ASSERT_ISVALIDVEC3V(b);
1399 return internalUnitSSE2Simd::BAllTrue3_R(V4IsEq(a, b));
1400}
1401
1402PX_FORCE_INLINE Vec3V V3Round(const Vec3V a)
1403{
1404 ASSERT_ISVALIDVEC3V(a);
1405#ifdef __SSE4_2__
1406 return _mm_round_ps(a, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC);
1407#else
1408 // return _mm_round_ps(a, 0x0);
1409 const Vec3V half = V3Load(0.5f);
1410 const __m128 signBit = _mm_cvtepi32_ps(_mm_srli_epi32(_mm_cvtps_epi32(a), 31));
1411 const Vec3V aRound = V3Sub(V3Add(a, half), signBit);
1412 __m128i tmp = _mm_cvttps_epi32(aRound);
1413 return _mm_cvtepi32_ps(tmp);
1414#endif
1415}
1416
1417PX_FORCE_INLINE Vec3V V3Sin(const Vec3V a)
1418{
1419 ASSERT_ISVALIDVEC3V(a);
1420 // Modulo the range of the given angles such that -XM_2PI <= Angles < XM_2PI
1421 const Vec4V recipTwoPi = V4LoadA(g_PXReciprocalTwoPi.f);
1422 const Vec4V twoPi = V4LoadA(g_PXTwoPi.f);
1423 const Vec3V tmp = V3Scale(a, recipTwoPi);
1424 const Vec3V b = V3Round(tmp);
1425 const Vec3V V1 = V3NegScaleSub(b, twoPi, a);
1426
1427 // sin(V) ~= V - V^3 / 3! + V^5 / 5! - V^7 / 7! + V^9 / 9! - V^11 / 11! + V^13 / 13! -
1428 // V^15 / 15! + V^17 / 17! - V^19 / 19! + V^21 / 21! - V^23 / 23! (for -PI <= V < PI)
1429 const Vec3V V2 = V3Mul(V1, V1);
1430 const Vec3V V3 = V3Mul(V2, V1);
1431 const Vec3V V5 = V3Mul(V3, V2);
1432 const Vec3V V7 = V3Mul(V5, V2);
1433 const Vec3V V9 = V3Mul(V7, V2);
1434 const Vec3V V11 = V3Mul(V9, V2);
1435 const Vec3V V13 = V3Mul(V11, V2);
1436 const Vec3V V15 = V3Mul(V13, V2);
1437 const Vec3V V17 = V3Mul(V15, V2);
1438 const Vec3V V19 = V3Mul(V17, V2);
1439 const Vec3V V21 = V3Mul(V19, V2);
1440 const Vec3V V23 = V3Mul(V21, V2);
1441
1442 const Vec4V sinCoefficients0 = V4LoadA(g_PXSinCoefficients0.f);
1443 const Vec4V sinCoefficients1 = V4LoadA(g_PXSinCoefficients1.f);
1444 const Vec4V sinCoefficients2 = V4LoadA(g_PXSinCoefficients2.f);
1445
1446 const FloatV S1 = V4GetY(sinCoefficients0);
1447 const FloatV S2 = V4GetZ(sinCoefficients0);
1448 const FloatV S3 = V4GetW(sinCoefficients0);
1449 const FloatV S4 = V4GetX(sinCoefficients1);
1450 const FloatV S5 = V4GetY(sinCoefficients1);
1451 const FloatV S6 = V4GetZ(sinCoefficients1);
1452 const FloatV S7 = V4GetW(sinCoefficients1);
1453 const FloatV S8 = V4GetX(sinCoefficients2);
1454 const FloatV S9 = V4GetY(sinCoefficients2);
1455 const FloatV S10 = V4GetZ(sinCoefficients2);
1456 const FloatV S11 = V4GetW(sinCoefficients2);
1457
1458 Vec3V Result;
1459 Result = V3ScaleAdd(V3, S1, V1);
1460 Result = V3ScaleAdd(V5, S2, Result);
1461 Result = V3ScaleAdd(V7, S3, Result);
1462 Result = V3ScaleAdd(V9, S4, Result);
1463 Result = V3ScaleAdd(V11, S5, Result);
1464 Result = V3ScaleAdd(V13, S6, Result);
1465 Result = V3ScaleAdd(V15, S7, Result);
1466 Result = V3ScaleAdd(V17, S8, Result);
1467 Result = V3ScaleAdd(V19, S9, Result);
1468 Result = V3ScaleAdd(V21, S10, Result);
1469 Result = V3ScaleAdd(V23, S11, Result);
1470
1471 ASSERT_ISVALIDVEC3V(Result);
1472 return Result;
1473}
1474
1475PX_FORCE_INLINE Vec3V V3Cos(const Vec3V a)
1476{
1477 ASSERT_ISVALIDVEC3V(a);
1478
1479 // Modulo the range of the given angles such that -XM_2PI <= Angles < XM_2PI
1480 const Vec4V recipTwoPi = V4LoadA(g_PXReciprocalTwoPi.f);
1481 const Vec4V twoPi = V4LoadA(g_PXTwoPi.f);
1482 const Vec3V tmp = V3Scale(a, recipTwoPi);
1483 const Vec3V b = V3Round(tmp);
1484 const Vec3V V1 = V3NegScaleSub(b, twoPi, a);
1485
1486 // cos(V) ~= 1 - V^2 / 2! + V^4 / 4! - V^6 / 6! + V^8 / 8! - V^10 / 10! + V^12 / 12! -
1487 // V^14 / 14! + V^16 / 16! - V^18 / 18! + V^20 / 20! - V^22 / 22! (for -PI <= V < PI)
1488 const Vec3V V2 = V3Mul(V1, V1);
1489 const Vec3V V4 = V3Mul(V2, V2);
1490 const Vec3V V6 = V3Mul(V4, V2);
1491 const Vec3V V8 = V3Mul(V4, V4);
1492 const Vec3V V10 = V3Mul(V6, V4);
1493 const Vec3V V12 = V3Mul(V6, V6);
1494 const Vec3V V14 = V3Mul(V8, V6);
1495 const Vec3V V16 = V3Mul(V8, V8);
1496 const Vec3V V18 = V3Mul(V10, V8);
1497 const Vec3V V20 = V3Mul(V10, V10);
1498 const Vec3V V22 = V3Mul(V12, V10);
1499
1500 const Vec4V cosCoefficients0 = V4LoadA(g_PXCosCoefficients0.f);
1501 const Vec4V cosCoefficients1 = V4LoadA(g_PXCosCoefficients1.f);
1502 const Vec4V cosCoefficients2 = V4LoadA(g_PXCosCoefficients2.f);
1503
1504 const FloatV C1 = V4GetY(cosCoefficients0);
1505 const FloatV C2 = V4GetZ(cosCoefficients0);
1506 const FloatV C3 = V4GetW(cosCoefficients0);
1507 const FloatV C4 = V4GetX(cosCoefficients1);
1508 const FloatV C5 = V4GetY(cosCoefficients1);
1509 const FloatV C6 = V4GetZ(cosCoefficients1);
1510 const FloatV C7 = V4GetW(cosCoefficients1);
1511 const FloatV C8 = V4GetX(cosCoefficients2);
1512 const FloatV C9 = V4GetY(cosCoefficients2);
1513 const FloatV C10 = V4GetZ(cosCoefficients2);
1514 const FloatV C11 = V4GetW(cosCoefficients2);
1515
1516 Vec3V Result;
1517 Result = V3ScaleAdd(V2, C1, V3One());
1518 Result = V3ScaleAdd(V4, C2, Result);
1519 Result = V3ScaleAdd(V6, C3, Result);
1520 Result = V3ScaleAdd(V8, C4, Result);
1521 Result = V3ScaleAdd(V10, C5, Result);
1522 Result = V3ScaleAdd(V12, C6, Result);
1523 Result = V3ScaleAdd(V14, C7, Result);
1524 Result = V3ScaleAdd(V16, C8, Result);
1525 Result = V3ScaleAdd(V18, C9, Result);
1526 Result = V3ScaleAdd(V20, C10, Result);
1527 Result = V3ScaleAdd(V22, C11, Result);
1528
1529 ASSERT_ISVALIDVEC3V(Result);
1530 return Result;
1531}
1532
1533PX_FORCE_INLINE Vec3V V3PermYZZ(const Vec3V a)
1534{
1535 ASSERT_ISVALIDVEC3V(a);
1536 return _mm_shuffle_ps(a, a, _MM_SHUFFLE(3, 2, 2, 1));
1537}
1538
1539PX_FORCE_INLINE Vec3V V3PermXYX(const Vec3V a)
1540{
1541 ASSERT_ISVALIDVEC3V(a);
1542 return _mm_shuffle_ps(a, a, _MM_SHUFFLE(3, 0, 1, 0));
1543}
1544
1545PX_FORCE_INLINE Vec3V V3PermYZX(const Vec3V a)
1546{
1547 ASSERT_ISVALIDVEC3V(a);
1548 return _mm_shuffle_ps(a, a, _MM_SHUFFLE(3, 0, 2, 1));
1549}
1550
1551PX_FORCE_INLINE Vec3V V3PermZXY(const Vec3V a)
1552{
1553 ASSERT_ISVALIDVEC3V(a);
1554 return _mm_shuffle_ps(a, a, _MM_SHUFFLE(3, 1, 0, 2));
1555}
1556
1557PX_FORCE_INLINE Vec3V V3PermZZY(const Vec3V a)
1558{
1559 ASSERT_ISVALIDVEC3V(a);
1560 return _mm_shuffle_ps(a, a, _MM_SHUFFLE(3, 1, 2, 2));
1561}
1562
1563PX_FORCE_INLINE Vec3V V3PermYXX(const Vec3V a)
1564{
1565 ASSERT_ISVALIDVEC3V(a);
1566 return _mm_shuffle_ps(a, a, _MM_SHUFFLE(3, 0, 0, 1));
1567}
1568
1569PX_FORCE_INLINE Vec3V V3Perm_Zero_1Z_0Y(const Vec3V v0, const Vec3V v1)
1570{
1571 ASSERT_ISVALIDVEC3V(v0);
1572 ASSERT_ISVALIDVEC3V(v1);
1573 return _mm_shuffle_ps(v1, v0, _MM_SHUFFLE(3, 1, 2, 3));
1574}
1575
1576PX_FORCE_INLINE Vec3V V3Perm_0Z_Zero_1X(const Vec3V v0, const Vec3V v1)
1577{
1578 ASSERT_ISVALIDVEC3V(v0);
1579 ASSERT_ISVALIDVEC3V(v1);
1580 return _mm_shuffle_ps(v0, v1, _MM_SHUFFLE(3, 0, 3, 2));
1581}
1582
1583PX_FORCE_INLINE Vec3V V3Perm_1Y_0X_Zero(const Vec3V v0, const Vec3V v1)
1584{
1585 ASSERT_ISVALIDVEC3V(v0);
1586 ASSERT_ISVALIDVEC3V(v1);
1587 // There must be a better way to do this.
1588 Vec3V v2 = V3Zero();
1589 FloatV y1 = V3GetY(v1);
1590 FloatV x0 = V3GetX(v0);
1591 v2 = V3SetX(v2, y1);
1592 return V3SetY(v2, x0);
1593}
1594
1595PX_FORCE_INLINE FloatV V3SumElems(const Vec3V a)
1596{
1597 ASSERT_ISVALIDVEC3V(a);
1598#ifdef __SSE4_2__
1599 Vec3V r = _mm_hadd_ps(a, a);
1600 r = _mm_hadd_ps(r, r);
1601 return r;
1602#else
1603 __m128 shuf1 = _mm_shuffle_ps(a, a, _MM_SHUFFLE(0, 0, 0, 0)); // z,y,x,w
1604 __m128 shuf2 = _mm_shuffle_ps(a, a, _MM_SHUFFLE(1, 1, 1, 1)); // y,x,w,z
1605 __m128 shuf3 = _mm_shuffle_ps(a, a, _MM_SHUFFLE(2, 2, 2, 2)); // x,w,z,y
1606 return _mm_add_ps(_mm_add_ps(shuf1, shuf2), shuf3);
1607#endif
1608}
1609
1610PX_FORCE_INLINE PxU32 V3OutOfBounds(const Vec3V a, const Vec3V min, const Vec3V max)
1611{
1612 ASSERT_ISVALIDVEC3V(a);
1613 ASSERT_ISVALIDVEC3V(min);
1614 ASSERT_ISVALIDVEC3V(max);
1615 const BoolV c = BOr(V3IsGrtr(a, max), V3IsGrtr(min, a));
1616 return !BAllEqFFFF(c);
1617}
1618
1619PX_FORCE_INLINE PxU32 V3InBounds(const Vec3V a, const Vec3V min, const Vec3V max)
1620{
1621 ASSERT_ISVALIDVEC3V(a);
1622 ASSERT_ISVALIDVEC3V(min);
1623 ASSERT_ISVALIDVEC3V(max);
1624 const BoolV c = BAnd(V3IsGrtrOrEq(a, min), V3IsGrtrOrEq(max, a));
1625 return BAllEqTTTT(c);
1626}
1627
1628PX_FORCE_INLINE PxU32 V3OutOfBounds(const Vec3V a, const Vec3V bounds)
1629{
1630 ASSERT_ISVALIDVEC3V(a);
1631 ASSERT_ISVALIDVEC3V(bounds);
1632 return V3OutOfBounds(a, V3Neg(bounds), bounds);
1633}
1634
1635PX_FORCE_INLINE PxU32 V3InBounds(const Vec3V a, const Vec3V bounds)
1636{
1637 ASSERT_ISVALIDVEC3V(a);
1638 ASSERT_ISVALIDVEC3V(bounds)
1639 return V3InBounds(a, V3Neg(bounds), bounds);
1640}
1641
1642PX_FORCE_INLINE void V3Transpose(Vec3V& col0, Vec3V& col1, Vec3V& col2)
1643{
1644 ASSERT_ISVALIDVEC3V(col0);
1645 ASSERT_ISVALIDVEC3V(col1);
1646 ASSERT_ISVALIDVEC3V(col2);
1647
1648 const Vec3V col3 = _mm_setzero_ps();
1649 Vec3V tmp0 = _mm_unpacklo_ps(col0, col1);
1650 Vec3V tmp2 = _mm_unpacklo_ps(col2, col3);
1651 Vec3V tmp1 = _mm_unpackhi_ps(col0, col1);
1652 Vec3V tmp3 = _mm_unpackhi_ps(col2, col3);
1653 col0 = _mm_movelh_ps(tmp0, tmp2);
1654 col1 = _mm_movehl_ps(tmp2, tmp0);
1655 col2 = _mm_movelh_ps(tmp1, tmp3);
1656}
1657
1659// VEC4V
1661
1662PX_FORCE_INLINE Vec4V V4Splat(const FloatV f)
1663{
1664 ASSERT_ISVALIDFLOATV(f);
1665 // return _mm_shuffle_ps(f, f, _MM_SHUFFLE(0,0,0,0));
1666 return f;
1667}
1668
1669PX_FORCE_INLINE Vec4V V4Merge(const FloatV* const floatVArray)
1670{
1671 ASSERT_ISVALIDFLOATV(floatVArray[0]);
1672 ASSERT_ISVALIDFLOATV(floatVArray[1]);
1673 ASSERT_ISVALIDFLOATV(floatVArray[2]);
1674 ASSERT_ISVALIDFLOATV(floatVArray[3]);
1675 const __m128 xw = _mm_move_ss(floatVArray[1], floatVArray[0]); // y, y, y, x
1676 const __m128 yz = _mm_move_ss(floatVArray[2], floatVArray[3]); // z, z, z, w
1677 return _mm_shuffle_ps(xw, yz, _MM_SHUFFLE(0, 2, 1, 0));
1678}
1679
1680PX_FORCE_INLINE Vec4V V4Merge(const FloatVArg x, const FloatVArg y, const FloatVArg z, const FloatVArg w)
1681{
1682 ASSERT_ISVALIDFLOATV(x);
1683 ASSERT_ISVALIDFLOATV(y);
1684 ASSERT_ISVALIDFLOATV(z);
1685 ASSERT_ISVALIDFLOATV(w);
1686 const __m128 xw = _mm_move_ss(y, x); // y, y, y, x
1687 const __m128 yz = _mm_move_ss(z, w); // z, z, z, w
1688 return _mm_shuffle_ps(xw, yz, _MM_SHUFFLE(0, 2, 1, 0));
1689}
1690
1691PX_FORCE_INLINE Vec4V V4MergeW(const Vec4VArg x, const Vec4VArg y, const Vec4VArg z, const Vec4VArg w)
1692{
1693 const Vec4V xz = _mm_unpackhi_ps(x, z);
1694 const Vec4V yw = _mm_unpackhi_ps(y, w);
1695 return _mm_unpackhi_ps(xz, yw);
1696}
1697
1698PX_FORCE_INLINE Vec4V V4MergeZ(const Vec4VArg x, const Vec4VArg y, const Vec4VArg z, const Vec4VArg w)
1699{
1700 const Vec4V xz = _mm_unpackhi_ps(x, z);
1701 const Vec4V yw = _mm_unpackhi_ps(y, w);
1702 return _mm_unpacklo_ps(xz, yw);
1703}
1704
1705PX_FORCE_INLINE Vec4V V4MergeY(const Vec4VArg x, const Vec4VArg y, const Vec4VArg z, const Vec4VArg w)
1706{
1707 const Vec4V xz = _mm_unpacklo_ps(x, z);
1708 const Vec4V yw = _mm_unpacklo_ps(y, w);
1709 return _mm_unpackhi_ps(xz, yw);
1710}
1711
1712PX_FORCE_INLINE Vec4V V4MergeX(const Vec4VArg x, const Vec4VArg y, const Vec4VArg z, const Vec4VArg w)
1713{
1714 const Vec4V xz = _mm_unpacklo_ps(x, z);
1715 const Vec4V yw = _mm_unpacklo_ps(y, w);
1716 return _mm_unpacklo_ps(xz, yw);
1717}
1718
1719PX_FORCE_INLINE Vec4V V4UnpackXY(const Vec4VArg a, const Vec4VArg b)
1720{
1721 return _mm_unpacklo_ps(a, b);
1722}
1723
1724PX_FORCE_INLINE Vec4V V4UnpackZW(const Vec4VArg a, const Vec4VArg b)
1725{
1726 return _mm_unpackhi_ps(a, b);
1727}
1728
1729PX_FORCE_INLINE Vec4V V4UnitW()
1730{
1731 const PX_ALIGN(16, PxF32) w[4] = { 0.0f, 0.0f, 0.0f, 1.0f };
1732 const __m128 w128 = _mm_load_ps(w);
1733 return w128;
1734}
1735
1736PX_FORCE_INLINE Vec4V V4UnitX()
1737{
1738 const PX_ALIGN(16, PxF32) x[4] = { 1.0f, 0.0f, 0.0f, 0.0f };
1739 const __m128 x128 = _mm_load_ps(x);
1740 return x128;
1741}
1742
1743PX_FORCE_INLINE Vec4V V4UnitY()
1744{
1745 const PX_ALIGN(16, PxF32) y[4] = { 0.0f, 1.0f, 0.0f, 0.0f };
1746 const __m128 y128 = _mm_load_ps(y);
1747 return y128;
1748}
1749
1750PX_FORCE_INLINE Vec4V V4UnitZ()
1751{
1752 const PX_ALIGN(16, PxF32) z[4] = { 0.0f, 0.0f, 1.0f, 0.0f };
1753 const __m128 z128 = _mm_load_ps(z);
1754 return z128;
1755}
1756
1757PX_FORCE_INLINE FloatV V4GetW(const Vec4V f)
1758{
1759 return _mm_shuffle_ps(f, f, _MM_SHUFFLE(3, 3, 3, 3));
1760}
1761
1762PX_FORCE_INLINE FloatV V4GetX(const Vec4V f)
1763{
1764 return _mm_shuffle_ps(f, f, _MM_SHUFFLE(0, 0, 0, 0));
1765}
1766
1767PX_FORCE_INLINE FloatV V4GetY(const Vec4V f)
1768{
1769 return _mm_shuffle_ps(f, f, _MM_SHUFFLE(1, 1, 1, 1));
1770}
1771
1772PX_FORCE_INLINE FloatV V4GetZ(const Vec4V f)
1773{
1774 return _mm_shuffle_ps(f, f, _MM_SHUFFLE(2, 2, 2, 2));
1775}
1776
1777PX_FORCE_INLINE Vec4V V4SetW(const Vec4V v, const FloatV f)
1778{
1779 ASSERT_ISVALIDFLOATV(f);
1780 return V4Sel(BTTTF(), v, f);
1781}
1782
1783PX_FORCE_INLINE Vec4V V4SetX(const Vec4V v, const FloatV f)
1784{
1785 ASSERT_ISVALIDFLOATV(f);
1786 return V4Sel(BFTTT(), v, f);
1787}
1788
1789PX_FORCE_INLINE Vec4V V4SetY(const Vec4V v, const FloatV f)
1790{
1791 ASSERT_ISVALIDFLOATV(f);
1792 return V4Sel(BTFTT(), v, f);
1793}
1794
1795PX_FORCE_INLINE Vec4V V4SetZ(const Vec4V v, const FloatV f)
1796{
1797 ASSERT_ISVALIDFLOATV(f);
1798 return V4Sel(BTTFT(), v, f);
1799}
1800
1801PX_FORCE_INLINE Vec4V V4ClearW(const Vec4V v)
1802{
1803#if !PX_EMSCRIPTEN
1804 return _mm_and_ps(v, V4LoadA(internalUnitSSE2Simd::gMaskXYZ));
1805#else
1806 return _mm_and_ps(v, (VecI32V&)internalUnitSSE2Simd::gMaskXYZ);
1807#endif
1808}
1809
1810PX_FORCE_INLINE Vec4V V4PermYXWZ(const Vec4V a)
1811{
1812 return _mm_shuffle_ps(a, a, _MM_SHUFFLE(2, 3, 0, 1));
1813}
1814
1815PX_FORCE_INLINE Vec4V V4PermXZXZ(const Vec4V a)
1816{
1817 return _mm_shuffle_ps(a, a, _MM_SHUFFLE(2, 0, 2, 0));
1818}
1819
1820PX_FORCE_INLINE Vec4V V4PermYWYW(const Vec4V a)
1821{
1822 return _mm_shuffle_ps(a, a, _MM_SHUFFLE(3, 1, 3, 1));
1823}
1824
1825PX_FORCE_INLINE Vec4V V4PermYZXW(const Vec4V a)
1826{
1827 return _mm_shuffle_ps(a, a, _MM_SHUFFLE(3, 0, 2, 1));
1828}
1829
1830PX_FORCE_INLINE Vec4V V4PermZWXY(const Vec4V a)
1831{
1832 return _mm_shuffle_ps(a, a, _MM_SHUFFLE(1, 0, 3, 2));
1833}
1834
1835template <PxU8 x, PxU8 y, PxU8 z, PxU8 w>
1836PX_FORCE_INLINE Vec4V V4Perm(const Vec4V a)
1837{
1838 return _mm_shuffle_ps(a, a, _MM_SHUFFLE(w, z, y, x));
1839}
1840
1841PX_FORCE_INLINE Vec4V V4Zero()
1842{
1843 return V4Load(0.0f);
1844}
1845
1846PX_FORCE_INLINE Vec4V V4One()
1847{
1848 return V4Load(1.0f);
1849}
1850
1851PX_FORCE_INLINE Vec4V V4Eps()
1852{
1853 return V4Load(PX_EPS_REAL);
1854}
1855
1856PX_FORCE_INLINE Vec4V V4Neg(const Vec4V f)
1857{
1858 return _mm_sub_ps(_mm_setzero_ps(), f);
1859}
1860
1861PX_FORCE_INLINE Vec4V V4Add(const Vec4V a, const Vec4V b)
1862{
1863 return _mm_add_ps(a, b);
1864}
1865
1866PX_FORCE_INLINE Vec4V V4Sub(const Vec4V a, const Vec4V b)
1867{
1868 return _mm_sub_ps(a, b);
1869}
1870
1871PX_FORCE_INLINE Vec4V V4Scale(const Vec4V a, const FloatV b)
1872{
1873 return _mm_mul_ps(a, b);
1874}
1875
1876PX_FORCE_INLINE Vec4V V4Mul(const Vec4V a, const Vec4V b)
1877{
1878 return _mm_mul_ps(a, b);
1879}
1880
1881PX_FORCE_INLINE Vec4V V4ScaleInv(const Vec4V a, const FloatV b)
1882{
1883 ASSERT_ISVALIDFLOATV(b);
1884 return _mm_div_ps(a, b);
1885}
1886
1887PX_FORCE_INLINE Vec4V V4Div(const Vec4V a, const Vec4V b)
1888{
1889 return _mm_div_ps(a, b);
1890}
1891
1892PX_FORCE_INLINE Vec4V V4ScaleInvFast(const Vec4V a, const FloatV b)
1893{
1894 ASSERT_ISVALIDFLOATV(b);
1895 return _mm_mul_ps(a, _mm_rcp_ps(b));
1896}
1897
1898PX_FORCE_INLINE Vec4V V4DivFast(const Vec4V a, const Vec4V b)
1899{
1900 return _mm_mul_ps(a, _mm_rcp_ps(b));
1901}
1902
1903PX_FORCE_INLINE Vec4V V4Recip(const Vec4V a)
1904{
1905 return _mm_div_ps(V4One(), a);
1906}
1907
1908PX_FORCE_INLINE Vec4V V4RecipFast(const Vec4V a)
1909{
1910 return _mm_rcp_ps(a);
1911}
1912
1913PX_FORCE_INLINE Vec4V V4Rsqrt(const Vec4V a)
1914{
1915 return _mm_div_ps(V4One(), _mm_sqrt_ps(a));
1916}
1917
1918PX_FORCE_INLINE Vec4V V4RsqrtFast(const Vec4V a)
1919{
1920 return _mm_rsqrt_ps(a);
1921}
1922
1923PX_FORCE_INLINE Vec4V V4Sqrt(const Vec4V a)
1924{
1925 return _mm_sqrt_ps(a);
1926}
1927
1928PX_FORCE_INLINE Vec4V V4ScaleAdd(const Vec4V a, const FloatV b, const Vec4V c)
1929{
1930 ASSERT_ISVALIDFLOATV(b);
1931 return V4Add(V4Scale(a, b), c);
1932}
1933
1934PX_FORCE_INLINE Vec4V V4NegScaleSub(const Vec4V a, const FloatV b, const Vec4V c)
1935{
1936 ASSERT_ISVALIDFLOATV(b);
1937 return V4Sub(c, V4Scale(a, b));
1938}
1939
1940PX_FORCE_INLINE Vec4V V4MulAdd(const Vec4V a, const Vec4V b, const Vec4V c)
1941{
1942 return V4Add(V4Mul(a, b), c);
1943}
1944
1945PX_FORCE_INLINE Vec4V V4NegMulSub(const Vec4V a, const Vec4V b, const Vec4V c)
1946{
1947 return V4Sub(c, V4Mul(a, b));
1948}
1949
1950PX_FORCE_INLINE Vec4V V4Abs(const Vec4V a)
1951{
1952 return V4Max(a, V4Neg(a));
1953}
1954
1955PX_FORCE_INLINE FloatV V4SumElements(const Vec4V a)
1956{
1957#ifdef __SSE4_2__
1958 Vec4V r = _mm_hadd_ps(a, a);
1959 r = _mm_hadd_ps(r, r);
1960 return r;
1961#else
1962 const Vec4V xy = V4UnpackXY(a, a); // x,x,y,y
1963 const Vec4V zw = V4UnpackZW(a, a); // z,z,w,w
1964 const Vec4V xz_yw = V4Add(xy, zw); // x+z,x+z,y+w,y+w
1965 const FloatV xz = V4GetX(xz_yw); // x+z
1966 const FloatV yw = V4GetZ(xz_yw); // y+w
1967 return FAdd(xz, yw); // sum
1968#endif
1969}
1970
1971PX_FORCE_INLINE FloatV V4Dot(const Vec4V a, const Vec4V b)
1972{
1973#ifdef __SSE4_2__
1974 return _mm_dp_ps(a, b, 0xff);
1975#else
1976 //const __m128 dot1 = _mm_mul_ps(a, b); // x,y,z,w
1977 //const __m128 shuf1 = _mm_shuffle_ps(dot1, dot1, _MM_SHUFFLE(2, 1, 0, 3)); // w,x,y,z
1978 //const __m128 shuf2 = _mm_shuffle_ps(dot1, dot1, _MM_SHUFFLE(1, 0, 3, 2)); // z,w,x,y
1979 //const __m128 shuf3 = _mm_shuffle_ps(dot1, dot1, _MM_SHUFFLE(0, 3, 2, 1)); // y,z,w,x
1980 //return _mm_add_ps(_mm_add_ps(shuf2, shuf3), _mm_add_ps(dot1, shuf1));
1981
1982 // aw*bw | az*bz | ay*by | ax*bx
1983 const __m128 t0 = _mm_mul_ps(a, b);
1984 // ay*by | ax*bx | aw*bw | az*bz
1985 const __m128 t1 = _mm_shuffle_ps(t0, t0, _MM_SHUFFLE(1, 0, 3, 2));
1986 // ay*by + aw*bw | ax*bx + az*bz | aw*bw + ay*by | az*bz + ax*bx
1987 const __m128 t2 = _mm_add_ps(t0, t1);
1988 // ax*bx + az*bz | ay*by + aw*bw | az*bz + ax*bx | aw*bw + ay*by
1989 const __m128 t3 = _mm_shuffle_ps(t2, t2, _MM_SHUFFLE(2, 3, 0, 1));
1990 // ax*bx + az*bz + ay*by + aw*bw
1991 return _mm_add_ps(t3, t2);
1992#endif
1993}
1994
1995PX_FORCE_INLINE FloatV V4Dot3(const Vec4V a, const Vec4V b)
1996{
1997#ifdef __SSE4_2__
1998 return _mm_dp_ps(a, b, 0x7f);
1999#else
2000 const __m128 dot1 = _mm_mul_ps(a, b); // w,z,y,x
2001 const __m128 shuf1 = _mm_shuffle_ps(dot1, dot1, _MM_SHUFFLE(0, 0, 0, 0)); // z,y,x,w
2002 const __m128 shuf2 = _mm_shuffle_ps(dot1, dot1, _MM_SHUFFLE(1, 1, 1, 1)); // y,x,w,z
2003 const __m128 shuf3 = _mm_shuffle_ps(dot1, dot1, _MM_SHUFFLE(2, 2, 2, 2)); // x,w,z,y
2004 return _mm_add_ps(_mm_add_ps(shuf1, shuf2), shuf3);
2005#endif
2006}
2007
2008PX_FORCE_INLINE Vec4V V4Cross(const Vec4V a, const Vec4V b)
2009{
2010 const __m128 r1 = _mm_shuffle_ps(a, a, _MM_SHUFFLE(3, 1, 0, 2)); // z,x,y,w
2011 const __m128 r2 = _mm_shuffle_ps(b, b, _MM_SHUFFLE(3, 0, 2, 1)); // y,z,x,w
2012 const __m128 l1 = _mm_shuffle_ps(a, a, _MM_SHUFFLE(3, 0, 2, 1)); // y,z,x,w
2013 const __m128 l2 = _mm_shuffle_ps(b, b, _MM_SHUFFLE(3, 1, 0, 2)); // z,x,y,w
2014 return _mm_sub_ps(_mm_mul_ps(l1, l2), _mm_mul_ps(r1, r2));
2015}
2016
2017PX_FORCE_INLINE FloatV V4Length(const Vec4V a)
2018{
2019 return _mm_sqrt_ps(V4Dot(a, a));
2020}
2021
2022PX_FORCE_INLINE FloatV V4LengthSq(const Vec4V a)
2023{
2024 return V4Dot(a, a);
2025}
2026
2027PX_FORCE_INLINE Vec4V V4Normalize(const Vec4V a)
2028{
2029 ASSERT_ISFINITELENGTH(a);
2030 return V4ScaleInv(a, _mm_sqrt_ps(V4Dot(a, a)));
2031}
2032
2033PX_FORCE_INLINE Vec4V V4NormalizeFast(const Vec4V a)
2034{
2035 ASSERT_ISFINITELENGTH(a);
2036 return V4ScaleInvFast(a, _mm_sqrt_ps(V4Dot(a, a)));
2037}
2038
2039PX_FORCE_INLINE Vec4V V4NormalizeSafe(const Vec4V a, const Vec3V unsafeReturnValue)
2040{
2041 const __m128 eps = V3Eps();
2042 const __m128 length = V4Length(a);
2043 const __m128 isGreaterThanZero = V4IsGrtr(length, eps);
2044 return V4Sel(isGreaterThanZero, V4ScaleInv(a, length), unsafeReturnValue);
2045}
2046
2047PX_FORCE_INLINE BoolV V4IsEqU32(const VecU32V a, const VecU32V b)
2048{
2049 return m128_I2F(_mm_cmpeq_epi32(m128_F2I(a), m128_F2I(b)));
2050}
2051
2052PX_FORCE_INLINE Vec4V V4Sel(const BoolV c, const Vec4V a, const Vec4V b)
2053{
2054 return _mm_or_ps(_mm_andnot_ps(c, b), _mm_and_ps(c, a));
2055}
2056
2057PX_FORCE_INLINE BoolV V4IsGrtr(const Vec4V a, const Vec4V b)
2058{
2059 return _mm_cmpgt_ps(a, b);
2060}
2061
2062PX_FORCE_INLINE BoolV V4IsGrtrOrEq(const Vec4V a, const Vec4V b)
2063{
2064 return _mm_cmpge_ps(a, b);
2065}
2066
2067PX_FORCE_INLINE BoolV V4IsEq(const Vec4V a, const Vec4V b)
2068{
2069 return _mm_cmpeq_ps(a, b);
2070}
2071
2072PX_FORCE_INLINE Vec4V V4Max(const Vec4V a, const Vec4V b)
2073{
2074 return _mm_max_ps(a, b);
2075}
2076
2077PX_FORCE_INLINE Vec4V V4Min(const Vec4V a, const Vec4V b)
2078{
2079 return _mm_min_ps(a, b);
2080}
2081
2082PX_FORCE_INLINE FloatV V4ExtractMax(const Vec4V a)
2083{
2084 const __m128 shuf1 = _mm_shuffle_ps(a, a, _MM_SHUFFLE(2, 1, 0, 3));
2085 const __m128 shuf2 = _mm_shuffle_ps(a, a, _MM_SHUFFLE(1, 0, 3, 2));
2086 const __m128 shuf3 = _mm_shuffle_ps(a, a, _MM_SHUFFLE(0, 3, 2, 1));
2087
2088 return _mm_max_ps(_mm_max_ps(a, shuf1), _mm_max_ps(shuf2, shuf3));
2089}
2090
2091PX_FORCE_INLINE FloatV V4ExtractMin(const Vec4V a)
2092{
2093 const __m128 shuf1 = _mm_shuffle_ps(a, a, _MM_SHUFFLE(2, 1, 0, 3));
2094 const __m128 shuf2 = _mm_shuffle_ps(a, a, _MM_SHUFFLE(1, 0, 3, 2));
2095 const __m128 shuf3 = _mm_shuffle_ps(a, a, _MM_SHUFFLE(0, 3, 2, 1));
2096
2097 return _mm_min_ps(_mm_min_ps(a, shuf1), _mm_min_ps(shuf2, shuf3));
2098}
2099
2100PX_FORCE_INLINE Vec4V V4Clamp(const Vec4V a, const Vec4V minV, const Vec4V maxV)
2101{
2102 return V4Max(V4Min(a, maxV), minV);
2103}
2104
2105PX_FORCE_INLINE PxU32 V4AllGrtr(const Vec4V a, const Vec4V b)
2106{
2107 return internalUnitSSE2Simd::BAllTrue4_R(V4IsGrtr(a, b));
2108}
2109
2110PX_FORCE_INLINE PxU32 V4AllGrtrOrEq(const Vec4V a, const Vec4V b)
2111{
2112 return internalUnitSSE2Simd::BAllTrue4_R(V4IsGrtrOrEq(a, b));
2113}
2114
2115PX_FORCE_INLINE PxU32 V4AllGrtrOrEq3(const Vec4V a, const Vec4V b)
2116{
2117 return internalUnitSSE2Simd::BAllTrue3_R(V4IsGrtrOrEq(a, b));
2118}
2119
2120PX_FORCE_INLINE PxU32 V4AllEq(const Vec4V a, const Vec4V b)
2121{
2122 return internalUnitSSE2Simd::BAllTrue4_R(V4IsEq(a, b));
2123}
2124
2125PX_FORCE_INLINE PxU32 V4AnyGrtr3(const Vec4V a, const Vec4V b)
2126{
2127 return internalUnitSSE2Simd::BAnyTrue3_R(V4IsGrtr(a, b));
2128}
2129
2130PX_FORCE_INLINE Vec4V V4Round(const Vec4V a)
2131{
2132#ifdef __SSE4_2__
2133 return _mm_round_ps(a, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC);
2134#else
2135 // return _mm_round_ps(a, 0x0);
2136 const Vec4V half = V4Load(0.5f);
2137 const __m128 signBit = _mm_cvtepi32_ps(_mm_srli_epi32(_mm_cvtps_epi32(a), 31));
2138 const Vec4V aRound = V4Sub(V4Add(a, half), signBit);
2139 __m128i tmp = _mm_cvttps_epi32(aRound);
2140 return _mm_cvtepi32_ps(tmp);
2141#endif
2142}
2143
2144PX_FORCE_INLINE Vec4V V4Sin(const Vec4V a)
2145{
2146 const Vec4V recipTwoPi = V4LoadA(g_PXReciprocalTwoPi.f);
2147 const Vec4V twoPi = V4LoadA(g_PXTwoPi.f);
2148 const Vec4V tmp = V4Mul(a, recipTwoPi);
2149 const Vec4V b = V4Round(tmp);
2150 const Vec4V V1 = V4NegMulSub(twoPi, b, a);
2151
2152 // sin(V) ~= V - V^3 / 3! + V^5 / 5! - V^7 / 7! + V^9 / 9! - V^11 / 11! + V^13 / 13! -
2153 // V^15 / 15! + V^17 / 17! - V^19 / 19! + V^21 / 21! - V^23 / 23! (for -PI <= V < PI)
2154 const Vec4V V2 = V4Mul(V1, V1);
2155 const Vec4V V3 = V4Mul(V2, V1);
2156 const Vec4V V5 = V4Mul(V3, V2);
2157 const Vec4V V7 = V4Mul(V5, V2);
2158 const Vec4V V9 = V4Mul(V7, V2);
2159 const Vec4V V11 = V4Mul(V9, V2);
2160 const Vec4V V13 = V4Mul(V11, V2);
2161 const Vec4V V15 = V4Mul(V13, V2);
2162 const Vec4V V17 = V4Mul(V15, V2);
2163 const Vec4V V19 = V4Mul(V17, V2);
2164 const Vec4V V21 = V4Mul(V19, V2);
2165 const Vec4V V23 = V4Mul(V21, V2);
2166
2167 const Vec4V sinCoefficients0 = V4LoadA(g_PXSinCoefficients0.f);
2168 const Vec4V sinCoefficients1 = V4LoadA(g_PXSinCoefficients1.f);
2169 const Vec4V sinCoefficients2 = V4LoadA(g_PXSinCoefficients2.f);
2170
2171 const FloatV S1 = V4GetY(sinCoefficients0);
2172 const FloatV S2 = V4GetZ(sinCoefficients0);
2173 const FloatV S3 = V4GetW(sinCoefficients0);
2174 const FloatV S4 = V4GetX(sinCoefficients1);
2175 const FloatV S5 = V4GetY(sinCoefficients1);
2176 const FloatV S6 = V4GetZ(sinCoefficients1);
2177 const FloatV S7 = V4GetW(sinCoefficients1);
2178 const FloatV S8 = V4GetX(sinCoefficients2);
2179 const FloatV S9 = V4GetY(sinCoefficients2);
2180 const FloatV S10 = V4GetZ(sinCoefficients2);
2181 const FloatV S11 = V4GetW(sinCoefficients2);
2182
2183 Vec4V Result;
2184 Result = V4MulAdd(S1, V3, V1);
2185 Result = V4MulAdd(S2, V5, Result);
2186 Result = V4MulAdd(S3, V7, Result);
2187 Result = V4MulAdd(S4, V9, Result);
2188 Result = V4MulAdd(S5, V11, Result);
2189 Result = V4MulAdd(S6, V13, Result);
2190 Result = V4MulAdd(S7, V15, Result);
2191 Result = V4MulAdd(S8, V17, Result);
2192 Result = V4MulAdd(S9, V19, Result);
2193 Result = V4MulAdd(S10, V21, Result);
2194 Result = V4MulAdd(S11, V23, Result);
2195
2196 return Result;
2197}
2198
2199PX_FORCE_INLINE Vec4V V4Cos(const Vec4V a)
2200{
2201 const Vec4V recipTwoPi = V4LoadA(g_PXReciprocalTwoPi.f);
2202 const Vec4V twoPi = V4LoadA(g_PXTwoPi.f);
2203 const Vec4V tmp = V4Mul(a, recipTwoPi);
2204 const Vec4V b = V4Round(tmp);
2205 const Vec4V V1 = V4NegMulSub(twoPi, b, a);
2206
2207 // cos(V) ~= 1 - V^2 / 2! + V^4 / 4! - V^6 / 6! + V^8 / 8! - V^10 / 10! + V^12 / 12! -
2208 // V^14 / 14! + V^16 / 16! - V^18 / 18! + V^20 / 20! - V^22 / 22! (for -PI <= V < PI)
2209 const Vec4V V2 = V4Mul(V1, V1);
2210 const Vec4V V4 = V4Mul(V2, V2);
2211 const Vec4V V6 = V4Mul(V4, V2);
2212 const Vec4V V8 = V4Mul(V4, V4);
2213 const Vec4V V10 = V4Mul(V6, V4);
2214 const Vec4V V12 = V4Mul(V6, V6);
2215 const Vec4V V14 = V4Mul(V8, V6);
2216 const Vec4V V16 = V4Mul(V8, V8);
2217 const Vec4V V18 = V4Mul(V10, V8);
2218 const Vec4V V20 = V4Mul(V10, V10);
2219 const Vec4V V22 = V4Mul(V12, V10);
2220
2221 const Vec4V cosCoefficients0 = V4LoadA(g_PXCosCoefficients0.f);
2222 const Vec4V cosCoefficients1 = V4LoadA(g_PXCosCoefficients1.f);
2223 const Vec4V cosCoefficients2 = V4LoadA(g_PXCosCoefficients2.f);
2224
2225 const FloatV C1 = V4GetY(cosCoefficients0);
2226 const FloatV C2 = V4GetZ(cosCoefficients0);
2227 const FloatV C3 = V4GetW(cosCoefficients0);
2228 const FloatV C4 = V4GetX(cosCoefficients1);
2229 const FloatV C5 = V4GetY(cosCoefficients1);
2230 const FloatV C6 = V4GetZ(cosCoefficients1);
2231 const FloatV C7 = V4GetW(cosCoefficients1);
2232 const FloatV C8 = V4GetX(cosCoefficients2);
2233 const FloatV C9 = V4GetY(cosCoefficients2);
2234 const FloatV C10 = V4GetZ(cosCoefficients2);
2235 const FloatV C11 = V4GetW(cosCoefficients2);
2236
2237 Vec4V Result;
2238 Result = V4MulAdd(C1, V2, V4One());
2239 Result = V4MulAdd(C2, V4, Result);
2240 Result = V4MulAdd(C3, V6, Result);
2241 Result = V4MulAdd(C4, V8, Result);
2242 Result = V4MulAdd(C5, V10, Result);
2243 Result = V4MulAdd(C6, V12, Result);
2244 Result = V4MulAdd(C7, V14, Result);
2245 Result = V4MulAdd(C8, V16, Result);
2246 Result = V4MulAdd(C9, V18, Result);
2247 Result = V4MulAdd(C10, V20, Result);
2248 Result = V4MulAdd(C11, V22, Result);
2249
2250 return Result;
2251}
2252
2253PX_FORCE_INLINE void V4Transpose(Vec4V& col0, Vec4V& col1, Vec4V& col2, Vec4V& col3)
2254{
2255 Vec4V tmp0 = _mm_unpacklo_ps(col0, col1);
2256 Vec4V tmp2 = _mm_unpacklo_ps(col2, col3);
2257 Vec4V tmp1 = _mm_unpackhi_ps(col0, col1);
2258 Vec4V tmp3 = _mm_unpackhi_ps(col2, col3);
2259 col0 = _mm_movelh_ps(tmp0, tmp2);
2260 col1 = _mm_movehl_ps(tmp2, tmp0);
2261 col2 = _mm_movelh_ps(tmp1, tmp3);
2262 col3 = _mm_movehl_ps(tmp3, tmp1);
2263}
2264
2266// BoolV
2268
2269PX_FORCE_INLINE BoolV BFFFF()
2270{
2271 return _mm_setzero_ps();
2272}
2273
2274PX_FORCE_INLINE BoolV BFFFT()
2275{
2276 /*const PX_ALIGN(16, PxU32 f[4])={0,0,0,0xFFFFFFFF};
2277 const __m128 ffft=_mm_load_ps((float*)&f);
2278 return ffft;*/
2279 return m128_I2F(_mm_set_epi32(-1, 0, 0, 0));
2280}
2281
2282PX_FORCE_INLINE BoolV BFFTF()
2283{
2284 /*const PX_ALIGN(16, PxU32 f[4])={0,0,0xFFFFFFFF,0};
2285 const __m128 fftf=_mm_load_ps((float*)&f);
2286 return fftf;*/
2287 return m128_I2F(_mm_set_epi32(0, -1, 0, 0));
2288}
2289
2290PX_FORCE_INLINE BoolV BFFTT()
2291{
2292 /*const PX_ALIGN(16, PxU32 f[4])={0,0,0xFFFFFFFF,0xFFFFFFFF};
2293 const __m128 fftt=_mm_load_ps((float*)&f);
2294 return fftt;*/
2295 return m128_I2F(_mm_set_epi32(-1, -1, 0, 0));
2296}
2297
2298PX_FORCE_INLINE BoolV BFTFF()
2299{
2300 /*const PX_ALIGN(16, PxU32 f[4])={0,0xFFFFFFFF,0,0};
2301 const __m128 ftff=_mm_load_ps((float*)&f);
2302 return ftff;*/
2303 return m128_I2F(_mm_set_epi32(0, 0, -1, 0));
2304}
2305
2306PX_FORCE_INLINE BoolV BFTFT()
2307{
2308 /*const PX_ALIGN(16, PxU32 f[4])={0,0xFFFFFFFF,0,0xFFFFFFFF};
2309 const __m128 ftft=_mm_load_ps((float*)&f);
2310 return ftft;*/
2311 return m128_I2F(_mm_set_epi32(-1, 0, -1, 0));
2312}
2313
2314PX_FORCE_INLINE BoolV BFTTF()
2315{
2316 /*const PX_ALIGN(16, PxU32 f[4])={0,0xFFFFFFFF,0xFFFFFFFF,0};
2317 const __m128 fttf=_mm_load_ps((float*)&f);
2318 return fttf;*/
2319 return m128_I2F(_mm_set_epi32(0, -1, -1, 0));
2320}
2321
2322PX_FORCE_INLINE BoolV BFTTT()
2323{
2324 /*const PX_ALIGN(16, PxU32 f[4])={0,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF};
2325 const __m128 fttt=_mm_load_ps((float*)&f);
2326 return fttt;*/
2327 return m128_I2F(_mm_set_epi32(-1, -1, -1, 0));
2328}
2329
2330PX_FORCE_INLINE BoolV BTFFF()
2331{
2332 // const PX_ALIGN(16, PxU32 f[4])={0xFFFFFFFF,0,0,0};
2333 // const __m128 tfff=_mm_load_ps((float*)&f);
2334 // return tfff;
2335 return m128_I2F(_mm_set_epi32(0, 0, 0, -1));
2336}
2337
2338PX_FORCE_INLINE BoolV BTFFT()
2339{
2340 /*const PX_ALIGN(16, PxU32 f[4])={0xFFFFFFFF,0,0,0xFFFFFFFF};
2341 const __m128 tfft=_mm_load_ps((float*)&f);
2342 return tfft;*/
2343 return m128_I2F(_mm_set_epi32(-1, 0, 0, -1));
2344}
2345
2346PX_FORCE_INLINE BoolV BTFTF()
2347{
2348 /*const PX_ALIGN(16, PxU32 f[4])={0xFFFFFFFF,0,0xFFFFFFFF,0};
2349 const __m128 tftf=_mm_load_ps((float*)&f);
2350 return tftf;*/
2351 return m128_I2F(_mm_set_epi32(0, -1, 0, -1));
2352}
2353
2354PX_FORCE_INLINE BoolV BTFTT()
2355{
2356 /*const PX_ALIGN(16, PxU32 f[4])={0xFFFFFFFF,0,0xFFFFFFFF,0xFFFFFFFF};
2357 const __m128 tftt=_mm_load_ps((float*)&f);
2358 return tftt;*/
2359 return m128_I2F(_mm_set_epi32(-1, -1, 0, -1));
2360}
2361
2362PX_FORCE_INLINE BoolV BTTFF()
2363{
2364 /*const PX_ALIGN(16, PxU32 f[4])={0xFFFFFFFF,0xFFFFFFFF,0,0};
2365 const __m128 ttff=_mm_load_ps((float*)&f);
2366 return ttff;*/
2367 return m128_I2F(_mm_set_epi32(0, 0, -1, -1));
2368}
2369
2370PX_FORCE_INLINE BoolV BTTFT()
2371{
2372 /*const PX_ALIGN(16, PxU32 f[4])={0xFFFFFFFF,0xFFFFFFFF,0,0xFFFFFFFF};
2373 const __m128 ttft=_mm_load_ps((float*)&f);
2374 return ttft;*/
2375 return m128_I2F(_mm_set_epi32(-1, 0, -1, -1));
2376}
2377
2378PX_FORCE_INLINE BoolV BTTTF()
2379{
2380 /*const PX_ALIGN(16, PxU32 f[4])={0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0};
2381 const __m128 tttf=_mm_load_ps((float*)&f);
2382 return tttf;*/
2383 return m128_I2F(_mm_set_epi32(0, -1, -1, -1));
2384}
2385
2386PX_FORCE_INLINE BoolV BTTTT()
2387{
2388 /*const PX_ALIGN(16, PxU32 f[4])={0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF};
2389 const __m128 tttt=_mm_load_ps((float*)&f);
2390 return tttt;*/
2391 return m128_I2F(_mm_set_epi32(-1, -1, -1, -1));
2392}
2393
2394PX_FORCE_INLINE BoolV BXMask()
2395{
2396 /*const PX_ALIGN(16, PxU32 f[4])={0xFFFFFFFF,0,0,0};
2397 const __m128 tfff=_mm_load_ps((float*)&f);
2398 return tfff;*/
2399 return m128_I2F(_mm_set_epi32(0, 0, 0, -1));
2400}
2401
2402PX_FORCE_INLINE BoolV BYMask()
2403{
2404 /*const PX_ALIGN(16, PxU32 f[4])={0,0xFFFFFFFF,0,0};
2405 const __m128 ftff=_mm_load_ps((float*)&f);
2406 return ftff;*/
2407 return m128_I2F(_mm_set_epi32(0, 0, -1, 0));
2408}
2409
2410PX_FORCE_INLINE BoolV BZMask()
2411{
2412 /*const PX_ALIGN(16, PxU32 f[4])={0,0,0xFFFFFFFF,0};
2413 const __m128 fftf=_mm_load_ps((float*)&f);
2414 return fftf;*/
2415 return m128_I2F(_mm_set_epi32(0, -1, 0, 0));
2416}
2417
2418PX_FORCE_INLINE BoolV BWMask()
2419{
2420 /*const PX_ALIGN(16, PxU32 f[4])={0,0,0,0xFFFFFFFF};
2421 const __m128 ffft=_mm_load_ps((float*)&f);
2422 return ffft;*/
2423 return m128_I2F(_mm_set_epi32(-1, 0, 0, 0));
2424}
2425
2426PX_FORCE_INLINE BoolV BGetX(const BoolV f)
2427{
2428 return _mm_shuffle_ps(f, f, _MM_SHUFFLE(0, 0, 0, 0));
2429}
2430
2431PX_FORCE_INLINE BoolV BGetY(const BoolV f)
2432{
2433 return _mm_shuffle_ps(f, f, _MM_SHUFFLE(1, 1, 1, 1));
2434}
2435
2436PX_FORCE_INLINE BoolV BGetZ(const BoolV f)
2437{
2438 return _mm_shuffle_ps(f, f, _MM_SHUFFLE(2, 2, 2, 2));
2439}
2440
2441PX_FORCE_INLINE BoolV BGetW(const BoolV f)
2442{
2443 return _mm_shuffle_ps(f, f, _MM_SHUFFLE(3, 3, 3, 3));
2444}
2445
2446PX_FORCE_INLINE BoolV BSetX(const BoolV v, const BoolV f)
2447{
2448 return V4Sel(BFTTT(), v, f);
2449}
2450
2451PX_FORCE_INLINE BoolV BSetY(const BoolV v, const BoolV f)
2452{
2453 return V4Sel(BTFTT(), v, f);
2454}
2455
2456PX_FORCE_INLINE BoolV BSetZ(const BoolV v, const BoolV f)
2457{
2458 return V4Sel(BTTFT(), v, f);
2459}
2460
2461PX_FORCE_INLINE BoolV BSetW(const BoolV v, const BoolV f)
2462{
2463 return V4Sel(BTTTF(), v, f);
2464}
2465
2466PX_FORCE_INLINE BoolV BAnd(const BoolV a, const BoolV b)
2467{
2468 return _mm_and_ps(a, b);
2469}
2470
2471PX_FORCE_INLINE BoolV BNot(const BoolV a)
2472{
2473 const BoolV bAllTrue(BTTTT());
2474 return _mm_xor_ps(a, bAllTrue);
2475}
2476
2477PX_FORCE_INLINE BoolV BAndNot(const BoolV a, const BoolV b)
2478{
2479 return _mm_andnot_ps(b, a);
2480}
2481
2482PX_FORCE_INLINE BoolV BOr(const BoolV a, const BoolV b)
2483{
2484 return _mm_or_ps(a, b);
2485}
2486
2487PX_FORCE_INLINE BoolV BAllTrue4(const BoolV a)
2488{
2489 const BoolV bTmp =
2490 _mm_and_ps(_mm_shuffle_ps(a, a, _MM_SHUFFLE(0, 1, 0, 1)), _mm_shuffle_ps(a, a, _MM_SHUFFLE(2, 3, 2, 3)));
2491 return _mm_and_ps(_mm_shuffle_ps(bTmp, bTmp, _MM_SHUFFLE(0, 0, 0, 0)),
2492 _mm_shuffle_ps(bTmp, bTmp, _MM_SHUFFLE(1, 1, 1, 1)));
2493}
2494
2495PX_FORCE_INLINE BoolV BAnyTrue4(const BoolV a)
2496{
2497 const BoolV bTmp =
2498 _mm_or_ps(_mm_shuffle_ps(a, a, _MM_SHUFFLE(0, 1, 0, 1)), _mm_shuffle_ps(a, a, _MM_SHUFFLE(2, 3, 2, 3)));
2499 return _mm_or_ps(_mm_shuffle_ps(bTmp, bTmp, _MM_SHUFFLE(0, 0, 0, 0)),
2500 _mm_shuffle_ps(bTmp, bTmp, _MM_SHUFFLE(1, 1, 1, 1)));
2501}
2502
2503PX_FORCE_INLINE BoolV BAllTrue3(const BoolV a)
2504{
2505 const BoolV bTmp =
2506 _mm_and_ps(_mm_shuffle_ps(a, a, _MM_SHUFFLE(0, 1, 0, 1)), _mm_shuffle_ps(a, a, _MM_SHUFFLE(2, 2, 2, 2)));
2507 return _mm_and_ps(_mm_shuffle_ps(bTmp, bTmp, _MM_SHUFFLE(0, 0, 0, 0)),
2508 _mm_shuffle_ps(bTmp, bTmp, _MM_SHUFFLE(1, 1, 1, 1)));
2509}
2510
2511PX_FORCE_INLINE BoolV BAnyTrue3(const BoolV a)
2512{
2513 const BoolV bTmp =
2514 _mm_or_ps(_mm_shuffle_ps(a, a, _MM_SHUFFLE(0, 1, 0, 1)), _mm_shuffle_ps(a, a, _MM_SHUFFLE(2, 2, 2, 2)));
2515 return _mm_or_ps(_mm_shuffle_ps(bTmp, bTmp, _MM_SHUFFLE(0, 0, 0, 0)),
2516 _mm_shuffle_ps(bTmp, bTmp, _MM_SHUFFLE(1, 1, 1, 1)));
2517}
2518
2519PX_FORCE_INLINE PxU32 BAllEq(const BoolV a, const BoolV b)
2520{
2521 const BoolV bTest = m128_I2F(_mm_cmpeq_epi32(m128_F2I(a), m128_F2I(b)));
2522 return internalUnitSSE2Simd::BAllTrue4_R(bTest);
2523}
2524
2525PX_FORCE_INLINE PxU32 BAllEqTTTT(const BoolV a)
2526{
2527 return PxU32(_mm_movemask_ps(a)==15);
2528}
2529
2530PX_FORCE_INLINE PxU32 BAllEqFFFF(const BoolV a)
2531{
2532 return PxU32(_mm_movemask_ps(a)==0);
2533}
2534
2535PX_FORCE_INLINE PxU32 BGetBitMask(const BoolV a)
2536{
2537 return PxU32(_mm_movemask_ps(a));
2538}
2539
2541// MAT33V
2543
2544PX_FORCE_INLINE Vec3V M33MulV3(const Mat33V& a, const Vec3V b)
2545{
2546 const FloatV x = V3GetX(b);
2547 const FloatV y = V3GetY(b);
2548 const FloatV z = V3GetZ(b);
2549 const Vec3V v0 = V3Scale(a.col0, x);
2550 const Vec3V v1 = V3Scale(a.col1, y);
2551 const Vec3V v2 = V3Scale(a.col2, z);
2552 const Vec3V v0PlusV1 = V3Add(v0, v1);
2553 return V3Add(v0PlusV1, v2);
2554}
2555
2556PX_FORCE_INLINE Vec3V M33TrnspsMulV3(const Mat33V& a, const Vec3V b)
2557{
2558 const FloatV x = V3Dot(a.col0, b);
2559 const FloatV y = V3Dot(a.col1, b);
2560 const FloatV z = V3Dot(a.col2, b);
2561 return V3Merge(x, y, z);
2562}
2563
2564PX_FORCE_INLINE Vec3V M33MulV3AddV3(const Mat33V& A, const Vec3V b, const Vec3V c)
2565{
2566 const FloatV x = V3GetX(b);
2567 const FloatV y = V3GetY(b);
2568 const FloatV z = V3GetZ(b);
2569 Vec3V result = V3ScaleAdd(A.col0, x, c);
2570 result = V3ScaleAdd(A.col1, y, result);
2571 return V3ScaleAdd(A.col2, z, result);
2572}
2573
2574PX_FORCE_INLINE Mat33V M33MulM33(const Mat33V& a, const Mat33V& b)
2575{
2576 return Mat33V(M33MulV3(a, b.col0), M33MulV3(a, b.col1), M33MulV3(a, b.col2));
2577}
2578
2579PX_FORCE_INLINE Mat33V M33Add(const Mat33V& a, const Mat33V& b)
2580{
2581 return Mat33V(V3Add(a.col0, b.col0), V3Add(a.col1, b.col1), V3Add(a.col2, b.col2));
2582}
2583
2584PX_FORCE_INLINE Mat33V M33Scale(const Mat33V& a, const FloatV& b)
2585{
2586 return Mat33V(V3Scale(a.col0, b), V3Scale(a.col1, b), V3Scale(a.col2, b));
2587}
2588
2589PX_FORCE_INLINE Mat33V M33Inverse(const Mat33V& a)
2590{
2591 const BoolV tfft = BTFFT();
2592 const BoolV tttf = BTTTF();
2593 const FloatV zero = FZero();
2594 const Vec3V cross01 = V3Cross(a.col0, a.col1);
2595 const Vec3V cross12 = V3Cross(a.col1, a.col2);
2596 const Vec3V cross20 = V3Cross(a.col2, a.col0);
2597 const FloatV dot = V3Dot(cross01, a.col2);
2598 const FloatV invDet = _mm_rcp_ps(dot);
2599 const Vec3V mergeh = _mm_unpacklo_ps(cross12, cross01);
2600 const Vec3V mergel = _mm_unpackhi_ps(cross12, cross01);
2601 Vec3V colInv0 = _mm_unpacklo_ps(mergeh, cross20);
2602 colInv0 = _mm_or_ps(_mm_andnot_ps(tttf, zero), _mm_and_ps(tttf, colInv0));
2603 const Vec3V zppd = _mm_shuffle_ps(mergeh, cross20, _MM_SHUFFLE(3, 0, 0, 2));
2604 const Vec3V pbwp = _mm_shuffle_ps(cross20, mergeh, _MM_SHUFFLE(3, 3, 1, 0));
2605 const Vec3V colInv1 = _mm_or_ps(_mm_andnot_ps(BTFFT(), pbwp), _mm_and_ps(BTFFT(), zppd));
2606 const Vec3V xppd = _mm_shuffle_ps(mergel, cross20, _MM_SHUFFLE(3, 0, 0, 0));
2607 const Vec3V pcyp = _mm_shuffle_ps(cross20, mergel, _MM_SHUFFLE(3, 1, 2, 0));
2608 const Vec3V colInv2 = _mm_or_ps(_mm_andnot_ps(tfft, pcyp), _mm_and_ps(tfft, xppd));
2609
2610 return Mat33V(_mm_mul_ps(colInv0, invDet), _mm_mul_ps(colInv1, invDet), _mm_mul_ps(colInv2, invDet));
2611}
2612
2613PX_FORCE_INLINE Mat33V M33Trnsps(const Mat33V& a)
2614{
2615 return Mat33V(V3Merge(V3GetX(a.col0), V3GetX(a.col1), V3GetX(a.col2)),
2616 V3Merge(V3GetY(a.col0), V3GetY(a.col1), V3GetY(a.col2)),
2617 V3Merge(V3GetZ(a.col0), V3GetZ(a.col1), V3GetZ(a.col2)));
2618}
2619
2620PX_FORCE_INLINE Mat33V M33Identity()
2621{
2622 return Mat33V(V3UnitX(), V3UnitY(), V3UnitZ());
2623}
2624
2625PX_FORCE_INLINE Mat33V M33Sub(const Mat33V& a, const Mat33V& b)
2626{
2627 return Mat33V(V3Sub(a.col0, b.col0), V3Sub(a.col1, b.col1), V3Sub(a.col2, b.col2));
2628}
2629
2630PX_FORCE_INLINE Mat33V M33Neg(const Mat33V& a)
2631{
2632 return Mat33V(V3Neg(a.col0), V3Neg(a.col1), V3Neg(a.col2));
2633}
2634
2635PX_FORCE_INLINE Mat33V M33Abs(const Mat33V& a)
2636{
2637 return Mat33V(V3Abs(a.col0), V3Abs(a.col1), V3Abs(a.col2));
2638}
2639
2640PX_FORCE_INLINE Mat33V PromoteVec3V(const Vec3V v)
2641{
2642 const BoolV bTFFF = BTFFF();
2643 const BoolV bFTFF = BFTFF();
2644 const BoolV bFFTF = BTFTF();
2645
2646 const Vec3V zero = V3Zero();
2647
2648 return Mat33V(V3Sel(bTFFF, v, zero), V3Sel(bFTFF, v, zero), V3Sel(bFFTF, v, zero));
2649}
2650
2651PX_FORCE_INLINE Mat33V M33Diagonal(const Vec3VArg d)
2652{
2653 const FloatV x = V3Mul(V3UnitX(), d);
2654 const FloatV y = V3Mul(V3UnitY(), d);
2655 const FloatV z = V3Mul(V3UnitZ(), d);
2656 return Mat33V(x, y, z);
2657}
2658
2660// MAT34V
2662
2663PX_FORCE_INLINE Vec3V M34MulV3(const Mat34V& a, const Vec3V b)
2664{
2665 const FloatV x = V3GetX(b);
2666 const FloatV y = V3GetY(b);
2667 const FloatV z = V3GetZ(b);
2668 const Vec3V v0 = V3Scale(a.col0, x);
2669 const Vec3V v1 = V3Scale(a.col1, y);
2670 const Vec3V v2 = V3Scale(a.col2, z);
2671 const Vec3V v0PlusV1 = V3Add(v0, v1);
2672 const Vec3V v0PlusV1Plusv2 = V3Add(v0PlusV1, v2);
2673 return V3Add(v0PlusV1Plusv2, a.col3);
2674}
2675
2676PX_FORCE_INLINE Vec3V M34Mul33V3(const Mat34V& a, const Vec3V b)
2677{
2678 const FloatV x = V3GetX(b);
2679 const FloatV y = V3GetY(b);
2680 const FloatV z = V3GetZ(b);
2681 const Vec3V v0 = V3Scale(a.col0, x);
2682 const Vec3V v1 = V3Scale(a.col1, y);
2683 const Vec3V v2 = V3Scale(a.col2, z);
2684 const Vec3V v0PlusV1 = V3Add(v0, v1);
2685 return V3Add(v0PlusV1, v2);
2686}
2687
2688PX_FORCE_INLINE Vec3V M34TrnspsMul33V3(const Mat34V& a, const Vec3V b)
2689{
2690 const FloatV x = V3Dot(a.col0, b);
2691 const FloatV y = V3Dot(a.col1, b);
2692 const FloatV z = V3Dot(a.col2, b);
2693 return V3Merge(x, y, z);
2694}
2695
2696PX_FORCE_INLINE Mat34V M34MulM34(const Mat34V& a, const Mat34V& b)
2697{
2698 return Mat34V(M34Mul33V3(a, b.col0), M34Mul33V3(a, b.col1), M34Mul33V3(a, b.col2), M34MulV3(a, b.col3));
2699}
2700
2701PX_FORCE_INLINE Mat33V M34MulM33(const Mat34V& a, const Mat33V& b)
2702{
2703 return Mat33V(M34Mul33V3(a, b.col0), M34Mul33V3(a, b.col1), M34Mul33V3(a, b.col2));
2704}
2705
2706PX_FORCE_INLINE Mat33V M34Mul33MM34(const Mat34V& a, const Mat34V& b)
2707{
2708 return Mat33V(M34Mul33V3(a, b.col0), M34Mul33V3(a, b.col1), M34Mul33V3(a, b.col2));
2709}
2710
2711PX_FORCE_INLINE Mat34V M34Add(const Mat34V& a, const Mat34V& b)
2712{
2713 return Mat34V(V3Add(a.col0, b.col0), V3Add(a.col1, b.col1), V3Add(a.col2, b.col2), V3Add(a.col3, b.col3));
2714}
2715
2716PX_FORCE_INLINE Mat33V M34Trnsps33(const Mat34V& a)
2717{
2718 return Mat33V(V3Merge(V3GetX(a.col0), V3GetX(a.col1), V3GetX(a.col2)),
2719 V3Merge(V3GetY(a.col0), V3GetY(a.col1), V3GetY(a.col2)),
2720 V3Merge(V3GetZ(a.col0), V3GetZ(a.col1), V3GetZ(a.col2)));
2721}
2722
2724// MAT44V
2726
2727PX_FORCE_INLINE Vec4V M44MulV4(const Mat44V& a, const Vec4V b)
2728{
2729 const FloatV x = V4GetX(b);
2730 const FloatV y = V4GetY(b);
2731 const FloatV z = V4GetZ(b);
2732 const FloatV w = V4GetW(b);
2733
2734 const Vec4V v0 = V4Scale(a.col0, x);
2735 const Vec4V v1 = V4Scale(a.col1, y);
2736 const Vec4V v2 = V4Scale(a.col2, z);
2737 const Vec4V v3 = V4Scale(a.col3, w);
2738 const Vec4V v0PlusV1 = V4Add(v0, v1);
2739 const Vec4V v0PlusV1Plusv2 = V4Add(v0PlusV1, v2);
2740 return V4Add(v0PlusV1Plusv2, v3);
2741}
2742
2743PX_FORCE_INLINE Vec4V M44TrnspsMulV4(const Mat44V& a, const Vec4V b)
2744{
2745 PX_ALIGN(16, FloatV) dotProdArray[4] = { V4Dot(a.col0, b), V4Dot(a.col1, b), V4Dot(a.col2, b), V4Dot(a.col3, b) };
2746 return V4Merge(dotProdArray);
2747}
2748
2749PX_FORCE_INLINE Mat44V M44MulM44(const Mat44V& a, const Mat44V& b)
2750{
2751 return Mat44V(M44MulV4(a, b.col0), M44MulV4(a, b.col1), M44MulV4(a, b.col2), M44MulV4(a, b.col3));
2752}
2753
2754PX_FORCE_INLINE Mat44V M44Add(const Mat44V& a, const Mat44V& b)
2755{
2756 return Mat44V(V4Add(a.col0, b.col0), V4Add(a.col1, b.col1), V4Add(a.col2, b.col2), V4Add(a.col3, b.col3));
2757}
2758
2759PX_FORCE_INLINE Mat44V M44Trnsps(const Mat44V& a)
2760{
2761 const Vec4V v0 = _mm_unpacklo_ps(a.col0, a.col2);
2762 const Vec4V v1 = _mm_unpackhi_ps(a.col0, a.col2);
2763 const Vec4V v2 = _mm_unpacklo_ps(a.col1, a.col3);
2764 const Vec4V v3 = _mm_unpackhi_ps(a.col1, a.col3);
2765 return Mat44V(_mm_unpacklo_ps(v0, v2), _mm_unpackhi_ps(v0, v2), _mm_unpacklo_ps(v1, v3), _mm_unpackhi_ps(v1, v3));
2766}
2767
2768PX_FORCE_INLINE Mat44V M44Inverse(const Mat44V& a)
2769{
2770 __m128 minor0, minor1, minor2, minor3;
2771 __m128 row0, row1, row2, row3;
2772 __m128 det, tmp1;
2773
2774 tmp1 = V4Zero();
2775 row1 = V4Zero();
2776 row3 = V4Zero();
2777
2778 row0 = a.col0;
2779 row1 = _mm_shuffle_ps(a.col1, a.col1, _MM_SHUFFLE(1, 0, 3, 2));
2780 row2 = a.col2;
2781 row3 = _mm_shuffle_ps(a.col3, a.col3, _MM_SHUFFLE(1, 0, 3, 2));
2782
2783 tmp1 = _mm_mul_ps(row2, row3);
2784 tmp1 = _mm_shuffle_ps(tmp1, tmp1, 0xB1);
2785 minor0 = _mm_mul_ps(row1, tmp1);
2786 minor1 = _mm_mul_ps(row0, tmp1);
2787 tmp1 = _mm_shuffle_ps(tmp1, tmp1, 0x4E);
2788 minor0 = _mm_sub_ps(_mm_mul_ps(row1, tmp1), minor0);
2789 minor1 = _mm_sub_ps(_mm_mul_ps(row0, tmp1), minor1);
2790 minor1 = _mm_shuffle_ps(minor1, minor1, 0x4E);
2791
2792 tmp1 = _mm_mul_ps(row1, row2);
2793 tmp1 = _mm_shuffle_ps(tmp1, tmp1, 0xB1);
2794 minor0 = _mm_add_ps(_mm_mul_ps(row3, tmp1), minor0);
2795 minor3 = _mm_mul_ps(row0, tmp1);
2796 tmp1 = _mm_shuffle_ps(tmp1, tmp1, 0x4E);
2797 minor0 = _mm_sub_ps(minor0, _mm_mul_ps(row3, tmp1));
2798 minor3 = _mm_sub_ps(_mm_mul_ps(row0, tmp1), minor3);
2799 minor3 = _mm_shuffle_ps(minor3, minor3, 0x4E);
2800
2801 tmp1 = _mm_mul_ps(_mm_shuffle_ps(row1, row1, 0x4E), row3);
2802 tmp1 = _mm_shuffle_ps(tmp1, tmp1, 0xB1);
2803 row2 = _mm_shuffle_ps(row2, row2, 0x4E);
2804 minor0 = _mm_add_ps(_mm_mul_ps(row2, tmp1), minor0);
2805 minor2 = _mm_mul_ps(row0, tmp1);
2806 tmp1 = _mm_shuffle_ps(tmp1, tmp1, 0x4E);
2807 minor0 = _mm_sub_ps(minor0, _mm_mul_ps(row2, tmp1));
2808 minor2 = _mm_sub_ps(_mm_mul_ps(row0, tmp1), minor2);
2809 minor2 = _mm_shuffle_ps(minor2, minor2, 0x4E);
2810
2811 tmp1 = _mm_mul_ps(row0, row1);
2812 tmp1 = _mm_shuffle_ps(tmp1, tmp1, 0xB1);
2813 minor2 = _mm_add_ps(_mm_mul_ps(row3, tmp1), minor2);
2814 minor3 = _mm_sub_ps(_mm_mul_ps(row2, tmp1), minor3);
2815 tmp1 = _mm_shuffle_ps(tmp1, tmp1, 0x4E);
2816 minor2 = _mm_sub_ps(_mm_mul_ps(row3, tmp1), minor2);
2817 minor3 = _mm_sub_ps(minor3, _mm_mul_ps(row2, tmp1));
2818
2819 tmp1 = _mm_mul_ps(row0, row3);
2820 tmp1 = _mm_shuffle_ps(tmp1, tmp1, 0xB1);
2821 minor1 = _mm_sub_ps(minor1, _mm_mul_ps(row2, tmp1));
2822 minor2 = _mm_add_ps(_mm_mul_ps(row1, tmp1), minor2);
2823 tmp1 = _mm_shuffle_ps(tmp1, tmp1, 0x4E);
2824 minor1 = _mm_add_ps(_mm_mul_ps(row2, tmp1), minor1);
2825 minor2 = _mm_sub_ps(minor2, _mm_mul_ps(row1, tmp1));
2826
2827 tmp1 = _mm_mul_ps(row0, row2);
2828 tmp1 = _mm_shuffle_ps(tmp1, tmp1, 0xB1);
2829 minor1 = _mm_add_ps(_mm_mul_ps(row3, tmp1), minor1);
2830 minor3 = _mm_sub_ps(minor3, _mm_mul_ps(row1, tmp1));
2831 tmp1 = _mm_shuffle_ps(tmp1, tmp1, 0x4E);
2832 minor1 = _mm_sub_ps(minor1, _mm_mul_ps(row3, tmp1));
2833 minor3 = _mm_add_ps(_mm_mul_ps(row1, tmp1), minor3);
2834
2835 det = _mm_mul_ps(row0, minor0);
2836 det = _mm_add_ps(_mm_shuffle_ps(det, det, 0x4E), det);
2837 det = _mm_add_ss(_mm_shuffle_ps(det, det, 0xB1), det);
2838 tmp1 = _mm_rcp_ss(det);
2839#if 0
2840 det = _mm_sub_ss(_mm_add_ss(tmp1, tmp1), _mm_mul_ss(det, _mm_mul_ss(tmp1, tmp1)));
2841 det = _mm_shuffle_ps(det, det, 0x00);
2842#else
2843 det = _mm_shuffle_ps(tmp1, tmp1, _MM_SHUFFLE(0, 0, 0, 0));
2844#endif
2845
2846 minor0 = _mm_mul_ps(det, minor0);
2847 minor1 = _mm_mul_ps(det, minor1);
2848 minor2 = _mm_mul_ps(det, minor2);
2849 minor3 = _mm_mul_ps(det, minor3);
2850 Mat44V invTrans(minor0, minor1, minor2, minor3);
2851 return M44Trnsps(invTrans);
2852}
2853
2854PX_FORCE_INLINE Vec4V V4LoadXYZW(const PxF32& x, const PxF32& y, const PxF32& z, const PxF32& w)
2855{
2856 return _mm_set_ps(w, z, y, x);
2857}
2858
2859/*
2860// AP: work in progress - use proper SSE intrinsics where possible
2861PX_FORCE_INLINE VecU16V V4U32PK(VecU32V a, VecU32V b)
2862{
2863 VecU16V result;
2864 result.m128_u16[0] = PxU16(PxClamp<PxU32>((a).m128_u32[0], 0, 0xFFFF));
2865 result.m128_u16[1] = PxU16(PxClamp<PxU32>((a).m128_u32[1], 0, 0xFFFF));
2866 result.m128_u16[2] = PxU16(PxClamp<PxU32>((a).m128_u32[2], 0, 0xFFFF));
2867 result.m128_u16[3] = PxU16(PxClamp<PxU32>((a).m128_u32[3], 0, 0xFFFF));
2868 result.m128_u16[4] = PxU16(PxClamp<PxU32>((b).m128_u32[0], 0, 0xFFFF));
2869 result.m128_u16[5] = PxU16(PxClamp<PxU32>((b).m128_u32[1], 0, 0xFFFF));
2870 result.m128_u16[6] = PxU16(PxClamp<PxU32>((b).m128_u32[2], 0, 0xFFFF));
2871 result.m128_u16[7] = PxU16(PxClamp<PxU32>((b).m128_u32[3], 0, 0xFFFF));
2872 return result;
2873}
2874*/
2875
2876PX_FORCE_INLINE VecU32V V4U32Sel(const BoolV c, const VecU32V a, const VecU32V b)
2877{
2878 return m128_I2F(_mm_or_si128(_mm_andnot_si128(m128_F2I(c), m128_F2I(b)), _mm_and_si128(m128_F2I(c), m128_F2I(a))));
2879}
2880
2881PX_FORCE_INLINE VecU32V V4U32or(VecU32V a, VecU32V b)
2882{
2883 return m128_I2F(_mm_or_si128(m128_F2I(a), m128_F2I(b)));
2884}
2885
2886PX_FORCE_INLINE VecU32V V4U32xor(VecU32V a, VecU32V b)
2887{
2888 return m128_I2F(_mm_xor_si128(m128_F2I(a), m128_F2I(b)));
2889}
2890
2891PX_FORCE_INLINE VecU32V V4U32and(VecU32V a, VecU32V b)
2892{
2893 return m128_I2F(_mm_and_si128(m128_F2I(a), m128_F2I(b)));
2894}
2895
2896PX_FORCE_INLINE VecU32V V4U32Andc(VecU32V a, VecU32V b)
2897{
2898 return m128_I2F(_mm_andnot_si128(m128_F2I(b), m128_F2I(a)));
2899}
2900
2901/*
2902PX_FORCE_INLINE VecU16V V4U16Or(VecU16V a, VecU16V b)
2903{
2904 return m128_I2F(_mm_or_si128(m128_F2I(a), m128_F2I(b)));
2905}
2906*/
2907
2908/*
2909PX_FORCE_INLINE VecU16V V4U16And(VecU16V a, VecU16V b)
2910{
2911 return m128_I2F(_mm_and_si128(m128_F2I(a), m128_F2I(b)));
2912}
2913*/
2914
2915/*
2916PX_FORCE_INLINE VecU16V V4U16Andc(VecU16V a, VecU16V b)
2917{
2918 return m128_I2F(_mm_andnot_si128(m128_F2I(b), m128_F2I(a)));
2919}
2920*/
2921
2922PX_FORCE_INLINE VecI32V I4Load(const PxI32 i)
2923{
2924 return m128_F2I(_mm_load1_ps(reinterpret_cast<const PxF32*>(&i)));
2925}
2926
2927PX_FORCE_INLINE VecI32V I4LoadU(const PxI32* i)
2928{
2929 return m128_F2I(_mm_loadu_ps(reinterpret_cast<const PxF32*>(i)));
2930}
2931
2932PX_FORCE_INLINE VecI32V I4LoadA(const PxI32* i)
2933{
2934 return m128_F2I(_mm_load_ps(reinterpret_cast<const PxF32*>(i)));
2935}
2936
2937PX_FORCE_INLINE VecI32V VecI32V_Add(const VecI32VArg a, const VecI32VArg b)
2938{
2939 return _mm_add_epi32(a, b);
2940}
2941
2942PX_FORCE_INLINE VecI32V VecI32V_Sub(const VecI32VArg a, const VecI32VArg b)
2943{
2944 return _mm_sub_epi32(a, b);
2945}
2946
2947PX_FORCE_INLINE BoolV VecI32V_IsGrtr(const VecI32VArg a, const VecI32VArg b)
2948{
2949 return m128_I2F(_mm_cmpgt_epi32(a, b));
2950}
2951
2952PX_FORCE_INLINE BoolV VecI32V_IsEq(const VecI32VArg a, const VecI32VArg b)
2953{
2954 return m128_I2F(_mm_cmpeq_epi32(a, b));
2955}
2956
2957PX_FORCE_INLINE VecI32V V4I32Sel(const BoolV c, const VecI32V a, const VecI32V b)
2958{
2959 return _mm_or_si128(_mm_andnot_si128(m128_F2I(c), b), _mm_and_si128(m128_F2I(c), a));
2960}
2961
2962PX_FORCE_INLINE VecI32V VecI32V_Zero()
2963{
2964 return _mm_setzero_si128();
2965}
2966
2967PX_FORCE_INLINE VecI32V VecI32V_One()
2968{
2969 return I4Load(1);
2970}
2971
2972PX_FORCE_INLINE VecI32V VecI32V_Two()
2973{
2974 return I4Load(2);
2975}
2976
2977PX_FORCE_INLINE VecI32V VecI32V_MinusOne()
2978{
2979 return I4Load(-1);
2980}
2981
2982PX_FORCE_INLINE VecU32V U4Zero()
2983{
2984 return U4Load(0);
2985}
2986
2987PX_FORCE_INLINE VecU32V U4One()
2988{
2989 return U4Load(1);
2990}
2991
2992PX_FORCE_INLINE VecU32V U4Two()
2993{
2994 return U4Load(2);
2995}
2996
2997PX_FORCE_INLINE VecI32V VecI32V_Sel(const BoolV c, const VecI32VArg a, const VecI32VArg b)
2998{
2999 return _mm_or_si128(_mm_andnot_si128(m128_F2I(c), b), _mm_and_si128(m128_F2I(c), a));
3000}
3001
3002PX_FORCE_INLINE VecShiftV VecI32V_PrepareShift(const VecI32VArg shift)
3003{
3004 VecShiftV s;
3005 s.shift = VecI32V_Sel(BTFFF(), shift, VecI32V_Zero());
3006 return s;
3007}
3008
3009PX_FORCE_INLINE VecI32V VecI32V_LeftShift(const VecI32VArg a, const VecShiftVArg count)
3010{
3011 return _mm_sll_epi32(a, count.shift);
3012}
3013
3014PX_FORCE_INLINE VecI32V VecI32V_RightShift(const VecI32VArg a, const VecShiftVArg count)
3015{
3016 return _mm_srl_epi32(a, count.shift);
3017}
3018
3019PX_FORCE_INLINE VecI32V VecI32V_LeftShift(const VecI32VArg a, const PxU32 count)
3020{
3021 return _mm_slli_epi32(a, PxI32(count));
3022}
3023
3024PX_FORCE_INLINE VecI32V VecI32V_RightShift(const VecI32VArg a, const PxU32 count)
3025{
3026 return _mm_srai_epi32(a, PxI32(count));
3027}
3028
3029PX_FORCE_INLINE VecI32V VecI32V_And(const VecI32VArg a, const VecI32VArg b)
3030{
3031 return _mm_and_si128(a, b);
3032}
3033
3034PX_FORCE_INLINE VecI32V VecI32V_Or(const VecI32VArg a, const VecI32VArg b)
3035{
3036 return _mm_or_si128(a, b);
3037}
3038
3039PX_FORCE_INLINE VecI32V VecI32V_GetX(const VecI32VArg a)
3040{
3041 return m128_F2I(_mm_shuffle_ps(m128_I2F(a), m128_I2F(a), _MM_SHUFFLE(0, 0, 0, 0)));
3042}
3043
3044PX_FORCE_INLINE VecI32V VecI32V_GetY(const VecI32VArg a)
3045{
3046 return m128_F2I(_mm_shuffle_ps(m128_I2F(a), m128_I2F(a), _MM_SHUFFLE(1, 1, 1, 1)));
3047}
3048
3049PX_FORCE_INLINE VecI32V VecI32V_GetZ(const VecI32VArg a)
3050{
3051 return m128_F2I(_mm_shuffle_ps(m128_I2F(a), m128_I2F(a), _MM_SHUFFLE(2, 2, 2, 2)));
3052}
3053
3054PX_FORCE_INLINE VecI32V VecI32V_GetW(const VecI32VArg a)
3055{
3056 return m128_F2I(_mm_shuffle_ps(m128_I2F(a), m128_I2F(a), _MM_SHUFFLE(3, 3, 3, 3)));
3057}
3058
3059PX_FORCE_INLINE void PxI32_From_VecI32V(const VecI32VArg a, PxI32* i)
3060{
3061 _mm_store_ss(reinterpret_cast<PxF32*>(i), m128_I2F(a));
3062}
3063
3064PX_FORCE_INLINE VecI32V VecI32V_Merge(const VecI32VArg x, const VecI32VArg y, const VecI32VArg z, const VecI32VArg w)
3065{
3066 const __m128 xw = _mm_move_ss(m128_I2F(y), m128_I2F(x)); // y, y, y, x
3067 const __m128 yz = _mm_move_ss(m128_I2F(z), m128_I2F(w)); // z, z, z, w
3068 return m128_F2I(_mm_shuffle_ps(xw, yz, _MM_SHUFFLE(0, 2, 1, 0)));
3069}
3070
3071PX_FORCE_INLINE VecI32V VecI32V_From_BoolV(const BoolVArg a)
3072{
3073 return m128_F2I(a);
3074}
3075
3076PX_FORCE_INLINE VecU32V VecU32V_From_BoolV(const BoolVArg a)
3077{
3078 return a;
3079}
3080
3081/*
3082template<int a> PX_FORCE_INLINE VecI32V V4ISplat()
3083{
3084 VecI32V result;
3085 result.m128_i32[0] = a;
3086 result.m128_i32[1] = a;
3087 result.m128_i32[2] = a;
3088 result.m128_i32[3] = a;
3089 return result;
3090}
3091
3092template<PxU32 a> PX_FORCE_INLINE VecU32V V4USplat()
3093{
3094 VecU32V result;
3095 result.m128_u32[0] = a;
3096 result.m128_u32[1] = a;
3097 result.m128_u32[2] = a;
3098 result.m128_u32[3] = a;
3099 return result;
3100}
3101*/
3102
3103/*
3104PX_FORCE_INLINE void V4U16StoreAligned(VecU16V val, VecU16V* address)
3105{
3106 *address = val;
3107}
3108*/
3109
3110PX_FORCE_INLINE void V4U32StoreAligned(VecU32V val, VecU32V* address)
3111{
3112 *address = val;
3113}
3114
3115PX_FORCE_INLINE Vec4V V4LoadAligned(Vec4V* addr)
3116{
3117 return *addr;
3118}
3119
3120PX_FORCE_INLINE Vec4V V4LoadUnaligned(Vec4V* addr)
3121{
3122 return V4LoadU(reinterpret_cast<float*>(addr));
3123}
3124
3125PX_FORCE_INLINE Vec4V V4Andc(const Vec4V a, const VecU32V b)
3126{
3127 VecU32V result32(a);
3128 result32 = V4U32Andc(result32, b);
3129 return Vec4V(result32);
3130}
3131
3132PX_FORCE_INLINE VecU32V V4IsGrtrV32u(const Vec4V a, const Vec4V b)
3133{
3134 return V4IsGrtr(a, b);
3135}
3136
3137PX_FORCE_INLINE VecU16V V4U16LoadAligned(VecU16V* addr)
3138{
3139 return *addr;
3140}
3141
3142PX_FORCE_INLINE VecU16V V4U16LoadUnaligned(VecU16V* addr)
3143{
3144 return *addr;
3145}
3146
3147PX_FORCE_INLINE VecU16V V4U16CompareGt(VecU16V a, VecU16V b)
3148{
3149 // _mm_cmpgt_epi16 doesn't work for unsigned values unfortunately
3150 // return m128_I2F(_mm_cmpgt_epi16(m128_F2I(a), m128_F2I(b)));
3151 VecU16V result;
3152 result.m128_u16[0] = (a).m128_u16[0] > (b).m128_u16[0];
3153 result.m128_u16[1] = (a).m128_u16[1] > (b).m128_u16[1];
3154 result.m128_u16[2] = (a).m128_u16[2] > (b).m128_u16[2];
3155 result.m128_u16[3] = (a).m128_u16[3] > (b).m128_u16[3];
3156 result.m128_u16[4] = (a).m128_u16[4] > (b).m128_u16[4];
3157 result.m128_u16[5] = (a).m128_u16[5] > (b).m128_u16[5];
3158 result.m128_u16[6] = (a).m128_u16[6] > (b).m128_u16[6];
3159 result.m128_u16[7] = (a).m128_u16[7] > (b).m128_u16[7];
3160 return result;
3161}
3162
3163PX_FORCE_INLINE VecU16V V4I16CompareGt(VecU16V a, VecU16V b)
3164{
3165 return m128_I2F(_mm_cmpgt_epi16(m128_F2I(a), m128_F2I(b)));
3166}
3167
3168PX_FORCE_INLINE Vec4V Vec4V_From_VecU32V(VecU32V a)
3169{
3170 Vec4V result = V4LoadXYZW(PxF32(a.m128_u32[0]), PxF32(a.m128_u32[1]), PxF32(a.m128_u32[2]), PxF32(a.m128_u32[3]));
3171 return result;
3172}
3173
3174PX_FORCE_INLINE Vec4V Vec4V_From_VecI32V(VecI32V in)
3175{
3176 return _mm_cvtepi32_ps(in);
3177}
3178
3179PX_FORCE_INLINE VecI32V VecI32V_From_Vec4V(Vec4V a)
3180{
3181 return _mm_cvttps_epi32(a);
3182}
3183
3184PX_FORCE_INLINE Vec4V Vec4V_ReinterpretFrom_VecU32V(VecU32V a)
3185{
3186 return Vec4V(a);
3187}
3188
3189PX_FORCE_INLINE Vec4V Vec4V_ReinterpretFrom_VecI32V(VecI32V a)
3190{
3191 return m128_I2F(a);
3192}
3193
3194PX_FORCE_INLINE VecU32V VecU32V_ReinterpretFrom_Vec4V(Vec4V a)
3195{
3196 return VecU32V(a);
3197}
3198
3199PX_FORCE_INLINE VecI32V VecI32V_ReinterpretFrom_Vec4V(Vec4V a)
3200{
3201 return m128_F2I(a);
3202}
3203
3204/*
3205template<int index> PX_FORCE_INLINE BoolV BSplatElement(BoolV a)
3206{
3207 BoolV result;
3208 result[0] = result[1] = result[2] = result[3] = a[index];
3209 return result;
3210}
3211*/
3212
3213template <int index>
3214BoolV BSplatElement(BoolV a)
3215{
3216 float* data = reinterpret_cast<float*>(&a);
3217 return V4Load(data[index]);
3218}
3219
3220template <int index>
3221PX_FORCE_INLINE VecU32V V4U32SplatElement(VecU32V a)
3222{
3223 VecU32V result;
3224 result.m128_u32[0] = result.m128_u32[1] = result.m128_u32[2] = result.m128_u32[3] = a.m128_u32[index];
3225 return result;
3226}
3227
3228template <int index>
3229PX_FORCE_INLINE Vec4V V4SplatElement(Vec4V a)
3230{
3231 float* data = reinterpret_cast<float*>(&a);
3232 return V4Load(data[index]);
3233}
3234
3235PX_FORCE_INLINE VecU32V U4LoadXYZW(PxU32 x, PxU32 y, PxU32 z, PxU32 w)
3236{
3237 VecU32V result;
3238 result.m128_u32[0] = x;
3239 result.m128_u32[1] = y;
3240 result.m128_u32[2] = z;
3241 result.m128_u32[3] = w;
3242 return result;
3243}
3244
3245PX_FORCE_INLINE Vec4V V4Ceil(const Vec4V in)
3246{
3247 UnionM128 a(in);
3248 return V4LoadXYZW(PxCeil(a.m128_f32[0]), PxCeil(a.m128_f32[1]), PxCeil(a.m128_f32[2]), PxCeil(a.m128_f32[3]));
3249}
3250
3251PX_FORCE_INLINE Vec4V V4Floor(const Vec4V in)
3252{
3253 UnionM128 a(in);
3254 return V4LoadXYZW(PxFloor(a.m128_f32[0]), PxFloor(a.m128_f32[1]), PxFloor(a.m128_f32[2]), PxFloor(a.m128_f32[3]));
3255}
3256
3257PX_FORCE_INLINE VecU32V V4ConvertToU32VSaturate(const Vec4V in, PxU32 power)
3258{
3259 PX_ASSERT(power == 0 && "Non-zero power not supported in convertToU32VSaturate");
3260 PX_UNUSED(power); // prevent warning in release builds
3261 PxF32 ffffFFFFasFloat = PxF32(0xFFFF0000);
3262 UnionM128 a(in);
3263 VecU32V result;
3264 result.m128_u32[0] = PxU32(PxClamp<PxF32>((a).m128_f32[0], 0.0f, ffffFFFFasFloat));
3265 result.m128_u32[1] = PxU32(PxClamp<PxF32>((a).m128_f32[1], 0.0f, ffffFFFFasFloat));
3266 result.m128_u32[2] = PxU32(PxClamp<PxF32>((a).m128_f32[2], 0.0f, ffffFFFFasFloat));
3267 result.m128_u32[3] = PxU32(PxClamp<PxF32>((a).m128_f32[3], 0.0f, ffffFFFFasFloat));
3268 return result;
3269}
3270
3271} // namespace aos
3272} // namespace physx
3273
3274#endif // PXFOUNDATION_PXUNIXSSE2INLINEAOS_H
#define PX_RESTRICT
Definition PxPreprocessor.h:355
#define PX_FORCE_INLINE
Definition PxPreprocessor.h:335
#define PX_ALIGN(alignment, decl)
Definition PxPreprocessor.h:402
GLM_FUNC_DECL GLM_CONSTEXPR genType zero()
Definition constants.inl:6
Sorts an array of objects in ascending order, assuming that the predicate implements the < operator:
Definition PxBoxController.h:39