summaryrefslogtreecommitdiffhomepage
path: root/ovr_sdk_win_23.0.0/LibOVR/Include/Extras/OVR_Math.h
diff options
context:
space:
mode:
Diffstat (limited to 'ovr_sdk_win_23.0.0/LibOVR/Include/Extras/OVR_Math.h')
-rw-r--r--ovr_sdk_win_23.0.0/LibOVR/Include/Extras/OVR_Math.h4526
1 files changed, 4526 insertions, 0 deletions
diff --git a/ovr_sdk_win_23.0.0/LibOVR/Include/Extras/OVR_Math.h b/ovr_sdk_win_23.0.0/LibOVR/Include/Extras/OVR_Math.h
new file mode 100644
index 0000000..a31911f
--- /dev/null
+++ b/ovr_sdk_win_23.0.0/LibOVR/Include/Extras/OVR_Math.h
@@ -0,0 +1,4526 @@
+/********************************************************************************/ /**
+ \file OVR_Math.h
+ \brief Implementation of 3D primitives such as vectors, matrices.
+ \copyright Copyright (c) Facebook Technologies, LLC and its affiliates. All rights reserved.
+ *************************************************************************************/
+
+#ifndef OVR_Math_h
+#define OVR_Math_h
+
+// This file is intended to be independent of the rest of LibOVR and LibOVRKernel and thus
+// has no #include dependencies on either.
+
+#include <float.h>
+#include <math.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifndef OVR_EXCLUDE_CAPI_FROM_MATH
+#include "../OVR_CAPI.h" // Required due to a dependence on the ovrFovPort_ declaration.
+#endif
+
+#if defined(_MSC_VER)
+#pragma warning(push)
+#pragma warning(disable : 4127) // conditional expression is constant
+
+#if _MSC_VER < 1800 // isfinite was introduced in VS2013
+#define isfinite(x) _finite((x))
+#endif
+#endif
+
+#if defined(_MSC_VER)
+#define OVRMath_sprintf sprintf_s
+#else
+#define OVRMath_sprintf snprintf
+#endif
+
+//-------------------------------------------------------------------------------------
+// ***** OVR_MATH_ASSERT
+//
+// Independent debug break implementation for OVR_Math.h.
+
+#if !defined(OVR_MATH_DEBUG_BREAK)
+#if defined(_DEBUG)
+#if defined(_MSC_VER)
+#define OVR_MATH_DEBUG_BREAK __debugbreak()
+#else
+#define OVR_MATH_DEBUG_BREAK __builtin_trap()
+#endif
+#else
+#define OVR_MATH_DEBUG_BREAK ((void)0)
+#endif
+#endif
+
+//-------------------------------------------------------------------------------------
+// ***** OVR_MATH_ASSERT
+//
+// Independent OVR_MATH_ASSERT implementation for OVR_Math.h.
+
+#if !defined(OVR_MATH_ASSERT)
+#if defined(_DEBUG)
+#define OVR_MATH_ASSERT(p) \
+ if (!(p)) { \
+ OVR_MATH_DEBUG_BREAK; \
+ }
+#else
+#define OVR_MATH_ASSERT(p) ((void)0)
+#endif
+#endif
+
+//-------------------------------------------------------------------------------------
+// ***** OVR_MATH_STATIC_ASSERT
+//
+// Independent OVR_MATH_ASSERT implementation for OVR_Math.h.
+
+#if !defined(OVR_MATH_STATIC_ASSERT)
+#if defined(__cplusplus) && \
+ ((defined(_MSC_VER) && (defined(_MSC_VER) >= 1600)) || defined(__GXX_EXPERIMENTAL_CXX0X__) || \
+ (__cplusplus >= 201103L))
+#define OVR_MATH_STATIC_ASSERT static_assert
+#else
+#if !defined(OVR_SA_UNUSED)
+#if defined(__GNUC__) || defined(__clang__)
+#define OVR_SA_UNUSED __attribute__((unused))
+#else
+#define OVR_SA_UNUSED
+#endif
+#define OVR_SA_PASTE(a, b) a##b
+#define OVR_SA_HELP(a, b) OVR_SA_PASTE(a, b)
+#endif
+
+#define OVR_MATH_STATIC_ASSERT(expression, msg) \
+ typedef char OVR_SA_HELP(compileTimeAssert, __LINE__)[((expression) != 0) ? 1 : -1] OVR_SA_UNUSED
+#endif
+#endif
+
+namespace OVR {
+
+template <class T>
+const T OVRMath_Min(const T a, const T b) {
+ return (a < b) ? a : b;
+}
+
+template <class T>
+const T OVRMath_Max(const T a, const T b) {
+ return (b < a) ? a : b;
+}
+
+template <class T>
+void OVRMath_Swap(T& a, T& b) {
+ T temp(a);
+ a = b;
+ b = temp;
+}
+
+//-------------------------------------------------------------------------------------
+// ***** Constants for 3D world/axis definitions.
+
+// Definitions of axes for coordinate and rotation conversions.
+enum Axis { Axis_X = 0, Axis_Y = 1, Axis_Z = 2 };
+
+// RotateDirection describes the rotation direction around an axis, interpreted as follows:
+// CW - Clockwise while looking "down" from positive axis towards the origin.
+// CCW - Counter-clockwise while looking from the positive axis towards the origin,
+// which is in the negative axis direction.
+// CCW is the default for the RHS coordinate system. Oculus standard RHS coordinate
+// system defines Y up, X right, and Z back (pointing out from the screen). In this
+// system Rotate_CCW around Z will specifies counter-clockwise rotation in XY plane.
+enum RotateDirection { Rotate_CCW = 1, Rotate_CW = -1 };
+
+// Constants for right handed and left handed coordinate systems
+enum HandedSystem { Handed_R = 1, Handed_L = -1 };
+
+// AxisDirection describes which way the coordinate axis points. Used by WorldAxes.
+enum AxisDirection {
+ Axis_Up = 2,
+ Axis_Down = -2,
+ Axis_Right = 1,
+ Axis_Left = -1,
+ Axis_In = 3,
+ Axis_Out = -3
+};
+
+struct WorldAxes {
+ AxisDirection XAxis, YAxis, ZAxis;
+
+ WorldAxes(AxisDirection x, AxisDirection y, AxisDirection z) : XAxis(x), YAxis(y), ZAxis(z) {
+ OVR_MATH_ASSERT(abs(x) != abs(y) && abs(y) != abs(z) && abs(z) != abs(x));
+ }
+};
+
+} // namespace OVR
+
+//------------------------------------------------------------------------------------//
+// ***** C Compatibility Types
+
+// These declarations are used to support conversion between C types used in
+// LibOVR C interfaces and their C++ versions. As an example, they allow passing
+// Vector3f into a function that expects ovrVector3f.
+
+typedef struct ovrQuatf_ ovrQuatf;
+typedef struct ovrQuatd_ ovrQuatd;
+typedef struct ovrSizei_ ovrSizei;
+typedef struct ovrSizef_ ovrSizef;
+typedef struct ovrSized_ ovrSized;
+typedef struct ovrRecti_ ovrRecti;
+typedef struct ovrVector2i_ ovrVector2i;
+typedef struct ovrVector2f_ ovrVector2f;
+typedef struct ovrVector2d_ ovrVector2d;
+typedef struct ovrVector3f_ ovrVector3f;
+typedef struct ovrVector3d_ ovrVector3d;
+typedef struct ovrVector4f_ ovrVector4f;
+typedef struct ovrVector4d_ ovrVector4d;
+typedef struct ovrMatrix2f_ ovrMatrix2f;
+typedef struct ovrMatrix2d_ ovrMatrix2d;
+typedef struct ovrMatrix3f_ ovrMatrix3f;
+typedef struct ovrMatrix3d_ ovrMatrix3d;
+typedef struct ovrMatrix4f_ ovrMatrix4f;
+typedef struct ovrMatrix4d_ ovrMatrix4d;
+typedef struct ovrPosef_ ovrPosef;
+typedef struct ovrPosed_ ovrPosed;
+typedef struct ovrPoseStatef_ ovrPoseStatef;
+typedef struct ovrPoseStated_ ovrPoseStated;
+typedef struct ovrFovPort_ ovrFovPort;
+
+namespace OVR {
+
+// Forward-declare our templates.
+template <class T>
+class Quat;
+template <class T>
+class Size;
+template <class T>
+class Rect;
+template <class T>
+class Vector2;
+template <class T>
+class Vector3;
+template <class T>
+class Vector4;
+template <class T>
+class Matrix2;
+template <class T>
+class Matrix3;
+template <class T>
+class Matrix4;
+template <class T>
+class Pose;
+template <class T>
+class PoseState;
+struct FovPort;
+
+// CompatibleTypes::Type is used to lookup a compatible C-version of a C++ class.
+template <class C>
+struct CompatibleTypes {
+ // Declaration here seems necessary for MSVC; specializations are
+ // used instead.
+ typedef struct {
+ } Type;
+};
+
+// Specializations providing CompatibleTypes::Type value.
+template <>
+struct CompatibleTypes<Quat<float>> {
+ typedef ovrQuatf Type;
+};
+template <>
+struct CompatibleTypes<Quat<double>> {
+ typedef ovrQuatd Type;
+};
+template <>
+struct CompatibleTypes<Matrix2<float>> {
+ typedef ovrMatrix2f Type;
+};
+template <>
+struct CompatibleTypes<Matrix2<double>> {
+ typedef ovrMatrix2d Type;
+};
+template <>
+struct CompatibleTypes<Matrix3<float>> {
+ typedef ovrMatrix3f Type;
+};
+template <>
+struct CompatibleTypes<Matrix3<double>> {
+ typedef ovrMatrix3d Type;
+};
+template <>
+struct CompatibleTypes<Matrix4<float>> {
+ typedef ovrMatrix4f Type;
+};
+template <>
+struct CompatibleTypes<Matrix4<double>> {
+ typedef ovrMatrix4d Type;
+};
+template <>
+struct CompatibleTypes<Size<int>> {
+ typedef ovrSizei Type;
+};
+template <>
+struct CompatibleTypes<Size<float>> {
+ typedef ovrSizef Type;
+};
+template <>
+struct CompatibleTypes<Size<double>> {
+ typedef ovrSized Type;
+};
+template <>
+struct CompatibleTypes<Rect<int>> {
+ typedef ovrRecti Type;
+};
+template <>
+struct CompatibleTypes<Vector2<int>> {
+ typedef ovrVector2i Type;
+};
+template <>
+struct CompatibleTypes<Vector2<float>> {
+ typedef ovrVector2f Type;
+};
+template <>
+struct CompatibleTypes<Vector2<double>> {
+ typedef ovrVector2d Type;
+};
+template <>
+struct CompatibleTypes<Vector3<float>> {
+ typedef ovrVector3f Type;
+};
+template <>
+struct CompatibleTypes<Vector3<double>> {
+ typedef ovrVector3d Type;
+};
+template <>
+struct CompatibleTypes<Vector4<float>> {
+ typedef ovrVector4f Type;
+};
+template <>
+struct CompatibleTypes<Vector4<double>> {
+ typedef ovrVector4d Type;
+};
+template <>
+struct CompatibleTypes<Pose<float>> {
+ typedef ovrPosef Type;
+};
+template <>
+struct CompatibleTypes<Pose<double>> {
+ typedef ovrPosed Type;
+};
+template <>
+struct CompatibleTypes<FovPort> {
+ typedef ovrFovPort Type;
+};
+
+//------------------------------------------------------------------------------------//
+// ***** Math
+//
+// Math class contains constants and functions. This class is a template specialized
+// per type, with Math<float> and Math<double> being distinct.
+template <class T>
+class Math {
+ public:
+ // By default, support explicit conversion to float. This allows Vector2<int> to
+ // compile, for example.
+ typedef float OtherFloatType;
+
+ static int Tolerance() {
+ return 0;
+ } // Default value so integer types compile
+};
+
+//------------------------------------------------------------------------------------//
+// ***** double constants
+#define MATH_DOUBLE_PI 3.14159265358979323846
+#define MATH_DOUBLE_TWOPI (2 * MATH_DOUBLE_PI)
+#define MATH_DOUBLE_PIOVER2 (0.5 * MATH_DOUBLE_PI)
+#define MATH_DOUBLE_PIOVER4 (0.25 * MATH_DOUBLE_PI)
+#define MATH_FLOAT_MAXVALUE (FLT_MAX)
+
+#define MATH_DOUBLE_RADTODEGREEFACTOR (360.0 / MATH_DOUBLE_TWOPI)
+#define MATH_DOUBLE_DEGREETORADFACTOR (MATH_DOUBLE_TWOPI / 360.0)
+
+#define MATH_DOUBLE_E 2.71828182845904523536
+#define MATH_DOUBLE_LOG2E 1.44269504088896340736
+#define MATH_DOUBLE_LOG10E 0.434294481903251827651
+#define MATH_DOUBLE_LN2 0.693147180559945309417
+#define MATH_DOUBLE_LN10 2.30258509299404568402
+
+#define MATH_DOUBLE_SQRT2 1.41421356237309504880
+#define MATH_DOUBLE_SQRT1_2 0.707106781186547524401
+
+#define MATH_DOUBLE_TOLERANCE \
+ 1e-12 // a default number for value equality tolerance: about 4500*Epsilon;
+#define MATH_DOUBLE_SINGULARITYRADIUS \
+ 1e-12 // about 1-cos(.0001 degree), for gimbal lock numerical problems
+
+#define MATH_DOUBLE_HUGENUMBER 1.3407807929942596e+154
+#define MATH_DOUBLE_SMALLESTNONDENORMAL 2.2250738585072014e-308
+
+//------------------------------------------------------------------------------------//
+// ***** float constants
+#define MATH_FLOAT_PI float(MATH_DOUBLE_PI)
+#define MATH_FLOAT_TWOPI float(MATH_DOUBLE_TWOPI)
+#define MATH_FLOAT_PIOVER2 float(MATH_DOUBLE_PIOVER2)
+#define MATH_FLOAT_PIOVER4 float(MATH_DOUBLE_PIOVER4)
+
+#define MATH_FLOAT_RADTODEGREEFACTOR float(MATH_DOUBLE_RADTODEGREEFACTOR)
+#define MATH_FLOAT_DEGREETORADFACTOR float(MATH_DOUBLE_DEGREETORADFACTOR)
+
+#define MATH_FLOAT_E float(MATH_DOUBLE_E)
+#define MATH_FLOAT_LOG2E float(MATH_DOUBLE_LOG2E)
+#define MATH_FLOAT_LOG10E float(MATH_DOUBLE_LOG10E)
+#define MATH_FLOAT_LN2 float(MATH_DOUBLE_LN2)
+#define MATH_FLOAT_LN10 float(MATH_DOUBLE_LN10)
+
+#define MATH_FLOAT_SQRT2 float(MATH_DOUBLE_SQRT2)
+#define MATH_FLOAT_SQRT1_2 float(MATH_DOUBLE_SQRT1_2)
+
+#define MATH_FLOAT_TOLERANCE \
+ 1e-5f // a default number for value equality tolerance: 1e-5, about 84*EPSILON;
+#define MATH_FLOAT_SINGULARITYRADIUS \
+ 1e-7f // about 1-cos(.025 degree), for gimbal lock numerical problems
+
+#define MATH_FLOAT_HUGENUMBER 1.8446742974197924e+019f
+#define MATH_FLOAT_SMALLESTNONDENORMAL 1.1754943508222875e-038f
+
+// Single-precision Math constants class.
+template <>
+class Math<float> {
+ public:
+ typedef double OtherFloatType;
+
+ static inline float MaxValue() {
+ return FLT_MAX;
+ };
+ static inline float Tolerance() {
+ return MATH_FLOAT_TOLERANCE;
+ }; // a default number for value equality tolerance
+ static inline float SingularityRadius() {
+ return MATH_FLOAT_SINGULARITYRADIUS;
+ }; // for gimbal lock numerical problems
+ static inline float HugeNumber() {
+ return MATH_FLOAT_HUGENUMBER;
+ }
+ static inline float SmallestNonDenormal() {
+ return MATH_FLOAT_SMALLESTNONDENORMAL;
+ }
+};
+
+// Double-precision Math constants class
+template <>
+class Math<double> {
+ public:
+ typedef float OtherFloatType;
+
+ static inline double Tolerance() {
+ return MATH_DOUBLE_TOLERANCE;
+ }; // a default number for value equality tolerance
+ static inline double SingularityRadius() {
+ return MATH_DOUBLE_SINGULARITYRADIUS;
+ }; // for gimbal lock numerical problems
+ static inline double HugeNumber() {
+ return MATH_DOUBLE_HUGENUMBER;
+ }
+ static inline double SmallestNonDenormal() {
+ return MATH_DOUBLE_SMALLESTNONDENORMAL;
+ }
+};
+
+typedef Math<float> Mathf;
+typedef Math<double> Mathd;
+
+// Conversion functions between degrees and radians
+// (non-templated to ensure passing int arguments causes warning)
+inline float RadToDegree(float rad) {
+ return rad * MATH_FLOAT_RADTODEGREEFACTOR;
+}
+inline double RadToDegree(double rad) {
+ return rad * MATH_DOUBLE_RADTODEGREEFACTOR;
+}
+
+inline float DegreeToRad(float deg) {
+ return deg * MATH_FLOAT_DEGREETORADFACTOR;
+}
+inline double DegreeToRad(double deg) {
+ return deg * MATH_DOUBLE_DEGREETORADFACTOR;
+}
+
+// Square function
+template <class T>
+inline T Sqr(T x) {
+ return x * x;
+}
+
+// MERGE_MOBILE_SDK
+// Safe reciprocal square root.
+template <class T>
+T RcpSqrt(const T f) {
+ return (f >= Math<T>::SmallestNonDenormal()) ? static_cast<T>(1.0 / sqrt(f))
+ : Math<T>::HugeNumber();
+}
+// MERGE_MOBILE_SDK
+
+// Sign: returns 0 if x == 0, -1 if x < 0, and 1 if x > 0
+template <class T>
+inline T Sign(T x) {
+ return (x != T(0)) ? (x < T(0) ? T(-1) : T(1)) : T(0);
+}
+
+// Numerically stable acos function
+inline float Acos(float x) {
+ return (x > 1.0f) ? 0.0f : (x < -1.0f) ? MATH_FLOAT_PI : acosf(x);
+}
+inline double Acos(double x) {
+ return (x > 1.0) ? 0.0 : (x < -1.0) ? MATH_DOUBLE_PI : acos(x);
+}
+
+// Numerically stable asin function
+inline float Asin(float x) {
+ return (x > 1.0f) ? MATH_FLOAT_PIOVER2 : (x < -1.0f) ? -MATH_FLOAT_PIOVER2 : asinf(x);
+}
+inline double Asin(double x) {
+ return (x > 1.0) ? MATH_DOUBLE_PIOVER2 : (x < -1.0) ? -MATH_DOUBLE_PIOVER2 : asin(x);
+}
+
+template <class T>
+class Quat;
+
+//-------------------------------------------------------------------------------------
+// ***** Vector2<>
+
+// Vector2f (Vector2d) represents a 2-dimensional vector or point in space,
+// consisting of coordinates x and y
+
+template <class T>
+class Vector2 {
+ public:
+ typedef T ElementType;
+ static const size_t ElementCount = 2;
+
+ T x, y;
+
+ Vector2() : x(0), y(0) {}
+ Vector2(T x_, T y_) : x(x_), y(y_) {}
+ explicit Vector2(T s) : x(s), y(s) {}
+ explicit Vector2(const Vector2<typename Math<T>::OtherFloatType>& src)
+ : x((T)src.x), y((T)src.y) {}
+
+ static Vector2 Zero() {
+ return Vector2(0, 0);
+ }
+
+ // C-interop support.
+ typedef typename CompatibleTypes<Vector2<T>>::Type CompatibleType;
+
+ Vector2(const CompatibleType& s) : x(s.x), y(s.y) {}
+
+ operator const CompatibleType&() const {
+ OVR_MATH_STATIC_ASSERT(
+ sizeof(Vector2<T>) == sizeof(CompatibleType), "sizeof(Vector2<T>) failure");
+ return reinterpret_cast<const CompatibleType&>(*this);
+ }
+
+ bool operator==(const Vector2& b) const {
+ return x == b.x && y == b.y;
+ }
+ bool operator!=(const Vector2& b) const {
+ return x != b.x || y != b.y;
+ }
+
+ Vector2 operator+(const Vector2& b) const {
+ return Vector2(x + b.x, y + b.y);
+ }
+ Vector2& operator+=(const Vector2& b) {
+ x += b.x;
+ y += b.y;
+ return *this;
+ }
+ Vector2 operator-(const Vector2& b) const {
+ return Vector2(x - b.x, y - b.y);
+ }
+ Vector2& operator-=(const Vector2& b) {
+ x -= b.x;
+ y -= b.y;
+ return *this;
+ }
+ Vector2 operator-() const {
+ return Vector2(-x, -y);
+ }
+
+ // Scalar multiplication/division scales vector.
+ Vector2 operator*(T s) const {
+ return Vector2(x * s, y * s);
+ }
+ Vector2& operator*=(T s) {
+ x *= s;
+ y *= s;
+ return *this;
+ }
+
+ Vector2 operator/(T s) const {
+ T rcp = T(1) / s;
+ return Vector2(x * rcp, y * rcp);
+ }
+ Vector2& operator/=(T s) {
+ T rcp = T(1) / s;
+ x *= rcp;
+ y *= rcp;
+ return *this;
+ }
+
+ static Vector2 Min(const Vector2& a, const Vector2& b) {
+ return Vector2((a.x < b.x) ? a.x : b.x, (a.y < b.y) ? a.y : b.y);
+ }
+ static Vector2 Max(const Vector2& a, const Vector2& b) {
+ return Vector2((a.x > b.x) ? a.x : b.x, (a.y > b.y) ? a.y : b.y);
+ }
+
+ Vector2 Clamped(T maxMag) const {
+ T magSquared = LengthSq();
+ if (magSquared <= Sqr(maxMag))
+ return *this;
+ else
+ return *this * (maxMag / sqrt(magSquared));
+ }
+
+ // Compare two vectors for equality with tolerance. Returns true if vectors match within
+ // tolerance.
+ bool IsEqual(const Vector2& b, T tolerance = Math<T>::Tolerance()) const {
+ return (fabs(b.x - x) <= tolerance) && (fabs(b.y - y) <= tolerance);
+ }
+ bool Compare(const Vector2& b, T tolerance = Math<T>::Tolerance()) const {
+ return IsEqual(b, tolerance);
+ }
+
+ // Access element by index
+ T& operator[](int idx) {
+ OVR_MATH_ASSERT(0 <= idx && idx < 2);
+ return *(&x + idx);
+ }
+ const T& operator[](int idx) const {
+ OVR_MATH_ASSERT(0 <= idx && idx < 2);
+ return *(&x + idx);
+ }
+
+ // Entry-wise product of two vectors
+ Vector2 EntrywiseMultiply(const Vector2& b) const {
+ return Vector2(x * b.x, y * b.y);
+ }
+
+ // Multiply and divide operators do entry-wise math. Used Dot() for dot product.
+ Vector2 operator*(const Vector2& b) const {
+ return Vector2(x * b.x, y * b.y);
+ }
+ Vector2 operator/(const Vector2& b) const {
+ return Vector2(x / b.x, y / b.y);
+ }
+
+ // Dot product
+ // Used to calculate angle q between two vectors among other things,
+ // as (A dot B) = |a||b|cos(q).
+ T Dot(const Vector2& b) const {
+ return x * b.x + y * b.y;
+ }
+
+ // Returns the angle from this vector to b, in radians.
+ T Angle(const Vector2& b) const {
+ T div = LengthSq() * b.LengthSq();
+ OVR_MATH_ASSERT(div != T(0));
+ T result = Acos((this->Dot(b)) / sqrt(div));
+ return result;
+ }
+
+ // Return Length of the vector squared.
+ T LengthSq() const {
+ return (x * x + y * y);
+ }
+
+ // Return vector length.
+ T Length() const {
+ return sqrt(LengthSq());
+ }
+
+ // Returns squared distance between two points represented by vectors.
+ T DistanceSq(const Vector2& b) const {
+ return (*this - b).LengthSq();
+ }
+
+ // Returns distance between two points represented by vectors.
+ T Distance(const Vector2& b) const {
+ return (*this - b).Length();
+ }
+
+ // Determine if this a unit vector.
+ bool IsNormalized() const {
+ return fabs(LengthSq() - T(1)) < Math<T>::Tolerance();
+ }
+
+ // Normalize, convention vector length to 1.
+ void Normalize() {
+ T s = Length();
+ if (s != T(0))
+ s = T(1) / s;
+ *this *= s;
+ }
+
+ // Returns normalized (unit) version of the vector without modifying itself.
+ Vector2 Normalized() const {
+ T s = Length();
+ if (s != T(0))
+ s = T(1) / s;
+ return *this * s;
+ }
+
+ // Linearly interpolates from this vector to another.
+ // Factor should be between 0.0 and 1.0, with 0 giving full value to this.
+ Vector2 Lerp(const Vector2& b, T f) const {
+ return *this * (T(1) - f) + b * f;
+ }
+
+ // Projects this vector onto the argument; in other words,
+ // A.Project(B) returns projection of vector A onto B.
+ Vector2 ProjectTo(const Vector2& b) const {
+ T l2 = b.LengthSq();
+ OVR_MATH_ASSERT(l2 != T(0));
+ return b * (Dot(b) / l2);
+ }
+
+ // returns true if vector b is clockwise from this vector
+ bool IsClockwise(const Vector2& b) const {
+ return (x * b.y - y * b.x) < 0;
+ }
+};
+
+typedef Vector2<float> Vector2f;
+typedef Vector2<double> Vector2d;
+typedef Vector2<int> Vector2i;
+
+typedef Vector2<float> Point2f;
+typedef Vector2<double> Point2d;
+typedef Vector2<int> Point2i;
+
+//-------------------------------------------------------------------------------------
+// ***** Vector3<> - 3D vector of {x, y, z}
+
+//
+// Vector3f (Vector3d) represents a 3-dimensional vector or point in space,
+// consisting of coordinates x, y and z.
+
+template <class T>
+class Vector3 {
+ public:
+ typedef T ElementType;
+ static const size_t ElementCount = 3;
+
+ T x, y, z;
+
+ // FIXME: default initialization of a vector class can be very expensive in a full-blown
+ // application. A few hundred thousand vector constructions is not unlikely and can add
+ // up to milliseconds of time on processors like the PS3 PPU.
+ Vector3() : x(0), y(0), z(0) {}
+ Vector3(T x_, T y_, T z_ = 0) : x(x_), y(y_), z(z_) {}
+ explicit Vector3(T s) : x(s), y(s), z(s) {}
+ explicit Vector3(const Vector3<typename Math<T>::OtherFloatType>& src)
+ : x((T)src.x), y((T)src.y), z((T)src.z) {}
+
+ static Vector3 Zero() {
+ return Vector3(0, 0, 0);
+ }
+
+ // C-interop support.
+ typedef typename CompatibleTypes<Vector3<T>>::Type CompatibleType;
+
+ Vector3(const CompatibleType& s) : x(s.x), y(s.y), z(s.z) {}
+
+ operator const CompatibleType&() const {
+ OVR_MATH_STATIC_ASSERT(
+ sizeof(Vector3<T>) == sizeof(CompatibleType), "sizeof(Vector3<T>) failure");
+ return reinterpret_cast<const CompatibleType&>(*this);
+ }
+
+ bool operator==(const Vector3& b) const {
+ return x == b.x && y == b.y && z == b.z;
+ }
+ bool operator!=(const Vector3& b) const {
+ return x != b.x || y != b.y || z != b.z;
+ }
+
+ Vector3 operator+(const Vector3& b) const {
+ return Vector3(x + b.x, y + b.y, z + b.z);
+ }
+ Vector3& operator+=(const Vector3& b) {
+ x += b.x;
+ y += b.y;
+ z += b.z;
+ return *this;
+ }
+ Vector3 operator-(const Vector3& b) const {
+ return Vector3(x - b.x, y - b.y, z - b.z);
+ }
+ Vector3& operator-=(const Vector3& b) {
+ x -= b.x;
+ y -= b.y;
+ z -= b.z;
+ return *this;
+ }
+ Vector3 operator-() const {
+ return Vector3(-x, -y, -z);
+ }
+
+ // Scalar multiplication/division scales vector.
+ Vector3 operator*(T s) const {
+ return Vector3(x * s, y * s, z * s);
+ }
+ Vector3& operator*=(T s) {
+ x *= s;
+ y *= s;
+ z *= s;
+ return *this;
+ }
+
+ Vector3 operator/(T s) const {
+ T rcp = T(1) / s;
+ return Vector3(x * rcp, y * rcp, z * rcp);
+ }
+ Vector3& operator/=(T s) {
+ T rcp = T(1) / s;
+ x *= rcp;
+ y *= rcp;
+ z *= rcp;
+ return *this;
+ }
+
+ static Vector3 Min(const Vector3& a, const Vector3& b) {
+ return Vector3((a.x < b.x) ? a.x : b.x, (a.y < b.y) ? a.y : b.y, (a.z < b.z) ? a.z : b.z);
+ }
+ static Vector3 Max(const Vector3& a, const Vector3& b) {
+ return Vector3((a.x > b.x) ? a.x : b.x, (a.y > b.y) ? a.y : b.y, (a.z > b.z) ? a.z : b.z);
+ }
+
+ Vector3 Clamped(T maxMag) const {
+ T magSquared = LengthSq();
+ if (magSquared <= Sqr(maxMag))
+ return *this;
+ else
+ return *this * (maxMag / sqrt(magSquared));
+ }
+
+ // Compare two vectors for equality with tolerance. Returns true if vectors match within
+ // tolerance.
+ bool IsEqual(const Vector3& b, T tolerance = Math<T>::Tolerance()) const {
+ return (fabs(b.x - x) <= tolerance) && (fabs(b.y - y) <= tolerance) &&
+ (fabs(b.z - z) <= tolerance);
+ }
+ bool Compare(const Vector3& b, T tolerance = Math<T>::Tolerance()) const {
+ return IsEqual(b, tolerance);
+ }
+
+ T& operator[](int idx) {
+ OVR_MATH_ASSERT(0 <= idx && idx < 3);
+ return *(&x + idx);
+ }
+
+ const T& operator[](int idx) const {
+ OVR_MATH_ASSERT(0 <= idx && idx < 3);
+ return *(&x + idx);
+ }
+
+ // Entrywise product of two vectors
+ Vector3 EntrywiseMultiply(const Vector3& b) const {
+ return Vector3(x * b.x, y * b.y, z * b.z);
+ }
+
+ // Multiply and divide operators do entry-wise math
+ Vector3 operator*(const Vector3& b) const {
+ return Vector3(x * b.x, y * b.y, z * b.z);
+ }
+
+ Vector3 operator/(const Vector3& b) const {
+ return Vector3(x / b.x, y / b.y, z / b.z);
+ }
+
+ // Dot product
+ // Used to calculate angle q between two vectors among other things,
+ // as (A dot B) = |a||b|cos(q).
+ T Dot(const Vector3& b) const {
+ return x * b.x + y * b.y + z * b.z;
+ }
+
+ // Compute cross product, which generates a normal vector.
+ // Direction vector can be determined by right-hand rule: Pointing index finder in
+ // direction a and middle finger in direction b, thumb will point in a.Cross(b).
+ Vector3 Cross(const Vector3& b) const {
+ return Vector3(y * b.z - z * b.y, z * b.x - x * b.z, x * b.y - y * b.x);
+ }
+
+ // Returns the angle from this vector to b, in radians.
+ T Angle(const Vector3& b) const {
+ T div = LengthSq() * b.LengthSq();
+ OVR_MATH_ASSERT(div != T(0));
+ T result = Acos((this->Dot(b)) / sqrt(div));
+ return result;
+ }
+
+ // Return Length of the vector squared.
+ T LengthSq() const {
+ return (x * x + y * y + z * z);
+ }
+
+ // Return vector length.
+ T Length() const {
+ return (T)sqrt(LengthSq());
+ }
+
+ // Returns squared distance between two points represented by vectors.
+ T DistanceSq(Vector3 const& b) const {
+ return (*this - b).LengthSq();
+ }
+
+ // Returns distance between two points represented by vectors.
+ T Distance(Vector3 const& b) const {
+ return (*this - b).Length();
+ }
+
+ bool IsNormalized() const {
+ return fabs(LengthSq() - T(1)) < Math<T>::Tolerance();
+ }
+
+ // Normalize, convention vector length to 1.
+ void Normalize() {
+ T s = Length();
+ if (s != T(0))
+ s = T(1) / s;
+ *this *= s;
+ }
+
+ // Returns normalized (unit) version of the vector without modifying itself.
+ Vector3 Normalized() const {
+ T s = Length();
+ if (s != T(0))
+ s = T(1) / s;
+ return *this * s;
+ }
+
+ // Linearly interpolates from this vector to another.
+ // Factor should be between 0.0 and 1.0, with 0 giving full value to this.
+ Vector3 Lerp(const Vector3& b, T f) const {
+ return *this * (T(1) - f) + b * f;
+ }
+
+ // Projects this vector onto the argument; in other words,
+ // A.Project(B) returns projection of vector A onto B.
+ Vector3 ProjectTo(const Vector3& b) const {
+ T l2 = b.LengthSq();
+ OVR_MATH_ASSERT(l2 != T(0));
+ return b * (Dot(b) / l2);
+ }
+
+ // Projects this vector onto a plane defined by a normal vector
+ Vector3 ProjectToPlane(const Vector3& normal) const {
+ return *this - this->ProjectTo(normal);
+ }
+
+ bool IsNan() const {
+ return !isfinite(x + y + z);
+ }
+ bool IsFinite() const {
+ return isfinite(x + y + z);
+ }
+};
+
+typedef Vector3<float> Vector3f;
+typedef Vector3<double> Vector3d;
+typedef Vector3<int32_t> Vector3i;
+
+OVR_MATH_STATIC_ASSERT((sizeof(Vector3f) == 3 * sizeof(float)), "sizeof(Vector3f) failure");
+OVR_MATH_STATIC_ASSERT((sizeof(Vector3d) == 3 * sizeof(double)), "sizeof(Vector3d) failure");
+OVR_MATH_STATIC_ASSERT((sizeof(Vector3i) == 3 * sizeof(int32_t)), "sizeof(Vector3i) failure");
+
+typedef Vector3<float> Point3f;
+typedef Vector3<double> Point3d;
+typedef Vector3<int32_t> Point3i;
+
+//-------------------------------------------------------------------------------------
+// ***** Vector4<> - 4D vector of {x, y, z, w}
+
+//
+// Vector4f (Vector4d) represents a 3-dimensional vector or point in space,
+// consisting of coordinates x, y, z and w.
+
+template <class T>
+class Vector4 {
+ public:
+ typedef T ElementType;
+ static const size_t ElementCount = 4;
+
+ T x, y, z, w;
+
+ // FIXME: default initialization of a vector class can be very expensive in a full-blown
+ // application. A few hundred thousand vector constructions is not unlikely and can add
+ // up to milliseconds of time on processors like the PS3 PPU.
+ Vector4() : x(0), y(0), z(0), w(0) {}
+ Vector4(T x_, T y_, T z_, T w_) : x(x_), y(y_), z(z_), w(w_) {}
+ explicit Vector4(T s) : x(s), y(s), z(s), w(s) {}
+ explicit Vector4(const Vector3<T>& v, const T w_ = T(1)) : x(v.x), y(v.y), z(v.z), w(w_) {}
+ explicit Vector4(const Vector4<typename Math<T>::OtherFloatType>& src)
+ : x((T)src.x), y((T)src.y), z((T)src.z), w((T)src.w) {}
+
+ static Vector4 Zero() {
+ return Vector4(0, 0, 0, 0);
+ }
+
+ // C-interop support.
+ typedef typename CompatibleTypes<Vector4<T>>::Type CompatibleType;
+
+ Vector4(const CompatibleType& s) : x(s.x), y(s.y), z(s.z), w(s.w) {}
+
+ operator const CompatibleType&() const {
+ OVR_MATH_STATIC_ASSERT(
+ sizeof(Vector4<T>) == sizeof(CompatibleType), "sizeof(Vector4<T>) failure");
+ return reinterpret_cast<const CompatibleType&>(*this);
+ }
+
+ Vector4& operator=(const Vector3<T>& other) {
+ x = other.x;
+ y = other.y;
+ z = other.z;
+ w = 1;
+ return *this;
+ }
+ bool operator==(const Vector4& b) const {
+ return x == b.x && y == b.y && z == b.z && w == b.w;
+ }
+ bool operator!=(const Vector4& b) const {
+ return x != b.x || y != b.y || z != b.z || w != b.w;
+ }
+
+ Vector4 operator+(const Vector4& b) const {
+ return Vector4(x + b.x, y + b.y, z + b.z, w + b.w);
+ }
+ Vector4& operator+=(const Vector4& b) {
+ x += b.x;
+ y += b.y;
+ z += b.z;
+ w += b.w;
+ return *this;
+ }
+ Vector4 operator-(const Vector4& b) const {
+ return Vector4(x - b.x, y - b.y, z - b.z, w - b.w);
+ }
+ Vector4& operator-=(const Vector4& b) {
+ x -= b.x;
+ y -= b.y;
+ z -= b.z;
+ w -= b.w;
+ return *this;
+ }
+ Vector4 operator-() const {
+ return Vector4(-x, -y, -z, -w);
+ }
+
+ // Scalar multiplication/division scales vector.
+ Vector4 operator*(T s) const {
+ return Vector4(x * s, y * s, z * s, w * s);
+ }
+ Vector4& operator*=(T s) {
+ x *= s;
+ y *= s;
+ z *= s;
+ w *= s;
+ return *this;
+ }
+
+ Vector4 operator/(T s) const {
+ T rcp = T(1) / s;
+ return Vector4(x * rcp, y * rcp, z * rcp, w * rcp);
+ }
+ Vector4& operator/=(T s) {
+ T rcp = T(1) / s;
+ x *= rcp;
+ y *= rcp;
+ z *= rcp;
+ w *= rcp;
+ return *this;
+ }
+
+ static Vector4 Min(const Vector4& a, const Vector4& b) {
+ return Vector4(
+ (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);
+ }
+ static Vector4 Max(const Vector4& a, const Vector4& b) {
+ return Vector4(
+ (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);
+ }
+
+ Vector4 Clamped(T maxMag) const {
+ T magSquared = LengthSq();
+ if (magSquared <= Sqr(maxMag))
+ return *this;
+ else
+ return *this * (maxMag / sqrt(magSquared));
+ }
+
+ // Compare two vectors for equality with tolerance. Returns true if vectors match within
+ // tolerance.
+ bool IsEqual(const Vector4& b, T tolerance = Math<T>::Tolerance()) const {
+ return (fabs(b.x - x) <= tolerance) && (fabs(b.y - y) <= tolerance) &&
+ (fabs(b.z - z) <= tolerance) && (fabs(b.w - w) <= tolerance);
+ }
+ bool Compare(const Vector4& b, T tolerance = Math<T>::Tolerance()) const {
+ return IsEqual(b, tolerance);
+ }
+
+ T& operator[](int idx) {
+ OVR_MATH_ASSERT(0 <= idx && idx < 4);
+ return *(&x + idx);
+ }
+
+ const T& operator[](int idx) const {
+ OVR_MATH_ASSERT(0 <= idx && idx < 4);
+ return *(&x + idx);
+ }
+
+ // Entry wise product of two vectors
+ Vector4 EntrywiseMultiply(const Vector4& b) const {
+ return Vector4(x * b.x, y * b.y, z * b.z, w * b.w);
+ }
+
+ // Multiply and divide operators do entry-wise math
+ Vector4 operator*(const Vector4& b) const {
+ return Vector4(x * b.x, y * b.y, z * b.z, w * b.w);
+ }
+
+ Vector4 operator/(const Vector4& b) const {
+ return Vector4(x / b.x, y / b.y, z / b.z, w / b.w);
+ }
+
+ // Dot product
+ T Dot(const Vector4& b) const {
+ return x * b.x + y * b.y + z * b.z + w * b.w;
+ }
+
+ // Return Length of the vector squared.
+ T LengthSq() const {
+ return (x * x + y * y + z * z + w * w);
+ }
+
+ // Return vector length.
+ T Length() const {
+ return sqrt(LengthSq());
+ }
+
+ bool IsNormalized() const {
+ return fabs(LengthSq() - T(1)) < Math<T>::Tolerance();
+ }
+
+ // Normalize, convention vector length to 1.
+ void Normalize() {
+ T s = Length();
+ if (s != T(0))
+ s = T(1) / s;
+ *this *= s;
+ }
+
+ // Returns normalized (unit) version of the vector without modifying itself.
+ Vector4 Normalized() const {
+ T s = Length();
+ if (s != T(0))
+ s = T(1) / s;
+ return *this * s;
+ }
+
+ // Linearly interpolates from this vector to another.
+ // Factor should be between 0.0 and 1.0, with 0 giving full value to this.
+ Vector4 Lerp(const Vector4& b, T f) const {
+ return *this * (T(1) - f) + b * f;
+ }
+};
+
+typedef Vector4<float> Vector4f;
+typedef Vector4<double> Vector4d;
+typedef Vector4<int> Vector4i;
+
+//-------------------------------------------------------------------------------------
+// ***** Bounds3
+
+// Bounds class used to describe a 3D axis aligned bounding box.
+
+template <class T>
+class Bounds3 {
+ public:
+ Vector3<T> b[2];
+
+ Bounds3() {
+ Clear();
+ }
+
+ Bounds3(const Vector3<T>& mins, const Vector3<T>& maxs) {
+ b[0] = mins;
+ b[1] = maxs;
+ }
+
+ void Clear() {
+ b[0].x = b[0].y = b[0].z = Math<T>::MaxValue();
+ b[1].x = b[1].y = b[1].z = -Math<T>::MaxValue();
+ }
+
+ void AddPoint(const Vector3<T>& v) {
+ b[0].x = (b[0].x < v.x ? b[0].x : v.x);
+ b[0].y = (b[0].y < v.y ? b[0].y : v.y);
+ b[0].z = (b[0].z < v.z ? b[0].z : v.z);
+ b[1].x = (v.x < b[1].x ? b[1].x : v.x);
+ b[1].y = (v.y < b[1].y ? b[1].y : v.y);
+ b[1].z = (v.z < b[1].z ? b[1].z : v.z);
+ }
+
+ bool Excludes(const Vector3<T>& v) const {
+ bool testing = false;
+ for (int32_t t = 0; t < 3; ++t) {
+ testing |= v[t] > b[1][t];
+ testing |= v[t] < b[0][t];
+ }
+ return testing;
+ }
+
+ // exludes, ignoring vertical
+ bool ExcludesXZ(const Vector3<T>& v) const {
+ bool testing = false;
+ testing |= v[0] > b[1][0];
+ testing |= v[0] < b[0][0];
+ testing |= v[2] > b[1][2];
+ testing |= v[2] < b[0][2];
+ return testing;
+ }
+
+ bool Excludes(const Bounds3<T>& bounds) const {
+ bool testing = false;
+ for (int32_t t = 0; t < 3; ++t) {
+ testing |= bounds.b[0][t] > b[1][t];
+ testing |= bounds.b[1][t] < b[0][t];
+ }
+ return testing;
+ }
+
+ const Vector3<T>& GetMins() const {
+ return b[0];
+ }
+ const Vector3<T>& GetMaxs() const {
+ return b[1];
+ }
+
+ Vector3<T>& GetMins() {
+ return b[0];
+ }
+ Vector3<T>& GetMaxs() {
+ return b[1];
+ }
+};
+
+typedef Bounds3<float> Bounds3f;
+typedef Bounds3<double> Bounds3d;
+
+//-------------------------------------------------------------------------------------
+// ***** Size
+
+// Size class represents 2D size with Width, Height components.
+// Used to describe distentions of render targets, etc.
+
+template <class T>
+class Size {
+ public:
+ T w, h;
+
+ Size() : w(0), h(0) {}
+ Size(T w_, T h_) : w(w_), h(h_) {}
+ explicit Size(T s) : w(s), h(s) {}
+ explicit Size(const Size<typename Math<T>::OtherFloatType>& src) : w((T)src.w), h((T)src.h) {}
+
+ // C-interop support.
+ typedef typename CompatibleTypes<Size<T>>::Type CompatibleType;
+
+ Size(const CompatibleType& s) : w(s.w), h(s.h) {}
+
+ operator const CompatibleType&() const {
+ OVR_MATH_STATIC_ASSERT(sizeof(Size<T>) == sizeof(CompatibleType), "sizeof(Size<T>) failure");
+ return reinterpret_cast<const CompatibleType&>(*this);
+ }
+
+ bool operator==(const Size& b) const {
+ return w == b.w && h == b.h;
+ }
+ bool operator!=(const Size& b) const {
+ return w != b.w || h != b.h;
+ }
+
+ Size operator+(const Size& b) const {
+ return Size(w + b.w, h + b.h);
+ }
+ Size& operator+=(const Size& b) {
+ w += b.w;
+ h += b.h;
+ return *this;
+ }
+ Size operator-(const Size& b) const {
+ return Size(w - b.w, h - b.h);
+ }
+ Size& operator-=(const Size& b) {
+ w -= b.w;
+ h -= b.h;
+ return *this;
+ }
+ Size operator-() const {
+ return Size(-w, -h);
+ }
+ Size operator*(const Size& b) const {
+ return Size(w * b.w, h * b.h);
+ }
+ Size& operator*=(const Size& b) {
+ w *= b.w;
+ h *= b.h;
+ return *this;
+ }
+ Size operator/(const Size& b) const {
+ return Size(w / b.w, h / b.h);
+ }
+ Size& operator/=(const Size& b) {
+ w /= b.w;
+ h /= b.h;
+ return *this;
+ }
+
+ // Scalar multiplication/division scales both components.
+ Size operator*(T s) const {
+ return Size(w * s, h * s);
+ }
+ Size& operator*=(T s) {
+ w *= s;
+ h *= s;
+ return *this;
+ }
+ Size operator/(T s) const {
+ return Size(w / s, h / s);
+ }
+ Size& operator/=(T s) {
+ w /= s;
+ h /= s;
+ return *this;
+ }
+
+ static Size Min(const Size& a, const Size& b) {
+ return Size((a.w < b.w) ? a.w : b.w, (a.h < b.h) ? a.h : b.h);
+ }
+ static Size Max(const Size& a, const Size& b) {
+ return Size((a.w > b.w) ? a.w : b.w, (a.h > b.h) ? a.h : b.h);
+ }
+
+ T Area() const {
+ return w * h;
+ }
+
+ inline Vector2<T> ToVector() const {
+ return Vector2<T>(w, h);
+ }
+};
+
+typedef Size<int> Sizei;
+typedef Size<unsigned> Sizeu;
+typedef Size<float> Sizef;
+typedef Size<double> Sized;
+
+//-------------------------------------------------------------------------------------
+// ***** Size3
+
+// Size3 class represents 3D size with Width, Height, Depth components.
+// Used to describe distentions of render targets, etc.
+
+template <class T>
+class Size3 {
+ public:
+ T w, h, d;
+
+ Size3() : w(0), h(0), d(0) {}
+ Size3(T w_, T h_, T d_) : w(w_), h(h_), d(d_) {}
+ explicit Size3(T s) : w(s), h(s), d(s) {}
+ explicit Size3(const Size<typename Math<T>::OtherFloatType>& src)
+ : w((T)src.w), h((T)src.h), d((T)1) {}
+ explicit Size3(const Size3<typename Math<T>::OtherFloatType>& src)
+ : w((T)src.w), h((T)src.h), d((T)src.d) {}
+
+ // C-interop support.
+ typedef typename CompatibleTypes<Size3<T>>::Type CompatibleType;
+
+ Size3(const CompatibleType& s) : w(s.w), h(s.h), d(s.d) {}
+
+ operator const CompatibleType&() const {
+ OVR_MATH_STATIC_ASSERT(sizeof(Size3<T>) == sizeof(CompatibleType), "sizeof(Size3<T>) failure");
+ return reinterpret_cast<const CompatibleType&>(*this);
+ }
+
+ bool operator==(const Size3& b) const {
+ return w == b.w && h == b.h && d == b.d;
+ }
+ bool operator!=(const Size3& b) const {
+ return w != b.w || h != b.h || d != b.d;
+ }
+
+ Size3 operator+(const Size3& b) const {
+ return Size3(w + b.w, h + b.h, d + b.d);
+ }
+ Size3& operator+=(const Size3& b) {
+ w += b.w;
+ h += b.h;
+ d += b.d;
+ return *this;
+ }
+ Size3 operator-(const Size3& b) const {
+ return Size3(w - b.w, h - b.h, d - b.d);
+ }
+ Size3& operator-=(const Size3& b) {
+ w -= b.w;
+ h -= b.h;
+ d -= b.d;
+ return *this;
+ }
+ Size3 operator-() const {
+ return Size3(-w, -h, -d);
+ }
+ Size3 operator*(const Size3& b) const {
+ return Size3(w * b.w, h * b.h, d * b.d);
+ }
+ Size3& operator*=(const Size3& b) {
+ w *= b.w;
+ h *= b.h;
+ d *= b.d;
+ return *this;
+ }
+ Size3 operator/(const Size3& b) const {
+ return Size3(w / b.w, h / b.h, d / b.d);
+ }
+ Size3& operator/=(const Size3& b) {
+ w /= b.w;
+ h /= b.h;
+ d /= b.d;
+ return *this;
+ }
+
+ // Scalar multiplication/division scales both components.
+ Size3 operator*(T s) const {
+ return Size3(w * s, h * s, d * s);
+ }
+ Size3& operator*=(T s) {
+ w *= s;
+ h *= s;
+ d *= s;
+ return *this;
+ }
+ Size3 operator/(T s) const {
+ return Size3(w / s, h / s, d / s);
+ }
+ Size3& operator/=(T s) {
+ w /= s;
+ h /= s;
+ d /= s;
+ return *this;
+ }
+
+ static Size3 Min(const Size3& a, const Size3& b) {
+ return Size3((a.w < b.w) ? a.w : b.w, (a.h < b.h) ? a.h : b.h, (a.d < b.d) ? a.d : b.d);
+ }
+ static Size3 Max(const Size3& a, const Size3& b) {
+ return Size3((a.w > b.w) ? a.w : b.w, (a.h > b.h) ? a.h : b.h, (a.d > b.d) ? a.d : b.d);
+ }
+
+ T Volume() const {
+ return w * h * d;
+ }
+
+ inline Vector3<T> ToVector() const {
+ return Vector3<T>(w, h, d);
+ }
+};
+
+typedef Size3<unsigned> Size3u;
+
+//-----------------------------------------------------------------------------------
+// ***** Rect
+
+// Rect describes a rectangular area for rendering, that includes position and size.
+template <class T>
+class Rect {
+ public:
+ T x, y;
+ T w, h;
+
+ Rect() {}
+ Rect(T x1, T y1, T w1, T h1) : x(x1), y(y1), w(w1), h(h1) {}
+ Rect(const Vector2<T>& pos, const Size<T>& sz) : x(pos.x), y(pos.y), w(sz.w), h(sz.h) {}
+ Rect(const Size<T>& sz) : x(0), y(0), w(sz.w), h(sz.h) {}
+
+ // C-interop support.
+ typedef typename CompatibleTypes<Rect<T>>::Type CompatibleType;
+
+ Rect(const CompatibleType& s) : x(s.Pos.x), y(s.Pos.y), w(s.Size.w), h(s.Size.h) {}
+
+ operator const CompatibleType&() const {
+ OVR_MATH_STATIC_ASSERT(sizeof(Rect<T>) == sizeof(CompatibleType), "sizeof(Rect<T>) failure");
+ return reinterpret_cast<const CompatibleType&>(*this);
+ }
+
+ Vector2<T> GetPos() const {
+ return Vector2<T>(x, y);
+ }
+ Size<T> GetSize() const {
+ return Size<T>(w, h);
+ }
+ void SetPos(const Vector2<T>& pos) {
+ x = pos.x;
+ y = pos.y;
+ }
+ void SetSize(const Size<T>& sz) {
+ w = sz.w;
+ h = sz.h;
+ }
+
+ bool operator==(const Rect& vp) const {
+ return (x == vp.x) && (y == vp.y) && (w == vp.w) && (h == vp.h);
+ }
+ bool operator!=(const Rect& vp) const {
+ return !operator==(vp);
+ }
+};
+
+typedef Rect<int> Recti;
+
+//-------------------------------------------------------------------------------------//
+// ***** Quat
+//
+// Quatf represents a quaternion class used for rotations.
+//
+// Quaternion multiplications are done in right-to-left order, to match the
+// behavior of matrices.
+
+template <class T>
+class Quat {
+ public:
+ typedef T ElementType;
+ static const size_t ElementCount = 4;
+
+ // x,y,z = axis*sin(angle), w = cos(angle)
+ T x, y, z, w;
+
+ Quat() : x(0), y(0), z(0), w(1) {}
+ Quat(T x_, T y_, T z_, T w_) : x(x_), y(y_), z(z_), w(w_) {}
+ explicit Quat(const Quat<typename Math<T>::OtherFloatType>& src)
+ : x((T)src.x), y((T)src.y), z((T)src.z), w((T)src.w) {
+ // NOTE: Converting a normalized Quat<float> to Quat<double>
+ // will generally result in an un-normalized quaternion.
+ // But we don't normalize here in case the quaternion
+ // being converted is not a normalized rotation quaternion.
+ }
+
+ typedef typename CompatibleTypes<Quat<T>>::Type CompatibleType;
+
+ // C-interop support.
+ Quat(const CompatibleType& s) : x(s.x), y(s.y), z(s.z), w(s.w) {}
+
+ operator CompatibleType() const {
+ CompatibleType result;
+ result.x = x;
+ result.y = y;
+ result.z = z;
+ result.w = w;
+ return result;
+ }
+
+ // Constructs quaternion for rotation around the axis by an angle.
+ Quat(const Vector3<T>& axis, T angle) {
+ // Make sure we don't divide by zero.
+ if (axis.LengthSq() == T(0)) {
+ // Assert if the axis is zero, but the angle isn't
+ OVR_MATH_ASSERT(angle == T(0));
+ x = y = z = T(0);
+ w = T(1);
+ return;
+ }
+
+ Vector3<T> unitAxis = axis.Normalized();
+ T sinHalfAngle = sin(angle * T(0.5));
+
+ w = cos(angle * T(0.5));
+ x = unitAxis.x * sinHalfAngle;
+ y = unitAxis.y * sinHalfAngle;
+ z = unitAxis.z * sinHalfAngle;
+ }
+
+ // Constructs quaternion for rotation around one of the coordinate axis by an angle.
+ Quat(Axis A, T angle, RotateDirection d = Rotate_CCW, HandedSystem s = Handed_R) {
+ T sinHalfAngle = s * d * sin(angle * T(0.5));
+ T v[3];
+ v[0] = v[1] = v[2] = T(0);
+ v[A] = sinHalfAngle;
+
+ w = cos(angle * T(0.5));
+ x = v[0];
+ y = v[1];
+ z = v[2];
+ }
+
+ Quat operator-() {
+ return Quat(-x, -y, -z, -w);
+ } // unary minus
+
+ static Quat Identity() {
+ return Quat(0, 0, 0, 1);
+ }
+
+ // Compute axis and angle from quaternion
+ void GetAxisAngle(Vector3<T>* axis, T* angle) const {
+ if (x * x + y * y + z * z > Math<T>::Tolerance() * Math<T>::Tolerance()) {
+ *axis = Vector3<T>(x, y, z).Normalized();
+ *angle = 2 * Acos(w);
+ if (*angle > ((T)MATH_DOUBLE_PI)) // Reduce the magnitude of the angle, if necessary
+ {
+ *angle = ((T)MATH_DOUBLE_TWOPI) - *angle;
+ *axis = *axis * (-1);
+ }
+ } else {
+ *axis = Vector3<T>(1, 0, 0);
+ *angle = T(0);
+ }
+ }
+
+ // Convert a quaternion to a rotation vector, also known as
+ // Rodrigues vector, AxisAngle vector, SORA vector, exponential map.
+ // A rotation vector describes a rotation about an axis:
+ // the axis of rotation is the vector normalized,
+ // the angle of rotation is the magnitude of the vector.
+ Vector3<T> ToRotationVector() const {
+ // OVR_MATH_ASSERT(IsNormalized()); // If this fires, caller has a quat math bug
+ T s = T(0);
+ T sinHalfAngle = sqrt(x * x + y * y + z * z);
+ if (sinHalfAngle > T(0)) {
+ T cosHalfAngle = w;
+ T halfAngle = atan2(sinHalfAngle, cosHalfAngle);
+
+ // Ensure minimum rotation magnitude
+ if (cosHalfAngle < 0)
+ halfAngle -= T(MATH_DOUBLE_PI);
+
+ s = T(2) * halfAngle / sinHalfAngle;
+ }
+ return Vector3<T>(x * s, y * s, z * s);
+ }
+
+ // Faster version of the above, optimized for use with small rotations, where rotation angle ~=
+ // sin(angle)
+ inline OVR::Vector3<T> FastToRotationVector() const {
+ OVR_MATH_ASSERT(IsNormalized()); // If this fires, caller has a quat math bug
+ T s;
+ T sinHalfSquared = x * x + y * y + z * z;
+ if (sinHalfSquared < T(.0037)) // =~ sin(7/2 degrees)^2
+ {
+ // Max rotation magnitude error is about .062% at 7 degrees rotation, or about .0043 degrees
+ s = T(2) * Sign(w);
+ } else {
+ T sinHalfAngle = sqrt(sinHalfSquared);
+ T cosHalfAngle = w;
+ T halfAngle = atan2(sinHalfAngle, cosHalfAngle);
+
+ // Ensure minimum rotation magnitude
+ if (cosHalfAngle < 0)
+ halfAngle -= T(MATH_DOUBLE_PI);
+
+ s = T(2) * halfAngle / sinHalfAngle;
+ }
+ return Vector3<T>(x * s, y * s, z * s);
+ }
+
+ // Given a rotation vector of form unitRotationAxis * angle,
+ // returns the equivalent quaternion (unitRotationAxis * sin(angle), cos(Angle)).
+ static Quat FromRotationVector(const Vector3<T>& v) {
+ T angleSquared = v.LengthSq();
+ T s = T(0);
+ T c = T(1);
+ if (angleSquared > T(0)) {
+ T angle = sqrt(angleSquared);
+ s = sin(angle * T(0.5)) / angle; // normalize
+ c = cos(angle * T(0.5));
+ }
+ return Quat(s * v.x, s * v.y, s * v.z, c);
+ }
+
+ // Faster version of above, optimized for use with small rotation magnitudes, where rotation angle
+ // =~ sin(angle).
+ // If normalize is false, small-angle quaternions are returned un-normalized.
+ inline static Quat FastFromRotationVector(const OVR::Vector3<T>& v, bool normalize = true) {
+ T s, c;
+ T angleSquared = v.LengthSq();
+ if (angleSquared < T(0.0076)) // =~ (5 degrees*pi/180)^2
+ {
+ s = T(0.5);
+ c = T(1.0);
+ // Max rotation magnitude error (after normalization) is about .064% at 5 degrees rotation, or
+ // .0032 degrees
+ if (normalize && angleSquared > 0) {
+ // sin(angle/2)^2 ~= (angle/2)^2 and cos(angle/2)^2 ~= 1
+ T invLen = T(1) / sqrt(angleSquared * T(0.25) + T(1)); // normalize
+ s = s * invLen;
+ c = c * invLen;
+ }
+ } else {
+ T angle = sqrt(angleSquared);
+ s = sin(angle * T(0.5)) / angle;
+ c = cos(angle * T(0.5));
+ }
+ return Quat(s * v.x, s * v.y, s * v.z, c);
+ }
+
+ // Constructs the quaternion from a rotation matrix
+ explicit Quat(const Matrix4<T>& m) {
+ T trace = m.M[0][0] + m.M[1][1] + m.M[2][2];
+
+ // In almost all cases, the first part is executed.
+ // However, if the trace is not positive, the other
+ // cases arise.
+ if (trace > T(0)) {
+ T s = sqrt(trace + T(1)) * T(2); // s=4*qw
+ w = T(0.25) * s;
+ x = (m.M[2][1] - m.M[1][2]) / s;
+ y = (m.M[0][2] - m.M[2][0]) / s;
+ z = (m.M[1][0] - m.M[0][1]) / s;
+ } else if ((m.M[0][0] > m.M[1][1]) && (m.M[0][0] > m.M[2][2])) {
+ T s = sqrt(T(1) + m.M[0][0] - m.M[1][1] - m.M[2][2]) * T(2);
+ w = (m.M[2][1] - m.M[1][2]) / s;
+ x = T(0.25) * s;
+ y = (m.M[0][1] + m.M[1][0]) / s;
+ z = (m.M[2][0] + m.M[0][2]) / s;
+ } else if (m.M[1][1] > m.M[2][2]) {
+ T s = sqrt(T(1) + m.M[1][1] - m.M[0][0] - m.M[2][2]) * T(2); // S=4*qy
+ w = (m.M[0][2] - m.M[2][0]) / s;
+ x = (m.M[0][1] + m.M[1][0]) / s;
+ y = T(0.25) * s;
+ z = (m.M[1][2] + m.M[2][1]) / s;
+ } else {
+ T s = sqrt(T(1) + m.M[2][2] - m.M[0][0] - m.M[1][1]) * T(2); // S=4*qz
+ w = (m.M[1][0] - m.M[0][1]) / s;
+ x = (m.M[0][2] + m.M[2][0]) / s;
+ y = (m.M[1][2] + m.M[2][1]) / s;
+ z = T(0.25) * s;
+ }
+ OVR_MATH_ASSERT(IsNormalized()); // Ensure input matrix is orthogonal
+ }
+
+ // Constructs the quaternion from a rotation matrix
+ explicit Quat(const Matrix3<T>& m) {
+ T trace = m.M[0][0] + m.M[1][1] + m.M[2][2];
+
+ // In almost all cases, the first part is executed.
+ // However, if the trace is not positive, the other
+ // cases arise.
+ if (trace > T(0)) {
+ T s = sqrt(trace + T(1)) * T(2); // s=4*qw
+ w = T(0.25) * s;
+ x = (m.M[2][1] - m.M[1][2]) / s;
+ y = (m.M[0][2] - m.M[2][0]) / s;
+ z = (m.M[1][0] - m.M[0][1]) / s;
+ } else if ((m.M[0][0] > m.M[1][1]) && (m.M[0][0] > m.M[2][2])) {
+ T s = sqrt(T(1) + m.M[0][0] - m.M[1][1] - m.M[2][2]) * T(2);
+ w = (m.M[2][1] - m.M[1][2]) / s;
+ x = T(0.25) * s;
+ y = (m.M[0][1] + m.M[1][0]) / s;
+ z = (m.M[2][0] + m.M[0][2]) / s;
+ } else if (m.M[1][1] > m.M[2][2]) {
+ T s = sqrt(T(1) + m.M[1][1] - m.M[0][0] - m.M[2][2]) * T(2); // S=4*qy
+ w = (m.M[0][2] - m.M[2][0]) / s;
+ x = (m.M[0][1] + m.M[1][0]) / s;
+ y = T(0.25) * s;
+ z = (m.M[1][2] + m.M[2][1]) / s;
+ } else {
+ T s = sqrt(T(1) + m.M[2][2] - m.M[0][0] - m.M[1][1]) * T(2); // S=4*qz
+ w = (m.M[1][0] - m.M[0][1]) / s;
+ x = (m.M[0][2] + m.M[2][0]) / s;
+ y = (m.M[1][2] + m.M[2][1]) / s;
+ z = T(0.25) * s;
+ }
+ OVR_MATH_ASSERT(IsNormalized()); // Ensure input matrix is orthogonal
+ }
+
+ // MERGE_MOBILE_SDK
+ // Constructs a quaternion that rotates 'from' to line up with 'to'.
+ explicit Quat(const Vector3<T>& from, const Vector3<T>& to) {
+ const T cx = from.y * to.z - from.z * to.y;
+ const T cy = from.z * to.x - from.x * to.z;
+ const T cz = from.x * to.y - from.y * to.x;
+ const T dot = from.x * to.x + from.y * to.y + from.z * to.z;
+ const T crossLengthSq = cx * cx + cy * cy + cz * cz;
+ const T magnitude = static_cast<T>(sqrt(crossLengthSq + dot * dot));
+ const T cw = dot + magnitude;
+ if (cw < Math<T>::SmallestNonDenormal()) {
+ const T sx = to.y * to.y + to.z * to.z;
+ const T sz = to.x * to.x + to.y * to.y;
+ if (sx > sz) {
+ const T rcpLength = RcpSqrt(sx);
+ x = T(0);
+ y = to.z * rcpLength;
+ z = -to.y * rcpLength;
+ w = T(0);
+ } else {
+ const T rcpLength = RcpSqrt(sz);
+ x = to.y * rcpLength;
+ y = -to.x * rcpLength;
+ z = T(0);
+ w = T(0);
+ }
+ return;
+ }
+ const T rcpLength = RcpSqrt(crossLengthSq + cw * cw);
+ x = cx * rcpLength;
+ y = cy * rcpLength;
+ z = cz * rcpLength;
+ w = cw * rcpLength;
+ }
+ // MERGE_MOBILE_SDK
+
+ bool operator==(const Quat& b) const {
+ return x == b.x && y == b.y && z == b.z && w == b.w;
+ }
+ bool operator!=(const Quat& b) const {
+ return x != b.x || y != b.y || z != b.z || w != b.w;
+ }
+
+ Quat operator+(const Quat& b) const {
+ return Quat(x + b.x, y + b.y, z + b.z, w + b.w);
+ }
+ Quat& operator+=(const Quat& b) {
+ w += b.w;
+ x += b.x;
+ y += b.y;
+ z += b.z;
+ return *this;
+ }
+ Quat operator-(const Quat& b) const {
+ return Quat(x - b.x, y - b.y, z - b.z, w - b.w);
+ }
+ Quat& operator-=(const Quat& b) {
+ w -= b.w;
+ x -= b.x;
+ y -= b.y;
+ z -= b.z;
+ return *this;
+ }
+
+ Quat operator*(T s) const {
+ return Quat(x * s, y * s, z * s, w * s);
+ }
+ Quat& operator*=(T s) {
+ w *= s;
+ x *= s;
+ y *= s;
+ z *= s;
+ return *this;
+ }
+ Quat operator/(T s) const {
+ T rcp = T(1) / s;
+ return Quat(x * rcp, y * rcp, z * rcp, w * rcp);
+ }
+ Quat& operator/=(T s) {
+ T rcp = T(1) / s;
+ w *= rcp;
+ x *= rcp;
+ y *= rcp;
+ z *= rcp;
+ return *this;
+ }
+
+ // MERGE_MOBILE_SDK
+ Vector3<T> operator*(const Vector3<T>& v) const {
+ return Rotate(v);
+ }
+ // MERGE_MOBILE_SDK
+
+ // Compare two quats for equality within tolerance. Returns true if quats match within tolerance.
+ bool IsEqual(const Quat& b, T tolerance = Math<T>::Tolerance()) const {
+ return Abs(Dot(b)) >= T(1) - tolerance;
+ }
+
+ // Compare two quats for equality within tolerance while checking matching hemispheres. Returns
+ // true if quats match within tolerance.
+ bool IsEqualMatchHemisphere(Quat b, T tolerance = Math<T>::Tolerance()) const {
+ b.EnsureSameHemisphere(*this);
+ return Abs(Dot(b)) >= T(1) - tolerance;
+ }
+
+ static T Abs(const T v) {
+ return (v >= 0) ? v : -v;
+ }
+
+ // Get Imaginary part vector
+ Vector3<T> Imag() const {
+ return Vector3<T>(x, y, z);
+ }
+
+ // Get quaternion length.
+ T Length() const {
+ return sqrt(LengthSq());
+ }
+
+ // Get quaternion length squared.
+ T LengthSq() const {
+ return (x * x + y * y + z * z + w * w);
+ }
+
+ // Simple Euclidean distance in R^4 (not SLERP distance, but at least respects Haar measure)
+ T Distance(const Quat& q) const {
+ T d1 = (*this - q).Length();
+ T d2 = (*this + q).Length(); // Antipodal point check
+ return (d1 < d2) ? d1 : d2;
+ }
+
+ T DistanceSq(const Quat& q) const {
+ T d1 = (*this - q).LengthSq();
+ T d2 = (*this + q).LengthSq(); // Antipodal point check
+ return (d1 < d2) ? d1 : d2;
+ }
+
+ T Dot(const Quat& q) const {
+ return x * q.x + y * q.y + z * q.z + w * q.w;
+ }
+
+ // Angle between two quaternions in radians
+ T Angle(const Quat& q) const {
+ return T(2) * Acos(Abs(Dot(q)));
+ }
+
+ // Angle of quaternion
+ T Angle() const {
+ return T(2) * Acos(Abs(w));
+ }
+
+ // Normalize
+ bool IsNormalized() const {
+ return fabs(LengthSq() - T(1)) < Math<T>::Tolerance();
+ }
+
+ void Normalize() {
+ T s = Length();
+ if (s != T(0))
+ s = T(1) / s;
+ *this *= s;
+ }
+
+ Quat Normalized() const {
+ T s = Length();
+ if (s != T(0))
+ s = T(1) / s;
+ return *this * s;
+ }
+
+ inline void EnsureSameHemisphere(const Quat& o) {
+ if (Dot(o) < T(0)) {
+ x = -x;
+ y = -y;
+ z = -z;
+ w = -w;
+ }
+ }
+
+ // Returns conjugate of the quaternion. Produces inverse rotation if quaternion is normalized.
+ Quat Conj() const {
+ return Quat(-x, -y, -z, w);
+ }
+
+ // Quaternion multiplication. Combines quaternion rotations, performing the one on the
+ // right hand side first.
+ Quat operator*(const Quat& b) const {
+ return Quat(
+ w * b.x + x * b.w + y * b.z - z * b.y,
+ w * b.y - x * b.z + y * b.w + z * b.x,
+ w * b.z + x * b.y - y * b.x + z * b.w,
+ w * b.w - x * b.x - y * b.y - z * b.z);
+ }
+ const Quat& operator*=(const Quat& b) {
+ *this = *this * b;
+ return *this;
+ }
+
+ //
+ // this^p normalized; same as rotating by this p times.
+ Quat PowNormalized(T p) const {
+ Vector3<T> v;
+ T a;
+ GetAxisAngle(&v, &a);
+ return Quat(v, a * p);
+ }
+
+ // Compute quaternion that rotates v into alignTo: alignTo = Quat::Align(alignTo, v).Rotate(v).
+ // NOTE: alignTo and v must be normalized.
+ static Quat Align(const Vector3<T>& alignTo, const Vector3<T>& v) {
+ OVR_MATH_ASSERT(alignTo.IsNormalized() && v.IsNormalized());
+ Vector3<T> bisector = (v + alignTo);
+ bisector.Normalize();
+ T cosHalfAngle = v.Dot(bisector); // 0..1
+ if (cosHalfAngle > T(0)) {
+ Vector3<T> imag = v.Cross(bisector);
+ return Quat(imag.x, imag.y, imag.z, cosHalfAngle);
+ } else {
+ // cosHalfAngle == 0: a 180 degree rotation.
+ // sinHalfAngle == 1, rotation axis is any axis perpendicular
+ // to alignTo. Choose axis to include largest magnitude components
+ if (fabs(v.x) > fabs(v.y)) {
+ // x or z is max magnitude component
+ // = Cross(v, (0,1,0)).Normalized();
+ T invLen = sqrt(v.x * v.x + v.z * v.z);
+ if (invLen > T(0))
+ invLen = T(1) / invLen;
+ return Quat(-v.z * invLen, 0, v.x * invLen, 0);
+ } else {
+ // y or z is max magnitude component
+ // = Cross(v, (1,0,0)).Normalized();
+ T invLen = sqrt(v.y * v.y + v.z * v.z);
+ if (invLen > T(0))
+ invLen = T(1) / invLen;
+ return Quat(0, v.z * invLen, -v.y * invLen, 0);
+ }
+ }
+ }
+
+ // Decompose a quat into quat = swing * twist, where twist is a rotation about axis,
+ // and swing is a rotation perpendicular to axis.
+ Quat GetSwingTwist(const Vector3<T>& axis, Quat* twist) const {
+ OVR_MATH_ASSERT(twist);
+ OVR_MATH_ASSERT(axis.IsNormalized());
+
+ // Create a normalized quaternion from projection of (x,y,z) onto axis
+ T d = axis.Dot(Vector3<T>(x, y, z));
+ *twist = Quat(axis.x * d, axis.y * d, axis.z * d, w);
+ T len = twist->Length();
+ if (len == 0)
+ twist->w = T(1); // identity
+ else
+ *twist /= len; // normalize
+
+ return *this * twist->Inverted();
+ }
+
+ // Normalized linear interpolation of quaternions
+ // NOTE: This function is a bad approximation of Slerp()
+ // when the angle between the *this and b is large.
+ // Use FastSlerp() or Slerp() instead.
+ Quat Lerp(const Quat& b, T s) const {
+ return (*this * (T(1) - s) + b * (Dot(b) < 0 ? -s : s)).Normalized();
+ }
+
+ // Spherical linear interpolation between rotations
+ Quat Slerp(const Quat& b, T s) const {
+ Vector3<T> delta = (b * this->Inverted()).ToRotationVector();
+ return (FromRotationVector(delta * s) * *this)
+ .Normalized(); // normalize so errors don't accumulate
+ }
+
+ // Spherical linear interpolation: much faster for small rotations, accurate for large rotations.
+ // See FastTo/FromRotationVector
+ Quat FastSlerp(const Quat& b, T s) const {
+ Vector3<T> delta = (b * this->Inverted()).FastToRotationVector();
+ return (FastFromRotationVector(delta * s, false) * *this).Normalized();
+ }
+
+ // MERGE_MOBILE_SDK
+ // FIXME: This is opposite of Lerp for some reason. It goes from 1 to 0 instead of 0 to 1.
+ // Leaving it as a gift for future generations to deal with.
+ Quat Nlerp(const Quat& other, T a) const {
+ T sign = (Dot(other) >= 0.0f) ? 1.0f : -1.0f;
+ return (*this * sign * a + other * (1 - a)).Normalized();
+ }
+ // MERGE_MOBILE_SDK
+
+ // Rotate transforms vector in a manner that matches Matrix rotations (counter-clockwise,
+ // assuming negative direction of the axis). Standard formula: q(t) * V * q(t)^-1.
+ Vector3<T> Rotate(const Vector3<T>& v) const {
+ OVR_MATH_ASSERT(IsNormalized()); // If this fires, caller has a quat math bug
+
+ // rv = q * (v,0) * q'
+ // Same as rv = v + real * cross(imag,v)*2 + cross(imag, cross(imag,v)*2);
+
+ // uv = 2 * Imag().Cross(v);
+ T uvx = T(2) * (y * v.z - z * v.y);
+ T uvy = T(2) * (z * v.x - x * v.z);
+ T uvz = T(2) * (x * v.y - y * v.x);
+
+ // return v + Real()*uv + Imag().Cross(uv);
+ return Vector3<T>(
+ v.x + w * uvx + y * uvz - z * uvy,
+ v.y + w * uvy + z * uvx - x * uvz,
+ v.z + w * uvz + x * uvy - y * uvx);
+ }
+
+ // Rotation by inverse of *this
+ Vector3<T> InverseRotate(const Vector3<T>& v) const {
+ OVR_MATH_ASSERT(IsNormalized()); // If this fires, caller has a quat math bug
+
+ // rv = q' * (v,0) * q
+ // Same as rv = v + real * cross(-imag,v)*2 + cross(-imag, cross(-imag,v)*2);
+ // or rv = v - real * cross(imag,v)*2 + cross(imag, cross(imag,v)*2);
+
+ // uv = 2 * Imag().Cross(v);
+ T uvx = T(2) * (y * v.z - z * v.y);
+ T uvy = T(2) * (z * v.x - x * v.z);
+ T uvz = T(2) * (x * v.y - y * v.x);
+
+ // return v - Real()*uv + Imag().Cross(uv);
+ return Vector3<T>(
+ v.x - w * uvx + y * uvz - z * uvy,
+ v.y - w * uvy + z * uvx - x * uvz,
+ v.z - w * uvz + x * uvy - y * uvx);
+ }
+
+ // Inversed quaternion rotates in the opposite direction.
+ Quat Inverted() const {
+ return Quat(-x, -y, -z, w);
+ }
+
+ Quat Inverse() const {
+ return Quat(-x, -y, -z, w);
+ }
+
+ // Sets this quaternion to the one rotates in the opposite direction.
+ void Invert() {
+ *this = Quat(-x, -y, -z, w);
+ }
+
+ // Time integration of constant angular velocity over dt
+ Quat TimeIntegrate(const Vector3<T>& angularVelocity, T dt) const {
+ // solution is: this * exp( omega*dt/2 ); FromRotationVector(v) gives exp(v*.5).
+ return (*this * FastFromRotationVector(angularVelocity * dt, false)).Normalized();
+ }
+
+ // Time integration of constant angular acceleration and velocity over dt
+ // These are the first two terms of the "Magnus expansion" of the solution
+ //
+ // o = o * exp( W=(W1 + W2 + W3+...) * 0.5 );
+ //
+ // omega1 = (omega + omegaDot*dt)
+ // W1 = (omega + omega1)*dt/2
+ // W2 = cross(omega, omega1)/12*dt^2 % (= -cross(omega_dot, omega)/12*dt^3)
+ // Terms 3 and beyond are vanishingly small:
+ // W3 = cross(omega_dot, cross(omega_dot, omega))/240*dt^5
+ //
+ Quat TimeIntegrate(const Vector3<T>& angularVelocity, const Vector3<T>& angularAcceleration, T dt)
+ const {
+ const Vector3<T>& omega = angularVelocity;
+ const Vector3<T>& omegaDot = angularAcceleration;
+
+ Vector3<T> omega1 = (omega + omegaDot * dt);
+ Vector3<T> W = ((omega + omega1) + omega.Cross(omega1) * (dt / T(6))) * (dt / T(2));
+
+ // FromRotationVector(v) is exp(v*.5)
+ return (*this * FastFromRotationVector(W, false)).Normalized();
+ }
+
+ // Decompose rotation into three rotations:
+ // roll radians about Z axis, then pitch radians about X axis, then yaw radians about Y axis.
+ // Call with nullptr if a return value is not needed.
+ void GetYawPitchRoll(T* yaw, T* pitch, T* roll) const {
+ return GetEulerAngles<Axis_Y, Axis_X, Axis_Z, Rotate_CCW, Handed_R>(yaw, pitch, roll);
+ }
+
+ // GetEulerAngles extracts Euler angles from the quaternion, in the specified order of
+ // axis rotations and the specified coordinate system. Right-handed coordinate system
+ // is the default, with CCW rotations while looking in the negative axis direction.
+ // Here a,b,c, are the Yaw/Pitch/Roll angles to be returned.
+ // Rotation order is c, b, a:
+ // rotation c around axis A3
+ // is followed by rotation b around axis A2
+ // is followed by rotation a around axis A1
+ // rotations are CCW or CW (D) in LH or RH coordinate system (S)
+ //
+ template <Axis A1, Axis A2, Axis A3, RotateDirection D, HandedSystem S>
+ void GetEulerAngles(T* a, T* b, T* c) const {
+ OVR_MATH_ASSERT(IsNormalized()); // If this fires, caller has a quat math bug
+ OVR_MATH_STATIC_ASSERT(
+ (A1 != A2) && (A2 != A3) && (A1 != A3), "(A1 != A2) && (A2 != A3) && (A1 != A3)");
+
+ T Q[3] = {x, y, z}; // Quaternion components x,y,z
+
+ T ww = w * w;
+ T Q11 = Q[A1] * Q[A1];
+ T Q22 = Q[A2] * Q[A2];
+ T Q33 = Q[A3] * Q[A3];
+
+ T psign = T(-1);
+ // Determine whether even permutation
+ if (((A1 + 1) % 3 == A2) && ((A2 + 1) % 3 == A3))
+ psign = T(1);
+
+ T s2 = psign * T(2) * (psign * w * Q[A2] + Q[A1] * Q[A3]);
+
+ T singularityRadius = Math<T>::SingularityRadius();
+ if (s2 < T(-1) + singularityRadius) { // South pole singularity
+ if (a)
+ *a = T(0);
+ if (b)
+ *b = -S * D * ((T)MATH_DOUBLE_PIOVER2);
+ if (c)
+ *c = S * D * atan2(T(2) * (psign * Q[A1] * Q[A2] + w * Q[A3]), ww + Q22 - Q11 - Q33);
+ } else if (s2 > T(1) - singularityRadius) { // North pole singularity
+ if (a)
+ *a = T(0);
+ if (b)
+ *b = S * D * ((T)MATH_DOUBLE_PIOVER2);
+ if (c)
+ *c = S * D * atan2(T(2) * (psign * Q[A1] * Q[A2] + w * Q[A3]), ww + Q22 - Q11 - Q33);
+ } else {
+ if (a)
+ *a = -S * D * atan2(T(-2) * (w * Q[A1] - psign * Q[A2] * Q[A3]), ww + Q33 - Q11 - Q22);
+ if (b)
+ *b = S * D * asin(s2);
+ if (c)
+ *c = S * D * atan2(T(2) * (w * Q[A3] - psign * Q[A1] * Q[A2]), ww + Q11 - Q22 - Q33);
+ }
+ }
+
+ template <Axis A1, Axis A2, Axis A3, RotateDirection D>
+ void GetEulerAngles(T* a, T* b, T* c) const {
+ GetEulerAngles<A1, A2, A3, D, Handed_R>(a, b, c);
+ }
+
+ template <Axis A1, Axis A2, Axis A3>
+ void GetEulerAngles(T* a, T* b, T* c) const {
+ GetEulerAngles<A1, A2, A3, Rotate_CCW, Handed_R>(a, b, c);
+ }
+
+ // GetEulerAnglesABA extracts Euler angles from the quaternion, in the specified order of
+ // axis rotations and the specified coordinate system. Right-handed coordinate system
+ // is the default, with CCW rotations while looking in the negative axis direction.
+ // Here a,b,c, are the Yaw/Pitch/Roll angles to be returned.
+ // rotation a around axis A1
+ // is followed by rotation b around axis A2
+ // is followed by rotation c around axis A1
+ // Rotations are CCW or CW (D) in LH or RH coordinate system (S)
+ template <Axis A1, Axis A2, RotateDirection D, HandedSystem S>
+ void GetEulerAnglesABA(T* a, T* b, T* c) const {
+ OVR_MATH_ASSERT(IsNormalized()); // If this fires, caller has a quat math bug
+ OVR_MATH_STATIC_ASSERT(A1 != A2, "A1 != A2");
+
+ T Q[3] = {x, y, z}; // Quaternion components
+
+ // Determine the missing axis that was not supplied
+ int m = 3 - A1 - A2;
+
+ T ww = w * w;
+ T Q11 = Q[A1] * Q[A1];
+ T Q22 = Q[A2] * Q[A2];
+ T Qmm = Q[m] * Q[m];
+
+ T psign = T(-1);
+ if ((A1 + 1) % 3 == A2) // Determine whether even permutation
+ {
+ psign = T(1);
+ }
+
+ T c2 = ww + Q11 - Q22 - Qmm;
+ T singularityRadius = Math<T>::SingularityRadius();
+ if (c2 < T(-1) + singularityRadius) { // South pole singularity
+ if (a)
+ *a = T(0);
+ if (b)
+ *b = S * D * ((T)MATH_DOUBLE_PI);
+ if (c)
+ *c = S * D * atan2(T(2) * (w * Q[A1] - psign * Q[A2] * Q[m]), ww + Q22 - Q11 - Qmm);
+ } else if (c2 > T(1) - singularityRadius) { // North pole singularity
+ if (a)
+ *a = T(0);
+ if (b)
+ *b = T(0);
+ if (c)
+ *c = S * D * atan2(T(2) * (w * Q[A1] - psign * Q[A2] * Q[m]), ww + Q22 - Q11 - Qmm);
+ } else {
+ if (a)
+ *a = S * D * atan2(psign * w * Q[m] + Q[A1] * Q[A2], w * Q[A2] - psign * Q[A1] * Q[m]);
+ if (b)
+ *b = S * D * acos(c2);
+ if (c)
+ *c = S * D * atan2(-psign * w * Q[m] + Q[A1] * Q[A2], w * Q[A2] + psign * Q[A1] * Q[m]);
+ }
+ }
+
+ bool IsNan() const {
+ return !isfinite(x + y + z + w);
+ }
+ bool IsFinite() const {
+ return isfinite(x + y + z + w);
+ }
+};
+
+typedef Quat<float> Quatf;
+typedef Quat<double> Quatd;
+
+OVR_MATH_STATIC_ASSERT((sizeof(Quatf) == 4 * sizeof(float)), "sizeof(Quatf) failure");
+OVR_MATH_STATIC_ASSERT((sizeof(Quatd) == 4 * sizeof(double)), "sizeof(Quatd) failure");
+
+//-------------------------------------------------------------------------------------
+// ***** Pose
+//
+// Position and orientation combined.
+//
+// This structure needs to be the same size and layout on 32-bit and 64-bit arch.
+// Update OVR_PadCheck.cpp when updating this object.
+template <class T>
+class Pose {
+ public:
+ typedef typename CompatibleTypes<Pose<T>>::Type CompatibleType;
+
+ Pose() {}
+ Pose(const Quat<T>& orientation, const Vector3<T>& pos)
+ : Rotation(orientation), Translation(pos) {}
+ Pose(const Pose& s) : Rotation(s.Rotation), Translation(s.Translation) {}
+ Pose(const Matrix3<T>& R, const Vector3<T>& t) : Rotation((Quat<T>)R), Translation(t) {}
+ Pose(const CompatibleType& s) : Rotation(s.Orientation), Translation(s.Position) {}
+
+ explicit Pose(const Pose<typename Math<T>::OtherFloatType>& s)
+ : Rotation(s.Rotation), Translation(s.Translation) {
+ // Ensure normalized rotation if converting from float to double
+ if (sizeof(T) > sizeof(typename Math<T>::OtherFloatType))
+ Rotation.Normalize();
+ }
+
+ static Pose Identity() {
+ return Pose(Quat<T>(0, 0, 0, 1), Vector3<T>(0, 0, 0));
+ }
+
+ void SetIdentity() {
+ Rotation = Quat<T>(0, 0, 0, 1);
+ Translation = Vector3<T>(0, 0, 0);
+ }
+
+ // used to make things obviously broken if someone tries to use the value
+ void SetInvalid() {
+ Rotation = Quat<T>(NAN, NAN, NAN, NAN);
+ Translation = Vector3<T>(NAN, NAN, NAN);
+ }
+
+ bool IsEqual(const Pose& b, T tolerance = Math<T>::Tolerance()) const {
+ return Translation.IsEqual(b.Translation, tolerance) && Rotation.IsEqual(b.Rotation, tolerance);
+ }
+
+ bool IsEqualMatchHemisphere(const Pose& b, T tolerance = Math<T>::Tolerance()) const {
+ return Translation.IsEqual(b.Translation, tolerance) &&
+ Rotation.IsEqualMatchHemisphere(b.Rotation, tolerance);
+ }
+
+ operator typename CompatibleTypes<Pose<T>>::Type() const {
+ typename CompatibleTypes<Pose<T>>::Type result;
+ result.Orientation = Rotation;
+ result.Position = Translation;
+ return result;
+ }
+
+ Quat<T> Rotation;
+ Vector3<T> Translation;
+
+ OVR_MATH_STATIC_ASSERT(
+ (sizeof(T) == sizeof(double) || sizeof(T) == sizeof(float)),
+ "(sizeof(T) == sizeof(double) || sizeof(T) == sizeof(float))");
+
+ void ToArray(T* arr) const {
+ T temp[7] = {Rotation.x,
+ Rotation.y,
+ Rotation.z,
+ Rotation.w,
+ Translation.x,
+ Translation.y,
+ Translation.z};
+ for (int i = 0; i < 7; i++)
+ arr[i] = temp[i];
+ }
+
+ static Pose<T> FromArray(const T* v) {
+ Quat<T> rotation(v[0], v[1], v[2], v[3]);
+ Vector3<T> translation(v[4], v[5], v[6]);
+ // Ensure rotation is normalized, in case it was originally a float, stored in a .json file,
+ // etc.
+ return Pose<T>(rotation.Normalized(), translation);
+ }
+
+ Vector3<T> Rotate(const Vector3<T>& v) const {
+ return Rotation.Rotate(v);
+ }
+
+ Vector3<T> InverseRotate(const Vector3<T>& v) const {
+ return Rotation.InverseRotate(v);
+ }
+
+ Vector3<T> Translate(const Vector3<T>& v) const {
+ return v + Translation;
+ }
+
+ Vector3<T> Transform(const Vector3<T>& v) const {
+ return Rotate(v) + Translation;
+ }
+
+ Vector3<T> InverseTransform(const Vector3<T>& v) const {
+ return InverseRotate(v - Translation);
+ }
+
+ Vector3<T> TransformNormal(const Vector3<T>& v) const {
+ return Rotate(v);
+ }
+
+ Vector3<T> InverseTransformNormal(const Vector3<T>& v) const {
+ return InverseRotate(v);
+ }
+
+ Vector3<T> Apply(const Vector3<T>& v) const {
+ return Transform(v);
+ }
+
+ Pose operator*(const Pose& other) const {
+ return Pose(Rotation * other.Rotation, Apply(other.Translation));
+ }
+
+ Pose Inverted() const {
+ Quat<T> inv = Rotation.Inverted();
+ return Pose(inv, inv.Rotate(-Translation));
+ }
+
+ // Interpolation between two poses: translation is interpolated with Lerp(),
+ // and rotations are interpolated with Slerp().
+ Pose Lerp(const Pose& b, T s) const {
+ return Pose(Rotation.Slerp(b.Rotation, s), Translation.Lerp(b.Translation, s));
+ }
+
+ // Similar to Lerp above, except faster in case of small rotation differences. See
+ // Quat<T>::FastSlerp.
+ Pose FastLerp(const Pose& b, T s) const {
+ return Pose(Rotation.FastSlerp(b.Rotation, s), Translation.Lerp(b.Translation, s));
+ }
+
+ Pose TimeIntegrate(const Vector3<T>& linearVelocity, const Vector3<T>& angularVelocity, T dt)
+ const {
+ return Pose(
+ (Rotation * Quat<T>::FastFromRotationVector(angularVelocity * dt, false)).Normalized(),
+ Translation + linearVelocity * dt);
+ }
+
+ Pose TimeIntegrate(
+ const Vector3<T>& linearVelocity,
+ const Vector3<T>& linearAcceleration,
+ const Vector3<T>& angularVelocity,
+ const Vector3<T>& angularAcceleration,
+ T dt) const {
+ return Pose(
+ Rotation.TimeIntegrate(angularVelocity, angularAcceleration, dt),
+ Translation + linearVelocity * dt + linearAcceleration * dt * dt * T(0.5));
+ }
+
+ Pose Normalized() const {
+ return Pose(Rotation.Normalized(), Translation);
+ }
+ void Normalize() {
+ Rotation.Normalize();
+ }
+
+ bool IsNan() const {
+ return Translation.IsNan() || Rotation.IsNan();
+ }
+ bool IsFinite() const {
+ return Translation.IsFinite() && Rotation.IsFinite();
+ }
+};
+
+typedef Pose<float> Posef;
+typedef Pose<double> Posed;
+
+OVR_MATH_STATIC_ASSERT(
+ (sizeof(Posed) == sizeof(Quatd) + sizeof(Vector3d)),
+ "sizeof(Posed) failure");
+OVR_MATH_STATIC_ASSERT(
+ (sizeof(Posef) == sizeof(Quatf) + sizeof(Vector3f)),
+ "sizeof(Posef) failure");
+
+//-------------------------------------------------------------------------------------
+// ***** Matrix4
+//
+// Matrix4 is a 4x4 matrix used for 3d transformations and projections.
+// Translation stored in the last column.
+// The matrix is stored in row-major order in memory, meaning that values
+// of the first row are stored before the next one.
+//
+// The arrangement of the matrix is chosen to be in Right-Handed
+// coordinate system and counterclockwise rotations when looking down
+// the axis
+//
+// Transformation Order:
+// - Transformations are applied from right to left, so the expression
+// M1 * M2 * M3 * V means that the vector V is transformed by M3 first,
+// followed by M2 and M1.
+//
+// Coordinate system: Right Handed
+//
+// Rotations: Counterclockwise when looking down the axis. All angles are in radians.
+//
+// | sx 01 02 tx | // First column (sx, 10, 20): Axis X basis vector.
+// | 10 sy 12 ty | // Second column (01, sy, 21): Axis Y basis vector.
+// | 20 21 sz tz | // Third columnt (02, 12, sz): Axis Z basis vector.
+// | 30 31 32 33 |
+//
+// The basis vectors are first three columns.
+
+template <class T>
+class Matrix4 {
+ public:
+ typedef T ElementType;
+ static const size_t Dimension = 4;
+
+ T M[4][4];
+
+ enum NoInitType { NoInit };
+
+ // Construct with no memory initialization.
+ Matrix4(NoInitType) {}
+
+ // By default, we construct identity matrix.
+ Matrix4() {
+ M[0][0] = M[1][1] = M[2][2] = M[3][3] = T(1);
+ M[0][1] = M[1][0] = M[2][3] = M[3][1] = T(0);
+ M[0][2] = M[1][2] = M[2][0] = M[3][2] = T(0);
+ M[0][3] = M[1][3] = M[2][1] = M[3][0] = T(0);
+ }
+
+ Matrix4(
+ T m11,
+ T m12,
+ T m13,
+ T m14,
+ T m21,
+ T m22,
+ T m23,
+ T m24,
+ T m31,
+ T m32,
+ T m33,
+ T m34,
+ T m41,
+ T m42,
+ T m43,
+ T m44) {
+ M[0][0] = m11;
+ M[0][1] = m12;
+ M[0][2] = m13;
+ M[0][3] = m14;
+ M[1][0] = m21;
+ M[1][1] = m22;
+ M[1][2] = m23;
+ M[1][3] = m24;
+ M[2][0] = m31;
+ M[2][1] = m32;
+ M[2][2] = m33;
+ M[2][3] = m34;
+ M[3][0] = m41;
+ M[3][1] = m42;
+ M[3][2] = m43;
+ M[3][3] = m44;
+ }
+
+ Matrix4(T m11, T m12, T m13, T m21, T m22, T m23, T m31, T m32, T m33) {
+ M[0][0] = m11;
+ M[0][1] = m12;
+ M[0][2] = m13;
+ M[0][3] = T(0);
+ M[1][0] = m21;
+ M[1][1] = m22;
+ M[1][2] = m23;
+ M[1][3] = T(0);
+ M[2][0] = m31;
+ M[2][1] = m32;
+ M[2][2] = m33;
+ M[2][3] = T(0);
+ M[3][0] = T(0);
+ M[3][1] = T(0);
+ M[3][2] = T(0);
+ M[3][3] = T(1);
+ }
+
+ explicit Matrix4(const Matrix3<T>& m) {
+ M[0][0] = m.M[0][0];
+ M[0][1] = m.M[0][1];
+ M[0][2] = m.M[0][2];
+ M[0][3] = T(0);
+ M[1][0] = m.M[1][0];
+ M[1][1] = m.M[1][1];
+ M[1][2] = m.M[1][2];
+ M[1][3] = T(0);
+ M[2][0] = m.M[2][0];
+ M[2][1] = m.M[2][1];
+ M[2][2] = m.M[2][2];
+ M[2][3] = T(0);
+ M[3][0] = T(0);
+ M[3][1] = T(0);
+ M[3][2] = T(0);
+ M[3][3] = T(1);
+ }
+
+ explicit Matrix4(const Quat<T>& q) {
+ OVR_MATH_ASSERT(q.IsNormalized()); // If this fires, caller has a quat math bug
+ T ww = q.w * q.w;
+ T xx = q.x * q.x;
+ T yy = q.y * q.y;
+ T zz = q.z * q.z;
+
+ M[0][0] = ww + xx - yy - zz;
+ M[0][1] = 2 * (q.x * q.y - q.w * q.z);
+ M[0][2] = 2 * (q.x * q.z + q.w * q.y);
+ M[0][3] = T(0);
+ M[1][0] = 2 * (q.x * q.y + q.w * q.z);
+ M[1][1] = ww - xx + yy - zz;
+ M[1][2] = 2 * (q.y * q.z - q.w * q.x);
+ M[1][3] = T(0);
+ M[2][0] = 2 * (q.x * q.z - q.w * q.y);
+ M[2][1] = 2 * (q.y * q.z + q.w * q.x);
+ M[2][2] = ww - xx - yy + zz;
+ M[2][3] = T(0);
+ M[3][0] = T(0);
+ M[3][1] = T(0);
+ M[3][2] = T(0);
+ M[3][3] = T(1);
+ }
+
+ explicit Matrix4(const Pose<T>& p) {
+ Matrix4 result(p.Rotation);
+ result.SetTranslation(p.Translation);
+ *this = result;
+ }
+
+ // C-interop support
+ explicit Matrix4(const Matrix4<typename Math<T>::OtherFloatType>& src) {
+ for (int i = 0; i < 4; i++)
+ for (int j = 0; j < 4; j++)
+ M[i][j] = (T)src.M[i][j];
+ }
+
+ // C-interop support.
+ Matrix4(const typename CompatibleTypes<Matrix4<T>>::Type& s) {
+ OVR_MATH_STATIC_ASSERT(sizeof(s) == sizeof(Matrix4), "sizeof(s) == sizeof(Matrix4)");
+ memcpy(M, s.M, sizeof(M));
+ }
+
+ operator typename CompatibleTypes<Matrix4<T>>::Type() const {
+ typename CompatibleTypes<Matrix4<T>>::Type result;
+ OVR_MATH_STATIC_ASSERT(sizeof(result) == sizeof(Matrix4), "sizeof(result) == sizeof(Matrix4)");
+ memcpy(result.M, M, sizeof(M));
+ return result;
+ }
+
+ void ToString(char* dest, size_t destsize) const {
+ size_t pos = 0;
+ for (int r = 0; r < 4; r++) {
+ for (int c = 0; c < 4; c++) {
+ pos += OVRMath_sprintf(dest + pos, destsize - pos, "%g ", M[r][c]);
+ }
+ }
+ }
+
+ static Matrix4 FromString(const char* src) {
+ Matrix4 result;
+ if (src) {
+ for (int r = 0; r < 4; r++) {
+ for (int c = 0; c < 4; c++) {
+ result.M[r][c] = (T)atof(src);
+ while (*src && *src != ' ') {
+ src++;
+ }
+ while (*src && *src == ' ') {
+ src++;
+ }
+ }
+ }
+ }
+ return result;
+ }
+
+ static Matrix4 Identity() {
+ return Matrix4();
+ }
+
+ void SetIdentity() {
+ M[0][0] = M[1][1] = M[2][2] = M[3][3] = T(1);
+ M[0][1] = M[1][0] = M[2][3] = M[3][1] = T(0);
+ M[0][2] = M[1][2] = M[2][0] = M[3][2] = T(0);
+ M[0][3] = M[1][3] = M[2][1] = M[3][0] = T(0);
+ }
+
+ void SetXBasis(const Vector3<T>& v) {
+ M[0][0] = v.x;
+ M[1][0] = v.y;
+ M[2][0] = v.z;
+ }
+ Vector3<T> GetXBasis() const {
+ return Vector3<T>(M[0][0], M[1][0], M[2][0]);
+ }
+
+ void SetYBasis(const Vector3<T>& v) {
+ M[0][1] = v.x;
+ M[1][1] = v.y;
+ M[2][1] = v.z;
+ }
+ Vector3<T> GetYBasis() const {
+ return Vector3<T>(M[0][1], M[1][1], M[2][1]);
+ }
+
+ void SetZBasis(const Vector3<T>& v) {
+ M[0][2] = v.x;
+ M[1][2] = v.y;
+ M[2][2] = v.z;
+ }
+ Vector3<T> GetZBasis() const {
+ return Vector3<T>(M[0][2], M[1][2], M[2][2]);
+ }
+
+ bool operator==(const Matrix4& b) const {
+ bool isEqual = true;
+ for (int i = 0; i < 4; i++)
+ for (int j = 0; j < 4; j++)
+ isEqual &= (M[i][j] == b.M[i][j]);
+
+ return isEqual;
+ }
+
+ Matrix4 operator+(const Matrix4& b) const {
+ Matrix4 result(*this);
+ result += b;
+ return result;
+ }
+
+ Matrix4& operator+=(const Matrix4& b) {
+ for (int i = 0; i < 4; i++)
+ for (int j = 0; j < 4; j++)
+ M[i][j] += b.M[i][j];
+ return *this;
+ }
+
+ Matrix4 operator-(const Matrix4& b) const {
+ Matrix4 result(*this);
+ result -= b;
+ return result;
+ }
+
+ Matrix4& operator-=(const Matrix4& b) {
+ for (int i = 0; i < 4; i++)
+ for (int j = 0; j < 4; j++)
+ M[i][j] -= b.M[i][j];
+ return *this;
+ }
+
+ // Multiplies two matrices into destination with minimum copying.
+ static Matrix4& Multiply(Matrix4* d, const Matrix4& a, const Matrix4& b) {
+ OVR_MATH_ASSERT((d != &a) && (d != &b));
+ int i = 0;
+ do {
+ d->M[i][0] = a.M[i][0] * b.M[0][0] + a.M[i][1] * b.M[1][0] + a.M[i][2] * b.M[2][0] +
+ a.M[i][3] * b.M[3][0];
+ d->M[i][1] = a.M[i][0] * b.M[0][1] + a.M[i][1] * b.M[1][1] + a.M[i][2] * b.M[2][1] +
+ a.M[i][3] * b.M[3][1];
+ d->M[i][2] = a.M[i][0] * b.M[0][2] + a.M[i][1] * b.M[1][2] + a.M[i][2] * b.M[2][2] +
+ a.M[i][3] * b.M[3][2];
+ d->M[i][3] = a.M[i][0] * b.M[0][3] + a.M[i][1] * b.M[1][3] + a.M[i][2] * b.M[2][3] +
+ a.M[i][3] * b.M[3][3];
+ } while ((++i) < 4);
+
+ return *d;
+ }
+
+ Matrix4 operator*(const Matrix4& b) const {
+ Matrix4 result(Matrix4::NoInit);
+ Multiply(&result, *this, b);
+ return result;
+ }
+
+ Matrix4& operator*=(const Matrix4& b) {
+ return Multiply(this, Matrix4(*this), b);
+ }
+
+ Matrix4 operator*(T s) const {
+ Matrix4 result(*this);
+ result *= s;
+ return result;
+ }
+
+ Matrix4& operator*=(T s) {
+ for (int i = 0; i < 4; i++)
+ for (int j = 0; j < 4; j++)
+ M[i][j] *= s;
+ return *this;
+ }
+
+ Matrix4 operator/(T s) const {
+ Matrix4 result(*this);
+ result /= s;
+ return result;
+ }
+
+ Matrix4& operator/=(T s) {
+ for (int i = 0; i < 4; i++)
+ for (int j = 0; j < 4; j++)
+ M[i][j] /= s;
+ return *this;
+ }
+
+ T operator()(int i, int j) const {
+ return M[i][j];
+ }
+ T& operator()(int i, int j) {
+ return M[i][j];
+ }
+
+ Vector4<T> operator*(const Vector4<T>& b) const {
+ return Transform(b);
+ }
+
+ Vector3<T> Transform(const Vector3<T>& v) const {
+ const T rcpW = T(1) / (M[3][0] * v.x + M[3][1] * v.y + M[3][2] * v.z + M[3][3]);
+ return Vector3<T>(
+ (M[0][0] * v.x + M[0][1] * v.y + M[0][2] * v.z + M[0][3]) * rcpW,
+ (M[1][0] * v.x + M[1][1] * v.y + M[1][2] * v.z + M[1][3]) * rcpW,
+ (M[2][0] * v.x + M[2][1] * v.y + M[2][2] * v.z + M[2][3]) * rcpW);
+ }
+
+ Vector4<T> Transform(const Vector4<T>& v) const {
+ return Vector4<T>(
+ M[0][0] * v.x + M[0][1] * v.y + M[0][2] * v.z + M[0][3] * v.w,
+ M[1][0] * v.x + M[1][1] * v.y + M[1][2] * v.z + M[1][3] * v.w,
+ M[2][0] * v.x + M[2][1] * v.y + M[2][2] * v.z + M[2][3] * v.w,
+ M[3][0] * v.x + M[3][1] * v.y + M[3][2] * v.z + M[3][3] * v.w);
+ }
+
+ Matrix4 Transposed() const {
+ return Matrix4(
+ M[0][0],
+ M[1][0],
+ M[2][0],
+ M[3][0],
+ M[0][1],
+ M[1][1],
+ M[2][1],
+ M[3][1],
+ M[0][2],
+ M[1][2],
+ M[2][2],
+ M[3][2],
+ M[0][3],
+ M[1][3],
+ M[2][3],
+ M[3][3]);
+ }
+
+ void Transpose() {
+ *this = Transposed();
+ }
+
+ T SubDet(const size_t* rows, const size_t* cols) const {
+ return M[rows[0]][cols[0]] *
+ (M[rows[1]][cols[1]] * M[rows[2]][cols[2]] - M[rows[1]][cols[2]] * M[rows[2]][cols[1]]) -
+ M[rows[0]][cols[1]] *
+ (M[rows[1]][cols[0]] * M[rows[2]][cols[2]] - M[rows[1]][cols[2]] * M[rows[2]][cols[0]]) +
+ M[rows[0]][cols[2]] *
+ (M[rows[1]][cols[0]] * M[rows[2]][cols[1]] - M[rows[1]][cols[1]] * M[rows[2]][cols[0]]);
+ }
+
+ T Cofactor(size_t I, size_t J) const {
+ const size_t indices[4][3] = {{1, 2, 3}, {0, 2, 3}, {0, 1, 3}, {0, 1, 2}};
+ return ((I + J) & 1) ? -SubDet(indices[I], indices[J]) : SubDet(indices[I], indices[J]);
+ }
+
+ T Determinant() const {
+ return M[0][0] * Cofactor(0, 0) + M[0][1] * Cofactor(0, 1) + M[0][2] * Cofactor(0, 2) +
+ M[0][3] * Cofactor(0, 3);
+ }
+
+ Matrix4 Adjugated() const {
+ return Matrix4(
+ Cofactor(0, 0),
+ Cofactor(1, 0),
+ Cofactor(2, 0),
+ Cofactor(3, 0),
+ Cofactor(0, 1),
+ Cofactor(1, 1),
+ Cofactor(2, 1),
+ Cofactor(3, 1),
+ Cofactor(0, 2),
+ Cofactor(1, 2),
+ Cofactor(2, 2),
+ Cofactor(3, 2),
+ Cofactor(0, 3),
+ Cofactor(1, 3),
+ Cofactor(2, 3),
+ Cofactor(3, 3));
+ }
+
+ Matrix4 Inverted() const {
+ T det = Determinant();
+ OVR_MATH_ASSERT(det != 0);
+ return Adjugated() * (T(1) / det);
+ }
+
+ void Invert() {
+ *this = Inverted();
+ }
+
+ // This is more efficient than general inverse, but ONLY works
+ // correctly if it is a homogeneous transform matrix (rot + trans)
+ Matrix4 InvertedHomogeneousTransform() const {
+ // Make the inverse rotation matrix
+ Matrix4 rinv = this->Transposed();
+ rinv.M[3][0] = rinv.M[3][1] = rinv.M[3][2] = T(0);
+ // Make the inverse translation matrix
+ Vector3<T> tvinv(-M[0][3], -M[1][3], -M[2][3]);
+ Matrix4 tinv = Matrix4::Translation(tvinv);
+ return rinv * tinv; // "untranslate", then "unrotate"
+ }
+
+ // This is more efficient than general inverse, but ONLY works
+ // correctly if it is a homogeneous transform matrix (rot + trans)
+ void InvertHomogeneousTransform() {
+ *this = InvertedHomogeneousTransform();
+ }
+
+ // Matrix to Euler Angles conversion
+ // a,b,c, are the YawPitchRoll angles to be returned
+ // rotation a around axis A1
+ // is followed by rotation b around axis A2
+ // is followed by rotation c around axis A3
+ // rotations are CCW or CW (D) in LH or RH coordinate system (S)
+ template <Axis A1, Axis A2, Axis A3, RotateDirection D, HandedSystem S>
+ void ToEulerAngles(T* a, T* b, T* c) const {
+ OVR_MATH_STATIC_ASSERT(
+ (A1 != A2) && (A2 != A3) && (A1 != A3), "(A1 != A2) && (A2 != A3) && (A1 != A3)");
+
+ T psign = T(-1);
+ if (((A1 + 1) % 3 == A2) && ((A2 + 1) % 3 == A3)) // Determine whether even permutation
+ psign = T(1);
+
+ T pm = psign * M[A1][A3];
+ T singularityRadius = Math<T>::SingularityRadius();
+ if (pm < T(-1) + singularityRadius) { // South pole singularity
+ *a = T(0);
+ *b = -S * D * ((T)MATH_DOUBLE_PIOVER2);
+ *c = S * D * atan2(psign * M[A2][A1], M[A2][A2]);
+ } else if (pm > T(1) - singularityRadius) { // North pole singularity
+ *a = T(0);
+ *b = S * D * ((T)MATH_DOUBLE_PIOVER2);
+ *c = S * D * atan2(psign * M[A2][A1], M[A2][A2]);
+ } else { // Normal case (nonsingular)
+ *a = S * D * atan2(-psign * M[A2][A3], M[A3][A3]);
+ *b = S * D * asin(pm);
+ *c = S * D * atan2(-psign * M[A1][A2], M[A1][A1]);
+ }
+ }
+
+ // Matrix to Euler Angles conversion
+ // a,b,c, are the YawPitchRoll angles to be returned
+ // rotation a around axis A1
+ // is followed by rotation b around axis A2
+ // is followed by rotation c around axis A1
+ // rotations are CCW or CW (D) in LH or RH coordinate system (S)
+ template <Axis A1, Axis A2, RotateDirection D, HandedSystem S>
+ void ToEulerAnglesABA(T* a, T* b, T* c) const {
+ OVR_MATH_STATIC_ASSERT(A1 != A2, "A1 != A2");
+
+ // Determine the axis that was not supplied
+ int m = 3 - A1 - A2;
+
+ T psign = T(-1);
+ if ((A1 + 1) % 3 == A2) // Determine whether even permutation
+ psign = T(1);
+
+ T c2 = M[A1][A1];
+ T singularityRadius = Math<T>::SingularityRadius();
+ if (c2 < T(-1) + singularityRadius) { // South pole singularity
+ *a = T(0);
+ *b = S * D * ((T)MATH_DOUBLE_PI);
+ *c = S * D * atan2(-psign * M[A2][m], M[A2][A2]);
+ } else if (c2 > T(1) - singularityRadius) { // North pole singularity
+ *a = T(0);
+ *b = T(0);
+ *c = S * D * atan2(-psign * M[A2][m], M[A2][A2]);
+ } else { // Normal case (nonsingular)
+ *a = S * D * atan2(M[A2][A1], -psign * M[m][A1]);
+ *b = S * D * acos(c2);
+ *c = S * D * atan2(M[A1][A2], psign * M[A1][m]);
+ }
+ }
+
+ // Creates a matrix that converts the vertices from one coordinate system
+ // to another.
+ static Matrix4 AxisConversion(const WorldAxes& to, const WorldAxes& from) {
+ // Holds axis values from the 'to' structure
+ int toArray[3] = {to.XAxis, to.YAxis, to.ZAxis};
+
+ // The inverse of the toArray
+ int inv[4];
+ inv[0] = inv[abs(to.XAxis)] = 0;
+ inv[abs(to.YAxis)] = 1;
+ inv[abs(to.ZAxis)] = 2;
+
+ Matrix4 m(0, 0, 0, 0, 0, 0, 0, 0, 0);
+
+ // Only three values in the matrix need to be changed to 1 or -1.
+ m.M[inv[abs(from.XAxis)]][0] = T(from.XAxis / toArray[inv[abs(from.XAxis)]]);
+ m.M[inv[abs(from.YAxis)]][1] = T(from.YAxis / toArray[inv[abs(from.YAxis)]]);
+ m.M[inv[abs(from.ZAxis)]][2] = T(from.ZAxis / toArray[inv[abs(from.ZAxis)]]);
+ return m;
+ }
+
+ // Creates a matrix for translation by vector
+ static Matrix4 Translation(const Vector3<T>& v) {
+ Matrix4 t;
+ t.M[0][3] = v.x;
+ t.M[1][3] = v.y;
+ t.M[2][3] = v.z;
+ return t;
+ }
+
+ // Creates a matrix for translation by vector
+ static Matrix4 Translation(T x, T y, T z = T(0)) {
+ Matrix4 t;
+ t.M[0][3] = x;
+ t.M[1][3] = y;
+ t.M[2][3] = z;
+ return t;
+ }
+
+ // Sets the translation part
+ void SetTranslation(const Vector3<T>& v) {
+ M[0][3] = v.x;
+ M[1][3] = v.y;
+ M[2][3] = v.z;
+ }
+
+ Vector3<T> GetTranslation() const {
+ return Vector3<T>(M[0][3], M[1][3], M[2][3]);
+ }
+
+ // Creates a matrix for scaling by vector
+ static Matrix4 Scaling(const Vector3<T>& v) {
+ Matrix4 t;
+ t.M[0][0] = v.x;
+ t.M[1][1] = v.y;
+ t.M[2][2] = v.z;
+ return t;
+ }
+
+ // Creates a matrix for scaling by vector
+ static Matrix4 Scaling(T x, T y, T z) {
+ Matrix4 t;
+ t.M[0][0] = x;
+ t.M[1][1] = y;
+ t.M[2][2] = z;
+ return t;
+ }
+
+ // Creates a matrix for scaling by constant
+ static Matrix4 Scaling(T s) {
+ Matrix4 t;
+ t.M[0][0] = s;
+ t.M[1][1] = s;
+ t.M[2][2] = s;
+ return t;
+ }
+
+ // Simple L1 distance in R^12
+ T Distance(const Matrix4& m2) const {
+ T d = fabs(M[0][0] - m2.M[0][0]) + fabs(M[0][1] - m2.M[0][1]);
+ d += fabs(M[0][2] - m2.M[0][2]) + fabs(M[0][3] - m2.M[0][3]);
+ d += fabs(M[1][0] - m2.M[1][0]) + fabs(M[1][1] - m2.M[1][1]);
+ d += fabs(M[1][2] - m2.M[1][2]) + fabs(M[1][3] - m2.M[1][3]);
+ d += fabs(M[2][0] - m2.M[2][0]) + fabs(M[2][1] - m2.M[2][1]);
+ d += fabs(M[2][2] - m2.M[2][2]) + fabs(M[2][3] - m2.M[2][3]);
+ d += fabs(M[3][0] - m2.M[3][0]) + fabs(M[3][1] - m2.M[3][1]);
+ d += fabs(M[3][2] - m2.M[3][2]) + fabs(M[3][3] - m2.M[3][3]);
+ return d;
+ }
+
+ // Creates a rotation matrix rotating around the X axis by 'angle' radians.
+ // Just for quick testing. Not for final API. Need to remove case.
+ static Matrix4 RotationAxis(Axis A, T angle, RotateDirection d, HandedSystem s) {
+ T sina = s * d * sin(angle);
+ T cosa = cos(angle);
+
+ switch (A) {
+ case Axis_X:
+ return Matrix4(1, 0, 0, 0, cosa, -sina, 0, sina, cosa);
+ case Axis_Y:
+ return Matrix4(cosa, 0, sina, 0, 1, 0, -sina, 0, cosa);
+ case Axis_Z:
+ return Matrix4(cosa, -sina, 0, sina, cosa, 0, 0, 0, 1);
+ default:
+ return Matrix4();
+ }
+ }
+
+ // Creates a rotation matrix rotating around the X axis by 'angle' radians.
+ // Rotation direction is depends on the coordinate system:
+ // RHS (Oculus default): Positive angle values rotate Counter-clockwise (CCW),
+ // while looking in the negative axis direction. This is the
+ // same as looking down from positive axis values towards origin.
+ // LHS: Positive angle values rotate clock-wise (CW), while looking in the
+ // negative axis direction.
+ static Matrix4 RotationX(T angle) {
+ T sina = sin(angle);
+ T cosa = cos(angle);
+ return Matrix4(1, 0, 0, 0, cosa, -sina, 0, sina, cosa);
+ }
+
+ // Creates a rotation matrix rotating around the Y axis by 'angle' radians.
+ // Rotation direction is depends on the coordinate system:
+ // RHS (Oculus default): Positive angle values rotate Counter-clockwise (CCW),
+ // while looking in the negative axis direction. This is the
+ // same as looking down from positive axis values towards origin.
+ // LHS: Positive angle values rotate clock-wise (CW), while looking in the
+ // negative axis direction.
+ static Matrix4 RotationY(T angle) {
+ T sina = (T)sin(angle);
+ T cosa = (T)cos(angle);
+ return Matrix4(cosa, 0, sina, 0, 1, 0, -sina, 0, cosa);
+ }
+
+ // Creates a rotation matrix rotating around the Z axis by 'angle' radians.
+ // Rotation direction is depends on the coordinate system:
+ // RHS (Oculus default): Positive angle values rotate Counter-clockwise (CCW),
+ // while looking in the negative axis direction. This is the
+ // same as looking down from positive axis values towards origin.
+ // LHS: Positive angle values rotate clock-wise (CW), while looking in the
+ // negative axis direction.
+ static Matrix4 RotationZ(T angle) {
+ T sina = sin(angle);
+ T cosa = cos(angle);
+ return Matrix4(cosa, -sina, 0, sina, cosa, 0, 0, 0, 1);
+ }
+
+ // LookAtRH creates a View transformation matrix for right-handed coordinate system.
+ // The resulting matrix points camera from 'eye' towards 'at' direction, with 'up'
+ // specifying the up vector. The resulting matrix should be used with PerspectiveRH
+ // projection.
+ static Matrix4 LookAtRH(const Vector3<T>& eye, const Vector3<T>& at, const Vector3<T>& up) {
+ Vector3<T> z = (eye - at).Normalized(); // Forward
+ Vector3<T> x = up.Cross(z).Normalized(); // Right
+ Vector3<T> y = z.Cross(x);
+
+ Matrix4 m(
+ x.x,
+ x.y,
+ x.z,
+ -(x.Dot(eye)),
+ y.x,
+ y.y,
+ y.z,
+ -(y.Dot(eye)),
+ z.x,
+ z.y,
+ z.z,
+ -(z.Dot(eye)),
+ 0,
+ 0,
+ 0,
+ 1);
+ return m;
+ }
+
+ // LookAtLH creates a View transformation matrix for left-handed coordinate system.
+ // The resulting matrix points camera from 'eye' towards 'at' direction, with 'up'
+ // specifying the up vector.
+ static Matrix4 LookAtLH(const Vector3<T>& eye, const Vector3<T>& at, const Vector3<T>& up) {
+ Vector3<T> z = (at - eye).Normalized(); // Forward
+ Vector3<T> x = up.Cross(z).Normalized(); // Right
+ Vector3<T> y = z.Cross(x);
+
+ Matrix4 m(
+ x.x,
+ x.y,
+ x.z,
+ -(x.Dot(eye)),
+ y.x,
+ y.y,
+ y.z,
+ -(y.Dot(eye)),
+ z.x,
+ z.y,
+ z.z,
+ -(z.Dot(eye)),
+ 0,
+ 0,
+ 0,
+ 1);
+ return m;
+ }
+
+ // PerspectiveRH creates a right-handed perspective projection matrix that can be
+ // used with the Oculus sample renderer.
+ // yfov - Specifies vertical field of view in radians.
+ // aspect - Screen aspect ration, which is usually width/height for square pixels.
+ // Note that xfov = yfov * aspect.
+ // znear - Absolute value of near Z clipping clipping range.
+ // zfar - Absolute value of far Z clipping clipping range (larger then near).
+ // Even though RHS usually looks in the direction of negative Z, positive values
+ // are expected for znear and zfar.
+ static Matrix4 PerspectiveRH(T yfov, T aspect, T znear, T zfar) {
+ Matrix4 m;
+ T tanHalfFov = (T)tan(yfov * T(0.5));
+
+ m.M[0][0] = T(1) / (aspect * tanHalfFov);
+ m.M[1][1] = T(1) / tanHalfFov;
+ m.M[2][2] = zfar / (znear - zfar);
+ m.M[3][2] = T(-1);
+ m.M[2][3] = (zfar * znear) / (znear - zfar);
+ m.M[3][3] = T(0);
+
+ // Note: Post-projection matrix result assumes Left-Handed coordinate system,
+ // with Y up, X right and Z forward. This supports positive z-buffer values.
+ // This is the case even for RHS coordinate input.
+ return m;
+ }
+
+ // PerspectiveLH creates a left-handed perspective projection matrix that can be
+ // used with the Oculus sample renderer.
+ // yfov - Specifies vertical field of view in radians.
+ // aspect - Screen aspect ration, which is usually width/height for square pixels.
+ // Note that xfov = yfov * aspect.
+ // znear - Absolute value of near Z clipping clipping range.
+ // zfar - Absolute value of far Z clipping clipping range (larger then near).
+ static Matrix4 PerspectiveLH(T yfov, T aspect, T znear, T zfar) {
+ Matrix4 m;
+ T tanHalfFov = (T)tan(yfov * T(0.5));
+
+ m.M[0][0] = T(1) / (aspect * tanHalfFov);
+ m.M[1][1] = T(1) / tanHalfFov;
+ // m.M[2][2] = zfar / (znear - zfar);
+ m.M[2][2] = zfar / (zfar - znear);
+ m.M[3][2] = T(-1);
+ m.M[2][3] = (zfar * znear) / (znear - zfar);
+ m.M[3][3] = T(0);
+
+ // Note: Post-projection matrix result assumes Left-Handed coordinate system,
+ // with Y up, X right and Z forward. This supports positive z-buffer values.
+ // This is the case even for RHS coordinate input.
+ return m;
+ }
+
+ static Matrix4 Ortho2D(T w, T h) {
+ Matrix4 m;
+ m.M[0][0] = T(2.0) / w;
+ m.M[1][1] = T(-2.0) / h;
+ m.M[0][3] = T(-1.0);
+ m.M[1][3] = T(1.0);
+ m.M[2][2] = T(0);
+ return m;
+ }
+};
+
+typedef Matrix4<float> Matrix4f;
+typedef Matrix4<double> Matrix4d;
+
+//-------------------------------------------------------------------------------------
+// ***** Matrix3
+//
+// Matrix3 is a 3x3 matrix used for representing a rotation matrix.
+// The matrix is stored in row-major order in memory, meaning that values
+// of the first row are stored before the next one.
+//
+// The arrangement of the matrix is chosen to be in Right-Handed
+// coordinate system and counterclockwise rotations when looking down
+// the axis
+//
+// Transformation Order:
+// - Transformations are applied from right to left, so the expression
+// M1 * M2 * M3 * V means that the vector V is transformed by M3 first,
+// followed by M2 and M1.
+//
+// Coordinate system: Right Handed
+//
+// Rotations: Counterclockwise when looking down the axis. All angles are in radians.
+
+template <class T>
+class Matrix3 {
+ public:
+ typedef T ElementType;
+ static const size_t Dimension = 3;
+
+ T M[3][3];
+
+ enum NoInitType { NoInit };
+
+ // Construct with no memory initialization.
+ Matrix3(NoInitType) {}
+
+ // By default, we construct identity matrix.
+ Matrix3() {
+ M[0][0] = M[1][1] = M[2][2] = T(1);
+ M[0][1] = M[1][0] = M[2][0] = T(0);
+ M[0][2] = M[1][2] = M[2][1] = T(0);
+ }
+
+ Matrix3(T m11, T m12, T m13, T m21, T m22, T m23, T m31, T m32, T m33) {
+ M[0][0] = m11;
+ M[0][1] = m12;
+ M[0][2] = m13;
+ M[1][0] = m21;
+ M[1][1] = m22;
+ M[1][2] = m23;
+ M[2][0] = m31;
+ M[2][1] = m32;
+ M[2][2] = m33;
+ }
+
+ // Construction from X, Y, Z basis vectors
+ Matrix3(const Vector3<T>& xBasis, const Vector3<T>& yBasis, const Vector3<T>& zBasis) {
+ M[0][0] = xBasis.x;
+ M[0][1] = yBasis.x;
+ M[0][2] = zBasis.x;
+ M[1][0] = xBasis.y;
+ M[1][1] = yBasis.y;
+ M[1][2] = zBasis.y;
+ M[2][0] = xBasis.z;
+ M[2][1] = yBasis.z;
+ M[2][2] = zBasis.z;
+ }
+
+ explicit Matrix3(const Quat<T>& q) {
+ OVR_MATH_ASSERT(q.IsNormalized()); // If this fires, caller has a quat math bug
+ const T tx = q.x + q.x, ty = q.y + q.y, tz = q.z + q.z;
+ const T twx = q.w * tx, twy = q.w * ty, twz = q.w * tz;
+ const T txx = q.x * tx, txy = q.x * ty, txz = q.x * tz;
+ const T tyy = q.y * ty, tyz = q.y * tz, tzz = q.z * tz;
+ M[0][0] = T(1) - (tyy + tzz);
+ M[0][1] = txy - twz;
+ M[0][2] = txz + twy;
+ M[1][0] = txy + twz;
+ M[1][1] = T(1) - (txx + tzz);
+ M[1][2] = tyz - twx;
+ M[2][0] = txz - twy;
+ M[2][1] = tyz + twx;
+ M[2][2] = T(1) - (txx + tyy);
+ }
+
+ inline explicit Matrix3(T s) {
+ M[0][0] = M[1][1] = M[2][2] = s;
+ M[0][1] = M[0][2] = M[1][0] = M[1][2] = M[2][0] = M[2][1] = T(0);
+ }
+
+ Matrix3(T m11, T m22, T m33) {
+ M[0][0] = m11;
+ M[0][1] = T(0);
+ M[0][2] = T(0);
+ M[1][0] = T(0);
+ M[1][1] = m22;
+ M[1][2] = T(0);
+ M[2][0] = T(0);
+ M[2][1] = T(0);
+ M[2][2] = m33;
+ }
+
+ explicit Matrix3(const Matrix3<typename Math<T>::OtherFloatType>& src) {
+ for (int i = 0; i < 3; i++)
+ for (int j = 0; j < 3; j++)
+ M[i][j] = (T)src.M[i][j];
+ }
+
+ // C-interop support.
+ Matrix3(const typename CompatibleTypes<Matrix3<T>>::Type& s) {
+ OVR_MATH_STATIC_ASSERT(sizeof(s) == sizeof(Matrix3), "sizeof(s) == sizeof(Matrix3)");
+ memcpy(M, s.M, sizeof(M));
+ }
+
+ operator const typename CompatibleTypes<Matrix3<T>>::Type() const {
+ typename CompatibleTypes<Matrix3<T>>::Type result;
+ OVR_MATH_STATIC_ASSERT(sizeof(result) == sizeof(Matrix3), "sizeof(result) == sizeof(Matrix3)");
+ memcpy(result.M, M, sizeof(M));
+ return result;
+ }
+
+ T operator()(int i, int j) const {
+ return M[i][j];
+ }
+ T& operator()(int i, int j) {
+ return M[i][j];
+ }
+
+ void ToString(char* dest, size_t destsize) const {
+ size_t pos = 0;
+ for (int r = 0; r < 3; r++) {
+ for (int c = 0; c < 3; c++)
+ pos += OVRMath_sprintf(dest + pos, destsize - pos, "%g ", M[r][c]);
+ }
+ }
+
+ static Matrix3 FromString(const char* src) {
+ Matrix3 result;
+ if (src) {
+ for (int r = 0; r < 3; r++) {
+ for (int c = 0; c < 3; c++) {
+ result.M[r][c] = (T)atof(src);
+ while (*src && *src != ' ')
+ src++;
+ while (*src && *src == ' ')
+ src++;
+ }
+ }
+ }
+ return result;
+ }
+
+ static Matrix3 Identity() {
+ return Matrix3();
+ }
+
+ void SetIdentity() {
+ M[0][0] = M[1][1] = M[2][2] = T(1);
+ M[0][1] = M[1][0] = M[2][0] = T(0);
+ M[0][2] = M[1][2] = M[2][1] = T(0);
+ }
+
+ static Matrix3 Diagonal(T m00, T m11, T m22) {
+ return Matrix3(m00, 0, 0, 0, m11, 0, 0, 0, m22);
+ }
+ static Matrix3 Diagonal(const Vector3<T>& v) {
+ return Diagonal(v.x, v.y, v.z);
+ }
+
+ T Trace() const {
+ return M[0][0] + M[1][1] + M[2][2];
+ }
+
+ bool operator==(const Matrix3& b) const {
+ bool isEqual = true;
+ for (int i = 0; i < 3; i++) {
+ for (int j = 0; j < 3; j++)
+ isEqual &= (M[i][j] == b.M[i][j]);
+ }
+
+ return isEqual;
+ }
+
+ Matrix3 operator+(const Matrix3& b) const {
+ Matrix3<T> result(*this);
+ result += b;
+ return result;
+ }
+
+ Matrix3& operator+=(const Matrix3& b) {
+ for (int i = 0; i < 3; i++)
+ for (int j = 0; j < 3; j++)
+ M[i][j] += b.M[i][j];
+ return *this;
+ }
+
+ void operator=(const Matrix3& b) {
+ for (int i = 0; i < 3; i++)
+ for (int j = 0; j < 3; j++)
+ M[i][j] = b.M[i][j];
+ }
+
+ Matrix3 operator-(const Matrix3& b) const {
+ Matrix3 result(*this);
+ result -= b;
+ return result;
+ }
+
+ Matrix3& operator-=(const Matrix3& b) {
+ for (int i = 0; i < 3; i++) {
+ for (int j = 0; j < 3; j++)
+ M[i][j] -= b.M[i][j];
+ }
+
+ return *this;
+ }
+
+ // Multiplies two matrices into destination with minimum copying.
+ static Matrix3& Multiply(Matrix3* d, const Matrix3& a, const Matrix3& b) {
+ OVR_MATH_ASSERT((d != &a) && (d != &b));
+ int i = 0;
+ do {
+ d->M[i][0] = a.M[i][0] * b.M[0][0] + a.M[i][1] * b.M[1][0] + a.M[i][2] * b.M[2][0];
+ d->M[i][1] = a.M[i][0] * b.M[0][1] + a.M[i][1] * b.M[1][1] + a.M[i][2] * b.M[2][1];
+ d->M[i][2] = a.M[i][0] * b.M[0][2] + a.M[i][1] * b.M[1][2] + a.M[i][2] * b.M[2][2];
+ } while ((++i) < 3);
+
+ return *d;
+ }
+
+ Matrix3 operator*(const Matrix3& b) const {
+ Matrix3 result(Matrix3::NoInit);
+ Multiply(&result, *this, b);
+ return result;
+ }
+
+ Matrix3& operator*=(const Matrix3& b) {
+ return Multiply(this, Matrix3(*this), b);
+ }
+
+ Matrix3 operator*(T s) const {
+ Matrix3 result(*this);
+ result *= s;
+ return result;
+ }
+
+ Matrix3& operator*=(T s) {
+ for (int i = 0; i < 3; i++) {
+ for (int j = 0; j < 3; j++)
+ M[i][j] *= s;
+ }
+
+ return *this;
+ }
+
+ Vector3<T> operator*(const Vector3<T>& b) const {
+ Vector3<T> result;
+ result.x = M[0][0] * b.x + M[0][1] * b.y + M[0][2] * b.z;
+ result.y = M[1][0] * b.x + M[1][1] * b.y + M[1][2] * b.z;
+ result.z = M[2][0] * b.x + M[2][1] * b.y + M[2][2] * b.z;
+
+ return result;
+ }
+
+ Matrix3 operator/(T s) const {
+ Matrix3 result(*this);
+ result /= s;
+ return result;
+ }
+
+ Matrix3& operator/=(T s) {
+ for (int i = 0; i < 3; i++) {
+ for (int j = 0; j < 3; j++)
+ M[i][j] /= s;
+ }
+
+ return *this;
+ }
+
+ Vector2<T> Transform(const Vector2<T>& v) const {
+ const T rcpZ = T(1) / (M[2][0] * v.x + M[2][1] * v.y + M[2][2]);
+ return Vector2<T>(
+ (M[0][0] * v.x + M[0][1] * v.y + M[0][2]) * rcpZ,
+ (M[1][0] * v.x + M[1][1] * v.y + M[1][2]) * rcpZ);
+ }
+
+ Vector3<T> Transform(const Vector3<T>& v) const {
+ return Vector3<T>(
+ M[0][0] * v.x + M[0][1] * v.y + M[0][2] * v.z,
+ M[1][0] * v.x + M[1][1] * v.y + M[1][2] * v.z,
+ M[2][0] * v.x + M[2][1] * v.y + M[2][2] * v.z);
+ }
+
+ Matrix3 Transposed() const {
+ return Matrix3(M[0][0], M[1][0], M[2][0], M[0][1], M[1][1], M[2][1], M[0][2], M[1][2], M[2][2]);
+ }
+
+ void Transpose() {
+ *this = Transposed();
+ }
+
+ T SubDet(const size_t* rows, const size_t* cols) const {
+ return M[rows[0]][cols[0]] *
+ (M[rows[1]][cols[1]] * M[rows[2]][cols[2]] - M[rows[1]][cols[2]] * M[rows[2]][cols[1]]) -
+ M[rows[0]][cols[1]] *
+ (M[rows[1]][cols[0]] * M[rows[2]][cols[2]] - M[rows[1]][cols[2]] * M[rows[2]][cols[0]]) +
+ M[rows[0]][cols[2]] *
+ (M[rows[1]][cols[0]] * M[rows[2]][cols[1]] - M[rows[1]][cols[1]] * M[rows[2]][cols[0]]);
+ }
+
+ // M += a*b.t()
+ inline void Rank1Add(const Vector3<T>& a, const Vector3<T>& b) {
+ M[0][0] += a.x * b.x;
+ M[0][1] += a.x * b.y;
+ M[0][2] += a.x * b.z;
+ M[1][0] += a.y * b.x;
+ M[1][1] += a.y * b.y;
+ M[1][2] += a.y * b.z;
+ M[2][0] += a.z * b.x;
+ M[2][1] += a.z * b.y;
+ M[2][2] += a.z * b.z;
+ }
+
+ // M -= a*b.t()
+ inline void Rank1Sub(const Vector3<T>& a, const Vector3<T>& b) {
+ M[0][0] -= a.x * b.x;
+ M[0][1] -= a.x * b.y;
+ M[0][2] -= a.x * b.z;
+ M[1][0] -= a.y * b.x;
+ M[1][1] -= a.y * b.y;
+ M[1][2] -= a.y * b.z;
+ M[2][0] -= a.z * b.x;
+ M[2][1] -= a.z * b.y;
+ M[2][2] -= a.z * b.z;
+ }
+
+ inline Vector3<T> Col(int c) const {
+ return Vector3<T>(M[0][c], M[1][c], M[2][c]);
+ }
+
+ inline Vector3<T> Row(int r) const {
+ return Vector3<T>(M[r][0], M[r][1], M[r][2]);
+ }
+
+ inline Vector3<T> GetColumn(int c) const {
+ return Vector3<T>(M[0][c], M[1][c], M[2][c]);
+ }
+
+ inline Vector3<T> GetRow(int r) const {
+ return Vector3<T>(M[r][0], M[r][1], M[r][2]);
+ }
+
+ inline void SetColumn(int c, const Vector3<T>& v) {
+ M[0][c] = v.x;
+ M[1][c] = v.y;
+ M[2][c] = v.z;
+ }
+
+ inline void SetRow(int r, const Vector3<T>& v) {
+ M[r][0] = v.x;
+ M[r][1] = v.y;
+ M[r][2] = v.z;
+ }
+
+ inline T Determinant() const {
+ const Matrix3<T>& m = *this;
+ T d;
+
+ d = m.M[0][0] * (m.M[1][1] * m.M[2][2] - m.M[1][2] * m.M[2][1]);
+ d -= m.M[0][1] * (m.M[1][0] * m.M[2][2] - m.M[1][2] * m.M[2][0]);
+ d += m.M[0][2] * (m.M[1][0] * m.M[2][1] - m.M[1][1] * m.M[2][0]);
+
+ return d;
+ }
+
+ inline Matrix3<T> Inverse() const {
+ Matrix3<T> a;
+ const Matrix3<T>& m = *this;
+ T d = Determinant();
+
+ OVR_MATH_ASSERT(d != 0);
+ T s = T(1) / d;
+
+ a.M[0][0] = s * (m.M[1][1] * m.M[2][2] - m.M[1][2] * m.M[2][1]);
+ a.M[1][0] = s * (m.M[1][2] * m.M[2][0] - m.M[1][0] * m.M[2][2]);
+ a.M[2][0] = s * (m.M[1][0] * m.M[2][1] - m.M[1][1] * m.M[2][0]);
+
+ a.M[0][1] = s * (m.M[0][2] * m.M[2][1] - m.M[0][1] * m.M[2][2]);
+ a.M[1][1] = s * (m.M[0][0] * m.M[2][2] - m.M[0][2] * m.M[2][0]);
+ a.M[2][1] = s * (m.M[0][1] * m.M[2][0] - m.M[0][0] * m.M[2][1]);
+
+ a.M[0][2] = s * (m.M[0][1] * m.M[1][2] - m.M[0][2] * m.M[1][1]);
+ a.M[1][2] = s * (m.M[0][2] * m.M[1][0] - m.M[0][0] * m.M[1][2]);
+ a.M[2][2] = s * (m.M[0][0] * m.M[1][1] - m.M[0][1] * m.M[1][0]);
+
+ return a;
+ }
+
+ // Outer Product of two column vectors: a * b.Transpose()
+ static Matrix3 OuterProduct(const Vector3<T>& a, const Vector3<T>& b) {
+ return Matrix3(
+ a.x * b.x,
+ a.x * b.y,
+ a.x * b.z,
+ a.y * b.x,
+ a.y * b.y,
+ a.y * b.z,
+ a.z * b.x,
+ a.z * b.y,
+ a.z * b.z);
+ }
+
+ // Vector cross product as a premultiply matrix:
+ // L.Cross(R) = LeftCrossAsMatrix(L) * R
+ static Matrix3 LeftCrossAsMatrix(const Vector3<T>& L) {
+ return Matrix3(T(0), -L.z, +L.y, +L.z, T(0), -L.x, -L.y, +L.x, T(0));
+ }
+
+ // Vector cross product as a premultiply matrix:
+ // L.Cross(R) = RightCrossAsMatrix(R) * L
+ static Matrix3 RightCrossAsMatrix(const Vector3<T>& R) {
+ return Matrix3(T(0), +R.z, -R.y, -R.z, T(0), +R.x, +R.y, -R.x, T(0));
+ }
+
+ // Angle in radians of a rotation matrix
+ // Uses identity trace(a) = 2*cos(theta) + 1
+ T Angle() const {
+ return Acos((Trace() - T(1)) * T(0.5));
+ }
+
+ // Angle in radians between two rotation matrices
+ T Angle(const Matrix3& b) const {
+ // Compute trace of (this->Transposed() * b)
+ // This works out to sum of products of elements.
+ T trace = T(0);
+ for (int i = 0; i < 3; i++) {
+ for (int j = 0; j < 3; j++) {
+ trace += M[i][j] * b.M[i][j];
+ }
+ }
+ return Acos((trace - T(1)) * T(0.5));
+ }
+};
+
+typedef Matrix3<float> Matrix3f;
+typedef Matrix3<double> Matrix3d;
+
+//-------------------------------------------------------------------------------------
+// ***** Matrix2
+
+template <class T>
+class Matrix2 {
+ public:
+ typedef T ElementType;
+ static const size_t Dimension = 2;
+
+ T M[2][2];
+
+ enum NoInitType { NoInit };
+
+ // Construct with no memory initialization.
+ Matrix2(NoInitType) {}
+
+ // By default, we construct identity matrix.
+ Matrix2() {
+ M[0][0] = M[1][1] = T(1);
+ M[0][1] = M[1][0] = T(0);
+ }
+
+ Matrix2(T m11, T m12, T m21, T m22) {
+ M[0][0] = m11;
+ M[0][1] = m12;
+ M[1][0] = m21;
+ M[1][1] = m22;
+ }
+
+ // Construction from X, Y basis vectors
+ Matrix2(const Vector2<T>& xBasis, const Vector2<T>& yBasis) {
+ M[0][0] = xBasis.x;
+ M[0][1] = yBasis.x;
+ M[1][0] = xBasis.y;
+ M[1][1] = yBasis.y;
+ }
+
+ explicit Matrix2(T s) {
+ M[0][0] = M[1][1] = s;
+ M[0][1] = M[1][0] = T(0);
+ }
+
+ Matrix2(T m11, T m22) {
+ M[0][0] = m11;
+ M[0][1] = T(0);
+ M[1][0] = T(0);
+ M[1][1] = m22;
+ }
+
+ explicit Matrix2(const Matrix2<typename Math<T>::OtherFloatType>& src) {
+ M[0][0] = T(src.M[0][0]);
+ M[0][1] = T(src.M[0][1]);
+ M[1][0] = T(src.M[1][0]);
+ M[1][1] = T(src.M[1][1]);
+ }
+
+ // C-interop support
+ Matrix2(const typename CompatibleTypes<Matrix2<T>>::Type& s) {
+ OVR_MATH_STATIC_ASSERT(sizeof(s) == sizeof(Matrix2), "sizeof(s) == sizeof(Matrix2)");
+ memcpy(M, s.M, sizeof(M));
+ }
+
+ operator const typename CompatibleTypes<Matrix2<T>>::Type() const {
+ typename CompatibleTypes<Matrix2<T>>::Type result;
+ OVR_MATH_STATIC_ASSERT(sizeof(result) == sizeof(Matrix2), "sizeof(result) == sizeof(Matrix2)");
+ memcpy(result.M, M, sizeof(M));
+ return result;
+ }
+
+ T operator()(int i, int j) const {
+ return M[i][j];
+ }
+ T& operator()(int i, int j) {
+ return M[i][j];
+ }
+ const T* operator[](int i) const {
+ return M[i];
+ }
+ T* operator[](int i) {
+ return M[i];
+ }
+
+ static Matrix2 Identity() {
+ return Matrix2();
+ }
+
+ void SetIdentity() {
+ M[0][0] = M[1][1] = T(1);
+ M[0][1] = M[1][0] = T(0);
+ }
+
+ static Matrix2 Diagonal(T m00, T m11) {
+ return Matrix2(m00, m11);
+ }
+ static Matrix2 Diagonal(const Vector2<T>& v) {
+ return Matrix2(v.x, v.y);
+ }
+
+ T Trace() const {
+ return M[0][0] + M[1][1];
+ }
+
+ bool operator==(const Matrix2& b) const {
+ return M[0][0] == b.M[0][0] && M[0][1] == b.M[0][1] && M[1][0] == b.M[1][0] &&
+ M[1][1] == b.M[1][1];
+ }
+
+ Matrix2 operator+(const Matrix2& b) const {
+ return Matrix2(
+ M[0][0] + b.M[0][0], M[0][1] + b.M[0][1], M[1][0] + b.M[1][0], M[1][1] + b.M[1][1]);
+ }
+
+ Matrix2& operator+=(const Matrix2& b) {
+ M[0][0] += b.M[0][0];
+ M[0][1] += b.M[0][1];
+ M[1][0] += b.M[1][0];
+ M[1][1] += b.M[1][1];
+ return *this;
+ }
+
+ void operator=(const Matrix2& b) {
+ M[0][0] = b.M[0][0];
+ M[0][1] = b.M[0][1];
+ M[1][0] = b.M[1][0];
+ M[1][1] = b.M[1][1];
+ }
+
+ Matrix2 operator-(const Matrix2& b) const {
+ return Matrix2(
+ M[0][0] - b.M[0][0], M[0][1] - b.M[0][1], M[1][0] - b.M[1][0], M[1][1] - b.M[1][1]);
+ }
+
+ Matrix2& operator-=(const Matrix2& b) {
+ M[0][0] -= b.M[0][0];
+ M[0][1] -= b.M[0][1];
+ M[1][0] -= b.M[1][0];
+ M[1][1] -= b.M[1][1];
+ return *this;
+ }
+
+ Matrix2 operator*(const Matrix2& b) const {
+ return Matrix2(
+ M[0][0] * b.M[0][0] + M[0][1] * b.M[1][0],
+ M[0][0] * b.M[0][1] + M[0][1] * b.M[1][1],
+ M[1][0] * b.M[0][0] + M[1][1] * b.M[1][0],
+ M[1][0] * b.M[0][1] + M[1][1] * b.M[1][1]);
+ }
+
+ Matrix2& operator*=(const Matrix2& b) {
+ *this = *this * b;
+ return *this;
+ }
+
+ Matrix2 operator*(T s) const {
+ return Matrix2(M[0][0] * s, M[0][1] * s, M[1][0] * s, M[1][1] * s);
+ }
+
+ Matrix2& operator*=(T s) {
+ M[0][0] *= s;
+ M[0][1] *= s;
+ M[1][0] *= s;
+ M[1][1] *= s;
+ return *this;
+ }
+
+ Matrix2 operator/(T s) const {
+ return *this * (T(1) / s);
+ }
+
+ Matrix2& operator/=(T s) {
+ return *this *= (T(1) / s);
+ }
+
+ Vector2<T> operator*(const Vector2<T>& b) const {
+ return Vector2<T>(M[0][0] * b.x + M[0][1] * b.y, M[1][0] * b.x + M[1][1] * b.y);
+ }
+
+ Vector2<T> Transform(const Vector2<T>& v) const {
+ return Vector2<T>(M[0][0] * v.x + M[0][1] * v.y, M[1][0] * v.x + M[1][1] * v.y);
+ }
+
+ Matrix2 Transposed() const {
+ return Matrix2(M[0][0], M[1][0], M[0][1], M[1][1]);
+ }
+
+ void Transpose() {
+ OVRMath_Swap(M[1][0], M[0][1]);
+ }
+
+ Vector2<T> GetColumn(int c) const {
+ return Vector2<T>(M[0][c], M[1][c]);
+ }
+
+ Vector2<T> GetRow(int r) const {
+ return Vector2<T>(M[r][0], M[r][1]);
+ }
+
+ void SetColumn(int c, const Vector2<T>& v) {
+ M[0][c] = v.x;
+ M[1][c] = v.y;
+ }
+
+ void SetRow(int r, const Vector2<T>& v) {
+ M[r][0] = v.x;
+ M[r][1] = v.y;
+ }
+
+ T Determinant() const {
+ return M[0][0] * M[1][1] - M[0][1] * M[1][0];
+ }
+
+ Matrix2 Inverse() const {
+ T rcpDet = T(1) / Determinant();
+ return Matrix2(M[1][1] * rcpDet, -M[0][1] * rcpDet, -M[1][0] * rcpDet, M[0][0] * rcpDet);
+ }
+
+ // Outer Product of two column vectors: a * b.Transpose()
+ static Matrix2 OuterProduct(const Vector2<T>& a, const Vector2<T>& b) {
+ return Matrix2(a.x * b.x, a.x * b.y, a.y * b.x, a.y * b.y);
+ }
+
+ // Angle in radians between two rotation matrices
+ T Angle(const Matrix2& b) const {
+ const Matrix2& a = *this;
+ return Acos(a(0, 0) * b(0, 0) + a(1, 0) * b(1, 0));
+ }
+};
+
+typedef Matrix2<float> Matrix2f;
+typedef Matrix2<double> Matrix2d;
+
+//-------------------------------------------------------------------------------------
+
+template <class T>
+class SymMat3 {
+ private:
+ typedef SymMat3<T> this_type;
+
+ public:
+ typedef T Value_t;
+ // Upper symmetric
+ T v[6]; // _00 _01 _02 _11 _12 _22
+
+ inline SymMat3() {}
+
+ inline explicit SymMat3(T s) {
+ v[0] = v[3] = v[5] = s;
+ v[1] = v[2] = v[4] = T(0);
+ }
+
+ inline explicit SymMat3(T a00, T a01, T a02, T a11, T a12, T a22) {
+ v[0] = a00;
+ v[1] = a01;
+ v[2] = a02;
+ v[3] = a11;
+ v[4] = a12;
+ v[5] = a22;
+ }
+
+ // Cast to symmetric Matrix3
+ operator Matrix3<T>() const {
+ return Matrix3<T>(v[0], v[1], v[2], v[1], v[3], v[4], v[2], v[4], v[5]);
+ }
+
+ static inline int Index(unsigned int i, unsigned int j) {
+ return (i <= j) ? (3 * i - i * (i + 1) / 2 + j) : (3 * j - j * (j + 1) / 2 + i);
+ }
+
+ inline T operator()(int i, int j) const {
+ return v[Index(i, j)];
+ }
+
+ inline T& operator()(int i, int j) {
+ return v[Index(i, j)];
+ }
+
+ inline this_type& operator+=(const this_type& b) {
+ v[0] += b.v[0];
+ v[1] += b.v[1];
+ v[2] += b.v[2];
+ v[3] += b.v[3];
+ v[4] += b.v[4];
+ v[5] += b.v[5];
+ return *this;
+ }
+
+ inline this_type& operator-=(const this_type& b) {
+ v[0] -= b.v[0];
+ v[1] -= b.v[1];
+ v[2] -= b.v[2];
+ v[3] -= b.v[3];
+ v[4] -= b.v[4];
+ v[5] -= b.v[5];
+
+ return *this;
+ }
+
+ inline this_type& operator*=(T s) {
+ v[0] *= s;
+ v[1] *= s;
+ v[2] *= s;
+ v[3] *= s;
+ v[4] *= s;
+ v[5] *= s;
+
+ return *this;
+ }
+
+ inline SymMat3 operator*(T s) const {
+ SymMat3 d;
+ d.v[0] = v[0] * s;
+ d.v[1] = v[1] * s;
+ d.v[2] = v[2] * s;
+ d.v[3] = v[3] * s;
+ d.v[4] = v[4] * s;
+ d.v[5] = v[5] * s;
+
+ return d;
+ }
+
+ // Multiplies two matrices into destination with minimum copying.
+ static SymMat3& Multiply(SymMat3* d, const SymMat3& a, const SymMat3& b) {
+ // _00 _01 _02 _11 _12 _22
+
+ d->v[0] = a.v[0] * b.v[0];
+ d->v[1] = a.v[0] * b.v[1] + a.v[1] * b.v[3];
+ d->v[2] = a.v[0] * b.v[2] + a.v[1] * b.v[4];
+
+ d->v[3] = a.v[3] * b.v[3];
+ d->v[4] = a.v[3] * b.v[4] + a.v[4] * b.v[5];
+
+ d->v[5] = a.v[5] * b.v[5];
+
+ return *d;
+ }
+
+ inline T Determinant() const {
+ const this_type& m = *this;
+ T d;
+
+ d = m(0, 0) * (m(1, 1) * m(2, 2) - m(1, 2) * m(2, 1));
+ d -= m(0, 1) * (m(1, 0) * m(2, 2) - m(1, 2) * m(2, 0));
+ d += m(0, 2) * (m(1, 0) * m(2, 1) - m(1, 1) * m(2, 0));
+
+ return d;
+ }
+
+ inline this_type Inverse() const {
+ this_type a;
+ const this_type& m = *this;
+ T d = Determinant();
+
+ OVR_MATH_ASSERT(d != 0);
+ T s = T(1) / d;
+
+ a(0, 0) = s * (m(1, 1) * m(2, 2) - m(1, 2) * m(2, 1));
+
+ a(0, 1) = s * (m(0, 2) * m(2, 1) - m(0, 1) * m(2, 2));
+ a(1, 1) = s * (m(0, 0) * m(2, 2) - m(0, 2) * m(2, 0));
+
+ a(0, 2) = s * (m(0, 1) * m(1, 2) - m(0, 2) * m(1, 1));
+ a(1, 2) = s * (m(0, 2) * m(1, 0) - m(0, 0) * m(1, 2));
+ a(2, 2) = s * (m(0, 0) * m(1, 1) - m(0, 1) * m(1, 0));
+
+ return a;
+ }
+
+ inline T Trace() const {
+ return v[0] + v[3] + v[5];
+ }
+
+ // M = a*a.t()
+ inline void Rank1(const Vector3<T>& a) {
+ v[0] = a.x * a.x;
+ v[1] = a.x * a.y;
+ v[2] = a.x * a.z;
+ v[3] = a.y * a.y;
+ v[4] = a.y * a.z;
+ v[5] = a.z * a.z;
+ }
+
+ // M += a*a.t()
+ inline void Rank1Add(const Vector3<T>& a) {
+ v[0] += a.x * a.x;
+ v[1] += a.x * a.y;
+ v[2] += a.x * a.z;
+ v[3] += a.y * a.y;
+ v[4] += a.y * a.z;
+ v[5] += a.z * a.z;
+ }
+
+ // M -= a*a.t()
+ inline void Rank1Sub(const Vector3<T>& a) {
+ v[0] -= a.x * a.x;
+ v[1] -= a.x * a.y;
+ v[2] -= a.x * a.z;
+ v[3] -= a.y * a.y;
+ v[4] -= a.y * a.z;
+ v[5] -= a.z * a.z;
+ }
+};
+
+typedef SymMat3<float> SymMat3f;
+typedef SymMat3<double> SymMat3d;
+
+template <class T>
+inline Matrix3<T> operator*(const SymMat3<T>& a, const SymMat3<T>& b) {
+#define AJB_ARBC(r, c) (a(r, 0) * b(0, c) + a(r, 1) * b(1, c) + a(r, 2) * b(2, c))
+ return Matrix3<T>(
+ AJB_ARBC(0, 0),
+ AJB_ARBC(0, 1),
+ AJB_ARBC(0, 2),
+ AJB_ARBC(1, 0),
+ AJB_ARBC(1, 1),
+ AJB_ARBC(1, 2),
+ AJB_ARBC(2, 0),
+ AJB_ARBC(2, 1),
+ AJB_ARBC(2, 2));
+#undef AJB_ARBC
+}
+
+template <class T>
+inline Matrix3<T> operator*(const Matrix3<T>& a, const SymMat3<T>& b) {
+#define AJB_ARBC(r, c) (a(r, 0) * b(0, c) + a(r, 1) * b(1, c) + a(r, 2) * b(2, c))
+ return Matrix3<T>(
+ AJB_ARBC(0, 0),
+ AJB_ARBC(0, 1),
+ AJB_ARBC(0, 2),
+ AJB_ARBC(1, 0),
+ AJB_ARBC(1, 1),
+ AJB_ARBC(1, 2),
+ AJB_ARBC(2, 0),
+ AJB_ARBC(2, 1),
+ AJB_ARBC(2, 2));
+#undef AJB_ARBC
+}
+
+//-------------------------------------------------------------------------------------
+// ***** Angle
+
+// Cleanly representing the algebra of 2D rotations.
+// The operations maintain the angle between -Pi and Pi, the same range as atan2.
+
+template <class T>
+class Angle {
+ public:
+ enum AngularUnits { Radians = 0, Degrees = 1 };
+
+ Angle() : a(0) {}
+
+ // Fix the range to be between -Pi and Pi
+ Angle(T a_, AngularUnits u = Radians)
+ : a((u == Radians) ? a_ : a_ * ((T)MATH_DOUBLE_DEGREETORADFACTOR)) {
+ FixRange();
+ }
+
+ T Get(AngularUnits u = Radians) const {
+ return (u == Radians) ? a : a * ((T)MATH_DOUBLE_RADTODEGREEFACTOR);
+ }
+ void Set(const T& x, AngularUnits u = Radians) {
+ a = (u == Radians) ? x : x * ((T)MATH_DOUBLE_DEGREETORADFACTOR);
+ FixRange();
+ }
+ int Sign() const {
+ if (a == 0)
+ return 0;
+ else
+ return (a > 0) ? 1 : -1;
+ }
+ T Abs() const {
+ return (a >= 0) ? a : -a;
+ }
+
+ bool operator==(const Angle& b) const {
+ return a == b.a;
+ }
+ bool operator!=(const Angle& b) const {
+ return a != b.a;
+ }
+ // bool operator< (const Angle& b) const { return a < a.b; }
+ // bool operator> (const Angle& b) const { return a > a.b; }
+ // bool operator<= (const Angle& b) const { return a <= a.b; }
+ // bool operator>= (const Angle& b) const { return a >= a.b; }
+ // bool operator= (const T& x) { a = x; FixRange(); }
+
+ // These operations assume a is already between -Pi and Pi.
+ Angle& operator+=(const Angle& b) {
+ a = a + b.a;
+ FastFixRange();
+ return *this;
+ }
+ Angle& operator+=(const T& x) {
+ a = a + x;
+ FixRange();
+ return *this;
+ }
+ Angle operator+(const Angle& b) const {
+ Angle res = *this;
+ res += b;
+ return res;
+ }
+ Angle operator+(const T& x) const {
+ Angle res = *this;
+ res += x;
+ return res;
+ }
+ Angle& operator-=(const Angle& b) {
+ a = a - b.a;
+ FastFixRange();
+ return *this;
+ }
+ Angle& operator-=(const T& x) {
+ a = a - x;
+ FixRange();
+ return *this;
+ }
+ Angle operator-(const Angle& b) const {
+ Angle res = *this;
+ res -= b;
+ return res;
+ }
+ Angle operator-(const T& x) const {
+ Angle res = *this;
+ res -= x;
+ return res;
+ }
+ Angle& operator*=(const T& x) {
+ a = a * x;
+ FixRange();
+ return *this;
+ }
+ Angle operator*(const T& x) const {
+ Angle res = *this;
+ res *= x;
+ return res;
+ }
+
+ T Distance(const Angle& b) {
+ T c = fabs(a - b.a);
+ return (c <= ((T)MATH_DOUBLE_PI)) ? c : ((T)MATH_DOUBLE_TWOPI) - c;
+ }
+
+ Angle Lerp(const Angle& b, T f) const {
+ return *this + (b - *this) * f;
+ }
+
+ private:
+ // The stored angle, which should be maintained between -Pi and Pi
+ T a;
+
+ // Fixes the angle range to [-Pi,Pi], but assumes no more than 2Pi away on either side
+ inline void FastFixRange() {
+ if (a < -((T)MATH_DOUBLE_PI))
+ a += ((T)MATH_DOUBLE_TWOPI);
+ else if (a > ((T)MATH_DOUBLE_PI))
+ a -= ((T)MATH_DOUBLE_TWOPI);
+ }
+
+ // Fixes the angle range to [-Pi,Pi] for any given range, but slower then the fast method
+ inline void FixRange() {
+ // do nothing if the value is already in the correct range, since fmod call is expensive
+ if (a >= -((T)MATH_DOUBLE_PI) && a <= ((T)MATH_DOUBLE_PI))
+ return;
+ a = fmod(a, ((T)MATH_DOUBLE_TWOPI));
+ if (a < -((T)MATH_DOUBLE_PI))
+ a += ((T)MATH_DOUBLE_TWOPI);
+ else if (a > ((T)MATH_DOUBLE_PI))
+ a -= ((T)MATH_DOUBLE_TWOPI);
+ }
+};
+
+typedef Angle<float> Anglef;
+typedef Angle<double> Angled;
+
+//-------------------------------------------------------------------------------------
+// ***** Plane
+
+// Consists of a normal vector and distance from the origin where the plane is located.
+
+template <class T>
+class Plane {
+ public:
+ Vector3<T> N;
+ T D;
+
+ Plane() : D(0) {}
+
+ // Normals must already be normalized
+ Plane(const Vector3<T>& n, T d) : N(n), D(d) {}
+ Plane(T x, T y, T z, T d) : N(x, y, z), D(d) {}
+
+ // construct from a point on the plane and the normal
+ Plane(const Vector3<T>& p, const Vector3<T>& n) : N(n), D(-(p.Dot(n))) {}
+
+ // Find the point to plane distance. The sign indicates what side of the plane the point is on (0
+ // = point on plane).
+ T TestSide(const Vector3<T>& p) const {
+ return (N.Dot(p)) + D;
+ }
+
+ Plane<T> Flipped() const {
+ return Plane(-N, -D);
+ }
+
+ void Flip() {
+ N = -N;
+ D = -D;
+ }
+
+ bool operator==(const Plane<T>& rhs) const {
+ return (this->D == rhs.D && this->N == rhs.N);
+ }
+};
+
+typedef Plane<float> Planef;
+typedef Plane<double> Planed;
+
+//-----------------------------------------------------------------------------------
+// ***** ScaleAndOffset
+
+template <class T>
+struct ScaleAndOffset {
+ T Scale;
+ T Offset;
+
+ ScaleAndOffset(float sx = 0.0f, float sy = 0.0f, float ox = 0.0f, float oy = 0.0f)
+ : Scale(sx, sy), Offset(ox, oy) {}
+
+ T ApplyTo(const T& input) const {
+ return input * Scale + Offset;
+ }
+
+ ScaleAndOffset Invert() const {
+ ScaleAndOffset inverted;
+ inverted.Scale = T(1.0f) / this->Scale;
+ inverted.Offset = -(this->Offset) * inverted.Scale;
+ return inverted;
+ }
+
+ // nextSO is the other scale-offset operation that would have normally followed this scale-offset.
+ // Result is a single scale-offset operation that can be applied to an input instead of
+ // two or more separate scale-offset applications on a given Vector2f input.
+ //
+ // So this:
+ // ScaleAndOffset2D so1, so2, so3; // initialized to some values
+ // Vector2f input = Vector2f(2.0f, -1.0f);
+ // input = so1.ApplyTo(input);
+ // input = so2.ApplyTo(input);
+ // input = so3.ApplyTo(input);
+ //
+ // equals this:
+ // ScaleAndOffset2D so1, so2, so3; // initialized to some values
+ // so1 = so1.Combine(so2);
+ // so1 = so1.Combine(so3);
+ // Vector2f input = Vector2f(2.0f, -1.0f);
+ // input = so1.ApplyTo(input);
+ //
+ ScaleAndOffset Combine(const ScaleAndOffset& nextSO) const {
+ ScaleAndOffset retValSO;
+ retValSO.Offset = this->Offset * nextSO.Scale + nextSO.Offset;
+ retValSO.Scale = nextSO.Scale * this->Scale;
+ return retValSO;
+ }
+};
+
+typedef ScaleAndOffset<Vector2f> ScaleAndOffset2D;
+typedef ScaleAndOffset<Vector3f> ScaleAndOffset3D;
+
+//-----------------------------------------------------------------------------------
+// ***** FovPort
+
+// FovPort describes Field Of View (FOV) of a viewport.
+// This class has values for up, down, left and right, stored in
+// tangent of the angle units to simplify calculations.
+//
+// As an example, for a standard 90 degree vertical FOV, we would
+// have: { UpTan = tan(90 degrees / 2), DownTan = tan(90 degrees / 2) }.
+//
+// CreateFromRadians/Degrees helper functions can be used to
+// access FOV in different units.
+
+// ***** FovPort
+
+struct FovPort {
+ float UpTan;
+ float DownTan;
+ float LeftTan;
+ float RightTan;
+
+ FovPort(float sideTan = 0.0f)
+ : UpTan(sideTan), DownTan(sideTan), LeftTan(sideTan), RightTan(sideTan) {}
+ FovPort(float u, float d, float l, float r) : UpTan(u), DownTan(d), LeftTan(l), RightTan(r) {}
+
+#ifndef OVR_EXCLUDE_CAPI_FROM_MATH
+ // C-interop support.
+ typedef CompatibleTypes<FovPort>::Type CompatibleType;
+
+ FovPort(const CompatibleType& s)
+ : UpTan(s.UpTan), DownTan(s.DownTan), LeftTan(s.LeftTan), RightTan(s.RightTan) {}
+
+ operator const CompatibleType&() const {
+ OVR_MATH_STATIC_ASSERT(sizeof(FovPort) == sizeof(CompatibleType), "sizeof(FovPort) failure");
+ return reinterpret_cast<const CompatibleType&>(*this);
+ }
+#endif
+
+ static FovPort CreateFromRadians(float horizontalFov, float verticalFov) {
+ FovPort result;
+ result.UpTan = tanf(verticalFov * 0.5f);
+ result.DownTan = tanf(verticalFov * 0.5f);
+ result.LeftTan = tanf(horizontalFov * 0.5f);
+ result.RightTan = tanf(horizontalFov * 0.5f);
+ return result;
+ }
+
+ static FovPort CreateFromDegrees(float horizontalFovDegrees, float verticalFovDegrees) {
+ return CreateFromRadians(DegreeToRad(horizontalFovDegrees), DegreeToRad(verticalFovDegrees));
+ }
+
+ // Get Horizontal/Vertical components of Fov in radians.
+ float GetVerticalFovRadians() const {
+ return atanf(UpTan) + atanf(DownTan);
+ }
+ float GetHorizontalFovRadians() const {
+ return atanf(LeftTan) + atanf(RightTan);
+ }
+ // Get Horizontal/Vertical components of Fov in degrees.
+ float GetVerticalFovDegrees() const {
+ return RadToDegree(GetVerticalFovRadians());
+ }
+ float GetHorizontalFovDegrees() const {
+ return RadToDegree(GetHorizontalFovRadians());
+ }
+
+ // Compute maximum tangent value among all four sides.
+ float GetMaxSideTan() const {
+ return OVRMath_Max(OVRMath_Max(UpTan, DownTan), OVRMath_Max(LeftTan, RightTan));
+ }
+
+ static ScaleAndOffset2D CreateNDCScaleAndOffsetFromFov(FovPort tanHalfFov) {
+ float projXScale = 2.0f / (tanHalfFov.LeftTan + tanHalfFov.RightTan);
+ float projXOffset = (tanHalfFov.LeftTan - tanHalfFov.RightTan) * projXScale * 0.5f;
+ float projYScale = 2.0f / (tanHalfFov.UpTan + tanHalfFov.DownTan);
+ float projYOffset = (tanHalfFov.UpTan - tanHalfFov.DownTan) * projYScale * 0.5f;
+
+ ScaleAndOffset2D result;
+ result.Scale = Vector2f(projXScale, projYScale);
+ result.Offset = Vector2f(projXOffset, projYOffset);
+ // Hey - why is that Y.Offset negated?
+ // It's because a projection matrix transforms from world coords with Y=up,
+ // whereas this is from NDC which is Y=down.
+
+ return result;
+ }
+
+ // Converts Fov Tan angle units to [-1,1] render target NDC space
+ Vector2f TanAngleToRendertargetNDC(Vector2f const& tanEyeAngle) {
+ ScaleAndOffset2D eyeToSourceNDC = CreateNDCScaleAndOffsetFromFov(*this);
+ return tanEyeAngle * eyeToSourceNDC.Scale + eyeToSourceNDC.Offset;
+ }
+
+ // Compute per-channel minimum and maximum of Fov.
+ static FovPort Min(const FovPort& a, const FovPort& b) {
+ FovPort fov(
+ OVRMath_Min(a.UpTan, b.UpTan),
+ OVRMath_Min(a.DownTan, b.DownTan),
+ OVRMath_Min(a.LeftTan, b.LeftTan),
+ OVRMath_Min(a.RightTan, b.RightTan));
+ return fov;
+ }
+
+ static FovPort Max(const FovPort& a, const FovPort& b) {
+ FovPort fov(
+ OVRMath_Max(a.UpTan, b.UpTan),
+ OVRMath_Max(a.DownTan, b.DownTan),
+ OVRMath_Max(a.LeftTan, b.LeftTan),
+ OVRMath_Max(a.RightTan, b.RightTan));
+ return fov;
+ }
+
+ static FovPort Uncant(const FovPort& cantedFov, Quatf canting) {
+ FovPort uncantedFov = cantedFov;
+
+ // make 3D vectors from the FovPorts projected to z=1 plane
+ Vector3f leftUp = Vector3f(cantedFov.LeftTan, -cantedFov.UpTan, 1.0f);
+ Vector3f rightUp = Vector3f(-cantedFov.RightTan, -cantedFov.UpTan, 1.0f);
+ Vector3f leftDown = Vector3f(cantedFov.LeftTan, cantedFov.DownTan, 1.0f);
+ Vector3f rightDown = Vector3f(-cantedFov.RightTan, cantedFov.DownTan, 1.0f);
+
+ // rotate these vectors using the canting specified
+ leftUp = canting.Rotate(leftUp);
+ rightUp = canting.Rotate(rightUp);
+ leftDown = canting.Rotate(leftDown);
+ rightDown = canting.Rotate(rightDown);
+
+ // If the z coordinates of any of the corners end up being really small or negative, then
+ // projection will generate extremely large or inverted frustums and we don't really want that
+ const float kMinValidZ = 0.01f;
+
+ // re-project back to z=1 plane while making sure we don't generate gigantic values (hence max)
+ leftUp /= OVRMath_Max(leftUp.z, kMinValidZ);
+ rightUp /= OVRMath_Max(rightUp.z, kMinValidZ);
+ leftDown /= OVRMath_Max(leftDown.z, kMinValidZ);
+ rightDown /= OVRMath_Max(rightDown.z, kMinValidZ);
+
+ // generate new FovTans as "bounding box" values
+ uncantedFov.UpTan = OVRMath_Max(-leftUp.y, -rightUp.y);
+ uncantedFov.DownTan = OVRMath_Max(leftDown.y, rightDown.y);
+ uncantedFov.LeftTan = OVRMath_Max(leftUp.x, leftDown.x);
+ uncantedFov.RightTan = OVRMath_Max(-rightDown.x, -rightUp.x);
+
+ return uncantedFov;
+ }
+
+ // Widens a given FovPort by specified angle in each direction
+ static FovPort Expand(const FovPort& inFov, float expandAngle) {
+ auto ClampedExpand = [expandAngle](float t) -> float {
+ // We don't want gigantic values coming out of this function, so we limit resulting FOV.
+ // Limit before calling tanf() to avoid wrap around to negative values.
+ const float limitFov = atanf(10.0f);
+ return tanf(OVRMath_Min(OVRMath_Max(atanf(t) + expandAngle, -limitFov), limitFov));
+ };
+
+ FovPort modFov = FovPort(
+ ClampedExpand(inFov.UpTan),
+ ClampedExpand(inFov.DownTan),
+ ClampedExpand(inFov.LeftTan),
+ ClampedExpand(inFov.RightTan));
+
+ return modFov;
+ }
+
+ template <class T>
+ static FovPort ScaleFovPort(const FovPort& fov, OVR::Vector2<T> scaleFactors) {
+ FovPort retFov = FovPort(fov);
+ retFov.LeftTan *= ((scaleFactors.x != 0.0) ? scaleFactors.x : 1.0f);
+ retFov.RightTan *= ((scaleFactors.x != 0.0) ? scaleFactors.x : 1.0f);
+ retFov.UpTan *= ((scaleFactors.y != 0.0) ? scaleFactors.y : 1.0f);
+ retFov.DownTan *= ((scaleFactors.y != 0.0) ? scaleFactors.y : 1.0f);
+ return retFov;
+ }
+};
+
+inline bool isNan(const Vector3d& v) {
+ return v.IsNan();
+}
+
+inline bool isNan(const Vector3f& v) {
+ return v.IsNan();
+}
+
+} // Namespace OVR
+
+#if defined(_MSC_VER)
+#pragma warning(pop)
+#endif
+
+#endif