Initial commit

This commit is contained in:
Martin Felis
2021-11-11 21:22:24 +01:00
commit b78045ffe7
812 changed files with 421882 additions and 0 deletions
+84
View File
@@ -0,0 +1,84 @@
//----------------------------------------------------------------------------//
// //
// ozz-animation is hosted at http://github.com/guillaumeblanc/ozz-animation //
// and distributed under the MIT License (MIT). //
// //
// Copyright (c) Guillaume Blanc //
// //
// Permission is hereby granted, free of charge, to any person obtaining a //
// copy of this software and associated documentation files (the "Software"), //
// to deal in the Software without restriction, including without limitation //
// the rights to use, copy, modify, merge, publish, distribute, sublicense, //
// and/or sell copies of the Software, and to permit persons to whom the //
// Software is furnished to do so, subject to the following conditions: //
// //
// The above copyright notice and this permission notice shall be included in //
// all copies or substantial portions of the Software. //
// //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR //
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, //
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL //
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER //
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING //
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER //
// DEALINGS IN THE SOFTWARE. //
// //
//----------------------------------------------------------------------------//
#ifndef OZZ_OZZ_BASE_MATHS_BOX_H_
#define OZZ_OZZ_BASE_MATHS_BOX_H_
#include <cstddef>
#include "ozz/base/maths/vec_float.h"
namespace ozz {
namespace math {
// Matrix forward declaration.
struct Float4x4;
// Defines an axis aligned box.
struct Box {
// Constructs an invalid box.
Box();
// Constructs a box with the specified _min and _max bounds.
Box(const Float3& _min, const Float3& _max) : min(_min), max(_max) {}
// Constructs the smallest box that contains the _count points _points.
// _stride is the number of bytes between points.
explicit Box(const Float3& _point) : min(_point), max(_point) {}
// Constructs the smallest box that contains the _count points _points.
// _stride is the number of bytes between points, it must be greater or
// equal to sizeof(Float3).
Box(const Float3* _points, size_t _stride, size_t _count);
// Tests whether *this is a valid box.
bool is_valid() const { return min <= max; }
// Tests whether _p is within box bounds.
bool is_inside(const Float3& _p) const { return _p >= min && _p <= max; }
// Box's min and max bounds.
Float3 min;
Float3 max;
};
// Merges two boxes _a and _b.
// Both _a and _b can be invalid.
OZZ_INLINE Box Merge(const Box& _a, const Box& _b) {
if (!_a.is_valid()) {
return _b;
} else if (!_b.is_valid()) {
return _a;
}
return Box(Min(_a.min, _b.min), Max(_a.max, _b.max));
}
// Compute box transformation by a matrix.
Box TransformBox(const Float4x4& _matrix, const Box& _box);
} // namespace math
} // namespace ozz
#endif // OZZ_OZZ_BASE_MATHS_BOX_H_
@@ -0,0 +1,463 @@
//----------------------------------------------------------------------------//
// //
// ozz-animation is hosted at http://github.com/guillaumeblanc/ozz-animation //
// and distributed under the MIT License (MIT). //
// //
// Copyright (c) Guillaume Blanc //
// //
// Permission is hereby granted, free of charge, to any person obtaining a //
// copy of this software and associated documentation files (the "Software"), //
// to deal in the Software without restriction, including without limitation //
// the rights to use, copy, modify, merge, publish, distribute, sublicense, //
// and/or sell copies of the Software, and to permit persons to whom the //
// Software is furnished to do so, subject to the following conditions: //
// //
// The above copyright notice and this permission notice shall be included in //
// all copies or substantial portions of the Software. //
// //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR //
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, //
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL //
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER //
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING //
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER //
// DEALINGS IN THE SOFTWARE. //
// //
//----------------------------------------------------------------------------//
#ifndef OZZ_OZZ_BASE_MATHS_GTEST_MATH_HELPER_H_
#define OZZ_OZZ_BASE_MATHS_GTEST_MATH_HELPER_H_
static const float kFloatNearTolerance = 1e-5f;
static const float kFloatNearEstTolerance = 1e-3f;
// Implements "float near" test as a function. Avoids overloading compiler
// optimizer when too much EXPECT_NEAR are used in a single compilation unit.
inline void ExpectFloatNear(float _a, float _b,
float _tol = kFloatNearTolerance) {
EXPECT_NEAR(_a, _b, _tol);
}
// Implements "int equality" test as a function. Avoids overloading compiler
// optimizer when too much EXPECT_TRUE are used in a single compilation unit.
inline void ExpectIntEq(int _a, int _b) { EXPECT_EQ(_a, _b); }
// Implements "bool equality" test as a function. Avoids overloading compiler
// optimizer when too much EXPECT_TRUE are used in a single compilation unit.
inline void ExpectTrue(bool _b) { EXPECT_TRUE(_b); }
// Macro for testing floats, dedicated to estimated functions with a lower
// precision.
#define EXPECT_FLOAT_EQ_EST(_expected, _x) \
EXPECT_NEAR(_expected, _x, kFloatNearEstTolerance)
// Macro for testing ozz::math::Float4 members with x, y, z, w float values,
// using EXPECT_FLOAT_EQ internally.
#define EXPECT_FLOAT4_EQ(_expected, _x, _y, _z, _w) \
\
do { \
SCOPED_TRACE(""); \
const ozz::math::Float4 expected(_expected); \
ExpectFloatNear(expected.x, _x); \
ExpectFloatNear(expected.y, _y); \
ExpectFloatNear(expected.z, _z); \
ExpectFloatNear(expected.w, _w); \
\
} while (void(0), 0)
// Macro for testing ozz::math::Float3 members with x, y, z float values,
// using EXPECT_FLOAT_EQ internally.
#define EXPECT_FLOAT3_EQ(_expected, _x, _y, _z) \
\
do { \
SCOPED_TRACE(""); \
const ozz::math::Float3 expected(_expected); \
ExpectFloatNear(expected.x, _x); \
ExpectFloatNear(expected.y, _y); \
ExpectFloatNear(expected.z, _z); \
\
} while (void(0), 0)
// Macro for testing ozz::math::Float2 members with x, y float values,
// using EXPECT_NEAR internally.
#define EXPECT_FLOAT2_EQ(_expected, _x, _y) \
\
do { \
SCOPED_TRACE(""); \
const ozz::math::Float2 expected(_expected); \
ExpectFloatNear(expected.x, _x); \
ExpectFloatNear(expected.y, _y); \
\
} while (void(0), 0)
// Macro for testing ozz::math::Quaternion members with x, y, z, w float value.
#define EXPECT_QUATERNION_EQ(_expected, _x, _y, _z, _w) \
\
do { \
SCOPED_TRACE(""); \
const ozz::math::Quaternion expected(_expected); \
ExpectFloatNear(expected.x, _x); \
ExpectFloatNear(expected.y, _y); \
ExpectFloatNear(expected.z, _z); \
ExpectFloatNear(expected.w, _w); \
\
} while (void(0), 0)
#define _IMPL_EXPECT_SIMDFLOAT_EQ_TOL(_expected, _x, _y, _z, _w, _tol) \
\
do { \
union { \
ozz::math::SimdFloat4 ret; \
float af[4]; \
} u = {_expected}; \
ExpectFloatNear(u.af[0], _x, _tol); \
ExpectFloatNear(u.af[1], _y, _tol); \
ExpectFloatNear(u.af[2], _z, _tol); \
ExpectFloatNear(u.af[3], _w, _tol); \
\
} while (void(0), 0)
#define _IMPL_EXPECT_SIMDFLOAT_EQ(_expected, _x, _y, _z, _w) \
_IMPL_EXPECT_SIMDFLOAT_EQ_TOL(_expected, _x, _y, _z, _w, kFloatNearTolerance)
#define _IMPL_EXPECT_SIMDFLOAT_EQ_EST(_expected, _x, _y, _z, _w) \
_IMPL_EXPECT_SIMDFLOAT_EQ_TOL(_expected, _x, _y, _z, _w, \
kFloatNearEstTolerance)
// Macro for testing ozz::math::simd::SimdFloat members with x, y, z, w values.
#define EXPECT_SIMDFLOAT_EQ(_expected, _x, _y, _z, _w) \
\
do { \
SCOPED_TRACE(""); \
_IMPL_EXPECT_SIMDFLOAT_EQ(_expected, _x, _y, _z, _w); \
\
} while (void(0), 0)
// Macro for testing ozz::math::simd::SimdFloat members with x, y, z, w values.
// Dedicated to estimated functions with a lower precision.
#define EXPECT_SIMDFLOAT_EQ_EST(_expected, _x, _y, _z, _w) \
\
do { \
SCOPED_TRACE(""); \
_IMPL_EXPECT_SIMDFLOAT_EQ_EST(_expected, _x, _y, _z, _w); \
\
} while (void(0), 0)
// Macro for testing ozz::math::simd::SimdFloat members with x, y values with
// a user defined precision.
#define _IMPL_EXPECT_SIMDFLOAT2_EQ_TOL(_expected, _x, _y, _tol) \
\
do { \
union { \
ozz::math::SimdFloat4 ret; \
float af[4]; \
} u = {_expected}; \
ExpectFloatNear(u.af[0], _x, _tol); \
ExpectFloatNear(u.af[1], _y, _tol); \
\
} while (void(0), 0)
// Macro for testing ozz::math::simd::SimdFloat members with x, y values.
#define EXPECT_SIMDFLOAT2_EQ(_expected, _x, _y) \
\
do { \
SCOPED_TRACE(""); \
_IMPL_EXPECT_SIMDFLOAT2_EQ_TOL(_expected, _x, _y, kFloatNearTolerance); \
\
} while (void(0), 0)
// Macro for testing ozz::math::simd::SimdFloat members with x, y values.
// Dedicated to estimated functions with a lower precision.
#define EXPECT_SIMDFLOAT2_EQ_EST(_expected, _x, _y) \
\
do { \
SCOPED_TRACE(""); \
_IMPL_EXPECT_SIMDFLOAT2_EQ_TOL(_expected, _x, _y, kFloatNearEstTolerance); \
\
} while (void(0), 0)
// Macro for testing ozz::math::simd::SimdFloat members with x, y, z values.
// Dedicated to estimated functions with a user defined precision.
#define EXPECT_SIMDFLOAT3_EQ_TOL(_expected, _x, _y, _z, _tol) \
\
do { \
SCOPED_TRACE(""); \
_IMPL_EXPECT_SIMDFLOAT3_EQ_TOL(_expected, _x, _y, _z, _tol); \
\
} while (void(0), 0)
// Macro for testing ozz::math::simd::SimdFloat members with x, y, z values with
// a user defined precision.
#define _IMPL_EXPECT_SIMDFLOAT3_EQ_TOL(_expected, _x, _y, _z, _tol) \
\
do { \
union { \
ozz::math::SimdFloat4 ret; \
float af[4]; \
} u = {_expected}; \
ExpectFloatNear(u.af[0], _x, _tol); \
ExpectFloatNear(u.af[1], _y, _tol); \
ExpectFloatNear(u.af[2], _z, _tol); \
\
} while (void(0), 0)
// Macro for testing ozz::math::simd::SimdFloat members with x, y, z values.
#define EXPECT_SIMDFLOAT3_EQ(_expected, _x, _y, _z) \
\
do { \
SCOPED_TRACE(""); \
_IMPL_EXPECT_SIMDFLOAT3_EQ_TOL(_expected, _x, _y, _z, \
kFloatNearTolerance); \
\
} while (void(0), 0)
// Macro for testing ozz::math::simd::SimdFloat members with x, y, z values.
// Dedicated to estimated functions with a lower precision.
#define EXPECT_SIMDFLOAT3_EQ_EST(_expected, _x, _y, _z) \
\
do { \
SCOPED_TRACE(""); \
_IMPL_EXPECT_SIMDFLOAT3_EQ_TOL(_expected, _x, _y, _z, \
kFloatNearEstTolerance); \
\
} while (void(0), 0)
// Macro for testing ozz::math::simd::SimdFloat members with x, y, z values.
// Dedicated to estimated functions with a user defined precision.
#define EXPECT_SIMDFLOAT3_EQ_TOL(_expected, _x, _y, _z, _tol) \
\
do { \
SCOPED_TRACE(""); \
_IMPL_EXPECT_SIMDFLOAT3_EQ_TOL(_expected, _x, _y, _z, _tol); \
\
} while (void(0), 0)
// Macro for testing ozz::math::simd::SimdInt members with x, y, z, w values.
#define EXPECT_SIMDINT_EQ(_expected, _x, _y, _z, _w) \
\
do { \
SCOPED_TRACE(""); \
union { \
ozz::math::SimdInt4 ret; \
int ai[4]; \
} u = {_expected}; \
ExpectIntEq(u.ai[0], static_cast<int>(_x)); \
ExpectIntEq(u.ai[1], static_cast<int>(_y)); \
ExpectIntEq(u.ai[2], static_cast<int>(_z)); \
ExpectIntEq(u.ai[3], static_cast<int>(_w)); \
\
} while (void(0), 0)
// Macro for testing ozz::math::SoaFloat4 members with x, y, z, w float values.
#define EXPECT_FLOAT4x4_EQ(_expected, _x0, _x1, _x2, _x3, _y0, _y1, _y2, _y3, \
_z0, _z1, _z2, _z3, _w0, _w1, _w2, _w3) \
\
do { \
SCOPED_TRACE(""); \
const ozz::math::Float4x4 expected(_expected); \
_IMPL_EXPECT_SIMDFLOAT_EQ(expected.cols[0], _x0, _x1, _x2, _x3); \
_IMPL_EXPECT_SIMDFLOAT_EQ(expected.cols[1], _y0, _y1, _y2, _y3); \
_IMPL_EXPECT_SIMDFLOAT_EQ(expected.cols[2], _z0, _z1, _z2, _z3); \
_IMPL_EXPECT_SIMDFLOAT_EQ(expected.cols[3], _w0, _w1, _w2, _w3); \
\
} while (void(0), 0)
// Macro for testing ozz::math::simd::SimdQuaternion members with x, y, z, w
// values.
#define EXPECT_SIMDQUATERNION_EQ(_expected, _x, _y, _z, _w) \
\
do { \
SCOPED_TRACE(""); \
_IMPL_EXPECT_SIMDFLOAT_EQ(_expected.xyzw, _x, _y, _z, _w); \
\
} while (void(0), 0)
// Macro for testing ozz::math::simd::SimdQuaternion members with x, y, z, w
// values.
#define EXPECT_SIMDQUATERNION_EQ_EST(_expected, _x, _y, _z, _w) \
\
do { \
SCOPED_TRACE(""); \
_IMPL_EXPECT_SIMDFLOAT_EQ_EST(_expected.xyzw, _x, _y, _z, _w); \
\
} while (void(0), 0)
// Macro for testing ozz::math::simd::SimdQuaternion members with x, y, z, w
// values.
#define EXPECT_SIMDQUATERNION_EQ_TOL(_expected, _x, _y, _z, _w, _tol) \
\
do { \
SCOPED_TRACE(""); \
_IMPL_EXPECT_SIMDFLOAT_EQ_TOL(_expected.xyzw, _x, _y, _z, _w, _tol); \
\
} while (void(0), 0)
// Macro for testing ozz::math::SoaFloat4 members with x, y, z, w float values.
#define EXPECT_SOAFLOAT4_EQ(_expected, _x0, _x1, _x2, _x3, _y0, _y1, _y2, _y3, \
_z0, _z1, _z2, _z3, _w0, _w1, _w2, _w3) \
\
do { \
SCOPED_TRACE(""); \
const ozz::math::SoaFloat4 expected(_expected); \
_IMPL_EXPECT_SIMDFLOAT_EQ(expected.x, _x0, _x1, _x2, _x3); \
_IMPL_EXPECT_SIMDFLOAT_EQ(expected.y, _y0, _y1, _y2, _y3); \
_IMPL_EXPECT_SIMDFLOAT_EQ(expected.z, _z0, _z1, _z2, _z3); \
_IMPL_EXPECT_SIMDFLOAT_EQ(expected.w, _w0, _w1, _w2, _w3); \
\
} while (void(0), 0)
// Macro for testing ozz::math::SoaFloat4 members with x, y, z, w float values.
// Dedicated to estimated functions with a lower precision.
#define EXPECT_SOAFLOAT4_EQ_EST(_expected, _x0, _x1, _x2, _x3, _y0, _y1, _y2, \
_y3, _z0, _z1, _z2, _z3, _w0, _w1, _w2, _w3) \
\
do { \
SCOPED_TRACE(""); \
const ozz::math::SoaFloat4 expected(_expected); \
_IMPL_EXPECT_SIMDFLOAT_EQ_EST(expected.x, _x0, _x1, _x2, _x3); \
_IMPL_EXPECT_SIMDFLOAT_EQ_EST(expected.y, _y0, _y1, _y2, _y3); \
_IMPL_EXPECT_SIMDFLOAT_EQ_EST(expected.z, _z0, _z1, _z2, _z3); \
_IMPL_EXPECT_SIMDFLOAT_EQ_EST(expected.w, _w0, _w1, _w2, _w3); \
\
} while (void(0), 0)
// Macro for testing ozz::math::SoaFloat3 members with x, y, z float values.
#define EXPECT_SOAFLOAT3_EQ(_expected, _x0, _x1, _x2, _x3, _y0, _y1, _y2, _y3, \
_z0, _z1, _z2, _z3) \
\
do { \
SCOPED_TRACE(""); \
const ozz::math::SoaFloat3 expected(_expected); \
_IMPL_EXPECT_SIMDFLOAT_EQ(expected.x, _x0, _x1, _x2, _x3); \
_IMPL_EXPECT_SIMDFLOAT_EQ(expected.y, _y0, _y1, _y2, _y3); \
_IMPL_EXPECT_SIMDFLOAT_EQ(expected.z, _z0, _z1, _z2, _z3); \
\
} while (void(0), 0)
// Macro for testing ozz::math::SoaFloat3 members with x, y, z float values.
// Dedicated to estimated functions with a lower precision.
#define EXPECT_SOAFLOAT3_EQ_EST(_expected, _x0, _x1, _x2, _x3, _y0, _y1, _y2, \
_y3, _z0, _z1, _z2, _z3) \
\
do { \
SCOPED_TRACE(""); \
const ozz::math::SoaFloat3 expected(_expected); \
_IMPL_EXPECT_SIMDFLOAT_EQ_EST(expected.x, _x0, _x1, _x2, _x3); \
_IMPL_EXPECT_SIMDFLOAT_EQ_EST(expected.y, _y0, _y1, _y2, _y3); \
_IMPL_EXPECT_SIMDFLOAT_EQ_EST(expected.z, _z0, _z1, _z2, _z3); \
\
} while (void(0), 0)
// Macro for testing ozz::math::SoaFloat2 members with x, y float values.
#define EXPECT_SOAFLOAT2_EQ(_expected, _x0, _x1, _x2, _x3, _y0, _y1, _y2, _y3) \
\
do { \
SCOPED_TRACE(""); \
const ozz::math::SoaFloat2 expected(_expected); \
_IMPL_EXPECT_SIMDFLOAT_EQ(expected.x, _x0, _x1, _x2, _x3); \
_IMPL_EXPECT_SIMDFLOAT_EQ(expected.y, _y0, _y1, _y2, _y3); \
\
} while (void(0), 0)
// Macro for testing ozz::math::SoaFloat2 members with x, y float values.
// Dedicated to estimated functions with a lower precision.
#define EXPECT_SOAFLOAT2_EQ_EST(_expected, _x0, _x1, _x2, _x3, _y0, _y1, _y2, \
_y3) \
\
do { \
SCOPED_TRACE(""); \
const ozz::math::SoaFloat2 expected(_expected); \
_IMPL_EXPECT_SIMDFLOAT_EQ_EST(expected.x, _x0, _x1, _x2, _x3); \
_IMPL_EXPECT_SIMDFLOAT_EQ_EST(expected.y, _y0, _y1, _y2, _y3); \
\
} while (void(0), 0)
// Macro for testing ozz::math::SoaFloat2 members with x, y float values.
#define EXPECT_SOAFLOAT1_EQ(_expected, _x0, _x1, _x2, _x3) \
_IMPL_EXPECT_SIMDFLOAT_EQ(_expected, _x0, _x1, _x2, _x3);
// Macro for testing ozz::math::SoaFloat2 members with x, y float values.
// Dedicated to estimated functions with a lower precision.
#define EXPECT_SOAFLOAT1_EQ_EST(_expected, _x0, _x1, _x2, _x3) \
_IMPL_EXPECT_SIMDFLOAT_EQ_EST(_expected, _x0, _x1, _x2, _x3);
// Macro for testing ozz::math::SoaQuaternion members with x, y, z, w float
// values.
#define EXPECT_SOAQUATERNION_EQ(_expected, _x0, _x1, _x2, _x3, _y0, _y1, _y2, \
_y3, _z0, _z1, _z2, _z3, _w0, _w1, _w2, _w3) \
\
do { \
SCOPED_TRACE(""); \
const ozz::math::SoaQuaternion expected(_expected); \
_IMPL_EXPECT_SIMDFLOAT_EQ(expected.x, _x0, _x1, _x2, _x3); \
_IMPL_EXPECT_SIMDFLOAT_EQ(expected.y, _y0, _y1, _y2, _y3); \
_IMPL_EXPECT_SIMDFLOAT_EQ(expected.z, _z0, _z1, _z2, _z3); \
_IMPL_EXPECT_SIMDFLOAT_EQ(expected.w, _w0, _w1, _w2, _w3); \
\
} while (void(0), 0)
// Macro for testing ozz::math::SoaQuaternion members with x, y, z, w float
// values.
// Dedicated to estimated functions with a lower precision.
#define EXPECT_SOAQUATERNION_EQ_EST(_expected, _x0, _x1, _x2, _x3, _y0, _y1, \
_y2, _y3, _z0, _z1, _z2, _z3, _w0, _w1, \
_w2, _w3) \
\
do { \
SCOPED_TRACE(""); \
const ozz::math::SoaQuaternion expected(_expected); \
_IMPL_EXPECT_SIMDFLOAT_EQ_EST(expected.x, _x0, _x1, _x2, _x3); \
_IMPL_EXPECT_SIMDFLOAT_EQ_EST(expected.y, _y0, _y1, _y2, _y3); \
_IMPL_EXPECT_SIMDFLOAT_EQ_EST(expected.z, _z0, _z1, _z2, _z3); \
_IMPL_EXPECT_SIMDFLOAT_EQ_EST(expected.w, _w0, _w1, _w2, _w3); \
\
} while (void(0), 0)
#define EXPECT_SOAFLOAT4x4_EQ( \
_expected, col0xx, col0xy, col0xz, col0xw, col0yx, col0yy, col0yz, col0yw, \
col0zx, col0zy, col0zz, col0zw, col0wx, col0wy, col0wz, col0ww, col1xx, \
col1xy, col1xz, col1xw, col1yx, col1yy, col1yz, col1yw, col1zx, col1zy, \
col1zz, col1zw, col1wx, col1wy, col1wz, col1ww, col2xx, col2xy, col2xz, \
col2xw, col2yx, col2yy, col2yz, col2yw, col2zx, col2zy, col2zz, col2zw, \
col2wx, col2wy, col2wz, col2ww, col3xx, col3xy, col3xz, col3xw, col3yx, \
col3yy, col3yz, col3yw, col3zx, col3zy, col3zz, col3zw, col3wx, col3wy, \
col3wz, col3ww) \
\
do { \
SCOPED_TRACE(""); \
const ozz::math::SoaFloat4x4 expected(_expected); \
_IMPL_EXPECT_SIMDFLOAT_EQ(expected.cols[0].x, col0xx, col0xy, col0xz, \
col0xw); \
_IMPL_EXPECT_SIMDFLOAT_EQ(expected.cols[0].y, col0yx, col0yy, col0yz, \
col0yw); \
_IMPL_EXPECT_SIMDFLOAT_EQ(expected.cols[0].z, col0zx, col0zy, col0zz, \
col0zw); \
_IMPL_EXPECT_SIMDFLOAT_EQ(expected.cols[0].w, col0wx, col0wy, col0wz, \
col0ww); \
_IMPL_EXPECT_SIMDFLOAT_EQ(expected.cols[1].x, col1xx, col1xy, col1xz, \
col1xw); \
_IMPL_EXPECT_SIMDFLOAT_EQ(expected.cols[1].y, col1yx, col1yy, col1yz, \
col1yw); \
_IMPL_EXPECT_SIMDFLOAT_EQ(expected.cols[1].z, col1zx, col1zy, col1zz, \
col1zw); \
_IMPL_EXPECT_SIMDFLOAT_EQ(expected.cols[1].w, col1wx, col1wy, col1wz, \
col1ww); \
_IMPL_EXPECT_SIMDFLOAT_EQ(expected.cols[2].x, col2xx, col2xy, col2xz, \
col2xw); \
_IMPL_EXPECT_SIMDFLOAT_EQ(expected.cols[2].y, col2yx, col2yy, col2yz, \
col2yw); \
_IMPL_EXPECT_SIMDFLOAT_EQ(expected.cols[2].z, col2zx, col2zy, col2zz, \
col2zw); \
_IMPL_EXPECT_SIMDFLOAT_EQ(expected.cols[2].w, col2wx, col2wy, col2wz, \
col2ww); \
_IMPL_EXPECT_SIMDFLOAT_EQ(expected.cols[3].x, col3xx, col3xy, col3xz, \
col3xw); \
_IMPL_EXPECT_SIMDFLOAT_EQ(expected.cols[3].y, col3yx, col3yy, col3yz, \
col3yw); \
_IMPL_EXPECT_SIMDFLOAT_EQ(expected.cols[3].z, col3zx, col3zy, col3zz, \
col3zw); \
_IMPL_EXPECT_SIMDFLOAT_EQ(expected.cols[3].w, col3wx, col3wy, col3wz, \
col3ww); \
\
} while (void(0), 0)
#endif // OZZ_OZZ_BASE_MATHS_GTEST_MATH_HELPER_H_
@@ -0,0 +1,159 @@
//----------------------------------------------------------------------------//
// //
// ozz-animation is hosted at http://github.com/guillaumeblanc/ozz-animation //
// and distributed under the MIT License (MIT). //
// //
// Copyright (c) Guillaume Blanc //
// //
// Permission is hereby granted, free of charge, to any person obtaining a //
// copy of this software and associated documentation files (the "Software"), //
// to deal in the Software without restriction, including without limitation //
// the rights to use, copy, modify, merge, publish, distribute, sublicense, //
// and/or sell copies of the Software, and to permit persons to whom the //
// Software is furnished to do so, subject to the following conditions: //
// //
// The above copyright notice and this permission notice shall be included in //
// all copies or substantial portions of the Software. //
// //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR //
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, //
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL //
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER //
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING //
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER //
// DEALINGS IN THE SOFTWARE. //
// //
//----------------------------------------------------------------------------//
#ifndef OZZ_OZZ_BASE_MATHS_INTERNAL_SIMD_MATH_CONFIG_H_
#define OZZ_OZZ_BASE_MATHS_INTERNAL_SIMD_MATH_CONFIG_H_
#include "ozz/base/platform.h"
// Avoid SIMD instruction detection if reference (aka scalar) implementation is
// forced.
#if !defined(OZZ_BUILD_SIMD_REF)
// Try to match a SSE2+ version.
#if defined(__AVX2__) || defined(OZZ_SIMD_AVX2)
#include <immintrin.h>
#define OZZ_SIMD_AVX2
#define OZZ_SIMD_AVX // avx is available if avx2 is.
#endif
#if defined(__FMA__) || defined(OZZ_SIMD_FMA)
#include <immintrin.h>
#define OZZ_SIMD_FMA
#endif
#if defined(__AVX__) || defined(OZZ_SIMD_AVX)
#include <immintrin.h>
#define OZZ_SIMD_AVX
#define OZZ_SIMD_SSE4_2 // SSE4.2 is available if avx is.
#endif
#if defined(__SSE4_2__) || defined(OZZ_SIMD_SSE4_2)
#include <nmmintrin.h>
#define OZZ_SIMD_SSE4_2
#define OZZ_SIMD_SSE4_1 // SSE4.1 is available if SSE4.2 is.
#endif
#if defined(__SSE4_1__) || defined(OZZ_SIMD_SSE4_1)
#include <smmintrin.h>
#define OZZ_SIMD_SSE4_1
#define OZZ_SIMD_SSSE3 // SSSE3 is available if SSE4.1 is.
#endif
#if defined(__SSSE3__) || defined(OZZ_SIMD_SSSE3)
#include <tmmintrin.h>
#define OZZ_SIMD_SSSE3
#define OZZ_SIMD_SSE3 // SSE3 is available if SSSE3 is.
#endif
#if defined(__SSE3__) || defined(OZZ_SIMD_SSE3)
#include <pmmintrin.h>
#define OZZ_SIMD_SSE3
#define OZZ_SIMD_SSE2 // SSE2 is available if SSE3 is.
#endif
// x64/amd64 have SSE2 instructions
// _M_IX86_FP is 2 if /arch:SSE2, /arch:AVX or /arch:AVX2 was used.
#if defined(__SSE2__) || defined(_M_AMD64) || defined(_M_X64) || \
(_M_IX86_FP >= 2) || defined(OZZ_SIMD_SSE2)
#include <emmintrin.h>
#define OZZ_SIMD_SSE2
#define OZZ_SIMD_SSEx // OZZ_SIMD_SSEx is the generic flag for SSE support
#endif
// End of SIMD instruction detection
#endif // !OZZ_BUILD_SIMD_REF
// SEE* intrinsics available
#if defined(OZZ_SIMD_SSEx)
namespace ozz {
namespace math {
// Vector of four floating point values.
typedef __m128 SimdFloat4;
// Argument type for Float4.
typedef const __m128 _SimdFloat4;
// Vector of four integer values.
typedef __m128i SimdInt4;
// Argument type for Int4.
typedef const __m128i _SimdInt4;
} // namespace math
} // namespace ozz
#else // No builtin simd available
// No simd instruction set detected, switch back to reference implementation.
// OZZ_SIMD_REF is the generic flag for SIMD reference implementation.
#define OZZ_SIMD_REF
// Declares reference simd float and integer vectors outside of ozz::math, in
// order to match non-reference implementation details.
// Vector of four floating point values.
struct SimdFloat4Def {
alignas(16) float x;
float y;
float z;
float w;
};
// Vector of four integer values.
struct SimdInt4Def {
alignas(16) int x;
int y;
int z;
int w;
};
namespace ozz {
namespace math {
// Vector of four floating point values.
typedef SimdFloat4Def SimdFloat4;
// Argument type for SimdFloat4
typedef const SimdFloat4& _SimdFloat4;
// Vector of four integer values.
typedef SimdInt4Def SimdInt4;
// Argument type for SimdInt4.
typedef const SimdInt4& _SimdInt4;
} // namespace math
} // namespace ozz
#endif // OZZ_SIMD_x
// Native SIMD operator already exist on some compilers, so they have to be disable from ozz implementation
#if !defined(OZZ_SIMD_REF) && (defined(__GNUC__) || defined(__llvm__))
#define OZZ_DISABLE_SSE_NATIVE_OPERATORS
#endif
#endif // OZZ_OZZ_BASE_MATHS_INTERNAL_SIMD_MATH_CONFIG_H_
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,118 @@
//----------------------------------------------------------------------------//
// //
// ozz-animation is hosted at http://github.com/guillaumeblanc/ozz-animation //
// and distributed under the MIT License (MIT). //
// //
// Copyright (c) Guillaume Blanc //
// //
// Permission is hereby granted, free of charge, to any person obtaining a //
// copy of this software and associated documentation files (the "Software"), //
// to deal in the Software without restriction, including without limitation //
// the rights to use, copy, modify, merge, publish, distribute, sublicense, //
// and/or sell copies of the Software, and to permit persons to whom the //
// Software is furnished to do so, subject to the following conditions: //
// //
// The above copyright notice and this permission notice shall be included in //
// all copies or substantial portions of the Software. //
// //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR //
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, //
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL //
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER //
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING //
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER //
// DEALINGS IN THE SOFTWARE. //
// //
//----------------------------------------------------------------------------//
#ifndef OZZ_OZZ_BASE_MATHS_MATH_ARCHIVE_H_
#define OZZ_OZZ_BASE_MATHS_MATH_ARCHIVE_H_
#include "ozz/base/io/archive_traits.h"
#include "ozz/base/platform.h"
namespace ozz {
namespace math {
struct Float2;
struct Float3;
struct Float4;
struct Quaternion;
struct Transform;
struct Box;
struct RectFloat;
struct RectInt;
} // namespace math
namespace io {
OZZ_IO_TYPE_NOT_VERSIONABLE(math::Float2)
template <>
struct Extern<math::Float2> {
static void Save(OArchive& _archive, const math::Float2* _values,
size_t _count);
static void Load(IArchive& _archive, math::Float2* _values, size_t _count,
uint32_t _version);
};
OZZ_IO_TYPE_NOT_VERSIONABLE(math::Float3)
template <>
struct Extern<math::Float3> {
static void Save(OArchive& _archive, const math::Float3* _values,
size_t _count);
static void Load(IArchive& _archive, math::Float3* _values, size_t _count,
uint32_t _version);
};
OZZ_IO_TYPE_NOT_VERSIONABLE(math::Float4)
template <>
struct Extern<math::Float4> {
static void Save(OArchive& _archive, const math::Float4* _values,
size_t _count);
static void Load(IArchive& _archive, math::Float4* _values, size_t _count,
uint32_t _version);
};
OZZ_IO_TYPE_NOT_VERSIONABLE(math::Quaternion)
template <>
struct Extern<math::Quaternion> {
static void Save(OArchive& _archive, const math::Quaternion* _values,
size_t _count);
static void Load(IArchive& _archive, math::Quaternion* _values, size_t _count,
uint32_t _version);
};
OZZ_IO_TYPE_NOT_VERSIONABLE(math::Transform)
template <>
struct Extern<math::Transform> {
static void Save(OArchive& _archive, const math::Transform* _values,
size_t _count);
static void Load(IArchive& _archive, math::Transform* _values, size_t _count,
uint32_t _version);
};
OZZ_IO_TYPE_NOT_VERSIONABLE(math::Box)
template <>
struct Extern<math::Box> {
static void Save(OArchive& _archive, const math::Box* _values, size_t _count);
static void Load(IArchive& _archive, math::Box* _values, size_t _count,
uint32_t _version);
};
OZZ_IO_TYPE_NOT_VERSIONABLE(math::RectFloat)
template <>
struct Extern<math::RectFloat> {
static void Save(OArchive& _archive, const math::RectFloat* _values,
size_t _count);
static void Load(IArchive& _archive, math::RectFloat* _values, size_t _count,
uint32_t _version);
};
OZZ_IO_TYPE_NOT_VERSIONABLE(math::RectInt)
template <>
struct Extern<math::RectInt> {
static void Save(OArchive& _archive, const math::RectInt* _values,
size_t _count);
static void Load(IArchive& _archive, math::RectInt* _values, size_t _count,
uint32_t _version);
};
} // namespace io
} // namespace ozz
#endif // OZZ_OZZ_BASE_MATHS_MATH_ARCHIVE_H_
@@ -0,0 +1,61 @@
//----------------------------------------------------------------------------//
// //
// ozz-animation is hosted at http://github.com/guillaumeblanc/ozz-animation //
// and distributed under the MIT License (MIT). //
// //
// Copyright (c) Guillaume Blanc //
// //
// Permission is hereby granted, free of charge, to any person obtaining a //
// copy of this software and associated documentation files (the "Software"), //
// to deal in the Software without restriction, including without limitation //
// the rights to use, copy, modify, merge, publish, distribute, sublicense, //
// and/or sell copies of the Software, and to permit persons to whom the //
// Software is furnished to do so, subject to the following conditions: //
// //
// The above copyright notice and this permission notice shall be included in //
// all copies or substantial portions of the Software. //
// //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR //
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, //
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL //
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER //
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING //
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER //
// DEALINGS IN THE SOFTWARE. //
// //
//----------------------------------------------------------------------------//
#ifndef OZZ_OZZ_BASE_MATHS_MATH_CONSTANT_H_
#define OZZ_OZZ_BASE_MATHS_MATH_CONSTANT_H_
#ifndef INCLUDE_OZZ_MATH_CONSTANT_H_
#define INCLUDE_OZZ_MATH_CONSTANT_H_
namespace ozz {
namespace math {
// Defines math trigonometric constants.
static const float k2Pi = 6.283185307179586476925286766559f;
static const float kPi = 3.1415926535897932384626433832795f;
static const float kPi_2 = 1.5707963267948966192313216916398f;
static const float kPi_4 = .78539816339744830961566084581988f;
static const float kSqrt3 = 1.7320508075688772935274463415059f;
static const float kSqrt3_2 = 0.86602540378443864676372317075294f;
static const float kSqrt2 = 1.4142135623730950488016887242097f;
static const float kSqrt2_2 = 0.70710678118654752440084436210485f;
// Angle unit conversion constants.
static const float kDegreeToRadian = kPi / 180.f;
static const float kRadianToDegree = 180.f / kPi;
// Defines the square normalization tolerance value.
static const float kNormalizationToleranceSq = 1e-6f;
static const float kNormalizationToleranceEstSq = 2e-3f;
// Defines the square orthogonalisation tolerance value.
static const float kOrthogonalisationToleranceSq = 1e-16f;
} // namespace math
} // namespace ozz
#endif // INCLUDE_OZZ_MATH_CONSTANT_H_
#endif // OZZ_OZZ_BASE_MATHS_MATH_CONSTANT_H_
+125
View File
@@ -0,0 +1,125 @@
//----------------------------------------------------------------------------//
// //
// ozz-animation is hosted at http://github.com/guillaumeblanc/ozz-animation //
// and distributed under the MIT License (MIT). //
// //
// Copyright (c) Guillaume Blanc //
// //
// Permission is hereby granted, free of charge, to any person obtaining a //
// copy of this software and associated documentation files (the "Software"), //
// to deal in the Software without restriction, including without limitation //
// the rights to use, copy, modify, merge, publish, distribute, sublicense, //
// and/or sell copies of the Software, and to permit persons to whom the //
// Software is furnished to do so, subject to the following conditions: //
// //
// The above copyright notice and this permission notice shall be included in //
// all copies or substantial portions of the Software. //
// //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR //
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, //
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL //
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER //
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING //
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER //
// DEALINGS IN THE SOFTWARE. //
// //
//----------------------------------------------------------------------------//
#ifndef OZZ_OZZ_BASE_MATHS_MATH_EX_H_
#define OZZ_OZZ_BASE_MATHS_MATH_EX_H_
#include <cassert>
#include <cmath>
#include "ozz/base/platform.h"
namespace ozz {
namespace math {
// Returns the linear interpolation of _a and _b with coefficient _f.
// _f is not limited to range [0,1].
OZZ_INLINE float Lerp(float _a, float _b, float _f) {
return (_b - _a) * _f + _a;
}
// Returns the minimum of _a and _b. Comparison's based on operator <.
template <typename _Ty>
OZZ_INLINE _Ty Min(_Ty _a, _Ty _b) {
return (_a < _b) ? _a : _b;
}
// Returns the maximum of _a and _b. Comparison's based on operator <.
template <typename _Ty>
OZZ_INLINE _Ty Max(_Ty _a, _Ty _b) {
return (_b < _a) ? _a : _b;
}
// Clamps _x between _a and _b. Comparison's based on operator <.
// Result is unknown if _a is not less or equal to _b.
template <typename _Ty>
OZZ_INLINE _Ty Clamp(_Ty _a, _Ty _x, _Ty _b) {
const _Ty min = _x < _b ? _x : _b;
return min < _a ? _a : min;
}
// Implements int selection, avoiding branching.
OZZ_INLINE int Select(bool _b, int _true, int _false) {
return _false ^ (-static_cast<int>(_b) & (_true ^ _false));
}
// Implements float selection, avoiding branching.
OZZ_INLINE float Select(bool _b, float _true, float _false) {
union {
float f;
int32_t i;
} t = {_true};
union {
float f;
int32_t i;
} f = {_false};
union {
int32_t i;
float f;
} r = {f.i ^ (-static_cast<int32_t>(_b) & (t.i ^ f.i))};
return r.f;
}
// Implements pointer selection, avoiding branching.
template <typename _Ty>
OZZ_INLINE _Ty* Select(bool _b, _Ty* _true, _Ty* _false) {
union {
_Ty* p;
intptr_t i;
} t = {_true};
union {
_Ty* p;
intptr_t i;
} f = {_false};
union {
intptr_t i;
_Ty* p;
} r = {f.i ^ (-static_cast<intptr_t>(_b) & (t.i ^ f.i))};
return r.p;
}
// Implements const pointer selection, avoiding branching.
template <typename _Ty>
OZZ_INLINE const _Ty* Select(bool _b, const _Ty* _true, const _Ty* _false) {
union {
const _Ty* p;
intptr_t i;
} t = {_true};
union {
const _Ty* p;
intptr_t i;
} f = {_false};
union {
intptr_t i;
const _Ty* p;
} r = {f.i ^ (-static_cast<intptr_t>(_b) & (t.i ^ f.i))};
return r.p;
}
} // namespace math
} // namespace ozz
#endif // OZZ_OZZ_BASE_MATHS_MATH_EX_H_
@@ -0,0 +1,370 @@
//----------------------------------------------------------------------------//
// //
// ozz-animation is hosted at http://github.com/guillaumeblanc/ozz-animation //
// and distributed under the MIT License (MIT). //
// //
// Copyright (c) Guillaume Blanc //
// //
// Permission is hereby granted, free of charge, to any person obtaining a //
// copy of this software and associated documentation files (the "Software"), //
// to deal in the Software without restriction, including without limitation //
// the rights to use, copy, modify, merge, publish, distribute, sublicense, //
// and/or sell copies of the Software, and to permit persons to whom the //
// Software is furnished to do so, subject to the following conditions: //
// //
// The above copyright notice and this permission notice shall be included in //
// all copies or substantial portions of the Software. //
// //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR //
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, //
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL //
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER //
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING //
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER //
// DEALINGS IN THE SOFTWARE. //
// //
//----------------------------------------------------------------------------//
#ifndef OZZ_OZZ_BASE_MATHS_QUATERNION_H_
#define OZZ_OZZ_BASE_MATHS_QUATERNION_H_
#include <cassert>
#include "ozz/base/maths/math_constant.h"
#include "ozz/base/maths/math_ex.h"
#include "ozz/base/maths/vec_float.h"
#include "ozz/base/platform.h"
namespace ozz {
namespace math {
struct Quaternion {
float x, y, z, w;
// Constructs an uninitialized quaternion.
OZZ_INLINE Quaternion() {}
// Constructs a quaternion from 4 floating point values.
OZZ_INLINE Quaternion(float _x, float _y, float _z, float _w)
: x(_x), y(_y), z(_z), w(_w) {}
// Returns a normalized quaternion initialized from an axis angle
// representation.
// Assumes the axis part (x, y, z) of _axis_angle is normalized.
// _angle.x is the angle in radian.
static OZZ_INLINE Quaternion FromAxisAngle(const Float3& _axis, float _angle);
// Returns a normalized quaternion initialized from an axis and angle cosine
// representation.
// Assumes the axis part (x, y, z) of _axis_angle is normalized.
// _angle.x is the angle cosine in radian, it must be within [-1,1] range.
static OZZ_INLINE Quaternion FromAxisCosAngle(const Float3& _axis,
float _cos);
// Returns a normalized quaternion initialized from an Euler representation.
// Euler angles are ordered Heading, Elevation and Bank, or Yaw, Pitch and
// Roll.
static OZZ_INLINE Quaternion FromEuler(float _yaw, float _pitch,
float _roll);
// Returns the quaternion that will rotate vector _from into vector _to,
// around their plan perpendicular axis.The input vectors don't need to be
// normalized, they can be null as well.
static OZZ_INLINE Quaternion FromVectors(const Float3& _from,
const Float3& _to);
// Returns the quaternion that will rotate vector _from into vector _to,
// around their plan perpendicular axis. The input vectors must be normalized.
static OZZ_INLINE Quaternion FromUnitVectors(const Float3& _from,
const Float3& _to);
// Returns the identity quaternion.
static OZZ_INLINE Quaternion identity() {
return Quaternion(0.f, 0.f, 0.f, 1.f);
}
};
// Returns true if each element of a is equal to each element of _b.
OZZ_INLINE bool operator==(const Quaternion& _a, const Quaternion& _b) {
return _a.x == _b.x && _a.y == _b.y && _a.z == _b.z && _a.w == _b.w;
}
// Returns true if one element of a differs from one element of _b.
OZZ_INLINE bool operator!=(const Quaternion& _a, const Quaternion& _b) {
return _a.x != _b.x || _a.y != _b.y || _a.z != _b.z || _a.w != _b.w;
}
// Returns the conjugate of _q. This is the same as the inverse if _q is
// normalized. Otherwise the magnitude of the inverse is 1.f/|_q|.
OZZ_INLINE Quaternion Conjugate(const Quaternion& _q) {
return Quaternion(-_q.x, -_q.y, -_q.z, _q.w);
}
// Returns the addition of _a and _b.
OZZ_INLINE Quaternion operator+(const Quaternion& _a, const Quaternion& _b) {
return Quaternion(_a.x + _b.x, _a.y + _b.y, _a.z + _b.z, _a.w + _b.w);
}
// Returns the multiplication of _q and a scalar _f.
OZZ_INLINE Quaternion operator*(const Quaternion& _q, float _f) {
return Quaternion(_q.x * _f, _q.y * _f, _q.z * _f, _q.w * _f);
}
// Returns the multiplication of _a and _b. If both _a and _b are normalized,
// then the result is normalized.
OZZ_INLINE Quaternion operator*(const Quaternion& _a, const Quaternion& _b) {
return Quaternion(_a.w * _b.x + _a.x * _b.w + _a.y * _b.z - _a.z * _b.y,
_a.w * _b.y + _a.y * _b.w + _a.z * _b.x - _a.x * _b.z,
_a.w * _b.z + _a.z * _b.w + _a.x * _b.y - _a.y * _b.x,
_a.w * _b.w - _a.x * _b.x - _a.y * _b.y - _a.z * _b.z);
}
// Returns the negate of _q. This represent the same rotation as q.
OZZ_INLINE Quaternion operator-(const Quaternion& _q) {
return Quaternion(-_q.x, -_q.y, -_q.z, -_q.w);
}
// Returns true if the angle between _a and _b is less than _tolerance.
OZZ_INLINE bool Compare(const math::Quaternion& _a, const math::Quaternion& _b,
float _cos_half_tolerance) {
// Computes w component of a-1 * b.
const float cos_half_angle =
_a.x * _b.x + _a.y * _b.y + _a.z * _b.z + _a.w * _b.w;
return std::abs(cos_half_angle) >= _cos_half_tolerance;
}
// Returns true if _q is a normalized quaternion.
OZZ_INLINE bool IsNormalized(const Quaternion& _q) {
const float sq_len = _q.x * _q.x + _q.y * _q.y + _q.z * _q.z + _q.w * _q.w;
return std::abs(sq_len - 1.f) < kNormalizationToleranceSq;
}
// Returns the normalized quaternion _q.
OZZ_INLINE Quaternion Normalize(const Quaternion& _q) {
const float sq_len = _q.x * _q.x + _q.y * _q.y + _q.z * _q.z + _q.w * _q.w;
assert(sq_len != 0.f && "_q is not normalizable");
const float inv_len = 1.f / std::sqrt(sq_len);
return Quaternion(_q.x * inv_len, _q.y * inv_len, _q.z * inv_len,
_q.w * inv_len);
}
// Returns the normalized quaternion _q if the norm of _q is not 0.
// Otherwise returns _safer.
OZZ_INLINE Quaternion NormalizeSafe(const Quaternion& _q,
const Quaternion& _safer) {
assert(IsNormalized(_safer) && "_safer is not normalized");
const float sq_len = _q.x * _q.x + _q.y * _q.y + _q.z * _q.z + _q.w * _q.w;
if (sq_len == 0) {
return _safer;
}
const float inv_len = 1.f / std::sqrt(sq_len);
return Quaternion(_q.x * inv_len, _q.y * inv_len, _q.z * inv_len,
_q.w * inv_len);
}
OZZ_INLINE Quaternion Quaternion::FromAxisAngle(const Float3& _axis,
float _angle) {
assert(IsNormalized(_axis) && "axis is not normalized.");
const float half_angle = _angle * .5f;
const float half_sin = std::sin(half_angle);
const float half_cos = std::cos(half_angle);
return Quaternion(_axis.x * half_sin, _axis.y * half_sin, _axis.z * half_sin,
half_cos);
}
OZZ_INLINE Quaternion Quaternion::FromAxisCosAngle(const Float3& _axis,
float _cos) {
assert(IsNormalized(_axis) && "axis is not normalized.");
assert(_cos >= -1.f && _cos <= 1.f && "cos is not in [-1,1] range.");
const float half_cos2 = (1.f + _cos) * 0.5f;
const float half_sin = std::sqrt(1.f - half_cos2);
return Quaternion(_axis.x * half_sin, _axis.y * half_sin, _axis.z * half_sin,
std::sqrt(half_cos2));
}
// Returns to an axis angle representation of quaternion _q.
// Assumes quaternion _q is normalized.
OZZ_INLINE Float4 ToAxisAngle(const Quaternion& _q) {
assert(IsNormalized(_q));
const float clamped_w = Clamp(-1.f, _q.w, 1.f);
const float angle = 2.f * std::acos(clamped_w);
const float s = std::sqrt(1.f - clamped_w * clamped_w);
// Assuming quaternion normalized then s always positive.
if (s < .001f) { // Tests to avoid divide by zero.
// If s close to zero then direction of axis is not important.
return Float4(1.f, 0.f, 0.f, angle);
} else {
// Normalize axis
const float inv_s = 1.f / s;
return Float4(_q.x * inv_s, _q.y * inv_s, _q.z * inv_s, angle);
}
}
OZZ_INLINE Quaternion Quaternion::FromEuler(float _yaw, float _pitch,
float _roll) {
const float half_yaw = _yaw * .5f;
const float c1 = std::cos(half_yaw);
const float s1 = std::sin(half_yaw);
const float half_pitch = _pitch * .5f;
const float c2 = std::cos(half_pitch);
const float s2 = std::sin(half_pitch);
const float half_roll = _roll * .5f;
const float c3 = std::cos(half_roll);
const float s3 = std::sin(half_roll);
const float c1c2 = c1 * c2;
const float s1s2 = s1 * s2;
return Quaternion(c1c2 * s3 + s1s2 * c3, s1 * c2 * c3 + c1 * s2 * s3,
c1 * s2 * c3 - s1 * c2 * s3, c1c2 * c3 - s1s2 * s3);
}
// Returns to an Euler representation of quaternion _q.
// Quaternion _q does not require to be normalized.
OZZ_INLINE Float3 ToEuler(const Quaternion& _q) {
const float sqw = _q.w * _q.w;
const float sqx = _q.x * _q.x;
const float sqy = _q.y * _q.y;
const float sqz = _q.z * _q.z;
// If normalized is one, otherwise is correction factor.
const float unit = sqx + sqy + sqz + sqw;
const float test = _q.x * _q.y + _q.z * _q.w;
Float3 euler;
if (test > .499f * unit) { // Singularity at north pole
euler.x = 2.f * std::atan2(_q.x, _q.w);
euler.y = ozz::math::kPi_2;
euler.z = 0;
} else if (test < -.499f * unit) { // Singularity at south pole
euler.x = -2 * std::atan2(_q.x, _q.w);
euler.y = -kPi_2;
euler.z = 0;
} else {
euler.x = std::atan2(2.f * _q.y * _q.w - 2.f * _q.x * _q.z,
sqx - sqy - sqz + sqw);
euler.y = std::asin(2.f * test / unit);
euler.z = std::atan2(2.f * _q.x * _q.w - 2.f * _q.y * _q.z,
-sqx + sqy - sqz + sqw);
}
return euler;
}
OZZ_INLINE Quaternion Quaternion::FromVectors(const Float3& _from,
const Float3& _to) {
// http://lolengine.net/blog/2014/02/24/quaternion-from-two-vectors-final
const float norm_from_norm_to = std::sqrt(LengthSqr(_from) * LengthSqr(_to));
if (norm_from_norm_to < 1.e-5f) {
return Quaternion::identity();
}
const float real_part = norm_from_norm_to + Dot(_from, _to);
Quaternion quat;
if (real_part < 1.e-6f * norm_from_norm_to) {
// If _from and _to are exactly opposite, rotate 180 degrees around an
// arbitrary orthogonal axis. Axis normalization can happen later, when we
// normalize the quaternion.
quat = std::abs(_from.x) > std::abs(_from.z)
? Quaternion(-_from.y, _from.x, 0.f, 0.f)
: Quaternion(0.f, -_from.z, _from.y, 0.f);
} else {
const Float3 cross = Cross(_from, _to);
quat = Quaternion(cross.x, cross.y, cross.z, real_part);
}
return Normalize(quat);
}
OZZ_INLINE Quaternion Quaternion::FromUnitVectors(const Float3& _from,
const Float3& _to) {
assert(IsNormalized(_from) && IsNormalized(_to) &&
"Input vectors must be normalized.");
// http://lolengine.net/blog/2014/02/24/quaternion-from-two-vectors-final
const float real_part = 1.f + Dot(_from, _to);
if (real_part < 1.e-6f) {
// If _from and _to are exactly opposite, rotate 180 degrees around an
// arbitrary orthogonal axis.
// Normalisation isn't needed, as from is already.
return std::abs(_from.x) > std::abs(_from.z)
? Quaternion(-_from.y, _from.x, 0.f, 0.f)
: Quaternion(0.f, -_from.z, _from.y, 0.f);
} else {
const Float3 cross = Cross(_from, _to);
return Normalize(Quaternion(cross.x, cross.y, cross.z, real_part));
}
}
// Returns the dot product of _a and _b.
OZZ_INLINE float Dot(const Quaternion& _a, const Quaternion& _b) {
return _a.x * _b.x + _a.y * _b.y + _a.z * _b.z + _a.w * _b.w;
}
// Returns the linear interpolation of quaternion _a and _b with coefficient
// _f.
OZZ_INLINE Quaternion Lerp(const Quaternion& _a, const Quaternion& _b,
float _f) {
return Quaternion((_b.x - _a.x) * _f + _a.x, (_b.y - _a.y) * _f + _a.y,
(_b.z - _a.z) * _f + _a.z, (_b.w - _a.w) * _f + _a.w);
}
// Returns the linear interpolation of quaternion _a and _b with coefficient
// _f. _a and _n must be from the same hemisphere (aka dot(_a, _b) >= 0).
OZZ_INLINE Quaternion NLerp(const Quaternion& _a, const Quaternion& _b,
float _f) {
const Float4 lerp((_b.x - _a.x) * _f + _a.x, (_b.y - _a.y) * _f + _a.y,
(_b.z - _a.z) * _f + _a.z, (_b.w - _a.w) * _f + _a.w);
const float sq_len =
lerp.x * lerp.x + lerp.y * lerp.y + lerp.z * lerp.z + lerp.w * lerp.w;
const float inv_len = 1.f / std::sqrt(sq_len);
return Quaternion(lerp.x * inv_len, lerp.y * inv_len, lerp.z * inv_len,
lerp.w * inv_len);
}
// Returns the spherical interpolation of quaternion _a and _b with
// coefficient _f.
OZZ_INLINE Quaternion SLerp(const Quaternion& _a, const Quaternion& _b,
float _f) {
assert(IsNormalized(_a));
assert(IsNormalized(_b));
// Calculate angle between them.
float cos_half_theta = _a.x * _b.x + _a.y * _b.y + _a.z * _b.z + _a.w * _b.w;
// If _a=_b or _a=-_b then theta = 0 and we can return _a.
if (std::abs(cos_half_theta) >= .999f) {
return _a;
}
// Calculate temporary values.
const float half_theta = std::acos(cos_half_theta);
const float sin_half_theta = std::sqrt(1.f - cos_half_theta * cos_half_theta);
// If theta = pi then result is not fully defined, we could rotate around
// any axis normal to _a or _b.
if (sin_half_theta < .001f) {
return Quaternion((_a.x + _b.x) * .5f, (_a.y + _b.y) * .5f,
(_a.z + _b.z) * .5f, (_a.w + _b.w) * .5f);
}
const float ratio_a = std::sin((1.f - _f) * half_theta) / sin_half_theta;
const float ratio_b = std::sin(_f * half_theta) / sin_half_theta;
// Calculate Quaternion.
return Quaternion(
ratio_a * _a.x + ratio_b * _b.x, ratio_a * _a.y + ratio_b * _b.y,
ratio_a * _a.z + ratio_b * _b.z, ratio_a * _a.w + ratio_b * _b.w);
}
// Computes the transformation of a Quaternion and a vector _v.
// This is equivalent to carrying out the quaternion multiplications:
// _q.conjugate() * (*this) * _q
OZZ_INLINE Float3 TransformVector(const Quaternion& _q, const Float3& _v) {
// http://www.neil.dantam.name/note/dantam-quaternion.pdf
// _v + 2.f * cross(_q.xyz, cross(_q.xyz, _v) + _q.w * _v);
const Float3 a(_q.y * _v.z - _q.z * _v.y + _v.x * _q.w,
_q.z * _v.x - _q.x * _v.z + _v.y * _q.w,
_q.x * _v.y - _q.y * _v.x + _v.z * _q.w);
const Float3 b(_q.y * a.z - _q.z * a.y, _q.z * a.x - _q.x * a.z,
_q.x * a.y - _q.y * a.x);
return Float3(_v.x + b.x + b.x, _v.y + b.y + b.y, _v.z + b.z + b.z);
}
} // namespace math
} // namespace ozz
#endif // OZZ_OZZ_BASE_MATHS_QUATERNION_H_
+99
View File
@@ -0,0 +1,99 @@
//----------------------------------------------------------------------------//
// //
// ozz-animation is hosted at http://github.com/guillaumeblanc/ozz-animation //
// and distributed under the MIT License (MIT). //
// //
// Copyright (c) Guillaume Blanc //
// //
// Permission is hereby granted, free of charge, to any person obtaining a //
// copy of this software and associated documentation files (the "Software"), //
// to deal in the Software without restriction, including without limitation //
// the rights to use, copy, modify, merge, publish, distribute, sublicense, //
// and/or sell copies of the Software, and to permit persons to whom the //
// Software is furnished to do so, subject to the following conditions: //
// //
// The above copyright notice and this permission notice shall be included in //
// all copies or substantial portions of the Software. //
// //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR //
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, //
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL //
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER //
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING //
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER //
// DEALINGS IN THE SOFTWARE. //
// //
//----------------------------------------------------------------------------//
#ifndef OZZ_OZZ_BASE_MATHS_RECT_H_
#define OZZ_OZZ_BASE_MATHS_RECT_H_
namespace ozz {
namespace math {
// Defines a rectangle by the integer coordinates of its lower-left and
// width-height.
struct RectInt {
// Constructs a uninitialized rectangle.
RectInt() {}
// Constructs a rectangle with the specified arguments.
RectInt(int _left, int _bottom, int _width, int _height)
: left(_left), bottom(_bottom), width(_width), height(_height) {}
// Tests whether _x and _y coordinates are within rectangle bounds.
bool is_inside(int _x, int _y) const {
return _x >= left && _x < left + width && _y >= bottom &&
_y < bottom + height;
}
// Gets the rectangle x coordinate of the right rectangle side.
int right() const { return left + width; }
// Gets the rectangle y coordinate of the top rectangle side.
int top() const { return bottom + height; }
// Specifies the x-coordinate of the lower side.
int left;
// Specifies the x-coordinate of the left side.
int bottom;
// Specifies the width of the rectangle.
int width;
// Specifies the height of the rectangle..
int height;
};
// Defines a rectangle by the floating point coordinates of its lower-left
// and width-height.
struct RectFloat {
// Constructs a uninitialized rectangle.
RectFloat() {}
// Constructs a rectangle with the specified arguments.
RectFloat(float _left, float _bottom, float _width, float _height)
: left(_left), bottom(_bottom), width(_width), height(_height) {}
// Tests whether _x and _y coordinates are within rectangle bounds
bool is_inside(float _x, float _y) const {
return _x >= left && _x < left + width && _y >= bottom &&
_y < bottom + height;
}
// Gets the rectangle x coordinate of the right rectangle side.
float right() const { return left + width; }
// Gets the rectangle y coordinate of the top rectangle side.
float top() const { return bottom + height; }
// Specifies the x-coordinate of the lower side.
float left;
// Specifies the x-coordinate of the left side.
float bottom;
// Specifies the width of the rectangle.
float width;
// Specifies the height of the rectangle.
float height;
};
} // namespace math
} // namespace ozz
#endif // OZZ_OZZ_BASE_MATHS_RECT_H_
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,65 @@
//----------------------------------------------------------------------------//
// //
// ozz-animation is hosted at http://github.com/guillaumeblanc/ozz-animation //
// and distributed under the MIT License (MIT). //
// //
// Copyright (c) Guillaume Blanc //
// //
// Permission is hereby granted, free of charge, to any person obtaining a //
// copy of this software and associated documentation files (the "Software"), //
// to deal in the Software without restriction, including without limitation //
// the rights to use, copy, modify, merge, publish, distribute, sublicense, //
// and/or sell copies of the Software, and to permit persons to whom the //
// Software is furnished to do so, subject to the following conditions: //
// //
// The above copyright notice and this permission notice shall be included in //
// all copies or substantial portions of the Software. //
// //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR //
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, //
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL //
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER //
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING //
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER //
// DEALINGS IN THE SOFTWARE. //
// //
//----------------------------------------------------------------------------//
#ifndef OZZ_OZZ_BASE_MATHS_SIMD_MATH_ARCHIVE_H_
#define OZZ_OZZ_BASE_MATHS_SIMD_MATH_ARCHIVE_H_
#include "ozz/base/io/archive_traits.h"
#include "ozz/base/maths/simd_math.h"
#include "ozz/base/platform.h"
namespace ozz {
namespace io {
OZZ_IO_TYPE_NOT_VERSIONABLE(math::SimdFloat4)
template <>
struct Extern<math::SimdFloat4> {
static void Save(OArchive& _archive, const math::SimdFloat4* _values,
size_t _count);
static void Load(IArchive& _archive, math::SimdFloat4* _values, size_t _count,
uint32_t _version);
};
OZZ_IO_TYPE_NOT_VERSIONABLE(math::SimdInt4)
template <>
struct Extern<math::SimdInt4> {
static void Save(OArchive& _archive, const math::SimdInt4* _values,
size_t _count);
static void Load(IArchive& _archive, math::SimdInt4* _values, size_t _count,
uint32_t _version);
};
OZZ_IO_TYPE_NOT_VERSIONABLE(math::Float4x4)
template <>
struct Extern<math::Float4x4> {
static void Save(OArchive& _archive, const math::Float4x4* _values,
size_t _count);
static void Load(IArchive& _archive, math::Float4x4* _values, size_t _count,
uint32_t _version);
};
} // namespace io
} // namespace ozz
#endif // OZZ_OZZ_BASE_MATHS_SIMD_MATH_ARCHIVE_H_
@@ -0,0 +1,274 @@
//----------------------------------------------------------------------------//
// //
// ozz-animation is hosted at http://github.com/guillaumeblanc/ozz-animation //
// and distributed under the MIT License (MIT). //
// //
// Copyright (c) Guillaume Blanc //
// //
// Permission is hereby granted, free of charge, to any person obtaining a //
// copy of this software and associated documentation files (the "Software"), //
// to deal in the Software without restriction, including without limitation //
// the rights to use, copy, modify, merge, publish, distribute, sublicense, //
// and/or sell copies of the Software, and to permit persons to whom the //
// Software is furnished to do so, subject to the following conditions: //
// //
// The above copyright notice and this permission notice shall be included in //
// all copies or substantial portions of the Software. //
// //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR //
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, //
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL //
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER //
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING //
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER //
// DEALINGS IN THE SOFTWARE. //
// //
//----------------------------------------------------------------------------//
#ifndef OZZ_OZZ_BASE_MATHS_SIMD_QUATERNION_H_
#define OZZ_OZZ_BASE_MATHS_SIMD_QUATERNION_H_
#include "ozz/base/maths/simd_math.h"
#include <cmath>
// Implement simd quaternion.
namespace ozz {
namespace math {
// Declare the Quaternion type.
struct SimdQuaternion {
SimdFloat4 xyzw;
// Returns the identity quaternion.
static OZZ_INLINE SimdQuaternion identity() {
const SimdQuaternion quat = {simd_float4::w_axis()};
return quat;
}
// the angle in radian.
static OZZ_INLINE SimdQuaternion FromAxisAngle(_SimdFloat4 _axis,
_SimdFloat4 _angle);
// Returns a normalized quaternion initialized from an axis and angle cosine
// representation.
// Assumes the axis part (x, y, z) of _axis_angle is normalized.
// _angle.x is the angle cosine in radian, it must be within [-1,1] range.
static OZZ_INLINE SimdQuaternion FromAxisCosAngle(_SimdFloat4 _axis,
_SimdFloat4 _cos);
// Returns the quaternion that will rotate vector _from into vector _to,
// around their plan perpendicular axis.The input vectors don't need to be
// normalized, they can be null also.
static OZZ_INLINE SimdQuaternion FromVectors(_SimdFloat4 _from,
_SimdFloat4 _to);
// Returns the quaternion that will rotate vector _from into vector _to,
// around their plan perpendicular axis. The input vectors must be normalized.
static OZZ_INLINE SimdQuaternion FromUnitVectors(_SimdFloat4 _from,
_SimdFloat4 _to);
// Returns a normalized quaternion initialized from an axis angle
// representation.
// Assumes the axis part (x, y, z) of _axis_angle is normalized. _angle.x is
};
// Returns the multiplication of _a and _b. If both _a and _b are normalized,
// then the result is normalized.
OZZ_INLINE SimdQuaternion operator*(const SimdQuaternion& _a,
const SimdQuaternion& _b) {
// Original quaternion multiplication can be swizzled in a simd friendly way
// if w is negated, and some w multiplications parts (1st/last) are swaped.
//
// p1 p2 p3 p4
// _a.w * _b.x + _a.x * _b.w + _a.y * _b.z - _a.z * _b.y
// _a.w * _b.y + _a.y * _b.w + _a.z * _b.x - _a.x * _b.z
// _a.w * _b.z + _a.z * _b.w + _a.x * _b.y - _a.y * _b.x
// _a.w * _b.w - _a.x * _b.x - _a.y * _b.y - _a.z * _b.z
// ... becomes ->
// _a.w * _b.x + _a.x * _b.w + _a.y * _b.z - _a.z * _b.y
// _a.w * _b.y + _a.y * _b.w + _a.z * _b.x - _a.x * _b.z
// _a.w * _b.z + _a.z * _b.w + _a.x * _b.y - _a.y * _b.x
// - (_a.z * _b.z + _a.x * _b.x + _a.y * _b.y - _a.w * _b.w)
const SimdFloat4 p1 =
Swizzle<3, 3, 3, 2>(_a.xyzw) * Swizzle<0, 1, 2, 2>(_b.xyzw);
const SimdFloat4 p2 =
Swizzle<0, 1, 2, 0>(_a.xyzw) * Swizzle<3, 3, 3, 0>(_b.xyzw);
const SimdFloat4 p13 =
MAdd(Swizzle<1, 2, 0, 1>(_a.xyzw), Swizzle<2, 0, 1, 1>(_b.xyzw), p1);
const SimdFloat4 p24 =
NMAdd(Swizzle<2, 0, 1, 3>(_a.xyzw), Swizzle<1, 2, 0, 3>(_b.xyzw), p2);
const SimdQuaternion quat = {Xor(p13 + p24, simd_int4::mask_sign_w())};
return quat;
}
// Returns the conjugate of _q. This is the same as the inverse if _q is
// normalized. Otherwise the magnitude of the inverse is 1.f/|_q|.
OZZ_INLINE SimdQuaternion Conjugate(const SimdQuaternion& _q) {
const SimdQuaternion quat = {Xor(_q.xyzw, simd_int4::mask_sign_xyz())};
return quat;
}
// Returns the negate of _q. This represent the same rotation as q.
OZZ_INLINE SimdQuaternion operator-(const SimdQuaternion& _q) {
const SimdQuaternion quat = {Xor(_q.xyzw, simd_int4::mask_sign())};
return quat;
}
// Returns the normalized quaternion _q.
OZZ_INLINE SimdQuaternion Normalize(const SimdQuaternion& _q) {
const SimdQuaternion quat = {Normalize4(_q.xyzw)};
return quat;
}
// Returns the normalized quaternion _q if the norm of _q is not 0.
// Otherwise returns _safer.
OZZ_INLINE SimdQuaternion NormalizeSafe(const SimdQuaternion& _q,
const SimdQuaternion& _safer) {
const SimdQuaternion quat = {NormalizeSafe4(_q.xyzw, _safer.xyzw)};
return quat;
}
// Returns the estimated normalized quaternion _q.
OZZ_INLINE SimdQuaternion NormalizeEst(const SimdQuaternion& _q) {
const SimdQuaternion quat = {NormalizeEst4(_q.xyzw)};
return quat;
}
// Returns the estimated normalized quaternion _q if the norm of _q is not 0.
// Otherwise returns _safer.
OZZ_INLINE SimdQuaternion NormalizeSafeEst(const SimdQuaternion& _q,
const SimdQuaternion& _safer) {
const SimdQuaternion quat = {NormalizeSafeEst4(_q.xyzw, _safer.xyzw)};
return quat;
}
// Tests if the _q is a normalized quaternion.
// Returns the result in the x component of the returned vector. y, z and w are
// set to 0.
OZZ_INLINE SimdInt4 IsNormalized(const SimdQuaternion& _q) {
return IsNormalized4(_q.xyzw);
}
// Tests if the _q is a normalized quaternion.
// Uses the estimated normalization coefficient, that matches estimated math
// functions (RecpEst, MormalizeEst...).
// Returns the result in the x component of the returned vector. y, z and w are
// set to 0.
OZZ_INLINE SimdInt4 IsNormalizedEst(const SimdQuaternion& _q) {
return IsNormalizedEst4(_q.xyzw);
}
OZZ_INLINE SimdQuaternion SimdQuaternion::FromAxisAngle(_SimdFloat4 _axis,
_SimdFloat4 _angle) {
assert(AreAllTrue1(IsNormalizedEst3(_axis)) && "axis is not normalized.");
const SimdFloat4 half_angle = _angle * simd_float4::Load1(.5f);
const SimdFloat4 half_sin = SinX(half_angle);
const SimdFloat4 half_cos = CosX(half_angle);
const SimdQuaternion quat = {SetW(_axis * SplatX(half_sin), half_cos)};
return quat;
}
OZZ_INLINE SimdQuaternion SimdQuaternion::FromAxisCosAngle(_SimdFloat4 _axis,
_SimdFloat4 _cos) {
const SimdFloat4 one = simd_float4::one();
const SimdFloat4 half = simd_float4::Load1(.5f);
assert(AreAllTrue1(IsNormalizedEst3(_axis)) && "axis is not normalized.");
assert(AreAllTrue1(And(CmpGe(_cos, -one), CmpLe(_cos, one))) &&
"cos is not in [-1,1] range.");
const SimdFloat4 half_cos2 = (one + _cos) * half;
const SimdFloat4 half_sin2 = one - half_cos2;
const SimdFloat4 half_sincos2 = SetY(half_cos2, half_sin2);
const SimdFloat4 half_sincos = Sqrt(half_sincos2);
const SimdFloat4 half_sin = SplatY(half_sincos);
const SimdQuaternion quat = {SetW(_axis * half_sin, half_sincos)};
return quat;
}
// Returns to an axis angle representation of quaternion _q.
// Assumes quaternion _q is normalized.
OZZ_INLINE SimdFloat4 ToAxisAngle(const SimdQuaternion& _q) {
assert(AreAllTrue1(IsNormalizedEst4(_q.xyzw)) && "_q is not normalized.");
const SimdFloat4 x_axis = simd_float4::x_axis();
const SimdFloat4 clamped_w = Clamp(-x_axis, SplatW(_q.xyzw), x_axis);
const SimdFloat4 half_angle = ACosX(clamped_w);
// Assuming quaternion is normalized then s always positive.
const SimdFloat4 s = SplatX(SqrtX(NMAdd(clamped_w, clamped_w, x_axis)));
// If s is close to zero then direction of axis is not important.
const SimdInt4 low = CmpLt(s, simd_float4::Load1(1e-3f));
return Select(low, x_axis,
SetW(_q.xyzw * RcpEstNR(s), half_angle + half_angle));
}
OZZ_INLINE SimdQuaternion SimdQuaternion::FromVectors(_SimdFloat4 _from,
_SimdFloat4 _to) {
// http://lolengine.net/blog/2014/02/24/quaternion-from-two-vectors-final
const SimdFloat4 norm_from_norm_to =
SqrtX(Length3Sqr(_from) * Length3Sqr(_to));
const float norm_from_norm_to_x = GetX(norm_from_norm_to);
if (norm_from_norm_to_x < 1.e-6f) {
return SimdQuaternion::identity();
}
const SimdFloat4 real_part = norm_from_norm_to + Dot3(_from, _to);
SimdQuaternion quat;
if (GetX(real_part) < 1.e-6f * norm_from_norm_to_x) {
// If _from and _to are exactly opposite, rotate 180 degrees around an
// arbitrary orthogonal axis. Axis normalization can happen later, when we
// normalize the quaternion.
float from[4];
ozz::math::StorePtrU(_from, from);
quat.xyzw = std::abs(from[0]) > std::abs(from[2])
? ozz::math::simd_float4::Load(-from[1], from[0], 0.f, 0.f)
: ozz::math::simd_float4::Load(0.f, -from[2], from[1], 0.f);
} else {
// This is the general code path.
quat.xyzw = SetW(Cross3(_from, _to), real_part);
}
return Normalize(quat);
}
OZZ_INLINE SimdQuaternion SimdQuaternion::FromUnitVectors(_SimdFloat4 _from,
_SimdFloat4 _to) {
// http://lolengine.net/blog/2014/02/24/quaternion-from-two-vectors-final
assert(ozz::math::AreAllTrue1(
And(IsNormalizedEst3(_from), IsNormalizedEst3(_to))) &&
"Input vectors must be normalized.");
const SimdFloat4 real_part =
ozz::math::simd_float4::x_axis() + Dot3(_from, _to);
if (GetX(real_part) < 1.e-6f) {
// If _from and _to are exactly opposite, rotate 180 degrees around an
// arbitrary orthogonal axis.
// Normalization isn't needed, as from is already.
float from[4];
ozz::math::StorePtrU(_from, from);
SimdQuaternion quat = {
std::abs(from[0]) > std::abs(from[2])
? ozz::math::simd_float4::Load(-from[1], from[0], 0.f, 0.f)
: ozz::math::simd_float4::Load(0.f, -from[2], from[1], 0.f)};
return quat;
} else {
// This is the general code path.
SimdQuaternion quat = {SetW(Cross3(_from, _to), real_part)};
return Normalize(quat);
}
}
// Computes the transformation of a Quaternion and a vector _v.
// This is equivalent to carrying out the quaternion multiplications:
// _q.conjugate() * (*this) * _q
// w component of the returned vector is undefined.
OZZ_INLINE SimdFloat4 TransformVector(const SimdQuaternion& _q,
_SimdFloat4 _v) {
// http://www.neil.dantam.name/note/dantam-quaternion.pdf
// _v + 2.f * cross(_q.xyz, cross(_q.xyz, _v) + _q.w * _v)
const SimdFloat4 cross1 = MAdd(SplatW(_q.xyzw), _v, Cross3(_q.xyzw, _v));
const SimdFloat4 cross2 = Cross3(_q.xyzw, cross1);
return _v + cross2 + cross2;
}
} // namespace math
} // namespace ozz
#endif // OZZ_OZZ_BASE_MATHS_SIMD_QUATERNION_H_
@@ -0,0 +1,676 @@
//----------------------------------------------------------------------------//
// //
// ozz-animation is hosted at http://github.com/guillaumeblanc/ozz-animation //
// and distributed under the MIT License (MIT). //
// //
// Copyright (c) Guillaume Blanc //
// //
// Permission is hereby granted, free of charge, to any person obtaining a //
// copy of this software and associated documentation files (the "Software"), //
// to deal in the Software without restriction, including without limitation //
// the rights to use, copy, modify, merge, publish, distribute, sublicense, //
// and/or sell copies of the Software, and to permit persons to whom the //
// Software is furnished to do so, subject to the following conditions: //
// //
// The above copyright notice and this permission notice shall be included in //
// all copies or substantial portions of the Software. //
// //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR //
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, //
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL //
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER //
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING //
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER //
// DEALINGS IN THE SOFTWARE. //
// //
//----------------------------------------------------------------------------//
#ifndef OZZ_OZZ_BASE_MATHS_SOA_FLOAT_H_
#define OZZ_OZZ_BASE_MATHS_SOA_FLOAT_H_
#include <cassert>
#include "ozz/base/maths/math_constant.h"
#include "ozz/base/maths/simd_math.h"
#include "ozz/base/platform.h"
namespace ozz {
namespace math {
struct SoaFloat2 {
SimdFloat4 x, y;
static OZZ_INLINE SoaFloat2 Load(_SimdFloat4 _x, _SimdFloat4 _y) {
const SoaFloat2 r = {_x, _y};
return r;
}
static OZZ_INLINE SoaFloat2 zero() {
const SoaFloat2 r = {simd_float4::zero(), simd_float4::zero()};
return r;
}
static OZZ_INLINE SoaFloat2 one() {
const SoaFloat2 r = {simd_float4::one(), simd_float4::one()};
return r;
}
static OZZ_INLINE SoaFloat2 x_axis() {
const SoaFloat2 r = {simd_float4::one(), simd_float4::zero()};
return r;
}
static OZZ_INLINE SoaFloat2 y_axis() {
const SoaFloat2 r = {simd_float4::zero(), simd_float4::one()};
return r;
}
};
struct SoaFloat3 {
SimdFloat4 x, y, z;
static OZZ_INLINE SoaFloat3 Load(_SimdFloat4 _x, _SimdFloat4 _y,
_SimdFloat4 _z) {
const SoaFloat3 r = {_x, _y, _z};
return r;
}
static OZZ_INLINE SoaFloat3 Load(const SoaFloat2& _v, _SimdFloat4 _z) {
const SoaFloat3 r = {_v.x, _v.y, _z};
return r;
}
static OZZ_INLINE SoaFloat3 zero() {
const SoaFloat3 r = {simd_float4::zero(), simd_float4::zero(),
simd_float4::zero()};
return r;
}
static OZZ_INLINE SoaFloat3 one() {
const SoaFloat3 r = {simd_float4::one(), simd_float4::one(),
simd_float4::one()};
return r;
}
static OZZ_INLINE SoaFloat3 x_axis() {
const SoaFloat3 r = {simd_float4::one(), simd_float4::zero(),
simd_float4::zero()};
return r;
}
static OZZ_INLINE SoaFloat3 y_axis() {
const SoaFloat3 r = {simd_float4::zero(), simd_float4::one(),
simd_float4::zero()};
return r;
}
static OZZ_INLINE SoaFloat3 z_axis() {
const SoaFloat3 r = {simd_float4::zero(), simd_float4::zero(),
simd_float4::one()};
return r;
}
};
struct SoaFloat4 {
SimdFloat4 x, y, z, w;
static OZZ_INLINE SoaFloat4 Load(_SimdFloat4 _x, _SimdFloat4 _y,
_SimdFloat4 _z, const SimdFloat4& _w) {
const SoaFloat4 r = {_x, _y, _z, _w};
return r;
}
static OZZ_INLINE SoaFloat4 Load(const SoaFloat3& _v, _SimdFloat4 _w) {
const SoaFloat4 r = {_v.x, _v.y, _v.z, _w};
return r;
}
static OZZ_INLINE SoaFloat4 Load(const SoaFloat2& _v, _SimdFloat4 _z,
_SimdFloat4 _w) {
const SoaFloat4 r = {_v.x, _v.y, _z, _w};
return r;
}
static OZZ_INLINE SoaFloat4 zero() {
const SimdFloat4 zero = simd_float4::zero();
const SoaFloat4 r = {zero, zero, zero, zero};
return r;
}
static OZZ_INLINE SoaFloat4 one() {
const SimdFloat4 one = simd_float4::one();
const SoaFloat4 r = {one, one, one, one};
return r;
}
static OZZ_INLINE SoaFloat4 x_axis() {
const SimdFloat4 zero = simd_float4::zero();
const SoaFloat4 r = {simd_float4::one(), zero, zero, zero};
return r;
}
static OZZ_INLINE SoaFloat4 y_axis() {
const SimdFloat4 zero = simd_float4::zero();
const SoaFloat4 r = {zero, simd_float4::one(), zero, zero};
return r;
}
static OZZ_INLINE SoaFloat4 z_axis() {
const SimdFloat4 zero = simd_float4::zero();
const SoaFloat4 r = {zero, zero, simd_float4::one(), zero};
return r;
}
static OZZ_INLINE SoaFloat4 w_axis() {
const SimdFloat4 zero = simd_float4::zero();
const SoaFloat4 r = {zero, zero, zero, simd_float4::one()};
return r;
}
};
} // namespace math
} // namespace ozz
// Returns per element addition of _a and _b using operator +.
OZZ_INLINE ozz::math::SoaFloat4 operator+(const ozz::math::SoaFloat4& _a,
const ozz::math::SoaFloat4& _b) {
const ozz::math::SoaFloat4 r = {_a.x + _b.x, _a.y + _b.y, _a.z + _b.z,
_a.w + _b.w};
return r;
}
OZZ_INLINE ozz::math::SoaFloat3 operator+(const ozz::math::SoaFloat3& _a,
const ozz::math::SoaFloat3& _b) {
const ozz::math::SoaFloat3 r = {_a.x + _b.x, _a.y + _b.y, _a.z + _b.z};
return r;
}
OZZ_INLINE ozz::math::SoaFloat2 operator+(const ozz::math::SoaFloat2& _a,
const ozz::math::SoaFloat2& _b) {
const ozz::math::SoaFloat2 r = {_a.x + _b.x, _a.y + _b.y};
return r;
}
// Returns per element subtraction of _a and _b using operator -.
OZZ_INLINE ozz::math::SoaFloat4 operator-(const ozz::math::SoaFloat4& _a,
const ozz::math::SoaFloat4& _b) {
const ozz::math::SoaFloat4 r = {_a.x - _b.x, _a.y - _b.y, _a.z - _b.z,
_a.w - _b.w};
return r;
}
OZZ_INLINE ozz::math::SoaFloat3 operator-(const ozz::math::SoaFloat3& _a,
const ozz::math::SoaFloat3& _b) {
const ozz::math::SoaFloat3 r = {_a.x - _b.x, _a.y - _b.y, _a.z - _b.z};
return r;
}
OZZ_INLINE ozz::math::SoaFloat2 operator-(const ozz::math::SoaFloat2& _a,
const ozz::math::SoaFloat2& _b) {
const ozz::math::SoaFloat2 r = {_a.x - _b.x, _a.y - _b.y};
return r;
}
// Returns per element negative value of _v.
OZZ_INLINE ozz::math::SoaFloat4 operator-(const ozz::math::SoaFloat4& _v) {
const ozz::math::SoaFloat4 r = {-_v.x, -_v.y, -_v.z, -_v.w};
return r;
}
OZZ_INLINE ozz::math::SoaFloat3 operator-(const ozz::math::SoaFloat3& _v) {
const ozz::math::SoaFloat3 r = {-_v.x, -_v.y, -_v.z};
return r;
}
OZZ_INLINE ozz::math::SoaFloat2 operator-(const ozz::math::SoaFloat2& _v) {
const ozz::math::SoaFloat2 r = {-_v.x, -_v.y};
return r;
}
// Returns per element multiplication of _a and _b using operator *.
OZZ_INLINE ozz::math::SoaFloat4 operator*(const ozz::math::SoaFloat4& _a,
const ozz::math::SoaFloat4& _b) {
const ozz::math::SoaFloat4 r = {_a.x * _b.x, _a.y * _b.y, _a.z * _b.z,
_a.w * _b.w};
return r;
}
OZZ_INLINE ozz::math::SoaFloat3 operator*(const ozz::math::SoaFloat3& _a,
const ozz::math::SoaFloat3& _b) {
const ozz::math::SoaFloat3 r = {_a.x * _b.x, _a.y * _b.y, _a.z * _b.z};
return r;
}
OZZ_INLINE ozz::math::SoaFloat2 operator*(const ozz::math::SoaFloat2& _a,
const ozz::math::SoaFloat2& _b) {
const ozz::math::SoaFloat2 r = {_a.x * _b.x, _a.y * _b.y};
return r;
}
// Returns per element multiplication of _a and scalar value _f using
// operator *.
OZZ_INLINE ozz::math::SoaFloat4 operator*(const ozz::math::SoaFloat4& _a,
ozz::math::_SimdFloat4 _f) {
const ozz::math::SoaFloat4 r = {_a.x * _f, _a.y * _f, _a.z * _f, _a.w * _f};
return r;
}
OZZ_INLINE ozz::math::SoaFloat3 operator*(const ozz::math::SoaFloat3& _a,
ozz::math::_SimdFloat4 _f) {
const ozz::math::SoaFloat3 r = {_a.x * _f, _a.y * _f, _a.z * _f};
return r;
}
OZZ_INLINE ozz::math::SoaFloat2 operator*(const ozz::math::SoaFloat2& _a,
ozz::math::_SimdFloat4 _f) {
const ozz::math::SoaFloat2 r = {_a.x * _f, _a.y * _f};
return r;
}
// Multiplies _a and _b, then adds _addend.
// v = (_a * _b) + _addend
OZZ_INLINE ozz::math::SoaFloat2 MAdd(const ozz::math::SoaFloat2& _a,
const ozz::math::SoaFloat2& _b,
const ozz::math::SoaFloat2& _addend) {
const ozz::math::SoaFloat2 r = {ozz::math::MAdd(_a.x, _b.x, _addend.x),
ozz::math::MAdd(_a.y, _b.y, _addend.y)};
return r;
}
OZZ_INLINE ozz::math::SoaFloat3 MAdd(const ozz::math::SoaFloat3& _a,
const ozz::math::SoaFloat3& _b,
const ozz::math::SoaFloat3& _addend) {
const ozz::math::SoaFloat3 r = {ozz::math::MAdd(_a.x, _b.x, _addend.x),
ozz::math::MAdd(_a.y, _b.y, _addend.y),
ozz::math::MAdd(_a.z, _b.z, _addend.z)};
return r;
}
OZZ_INLINE ozz::math::SoaFloat4 MAdd(const ozz::math::SoaFloat4& _a,
const ozz::math::SoaFloat4& _b,
const ozz::math::SoaFloat4& _addend) {
const ozz::math::SoaFloat4 r = {ozz::math::MAdd(_a.x, _b.x, _addend.x),
ozz::math::MAdd(_a.y, _b.y, _addend.y),
ozz::math::MAdd(_a.z, _b.z, _addend.z),
ozz::math::MAdd(_a.w, _b.w, _addend.w)};
return r;
}
// Returns per element division of _a and _b using operator /.
OZZ_INLINE ozz::math::SoaFloat4 operator/(const ozz::math::SoaFloat4& _a,
const ozz::math::SoaFloat4& _b) {
const ozz::math::SoaFloat4 r = {_a.x / _b.x, _a.y / _b.y, _a.z / _b.z,
_a.w / _b.w};
return r;
}
OZZ_INLINE ozz::math::SoaFloat3 operator/(const ozz::math::SoaFloat3& _a,
const ozz::math::SoaFloat3& _b) {
const ozz::math::SoaFloat3 r = {_a.x / _b.x, _a.y / _b.y, _a.z / _b.z};
return r;
}
OZZ_INLINE ozz::math::SoaFloat2 operator/(const ozz::math::SoaFloat2& _a,
const ozz::math::SoaFloat2& _b) {
const ozz::math::SoaFloat2 r = {_a.x / _b.x, _a.y / _b.y};
return r;
}
// Returns per element division of _a and scalar value _f using operator/.
OZZ_INLINE ozz::math::SoaFloat4 operator/(const ozz::math::SoaFloat4& _a,
ozz::math::_SimdFloat4 _f) {
const ozz::math::SoaFloat4 r = {_a.x / _f, _a.y / _f, _a.z / _f, _a.w / _f};
return r;
}
OZZ_INLINE ozz::math::SoaFloat3 operator/(const ozz::math::SoaFloat3& _a,
ozz::math::_SimdFloat4 _f) {
const ozz::math::SoaFloat3 r = {_a.x / _f, _a.y / _f, _a.z / _f};
return r;
}
OZZ_INLINE ozz::math::SoaFloat2 operator/(const ozz::math::SoaFloat2& _a,
ozz::math::_SimdFloat4 _f) {
const ozz::math::SoaFloat2 r = {_a.x / _f, _a.y / _f};
return r;
}
// Returns true if each element of a is less than each element of _b.
OZZ_INLINE ozz::math::SimdInt4 operator<(const ozz::math::SoaFloat4& _a,
const ozz::math::SoaFloat4& _b) {
const ozz::math::SimdInt4 x = ozz::math::CmpLt(_a.x, _b.x);
const ozz::math::SimdInt4 y = ozz::math::CmpLt(_a.y, _b.y);
const ozz::math::SimdInt4 z = ozz::math::CmpLt(_a.z, _b.z);
const ozz::math::SimdInt4 w = ozz::math::CmpLt(_a.w, _b.w);
return ozz::math::And(ozz::math::And(ozz::math::And(x, y), z), w);
}
OZZ_INLINE ozz::math::SimdInt4 operator<(const ozz::math::SoaFloat3& _a,
const ozz::math::SoaFloat3& _b) {
const ozz::math::SimdInt4 x = ozz::math::CmpLt(_a.x, _b.x);
const ozz::math::SimdInt4 y = ozz::math::CmpLt(_a.y, _b.y);
const ozz::math::SimdInt4 z = ozz::math::CmpLt(_a.z, _b.z);
return ozz::math::And(ozz::math::And(x, y), z);
}
OZZ_INLINE ozz::math::SimdInt4 operator<(const ozz::math::SoaFloat2& _a,
const ozz::math::SoaFloat2& _b) {
const ozz::math::SimdInt4 x = ozz::math::CmpLt(_a.x, _b.x);
const ozz::math::SimdInt4 y = ozz::math::CmpLt(_a.y, _b.y);
return ozz::math::And(x, y);
}
// Returns true if each element of a is less or equal to each element of _b.
OZZ_INLINE ozz::math::SimdInt4 operator<=(const ozz::math::SoaFloat4& _a,
const ozz::math::SoaFloat4& _b) {
const ozz::math::SimdInt4 x = ozz::math::CmpLe(_a.x, _b.x);
const ozz::math::SimdInt4 y = ozz::math::CmpLe(_a.y, _b.y);
const ozz::math::SimdInt4 z = ozz::math::CmpLe(_a.z, _b.z);
const ozz::math::SimdInt4 w = ozz::math::CmpLe(_a.w, _b.w);
return ozz::math::And(ozz::math::And(ozz::math::And(x, y), z), w);
}
OZZ_INLINE ozz::math::SimdInt4 operator<=(const ozz::math::SoaFloat3& _a,
const ozz::math::SoaFloat3& _b) {
const ozz::math::SimdInt4 x = ozz::math::CmpLe(_a.x, _b.x);
const ozz::math::SimdInt4 y = ozz::math::CmpLe(_a.y, _b.y);
const ozz::math::SimdInt4 z = ozz::math::CmpLe(_a.z, _b.z);
return ozz::math::And(ozz::math::And(x, y), z);
}
OZZ_INLINE ozz::math::SimdInt4 operator<=(const ozz::math::SoaFloat2& _a,
const ozz::math::SoaFloat2& _b) {
const ozz::math::SimdInt4 x = ozz::math::CmpLe(_a.x, _b.x);
const ozz::math::SimdInt4 y = ozz::math::CmpLe(_a.y, _b.y);
return ozz::math::And(x, y);
}
// Returns true if each element of a is greater than each element of _b.
OZZ_INLINE ozz::math::SimdInt4 operator>(const ozz::math::SoaFloat4& _a,
const ozz::math::SoaFloat4& _b) {
const ozz::math::SimdInt4 x = ozz::math::CmpGt(_a.x, _b.x);
const ozz::math::SimdInt4 y = ozz::math::CmpGt(_a.y, _b.y);
const ozz::math::SimdInt4 z = ozz::math::CmpGt(_a.z, _b.z);
const ozz::math::SimdInt4 w = ozz::math::CmpGt(_a.w, _b.w);
return ozz::math::And(ozz::math::And(ozz::math::And(x, y), z), w);
}
OZZ_INLINE ozz::math::SimdInt4 operator>(const ozz::math::SoaFloat3& _a,
const ozz::math::SoaFloat3& _b) {
const ozz::math::SimdInt4 x = ozz::math::CmpGt(_a.x, _b.x);
const ozz::math::SimdInt4 y = ozz::math::CmpGt(_a.y, _b.y);
const ozz::math::SimdInt4 z = ozz::math::CmpGt(_a.z, _b.z);
return ozz::math::And(ozz::math::And(x, y), z);
}
OZZ_INLINE ozz::math::SimdInt4 operator>(const ozz::math::SoaFloat2& _a,
const ozz::math::SoaFloat2& _b) {
const ozz::math::SimdInt4 x = ozz::math::CmpGt(_a.x, _b.x);
const ozz::math::SimdInt4 y = ozz::math::CmpGt(_a.y, _b.y);
return ozz::math::And(x, y);
}
// Returns true if each element of a is greater or equal to each element of _b.
OZZ_INLINE ozz::math::SimdInt4 operator>=(const ozz::math::SoaFloat4& _a,
const ozz::math::SoaFloat4& _b) {
const ozz::math::SimdInt4 x = ozz::math::CmpGe(_a.x, _b.x);
const ozz::math::SimdInt4 y = ozz::math::CmpGe(_a.y, _b.y);
const ozz::math::SimdInt4 z = ozz::math::CmpGe(_a.z, _b.z);
const ozz::math::SimdInt4 w = ozz::math::CmpGe(_a.w, _b.w);
return ozz::math::And(ozz::math::And(ozz::math::And(x, y), z), w);
}
OZZ_INLINE ozz::math::SimdInt4 operator>=(const ozz::math::SoaFloat3& _a,
const ozz::math::SoaFloat3& _b) {
const ozz::math::SimdInt4 x = ozz::math::CmpGe(_a.x, _b.x);
const ozz::math::SimdInt4 y = ozz::math::CmpGe(_a.y, _b.y);
const ozz::math::SimdInt4 z = ozz::math::CmpGe(_a.z, _b.z);
return ozz::math::And(ozz::math::And(x, y), z);
}
OZZ_INLINE ozz::math::SimdInt4 operator>=(const ozz::math::SoaFloat2& _a,
const ozz::math::SoaFloat2& _b) {
const ozz::math::SimdInt4 x = ozz::math::CmpGe(_a.x, _b.x);
const ozz::math::SimdInt4 y = ozz::math::CmpGe(_a.y, _b.y);
return ozz::math::And(x, y);
}
// Returns true if each element of _a is equal to each element of _b.
// Uses a bitwise comparison of _a and _b, no tolerance is applied.
OZZ_INLINE ozz::math::SimdInt4 operator==(const ozz::math::SoaFloat4& _a,
const ozz::math::SoaFloat4& _b) {
const ozz::math::SimdInt4 x = ozz::math::CmpEq(_a.x, _b.x);
const ozz::math::SimdInt4 y = ozz::math::CmpEq(_a.y, _b.y);
const ozz::math::SimdInt4 z = ozz::math::CmpEq(_a.z, _b.z);
const ozz::math::SimdInt4 w = ozz::math::CmpEq(_a.w, _b.w);
return ozz::math::And(ozz::math::And(ozz::math::And(x, y), z), w);
}
OZZ_INLINE ozz::math::SimdInt4 operator==(const ozz::math::SoaFloat3& _a,
const ozz::math::SoaFloat3& _b) {
const ozz::math::SimdInt4 x = ozz::math::CmpEq(_a.x, _b.x);
const ozz::math::SimdInt4 y = ozz::math::CmpEq(_a.y, _b.y);
const ozz::math::SimdInt4 z = ozz::math::CmpEq(_a.z, _b.z);
return ozz::math::And(ozz::math::And(x, y), z);
}
OZZ_INLINE ozz::math::SimdInt4 operator==(const ozz::math::SoaFloat2& _a,
const ozz::math::SoaFloat2& _b) {
const ozz::math::SimdInt4 x = ozz::math::CmpEq(_a.x, _b.x);
const ozz::math::SimdInt4 y = ozz::math::CmpEq(_a.y, _b.y);
return ozz::math::And(x, y);
}
// Returns true if each element of a is different from each element of _b.
// Uses a bitwise comparison of _a and _b, no tolerance is applied.
OZZ_INLINE ozz::math::SimdInt4 operator!=(const ozz::math::SoaFloat4& _a,
const ozz::math::SoaFloat4& _b) {
const ozz::math::SimdInt4 x = ozz::math::CmpNe(_a.x, _b.x);
const ozz::math::SimdInt4 y = ozz::math::CmpNe(_a.y, _b.y);
const ozz::math::SimdInt4 z = ozz::math::CmpNe(_a.z, _b.z);
const ozz::math::SimdInt4 w = ozz::math::CmpNe(_a.w, _b.w);
return ozz::math::Or(ozz::math::Or(ozz::math::Or(x, y), z), w);
}
OZZ_INLINE ozz::math::SimdInt4 operator!=(const ozz::math::SoaFloat3& _a,
const ozz::math::SoaFloat3& _b) {
const ozz::math::SimdInt4 x = ozz::math::CmpNe(_a.x, _b.x);
const ozz::math::SimdInt4 y = ozz::math::CmpNe(_a.y, _b.y);
const ozz::math::SimdInt4 z = ozz::math::CmpNe(_a.z, _b.z);
return ozz::math::Or(ozz::math::Or(x, y), z);
}
OZZ_INLINE ozz::math::SimdInt4 operator!=(const ozz::math::SoaFloat2& _a,
const ozz::math::SoaFloat2& _b) {
const ozz::math::SimdInt4 x = ozz::math::CmpNe(_a.x, _b.x);
const ozz::math::SimdInt4 y = ozz::math::CmpNe(_a.y, _b.y);
return ozz::math::Or(x, y);
}
namespace ozz {
namespace math {
// Returns the (horizontal) addition of each element of _v.
OZZ_INLINE SimdFloat4 HAdd(const SoaFloat4& _v) {
return _v.x + _v.y + _v.z + _v.w;
}
OZZ_INLINE SimdFloat4 HAdd(const SoaFloat3& _v) { return _v.x + _v.y + _v.z; }
OZZ_INLINE SimdFloat4 HAdd(const SoaFloat2& _v) { return _v.x + _v.y; }
// Returns the dot product of _a and _b.
OZZ_INLINE SimdFloat4 Dot(const SoaFloat4& _a, const SoaFloat4& _b) {
return _a.x * _b.x + _a.y * _b.y + _a.z * _b.z + _a.w * _b.w;
}
OZZ_INLINE SimdFloat4 Dot(const SoaFloat3& _a, const SoaFloat3& _b) {
return _a.x * _b.x + _a.y * _b.y + _a.z * _b.z;
}
OZZ_INLINE SimdFloat4 Dot(const SoaFloat2& _a, const SoaFloat2& _b) {
return _a.x * _b.x + _a.y * _b.y;
}
// Returns the cross product of _a and _b.
OZZ_INLINE SoaFloat3 Cross(const SoaFloat3& _a, const SoaFloat3& _b) {
const SoaFloat3 r = {_a.y * _b.z - _b.y * _a.z, _a.z * _b.x - _b.z * _a.x,
_a.x * _b.y - _b.x * _a.y};
return r;
}
// Returns the length |_v| of _v.
OZZ_INLINE SimdFloat4 Length(const SoaFloat4& _v) {
const SimdFloat4 len2 = _v.x * _v.x + _v.y * _v.y + _v.z * _v.z + _v.w * _v.w;
return Sqrt(len2);
}
OZZ_INLINE SimdFloat4 Length(const SoaFloat3& _v) {
const SimdFloat4 len2 = _v.x * _v.x + _v.y * _v.y + _v.z * _v.z;
return Sqrt(len2);
}
OZZ_INLINE SimdFloat4 Length(const SoaFloat2& _v) {
const SimdFloat4 len2 = _v.x * _v.x + _v.y * _v.y;
return Sqrt(len2);
}
// Returns the square length |_v|^2 of _v.
OZZ_INLINE SimdFloat4 LengthSqr(const SoaFloat4& _v) {
return _v.x * _v.x + _v.y * _v.y + _v.z * _v.z + _v.w * _v.w;
}
OZZ_INLINE SimdFloat4 LengthSqr(const SoaFloat3& _v) {
return _v.x * _v.x + _v.y * _v.y + _v.z * _v.z;
}
OZZ_INLINE SimdFloat4 LengthSqr(const SoaFloat2& _v) {
return _v.x * _v.x + _v.y * _v.y;
}
// Returns the normalized vector _v.
OZZ_INLINE SoaFloat4 Normalize(const SoaFloat4& _v) {
const SimdFloat4 len2 = _v.x * _v.x + _v.y * _v.y + _v.z * _v.z + _v.w * _v.w;
assert(AreAllTrue(CmpNe(len2, simd_float4::zero())) &&
"_v is not normalizable");
const SimdFloat4 inv_len = math::simd_float4::one() / Sqrt(len2);
const SoaFloat4 r = {_v.x * inv_len, _v.y * inv_len, _v.z * inv_len,
_v.w * inv_len};
return r;
}
OZZ_INLINE SoaFloat3 Normalize(const SoaFloat3& _v) {
const SimdFloat4 len2 = _v.x * _v.x + _v.y * _v.y + _v.z * _v.z;
assert(AreAllTrue(CmpNe(len2, simd_float4::zero())) &&
"_v is not normalizable");
const SimdFloat4 inv_len = math::simd_float4::one() / Sqrt(len2);
const SoaFloat3 r = {_v.x * inv_len, _v.y * inv_len, _v.z * inv_len};
return r;
}
OZZ_INLINE SoaFloat2 Normalize(const SoaFloat2& _v) {
const SimdFloat4 len2 = _v.x * _v.x + _v.y * _v.y;
assert(AreAllTrue(CmpNe(len2, simd_float4::zero())) &&
"_v is not normalizable");
const SimdFloat4 inv_len = math::simd_float4::one() / Sqrt(len2);
const SoaFloat2 r = {_v.x * inv_len, _v.y * inv_len};
return r;
}
// Test if each vector _v is normalized.
OZZ_INLINE math::SimdInt4 IsNormalized(const SoaFloat4& _v) {
const SimdFloat4 len2 = _v.x * _v.x + _v.y * _v.y + _v.z * _v.z + _v.w * _v.w;
return CmpLt(Abs(len2 - math::simd_float4::one()),
simd_float4::Load1(kNormalizationToleranceSq));
}
OZZ_INLINE math::SimdInt4 IsNormalized(const SoaFloat3& _v) {
const SimdFloat4 len2 = _v.x * _v.x + _v.y * _v.y + _v.z * _v.z;
return CmpLt(Abs(len2 - math::simd_float4::one()),
simd_float4::Load1(kNormalizationToleranceSq));
}
OZZ_INLINE math::SimdInt4 IsNormalized(const SoaFloat2& _v) {
const SimdFloat4 len2 = _v.x * _v.x + _v.y * _v.y;
return CmpLt(Abs(len2 - math::simd_float4::one()),
simd_float4::Load1(kNormalizationToleranceSq));
}
// Test if each vector _v is normalized using estimated tolerance.
OZZ_INLINE math::SimdInt4 IsNormalizedEst(const SoaFloat4& _v) {
const SimdFloat4 len2 = _v.x * _v.x + _v.y * _v.y + _v.z * _v.z + _v.w * _v.w;
return CmpLt(Abs(len2 - math::simd_float4::one()),
simd_float4::Load1(kNormalizationToleranceEstSq));
}
OZZ_INLINE math::SimdInt4 IsNormalizedEst(const SoaFloat3& _v) {
const SimdFloat4 len2 = _v.x * _v.x + _v.y * _v.y + _v.z * _v.z;
return CmpLt(Abs(len2 - math::simd_float4::one()),
simd_float4::Load1(kNormalizationToleranceEstSq));
}
OZZ_INLINE math::SimdInt4 IsNormalizedEst(const SoaFloat2& _v) {
const SimdFloat4 len2 = _v.x * _v.x + _v.y * _v.y;
return CmpLt(Abs(len2 - math::simd_float4::one()),
simd_float4::Load1(kNormalizationToleranceEstSq));
}
// Returns the normalized vector _v if the norm of _v is not 0.
// Otherwise returns _safer.
OZZ_INLINE SoaFloat4 NormalizeSafe(const SoaFloat4& _v,
const SoaFloat4& _safer) {
assert(AreAllTrue(IsNormalizedEst(_safer)) && "_safer is not normalized");
const SimdFloat4 len2 = _v.x * _v.x + _v.y * _v.y + _v.z * _v.z + _v.w * _v.w;
const math::SimdInt4 b = CmpNe(len2, math::simd_float4::zero());
const SimdFloat4 inv_len = math::simd_float4::one() / Sqrt(len2);
const SoaFloat4 r = {
Select(b, _v.x * inv_len, _safer.x), Select(b, _v.y * inv_len, _safer.y),
Select(b, _v.z * inv_len, _safer.z), Select(b, _v.w * inv_len, _safer.w)};
return r;
}
OZZ_INLINE SoaFloat3 NormalizeSafe(const SoaFloat3& _v,
const SoaFloat3& _safer) {
assert(AreAllTrue(IsNormalizedEst(_safer)) && "_safer is not normalized");
const SimdFloat4 len2 = _v.x * _v.x + _v.y * _v.y + _v.z * _v.z;
const math::SimdInt4 b = CmpNe(len2, math::simd_float4::zero());
const SimdFloat4 inv_len = math::simd_float4::one() / Sqrt(len2);
const SoaFloat3 r = {Select(b, _v.x * inv_len, _safer.x),
Select(b, _v.y * inv_len, _safer.y),
Select(b, _v.z * inv_len, _safer.z)};
return r;
}
OZZ_INLINE SoaFloat2 NormalizeSafe(const SoaFloat2& _v,
const SoaFloat2& _safer) {
assert(AreAllTrue(IsNormalizedEst(_safer)) && "_safer is not normalized");
const SimdFloat4 len2 = _v.x * _v.x + _v.y * _v.y;
const math::SimdInt4 b = CmpNe(len2, math::simd_float4::zero());
const SimdFloat4 inv_len = math::simd_float4::one() / Sqrt(len2);
const SoaFloat2 r = {Select(b, _v.x * inv_len, _safer.x),
Select(b, _v.y * inv_len, _safer.y)};
return r;
}
// Returns the linear interpolation of _a and _b with coefficient _f.
// _f is not limited to range [0,1].
OZZ_INLINE SoaFloat4 Lerp(const SoaFloat4& _a, const SoaFloat4& _b,
_SimdFloat4 _f) {
const SoaFloat4 r = {(_b.x - _a.x) * _f + _a.x, (_b.y - _a.y) * _f + _a.y,
(_b.z - _a.z) * _f + _a.z, (_b.w - _a.w) * _f + _a.w};
return r;
}
OZZ_INLINE SoaFloat3 Lerp(const SoaFloat3& _a, const SoaFloat3& _b,
_SimdFloat4 _f) {
const SoaFloat3 r = {(_b.x - _a.x) * _f + _a.x, (_b.y - _a.y) * _f + _a.y,
(_b.z - _a.z) * _f + _a.z};
return r;
}
OZZ_INLINE SoaFloat2 Lerp(const SoaFloat2& _a, const SoaFloat2& _b,
_SimdFloat4 _f) {
const SoaFloat2 r = {(_b.x - _a.x) * _f + _a.x, (_b.y - _a.y) * _f + _a.y};
return r;
}
// Returns the minimum of each element of _a and _b.
OZZ_INLINE SoaFloat4 Min(const SoaFloat4& _a, const SoaFloat4& _b) {
const SoaFloat4 r = {Min(_a.x, _b.x), Min(_a.y, _b.y), Min(_a.z, _b.z),
Min(_a.w, _b.w)};
return r;
}
OZZ_INLINE SoaFloat3 Min(const SoaFloat3& _a, const SoaFloat3& _b) {
const SoaFloat3 r = {Min(_a.x, _b.x), Min(_a.y, _b.y), Min(_a.z, _b.z)};
return r;
}
OZZ_INLINE SoaFloat2 Min(const SoaFloat2& _a, const SoaFloat2& _b) {
const SoaFloat2 r = {Min(_a.x, _b.x), Min(_a.y, _b.y)};
return r;
}
// Returns the maximum of each element of _a and _b.
OZZ_INLINE SoaFloat4 Max(const SoaFloat4& _a, const SoaFloat4& _b) {
const SoaFloat4 r = {Max(_a.x, _b.x), Max(_a.y, _b.y), Max(_a.z, _b.z),
Max(_a.w, _b.w)};
return r;
}
OZZ_INLINE SoaFloat3 Max(const SoaFloat3& _a, const SoaFloat3& _b) {
const SoaFloat3 r = {Max(_a.x, _b.x), Max(_a.y, _b.y), Max(_a.z, _b.z)};
return r;
}
OZZ_INLINE SoaFloat2 Max(const SoaFloat2& _a, const SoaFloat2& _b) {
const SoaFloat2 r = {Max(_a.x, _b.x), Max(_a.y, _b.y)};
return r;
}
// Clamps each element of _x between _a and _b.
// _a must be less or equal to b;
OZZ_INLINE SoaFloat4 Clamp(const SoaFloat4& _a, const SoaFloat4& _v,
const SoaFloat4& _b) {
return Max(_a, Min(_v, _b));
}
OZZ_INLINE SoaFloat3 Clamp(const SoaFloat3& _a, const SoaFloat3& _v,
const SoaFloat3& _b) {
return Max(_a, Min(_v, _b));
}
OZZ_INLINE SoaFloat2 Clamp(const SoaFloat2& _a, const SoaFloat2& _v,
const SoaFloat2& _b) {
return Max(_a, Min(_v, _b));
}
} // namespace math
} // namespace ozz
#endif // OZZ_OZZ_BASE_MATHS_SOA_FLOAT_H_
@@ -0,0 +1,276 @@
//----------------------------------------------------------------------------//
// //
// ozz-animation is hosted at http://github.com/guillaumeblanc/ozz-animation //
// and distributed under the MIT License (MIT). //
// //
// Copyright (c) Guillaume Blanc //
// //
// Permission is hereby granted, free of charge, to any person obtaining a //
// copy of this software and associated documentation files (the "Software"), //
// to deal in the Software without restriction, including without limitation //
// the rights to use, copy, modify, merge, publish, distribute, sublicense, //
// and/or sell copies of the Software, and to permit persons to whom the //
// Software is furnished to do so, subject to the following conditions: //
// //
// The above copyright notice and this permission notice shall be included in //
// all copies or substantial portions of the Software. //
// //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR //
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, //
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL //
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER //
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING //
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER //
// DEALINGS IN THE SOFTWARE. //
// //
//----------------------------------------------------------------------------//
#ifndef OZZ_OZZ_BASE_MATHS_SOA_FLOAT4X4_H_
#define OZZ_OZZ_BASE_MATHS_SOA_FLOAT4X4_H_
#include <cassert>
#include "ozz/base/maths/soa_float.h"
#include "ozz/base/maths/soa_quaternion.h"
#include "ozz/base/platform.h"
namespace ozz {
namespace math {
// Declare the 4x4 soa matrix type. Uses the column major convention where the
// matrix-times-vector is written v'=Mv:
// [ m.cols[0].x m.cols[1].x m.cols[2].x m.cols[3].x ] {v.x}
// | m.cols[0].y m.cols[1].y m.cols[2].y m.cols[3].y | * {v.y}
// | m.cols[0].z m.cols[1].y m.cols[2].y m.cols[3].y | {v.z}
// [ m.cols[0].w m.cols[1].w m.cols[2].w m.cols[3].w ] {v.1}
struct SoaFloat4x4 {
// Soa matrix columns.
SoaFloat4 cols[4];
// Returns the identity matrix.
static OZZ_INLINE SoaFloat4x4 identity() {
const SimdFloat4 zero = simd_float4::zero();
const SimdFloat4 one = simd_float4::one();
SoaFloat4x4 ret = {{{one, zero, zero, zero},
{zero, one, zero, zero},
{zero, zero, one, zero},
{zero, zero, zero, one}}};
return ret;
}
// Returns a scaling matrix that scales along _v.
// _v.w is ignored.
static OZZ_INLINE SoaFloat4x4 Scaling(const SoaFloat4& _v) {
const SimdFloat4 zero = simd_float4::zero();
const SimdFloat4 one = simd_float4::one();
const SoaFloat4x4 ret = {{{_v.x, zero, zero, zero},
{zero, _v.y, zero, zero},
{zero, zero, _v.z, zero},
{zero, zero, zero, one}}};
return ret;
}
// Returns the rotation matrix built from quaternion defined by x, y, z and w
// components of _v.
static OZZ_INLINE SoaFloat4x4 FromQuaternion(const SoaQuaternion& _q) {
assert(AreAllTrue(IsNormalizedEst(_q)));
const SimdFloat4 zero = simd_float4::zero();
const SimdFloat4 one = simd_float4::one();
const SimdFloat4 two = one + one;
const SimdFloat4 xx = _q.x * _q.x;
const SimdFloat4 xy = _q.x * _q.y;
const SimdFloat4 xz = _q.x * _q.z;
const SimdFloat4 xw = _q.x * _q.w;
const SimdFloat4 yy = _q.y * _q.y;
const SimdFloat4 yz = _q.y * _q.z;
const SimdFloat4 yw = _q.y * _q.w;
const SimdFloat4 zz = _q.z * _q.z;
const SimdFloat4 zw = _q.z * _q.w;
const SoaFloat4x4 ret = {
{{one - two * (yy + zz), two * (xy + zw), two * (xz - yw), zero},
{two * (xy - zw), one - two * (xx + zz), two * (yz + xw), zero},
{two * (xz + yw), two * (yz - xw), one - two * (xx + yy), zero},
{zero, zero, zero, one}}};
return ret;
}
// Returns the affine transformation matrix built from split translation,
// rotation (quaternion) and scale.
static OZZ_INLINE SoaFloat4x4 FromAffine(const SoaFloat3& _translation,
const SoaQuaternion& _quaternion,
const SoaFloat3& _scale) {
assert(AreAllTrue(IsNormalizedEst(_quaternion)));
const SimdFloat4 zero = simd_float4::zero();
const SimdFloat4 one = simd_float4::one();
const SimdFloat4 two = one + one;
const SimdFloat4 xx = _quaternion.x * _quaternion.x;
const SimdFloat4 xy = _quaternion.x * _quaternion.y;
const SimdFloat4 xz = _quaternion.x * _quaternion.z;
const SimdFloat4 xw = _quaternion.x * _quaternion.w;
const SimdFloat4 yy = _quaternion.y * _quaternion.y;
const SimdFloat4 yz = _quaternion.y * _quaternion.z;
const SimdFloat4 yw = _quaternion.y * _quaternion.w;
const SimdFloat4 zz = _quaternion.z * _quaternion.z;
const SimdFloat4 zw = _quaternion.z * _quaternion.w;
const SoaFloat4x4 ret = {
{{_scale.x * (one - two * (yy + zz)), _scale.x * two * (xy + zw),
_scale.x * two * (xz - yw), zero},
{_scale.y * two * (xy - zw), _scale.y * (one - two * (xx + zz)),
_scale.y * two * (yz + xw), zero},
{_scale.z * two * (xz + yw), _scale.z * two * (yz - xw),
_scale.z * (one - two * (xx + yy)), zero},
{_translation.x, _translation.y, _translation.z, one}}};
return ret;
}
};
// Returns the transpose of matrix _m.
OZZ_INLINE SoaFloat4x4 Transpose(const SoaFloat4x4& _m) {
const SoaFloat4x4 ret = {
{{_m.cols[0].x, _m.cols[1].x, _m.cols[2].x, _m.cols[3].x},
{_m.cols[0].y, _m.cols[1].y, _m.cols[2].y, _m.cols[3].y},
{_m.cols[0].z, _m.cols[1].z, _m.cols[2].z, _m.cols[3].z},
{_m.cols[0].w, _m.cols[1].w, _m.cols[2].w, _m.cols[3].w}}};
return ret;
}
// Returns the inverse of matrix _m.
// If _invertible is not nullptr, each component will be set to true if its
// respective matrix is invertible. If _invertible is nullptr, then an assert is
// triggered in case any of the 4 matrices isn't invertible.
OZZ_INLINE SoaFloat4x4 Invert(const SoaFloat4x4& _m,
SimdInt4* _invertible = nullptr) {
const SoaFloat4* cols = _m.cols;
const SimdFloat4 a00 = cols[2].z * cols[3].w - cols[3].z * cols[2].w;
const SimdFloat4 a01 = cols[2].y * cols[3].w - cols[3].y * cols[2].w;
const SimdFloat4 a02 = cols[2].y * cols[3].z - cols[3].y * cols[2].z;
const SimdFloat4 a03 = cols[2].x * cols[3].w - cols[3].x * cols[2].w;
const SimdFloat4 a04 = cols[2].x * cols[3].z - cols[3].x * cols[2].z;
const SimdFloat4 a05 = cols[2].x * cols[3].y - cols[3].x * cols[2].y;
const SimdFloat4 a06 = cols[1].z * cols[3].w - cols[3].z * cols[1].w;
const SimdFloat4 a07 = cols[1].y * cols[3].w - cols[3].y * cols[1].w;
const SimdFloat4 a08 = cols[1].y * cols[3].z - cols[3].y * cols[1].z;
const SimdFloat4 a09 = cols[1].x * cols[3].w - cols[3].x * cols[1].w;
const SimdFloat4 a10 = cols[1].x * cols[3].z - cols[3].x * cols[1].z;
const SimdFloat4 a11 = cols[1].y * cols[3].w - cols[3].y * cols[1].w;
const SimdFloat4 a12 = cols[1].x * cols[3].y - cols[3].x * cols[1].y;
const SimdFloat4 a13 = cols[1].z * cols[2].w - cols[2].z * cols[1].w;
const SimdFloat4 a14 = cols[1].y * cols[2].w - cols[2].y * cols[1].w;
const SimdFloat4 a15 = cols[1].y * cols[2].z - cols[2].y * cols[1].z;
const SimdFloat4 a16 = cols[1].x * cols[2].w - cols[2].x * cols[1].w;
const SimdFloat4 a17 = cols[1].x * cols[2].z - cols[2].x * cols[1].z;
const SimdFloat4 a18 = cols[1].x * cols[2].y - cols[2].x * cols[1].y;
const SimdFloat4 b0x = cols[1].y * a00 - cols[1].z * a01 + cols[1].w * a02;
const SimdFloat4 b1x = -cols[1].x * a00 + cols[1].z * a03 - cols[1].w * a04;
const SimdFloat4 b2x = cols[1].x * a01 - cols[1].y * a03 + cols[1].w * a05;
const SimdFloat4 b3x = -cols[1].x * a02 + cols[1].y * a04 - cols[1].z * a05;
const SimdFloat4 b0y = -cols[0].y * a00 + cols[0].z * a01 - cols[0].w * a02;
const SimdFloat4 b1y = cols[0].x * a00 - cols[0].z * a03 + cols[0].w * a04;
const SimdFloat4 b2y = -cols[0].x * a01 + cols[0].y * a03 - cols[0].w * a05;
const SimdFloat4 b3y = cols[0].x * a02 - cols[0].y * a04 + cols[0].z * a05;
const SimdFloat4 b0z = cols[0].y * a06 - cols[0].z * a07 + cols[0].w * a08;
const SimdFloat4 b1z = -cols[0].x * a06 + cols[0].z * a09 - cols[0].w * a10;
const SimdFloat4 b2z = cols[0].x * a11 - cols[0].y * a09 + cols[0].w * a12;
const SimdFloat4 b3z = -cols[0].x * a08 + cols[0].y * a10 - cols[0].z * a12;
const SimdFloat4 b0w = -cols[0].y * a13 + cols[0].z * a14 - cols[0].w * a15;
const SimdFloat4 b1w = cols[0].x * a13 - cols[0].z * a16 + cols[0].w * a17;
const SimdFloat4 b2w = -cols[0].x * a14 + cols[0].y * a16 - cols[0].w * a18;
const SimdFloat4 b3w = cols[0].x * a15 - cols[0].y * a17 + cols[0].z * a18;
const SimdFloat4 det =
cols[0].x * b0x + cols[0].y * b1x + cols[0].z * b2x + cols[0].w * b3x;
const SimdInt4 invertible = CmpNe(det, simd_float4::zero());
assert((_invertible || AreAllTrue(invertible)) && "Matrix is not invertible");
if (_invertible != nullptr) {
*_invertible = invertible;
}
const SimdFloat4 inv_det =
Select(invertible, RcpEstNR(det), simd_float4::zero());
const SoaFloat4x4 ret = {
{{b0x * inv_det, b0y * inv_det, b0z * inv_det, b0w * inv_det},
{b1x * inv_det, b1y * inv_det, b1z * inv_det, b1w * inv_det},
{b2x * inv_det, b2y * inv_det, b2z * inv_det, b2w * inv_det},
{b3x * inv_det, b3y * inv_det, b3z * inv_det, b3w * inv_det}}};
return ret;
}
// Scales matrix _m along the axis defined by _v components.
// _v.w is ignored.
OZZ_INLINE SoaFloat4x4 Scale(const SoaFloat4x4& _m, const SoaFloat4& _v) {
const SoaFloat4x4 ret = {{{_m.cols[0].x * _v.x, _m.cols[0].y * _v.x,
_m.cols[0].z * _v.x, _m.cols[0].w * _v.x},
{_m.cols[1].x * _v.y, _m.cols[1].y * _v.y,
_m.cols[1].z * _v.y, _m.cols[1].w * _v.y},
{_m.cols[2].x * _v.z, _m.cols[2].y * _v.z,
_m.cols[2].z * _v.z, _m.cols[2].w * _v.z},
_m.cols[3]}};
return ret;
}
} // namespace math
} // namespace ozz
// Computes the multiplication of matrix Float4x4 and vector _v.
OZZ_INLINE ozz::math::SoaFloat4 operator*(const ozz::math::SoaFloat4x4& _m,
const ozz::math::SoaFloat4& _v) {
const ozz::math::SoaFloat4 ret = {
_m.cols[0].x * _v.x + _m.cols[1].x * _v.y + _m.cols[2].x * _v.z +
_m.cols[3].x * _v.w,
_m.cols[0].y * _v.x + _m.cols[1].y * _v.y + _m.cols[2].y * _v.z +
_m.cols[3].y * _v.w,
_m.cols[0].z * _v.x + _m.cols[1].z * _v.y + _m.cols[2].z * _v.z +
_m.cols[3].z * _v.w,
_m.cols[0].w * _v.x + _m.cols[1].w * _v.y + _m.cols[2].w * _v.z +
_m.cols[3].w * _v.w};
return ret;
}
// Computes the multiplication of two matrices _a and _b.
OZZ_INLINE ozz::math::SoaFloat4x4 operator*(const ozz::math::SoaFloat4x4& _a,
const ozz::math::SoaFloat4x4& _b) {
const ozz::math::SoaFloat4x4 ret = {
{_a * _b.cols[0], _a * _b.cols[1], _a * _b.cols[2], _a * _b.cols[3]}};
return ret;
}
// Computes the per element addition of two matrices _a and _b.
OZZ_INLINE ozz::math::SoaFloat4x4 operator+(const ozz::math::SoaFloat4x4& _a,
const ozz::math::SoaFloat4x4& _b) {
const ozz::math::SoaFloat4x4 ret = {
{{_a.cols[0].x + _b.cols[0].x, _a.cols[0].y + _b.cols[0].y,
_a.cols[0].z + _b.cols[0].z, _a.cols[0].w + _b.cols[0].w},
{_a.cols[1].x + _b.cols[1].x, _a.cols[1].y + _b.cols[1].y,
_a.cols[1].z + _b.cols[1].z, _a.cols[1].w + _b.cols[1].w},
{_a.cols[2].x + _b.cols[2].x, _a.cols[2].y + _b.cols[2].y,
_a.cols[2].z + _b.cols[2].z, _a.cols[2].w + _b.cols[2].w},
{_a.cols[3].x + _b.cols[3].x, _a.cols[3].y + _b.cols[3].y,
_a.cols[3].z + _b.cols[3].z, _a.cols[3].w + _b.cols[3].w}}};
return ret;
}
// Computes the per element subtraction of two matrices _a and _b.
OZZ_INLINE ozz::math::SoaFloat4x4 operator-(const ozz::math::SoaFloat4x4& _a,
const ozz::math::SoaFloat4x4& _b) {
const ozz::math::SoaFloat4x4 ret = {
{{_a.cols[0].x - _b.cols[0].x, _a.cols[0].y - _b.cols[0].y,
_a.cols[0].z - _b.cols[0].z, _a.cols[0].w - _b.cols[0].w},
{_a.cols[1].x - _b.cols[1].x, _a.cols[1].y - _b.cols[1].y,
_a.cols[1].z - _b.cols[1].z, _a.cols[1].w - _b.cols[1].w},
{_a.cols[2].x - _b.cols[2].x, _a.cols[2].y - _b.cols[2].y,
_a.cols[2].z - _b.cols[2].z, _a.cols[2].w - _b.cols[2].w},
{_a.cols[3].x - _b.cols[3].x, _a.cols[3].y - _b.cols[3].y,
_a.cols[3].z - _b.cols[3].z, _a.cols[3].w - _b.cols[3].w}}};
return ret;
}
#endif // OZZ_OZZ_BASE_MATHS_SOA_FLOAT4X4_H_
@@ -0,0 +1,99 @@
//----------------------------------------------------------------------------//
// //
// ozz-animation is hosted at http://github.com/guillaumeblanc/ozz-animation //
// and distributed under the MIT License (MIT). //
// //
// Copyright (c) Guillaume Blanc //
// //
// Permission is hereby granted, free of charge, to any person obtaining a //
// copy of this software and associated documentation files (the "Software"), //
// to deal in the Software without restriction, including without limitation //
// the rights to use, copy, modify, merge, publish, distribute, sublicense, //
// and/or sell copies of the Software, and to permit persons to whom the //
// Software is furnished to do so, subject to the following conditions: //
// //
// The above copyright notice and this permission notice shall be included in //
// all copies or substantial portions of the Software. //
// //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR //
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, //
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL //
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER //
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING //
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER //
// DEALINGS IN THE SOFTWARE. //
// //
//----------------------------------------------------------------------------//
#ifndef OZZ_OZZ_BASE_MATHS_SOA_MATH_ARCHIVE_H_
#define OZZ_OZZ_BASE_MATHS_SOA_MATH_ARCHIVE_H_
#include "ozz/base/io/archive_traits.h"
#include "ozz/base/platform.h"
namespace ozz {
namespace math {
struct SoaFloat2;
struct SoaFloat3;
struct SoaFloat4;
struct SoaQuaternion;
struct SoaFloat4x4;
struct SoaTransform;
} // namespace math
namespace io {
OZZ_IO_TYPE_NOT_VERSIONABLE(math::SoaFloat2)
template <>
struct Extern<math::SoaFloat2> {
static void Save(OArchive& _archive, const math::SoaFloat2* _values,
size_t _count);
static void Load(IArchive& _archive, math::SoaFloat2* _values, size_t _count,
uint32_t _version);
};
OZZ_IO_TYPE_NOT_VERSIONABLE(math::SoaFloat3)
template <>
struct Extern<math::SoaFloat3> {
static void Save(OArchive& _archive, const math::SoaFloat3* _values,
size_t _count);
static void Load(IArchive& _archive, math::SoaFloat3* _values, size_t _count,
uint32_t _version);
};
OZZ_IO_TYPE_NOT_VERSIONABLE(math::SoaFloat4)
template <>
struct Extern<math::SoaFloat4> {
static void Save(OArchive& _archive, const math::SoaFloat4* _values,
size_t _count);
static void Load(IArchive& _archive, math::SoaFloat4* _values, size_t _count,
uint32_t _version);
};
OZZ_IO_TYPE_NOT_VERSIONABLE(math::SoaQuaternion)
template <>
struct Extern<math::SoaQuaternion> {
static void Save(OArchive& _archive, const math::SoaQuaternion* _values,
size_t _count);
static void Load(IArchive& _archive, math::SoaQuaternion* _values,
size_t _count, uint32_t _version);
};
OZZ_IO_TYPE_NOT_VERSIONABLE(math::SoaFloat4x4)
template <>
struct Extern<math::SoaFloat4x4> {
static void Save(OArchive& _archive, const math::SoaFloat4x4* _values,
size_t _count);
static void Load(IArchive& _archive, math::SoaFloat4x4* _values,
size_t _count, uint32_t _version);
};
OZZ_IO_TYPE_NOT_VERSIONABLE(math::SoaTransform)
template <>
struct Extern<math::SoaTransform> {
static void Save(OArchive& _archive, const math::SoaTransform* _values,
size_t _count);
static void Load(IArchive& _archive, math::SoaTransform* _values,
size_t _count, uint32_t _version);
};
} // namespace io
} // namespace ozz
#endif // OZZ_OZZ_BASE_MATHS_SOA_MATH_ARCHIVE_H_
@@ -0,0 +1,189 @@
//----------------------------------------------------------------------------//
// //
// ozz-animation is hosted at http://github.com/guillaumeblanc/ozz-animation //
// and distributed under the MIT License (MIT). //
// //
// Copyright (c) Guillaume Blanc //
// //
// Permission is hereby granted, free of charge, to any person obtaining a //
// copy of this software and associated documentation files (the "Software"), //
// to deal in the Software without restriction, including without limitation //
// the rights to use, copy, modify, merge, publish, distribute, sublicense, //
// and/or sell copies of the Software, and to permit persons to whom the //
// Software is furnished to do so, subject to the following conditions: //
// //
// The above copyright notice and this permission notice shall be included in //
// all copies or substantial portions of the Software. //
// //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR //
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, //
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL //
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER //
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING //
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER //
// DEALINGS IN THE SOFTWARE. //
// //
//----------------------------------------------------------------------------//
#ifndef OZZ_OZZ_BASE_MATHS_SOA_QUATERNION_H_
#define OZZ_OZZ_BASE_MATHS_SOA_QUATERNION_H_
#include <cassert>
#include "ozz/base/maths/soa_float.h"
#include "ozz/base/platform.h"
namespace ozz {
namespace math {
struct SoaQuaternion {
SimdFloat4 x, y, z, w;
// Loads a quaternion from 4 SimdFloat4 values.
static OZZ_INLINE SoaQuaternion Load(_SimdFloat4 _x, _SimdFloat4 _y,
_SimdFloat4 _z, const SimdFloat4& _w) {
const SoaQuaternion r = {_x, _y, _z, _w};
return r;
}
// Returns the identity SoaQuaternion.
static OZZ_INLINE SoaQuaternion identity() {
const SimdFloat4 zero = simd_float4::zero();
const SoaQuaternion r = {zero, zero, zero, simd_float4::one()};
return r;
}
};
// Returns the conjugate of _q. This is the same as the inverse if _q is
// normalized. Otherwise the magnitude of the inverse is 1.f/|_q|.
OZZ_INLINE SoaQuaternion Conjugate(const SoaQuaternion& _q) {
const SoaQuaternion r = {-_q.x, -_q.y, -_q.z, _q.w};
return r;
}
// Returns the negate of _q. This represent the same rotation as q.
OZZ_INLINE SoaQuaternion operator-(const SoaQuaternion& _q) {
const SoaQuaternion r = {-_q.x, -_q.y, -_q.z, -_q.w};
return r;
}
// Returns the 4D dot product of quaternion _a and _b.
OZZ_INLINE SimdFloat4 Dot(const SoaQuaternion& _a, const SoaQuaternion& _b) {
return _a.x * _b.x + _a.y * _b.y + _a.z * _b.z + _a.w * _b.w;
}
// Returns the normalized SoaQuaternion _q.
OZZ_INLINE SoaQuaternion Normalize(const SoaQuaternion& _q) {
const SimdFloat4 len2 = _q.x * _q.x + _q.y * _q.y + _q.z * _q.z + _q.w * _q.w;
const SimdFloat4 inv_len = math::simd_float4::one() / Sqrt(len2);
const SoaQuaternion r = {_q.x * inv_len, _q.y * inv_len, _q.z * inv_len,
_q.w * inv_len};
return r;
}
// Returns the estimated normalized SoaQuaternion _q.
OZZ_INLINE SoaQuaternion NormalizeEst(const SoaQuaternion& _q) {
const SimdFloat4 len2 = _q.x * _q.x + _q.y * _q.y + _q.z * _q.z + _q.w * _q.w;
// Uses RSqrtEstNR (with one more Newton-Raphson step) as quaternions loose
// much precision due to normalization.
const SimdFloat4 inv_len = RSqrtEstNR(len2);
const SoaQuaternion r = {_q.x * inv_len, _q.y * inv_len, _q.z * inv_len,
_q.w * inv_len};
return r;
}
// Test if each quaternion of _q is normalized.
OZZ_INLINE SimdInt4 IsNormalized(const SoaQuaternion& _q) {
const SimdFloat4 len2 = _q.x * _q.x + _q.y * _q.y + _q.z * _q.z + _q.w * _q.w;
return CmpLt(Abs(len2 - math::simd_float4::one()),
simd_float4::Load1(kNormalizationToleranceSq));
}
// Test if each quaternion of _q is normalized. using estimated tolerance.
OZZ_INLINE SimdInt4 IsNormalizedEst(const SoaQuaternion& _q) {
const SimdFloat4 len2 = _q.x * _q.x + _q.y * _q.y + _q.z * _q.z + _q.w * _q.w;
return CmpLt(Abs(len2 - math::simd_float4::one()),
simd_float4::Load1(kNormalizationToleranceEstSq));
}
// Returns the linear interpolation of SoaQuaternion _a and _b with coefficient
// _f.
OZZ_INLINE SoaQuaternion Lerp(const SoaQuaternion& _a, const SoaQuaternion& _b,
_SimdFloat4 _f) {
const SoaQuaternion r = {(_b.x - _a.x) * _f + _a.x, (_b.y - _a.y) * _f + _a.y,
(_b.z - _a.z) * _f + _a.z,
(_b.w - _a.w) * _f + _a.w};
return r;
}
// Returns the linear interpolation of SoaQuaternion _a and _b with coefficient
// _f.
OZZ_INLINE SoaQuaternion NLerp(const SoaQuaternion& _a, const SoaQuaternion& _b,
_SimdFloat4 _f) {
const SoaFloat4 lerp = {(_b.x - _a.x) * _f + _a.x, (_b.y - _a.y) * _f + _a.y,
(_b.z - _a.z) * _f + _a.z, (_b.w - _a.w) * _f + _a.w};
const SimdFloat4 len2 =
lerp.x * lerp.x + lerp.y * lerp.y + lerp.z * lerp.z + lerp.w * lerp.w;
const SimdFloat4 inv_len = math::simd_float4::one() / Sqrt(len2);
const SoaQuaternion r = {lerp.x * inv_len, lerp.y * inv_len, lerp.z * inv_len,
lerp.w * inv_len};
return r;
}
// Returns the estimated linear interpolation of SoaQuaternion _a and _b with
// coefficient _f.
OZZ_INLINE SoaQuaternion NLerpEst(const SoaQuaternion& _a,
const SoaQuaternion& _b, _SimdFloat4 _f) {
const SoaFloat4 lerp = {(_b.x - _a.x) * _f + _a.x, (_b.y - _a.y) * _f + _a.y,
(_b.z - _a.z) * _f + _a.z, (_b.w - _a.w) * _f + _a.w};
const SimdFloat4 len2 =
lerp.x * lerp.x + lerp.y * lerp.y + lerp.z * lerp.z + lerp.w * lerp.w;
// Uses RSqrtEstNR (with one more Newton-Raphson step) as quaternions loose
// much precision due to normalization.
const SimdFloat4 inv_len = RSqrtEstNR(len2);
const SoaQuaternion r = {lerp.x * inv_len, lerp.y * inv_len, lerp.z * inv_len,
lerp.w * inv_len};
return r;
}
} // namespace math
} // namespace ozz
// Returns the addition of _a and _b.
OZZ_INLINE ozz::math::SoaQuaternion operator+(
const ozz::math::SoaQuaternion& _a, const ozz::math::SoaQuaternion& _b) {
const ozz::math::SoaQuaternion r = {_a.x + _b.x, _a.y + _b.y, _a.z + _b.z,
_a.w + _b.w};
return r;
}
// Returns the multiplication of _q and scalar value _f.
OZZ_INLINE ozz::math::SoaQuaternion operator*(
const ozz::math::SoaQuaternion& _q, const ozz::math::SimdFloat4& _f) {
const ozz::math::SoaQuaternion r = {_q.x * _f, _q.y * _f, _q.z * _f,
_q.w * _f};
return r;
}
// Returns the multiplication of _a and _b. If both _a and _b are normalized,
// then the result is normalized.
OZZ_INLINE ozz::math::SoaQuaternion operator*(
const ozz::math::SoaQuaternion& _a, const ozz::math::SoaQuaternion& _b) {
const ozz::math::SoaQuaternion r = {
_a.w * _b.x + _a.x * _b.w + _a.y * _b.z - _a.z * _b.y,
_a.w * _b.y + _a.y * _b.w + _a.z * _b.x - _a.x * _b.z,
_a.w * _b.z + _a.z * _b.w + _a.x * _b.y - _a.y * _b.x,
_a.w * _b.w - _a.x * _b.x - _a.y * _b.y - _a.z * _b.z};
return r;
}
// Returns true if each element of _a is equal to each element of _b.
// Uses a bitwise comparison of _a and _b, no tolerance is applied.
OZZ_INLINE ozz::math::SimdInt4 operator==(const ozz::math::SoaQuaternion& _a,
const ozz::math::SoaQuaternion& _b) {
const ozz::math::SimdInt4 x = ozz::math::CmpEq(_a.x, _b.x);
const ozz::math::SimdInt4 y = ozz::math::CmpEq(_a.y, _b.y);
const ozz::math::SimdInt4 z = ozz::math::CmpEq(_a.z, _b.z);
const ozz::math::SimdInt4 w = ozz::math::CmpEq(_a.w, _b.w);
return ozz::math::And(ozz::math::And(ozz::math::And(x, y), z), w);
}
#endif // OZZ_OZZ_BASE_MATHS_SOA_QUATERNION_H_
@@ -0,0 +1,53 @@
//----------------------------------------------------------------------------//
// //
// ozz-animation is hosted at http://github.com/guillaumeblanc/ozz-animation //
// and distributed under the MIT License (MIT). //
// //
// Copyright (c) Guillaume Blanc //
// //
// Permission is hereby granted, free of charge, to any person obtaining a //
// copy of this software and associated documentation files (the "Software"), //
// to deal in the Software without restriction, including without limitation //
// the rights to use, copy, modify, merge, publish, distribute, sublicense, //
// and/or sell copies of the Software, and to permit persons to whom the //
// Software is furnished to do so, subject to the following conditions: //
// //
// The above copyright notice and this permission notice shall be included in //
// all copies or substantial portions of the Software. //
// //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR //
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, //
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL //
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER //
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING //
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER //
// DEALINGS IN THE SOFTWARE. //
// //
//----------------------------------------------------------------------------//
#ifndef OZZ_OZZ_BASE_MATHS_SOA_TRANSFORM_H_
#define OZZ_OZZ_BASE_MATHS_SOA_TRANSFORM_H_
#include "ozz/base/maths/soa_float.h"
#include "ozz/base/maths/soa_quaternion.h"
#include "ozz/base/platform.h"
namespace ozz {
namespace math {
// Stores an affine transformation with separate translation, rotation and scale
// attributes.
struct SoaTransform {
SoaFloat3 translation;
SoaQuaternion rotation;
SoaFloat3 scale;
static OZZ_INLINE SoaTransform identity() {
const SoaTransform ret = {SoaFloat3::zero(), SoaQuaternion::identity(),
SoaFloat3::one()};
return ret;
}
};
} // namespace math
} // namespace ozz
#endif // OZZ_OZZ_BASE_MATHS_SOA_TRANSFORM_H_
@@ -0,0 +1,59 @@
//----------------------------------------------------------------------------//
// //
// ozz-animation is hosted at http://github.com/guillaumeblanc/ozz-animation //
// and distributed under the MIT License (MIT). //
// //
// Copyright (c) Guillaume Blanc //
// //
// Permission is hereby granted, free of charge, to any person obtaining a //
// copy of this software and associated documentation files (the "Software"), //
// to deal in the Software without restriction, including without limitation //
// the rights to use, copy, modify, merge, publish, distribute, sublicense, //
// and/or sell copies of the Software, and to permit persons to whom the //
// Software is furnished to do so, subject to the following conditions: //
// //
// The above copyright notice and this permission notice shall be included in //
// all copies or substantial portions of the Software. //
// //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR //
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, //
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL //
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER //
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING //
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER //
// DEALINGS IN THE SOFTWARE. //
// //
//----------------------------------------------------------------------------//
#ifndef OZZ_OZZ_BASE_MATHS_TRANSFORM_H_
#define OZZ_OZZ_BASE_MATHS_TRANSFORM_H_
#include "ozz/base/maths/quaternion.h"
#include "ozz/base/maths/vec_float.h"
#include "ozz/base/platform.h"
namespace ozz {
namespace math {
// Stores an affine transformation with separate translation, rotation and scale
// attributes.
struct Transform {
// Translation affine transformation component.
Float3 translation;
// Rotation affine transformation component.
Quaternion rotation;
// Scale affine transformation component.
Float3 scale;
// Builds an identity transform.
static OZZ_INLINE Transform identity() {
const Transform ret = {Float3::zero(), Quaternion::identity(),
Float3::one()};
return ret;
}
};
} // namespace math
} // namespace ozz
#endif // OZZ_OZZ_BASE_MATHS_TRANSFORM_H_
@@ -0,0 +1,467 @@
//----------------------------------------------------------------------------//
// //
// ozz-animation is hosted at http://github.com/guillaumeblanc/ozz-animation //
// and distributed under the MIT License (MIT). //
// //
// Copyright (c) Guillaume Blanc //
// //
// Permission is hereby granted, free of charge, to any person obtaining a //
// copy of this software and associated documentation files (the "Software"), //
// to deal in the Software without restriction, including without limitation //
// the rights to use, copy, modify, merge, publish, distribute, sublicense, //
// and/or sell copies of the Software, and to permit persons to whom the //
// Software is furnished to do so, subject to the following conditions: //
// //
// The above copyright notice and this permission notice shall be included in //
// all copies or substantial portions of the Software. //
// //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR //
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, //
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL //
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER //
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING //
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER //
// DEALINGS IN THE SOFTWARE. //
// //
//----------------------------------------------------------------------------//
#ifndef OZZ_OZZ_BASE_MATHS_VEC_FLOAT_H_
#define OZZ_OZZ_BASE_MATHS_VEC_FLOAT_H_
#include <cassert>
#include <cmath>
#include "ozz/base/maths/math_constant.h"
#include "ozz/base/platform.h"
namespace ozz {
namespace math {
// Declares a 2d float vector.
struct Float2 {
float x, y;
// Constructs an uninitialized vector.
OZZ_INLINE Float2() {}
// Constructs a vector initialized with _f value.
explicit OZZ_INLINE Float2(float _f) : x(_f), y(_f) {}
// Constructs a vector initialized with _x and _y values.
OZZ_INLINE Float2(float _x, float _y) : x(_x), y(_y) {}
// Returns a vector with all components set to 0.
static OZZ_INLINE Float2 zero() { return Float2(0.f); }
// Returns a vector with all components set to 1.
static OZZ_INLINE Float2 one() { return Float2(1.f); }
// Returns a unitary vector x.
static OZZ_INLINE Float2 x_axis() { return Float2(1.f, 0.f); }
// Returns a unitary vector y.
static OZZ_INLINE Float2 y_axis() { return Float2(0.f, 1.f); }
};
// Declares a 3d float vector.
struct Float3 {
float x, y, z;
// Constructs an uninitialized vector.
OZZ_INLINE Float3() {}
// Constructs a vector initialized with _f value.
explicit OZZ_INLINE Float3(float _f) : x(_f), y(_f), z(_f) {}
// Constructs a vector initialized with _x, _y and _z values.
OZZ_INLINE Float3(float _x, float _y, float _z) : x(_x), y(_y), z(_z) {}
// Returns a vector initialized with _v.x, _v.y and _z values.
OZZ_INLINE Float3(Float2 _v, float _z) : x(_v.x), y(_v.y), z(_z) {}
// Returns a vector with all components set to 0.
static OZZ_INLINE Float3 zero() { return Float3(0.f); }
// Returns a vector with all components set to 1.
static OZZ_INLINE Float3 one() { return Float3(1.f); }
// Returns a unitary vector x.
static OZZ_INLINE Float3 x_axis() { return Float3(1.f, 0.f, 0.f); }
// Returns a unitary vector y.
static OZZ_INLINE Float3 y_axis() { return Float3(0.f, 1.f, 0.f); }
// Returns a unitary vector z.
static OZZ_INLINE Float3 z_axis() { return Float3(0.f, 0.f, 1.f); }
};
// Declares a 4d float vector.
struct Float4 {
float x, y, z, w;
// Constructs an uninitialized vector.
OZZ_INLINE Float4() {}
// Constructs a vector initialized with _f value.
explicit OZZ_INLINE Float4(float _f) : x(_f), y(_f), z(_f), w(_f) {}
// Constructs a vector initialized with _x, _y, _z and _w values.
OZZ_INLINE Float4(float _x, float _y, float _z, float _w)
: x(_x), y(_y), z(_z), w(_w) {}
// Constructs a vector initialized with _v.x, _v.y, _v.z and _w values.
OZZ_INLINE Float4(Float3 _v, float _w) : x(_v.x), y(_v.y), z(_v.z), w(_w) {}
// Constructs a vector initialized with _v.x, _v.y, _z and _w values.
OZZ_INLINE Float4(Float2 _v, float _z, float _w)
: x(_v.x), y(_v.y), z(_z), w(_w) {}
// Returns a vector with all components set to 0.
static OZZ_INLINE Float4 zero() { return Float4(0.f); }
// Returns a vector with all components set to 1.
static OZZ_INLINE Float4 one() { return Float4(1.f); }
// Returns a unitary vector x.
static OZZ_INLINE Float4 x_axis() { return Float4(1.f, 0.f, 0.f, 0.f); }
// Returns a unitary vector y.
static OZZ_INLINE Float4 y_axis() { return Float4(0.f, 1.f, 0.f, 0.f); }
// Returns a unitary vector z.
static OZZ_INLINE Float4 z_axis() { return Float4(0.f, 0.f, 1.f, 0.f); }
// Returns a unitary vector w.
static OZZ_INLINE Float4 w_axis() { return Float4(0.f, 0.f, 0.f, 1.f); }
};
// Returns per element addition of _a and _b using operator +.
OZZ_INLINE Float4 operator+(const Float4& _a, const Float4& _b) {
return Float4(_a.x + _b.x, _a.y + _b.y, _a.z + _b.z, _a.w + _b.w);
}
OZZ_INLINE Float3 operator+(const Float3& _a, const Float3& _b) {
return Float3(_a.x + _b.x, _a.y + _b.y, _a.z + _b.z);
}
OZZ_INLINE Float2 operator+(const Float2& _a, const Float2& _b) {
return Float2(_a.x + _b.x, _a.y + _b.y);
}
// Returns per element subtraction of _a and _b using operator -.
OZZ_INLINE Float4 operator-(const Float4& _a, const Float4& _b) {
return Float4(_a.x - _b.x, _a.y - _b.y, _a.z - _b.z, _a.w - _b.w);
}
OZZ_INLINE Float3 operator-(const Float3& _a, const Float3& _b) {
return Float3(_a.x - _b.x, _a.y - _b.y, _a.z - _b.z);
}
OZZ_INLINE Float2 operator-(const Float2& _a, const Float2& _b) {
return Float2(_a.x - _b.x, _a.y - _b.y);
}
// Returns per element negative value of _v.
OZZ_INLINE Float4 operator-(const Float4& _v) {
return Float4(-_v.x, -_v.y, -_v.z, -_v.w);
}
OZZ_INLINE Float3 operator-(const Float3& _v) {
return Float3(-_v.x, -_v.y, -_v.z);
}
OZZ_INLINE Float2 operator-(const Float2& _v) { return Float2(-_v.x, -_v.y); }
// Returns per element multiplication of _a and _b using operator *.
OZZ_INLINE Float4 operator*(const Float4& _a, const Float4& _b) {
return Float4(_a.x * _b.x, _a.y * _b.y, _a.z * _b.z, _a.w * _b.w);
}
OZZ_INLINE Float3 operator*(const Float3& _a, const Float3& _b) {
return Float3(_a.x * _b.x, _a.y * _b.y, _a.z * _b.z);
}
OZZ_INLINE Float2 operator*(const Float2& _a, const Float2& _b) {
return Float2(_a.x * _b.x, _a.y * _b.y);
}
// Returns per element multiplication of _a and scalar value _f using
// operator *.
OZZ_INLINE Float4 operator*(const Float4& _a, float _f) {
return Float4(_a.x * _f, _a.y * _f, _a.z * _f, _a.w * _f);
}
OZZ_INLINE Float3 operator*(const Float3& _a, float _f) {
return Float3(_a.x * _f, _a.y * _f, _a.z * _f);
}
OZZ_INLINE Float2 operator*(const Float2& _a, float _f) {
return Float2(_a.x * _f, _a.y * _f);
}
// Returns per element division of _a and _b using operator /.
OZZ_INLINE Float4 operator/(const Float4& _a, const Float4& _b) {
return Float4(_a.x / _b.x, _a.y / _b.y, _a.z / _b.z, _a.w / _b.w);
}
OZZ_INLINE Float3 operator/(const Float3& _a, const Float3& _b) {
return Float3(_a.x / _b.x, _a.y / _b.y, _a.z / _b.z);
}
OZZ_INLINE Float2 operator/(const Float2& _a, const Float2& _b) {
return Float2(_a.x / _b.x, _a.y / _b.y);
}
// Returns per element division of _a and scalar value _f using operator/.
OZZ_INLINE Float4 operator/(const Float4& _a, float _f) {
return Float4(_a.x / _f, _a.y / _f, _a.z / _f, _a.w / _f);
}
OZZ_INLINE Float3 operator/(const Float3& _a, float _f) {
return Float3(_a.x / _f, _a.y / _f, _a.z / _f);
}
OZZ_INLINE Float2 operator/(const Float2& _a, float _f) {
return Float2(_a.x / _f, _a.y / _f);
}
// Returns the (horizontal) addition of each element of _v.
OZZ_INLINE float HAdd(const Float4& _v) { return _v.x + _v.y + _v.z + _v.w; }
OZZ_INLINE float HAdd(const Float3& _v) { return _v.x + _v.y + _v.z; }
OZZ_INLINE float HAdd(const Float2& _v) { return _v.x + _v.y; }
// Returns the dot product of _a and _b.
OZZ_INLINE float Dot(const Float4& _a, const Float4& _b) {
return _a.x * _b.x + _a.y * _b.y + _a.z * _b.z + _a.w * _b.w;
}
OZZ_INLINE float Dot(const Float3& _a, const Float3& _b) {
return _a.x * _b.x + _a.y * _b.y + _a.z * _b.z;
}
OZZ_INLINE float Dot(const Float2& _a, const Float2& _b) {
return _a.x * _b.x + _a.y * _b.y;
}
// Returns the cross product of _a and _b.
OZZ_INLINE Float3 Cross(const Float3& _a, const Float3& _b) {
return Float3(_a.y * _b.z - _b.y * _a.z, _a.z * _b.x - _b.z * _a.x,
_a.x * _b.y - _b.x * _a.y);
}
// Returns the length |_v| of _v.
OZZ_INLINE float Length(const Float4& _v) {
const float len2 = _v.x * _v.x + _v.y * _v.y + _v.z * _v.z + _v.w * _v.w;
return std::sqrt(len2);
}
OZZ_INLINE float Length(const Float3& _v) {
const float len2 = _v.x * _v.x + _v.y * _v.y + _v.z * _v.z;
return std::sqrt(len2);
}
OZZ_INLINE float Length(const Float2& _v) {
const float len2 = _v.x * _v.x + _v.y * _v.y;
return std::sqrt(len2);
}
// Returns the square length |_v|^2 of _v.
OZZ_INLINE float LengthSqr(const Float4& _v) {
return _v.x * _v.x + _v.y * _v.y + _v.z * _v.z + _v.w * _v.w;
}
OZZ_INLINE float LengthSqr(const Float3& _v) {
return _v.x * _v.x + _v.y * _v.y + _v.z * _v.z;
}
OZZ_INLINE float LengthSqr(const Float2& _v) {
return _v.x * _v.x + _v.y * _v.y;
}
// Returns the normalized vector _v.
OZZ_INLINE Float4 Normalize(const Float4& _v) {
const float len2 = _v.x * _v.x + _v.y * _v.y + _v.z * _v.z + _v.w * _v.w;
assert(len2 != 0.f && "_v is not normalizable");
const float len = std::sqrt(len2);
return Float4(_v.x / len, _v.y / len, _v.z / len, _v.w / len);
}
OZZ_INLINE Float3 Normalize(const Float3& _v) {
const float len2 = _v.x * _v.x + _v.y * _v.y + _v.z * _v.z;
assert(len2 != 0.f && "_v is not normalizable");
const float len = std::sqrt(len2);
return Float3(_v.x / len, _v.y / len, _v.z / len);
}
OZZ_INLINE Float2 Normalize(const Float2& _v) {
const float len2 = _v.x * _v.x + _v.y * _v.y;
assert(len2 != 0.f && "_v is not normalizable");
const float len = std::sqrt(len2);
return Float2(_v.x / len, _v.y / len);
}
// Returns true if _v is normalized.
OZZ_INLINE bool IsNormalized(const Float4& _v) {
const float len2 = _v.x * _v.x + _v.y * _v.y + _v.z * _v.z + _v.w * _v.w;
return std::abs(len2 - 1.f) < kNormalizationToleranceSq;
}
OZZ_INLINE bool IsNormalized(const Float3& _v) {
const float len2 = _v.x * _v.x + _v.y * _v.y + _v.z * _v.z;
return std::abs(len2 - 1.f) < kNormalizationToleranceSq;
}
OZZ_INLINE bool IsNormalized(const Float2& _v) {
const float len2 = _v.x * _v.x + _v.y * _v.y;
return std::abs(len2 - 1.f) < kNormalizationToleranceSq;
}
// Returns the normalized vector _v if the norm of _v is not 0.
// Otherwise returns _safer.
OZZ_INLINE Float4 NormalizeSafe(const Float4& _v, const Float4& _safer) {
assert(IsNormalized(_safer) && "_safer is not normalized");
const float len2 = _v.x * _v.x + _v.y * _v.y + _v.z * _v.z + _v.w * _v.w;
if (len2 <= 0.f) {
return _safer;
}
const float len = std::sqrt(len2);
return Float4(_v.x / len, _v.y / len, _v.z / len, _v.w / len);
}
OZZ_INLINE Float3 NormalizeSafe(const Float3& _v, const Float3& _safer) {
assert(IsNormalized(_safer) && "_safer is not normalized");
const float len2 = _v.x * _v.x + _v.y * _v.y + _v.z * _v.z;
if (len2 <= 0.f) {
return _safer;
}
const float len = std::sqrt(len2);
return Float3(_v.x / len, _v.y / len, _v.z / len);
}
OZZ_INLINE Float2 NormalizeSafe(const Float2& _v, const Float2& _safer) {
assert(IsNormalized(_safer) && "_safer is not normalized");
const float len2 = _v.x * _v.x + _v.y * _v.y;
if (len2 <= 0.f) {
return _safer;
}
const float len = std::sqrt(len2);
return Float2(_v.x / len, _v.y / len);
}
// Returns the linear interpolation of _a and _b with coefficient _f.
// _f is not limited to range [0,1].
OZZ_INLINE Float4 Lerp(const Float4& _a, const Float4& _b, float _f) {
return Float4((_b.x - _a.x) * _f + _a.x, (_b.y - _a.y) * _f + _a.y,
(_b.z - _a.z) * _f + _a.z, (_b.w - _a.w) * _f + _a.w);
}
OZZ_INLINE Float3 Lerp(const Float3& _a, const Float3& _b, float _f) {
return Float3((_b.x - _a.x) * _f + _a.x, (_b.y - _a.y) * _f + _a.y,
(_b.z - _a.z) * _f + _a.z);
}
OZZ_INLINE Float2 Lerp(const Float2& _a, const Float2& _b, float _f) {
return Float2((_b.x - _a.x) * _f + _a.x, (_b.y - _a.y) * _f + _a.y);
}
// Returns true if the distance between _a and _b is less than _tolerance.
OZZ_INLINE bool Compare(const Float4& _a, const Float4& _b, float _tolerance) {
const math::Float4 diff = _a - _b;
return Dot(diff, diff) <= _tolerance * _tolerance;
}
OZZ_INLINE bool Compare(const Float3& _a, const Float3& _b, float _tolerance) {
const math::Float3 diff = _a - _b;
return Dot(diff, diff) <= _tolerance * _tolerance;
}
OZZ_INLINE bool Compare(const Float2& _a, const Float2& _b, float _tolerance) {
const math::Float2 diff = _a - _b;
return Dot(diff, diff) <= _tolerance * _tolerance;
}
// Returns true if each element of a is less than each element of _b.
OZZ_INLINE bool operator<(const Float4& _a, const Float4& _b) {
return _a.x < _b.x && _a.y < _b.y && _a.z < _b.z && _a.w < _b.w;
}
OZZ_INLINE bool operator<(const Float3& _a, const Float3& _b) {
return _a.x < _b.x && _a.y < _b.y && _a.z < _b.z;
}
OZZ_INLINE bool operator<(const Float2& _a, const Float2& _b) {
return _a.x < _b.x && _a.y < _b.y;
}
// Returns true if each element of a is less or equal to each element of _b.
OZZ_INLINE bool operator<=(const Float4& _a, const Float4& _b) {
return _a.x <= _b.x && _a.y <= _b.y && _a.z <= _b.z && _a.w <= _b.w;
}
OZZ_INLINE bool operator<=(const Float3& _a, const Float3& _b) {
return _a.x <= _b.x && _a.y <= _b.y && _a.z <= _b.z;
}
OZZ_INLINE bool operator<=(const Float2& _a, const Float2& _b) {
return _a.x <= _b.x && _a.y <= _b.y;
}
// Returns true if each element of a is greater than each element of _b.
OZZ_INLINE bool operator>(const Float4& _a, const Float4& _b) {
return _a.x > _b.x && _a.y > _b.y && _a.z > _b.z && _a.w > _b.w;
}
OZZ_INLINE bool operator>(const Float3& _a, const Float3& _b) {
return _a.x > _b.x && _a.y > _b.y && _a.z > _b.z;
}
OZZ_INLINE bool operator>(const Float2& _a, const Float2& _b) {
return _a.x > _b.x && _a.y > _b.y;
}
// Returns true if each element of a is greater or equal to each element of _b.
OZZ_INLINE bool operator>=(const Float4& _a, const Float4& _b) {
return _a.x >= _b.x && _a.y >= _b.y && _a.z >= _b.z && _a.w >= _b.w;
}
OZZ_INLINE bool operator>=(const Float3& _a, const Float3& _b) {
return _a.x >= _b.x && _a.y >= _b.y && _a.z >= _b.z;
}
OZZ_INLINE bool operator>=(const Float2& _a, const Float2& _b) {
return _a.x >= _b.x && _a.y >= _b.y;
}
// Returns true if each element of a is equal to each element of _b.
// Uses a bitwise comparison of _a and _b, no tolerance is applied.
OZZ_INLINE bool operator==(const Float4& _a, const Float4& _b) {
return _a.x == _b.x && _a.y == _b.y && _a.z == _b.z && _a.w == _b.w;
}
OZZ_INLINE bool operator==(const Float3& _a, const Float3& _b) {
return _a.x == _b.x && _a.y == _b.y && _a.z == _b.z;
}
OZZ_INLINE bool operator==(const Float2& _a, const Float2& _b) {
return _a.x == _b.x && _a.y == _b.y;
}
// Returns true if each element of a is different from each element of _b.
// Uses a bitwise comparison of _a and _b, no tolerance is applied.
OZZ_INLINE bool operator!=(const Float4& _a, const Float4& _b) {
return _a.x != _b.x || _a.y != _b.y || _a.z != _b.z || _a.w != _b.w;
}
OZZ_INLINE bool operator!=(const Float3& _a, const Float3& _b) {
return _a.x != _b.x || _a.y != _b.y || _a.z != _b.z;
}
OZZ_INLINE bool operator!=(const Float2& _a, const Float2& _b) {
return _a.x != _b.x || _a.y != _b.y;
}
// Returns the minimum of each element of _a and _b.
OZZ_INLINE Float4 Min(const Float4& _a, const Float4& _b) {
return Float4(_a.x < _b.x ? _a.x : _b.x, _a.y < _b.y ? _a.y : _b.y,
_a.z < _b.z ? _a.z : _b.z, _a.w < _b.w ? _a.w : _b.w);
}
OZZ_INLINE Float3 Min(const Float3& _a, const Float3& _b) {
return Float3(_a.x < _b.x ? _a.x : _b.x, _a.y < _b.y ? _a.y : _b.y,
_a.z < _b.z ? _a.z : _b.z);
}
OZZ_INLINE Float2 Min(const Float2& _a, const Float2& _b) {
return Float2(_a.x < _b.x ? _a.x : _b.x, _a.y < _b.y ? _a.y : _b.y);
}
// Returns the maximum of each element of _a and _b.
OZZ_INLINE Float4 Max(const Float4& _a, const Float4& _b) {
return Float4(_a.x > _b.x ? _a.x : _b.x, _a.y > _b.y ? _a.y : _b.y,
_a.z > _b.z ? _a.z : _b.z, _a.w > _b.w ? _a.w : _b.w);
}
OZZ_INLINE Float3 Max(const Float3& _a, const Float3& _b) {
return Float3(_a.x > _b.x ? _a.x : _b.x, _a.y > _b.y ? _a.y : _b.y,
_a.z > _b.z ? _a.z : _b.z);
}
OZZ_INLINE Float2 Max(const Float2& _a, const Float2& _b) {
return Float2(_a.x > _b.x ? _a.x : _b.x, _a.y > _b.y ? _a.y : _b.y);
}
// Clamps each element of _x between _a and _b.
// _a must be less or equal to b;
OZZ_INLINE Float4 Clamp(const Float4& _a, const Float4& _v, const Float4& _b) {
const Float4 min(_v.x < _b.x ? _v.x : _b.x, _v.y < _b.y ? _v.y : _b.y,
_v.z < _b.z ? _v.z : _b.z, _v.w < _b.w ? _v.w : _b.w);
return Float4(_a.x > min.x ? _a.x : min.x, _a.y > min.y ? _a.y : min.y,
_a.z > min.z ? _a.z : min.z, _a.w > min.w ? _a.w : min.w);
}
OZZ_INLINE Float3 Clamp(const Float3& _a, const Float3& _v, const Float3& _b) {
const Float3 min(_v.x < _b.x ? _v.x : _b.x, _v.y < _b.y ? _v.y : _b.y,
_v.z < _b.z ? _v.z : _b.z);
return Float3(_a.x > min.x ? _a.x : min.x, _a.y > min.y ? _a.y : min.y,
_a.z > min.z ? _a.z : min.z);
}
OZZ_INLINE Float2 Clamp(const Float2& _a, const Float2& _v, const Float2& _b) {
const Float2 min(_v.x < _b.x ? _v.x : _b.x, _v.y < _b.y ? _v.y : _b.y);
return Float2(_a.x > min.x ? _a.x : min.x, _a.y > min.y ? _a.y : min.y);
}
} // namespace math
} // namespace ozz
#endif // OZZ_OZZ_BASE_MATHS_VEC_FLOAT_H_