diff options
author | Sven Gothel <[email protected]> | 2015-03-28 01:43:35 +0100 |
---|---|---|
committer | Sven Gothel <[email protected]> | 2015-03-28 01:43:35 +0100 |
commit | 4207f9c279e832e3afcb3f5fc6cd8d84cb4cfe4c (patch) | |
tree | cf3671058d55b47ab6cb6f36f369928606137628 /LibOVR/Include | |
parent | c29cd1a2fbff6282bab956ad61661ac9d48c4e6e (diff) |
Bump OculusVR RIFT SDK to 0.5.0.1vanilla_0.5.0.1
Diffstat (limited to 'LibOVR/Include')
-rw-r--r-- | LibOVR/Include/Extras/OVR_Math.h | 3663 | ||||
-rw-r--r-- | LibOVR/Include/OVR.h | 12 | ||||
-rw-r--r-- | LibOVR/Include/OVR_CAPI.h | 4 | ||||
-rwxr-xr-x | LibOVR/Include/OVR_CAPI_0_5_0.h | 1178 | ||||
-rw-r--r-- | LibOVR/Include/OVR_CAPI_GL.h | 87 | ||||
-rw-r--r-- | LibOVR/Include/OVR_CAPI_Keys.h | 56 | ||||
-rw-r--r-- | LibOVR/Include/OVR_CAPI_Util.h | 79 | ||||
-rwxr-xr-x | LibOVR/Include/OVR_ErrorCode.h | 66 | ||||
-rw-r--r-- | LibOVR/Include/OVR_Kernel.h | 30 | ||||
-rwxr-xr-x[-rw-r--r--] | LibOVR/Include/OVR_Version.h | 55 |
10 files changed, 5204 insertions, 26 deletions
diff --git a/LibOVR/Include/Extras/OVR_Math.h b/LibOVR/Include/Extras/OVR_Math.h new file mode 100644 index 0000000..91f0b07 --- /dev/null +++ b/LibOVR/Include/Extras/OVR_Math.h @@ -0,0 +1,3663 @@ +/************************************************************************************ + +PublicHeader: OVR_Kernel.h +Filename : OVR_Math.h +Content : Implementation of 3D primitives such as vectors, matrices. +Created : September 4, 2012 +Authors : Andrew Reisse, Michael Antonov, Steve LaValle, + Anna Yershova, Max Katsev, Dov Katz + +Copyright : Copyright 2014 Oculus VR, LLC All Rights reserved. + +Licensed under the Oculus VR Rift SDK License Version 3.2 (the "License"); +you may not use the Oculus VR Rift SDK except in compliance with the License, +which is provided at the time of installation or download, or which +otherwise accompanies this software in either electronic or hard copy form. + +You may obtain a copy of the License at + +http://www.oculusvr.com/licenses/LICENSE-3.2 + +Unless required by applicable law or agreed to in writing, the Oculus VR SDK +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +*************************************************************************************/ + +#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 <math.h> +#include <stdint.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <float.h> +#include "../OVR_CAPI.h" // Currently required due to a dependence on the ovrFovPort_ declaration. + +#if defined(_MSC_VER) + #pragma warning(push) + #pragma warning(disable: 4127) // conditional expression is constant +#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; + +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 Matrix3; +template<class T> class Matrix4; +template<class T> class Pose; +template<class T> class PoseState; + +// 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<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; }; + +//------------------------------------------------------------------------------------// +// ***** 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 4096*Epsilon; +#define MATH_DOUBLE_SINGULARITYRADIUS 1e-12 // about 1-cos(.0001 degree), for gimbal lock numerical problems + +//------------------------------------------------------------------------------------// +// ***** 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 64*EPSILON; +#define MATH_FLOAT_SINGULARITYRADIUS 1e-7f // about 1-cos(.025 degree), for gimbal lock numerical problems + + + +// Single-precision Math constants class. +template<> +class Math<float> +{ +public: + typedef double OtherFloatType; + + 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 +}; + +// 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 +}; + +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; } + +// 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 : acos(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 : asin(x); } +inline double Asin(double x) { return (x > 1.0) ? MATH_DOUBLE_PIOVER2 : (x < -1.0) ? -MATH_DOUBLE_PIOVER2 : asin(x); } + +#if defined(_MSC_VER) + inline int isnan(double x) { return ::_isnan(x); } +#elif !defined(isnan) // Some libraries #define isnan. + inline int isnan(double x) { return ::isnan(x); } +#endif + +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); } + + // Compare two vectors for equality with tolerance. Returns true if vectors match withing tolerance. + bool Compare(const Vector2&b, T tolerance =Math<T>::Tolerance()) + { + return (fabs(b.x-x) < tolerance) && (fabs(b.y-y) < 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 != 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 != 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); + } + + // Compare two vectors for equality with tolerance. Returns true if vectors match withing tolerance. + bool IsEqual(const Vector3&b, T tolerance = Math<T>::Tolerance()) + { + return (fabs(b.x-x) < tolerance) && + (fabs(b.y-y) < tolerance) && + (fabs(b.z-z) < 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 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 != 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 != 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); } +}; + +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 float w_=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); + } + + // Compare two vectors for equality with tolerance. Returns true if vectors match withing tolerance. + bool Compare(const Vector4&b, T tolerance = Math<T>::Tolerance()) + { + return (fabs(b.x-x) < tolerance) && + (fabs(b.y-y) < tolerance) && + (fabs(b.z-z) < tolerance) && + (fabs(b.w-w) < 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);} + + // 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 != 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 != 0) + s = T(1) / s; + return *this * s; + } +}; + +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() + { + } + + 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); + } + + 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; + + + +//----------------------------------------------------------------------------------- +// ***** 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) { } + + 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() == 0) + { + // Assert if the axis is zero, but the angle isn't + OVR_MATH_ASSERT(angle == 0); + x = 0; y = 0; z = 0; w = 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]; + } + + // Explicit identity for clairity, saves ambiguity at callsite about Quat() + // being initialized or not. + static Quat<T> Identity() { return Quat<T>(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= 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 + { + 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 + { + T s; + T sinHalfSquared = x*x + y*y + z*z; + if (sinHalfSquared < T(.0037)) // =~ sin(7/2 degrees)^2 + { + // Max rotation magnitude error is (1 - 2*halfAngle/sin(halfAngle)) = -.0044 radians (.06%) at 7 degrees rotation + s = T(2); + } + 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 .0031 degrees at 5 degrees, or .06% + if (normalize && angleSquared > 0) + { + T invLen = T(1) / sqrt(s * angleSquared + c); // 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; + } + } + + // 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; + } + } + + 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; } + + // Compare two vectors for equality with tolerance. Returns true if vectors match withing tolerance. + bool IsEqual(const Quat&b, T tolerance = Math<T>::Tolerance()) + { + return Abs(Dot(b)) >= 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 2 * Acos(Abs(Dot(q))); + } + + // Normalize + bool IsNormalized() const { return fabs(LengthSq() - T(1)) < Math<T>::Tolerance(); } + + void Normalize() + { + T s = Length(); + if (s != 0) + s = T(1) / s; + *this *= s; + } + + Quat Normalized() const + { + T s = Length(); + if (s != 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) + { + 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); + } + } + } + + // Normalized linear interpolation of quaternions + Quat Lerp(const Quat& b, T s) const + { + return (*this * (T(1) - s) + b * (Dot(b) < 0 ? -s : s)).Normalized(); + } + + // Normalized linear interpolation of quaternions + // WARNING, POSSIBLE BUG: This function doesn't work like Lerp() for other classes! + // If f is 1, then full value is given to *this, not "other" like other Lerp() functions + Quat Nlerp(const Quat& other, T a) + { + T sign = (Dot(other) >= 0) ? 1 : -1; + return (*this * sign * a + other * (1-a)).Normalized(); + } + + // 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 + { + // 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 + { + // 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(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(Vector3<T> angularVelocity, Vector3<T> angularAcceleration, T dt, T dtAcceleration) const + { + (void)dtAcceleration; + + const Vector3<T>& omega = angularVelocity; + const Vector3<T>& omegaDot = angularAcceleration; + + Vector3<T> omega1 = (omega + omegaDot * dtAcceleration); + Vector3<T> W = T(0.5)*dt*((omega + omega1) / T(2) + omega.Cross(omega1)*(dt * T(1)/T(12))); + + // 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(yaw, pitch, roll, Rotate_CCW, Handed_R); + } + + // 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_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_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; + if (c2 < T(-1) + Math<T>::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) - Math<T>::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]); + } + } +}; + +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. + +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) { } + + 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); } + + bool IsEqual(const Pose&b, T tolerance = Math<T>::Tolerance()) + { + return Translation.IsEqual(b.Translation, tolerance) && Rotation.IsEqual(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]); + return Pose<T>(rotation, 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> 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)); + } + + 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, T dtAcceleration) const + { + return Pose(Rotation.TimeIntegrate(angularVelocity, angularAcceleration, dt, dtAcceleration), + Translation + linearVelocity*dt + linearAcceleration*dt*dt / T(2)); + } +}; + +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] = 1; + M[0][1] = M[1][0] = M[2][3] = M[3][1] = 0; + M[0][2] = M[1][2] = M[2][0] = M[3][2] = 0; + M[0][3] = M[1][3] = M[2][1] = M[3][0] = 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] = 0; + M[1][0] = m21; M[1][1] = m22; M[1][2] = m23; M[1][3] = 0; + M[2][0] = m31; M[2][1] = m32; M[2][2] = m33; M[2][3] = 0; + M[3][0] = 0; M[3][1] = 0; M[3][2] = 0; M[3][3] = 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] = 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] = 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] = 0; + M[3][0] = 0; M[3][1] = 0; M[3][2] = 0; M[3][3] = 1; + } + + explicit Matrix4(const Quat<T>& q) + { + 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] = 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] = 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] = 0; + M[3][0] = 0; M[3][1] = 0; M[3][2] = 0; M[3][3] = 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] = 1; + M[0][1] = M[1][0] = M[2][3] = M[3][1] = 0; + M[0][2] = M[1][2] = M[2][0] = M[3][2] = 0; + M[0][3] = M[1][3] = M[2][1] = M[3][0] = 0; + } + + void SetXBasis(const Vector3f & v) + { + M[0][0] = v.x; + M[1][0] = v.y; + M[2][0] = v.z; + } + Vector3f GetXBasis() const + { + return Vector3f(M[0][0], M[1][0], M[2][0]); + } + + void SetYBasis(const Vector3f & v) + { + M[0][1] = v.x; + M[1][1] = v.y; + M[2][1] = v.z; + } + Vector3f GetYBasis() const + { + return Vector3f(M[0][1], M[1][1], M[2][1]); + } + + void SetZBasis(const Vector3f & v) + { + M[0][2] = v.x; + M[1][2] = v.y; + M[2][2] = v.z; + } + Vector3f GetZBasis() const + { + return Vector3f(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; + } + + Vector3<T> Transform(const Vector3<T>& v) const + { + const T rcpW = 1.0f / (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() * (1.0f/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] = 0.0f; + // 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 = -1; + if (((A1 + 1) % 3 == A2) && ((A2 + 1) % 3 == A3)) // Determine whether even permutation + psign = 1; + + T pm = psign*M[A1][A3]; + if (pm < -1.0f + Math<T>::SingularityRadius) + { // South pole singularity + *a = 0; + *b = -S*D*((T)MATH_DOUBLE_PIOVER2); + *c = S*D*atan2( psign*M[A2][A1], M[A2][A2] ); + } + else if (pm > 1.0f - Math<T>::SingularityRadius) + { // North pole singularity + *a = 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] ); + } + + return; + } + + // 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 = -1; + if ((A1 + 1) % 3 == A2) // Determine whether even permutation + psign = 1.0f; + + T c2 = M[A1][A1]; + if (c2 < -1 + Math<T>::SingularityRadius) + { // South pole singularity + *a = 0; + *b = S*D*((T)MATH_DOUBLE_PI); + *c = S*D*atan2( -psign*M[A2][m],M[A2][A2]); + } + else if (c2 > 1.0f - Math<T>::SingularityRadius) + { // North pole singularity + *a = 0; + *b = 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]); + } + return; + } + + // 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 = 0.0f) + { + 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); + } + } + + + // 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 = sin(angle); + T cosa = 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 = tan(yfov * 0.5f); + + m.M[0][0] = 1. / (aspect * tanHalfFov); + m.M[1][1] = 1. / tanHalfFov; + m.M[2][2] = zfar / (znear - zfar); + m.M[3][2] = -1.; + m.M[2][3] = (zfar * znear) / (znear - zfar); + m.M[3][3] = 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 = tan(yfov * 0.5f); + + m.M[0][0] = 1. / (aspect * tanHalfFov); + m.M[1][1] = 1. / tanHalfFov; + //m.M[2][2] = zfar / (znear - zfar); + m.M[2][2] = zfar / (zfar - znear); + m.M[3][2] = -1.; + m.M[2][3] = (zfar * znear) / (znear - zfar); + m.M[3][3] = 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] = 2.0/w; + m.M[1][1] = -2.0/h; + m.M[0][3] = -1.0; + m.M[1][3] = 1.0; + m.M[2][2] = 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] = 1; + M[0][1] = M[1][0] = M[2][0] = 0; + M[0][2] = M[1][2] = M[2][1] = 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) + { + 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] = 0; + } + + Matrix3(T m11, T m22, T m33) + { + M[0][0] = m11; M[0][1] = 0; M[0][2] = 0; + M[1][0] = 0; M[1][1] = m22; M[1][2] = 0; + M[2][0] = 0; M[2][1] = 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] = 1; + M[0][1] = M[1][0] = M[2][0] = 0; + M[0][2] = M[1][2] = M[2][1] = 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 float rcpZ = 1.0f / (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); + } + + // Angle in radians between two rotation matrices + // Uses identity trace(a*b') = 2*cos(theta) + 1 + T Angle(const Matrix3& b) const + { + const Matrix3& a = *this; + return Acos(((a * b.Transposed()).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] = 1; + M[0][1] = M[1][0] = 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] = 0; + } + + Matrix2(T m11, T m22) + { + M[0][0] = m11; M[0][1] = 0; + M[1][0] = 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] = 1; + M[0][1] = M[1][0] = 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; + } + + 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] = 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; } + + T Distance(const Angle& b) { T c = fabs(a - b.a); return (c <= ((T)MATH_DOUBLE_PI)) ? c : ((T)MATH_DOUBLE_TWOPI) - c; } + +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 * 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; + + + + +//----------------------------------------------------------------------------------- +// ***** ScaleAndOffset2D + +struct ScaleAndOffset2D +{ + Vector2f Scale; + Vector2f Offset; + + ScaleAndOffset2D(float sx = 0.0f, float sy = 0.0f, float ox = 0.0f, float oy = 0.0f) + : Scale(sx, sy), Offset(ox, oy) + { } +}; + + +//----------------------------------------------------------------------------------- +// ***** 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) { } + + // C-interop support: FovPort <-> ovrFovPort (implementation in OVR_CAPI.cpp). + FovPort(const ovrFovPort &src) + : UpTan(src.UpTan), DownTan(src.DownTan), LeftTan(src.LeftTan), RightTan(src.RightTan) + { } + + operator ovrFovPort () const + { + ovrFovPort result; + result.LeftTan = LeftTan; + result.RightTan = RightTan; + result.UpTan = UpTan; + result.DownTan = DownTan; + return result; + } + + 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; + } +}; + + +} // Namespace OVR + + +#if defined(_MSC_VER) + #pragma warning(pop) +#endif + + +#endif diff --git a/LibOVR/Include/OVR.h b/LibOVR/Include/OVR.h index b82e452..546e447 100644 --- a/LibOVR/Include/OVR.h +++ b/LibOVR/Include/OVR.h @@ -27,10 +27,14 @@ limitations under the License. #define OVR_h #include "OVR_Version.h" - -#include "../Src/Kernel/OVR_Math.h" - -#include "../Src/OVR_CAPI.h" +#include "OVR_CAPI.h" + +/* The following includes are deprecated from this location and will be removed from a future version of this library. */ +#include "Kernel/OVR_Types.h" +#include "Kernel/OVR_RefCount.h" +#include "Kernel/OVR_Std.h" +#include "Kernel/OVR_Alg.h" +#include "Extras/OVR_Math.h" #endif diff --git a/LibOVR/Include/OVR_CAPI.h b/LibOVR/Include/OVR_CAPI.h new file mode 100644 index 0000000..ab950b6 --- /dev/null +++ b/LibOVR/Include/OVR_CAPI.h @@ -0,0 +1,4 @@ + +// Temporary backward compatibility until we update all our internal code that's dependent on it. +#include "OVR_CAPI_0_5_0.h" + diff --git a/LibOVR/Include/OVR_CAPI_0_5_0.h b/LibOVR/Include/OVR_CAPI_0_5_0.h new file mode 100755 index 0000000..01f0dd8 --- /dev/null +++ b/LibOVR/Include/OVR_CAPI_0_5_0.h @@ -0,0 +1,1178 @@ +/************************************************************************************ + +Filename : OVR_CAPI_0_5_0.h +Content : C Interface to Oculus tracking and rendering. +Copyright : Copyright 2014 Oculus VR, LLC All Rights reserved. + +Licensed under the Oculus VR Rift SDK License Version 3.2 (the "License"); +you may not use the Oculus VR Rift SDK except in compliance with the License, +which is provided at the time of installation or download, or which +otherwise accompanies this software in either electronic or hard copy form. + +You may obtain a copy of the License at + +http://www.oculusvr.com/licenses/LICENSE-3.2 + +Unless required by applicable law or agreed to in writing, the Oculus VR SDK +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +************************************************************************************/ + +/// @file OVR_CAPI_0_5_0.h +/// Exposes all general Rift functionality. + +#ifndef OVR_CAPI_h // We don't use version numbers within this, as all versioned variations of +#define OVR_CAPI_h // this file are currently mutually exclusive. + + +#include "OVR_CAPI_Keys.h" +#include "OVR_Version.h" + + +#include <stdint.h> + +#if defined(_MSC_VER) + #pragma warning(push) + #pragma warning(disable: 4324) // structure was padded due to __declspec(align()) +#endif + + + +//----------------------------------------------------------------------------------- +// ***** OVR_OS +// +#if !defined(OVR_OS_WIN32) && defined(_WIN32) + #define OVR_OS_WIN32 +#endif + +#if !defined(OVR_OS_MAC) && defined(__APPLE__) + #define OVR_OS_MAC +#endif + +#if !defined(OVR_OS_LINUX) && defined(__linux__) + #define OVR_OS_LINUX +#endif + + + +//----------------------------------------------------------------------------------- +// ***** OVR_CPP +// +#if !defined(OVR_CPP) + #if defined(__cplusplus) + #define OVR_CPP(x) x + #else + #define OVR_CPP(x) /* Not C++ */ + #endif +#endif + + + +//----------------------------------------------------------------------------------- +// ***** OVR_CDECL +// +// LibOVR calling convention for 32-bit Windows builds. +// +#if !defined(OVR_CDECL) + #if defined(_WIN32) + #define OVR_CDECL __cdecl + #else + #define OVR_CDECL + #endif +#endif + + + +//----------------------------------------------------------------------------------- +// ***** OVR_EXTERN_C +// +// Defined as extern "C" when built from C++ code. +// +#if !defined(OVR_EXTERN_C) + #ifdef __cplusplus + #define OVR_EXTERN_C extern "C" + #else + #define OVR_EXTERN_C + #endif +#endif + + + +//----------------------------------------------------------------------------------- +// ***** OVR_PUBLIC_FUNCTION / OVR_PRIVATE_FUNCTION +// +// OVR_PUBLIC_FUNCTION - Functions that externally visible from a shared library. Corresponds to Microsoft __dllexport. +// OVR_PUBLIC_CLASS - C++ structs and classes that are externally visible from a shared library. Corresponds to Microsoft __dllexport. +// OVR_PRIVATE_FUNCTION - Functions that are not visible outside of a shared library. They are private to the shared library. +// OVR_PRIVATE_CLASS - C++ structs and classes that are not visible outside of a shared library. They are private to the shared library. +// +// OVR_DLL_BUILD - Used to indicate that the current compilation unit is of a shared library. +// OVR_DLL_IMPORT - Used to indicate that the current compilation unit is a user of the corresponding shared library. +// OVR_DLL_BUILD - used to indicate that the current compilation unit is not a shared library but rather statically linked code. +// +#if !defined(OVR_PUBLIC_FUNCTION) + #if defined(OVR_DLL_BUILD) + #if defined(_WIN32) + #define OVR_PUBLIC_FUNCTION(rval) OVR_EXTERN_C __declspec(dllexport) rval OVR_CDECL + #define OVR_PUBLIC_CLASS __declspec(dllexport) + #define OVR_PRIVATE_FUNCTION + #define OVR_PRIVATE_CLASS + #else + #define OVR_PUBLIC_FUNCTION(rval) OVR_EXTERN_C __attribute__((visibility("default"))) rval OVR_CDECL /* Requires GCC 4.0+ */ + #define OVR_PUBLIC_CLASS __attribute__((visibility("default"))) /* Requires GCC 4.0+ */ + #define OVR_PRIVATE_FUNCTION __attribute__((visibility("hidden"))) + #define OVR_PRIVATE_CLASS __attribute__((visibility("hidden"))) + #endif + #elif defined(OVR_DLL_IMPORT) + #if defined(_WIN32) + #define OVR_PUBLIC_FUNCTION(rval) OVR_EXTERN_C __declspec(dllimport) rval OVR_CDECL + #define OVR_PUBLIC_CLASS __declspec(dllimport) + #define OVR_PRIVATE_FUNCTION + #define OVR_PRIVATE_CLASS + #else + #define OVR_PUBLIC_FUNCTION(rval) OVR_EXTERN_C rval OVR_CDECL + #define OVR_PUBLIC_CLASS + #define OVR_PRIVATE_FUNCTION + #define OVR_PRIVATE_CLASS + #endif + #else // OVR_STATIC_BUILD + #define OVR_PUBLIC_FUNCTION(rval) OVR_EXTERN_C rval OVR_CDECL + #define OVR_PUBLIC_CLASS + #define OVR_PRIVATE_FUNCTION + #define OVR_PRIVATE_CLASS + #endif +#endif + + +//----------------------------------------------------------------------------------- +// ***** OVR_EXPORT +// +// Provided for backward compatibility with older usage. + +#if !defined(OVR_EXPORT) + #ifdef OVR_OS_WIN32 + #define OVR_EXPORT __declspec(dllexport) + #else + #define OVR_EXPORT + #endif +#endif + + + +//----------------------------------------------------------------------------------- +// ***** OVR_ALIGNAS +// + +#if !defined(OVR_ALIGNAS) + // C++11 alignas + #if defined(__GNUC__) && (((__GNUC__ * 100) + __GNUC_MINOR__) >= 408) && (defined(__GXX_EXPERIMENTAL_CXX0X__) || (__cplusplus >= 201103L)) + #define OVR_ALIGNAS(n) alignas(n) + #elif defined(__clang__) && !defined(__APPLE__) && (((__clang_major__ * 100) + __clang_minor__) >= 300) && (__cplusplus >= 201103L) + #define OVR_ALIGNAS(n) alignas(n) + #elif defined(__clang__) && defined(__APPLE__) && (((__clang_major__ * 100) + __clang_minor__) >= 401) && (__cplusplus >= 201103L) + #define OVR_ALIGNAS(n) alignas(n) + #elif defined(_MSC_VER) && (_MSC_VER >= 1900) + #define OVR_ALIGNAS(n) alignas(n) + #elif defined(__EDG_VERSION__) && (__EDG_VERSION__ >= 408) + #define OVR_ALIGNAS(n) alignas(n) + + // Pre-C++11 alignas fallbacks + #elif defined(__GNUC__) || defined(__clang__) + #define OVR_ALIGNAS(n) __attribute__((aligned(n))) + #elif defined(_MSC_VER) || defined(__INTEL_COMPILER) + #define OVR_ALIGNAS(n) __declspec(align(n)) // For Microsoft the alignment must be a literal integer. + #elif defined(__CC_ARM) + #define OVR_ALIGNAS(n) __align(n) + #else + #error Need to define OVR_ALIGNAS + #endif +#endif + + +//----------------------------------------------------------------------------------- +// ***** ovrBool + +typedef char ovrBool; +#define ovrFalse 0 +#define ovrTrue 1 + + +//----------------------------------------------------------------------------------- +// ***** Simple Math Structures + +/// A 2D vector with integer components. +typedef struct ovrVector2i_ +{ + int x, y; +} ovrVector2i; + +/// A 2D size with integer components. +typedef struct ovrSizei_ +{ + int w, h; +} ovrSizei; +/// A 2D rectangle with a position and size. +/// All components are integers. +typedef struct ovrRecti_ +{ + ovrVector2i Pos; + ovrSizei Size; +} ovrRecti; + +/// A quaternion rotation. +typedef struct ovrQuatf_ +{ + float x, y, z, w; +} ovrQuatf; + +/// A 2D vector with float components. +typedef struct ovrVector2f_ +{ + float x, y; +} ovrVector2f; + +/// A 3D vector with float components. +typedef struct ovrVector3f_ +{ + float x, y, z; +} ovrVector3f; + +/// A 4x4 matrix with float elements. +typedef struct ovrMatrix4f_ +{ + float M[4][4]; +} ovrMatrix4f; + +/// Position and orientation together. +typedef struct ovrPosef_ +{ + ovrQuatf Orientation; + ovrVector3f Position; +} ovrPosef; + +/// A full pose (rigid body) configuration with first and second derivatives. +typedef struct OVR_ALIGNAS(8) ovrPoseStatef_ +{ + ovrPosef ThePose; ///< The body's position and orientation. + ovrVector3f AngularVelocity; ///< The body's angular velocity in radians per second. + ovrVector3f LinearVelocity; ///< The body's velocity in meters per second. + ovrVector3f AngularAcceleration; ///< The body's angular acceleration in radians per second per second. + ovrVector3f LinearAcceleration; ///< The body's acceleration in meters per second per second. + float Pad; ///< Unused struct padding. + double TimeInSeconds; ///< Absolute time of this state sample. +} ovrPoseStatef; + +/// Field Of View (FOV) in tangent of the angle units. +/// As an example, for a standard 90 degree vertical FOV, we would +/// have: { UpTan = tan(90 degrees / 2), DownTan = tan(90 degrees / 2) }. +typedef struct ovrFovPort_ +{ + float UpTan; ///< The tangent of the angle between the viewing vector and the top edge of the field of view. + float DownTan; ///< The tangent of the angle between the viewing vector and the bottom edge of the field of view. + float LeftTan; ///< The tangent of the angle between the viewing vector and the left edge of the field of view. + float RightTan; ///< The tangent of the angle between the viewing vector and the right edge of the field of view. +} ovrFovPort; + +//----------------------------------------------------------------------------------- +// ***** HMD Types + +/// Enumerates all HMD types that we support. +typedef enum ovrHmdType_ +{ + ovrHmd_None = 0, + ovrHmd_DK1 = 3, + ovrHmd_DKHD = 4, + ovrHmd_DK2 = 6, + ovrHmd_BlackStar = 7, + ovrHmd_CB = 8, + ovrHmd_Other = 9, + ovrHmd_EnumSize = 0x7fffffff ///< Force type int32_t. +} ovrHmdType; + +/// HMD capability bits reported by device. +typedef enum ovrHmdCaps_ +{ + // Read-only flags. + ovrHmdCap_Present = 0x0001, ///< (read only) The HMD is plugged in and detected by the system. + ovrHmdCap_Available = 0x0002, ///< (read only) The HMD and its sensor are available for ownership use. + ///< i.e. it is not already owned by another application. + ovrHmdCap_Captured = 0x0004, ///< (read only) Set to 'true' if we captured ownership of this HMD. + ovrHmdCap_ExtendDesktop = 0x0008, ///< (read only) Means the display driver works via acting as an addition display monitor. + ovrHmdCap_DebugDevice = 0x0010, ///< (read only) Means HMD device is a virtual debug device. + + // Modifiable flags (through ovrHmd_SetEnabledCaps). + ovrHmdCap_NoMirrorToWindow = 0x2000, ///< Disables mirroring of HMD output to the window. This may improve + ///< rendering performance slightly (only if 'ExtendDesktop' is off). + ovrHmdCap_DisplayOff = 0x0040, ///< Turns off HMD screen and output (only if 'ExtendDesktop' is off). + ovrHmdCap_LowPersistence = 0x0080, ///< HMD supports low persistence mode. + ovrHmdCap_DynamicPrediction = 0x0200, ///< Adjust prediction dynamically based on internally measured latency. + ovrHmdCap_NoVSync = 0x1000, ///< Support rendering without VSync for debugging. + + // These bits can be modified by ovrHmd_SetEnabledCaps. + ovrHmdCap_Writable_Mask = ovrHmdCap_NoMirrorToWindow | + ovrHmdCap_DisplayOff | + ovrHmdCap_LowPersistence | + ovrHmdCap_DynamicPrediction | + ovrHmdCap_NoVSync, + + /// These flags are currently passed into the service. May change without notice. + ovrHmdCap_Service_Mask = ovrHmdCap_NoMirrorToWindow | + ovrHmdCap_DisplayOff | + ovrHmdCap_LowPersistence | + ovrHmdCap_DynamicPrediction + , ovrHmdCap_EnumSize = 0x7fffffff ///< Force type int32_t. +} ovrHmdCaps; + + +/// Tracking capability bits reported by the device. +/// Used with ovrHmd_ConfigureTracking. +typedef enum ovrTrackingCaps_ +{ + ovrTrackingCap_Orientation = 0x0010, ///< Supports orientation tracking (IMU). + ovrTrackingCap_MagYawCorrection = 0x0020, ///< Supports yaw drift correction via a magnetometer or other means. + ovrTrackingCap_Position = 0x0040, ///< Supports positional tracking. + /// Overrides the other flags. Indicates that the application + /// doesn't care about tracking settings. This is the internal + /// default before ovrHmd_ConfigureTracking is called. + ovrTrackingCap_Idle = 0x0100, + ovrTrackingCap_EnumSize = 0x7fffffff ///< Force type int32_t. +} ovrTrackingCaps; + +/// Distortion capability bits reported by device. +/// Used with ovrHmd_ConfigureRendering and ovrHmd_CreateDistortionMesh. +typedef enum ovrDistortionCaps_ +{ + // 0x01 unused - Previously ovrDistortionCap_Chromatic now enabled permanently. + ovrDistortionCap_TimeWarp = 0x02, ///< Supports timewarp. + // 0x04 unused + + ovrDistortionCap_Vignette = 0x08, ///< Supports vignetting around the edges of the view. + ovrDistortionCap_NoRestore = 0x10, ///< Do not save and restore the graphics and compute state when rendering distortion. + ovrDistortionCap_FlipInput = 0x20, ///< Flip the vertical texture coordinate of input images. + ovrDistortionCap_SRGB = 0x40, ///< Assume input images are in sRGB gamma-corrected color space. + ovrDistortionCap_Overdrive = 0x80, ///< Overdrive brightness transitions to reduce artifacts on DK2+ displays + ovrDistortionCap_HqDistortion = 0x100, ///< High-quality sampling of distortion buffer for anti-aliasing + ovrDistortionCap_LinuxDevFullscreen = 0x200, ///< Indicates window is fullscreen on a device when set. The SDK will automatically apply distortion mesh rotation if needed. + ovrDistortionCap_ComputeShader = 0x400, ///< Using compute shader (DX11+ only) + //ovrDistortionCap_NoTimewarpJit = 0x800 RETIRED - do not reuse this bit without major versioning changes. + ovrDistortionCap_TimewarpJitDelay = 0x1000, ///< Enables a spin-wait that tries to push time-warp to be as close to V-sync as possible. WARNING - this may backfire and cause framerate loss - use with caution. + + ovrDistortionCap_ProfileNoSpinWaits = 0x10000, ///< Use when profiling with timewarp to remove false positives + ovrDistortionCap_EnumSize = 0x7fffffff ///< Force type int32_t. +} ovrDistortionCaps; + +/// Specifies which eye is being used for rendering. +/// This type explicitly does not include a third "NoStereo" option, as such is +/// not required for an HMD-centered API. +typedef enum ovrEyeType_ +{ + ovrEye_Left = 0, + ovrEye_Right = 1, + ovrEye_Count = 2, + ovrEye_EnumSize = 0x7fffffff ///< Force type int32_t. +} ovrEyeType; + +/// This is a complete descriptor of the HMD. +typedef struct ovrHmdDesc_ +{ + /// Internal handle of this HMD. + struct ovrHmdStruct* Handle; + + /// This HMD's type. + ovrHmdType Type; + + /// Name string describing the product: "Oculus Rift DK1", etc. + const char* ProductName; + /// String describing the manufacturer. Usually "Oculus". + const char* Manufacturer; + + /// HID Vendor ID of the device. + short VendorId; + /// HID Product ID of the device. + short ProductId; + /// Sensor (and display) serial number. + char SerialNumber[24]; + /// Sensor firmware major version number. + short FirmwareMajor; + /// Sensor firmware minor version number. + short FirmwareMinor; + // External tracking camera frustum dimensions (if present). + float CameraFrustumHFovInRadians; ///< Horizontal field-of-view + float CameraFrustumVFovInRadians; ///< Vertical field-of-view + float CameraFrustumNearZInMeters; ///< Near clip distance + float CameraFrustumFarZInMeters; ///< Far clip distance + + /// Capability bits described by ovrHmdCaps. + unsigned int HmdCaps; + /// Capability bits described by ovrTrackingCaps. + unsigned int TrackingCaps; + /// Capability bits described by ovrDistortionCaps. + unsigned int DistortionCaps; + + /// The recommended optical FOV for the HMD. + ovrFovPort DefaultEyeFov[ovrEye_Count]; + /// The maximum optical FOV for the HMD. + ovrFovPort MaxEyeFov[ovrEye_Count]; + + /// Preferred eye rendering order for best performance. + /// Can help reduce latency on sideways-scanned screens. + ovrEyeType EyeRenderOrder[ovrEye_Count]; + + /// Resolution of the full HMD screen (both eyes) in pixels. + ovrSizei Resolution; + /// Location of the application window on the desktop (or 0,0). + ovrVector2i WindowsPos; + + /// Display that the HMD should present on. + /// TBD: It may be good to remove this information relying on WindowPos instead. + /// Ultimately, we may need to come up with a more convenient alternative, + /// such as API-specific functions that return adapter, or something that will + /// work with our monitor driver. + /// Windows: (e.g. "\\\\.\\DISPLAY3", can be used in EnumDisplaySettings/CreateDC). + const char* DisplayDeviceName; + /// MacOS: + int DisplayId; + +} ovrHmdDesc; + +/// Simple type ovrHmd is used in ovrHmd_* calls. +typedef const ovrHmdDesc * ovrHmd; + +/// Bit flags describing the current status of sensor tracking. +// The values must be the same as in enum StatusBits +typedef enum ovrStatusBits_ +{ + ovrStatus_OrientationTracked = 0x0001, ///< Orientation is currently tracked (connected and in use). + ovrStatus_PositionTracked = 0x0002, ///< Position is currently tracked (false if out of range). + ovrStatus_CameraPoseTracked = 0x0004, ///< Camera pose is currently tracked. + ovrStatus_PositionConnected = 0x0020, ///< Position tracking hardware is connected. + ovrStatus_HmdConnected = 0x0080, ///< HMD Display is available and connected. + ovrStatus_EnumSize = 0x7fffffff ///< Force type int32_t. +} ovrStatusBits; + +/// Specifies a reading we can query from the sensor. +typedef struct ovrSensorData_ +{ + ovrVector3f Accelerometer; /// Acceleration reading in m/s^2. + ovrVector3f Gyro; /// Rotation rate in rad/s. + ovrVector3f Magnetometer; /// Magnetic field in Gauss. + float Temperature; /// Temperature of the sensor in degrees Celsius. + float TimeInSeconds; /// Time when the reported IMU reading took place, in seconds. +} ovrSensorData; + + +/// Tracking state at a given absolute time (describes predicted HMD pose etc). +/// Returned by ovrHmd_GetTrackingState. +typedef struct ovrTrackingState_ +{ + /// Predicted head pose (and derivatives) at the requested absolute time. + /// The look-ahead interval is equal to (HeadPose.TimeInSeconds - RawSensorData.TimeInSeconds). + ovrPoseStatef HeadPose; + + /// Current pose of the external camera (if present). + /// This pose includes camera tilt (roll and pitch). For a leveled coordinate + /// system use LeveledCameraPose. + ovrPosef CameraPose; + + /// Camera frame aligned with gravity. + /// This value includes position and yaw of the camera, but not roll and pitch. + /// It can be used as a reference point to render real-world objects in the correct location. + ovrPosef LeveledCameraPose; + + /// The most recent sensor data received from the HMD. + ovrSensorData RawSensorData; + + /// Tracking status described by ovrStatusBits. + unsigned int StatusFlags; + + /// Tag the vision processing results to a certain frame counter number. + uint32_t LastCameraFrameCounter; + + /// Unused struct padding. + uint32_t Pad; +} ovrTrackingState; + + + +/// Frame timing data reported by ovrHmd_BeginFrameTiming() or ovrHmd_BeginFrame(). +typedef struct OVR_ALIGNAS(8) ovrFrameTiming_ +{ + /// The amount of time that has passed since the previous frame's + /// ThisFrameSeconds value (usable for movement scaling). + /// This will be clamped to no more than 0.1 seconds to prevent + /// excessive movement after pauses due to loading or initialization. + float DeltaSeconds; + + /// Unused struct padding. + float Pad; + + /// It is generally expected that the following holds: + /// ThisFrameSeconds < TimewarpPointSeconds < NextFrameSeconds < + /// EyeScanoutSeconds[EyeOrder[0]] <= ScanoutMidpointSeconds <= EyeScanoutSeconds[EyeOrder[1]]. + + /// Absolute time value when rendering of this frame began or is expected to + /// begin. Generally equal to NextFrameSeconds of the previous frame. Can be used + /// for animation timing. + double ThisFrameSeconds; + + /// Absolute point when IMU expects to be sampled for this frame. + double TimewarpPointSeconds; + + /// Absolute time when frame Present followed by GPU Flush will finish and the next frame begins. + double NextFrameSeconds; + + /// Time when half of the screen will be scanned out. Can be passed as an absolute time + /// to ovrHmd_GetTrackingState() to get the predicted general orientation. + double ScanoutMidpointSeconds; + + /// Timing points when each eye will be scanned out to display. Used when rendering each eye. + double EyeScanoutSeconds[2]; +} ovrFrameTiming; + +/// Rendering information for each eye. Computed by either ovrHmd_ConfigureRendering() +/// or ovrHmd_GetRenderDesc() based on the specified FOV. Note that the rendering viewport +/// is not included here as it can be specified separately and modified per frame through: +/// (a) ovrHmd_GetRenderScaleAndOffset in the case of client rendered distortion, +/// or (b) passing different values via ovrTexture in the case of SDK rendered distortion. +typedef struct ovrEyeRenderDesc_ +{ + ovrEyeType Eye; ///< The eye index this instance corresponds to. + ovrFovPort Fov; ///< The field of view. + ovrRecti DistortedViewport; ///< Distortion viewport. + ovrVector2f PixelsPerTanAngleAtCenter; ///< How many display pixels will fit in tan(angle) = 1. + ovrVector3f HmdToEyeViewOffset; ///< Translation to be applied to view matrix for each eye offset. +} ovrEyeRenderDesc; + +/// Rendering information for positional TimeWarp. +/// Contains the data necessary to properly calculate position info for timewarp matrices +/// and also interpret depth info provided via the depth buffer to the timewarp shader +typedef struct ovrPositionTimewarpDesc_ +{ + /// The same offset value pair provided in ovrEyeRenderDesc. + ovrVector3f HmdToEyeViewOffset[2]; + /// The near clip distance used in the projection matrix. + float NearClip; + /// The far clip distance used in the projection matrix + /// utilized when rendering the eye depth textures provided in ovrHmd_EndFrame + float FarClip; +} ovrPositionTimewarpDesc; + +//----------------------------------------------------------------------------------- +// ***** Platform-independent Rendering Configuration + +/// These types are used to hide platform-specific details when passing +/// render device, OS, and texture data to the API. +/// +/// The benefit of having these wrappers versus platform-specific API functions is +/// that they allow game glue code to be portable. A typical example is an +/// engine that has multiple back ends, say GL and D3D. Portable code that calls +/// these back ends may also use LibOVR. To do this, back ends can be modified +/// to return portable types such as ovrTexture and ovrRenderAPIConfig. +typedef enum ovrRenderAPIType_ +{ + ovrRenderAPI_None, + ovrRenderAPI_OpenGL, + ovrRenderAPI_Android_GLES, // May include extra native window pointers, etc. + ovrRenderAPI_D3D9, // Deprecated: Not supported for SDK rendering + ovrRenderAPI_D3D10, // Deprecated: Not supported for SDK rendering + ovrRenderAPI_D3D11, + ovrRenderAPI_Count, + ovrRenderAPI_EnumSize = 0x7fffffff ///< Force type int32_t. +} ovrRenderAPIType; + +/// Platform-independent part of rendering API-configuration data. +/// It is a part of ovrRenderAPIConfig, passed to ovrHmd_Configure. +typedef struct ovrRenderAPIConfigHeader_ +{ + ovrRenderAPIType API; ///< The graphics API in use. + ovrSizei BackBufferSize; ///< Previously named RTSize. + int Multisample; ///< The number of samples per pixel. +} ovrRenderAPIConfigHeader; + +/// Contains platform-specific information for rendering. +typedef struct ovrRenderAPIConfig_ +{ + ovrRenderAPIConfigHeader Header; ///< Platform-independent rendering information. + uintptr_t PlatformData[8]; ///< Platform-specific rendering information. +} ovrRenderAPIConfig; + +/// Platform-independent part of the eye texture descriptor. +/// It is a part of ovrTexture, passed to ovrHmd_EndFrame. +/// If RenderViewport is all zeros then the full texture will be used. +typedef struct ovrTextureHeader_ +{ + ovrRenderAPIType API; ///< The graphics API in use. + ovrSizei TextureSize; ///< The size of the texture. + ovrRecti RenderViewport; ///< Pixel viewport in texture that holds eye image. +} ovrTextureHeader; + +/// Contains platform-specific information about a texture. +/// Specialized for different rendering APIs in: +/// ovrGLTexture, ovrD3D11Texture +typedef struct ovrTexture_ +{ + ovrTextureHeader Header; ///< Platform-independent data about the texture. + uintptr_t PlatformData[8]; ///< Specialized in ovrGLTextureData, ovrD3D11TextureData etc. +} ovrTexture; + + +// ----------------------------------------------------------------------------------- +// ***** API Interfaces + +// Basic steps to use the API: +// +// Setup: +// * ovrInitialize() +// * ovrHMD hmd = ovrHmd_Create(0) +// * Use hmd members and ovrHmd_GetFovTextureSize() to determine graphics configuration. +// * Call ovrHmd_ConfigureTracking() to configure and initialize tracking. +// * Call ovrHmd_ConfigureRendering() to setup graphics for SDK rendering, +// which is the preferred approach. +// Please refer to "Client Distortion Rendering" below if you prefer to do that instead. +// * If the ovrHmdCap_ExtendDesktop flag is not set, then use ovrHmd_AttachToWindow to +// associate the relevant application window with the hmd. +// * Allocate render target textures as needed. +// +// Game Loop: +// * Call ovrHmd_BeginFrame() to get the current frame timing information. +// * Render each eye using ovrHmd_GetEyePoses() to get each eye pose. +// * Call ovrHmd_EndFrame() to render the distorted textures to the back buffer +// and present them on the hmd. +// +// Shutdown: +// * ovrHmd_Destroy(hmd) +// * ovr_Shutdown() +// + +#ifdef __cplusplus +extern "C" { +#endif + + +/// ovr_InitializeRenderingShim initializes the rendering shim apart from everything +/// else in LibOVR. This may be helpful if the application prefers to avoid +/// creating any OVR resources (allocations, service connections, etc) at this point. +/// ovr_InitializeRenderingShim does not bring up anything within LibOVR except the +/// necessary hooks to enable the Direct-to-Rift functionality. +/// +/// Either ovr_InitializeRenderingShim() or ovr_Initialize() must be called before any +/// Direct3D or OpenGL initialization is done by application (creation of devices, etc). +/// ovr_Initialize() must still be called after to use the rest of LibOVR APIs. +/// +/// Same as ovr_InitializeRenderingShim except it requests to support at least the +/// given minor LibOVR library version. +OVR_PUBLIC_FUNCTION(ovrBool) ovr_InitializeRenderingShimVersion(int requestedMinorVersion); + +OVR_PUBLIC_FUNCTION(ovrBool) ovr_InitializeRenderingShim(); + + +/// Library init/shutdown, must be called around all other OVR code. +/// No other functions calls besides ovr_InitializeRenderingShim are allowed before +/// ovr_Initialize succeeds or after ovr_Shutdown. +/// Initializes all Oculus functionality. +/// A second call to ovr_Initialize after successful second call returns ovrTrue. + +/// Flags for Initialize() +typedef enum ovrInitFlags_ +{ + // When a debug library is requested, a slower debugging version of the library will + // be run which can be used to help solve problems in the library and debug game code. + ovrInit_Debug = 0x00000001, + + // When ServerOptional is set, the ovr_Initialize() call not will block waiting for + // the server to respond. If the server is not reachable it may still succeed. + ovrInit_ServerOptional = 0x00000002, + + // When a version is requested, LibOVR runtime will respect the RequestedMinorVersion + // field and will verify that the RequestedMinorVersion is supported. + ovrInit_RequestVersion = 0x00000004, + + // Forces debug features of LibOVR off explicitly, even if it is built in debug mode. + ovrInit_ForceNoDebug = 0x00000008, + +} ovrInitFlags; + +/// Logging levels +typedef enum ovrLogLevel_ +{ + ovrLogLevel_Debug = 0, + ovrLogLevel_Info = 1, + ovrLogLevel_Error = 2 +} ovrLogLevel; + +/// Signature for the logging callback. +/// Level is one of the ovrLogLevel constants. +typedef void (OVR_CDECL *ovrLogCallback)(int level, const char* message); + +/// Parameters for the ovr_Initialize() call. +typedef struct +{ + /// Flags from ovrInitFlags to override default behavior. + /// Pass 0 for the defaults. + uint32_t Flags; ///< Combination of ovrInitFlags or 0 + + /// Request a specific minimum minor version of the LibOVR runtime. + /// Flags must include ovrInit_RequestVersion or this will be ignored. + uint32_t RequestedMinorVersion; + + /// Log callback function, which may be called at any time asynchronously from + /// multiple threads until ovr_Shutdown() completes. + /// Pass 0 for no log callback. + ovrLogCallback LogCallback; ///< Function pointer or 0 + + /// Number of milliseconds to wait for a connection to the server. + /// Pass 0 for the default timeout. + uint32_t ConnectionTimeoutMS; ///< Timeout in Milliseconds or 0 +} ovrInitParams; + +/// Initialize with extra parameters. +/// Pass 0 to initialize with default parameters, suitable for released games. +/// LibOVRRT shared library search order: +/// 1) Current working directory (often the same as the application directory). +/// 2) Module directory (usually the same as the application directory, but not if the module is a separate shared library). +/// 3) Application directory +/// 4) Development directory (only if OVR_ENABLE_DEVELOPER_SEARCH is enabled, which is off by default). +/// 5) Standard OS shared library search location(s) (OS-specific). +OVR_PUBLIC_FUNCTION(ovrBool) ovr_Initialize(ovrInitParams const* params OVR_CPP(= 0)); + +/// Shuts down all Oculus functionality. +OVR_PUBLIC_FUNCTION(void) ovr_Shutdown(); + +/// Returns version string representing libOVR version. Static, so +/// string remains valid for app lifespan +OVR_PUBLIC_FUNCTION(const char*) ovr_GetVersionString(); + +/// Detects or re-detects HMDs and reports the total number detected. +/// Users can get information about each HMD by calling ovrHmd_Create with an index. +/// Returns -1 when the service is unreachable. +OVR_PUBLIC_FUNCTION(int) ovrHmd_Detect(); + +/// Creates a handle to an HMD which doubles as a description structure. +/// Index can [0 .. ovrHmd_Detect()-1]. Index mappings can cange after each ovrHmd_Detect call. +/// If not null, then the returned handle must be freed with ovrHmd_Destroy. +OVR_PUBLIC_FUNCTION(ovrHmd) ovrHmd_Create(int index); +OVR_PUBLIC_FUNCTION(void) ovrHmd_Destroy(ovrHmd hmd); + +/// Creates a 'fake' HMD used for debugging only. This is not tied to specific hardware, +/// but may be used to debug some of the related rendering. +OVR_PUBLIC_FUNCTION(ovrHmd) ovrHmd_CreateDebug(ovrHmdType type); + +/// Returns last error for HMD state. Returns null for no error. +/// String is valid until next call or GetLastError or HMD is destroyed. +/// Pass null hmd to get global errors (during create etc). +OVR_PUBLIC_FUNCTION(const char*) ovrHmd_GetLastError(ovrHmd hmd); + +/// Platform specific function to specify the application window whose output will be +/// displayed on the HMD. Only used if the ovrHmdCap_ExtendDesktop flag is false. +/// Windows: SwapChain associated with this window will be displayed on the HMD. +/// Specify 'destMirrorRect' in window coordinates to indicate an area +/// of the render target output that will be mirrored from 'sourceRenderTargetRect'. +/// Null pointers mean "full size". +/// @note Source and dest mirror rects are not yet implemented. +OVR_PUBLIC_FUNCTION(ovrBool) ovrHmd_AttachToWindow(ovrHmd hmd, void* window, + const ovrRecti* destMirrorRect, + const ovrRecti* sourceRenderTargetRect); + +/// Returns capability bits that are enabled at this time as described by ovrHmdCaps. +/// Note that this value is different font ovrHmdDesc::HmdCaps, which describes what +/// capabilities are available for that HMD. +OVR_PUBLIC_FUNCTION(unsigned int) ovrHmd_GetEnabledCaps(ovrHmd hmd); + +/// Modifies capability bits described by ovrHmdCaps that can be modified, +/// such as ovrHmdCap_LowPersistance. +OVR_PUBLIC_FUNCTION(void) ovrHmd_SetEnabledCaps(ovrHmd hmd, unsigned int hmdCaps); + +//------------------------------------------------------------------------------------- +// ***** Tracking Interface + +/// All tracking interface functions are thread-safe, allowing tracking state to be sampled +/// from different threads. +/// ConfigureTracking starts sensor sampling, enabling specified capabilities, +/// described by ovrTrackingCaps. +/// - supportedTrackingCaps specifies support that is requested. The function will succeed +/// even if these caps are not available (i.e. sensor or camera is unplugged). Support +/// will automatically be enabled if such device is plugged in later. Software should +/// check ovrTrackingState.StatusFlags for real-time status. +/// - requiredTrackingCaps specify sensor capabilities required at the time of the call. +/// If they are not available, the function will fail. Pass 0 if only specifying +/// supportedTrackingCaps. +/// - Pass 0 for both supportedTrackingCaps and requiredTrackingCaps to disable tracking. +OVR_PUBLIC_FUNCTION(ovrBool) ovrHmd_ConfigureTracking(ovrHmd hmd, unsigned int supportedTrackingCaps, + unsigned int requiredTrackingCaps); + +/// Re-centers the sensor orientation. +/// Normally this will recenter the (x,y,z) translational components and the yaw +/// component of orientation. +OVR_PUBLIC_FUNCTION(void) ovrHmd_RecenterPose(ovrHmd hmd); + +/// Returns tracking state reading based on the specified absolute system time. +/// Pass an absTime value of 0.0 to request the most recent sensor reading. In this case +/// both PredictedPose and SamplePose will have the same value. +/// ovrHmd_GetEyePoses relies on a valid ovrTrackingState. +/// This may also be used for more refined timing of FrontBuffer rendering logic, etc. +OVR_PUBLIC_FUNCTION(ovrTrackingState) ovrHmd_GetTrackingState(ovrHmd hmd, double absTime); + + + + + +//------------------------------------------------------------------------------------- +// ***** Graphics Setup + +/// Calculates the recommended viewport size for rendering a given eye within the HMD +/// with a given FOV cone. Higher FOV will generally require larger textures to +/// maintain quality. +/// - pixelsPerDisplayPixel specifies the ratio of the number of render target pixels +/// to display pixels at the center of distortion. 1.0 is the default value. Lower +/// values can improve performance, higher values give improved quality. +/// Apps packing multiple eye views together on the same textue should ensure there is +/// roughly 8 pixels of padding between them to prevent texture filtering and chromatic +/// aberration causing images to "leak" between the two eye views. +OVR_PUBLIC_FUNCTION(ovrSizei) ovrHmd_GetFovTextureSize(ovrHmd hmd, ovrEyeType eye, ovrFovPort fov, + float pixelsPerDisplayPixel); + +//------------------------------------------------------------------------------------- +// ***** Rendering API Thread Safety + +// All of rendering functions including the configure and frame functions +// are *NOT thread safe*. It is ok to use ConfigureRendering on one thread and handle +// frames on another thread, but explicit synchronization must be done since +// functions that depend on configured state are not reentrant. +// +// As an extra requirement, any of the following calls must be done on +// the render thread, which is the same thread that calls ovrHmd_BeginFrame +// or ovrHmd_BeginFrameTiming. +// - ovrHmd_EndFrame +// - ovrHmd_GetEyeTimewarpMatrices + +//------------------------------------------------------------------------------------- +// ***** SDK Distortion Rendering Functions + +// These functions support rendering of distortion by the SDK through direct +// access to the underlying rendering API, such as D3D or GL. +// This is the recommended approach since it allows better support for future +// Oculus hardware, and enables a range of low-level optimizations. + +/// Configures rendering and fills in computed render parameters. +/// This function can be called multiple times to change rendering settings. +/// eyeRenderDescOut is a pointer to an array of two ovrEyeRenderDesc structs +/// that are used to return complete rendering information for each eye. +/// - apiConfig provides D3D/OpenGL specific parameters. Pass null +/// to shutdown rendering and release all resources. +/// - distortionCaps describe desired distortion settings. +OVR_PUBLIC_FUNCTION(ovrBool) ovrHmd_ConfigureRendering(ovrHmd hmd, + const ovrRenderAPIConfig* apiConfig, + unsigned int distortionCaps, + const ovrFovPort eyeFovIn[2], + ovrEyeRenderDesc eyeRenderDescOut[2] ); + + +/// Begins a frame, returning timing information. +/// This should be called at the beginning of the game rendering loop (on the render thread). +/// Pass 0 for the frame index if not using ovrHmd_GetFrameTiming. +OVR_PUBLIC_FUNCTION(ovrFrameTiming) ovrHmd_BeginFrame(ovrHmd hmd, unsigned int frameIndex); + +/// Ends a frame, submitting the rendered textures to the frame buffer. +/// - RenderViewport within each eyeTexture can change per frame if necessary. +/// - 'renderPose' will typically be the value returned from ovrHmd_GetEyePoses +/// but can be different if a different head pose was used for rendering. +/// - This may perform distortion and scaling internally, assuming is it not +/// delegated to another thread. +/// - Must be called on the same thread as BeginFrame. +/// - If ovrDistortionCap_DepthProjectedTimeWarp is enabled, then app must provide eyeDepthTexture +/// and posTimewarpDesc. Otherwise both can be NULL. +/// - *** This Function will call Present/SwapBuffers and potentially wait for GPU Sync ***. +OVR_PUBLIC_FUNCTION(void) ovrHmd_EndFrame(ovrHmd hmd, + const ovrPosef renderPose[2], + const ovrTexture eyeTexture[2]); + +/// Returns predicted head pose in outHmdTrackingState and offset eye poses in outEyePoses +/// as an atomic operation. Caller need not worry about applying HmdToEyeViewOffset to the +/// returned outEyePoses variables. +/// - Thread-safe function where caller should increment frameIndex with every frame +/// and pass the index where applicable to functions called on the rendering thread. +/// - hmdToEyeViewOffset[2] can be ovrEyeRenderDesc.HmdToEyeViewOffset returned from +/// ovrHmd_ConfigureRendering or ovrHmd_GetRenderDesc. For monoscopic rendering, +/// use a vector that is the average of the two vectors for both eyes. +/// - If frameIndex is not being utilized, pass in 0. +/// - Assuming outEyePoses are used for rendering, it should be passed into ovrHmd_EndFrame. +/// - If caller doesn't need outHmdTrackingState, it can be passed in as NULL +OVR_PUBLIC_FUNCTION(void) ovrHmd_GetEyePoses(ovrHmd hmd, unsigned int frameIndex, + const ovrVector3f hmdToEyeViewOffset[2], + ovrPosef outEyePoses[2], + ovrTrackingState* outHmdTrackingState); + +/// Function was previously called ovrHmd_GetEyePose +/// Returns the predicted head pose to use when rendering the specified eye. +/// - Important: Caller must apply HmdToEyeViewOffset before using ovrPosef for rendering +/// - Must be called between ovrHmd_BeginFrameTiming and ovrHmd_EndFrameTiming. +/// - If returned pose is used for rendering the eye, it should be passed to ovrHmd_EndFrame. +/// - Parameter 'eye' is used internally for prediction timing only +OVR_PUBLIC_FUNCTION(ovrPosef) ovrHmd_GetHmdPosePerEye(ovrHmd hmd, ovrEyeType eye); + + +//------------------------------------------------------------------------------------- +// ***** Client Distortion Rendering Functions + +// These functions provide the distortion data and render timing support necessary to allow +// client rendering of distortion. Client-side rendering involves the following steps: +// +// 1. Setup ovrEyeDesc based on the desired texture size and FOV. +// Call ovrHmd_GetRenderDesc to get the necessary rendering parameters for each eye. +// +// 2. Use ovrHmd_CreateDistortionMesh to generate the distortion mesh. +// +// 3. Use ovrHmd_BeginFrameTiming, ovrHmd_GetEyePoses, and ovrHmd_BeginFrameTiming in +// the rendering loop to obtain timing and predicted head orientation when rendering each eye. +// - When using timewarp, use ovr_WaitTillTime after the rendering and gpu flush, followed +// by ovrHmd_GetEyeTimewarpMatrices to obtain the timewarp matrices used +// by the distortion pixel shader. This will minimize latency. +// + +/// Computes the distortion viewport, view adjust, and other rendering parameters for +/// the specified eye. This can be used instead of ovrHmd_ConfigureRendering to do +/// setup for client rendered distortion. +OVR_PUBLIC_FUNCTION(ovrEyeRenderDesc) ovrHmd_GetRenderDesc(ovrHmd hmd, + ovrEyeType eyeType, ovrFovPort fov); + + +/// Describes a vertex used by the distortion mesh. This is intended to be converted into +/// the engine-specific format. Some fields may be unused based on the ovrDistortionCaps +/// flags selected. TexG and TexB, for example, are not used if chromatic correction is +/// not requested. +typedef struct ovrDistortionVertex_ +{ + ovrVector2f ScreenPosNDC; ///< [-1,+1],[-1,+1] over the entire framebuffer. + float TimeWarpFactor; ///< Lerp factor between time-warp matrices. Can be encoded in Pos.z. + float VignetteFactor; ///< Vignette fade factor. Can be encoded in Pos.w. + ovrVector2f TanEyeAnglesR; ///< The tangents of the horizontal and vertical eye angles for the red channel. + ovrVector2f TanEyeAnglesG; ///< The tangents of the horizontal and vertical eye angles for the green channel. + ovrVector2f TanEyeAnglesB; ///< The tangents of the horizontal and vertical eye angles for the blue channel. +} ovrDistortionVertex; + +/// Describes a full set of distortion mesh data, filled in by ovrHmd_CreateDistortionMesh. +/// Contents of this data structure, if not null, should be freed by ovrHmd_DestroyDistortionMesh. +typedef struct ovrDistortionMesh_ +{ + ovrDistortionVertex* pVertexData; ///< The distortion vertices representing each point in the mesh. + unsigned short* pIndexData; ///< Indices for connecting the mesh vertices into polygons. + unsigned int VertexCount; ///< The number of vertices in the mesh. + unsigned int IndexCount; ///< The number of indices in the mesh. +} ovrDistortionMesh; + +/// Generate distortion mesh per eye. +/// Distortion capabilities will depend on 'distortionCaps' flags. Users should +/// render using the appropriate shaders based on their settings. +/// Distortion mesh data will be allocated and written into the ovrDistortionMesh data structure, +/// which should be explicitly freed with ovrHmd_DestroyDistortionMesh. +/// Users should call ovrHmd_GetRenderScaleAndOffset to get uvScale and Offset values for rendering. +/// The function shouldn't fail unless theres is a configuration or memory error, in which case +/// ovrDistortionMesh values will be set to null. +/// This is the only function in the SDK reliant on eye relief, currently imported from profiles, +/// or overridden here. +OVR_PUBLIC_FUNCTION(ovrBool) ovrHmd_CreateDistortionMesh(ovrHmd hmd, + ovrEyeType eyeType, ovrFovPort fov, + unsigned int distortionCaps, + ovrDistortionMesh *meshData); +OVR_PUBLIC_FUNCTION(ovrBool) ovrHmd_CreateDistortionMeshDebug(ovrHmd hmddesc, + ovrEyeType eyeType, ovrFovPort fov, + unsigned int distortionCaps, + ovrDistortionMesh *meshData, + float debugEyeReliefOverrideInMetres); + + +/// Used to free the distortion mesh allocated by ovrHmd_GenerateDistortionMesh. meshData elements +/// are set to null and zeroes after the call. +OVR_PUBLIC_FUNCTION(void) ovrHmd_DestroyDistortionMesh(ovrDistortionMesh* meshData); + +/// Computes updated 'uvScaleOffsetOut' to be used with a distortion if render target size or +/// viewport changes after the fact. This can be used to adjust render size every frame if desired. +OVR_PUBLIC_FUNCTION(void) ovrHmd_GetRenderScaleAndOffset(ovrFovPort fov, + ovrSizei textureSize, ovrRecti renderViewport, + ovrVector2f uvScaleOffsetOut[2] ); + +/// Thread-safe timing function for the main thread. Caller should increment frameIndex +/// with every frame and pass the index where applicable to functions called on the +/// rendering thread. +OVR_PUBLIC_FUNCTION(ovrFrameTiming) ovrHmd_GetFrameTiming(ovrHmd hmd, unsigned int frameIndex); + +/// Called at the beginning of the frame on the rendering thread. +/// Pass frameIndex == 0 if ovrHmd_GetFrameTiming isn't being used. Otherwise, +/// pass the same frame index as was used for GetFrameTiming on the main thread. +OVR_PUBLIC_FUNCTION(ovrFrameTiming) ovrHmd_BeginFrameTiming(ovrHmd hmd, unsigned int frameIndex); + +/// Marks the end of client distortion rendered frame, tracking the necessary timing information. +/// This function must be called immediately after Present/SwapBuffers + GPU sync. GPU sync is +/// important before this call to reduce latency and ensure proper timing. +OVR_PUBLIC_FUNCTION(void) ovrHmd_EndFrameTiming(ovrHmd hmd); + +/// Initializes and resets frame time tracking. This is typically not necessary, but +/// is helpful if game changes vsync state or video mode. vsync is assumed to be on if this +/// isn't called. Resets internal frame index to the specified number. +OVR_PUBLIC_FUNCTION(void) ovrHmd_ResetFrameTiming(ovrHmd hmd, unsigned int frameIndex); + +/// Computes timewarp matrices used by distortion mesh shader, these are used to adjust +/// for head orientation change since the last call to ovrHmd_GetEyePoses +/// when rendering this eye. The ovrDistortionVertex::TimeWarpFactor is used to blend between the +/// matrices, usually representing two different sides of the screen. +/// Set 'calcPosition' to true when using depth based positional timewarp +/// Must be called on the same thread as ovrHmd_BeginFrameTiming. +OVR_PUBLIC_FUNCTION(void) ovrHmd_GetEyeTimewarpMatrices(ovrHmd hmd, ovrEyeType eye, ovrPosef renderPose, + ovrMatrix4f twmOut[2]); +OVR_PUBLIC_FUNCTION(void) ovrHmd_GetEyeTimewarpMatricesDebug(ovrHmd hmddesc, ovrEyeType eye, ovrPosef renderPose, + ovrQuatf playerTorsoMotion, ovrMatrix4f twmOut[2], + double debugTimingOffsetInSeconds); + + + + +//------------------------------------------------------------------------------------- +// ***** Stateless math setup functions + +/// Returns global, absolute high-resolution time in seconds. This is the same +/// value as used in sensor messages. +OVR_PUBLIC_FUNCTION(double) ovr_GetTimeInSeconds(); + + +// ----------------------------------------------------------------------------------- +// ***** Latency Test interface + +/// Does latency test processing and returns 'TRUE' if specified rgb color should +/// be used to clear the screen. +OVR_PUBLIC_FUNCTION(ovrBool) ovrHmd_ProcessLatencyTest(ovrHmd hmd, unsigned char rgbColorOut[3]); + +/// Returns non-null string once with latency test result, when it is available. +/// Buffer is valid until next call. +OVR_PUBLIC_FUNCTION(const char*) ovrHmd_GetLatencyTestResult(ovrHmd hmd); + +/// Returns the latency testing color in rgbColorOut to render when using a DK2 +/// Returns false if this feature is disabled or not-applicable (e.g. using a DK1) +OVR_PUBLIC_FUNCTION(ovrBool) ovrHmd_GetLatencyTest2DrawColor(ovrHmd hmddesc, unsigned char rgbColorOut[3]); + +//------------------------------------------------------------------------------------- +// ***** Health and Safety Warning Display interface +// + +/// Used by ovrhmd_GetHSWDisplayState to report the current display state. +typedef struct OVR_ALIGNAS(8) ovrHSWDisplayState_ +{ + /// If true then the warning should be currently visible + /// and the following variables have meaning. Else there is no + /// warning being displayed for this application on the given HMD. + ovrBool Displayed; ///< True if the Health&Safety Warning is currently displayed. + char Pad[8-sizeof(ovrBool)]; ///< Unused struct padding. + double StartTime; ///< Absolute time when the warning was first displayed. See ovr_GetTimeInSeconds(). + double DismissibleTime; ///< Earliest absolute time when the warning can be dismissed. May be a time in the past. +} ovrHSWDisplayState; + +/// Returns the current state of the HSW display. If the application is doing the rendering of +/// the HSW display then this function serves to indicate that the warning should be +/// currently displayed. If the application is using SDK-based eye rendering then the SDK by +/// default automatically handles the drawing of the HSW display. An application that uses +/// application-based eye rendering should use this function to know when to start drawing the +/// HSW display itself and can optionally use it in conjunction with ovrhmd_DismissHSWDisplay +/// as described below. +/// +/// Example usage for application-based rendering: +/// bool HSWDisplayCurrentlyDisplayed = false; // global or class member variable +/// ovrHSWDisplayState hswDisplayState; +/// ovrhmd_GetHSWDisplayState(Hmd, &hswDisplayState); +/// +/// if (hswDisplayState.Displayed && !HSWDisplayCurrentlyDisplayed) { +/// <insert model into the scene that stays in front of the user> +/// HSWDisplayCurrentlyDisplayed = true; +/// } +OVR_PUBLIC_FUNCTION(void) ovrHmd_GetHSWDisplayState(ovrHmd hmd, ovrHSWDisplayState *hasWarningState); + +/// Requests a dismissal of the HSWDisplay at the earliest possible time, which may be seconds +/// into the future due to display longevity requirements. +/// Returns true if the display is valid, in which case the request can always be honored. +/// +/// Example usage : +/// void ProcessEvent(int key) { +/// if (key == escape) +/// ovrhmd_DismissHSWDisplay(hmd); +/// } +OVR_PUBLIC_FUNCTION(ovrBool) ovrHmd_DismissHSWDisplay(ovrHmd hmd); + +/// Get boolean property. Returns first element if property is a boolean array. +/// Returns defaultValue if property doesn't exist. +OVR_PUBLIC_FUNCTION(ovrBool) ovrHmd_GetBool(ovrHmd hmd, const char* propertyName, ovrBool defaultVal); + +/// Modify bool property; false if property doesn't exist or is readonly. +OVR_PUBLIC_FUNCTION(ovrBool) ovrHmd_SetBool(ovrHmd hmd, const char* propertyName, ovrBool value); + +/// Get integer property. Returns first element if property is an integer array. +/// Returns defaultValue if property doesn't exist. +OVR_PUBLIC_FUNCTION(int) ovrHmd_GetInt(ovrHmd hmd, const char* propertyName, int defaultVal); + +/// Modify integer property; false if property doesn't exist or is readonly. +OVR_PUBLIC_FUNCTION(ovrBool) ovrHmd_SetInt(ovrHmd hmd, const char* propertyName, int value); + +/// Get float property. Returns first element if property is a float array. +/// Returns defaultValue if property doesn't exist. +OVR_PUBLIC_FUNCTION(float) ovrHmd_GetFloat(ovrHmd hmd, const char* propertyName, float defaultVal); + +/// Modify float property; false if property doesn't exist or is readonly. +OVR_PUBLIC_FUNCTION(ovrBool) ovrHmd_SetFloat(ovrHmd hmd, const char* propertyName, float value); + +/// Get float[] property. Returns the number of elements filled in, 0 if property doesn't exist. +/// Maximum of arraySize elements will be written. +OVR_PUBLIC_FUNCTION(unsigned int) ovrHmd_GetFloatArray(ovrHmd hmd, const char* propertyName, + float values[], unsigned int arraySize); + +/// Modify float[] property; false if property doesn't exist or is readonly. +OVR_PUBLIC_FUNCTION(ovrBool) ovrHmd_SetFloatArray(ovrHmd hmd, const char* propertyName, + float values[], unsigned int arraySize); + +/// Get string property. Returns first element if property is a string array. +/// Returns defaultValue if property doesn't exist. +/// String memory is guaranteed to exist until next call to GetString or GetStringArray, or HMD is destroyed. +OVR_PUBLIC_FUNCTION(const char*) ovrHmd_GetString(ovrHmd hmd, const char* propertyName, + const char* defaultVal); + +/// Set string property +OVR_PUBLIC_FUNCTION(ovrBool) ovrHmd_SetString(ovrHmd hmddesc, const char* propertyName, + const char* value); + +// ----------------------------------------------------------------------------------- +// ***** Logging + +/// Send a message string to the system tracing mechanism if enabled (currently Event Tracing for Windows) +/// Level is one of the ovrLogLevel constants. +/// returns the length of the message, or -1 if message is too large +OVR_PUBLIC_FUNCTION(int) ovr_TraceMessage(int level, const char* message); + + +// DEPRECATED: These functions are being phased out in favor of a more comprehensive logging system. +// These functions will return false and do nothing. +OVR_PUBLIC_FUNCTION(ovrBool) ovrHmd_StartPerfLog(ovrHmd hmd, const char* fileName, const char* userData1); +OVR_PUBLIC_FUNCTION(ovrBool) ovrHmd_StopPerfLog(ovrHmd hmd); + + +#ifdef __cplusplus +} // extern "C" +#endif + + +#if defined(_MSC_VER) + #pragma warning(pop) +#endif + + + +// ----------------------------------------------------------------------------------- +// ***** Backward compatibility #includes +// +// This is at the bottom of this file because the following is dependent on the +// declarations above. + +#if !defined(OVR_CAPI_NO_UTILS) + #include "OVR_CAPI_Util.h" +#endif + + +#endif // OVR_CAPI_h diff --git a/LibOVR/Include/OVR_CAPI_GL.h b/LibOVR/Include/OVR_CAPI_GL.h new file mode 100644 index 0000000..ef7cb45 --- /dev/null +++ b/LibOVR/Include/OVR_CAPI_GL.h @@ -0,0 +1,87 @@ +/************************************************************************************ + +Filename : OVR_CAPI_GL.h +Content : GL specific structures used by the CAPI interface. +Created : November 7, 2013 +Authors : Lee Cooper + +Copyright : Copyright 2013 Oculus VR, LLC. All Rights reserved. + +Use of this software is subject to the terms of the Oculus Inc license +agreement provided at the time of installation or download, or which +otherwise accompanies this software in either electronic or hard copy form. + +************************************************************************************/ +#ifndef OVR_CAPI_GL_h +#define OVR_CAPI_GL_h + +/// @file OVR_CAPI_GL.h +/// OpenGL rendering support. + +#include "OVR_CAPI.h" + +#if defined(OVR_OS_WIN32) + #include <Windows.h> + #include <gl/GL.h> +#elif defined(__APPLE__) + #include <OpenGL/gl.h> +#else + #include <GL/gl.h> +#endif + + +#if defined(_MSC_VER) + #pragma warning(push) + #pragma warning(disable: 4324) // structure was padded due to __declspec(align()) +#endif + + +/// Used to configure slave GL rendering (i.e. for devices created externally). +typedef struct ovrGLConfigData_s +{ + ovrRenderAPIConfigHeader Header; ///< General device settings. + +#if defined(OVR_OS_WIN32) + HWND Window; ///< The optional window handle. If unset, rendering will use the current window. + HDC DC; ///< The optional device context. If unset, rendering will use a new context. +#elif defined (OVR_OS_LINUX) + struct _XDisplay* Disp; ///< Optional display. If unset, will issue glXGetCurrentDisplay when context is current. +#endif +} ovrGLConfigData; + +#if defined(__cplusplus) + static_assert(sizeof(ovrRenderAPIConfig) >= sizeof(ovrGLConfigData), "Insufficient size."); +#endif + +/// Contains OpenGL-specific rendering information. +union ovrGLConfig +{ + ovrRenderAPIConfig Config; ///< General device settings. + ovrGLConfigData OGL; ///< OpenGL-specific settings. +}; + +/// Used to pass GL eye texture data to ovrHmd_EndFrame. +typedef struct ovrGLTextureData_s +{ + ovrTextureHeader Header; ///< General device settings. + GLuint TexId; ///< The OpenGL name for this texture. +} ovrGLTextureData; + +#if defined(__cplusplus) + static_assert(sizeof(ovrTexture) >= sizeof(ovrGLTextureData), "Insufficient size."); +#endif + +/// Contains OpenGL-specific texture information. +typedef union ovrGLTexture_s +{ + ovrTexture Texture; ///< General device settings. + ovrGLTextureData OGL; ///< OpenGL-specific settings. +} ovrGLTexture; + + +#if defined(_MSC_VER) + #pragma warning(pop) +#endif + + +#endif // OVR_CAPI_GL_h diff --git a/LibOVR/Include/OVR_CAPI_Keys.h b/LibOVR/Include/OVR_CAPI_Keys.h new file mode 100644 index 0000000..13451e5 --- /dev/null +++ b/LibOVR/Include/OVR_CAPI_Keys.h @@ -0,0 +1,56 @@ +/************************************************************************************ + +Filename : OVR_CAPI.h +Content : Keys for CAPI calls +Created : September 25, 2014 +Authors : + +Copyright : Copyright 2014 Oculus VR, LLC All Rights reserved. + +Licensed under the Oculus VR Rift SDK License Version 3.2 (the "License"); +you may not use the Oculus VR Rift SDK except in compliance with the License, +which is provided at the time of installation or download, or which +otherwise accompanies this software in either electronic or hard copy form. + +You may obtain a copy of the License at + +http://www.oculusvr.com/licenses/LICENSE-3.2 + +Unless required by applicable law or agreed to in writing, the Oculus VR SDK +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +************************************************************************************/ + + + +#define OVR_KEY_USER "User" // string +#define OVR_KEY_NAME "Name" // string +#define OVR_KEY_GENDER "Gender" // string +#define OVR_KEY_PLAYER_HEIGHT "PlayerHeight" // float +#define OVR_KEY_EYE_HEIGHT "EyeHeight" // float +#define OVR_KEY_IPD "IPD" // float +#define OVR_KEY_NECK_TO_EYE_DISTANCE "NeckEyeDistance" // float[2] +#define OVR_KEY_EYE_RELIEF_DIAL "EyeReliefDial" // int +#define OVR_KEY_EYE_TO_NOSE_DISTANCE "EyeToNoseDist" // float[2] +#define OVR_KEY_MAX_EYE_TO_PLATE_DISTANCE "MaxEyeToPlateDist" // float[2] +#define OVR_KEY_EYE_CUP "EyeCup" // char[16] +#define OVR_KEY_CUSTOM_EYE_RENDER "CustomEyeRender" // bool +#define OVR_KEY_CAMERA_POSITION "CenteredFromWorld" // double[7] + +// Default measurements empirically determined at Oculus to make us happy +// The neck model numbers were derived as an average of the male and female averages from ANSUR-88 +// NECK_TO_EYE_HORIZONTAL = H22 - H43 = INFRAORBITALE_BACK_OF_HEAD - TRAGION_BACK_OF_HEAD +// NECK_TO_EYE_VERTICAL = H21 - H15 = GONION_TOP_OF_HEAD - ECTOORBITALE_TOP_OF_HEAD +// These were determined to be the best in a small user study, clearly beating out the previous default values +#define OVR_DEFAULT_GENDER "Unknown" +#define OVR_DEFAULT_PLAYER_HEIGHT 1.778f +#define OVR_DEFAULT_EYE_HEIGHT 1.675f +#define OVR_DEFAULT_IPD 0.064f +#define OVR_DEFAULT_NECK_TO_EYE_HORIZONTAL 0.0805f +#define OVR_DEFAULT_NECK_TO_EYE_VERTICAL 0.075f +#define OVR_DEFAULT_EYE_RELIEF_DIAL 3 +#define OVR_DEFAULT_CAMERA_POSITION {0,0,0,1,0,0,0} + diff --git a/LibOVR/Include/OVR_CAPI_Util.h b/LibOVR/Include/OVR_CAPI_Util.h new file mode 100644 index 0000000..8d2f43d --- /dev/null +++ b/LibOVR/Include/OVR_CAPI_Util.h @@ -0,0 +1,79 @@ +/************************************************************************************ + +PublicHeader: OVR_CAPI_Util.h +Copyright : Copyright 2014 Oculus VR, LLC All Rights reserved. + +Licensed under the Oculus VR Rift SDK License Version 3.2 (the "License"); +you may not use the Oculus VR Rift SDK except in compliance with the License, +which is provided at the time of installation or download, or which +otherwise accompanies this software in either electronic or hard copy form. + +You may obtain a copy of the License at + +http://www.oculusvr.com/licenses/LICENSE-3.2 + +Unless required by applicable law or agreed to in writing, the Oculus VR SDK +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +*************************************************************************************/ + +#ifndef OVR_CAPI_Util_h +#define OVR_CAPI_Util_h + + +#include "OVR_CAPI.h" + + +#ifdef __cplusplus +extern "C" { +#endif + +/// Enumerates modifications to the projection matrix based on the application's needs +typedef enum +{ + /// Use for generating a default projection matrix that is: + /// * Left-handed + /// * Near depth values stored in the depth buffer are smaller than far depth values + /// * Both near and far are explicitly defined + /// * With a clipping range that is (0 to w) + ovrProjection_None = 0x00, + + /// Enable if using right-handed transformations in your application + ovrProjection_RightHanded = 0x01, + + /// After projection transform is applied, far values stored in the depth buffer will be less than closer depth values + /// NOTE: Enable only if application is using a floating-point depth buffer for proper precision + ovrProjection_FarLessThanNear = 0x02, + + /// When this flag is used, the zfar value pushed into ovrMatrix4f_Projection() will be ignored + /// NOTE: Enable only if ovrProjection_FarLessThanNear is also enabled where the far clipping plane will be pushed to infinity + ovrProjection_FarClipAtInfinity = 0x04, + + /// Enable if application is rendering with OpenGL and expects a projection matrix with a clipping range of (-w to w) + /// Ignore this flag if your application already handles the conversion from D3D range (0 to w) to OpenGL + ovrProjection_ClipRangeOpenGL = 0x08, +} ovrProjectionModifier; + +/// Used to generate projection from ovrEyeDesc::Fov. +/// projectionFlags is a combination of the ovrProjectionModifier flags defined above +OVR_PUBLIC_FUNCTION(ovrMatrix4f) ovrMatrix4f_Projection(ovrFovPort fov, float znear, float zfar, unsigned int projectionModFlags); + +/// Used for 2D rendering, Y is down +/// orthoScale = 1.0f / pixelsPerTanAngleAtCenter +/// orthoDistance = distance from camera, such as 0.8m +OVR_PUBLIC_FUNCTION(ovrMatrix4f) ovrMatrix4f_OrthoSubProjection(ovrMatrix4f projection, ovrVector2f orthoScale, + float orthoDistance, float hmdToEyeViewOffsetX); + +/// Waits until the specified absolute time. +OVR_PUBLIC_FUNCTION(double) ovr_WaitTillTime(double absTime); + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif // Header include guard diff --git a/LibOVR/Include/OVR_ErrorCode.h b/LibOVR/Include/OVR_ErrorCode.h new file mode 100755 index 0000000..51c9d7d --- /dev/null +++ b/LibOVR/Include/OVR_ErrorCode.h @@ -0,0 +1,66 @@ +/************************************************************************************ + +PublicHeader: OVR_ErrorCode.h +Copyright : Copyright 2015 Oculus VR, LLC All Rights reserved. + +Licensed under the Oculus VR Rift SDK License Version 3.2 (the "License"); +you may not use the Oculus VR Rift SDK except in compliance with the License, +which is provided at the time of installation or download, or which +otherwise accompanies this software in either electronic or hard copy form. + +You may obtain a copy of the License at + +http://www.oculusvr.com/licenses/LICENSE-3.2 + +Unless required by applicable law or agreed to in writing, the Oculus VR SDK +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +*************************************************************************************/ + +#include "OVR_Version.h" + + + + +#ifndef OVR_ErrorCode_h +#define OVR_ErrorCode_h + + +#include <stdint.h> + + +/* API call results are represented at the highest level by a single ovrResult. */ +#ifndef OVR_RESULT_DEFINED +#define OVR_RESULT_DEFINED +typedef int32_t ovrResult; +#endif + + +/* Success is zero, while all error types are non-zero values. */ +#ifndef OVR_SUCCESS_DEFINED +#define OVR_SUCCESS_DEFINED +const ovrResult ovrSuccess = 0; +#endif + + +enum +{ + /* Initialization errors. */ + ovrError_Initialize = 1000, /* Generic initialization error. */ + ovrError_LibLoad = 1001, /* Couldn't load LibOVRRT. */ + ovrError_LibVersion = 1002, /* LibOVRRT version incompatibility. */ + ovrError_ServiceConnection = 1003, /* Couldn't connect to the OVR Service. */ + ovrError_ServiceVersion = 1004, /* OVR Service version incompatibility. */ + ovrError_IncompatibleOS = 1005, /* The operating system version is incompatible. */ + ovrError_DisplayInit = 1006, /* Unable to initialize the HMD display. */ + ovrError_ServerStart = 1007, /* Unable to start the server. Is it already running? */ + ovrError_Reinitialization = 1008 /* Attempting to re-initialize with a different version. */ +}; + + +#endif /* Header include guard */ + + diff --git a/LibOVR/Include/OVR_Kernel.h b/LibOVR/Include/OVR_Kernel.h index 1a8a903..72ab48a 100644 --- a/LibOVR/Include/OVR_Kernel.h +++ b/LibOVR/Include/OVR_Kernel.h @@ -23,20 +23,22 @@ limitations under the License. *************************************************************************************/ -#ifndef OVR_h -#define OVR_h - -#include "../Src/Kernel/OVR_Types.h" -#include "../Src/Kernel/OVR_Allocator.h" -#include "../Src/Kernel/OVR_RefCount.h" -#include "../Src/Kernel/OVR_Log.h" -#include "../Src/Kernel/OVR_Math.h" -#include "../Src/Kernel/OVR_System.h" -#include "../Src/Kernel/OVR_Nullptr.h" -#include "../Src/Kernel/OVR_String.h" -#include "../Src/Kernel/OVR_Array.h" -#include "../Src/Kernel/OVR_Timer.h" -#include "../Src/Kernel/OVR_SysFile.h" +/* This header file is deprecated and will be removed from a future version of this library */ + +#ifndef OVR_Kernel_h +#define OVR_Kernel_h + +#include "Kernel/OVR_Types.h" +#include "Kernel/OVR_Allocator.h" +#include "Kernel/OVR_RefCount.h" +#include "Kernel/OVR_Log.h" +#include "Kernel/OVR_System.h" +#include "Kernel/OVR_Nullptr.h" +#include "Kernel/OVR_String.h" +#include "Kernel/OVR_Array.h" +#include "Kernel/OVR_Timer.h" +#include "Kernel/OVR_SysFile.h" +#include "Extras/OVR_Math.h" #endif diff --git a/LibOVR/Include/OVR_Version.h b/LibOVR/Include/OVR_Version.h index 2ba20bc..c33fa3c 100644..100755 --- a/LibOVR/Include/OVR_Version.h +++ b/LibOVR/Include/OVR_Version.h @@ -22,14 +22,53 @@ limitations under the License. *************************************************************************************/ -#ifndef _OVR_VERSION_H -#define _OVR_VERSION_H +#ifndef OVR_Version_h +#define OVR_Version_h -#define OVR_MAJOR_VERSION 0 -#define OVR_MINOR_VERSION 4 -#define OVR_BUILD_VERSION 4 -#define OVR_VERSION_STRING "0.4.4" -#define OVR_DK2_LATEST_FIRMWARE_MAJOR_VERSION 2 -#define OVR_DK2_LATEST_FIRMWARE_MINOR_VERSION 12 + + + +#if !defined(OVR_STRINGIZE) + #define OVR_STRINGIZEIMPL(x) #x + #define OVR_STRINGIZE(x) OVR_STRINGIZEIMPL(x) #endif + +// We are on major version 5 of the beta pre-release SDK. At some point we will +// transition to product version 1 and reset the major version back to 1 (first +// product release, version 1.0). +#define OVR_PRODUCT_VERSION 0 +#define OVR_MAJOR_VERSION 5 +#define OVR_MINOR_VERSION 0 +#define OVR_PATCH_VERSION 1 +#define OVR_BUILD_NUMBER 0 + +// "Product.Major.Minor.Patch" +#if !defined(OVR_VERSION_STRING) + #define OVR_VERSION_STRING OVR_STRINGIZE(OVR_PRODUCT_VERSION.OVR_MAJOR_VERSION.OVR_MINOR_VERSION.OVR_PATCH_VERSION) +#endif + +// "Product.Major.Minor.Patch.Build" +#if !defined(OVR_DETAILED_VERSION_STRING) + #define OVR_DETAILED_VERSION_STRING OVR_STRINGIZE(OVR_PRODUCT_VERSION.OVR_MAJOR_VERSION.OVR_MINOR_VERSION.OVR_PATCH_VERSION.OVR_BUILD_NUMBER) +#endif + +// This is the firmware version for the DK2 headset sensor board. +//#if !defined(OVR_DK2_LATEST_FIRMWARE_MAJOR_VERSION) + #define OVR_DK2_LATEST_FIRMWARE_MAJOR_VERSION 2 + #define OVR_DK2_LATEST_FIRMWARE_MINOR_VERSION 12 +//#endif + +// LibOVRRT description +// This appears in the user-visible file properties. It is intended to convey publicly available additional information +// such as feature builds. +#if !defined(OVR_FILE_DESCRIPTION_STRING) + #if defined(_DEBUG) + #define OVR_FILE_DESCRIPTION_STRING "LibOVRRT (debug)" + #else + #define OVR_FILE_DESCRIPTION_STRING "LibOVRRT" + #endif +#endif + + +#endif // OVR_Version_h |