nlib
SimdQuaternion.h
Go to the documentation of this file.
1 
2 /*--------------------------------------------------------------------------------*
3  Project: CrossRoad
4  Copyright (C)Nintendo All rights reserved.
5 
6  These coded instructions, statements, and computer programs contain proprietary
7  information of Nintendo and/or its licensed developers and are protected by
8  national and international copyright laws. They may not be disclosed to third
9  parties or copied or duplicated in any form, in whole or in part, without the
10  prior written consent of Nintendo.
11 
12  The content herein is highly confidential and should be handled accordingly.
13  *--------------------------------------------------------------------------------*/
14 
15 #pragma once
16 #ifndef INCLUDE_NN_NLIB_SIMD_SIMDQUATERNION_H_
17 #define INCLUDE_NN_NLIB_SIMD_SIMDQUATERNION_H_
18 
19 #include "nn/nlib/simd/SimdFloat.h"
21 
22 NLIB_NAMESPACE_BEGIN
23 namespace simd {
24 
26  public:
27  static SimdQuaternion __vectorcall Identity() NLIB_NOEXCEPT;
28  static SimdQuaternion __vectorcall Conjugate(SimdQuaternionArg q) NLIB_NOEXCEPT;
29  static f128 __vectorcall Length(SimdQuaternionArg q) NLIB_NOEXCEPT;
30  static f128 __vectorcall LengthSq(SimdQuaternionArg q) NLIB_NOEXCEPT;
31  static f128 __vectorcall RecpLength(SimdQuaternionArg q) NLIB_NOEXCEPT;
32  static SimdQuaternion __vectorcall Normalize(SimdQuaternionArg q) NLIB_NOEXCEPT;
33  static SimdQuaternion __vectorcall NormalizeEst(SimdQuaternionArg q) NLIB_NOEXCEPT;
34  static SimdQuaternion __vectorcall Inverse(SimdQuaternionArg q) NLIB_NOEXCEPT;
35  static SimdQuaternion __vectorcall Ln(SimdQuaternionArg q_normalized) NLIB_NOEXCEPT;
36  static SimdQuaternion __vectorcall Exp(SimdQuaternionArg q) NLIB_NOEXCEPT;
37 
38  static bool __vectorcall IsIdentity(SimdQuaternionArg q) NLIB_NOEXCEPT;
39  static bool __vectorcall IsInfinite(SimdQuaternionArg q) NLIB_NOEXCEPT;
40  static bool __vectorcall IsNaN(SimdQuaternionArg q) NLIB_NOEXCEPT;
41  static bool __vectorcall CmpEq(SimdQuaternionArg q0, SimdQuaternionArg q1) NLIB_NOEXCEPT;
42  static bool __vectorcall CmpNe(SimdQuaternionArg q0, SimdQuaternionArg q1) NLIB_NOEXCEPT;
43 
44  static f128 __vectorcall Dot(SimdQuaternionArg q0, SimdQuaternionArg q1) NLIB_NOEXCEPT;
45  static SimdQuaternion __vectorcall Mult(SimdQuaternionArg q0,
47 
48  static SimdQuaternion __vectorcall FromRotationAxisAndSinCos(SimdVectorArg axis_normalized,
49  float sin_half_rad,
50  float cos_half_rad) NLIB_NOEXCEPT;
51  static SimdQuaternion __vectorcall FromRotationMatrix(SimdMatrixArg m) NLIB_NOEXCEPT;
52  static SimdQuaternion __vectorcall FromRotationZXY(SimdVectorArg sin_half_xyz,
53  SimdVectorArg cos_half_xyz) NLIB_NOEXCEPT;
54  static SimdVector __vectorcall ToAxisAngle(float* rad, SimdQuaternion q) NLIB_NOEXCEPT;
55 
56  static SimdQuaternion __vectorcall Slerp(SimdQuaternionArg q0_normalized,
57  SimdQuaternionArg q1_normalized,
58  float t) NLIB_NOEXCEPT;
59  static SimdQuaternion __vectorcall Squad(SimdQuaternionArg q0_normalized,
60  SimdQuaternionArg q1_normalized,
61  SimdQuaternionArg q2_normalized,
62  SimdQuaternionArg q3_normalized,
63  float t) NLIB_NOEXCEPT;
64  static void __vectorcall SquadSetup(SimdQuaternion* a, SimdQuaternion* b, SimdQuaternion* c,
68  static SimdQuaternion __vectorcall BaryCentric(SimdQuaternionArg q0, SimdQuaternionArg q1,
69  SimdQuaternionArg q2, float f,
70  float g) NLIB_NOEXCEPT;
71 
72  private:
73  Quaternion(); // forbidden
74 };
75 
76 #ifndef NLIB_DOXYGEN
77 
78 #define NLIB_M(tp) inline tp __vectorcall
79 
80 // XMQuaternionIdentity
81 NLIB_M(SimdQuaternion) Quaternion::Identity() NLIB_NOEXCEPT {
82  return F128::Set0001();
83 }
84 
85 // XMQuaternionConjugate
86 NLIB_M(SimdQuaternion) Quaternion::Conjugate(SimdQuaternionArg q) NLIB_NOEXCEPT {
87  return F128::NegateEx<true, true, true, false>(q);
88 }
89 
90 // XMQuaternionLength
91 NLIB_M(f128) Quaternion::Length(SimdQuaternionArg q) NLIB_NOEXCEPT {
92  return Vector4::Length(q);
93 }
94 
95 // XMQuaternionLengthSq
96 NLIB_M(f128) Quaternion::LengthSq(SimdQuaternionArg q) NLIB_NOEXCEPT {
97  return Vector4::LengthSq(q);
98 }
99 
100 // XMQuaternionReciprocalLength
101 NLIB_M(f128) Quaternion::RecpLength(SimdQuaternionArg q) NLIB_NOEXCEPT {
102  return Vector4::RecpLength(q);
103 }
104 
105 // XMQuaternionNormalize
106 NLIB_M(SimdQuaternion) Quaternion::Normalize(SimdQuaternionArg q) NLIB_NOEXCEPT {
107  return Vector4::Normalize(q);
108 }
109 
110 // XMQuaternionNormalizeEst
111 NLIB_M(SimdQuaternion) Quaternion::NormalizeEst(SimdQuaternionArg q) NLIB_NOEXCEPT {
112  return Vector4::NormalizeEst(q);
113 }
114 
115 // XMQuaternionInverse
116 NLIB_M(SimdQuaternion) Quaternion::Inverse(SimdQuaternionArg q) NLIB_NOEXCEPT {
117  f128 len_sq = LengthSq(q);
118  SimdQuaternion conj = Conjugate(q);
119 
120  f128 eps = F128::SetEpsilon();
121  f128 near_zero = F128::CmpLe(len_sq, eps);
122 
123  SimdQuaternion inv = F128::Div(conj, len_sq);
124  return F128::AndNot(near_zero, inv);
125 }
126 
127 // XMQuaternionLn
128 NLIB_M(SimdQuaternion) Quaternion::Ln(SimdQuaternionArg q_normalized) NLIB_NOEXCEPT {
129  static const float one_eps = 1.f - 0.00001f;
130  f128 q0 = F128::SetZeroToLane<3>(q_normalized);
131  f128 w = F128::SetValue<3>(q_normalized, each_select32);
132  f128 xyz_len = Vector4::Length(q0);
133  f128 w_not_near_one = F128::InBound(w, F128::SetValue(one_eps, each_float));
134 
135  f128 theta = F128::ArcTan2(xyz_len, w);
136  f128 result = F128::Div(theta, xyz_len);
137  result = F128::Mult(q0, result);
138  result = F128::Select(w_not_near_one, result, q0);
139  return result;
140 }
141 
142 // XMQuaternionExp
143 NLIB_M(SimdQuaternion) Quaternion::Exp(SimdQuaternionArg q) NLIB_NOEXCEPT {
144  f128 xyz_len = Vector4::Length(F128::SetZeroToLane<3>(q));
145  f128x2 sc = F128::SinCos(xyz_len);
146 
147  f128 result = F128::Mult(q, F128::Div(sc.val[0], xyz_len));
148  f128 near_zero = F128::CmpNearEqZero(xyz_len, F128::SetEpsilon());
149  result = F128::Select(near_zero, q, result);
150  result = F128::Splat<false, false, false, true>(result, sc.val[1]);
151  return result;
152 }
153 
154 // XMQuaternionIsIdentity
155 NLIB_M(bool) Quaternion::IsIdentity(SimdQuaternionArg q) NLIB_NOEXCEPT {
156  return Vector4::CmpEq(q, Identity());
157 }
158 
159 // XMQuaternionIsInfinite
160 NLIB_M(bool) Quaternion::IsInfinite(SimdQuaternionArg q) NLIB_NOEXCEPT {
161  return Vector4::IsInfinite(q);
162 }
163 
164 // XMQuaternionIsNaN
165 NLIB_M(bool) Quaternion::IsNaN(SimdQuaternionArg q) NLIB_NOEXCEPT {
166  return Vector4::IsNaN(q);
167 }
168 
169 // XMQuaternionEqual
170 NLIB_M(bool)
171 Quaternion::CmpEq(SimdQuaternionArg q0, SimdQuaternionArg q1) NLIB_NOEXCEPT {
172  return Vector4::CmpEq(q0, q1);
173 }
174 
175 // XMQuaternionNotEqual
176 NLIB_M(bool)
177 Quaternion::CmpNe(SimdQuaternionArg q0, SimdQuaternionArg q1) NLIB_NOEXCEPT {
178  return Vector4::CmpNe(q0, q1);
179 }
180 
181 // XMQuaternionDot
182 NLIB_M(f128) Quaternion::Dot(SimdQuaternionArg q0, SimdQuaternionArg q1) NLIB_NOEXCEPT {
183  return Vector4::Dot(q0, q1);
184 }
185 
186 // XMQuaternionMultiply
187 NLIB_M(SimdQuaternion) Quaternion::Mult(SimdQuaternionArg q0, SimdQuaternionArg q1) NLIB_NOEXCEPT {
188  SimdVector v1 = F128::Swizzle<3, 0, 1, 2>(q1);
189  f128 r1 = F128::Swizzle<3, 2, 1, 0>(q0);
190  f128 r2 = F128::Swizzle<2, 3, 0, 1>(q0);
191  f128 r3 = F128::Swizzle<1, 0, 3, 2>(q0);
192  SimdMatrix m;
193  m.r[0] = q0;
194  m.r[1] = F128::NegateEx<false, true, false, true>(r1);
195  m.r[2] = F128::NegateEx<false, false, true, true>(r2);
196  m.r[3] = F128::NegateEx<true, false, false, true>(r3);
197  return Vector4::Transform(v1, m);
198 }
199 
200 // sin_half_rad = sin(rad/2), cos_half_rad = cos(rad/2)
201 // XMQuaternionRotationNormal
202 NLIB_M(SimdQuaternion)
203 Quaternion::FromRotationAxisAndSinCos(SimdVectorArg axis_normalized, float sin_half_rad,
204  float cos_half_rad) NLIB_NOEXCEPT {
205  SimdVector axis = F128::SetFloatToLane<3>(axis_normalized, 1.f);
206  f128 scale = F128::SetValue(sin_half_rad, sin_half_rad, sin_half_rad, cos_half_rad);
207  return F128::Mult(axis, scale);
208 }
209 
210 // m must be rotation matrix
211 NLIB_M(SimdQuaternion) Quaternion::FromRotationMatrix(SimdMatrixArg m) NLIB_NOEXCEPT {
212  // 1-2y^2-2z^2 2xy+2wz 2xz-2wy
213  // 2xy-2wz 1-2x^2-2z^2 2yz+2wx
214  // 2xz+2wy 2yz-2wx 1^2x^2^2y^2
215  f128 r0 = m.r[0];
216  f128 r1 = m.r[1];
217  f128 r2 = m.r[2];
218 
219  f128 elem;
220  // elem = { m00 - m11 - m22 + 1.f, -m00 + m11 - m22 + 1.f,
221  // -m00 - m11 + m22 + 1.f, m00 + m11 + m22 + 1.f }
222  // -> { 4x^2, 4y^2, 4z^2, 4w^2 }
223  {
224  f128 m00x = F128::SetValue<0>(r0, each_select32);
225  f128 m11x = F128::SetValue<1>(r1, each_select32);
226  f128 m22x = F128::SetValue<2>(r2, each_select32);
227  m00x = F128::NegateEx<false, true, true, false>(m00x);
228  m11x = F128::NegateEx<true, false, true, false>(m11x);
229  m22x = F128::NegateEx<true, true, false, false>(m22x);
230  f128 one = F128::SetOne();
231  elem = F128::Add(m00x, m11x);
232  elem = F128::Add(elem, m22x);
233  elem = F128::Add(elem, one);
234  }
235 
236  f128 xx_ge_yy;
237  f128 zz_ge_ww;
238  f128 xxyy_ge_zzww;
239  f128 elem_max;
240  {
241  f128 t0, t1, t2, t3;
242  t0 = F128::SetValue<0>(elem, each_select32);
243  t1 = F128::SetValue<1>(elem, each_select32);
244  t2 = F128::SetValue<2>(elem, each_select32);
245  t3 = F128::SetValue<3>(elem, each_select32);
246  xx_ge_yy = F128::CmpGe(t0, t1);
247  zz_ge_ww = F128::CmpGe(t2, t3);
248 
249  t0 = F128::PairwiseMax(elem, elem);
250  t2 = F128::SetValue<0>(t0, each_select32);
251  t3 = F128::SetValue<1>(t0, each_select32);
252  elem_max = F128::PairwiseMax(t0, t0);
253  xxyy_ge_zzww = F128::CmpGe(t2, t3);
254  }
255 
256  f128 v0_25 = F128::SetValue(0.25f, each_float);
257  elem_max = F128::Mult(v0_25, elem_max);
258  f128 mult = F128::RecpSqrt(elem_max);
259  f128 v = F128::Mult(mult, elem_max);
260  mult = F128::Mult(v0_25, mult);
261 
262  f128 m01_20_12;
263  m01_20_12 = F128::Permute<1, 4, 2, -1>(r0, r2);
264  m01_20_12 = F128::Permute<0, 1, 6, -1>(m01_20_12, r1);
265 
266  f128 m10_02_21;
267  m10_02_21 = F128::Permute<0, 1, 5, -1>(r1, r2);
268  m10_02_21 = F128::Permute<0, 6, 2, -1>(m10_02_21, r0);
269 
270  f128 ans_x_biggest, ans_y_biggest, ans_z_biggest, ans_w_biggest;
271  {
272  f128 tmp_x, tmp_y, tmp_z, tmp_w;
273  tmp_x = F128::NegateEx<false, false, true, true>(m10_02_21);
274  tmp_x = F128::Mult(mult, F128::Add(m01_20_12, tmp_x));
275 
276  tmp_y = F128::NegateEx<false, true, false, true>(m10_02_21);
277  tmp_y = F128::Mult(mult, F128::Add(m01_20_12, tmp_y));
278 
279  tmp_z = F128::NegateEx<true, false, false, true>(m10_02_21);
280  tmp_z = F128::Mult(mult, F128::Add(m01_20_12, tmp_z));
281 
282  tmp_w = F128::Mult(mult, F128::Sub(m01_20_12, m10_02_21));
283 
284  ans_x_biggest = F128::Permute<4, 0, 1, 2>(tmp_x, v);
285  ans_y_biggest = F128::Permute<0, 4, 2, 1>(tmp_y, v);
286  ans_z_biggest = F128::Permute<1, 2, 4, 0>(tmp_z, v);
287  ans_w_biggest = F128::Permute<2, 1, 0, 4>(tmp_w, v);
288  }
289 
290  f128 ans_xy = F128::Select(xx_ge_yy, ans_x_biggest, ans_y_biggest);
291  f128 ans_zw = F128::Select(zz_ge_ww, ans_z_biggest, ans_w_biggest);
292  return F128::Select(xxyy_ge_zzww, ans_xy, ans_zw);
293 }
294 
295 // sin_half_xyz = { sin(rad_x/2), sin(rad_y/2), sin(rad_z/2), * }
296 // cos_half_xyz = { cos(rad_x/2), cos(rad_y/2), cos(rad_z/2), * }
297 // XMQuaternionRotationRollPitchYawFromVector
298 NLIB_M(SimdQuaternion)
299 Quaternion::FromRotationZXY(SimdVectorArg sin_half_xyz, SimdVectorArg cos_half_xyz) NLIB_NOEXCEPT {
300  // CxSySz + SxCyCz
301  // -SxCySz + CxSyCz
302  // -SxSyCz + CxCySz
303  // SxSySz + CxCyCz
304  f128 x1 = F128::Permute<4, 0, 0, 0>(sin_half_xyz, cos_half_xyz);
305  f128 y1 = F128::Permute<1, 5, 1, 1>(sin_half_xyz, cos_half_xyz);
306  f128 z1 = F128::Permute<2, 2, 6, 2>(sin_half_xyz, cos_half_xyz);
307  x1 = F128::NegateEx<false, true, true, false>(x1);
308  f128 x0 = F128::Permute<0, 4, 4, 4>(sin_half_xyz, cos_half_xyz);
309  f128 y0 = F128::Permute<5, 1, 5, 5>(sin_half_xyz, cos_half_xyz);
310  f128 z0 = F128::Permute<6, 6, 2, 6>(sin_half_xyz, cos_half_xyz);
311 
312  f128 z0x0y0 = F128::Mult(x0, y0);
313  f128 z1x1y1 = F128::Mult(x1, y1);
314  z0x0y0 = F128::Mult(z0x0y0, z0);
315  return F128::MultAdd(z1x1y1, z1, z0x0y0);
316 }
317 
318 // XMQuaternionToAxisAngle
319 // rad can be nullptr
320 NLIB_M(SimdVector) Quaternion::ToAxisAngle(float* rad, SimdQuaternion q) NLIB_NOEXCEPT {
321  if (rad) {
322  *rad = 2.f * F128::GetFloatFromLane<3>(F128::ArcCos(q));
323  }
324  return q;
325 }
326 
327 // XMQuaternionSlerp
328 NLIB_M(SimdVector)
329 Quaternion::Slerp(SimdQuaternionArg q0_normalized, SimdQuaternionArg q1_normalized,
330  float t) NLIB_NOEXCEPT {
331  f128 q0q1 = Dot(q0_normalized, q1_normalized);
332  f128 too_near;
333  f128 sp;
334  {
335  f128 ss = F128::MultSub(q0q1, q0q1, F128::SetValue(1.f, each_float));
336  f128 eps = F128::SetEpsilon();
337  too_near = F128::CmpLe(ss, eps);
338  sp = F128::RecpSqrt(ss);
339  }
340  f128 ph = F128::ArcCos(q0q1);
341  f128 k = F128::SetValue(1.f - t, t, 0.f, 0.f);
342  f128 t0t1 = F128::Mult(sp, F128::Sin(F128::Mult(ph, k)));
343  f128 t0 = F128::SetValue<0>(t0t1, each_select32);
344  f128 t1 = F128::SetValue<1>(t0t1, each_select32);
345 
346  SimdVector ret = F128::Mult(q0_normalized, t0);
347  ret = F128::MultAdd(q1_normalized, t1, ret);
348  return F128::Select(too_near, q0_normalized, ret);
349 }
350 
351 // XMQuaternionSquad
352 NLIB_M(SimdVector)
353 Quaternion::Squad(SimdQuaternionArg q0_normalized, SimdQuaternionArg q1_normalized,
354  SimdQuaternionArg q2_normalized, SimdQuaternionArg q3_normalized,
355  float t) NLIB_NOEXCEPT {
356  float t2 = (t - t * t) * 2.f;
357  SimdQuaternion q03 = Slerp(q0_normalized, q3_normalized, t);
358  SimdQuaternion q12 = Slerp(q1_normalized, q2_normalized, t);
359  return Slerp(q03, q12, t2);
360 }
361 
362 // XMQuaternionBaryCentric
363 NLIB_M(SimdVector)
364 Quaternion::BaryCentric(SimdQuaternionArg q0, SimdQuaternionArg q1, SimdQuaternionArg q2, float f,
365  float g) NLIB_NOEXCEPT {
366  float fg = f + g;
367  if (fg <= 0.00001f && fg >= -0.00001f) return q0; // to avoid division by zero
368  SimdQuaternion q01 = Slerp(q0, q1, fg);
369  SimdQuaternion q02 = Slerp(q0, q2, fg);
370  return Slerp(q01, q02, g / fg);
371 }
372 
373 // XMQuaternionSquadSetup
374 inline void __vectorcall Quaternion::SquadSetup(SimdQuaternion* a, SimdQuaternion* b,
378  SimdQuaternion Q0, Q2, Q3;
379  {
380  f128 lensq_a01 = Quaternion::LengthSq(F128::Add(q0, q1));
381  f128 lensq_s01 = Quaternion::LengthSq(F128::Sub(q0, q1));
382  f128 cmp01 = F128::CmpLt(lensq_a01, lensq_s01);
383  f128 neg_q0 = F128::Negate(q0);
384  Q0 = F128::Select(cmp01, neg_q0, q0);
385 
386  f128 lensq_a12 = Quaternion::LengthSq(F128::Add(q1, q2));
387  f128 lensq_s12 = Quaternion::LengthSq(F128::Sub(q1, q2));
388  f128 cmp12 = F128::CmpLt(lensq_a12, lensq_s12);
389  f128 neg_q2 = F128::Negate(q2);
390  Q2 = F128::Select(cmp12, neg_q2, q2);
391 
392  f128 lensq_a23 = Quaternion::LengthSq(F128::Add(q2, q3));
393  f128 lensq_s23 = Quaternion::LengthSq(F128::Sub(q2, q3));
394  f128 cmp23 = F128::CmpLt(lensq_a23, lensq_s23);
395  f128 neg_q3 = F128::Negate(q3);
396  Q3 = F128::Select(cmp23, neg_q3, q3);
397  }
398  const SimdQuaternion& Q1 = q1;
399 
400  SimdQuaternion InvQ1 = Quaternion::Inverse(Q1);
401  SimdQuaternion Ln_ExpQ1_Q2 = Quaternion::Ln(Quaternion::Mult(InvQ1, Q2));
402  SimdQuaternion Ln_ExpQ1_Q0 = Quaternion::Ln(Quaternion::Mult(InvQ1, Q0));
403 
404  SimdQuaternion InvQ2 = Quaternion::Inverse(Q2);
405  SimdQuaternion Ln_ExpQ2_Q3 = Quaternion::Ln(Quaternion::Mult(InvQ2, Q3));
406  SimdQuaternion Ln_ExpQ2_Q1 = Quaternion::Ln(Quaternion::Mult(InvQ2, Q1));
407 
408  f128 v0_25 = F128::SetValue(0.25f, each_float);
409  SimdQuaternion A = F128::Mult(v0_25, F128::Add(Ln_ExpQ1_Q2, Ln_ExpQ1_Q0));
410  SimdQuaternion B = F128::Mult(v0_25, F128::Add(Ln_ExpQ2_Q3, Ln_ExpQ2_Q1));
411  A = Quaternion::Exp(A);
412  B = Quaternion::Exp(B);
413 
414  *a = Quaternion::Mult(Q1, A);
415  *b = Quaternion::Mult(Q2, B);
416  *c = Q2;
417 }
418 
419 #undef NLIB_M
420 
421 #endif // NLIB_DOXYGEN
422 
423 } // namespace simd
424 NLIB_NAMESPACE_END
425 
426 #endif // INCLUDE_NN_NLIB_SIMD_SIMDQUATERNION_H_
The class with the collection of functions that handle quaternions.
f128arg SimdVectorArg
f128arg is defined using typedef.
Definition: SimdFloat.h:4157
#define NLIB_VIS_HIDDEN
Symbols for functions and classes are not made available outside of the library.
Definition: Platform_unix.h:86
constexpr const each_float_tag each_float
The tag for representing a single-precision floating-point number with an each_float_tag-type constan...
Definition: SimdFloat.h:74
f128arg SimdQuaternionArg
f128arg is defined using typedef.
Definition: SimdFloat.h:4159
The structure for keeping a 4x4 matrix.
Definition: SimdFloat.h:4168
nlib_f128x2_t f128x2
nlib_f128x2_t is defined using typedef.
Definition: SimdFloat.h:79
#define NLIB_NOEXCEPT
Defines noexcept geared to the environment, or the equivalent.
Definition: Config.h:109
Defines the class and functions for SIMD computations on single-precision floating-point numbers...
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:63
nlib_f128_t f128
nlib_f128_t is defined using typedef.
Definition: SimdFloat.h:77
Defines a four-dimensional vector.
f128 SimdQuaternion
f128 is defined using typedef. Used when handling quaternions.
Definition: SimdFloat.h:4158
#define NLIB_NONNULL
Indicates that you cannot specify NULL for all arguments.
f128 SimdVector
f128 is defined using typedef. Used when handling three-dimensional or four-dimensional vectors...
Definition: SimdFloat.h:4156