nlib
SimdVector3.h
Go to the documentation of this file.
1 
2 #pragma once
3 #ifndef INCLUDE_NN_NLIB_SIMD_SIMDVECTOR3_H_
4 #define INCLUDE_NN_NLIB_SIMD_SIMDVECTOR3_H_
5 
9 
10 NLIB_NAMESPACE_BEGIN
11 namespace simd {
12 
14  public:
15  static SimdVector __vectorcall LoadFloat3(const Float3* p) NLIB_NOEXCEPT;
16  template<typename MyVector3>
17  static SimdVector __vectorcall LoadFloat3(const MyVector3* p) NLIB_NOEXCEPT;
18  static void __vectorcall StoreFloat3(Float3* p, SimdVectorArg vec) NLIB_NOEXCEPT;
19  template<typename MyVector3>
20  static void __vectorcall StoreFloat3(MyVector3* p, SimdVectorArg vec) NLIB_NOEXCEPT;
21  static bool __vectorcall CmpEq(SimdVectorArg vec1, SimdVectorArg vec2) NLIB_NOEXCEPT;
22  static bool __vectorcall CmpLt(SimdVectorArg vec1, SimdVectorArg vec2) NLIB_NOEXCEPT;
23  static bool __vectorcall CmpLe(SimdVectorArg vec1, SimdVectorArg vec2) NLIB_NOEXCEPT;
24  static bool __vectorcall CmpGt(SimdVectorArg vec1, SimdVectorArg vec2) NLIB_NOEXCEPT;
25  static bool __vectorcall CmpGe(SimdVectorArg vec1, SimdVectorArg vec2) NLIB_NOEXCEPT;
26  static bool __vectorcall CmpNe(SimdVectorArg vec1, SimdVectorArg vec2) NLIB_NOEXCEPT;
27  static bool __vectorcall
28  CmpNearEq(SimdVectorArg vec1, SimdVectorArg vec2, SimdVectorArg eps) NLIB_NOEXCEPT;
29  static bool __vectorcall IsNaN(SimdVectorArg vec) NLIB_NOEXCEPT;
30  static bool __vectorcall IsInfinite(SimdVectorArg vec) NLIB_NOEXCEPT;
31  static bool __vectorcall InBound(SimdVectorArg vec, SimdVectorArg bounds) NLIB_NOEXCEPT;
32  static f128 __vectorcall Dot(SimdVectorArg vec1, SimdVectorArg vec2) NLIB_NOEXCEPT;
33  template <bool SetLane0, bool SetLane1, bool SetLane2, bool SetLane3>
34  static f128 __vectorcall DotEx(SimdVectorArg vec1, SimdVectorArg vec2) NLIB_NOEXCEPT;
35  static SimdVector __vectorcall Cross(SimdVectorArg vec1, SimdVectorArg vec2) NLIB_NOEXCEPT;
36  static SimdVector __vectorcall Normalize(SimdVectorArg vec) NLIB_NOEXCEPT;
37  static SimdVector __vectorcall NormalizeEst(SimdVectorArg vec) NLIB_NOEXCEPT;
38  static float __vectorcall Normalize(SimdVector* normalized,
40  static float __vectorcall NormalizeEst(SimdVector* normalized,
42  static f128 __vectorcall LengthSq(SimdVectorArg vec) NLIB_NOEXCEPT;
43  static f128 __vectorcall Length(SimdVectorArg vec) NLIB_NOEXCEPT;
44  static f128 __vectorcall LengthEst(SimdVectorArg vec) NLIB_NOEXCEPT;
45  static f128 __vectorcall RecpLength(SimdVectorArg vec) NLIB_NOEXCEPT;
46  static f128 __vectorcall RecpLengthEst(SimdVectorArg vec) NLIB_NOEXCEPT;
47  static f128 __vectorcall GetAngle(SimdVectorArg vec1_normalized,
48  SimdVectorArg vec2_normalized) NLIB_NOEXCEPT;
49  static SimdVector __vectorcall Reflect(SimdVectorArg vec, SimdVectorArg normal) NLIB_NOEXCEPT;
50  static SimdVector __vectorcall Orthogonal(SimdVector vec) NLIB_NOEXCEPT; // not implemented yet
51 
52  static SimdVector __vectorcall Transform(SimdVectorArg vec, SimdMatrixArg m) NLIB_NOEXCEPT;
53  static SimdVector __vectorcall
54  TransformCoord(SimdVectorArg vec, SimdMatrixArg m) NLIB_NOEXCEPT;
55  static SimdVector __vectorcall
56  TransformNormal(SimdVectorArg vec, SimdMatrixArg m) NLIB_NOEXCEPT;
57 
58  static SimdVector __vectorcall
59  Rotate(SimdVectorArg vec, SimdQuaternionArg q_normalized) NLIB_NOEXCEPT;
60  static SimdVector __vectorcall
61  InvRotate(SimdVectorArg vec, SimdQuaternionArg q_normalized) NLIB_NOEXCEPT;
62 
63  // Transform****Stream
64  // Project, Unproject
65 
66  private:
67  Vector3(); // forbidden
68 };
69 
70 #ifndef NLIB_DOXYGEN
71 
72 #define NLIB_M(tp) inline tp __vectorcall
73 #define NLIB_MH(tp) inline tp __vectorcall
74 
75 // p is 4 bytes aligned
76 NLIB_M(SimdVector) Vector3::LoadFloat3(const Float3* p) NLIB_NOEXCEPT {
77 #ifdef NLIB_F128_SIMD_NOUSE
78  f128 ret;
79  ret.vec.v[0] = p->x;
80  ret.vec.v[1] = p->y;
81  ret.vec.v[2] = p->z;
82  ret.vec.v[3] = 0.f;
83  return ret;
84 #elif defined(NLIB_SSE41)
85  __m128 x = _mm_load_ss(&p->x);
86  __m128 y = _mm_load_ss(&p->y);
87  __m128 z = _mm_load_ss(&p->z);
88  __m128 xy = _mm_unpacklo_ps(x, y);
89  return _mm_shuffle_ps(xy, z, _MM_SHUFFLE(1, 0, 1, 0));
90 #elif defined(NLIB_NEON)
91  float32x2_t xy = vld1_f32(&p->x);
92  float32x2_t z = vld1_lane_f32(&p->z, xy, 0);
93  return vcombine_f32(xy, z);
94 #elif defined(CAFE)
95  f128 ret;
96  ret.vec.ps[0][0] = p->x;
97  ret.vec.ps[0][1] = p->y;
98  ret.vec.ps[1][0] = p->z;
99  return ret;
100 #endif
101 }
102 
103 template<typename MyVector3>
104 // MyVector is a structure like 'struct MyVector3 { float x, y, z; };'
105 // DirectX::XMFLOAT3, DirectX::XMFLOAT3A for example
106 NLIB_MH(SimdVector) Vector3::LoadFloat3(const MyVector3* p) NLIB_NOEXCEPT {
107  NLIB_STATIC_ASSERT(sizeof(p->x) == 4);
108  NLIB_STATIC_ASSERT(sizeof(p->y) == 4);
109  NLIB_STATIC_ASSERT(sizeof(p->z) == 4);
110  return Vector3::LoadFloat3(reinterpret_cast<const Float3*>(&p->x));
111 }
112 
113 // p is 4 bytes aligned
114 NLIB_M(void) Vector3::StoreFloat3(Float3* p, SimdVectorArg vec) NLIB_NOEXCEPT { // NOLINT
115 #ifdef NLIB_F128_SIMD_NOUSE
116  p->x = vec.vec.v[0];
117  p->y = vec.vec.v[1];
118  p->z = vec.vec.v[2];
119 #elif defined(NLIB_SSE41)
120  f128 y = _mm_shuffle_ps(vec, vec, _MM_SHUFFLE(1, 1, 1, 1));
121  f128 z = _mm_shuffle_ps(vec, vec, _MM_SHUFFLE(2, 2, 2, 2));
122  _mm_store_ss(&p->x, vec);
123  _mm_store_ss(&p->y, y);
124  _mm_store_ss(&p->z, z);
125 #elif defined(NLIB_NEON)
126  float32x2_t lo = vget_low_f32(vec);
127  vst1_f32(&p->x, lo);
128  vst1q_lane_f32(&p->z, vec, 2);
129 #elif defined(CAFE)
130  p->x = vec.vec.ps[0][0];
131  p->y = vec.vec.ps[0][1];
132  p->z = vec.vec.ps[1][0];
133 #endif
134 }
135 
136 template<typename MyVector3>
137 NLIB_MH(void) Vector3::StoreFloat3(MyVector3* p, SimdVectorArg vec) NLIB_NOEXCEPT { // NOLINT
138  // MyVector is a structure like 'struct MyVector3 { float x, y, z; };'
139  // DirectX::XMFLOAT3, DirectX::XMFLOAT3A for example
140  NLIB_STATIC_ASSERT(sizeof(p->x) == 4);
141  NLIB_STATIC_ASSERT(sizeof(p->y) == 4);
142  NLIB_STATIC_ASSERT(sizeof(p->z) == 4);
143  Vector3::StoreFloat3(reinterpret_cast<Float3*>(&p->x), vec);
144 }
145 
146 // true if vec1[xyz] == vec2[xyz]
147 inline bool __vectorcall Vector3::CmpEq(SimdVectorArg vec1, SimdVectorArg vec2) NLIB_NOEXCEPT {
148  f128 mask = F128::CmpEq(vec1, vec2);
149  return F128::IsAllMaskTrue(F128::Swizzle<0, 1, 2, 2>(mask));
150 }
151 
152 // true if vec1[xyz] < vec2[xyz]
153 inline bool __vectorcall Vector3::CmpLt(SimdVectorArg vec1, SimdVectorArg vec2) NLIB_NOEXCEPT {
154  f128 mask = F128::CmpLt(vec1, vec2);
155  return F128::IsAllMaskTrue(F128::Swizzle<0, 1, 2, 2>(mask));
156 }
157 
158 // true if vec1[xyz] <= vec2[xyz]
159 inline bool __vectorcall Vector3::CmpLe(SimdVectorArg vec1, SimdVectorArg vec2) NLIB_NOEXCEPT {
160  f128 mask = F128::CmpLe(vec1, vec2);
161  return F128::IsAllMaskTrue(F128::Swizzle<0, 1, 2, 2>(mask));
162 }
163 
164 // true if vec1[xyz] > vec2[xyz]
165 inline bool __vectorcall Vector3::CmpGt(SimdVectorArg vec1, SimdVectorArg vec2) NLIB_NOEXCEPT {
166  f128 mask = F128::CmpGt(vec1, vec2);
167  return F128::IsAllMaskTrue(F128::Swizzle<0, 1, 2, 2>(mask));
168 }
169 
170 // true if vec1[xyz] >= vec2[xyz]
171 inline bool __vectorcall Vector3::CmpGe(SimdVectorArg vec1, SimdVectorArg vec2) NLIB_NOEXCEPT {
172  f128 mask = F128::CmpGe(vec1, vec2);
173  return F128::IsAllMaskTrue(F128::Swizzle<0, 1, 2, 2>(mask));
174 }
175 
176 // vec1.x != vec2.x || vec1.y != vec2.y || vec1.z != vec2.z
177 inline bool __vectorcall Vector3::CmpNe(SimdVectorArg vec1, SimdVectorArg vec2) NLIB_NOEXCEPT {
178  f128 mask = F128::CmpNe(vec1, vec2);
179  return !F128::IsAllMaskFalse(F128::Swizzle<0, 1, 2, 2>(mask));
180 }
181 
182 inline bool __vectorcall
183 Vector3::CmpNearEq(SimdVectorArg vec1, SimdVectorArg vec2, SimdVectorArg eps) NLIB_NOEXCEPT {
184  f128 mask = F128::CmpNearEq(vec1, vec2, eps);
185  return F128::IsAllMaskTrue(F128::Swizzle<0, 1, 2, 2>(mask));
186 }
187 
188 // isnan(vec.x) || isnan(vec.y) || isnan(vec.z)
189 inline bool __vectorcall Vector3::IsNaN(SimdVectorArg vec) NLIB_NOEXCEPT {
190  f128 mask = F128::IsNaN(vec);
191  return F128::IsAllMaskTrue(F128::Swizzle<0, 1, 2, 2>(mask));
192 }
193 
194 // isinf(vec.x) || isinf(vec.y) || isinf(vec.z)
195 inline bool __vectorcall Vector3::IsInfinite(SimdVectorArg vec) NLIB_NOEXCEPT {
196  f128 mask = F128::IsInfinite(vec);
197  return F128::IsAllMaskTrue(F128::Swizzle<0, 1, 2, 2>(mask));
198 }
199 
200 // true if abs(vec[xyz]) <= bounds[xyz]
201 inline bool __vectorcall Vector3::InBound(SimdVectorArg vec, SimdVectorArg bounds) NLIB_NOEXCEPT {
202  f128 mask = F128::InBound(vec, bounds);
203  return F128::IsAllMaskTrue(F128::Swizzle<0, 1, 2, 2>(mask));
204 }
205 
206 // r = { dot, dot, dot, dot }
207 NLIB_M(f128) Vector3::Dot(SimdVectorArg vec1, SimdVectorArg vec2) NLIB_NOEXCEPT {
208 #ifdef NLIB_F128_SIMD_NOUSE
209  float tmp = vec1.vec.v[0] * vec2.vec.v[0] + vec1.vec.v[1] * vec2.vec.v[1] +
210  vec1.vec.v[2] * vec2.vec.v[2];
211  f128 rval;
212  rval.vec.v[0] = rval.vec.v[1] = rval.vec.v[2] = rval.vec.v[3] = tmp;
213  return rval;
214 #elif defined(NLIB_SSE41)
215  return _mm_dp_ps(vec1, vec2, 0x7F);
216 #elif defined(NLIB_NEON)
217 #ifdef __aarch64__
218  float32x4_t tmp = vmulq_f32(vec1, vec2);
219  tmp = F128::Permute<0, 1, 2, 6>(tmp, vdupq_n_f32(0.f));
220  tmp = vpaddq_f32(tmp, tmp);
221  tmp = vpaddq_f32(tmp, tmp);
222  return tmp;
223 #else
224  f128 tmp = vmulq_f32(vec1, vec2);
225  float32x2_t lo = vget_low_f32(tmp);
226  lo = vpadd_f32(lo, lo);
227  float32x2_t hi = vdup_lane_f32(vget_high_f32(tmp), 0);
228  lo = vadd_f32(lo, hi);
229  return vcombine_f32(lo, lo);
230 #endif
231 #elif defined(CAFE)
232  f128 tmp = F128::Mult(vec1, vec2);
233  f32x2 val = __PS_SUM0(tmp.vec.ps[0], tmp.vec.ps[0], tmp.vec.ps[0]);
234  val = __PS_ADD(val, tmp.vec.ps[1]);
235  f128 ret;
236  ret.vec.ps[0] = ret.vec.ps[1] = __PS_FDUP(val[0]);
237  return ret;
238 #endif
239 }
240 
241 template <bool SetLane0, bool SetLane1, bool SetLane2, bool SetLane3>
242 // r[i] = SetLane[i] ? dot : 0.f
243 NLIB_MH(f128) Vector3::DotEx(SimdVectorArg vec1, SimdVectorArg vec2) NLIB_NOEXCEPT {
244 #if !defined(NLIB_F128_SIMD_NOUSE) && defined(NLIB_SSE41)
245  return _mm_dp_ps(vec1, vec2,
246  (0x70 | (SetLane0 ? 1 : 0) | (SetLane1 ? 2 : 0) |
247  (SetLane2 ? 4 : 0) | (SetLane3 ? 8 : 0)));
248 #else
249  return F128::Splat<SetLane0, SetLane1, SetLane2, SetLane3>(F128::SetZero(), Dot(vec1, vec2));
250 #endif
251 }
252 
253 // 'w' component is arbitrary
254 NLIB_M(SimdVector) Vector3::Cross(SimdVectorArg vec1, SimdVectorArg vec2) NLIB_NOEXCEPT {
255  SimdVector rval = F128::Mult(F128::Swizzle<1, 2, 0, -1>(vec1),
256  F128::Swizzle<2, 0, 1, -1>(vec2));
257  // yz, zx, xy, *
258  rval = F128::MultSub(F128::Swizzle<2, 0, 1, -1>(vec1), F128::Swizzle<1, 2, 0, -1>(vec2), rval);
259  // yz - zy, zx - xz, xy - yx, *
260  return rval;
261 }
262 
263 // nan if |vec| is too big, 0 if |vec| = 0
264 NLIB_M(SimdVector) Vector3::Normalize(SimdVectorArg vec) NLIB_NOEXCEPT {
265  f128 dot = Vector3::Dot(vec, vec);
266 #if defined(NLIB_NEON) && !defined(NLIB_F128_SIMD_NOUSE)
267  float32x4_t x;
268  x = vrsqrteq_f32(dot);
269  x = vmulq_f32(x, vrsqrtsq_f32(dot, vmulq_f32(x, x)));
270  f128 rsqrt = vmulq_f32(x, vrsqrtsq_f32(dot, vmulq_f32(x, x)));
271 #else
272  f128 rsqrt = F128::RecpSqrt(dot);
273 #endif
274  f128 inf = F128::SetInfinity();
275  f128 eqzero = F128::CmpEqZero(dot);
276  f128 eqinf = F128::CmpEq(dot, inf);
277  SimdVector ret = F128::Mult(vec, rsqrt);
278  f128 nan = F128::SetNaN();
279  ret = F128::AndNot(eqzero, ret);
280  ret = F128::Select(eqinf, nan, ret);
281  return ret;
282 }
283 
284 NLIB_M(float) Vector3::Normalize(SimdVector* normalized, SimdVectorArg vec) NLIB_NOEXCEPT {
285  f128 dot = Vector3::Dot(vec, vec);
286  f128 rsqrt = F128::RecpSqrt(dot);
287  *normalized = F128::Mult(vec, rsqrt);
288  return F128::GetFloatFromLane<0>(dot);
289 }
290 
291 // r = { lensq, lensq, lensq, lensq }
292 NLIB_M(f128) Vector3::LengthSq(SimdVectorArg vec) NLIB_NOEXCEPT { return Dot(vec, vec); }
293 
294 // r = { len, len, len, len }
295 NLIB_M(f128) Vector3::Length(SimdVectorArg vec) NLIB_NOEXCEPT {
296  return F128::Sqrt(Dot(vec, vec));
297 }
298 
299 // r = { len, len, len, len }
300 NLIB_M(f128) Vector3::LengthEst(SimdVectorArg vec) NLIB_NOEXCEPT {
301  return F128::SqrtEst(Dot(vec, vec));
302 }
303 
304 // r = { recpLen, recpLen, recpLen, recpLen }
305 NLIB_M(f128) Vector3::RecpLength(SimdVectorArg vec) NLIB_NOEXCEPT {
306  return F128::RecpSqrt(Dot(vec, vec));
307 }
308 
309 // r = { recpLen, recpLen, recpLen, recpLen }
310 NLIB_M(f128) Vector3::RecpLengthEst(SimdVectorArg vec) NLIB_NOEXCEPT {
311  return F128::RecpSqrtEst(Dot(vec, vec));
312 }
313 
314 NLIB_M(SimdVector) Vector3::NormalizeEst(SimdVectorArg vec) NLIB_NOEXCEPT {
315  return F128::Mult(vec, RecpLengthEst(vec));
316 }
317 
318 NLIB_M(float) Vector3::NormalizeEst(SimdVector* normalized, SimdVectorArg vec) NLIB_NOEXCEPT {
319  f128 dot = Vector3::Dot(vec, vec);
320  f128 rsqrt = F128::RecpSqrtEst(dot);
321  *normalized = F128::Mult(vec, rsqrt);
322  return F128::GetFloatFromLane<0>(dot);
323 }
324 
325 // { radian, radian, radian, radian }
326 NLIB_M(f128) Vector3::GetAngle(SimdVectorArg vec1_normalized,
327  SimdVectorArg vec2_normalized) NLIB_NOEXCEPT {
328  f128 ret = Dot(vec1_normalized, vec2_normalized);
329  ret = F128::Clamp(ret, F128::SetNegativeOne(), F128::SetOne());
330  return F128::ArcCos(ret);
331 }
332 
333 NLIB_M(SimdVector) Vector3::Reflect(SimdVectorArg vec, SimdVectorArg normal) NLIB_NOEXCEPT {
334  f128 s = Dot(vec, normal);
335  s = F128::Add(s, s);
336  return F128::MultSub(s, normal, vec);
337 }
338 
339 /*
340 // Vector3::Transform(vec, m) is better in performance
341 NLIB_M(SimdVector) Vector3::Transform(SimdMatrixArg m, SimdVectorArg vec) NLIB_NOEXCEPT {
342  f128 v = F128::SetFloatToLane<3>(vec, 1.f);
343  return Vector4::Transform(m, v);
344 }
345 */
346 
347 // r = { vec.x, vec.y, vec.z, 1 } * m
348 NLIB_M(SimdVector) Vector3::Transform(SimdVectorArg vec, SimdMatrixArg m) NLIB_NOEXCEPT {
349  f128 ret = F128::Mult<0>(vec, m.r[0], each_select32);
350  ret = F128::MultAdd<1>(vec, m.r[1], ret, each_select32);
351  ret = F128::MultAdd<2>(vec, m.r[2], ret, each_select32);
352  return F128::Add(m.r[3], ret);
353 }
354 
355 // r = { vec.x, vec.y, vec.z, 1.f } * m, r = r / r.w
356 NLIB_M(SimdVector) Vector3::TransformCoord(SimdVectorArg vec, SimdMatrixArg m) NLIB_NOEXCEPT {
357  f128 tmp = Vector3::Transform(vec, m);
358  return F128::Div(tmp, F128::SetValue<3>(tmp, each_select32));
359 }
360 
361 /*
362 // Vector3::TransformNormal(vec, m) is better in performance
363 NLIB_M(SimdVector) Vector3::TransformNormal(SimdMatrixArg m, SimdVectorArg vec) NLIB_NOEXCEPT {
364  f128 v = F128::SetZeroToLane<3>(vec);
365  return Vector4::Transform(m, v);
366 }
367 */
368 
369 // r = { vec.x, vec.y, vec.z, 0 } * m
370 NLIB_M(SimdVector) Vector3::TransformNormal(SimdVectorArg vec, SimdMatrixArg m) NLIB_NOEXCEPT {
371  f128 ret = F128::Mult<0>(vec, m.r[0], each_select32);
372  ret = F128::MultAdd<1>(vec, m.r[1], ret, each_select32);
373  ret = F128::MultAdd<2>(vec, m.r[2], ret, each_select32);
374  return ret;
375 }
376 
377 NLIB_M(SimdVector) Vector3::Rotate(SimdVectorArg vec,
378  SimdQuaternionArg q_normalized) NLIB_NOEXCEPT {
379  SimdVector v = F128::SetZeroToLane<3>(vec);
380  SimdQuaternion conj = Quaternion::Conjugate(q_normalized);
381  return Quaternion::Mult(Quaternion::Mult(conj, v), q_normalized);
382 }
383 
384 NLIB_M(SimdVector) Vector3::InvRotate(SimdVectorArg vec,
385  SimdQuaternionArg q_normalized) NLIB_NOEXCEPT {
386  SimdVector v = F128::SetZeroToLane<3>(vec);
387  SimdQuaternion conj = Quaternion::Conjugate(q_normalized);
388  return Quaternion::Mult(Quaternion::Mult(q_normalized, v), conj);
389 }
390 
391 #undef NLIB_M
392 #undef NLIB_MH
393 
394 #endif // NLIB_DOXYGEN
395 
396 } // namespace simd
397 NLIB_NAMESPACE_END
398 
399 #endif // INCLUDE_NN_NLIB_SIMD_SIMDVECTOR3_H_
float x
The x-coordinate of the 3D vector.
Definition: SimdFloat.h:4279
Defines a quaternion.
f128arg SimdVectorArg
f128arg is defined using typedef.
Definition: SimdFloat.h:4137
#define NLIB_VIS_HIDDEN
Symbols for functions and classes are not made available outside of the library.
Definition: Platform_unix.h:60
f128arg SimdQuaternionArg
f128arg is defined using typedef.
Definition: SimdFloat.h:4139
The class with the collection of functions that perform calculations on three-dimensional vectors...
Definition: SimdVector3.h:13
f128 r[4]
Keeps each row of a 4x4 matrix.
Definition: SimdFloat.h:4164
The structure for keeping a 4x4 matrix.
Definition: SimdFloat.h:4148
#define NLIB_NOEXCEPT
Defines noexcept geared to the environment, or the equivalent.
Definition: Config.h:86
Defines the class and functions for SIMD computations on single-precision floating-point numbers...
The type for reading and writing three-dimensional vectors in memory. Keeps float-type x...
Definition: SimdFloat.h:4278
constexpr const each_select32_tag each_select32
The tag for representing the selection of a 32-bit lane with an each_select32_tag-type constant objec...
Definition: SimdInt.h:50
float y
The y-coordinate of the 3D vector.
Definition: SimdFloat.h:4280
nlib_f128_t f128
nlib_f128_t is defined using typedef.
Definition: SimdFloat.h:58
float z
The z-coordinate of the 3D vector.
Definition: SimdFloat.h:4281
#define NLIB_STATIC_ASSERT(exp)
Defines a static assertion. Uses static_assert if it is available for use.
Definition: Config.h:136
Defines a four-dimensional vector.
f128 SimdQuaternion
f128 is defined using typedef. Used when handling quaternions.
Definition: SimdFloat.h:4138
f128 SimdVector
f128 is defined using typedef. Used when handling three-dimensional or four-dimensional vectors...
Definition: SimdFloat.h:4136