@@ -143,8 +143,10 @@ void CrossProduct( const float *v1, const float *v2, float *cross )
143143 memcpy (&v1_reg, v1, sizeof (float ) * 3 );
144144 memcpy (&v2_reg, v2, sizeof (float ) * 3 );
145145
146- float32x4_t yzxy_a = vextq_f32 (vextq_f32 (v1_reg, v1_reg, 3 ), v1_reg, 2 ); // [aj, ak, ai, aj]
147- float32x4_t yzxy_b = vextq_f32 (vextq_f32 (v2_reg, v2_reg, 3 ), v2_reg, 2 ); // [bj, bk, bi, bj]
146+ float32x2_t xy_a = vget_low_f32 (v1_reg);
147+ float32x2_t xy_b = vget_low_f32 (v2_reg);
148+ float32x4_t yzxy_a = vcombine_f32 (vext_f32 (xy_a, vget_high_f32 (v1_reg), 1 ), xy_a); // [aj, ak, ai, aj]
149+ float32x4_t yzxy_b = vcombine_f32 (vext_f32 (xy_b, vget_high_f32 (v2_reg), 1 ), xy_b); // [bj, bk, bi, bj]
148150 float32x4_t zxyy_a = vextq_f32 (yzxy_a, yzxy_a, 1 ); // [ak, ai, aj, aj]
149151 float32x4_t zxyy_b = vextq_f32 (yzxy_b, yzxy_b, 1 ); // [bk, ai, bj, bj]
150152 float32x4_t cross_reg = vfmsq_f32 (vmulq_f32 (yzxy_a, zxyy_b), zxyy_a, yzxy_b); // [ajbk-akbj, akbi-aibk, aibj-ajbi, 0]
@@ -265,23 +267,23 @@ void AngleQuaternion( float *angles, vec4_t quaternion )
265267 sincos_ps (vmulq_n_f32 (angles_reg, 0.5 ), &sr_sp_sy_0_cr_cp_cy_1.val [0 ], &sr_sp_sy_0_cr_cp_cy_1.val [1 ]);
266268
267269 float32x4x2_t sr_sy_cr_cy_sp_0_cp_1 = vuzpq_f32 (sr_sp_sy_0_cr_cp_cy_1.val [0 ], sr_sp_sy_0_cr_cp_cy_1.val [1 ]);
268- float32x4_t cp_cp_cp_cp = vdupq_laneq_f32 (sr_sp_sy_0_cr_cp_cy_1.val [1 ], 1 );
269- float32x4_t sp_sp_sp_sp = vdupq_laneq_f32 (sr_sp_sy_0_cr_cp_cy_1.val [0 ], 1 );
270270
271271 float32x4_t sr_sy_cr_cy = sr_sy_cr_cy_sp_0_cp_1.val [0 ];
272272 float32x4_t sy_cr_cy_sr = vextq_f32 (sr_sy_cr_cy_sp_0_cp_1.val [0 ], sr_sy_cr_cy_sp_0_cp_1.val [0 ], 1 );
273- float32x4_t cr_cy_sr_sy = vextq_f32 (sr_sy_cr_cy_sp_0_cp_1.val [0 ], sr_sy_cr_cy_sp_0_cp_1.val [0 ], 2 );
274- float32x4_t cy_sr_sy_cr = vextq_f32 (sr_sy_cr_cy_sp_0_cp_1.val [0 ], sr_sy_cr_cy_sp_0_cp_1.val [0 ], 3 );
275- float32x4_t sp_sp_sp_sp_signed = vreinterpretq_f32_u32 (veorq_u32 (vreinterpretq_u32_f32 (sp_sp_sp_sp), AngleQuaternion_sign2));
273+ float32x4_t srsy_sycr_crcy_cysr = vmulq_f32 (sr_sy_cr_cy, sy_cr_cy_sr);
274+ float32x4_t sycr_crcy_cysr_srsy = vextq_f32 (srsy_sycr_crcy_cysr, srsy_sycr_crcy_cysr, 1 );
275+ float32x4_t cysr_srsy_sycr_crcy = vextq_f32 (srsy_sycr_crcy_cysr, srsy_sycr_crcy_cysr, 3 );
276+ float32x4_t sycr_crcy_cysr_srsy_signed = vreinterpretq_f32_u32 (veorq_u32 (vreinterpretq_u32_f32 (sycr_crcy_cysr_srsy), AngleQuaternion_sign2));
276277
277- float32x4_t left = vmulq_f32 ( vmulq_f32 (sr_sy_cr_cy, cp_cp_cp_cp), cy_sr_sy_cr );
278+ float32x4_t left = vmulq_laneq_f32 (cysr_srsy_sycr_crcy, sr_sp_sy_0_cr_cp_cy_1. val [ 1 ], 1 );
278279
279- float32x4_t out_reg = vfmaq_f32 (left, vmulq_f32 (cr_cy_sr_sy, sp_sp_sp_sp_signed), sy_cr_cy_sr );
280+ float32x4_t out_reg = vfmaq_laneq_f32 (left, sycr_crcy_cysr_srsy_signed, sr_sp_sy_0_cr_cp_cy_1. val [ 0 ], 1 );
280281 memcpy (quaternion, &out_reg, sizeof (float ) * 4 );
281- // quaternion[0] = sr * cp * cy - cr * sp * sy; // X
282- // quaternion[1] = sy * cp * sr + cy * sp * cr; // Y
283- // quaternion[2] = cr * cp * sy - sr * sp * cy; // Z
284- // quaternion[3] = cy * cp * cr + sy * sp * sr; // W
282+ // A = sr * sy, B = sy * cr, C = cr * cy, D = cy * sr
283+ // quaternion[0] = D * cp - B * sp; // X
284+ // quaternion[1] = A * cp + C * sp; // Y
285+ // quaternion[2] = B * cp - D * sp; // Z
286+ // quaternion[3] = C * cp + A * sp; // W
285287#else
286288 float angle;
287289 float sr, sp, sy, cr, cp, cy;
@@ -400,6 +402,63 @@ void QuaternionSlerp( vec4_t p, vec4_t q, float t, vec4_t qt )
400402#endif
401403}
402404
405+ /*
406+ ====================
407+ QuaternionSlerpX4
408+
409+ ====================
410+ */
411+ void QuaternionSlerpX4 ( vec4_t p[4 ], vec4_t q[4 ], float t, vec4_t qt[4 ] )
412+ {
413+ #if XASH_SIMD_NEON
414+ float32x4x4_t p_reg, q_reg;
415+ memcpy (&p_reg, p, sizeof (float ) * 4 * 4 );
416+ memcpy (&q_reg, q, sizeof (float ) * 4 * 4 );
417+
418+ // float32x4_t cosom = { DotProduct(p[0], q[0]), DotProduct(p[1], q[1]), DotProduct(p[2], q[2]), DotProduct(p[3], q[3]) };
419+ float32x4x4_t p_t = vld4q_f32 ((const float *)&p_reg);
420+ float32x4x4_t q_t = vld4q_f32 ((const float *)&q_reg);
421+ float32x4_t cosom = vmulq_f32 (p_t .val [0 ], q_t .val [0 ]);
422+ cosom = vfmaq_f32 (cosom, p_t .val [1 ], q_t .val [1 ]);
423+ cosom = vfmaq_f32 (cosom, p_t .val [2 ], q_t .val [2 ]);
424+ cosom = vfmaq_f32 (cosom, p_t .val [3 ], q_t .val [3 ]);
425+
426+ // if(cosom < 0) q=-q, cosom=-cosom
427+ uint32x4_t sign = vandq_u32 (vreinterpretq_u32_f32 (cosom), vdupq_n_u32 (0x80000000 ));
428+ q_reg.val [0 ] = vreinterpretq_f32_u32 (veorq_u32 (vreinterpretq_u32_f32 (q_reg.val [0 ]), vdupq_laneq_u32 (sign, 0 )));
429+ q_reg.val [1 ] = vreinterpretq_f32_u32 (veorq_u32 (vreinterpretq_u32_f32 (q_reg.val [1 ]), vdupq_laneq_u32 (sign, 1 )));
430+ q_reg.val [2 ] = vreinterpretq_f32_u32 (veorq_u32 (vreinterpretq_u32_f32 (q_reg.val [2 ]), vdupq_laneq_u32 (sign, 2 )));
431+ q_reg.val [3 ] = vreinterpretq_f32_u32 (veorq_u32 (vreinterpretq_u32_f32 (q_reg.val [3 ]), vdupq_laneq_u32 (sign, 3 )));
432+ cosom = vabsq_f32 (cosom);
433+
434+ float32x4_t sclp = vdupq_n_f32 (1 .0f - t);
435+ float32x4_t sclq = vdupq_n_f32 (t);
436+ // if ((1.0 - cosom) > 0.000001) scl = sin(scl * omega) / sinom;
437+ uint32x4_t cosom_less_then_one = vcltq_f32 (cosom, vdupq_n_f32 (1 .0f - 0 .00001f ));
438+ float32x4_t omega = acos_ps (cosom);
439+ // 1/sinom = rsqrt(1-cosom*cosom)
440+ float32x4_t sinom = sin_ps (omega);
441+ float32x4_t sinom_reciprocal = vrecpeq_f32 (sinom); // vdivq_f32(vdupq_n_f32(1), sin_ps(omega));
442+ sinom_reciprocal = vmulq_f32 (sinom_reciprocal, vrecpsq_f32 (sinom, sinom_reciprocal));
443+ sclp = vbslq_f32 (cosom_less_then_one, sclp, vmulq_f32 (sin_ps (vmulq_f32 (sclp, omega)), sinom_reciprocal));
444+ sclq = vbslq_f32 (cosom_less_then_one, sclq, vmulq_f32 (sin_ps (vmulq_f32 (sclq, omega)), sinom_reciprocal));
445+
446+ // qt = (sclp * p + sclq * q);
447+ float32x4x4_t qt_reg;
448+ qt_reg.val [0 ] = vfmaq_laneq_f32 (vmulq_laneq_f32 (p_reg.val [0 ], sclp, 0 ), q_reg.val [0 ], sclq, 0 );
449+ qt_reg.val [1 ] = vfmaq_laneq_f32 (vmulq_laneq_f32 (p_reg.val [1 ], sclp, 1 ), q_reg.val [1 ], sclq, 1 );
450+ qt_reg.val [2 ] = vfmaq_laneq_f32 (vmulq_laneq_f32 (p_reg.val [2 ], sclp, 2 ), q_reg.val [2 ], sclq, 2 );
451+ qt_reg.val [3 ] = vfmaq_laneq_f32 (vmulq_laneq_f32 (p_reg.val [3 ], sclp, 3 ), q_reg.val [3 ], sclq, 3 );
452+
453+ memcpy (qt, &qt_reg, sizeof (float ) * 4 * 4 );
454+ #else
455+ QuaternionSlerp (p[0 ], q[0 ], t, qt[0 ]);
456+ QuaternionSlerp (p[1 ], q[1 ], t, qt[1 ]);
457+ QuaternionSlerp (p[2 ], q[2 ], t, qt[2 ]);
458+ QuaternionSlerp (p[3 ], q[3 ], t, qt[3 ]);
459+ #endif
460+ }
461+
403462/*
404463====================
405464QuaternionMatrix
0 commit comments