rev |
line source |
nuclear@1
|
1 /************************************************************************************
|
nuclear@1
|
2
|
nuclear@1
|
3 PublicHeader: OVR.h
|
nuclear@1
|
4 Filename : OVR_Math.h
|
nuclear@1
|
5 Content : Implementation of 3D primitives such as vectors, matrices.
|
nuclear@1
|
6 Created : September 4, 2012
|
nuclear@1
|
7 Authors : Andrew Reisse, Michael Antonov, Steve LaValle, Anna Yershova
|
nuclear@1
|
8
|
nuclear@1
|
9 Copyright : Copyright 2012 Oculus VR, Inc. All Rights reserved.
|
nuclear@1
|
10
|
nuclear@1
|
11 Use of this software is subject to the terms of the Oculus license
|
nuclear@1
|
12 agreement provided at the time of installation or download, or which
|
nuclear@1
|
13 otherwise accompanies this software in either electronic or hard copy form.
|
nuclear@1
|
14
|
nuclear@1
|
15 *************************************************************************************/
|
nuclear@1
|
16
|
nuclear@1
|
17 #ifndef OVR_Math_h
|
nuclear@1
|
18 #define OVR_Math_h
|
nuclear@1
|
19
|
nuclear@1
|
20 #include <assert.h>
|
nuclear@1
|
21 #include <stdlib.h>
|
nuclear@1
|
22 #include <math.h>
|
nuclear@1
|
23
|
nuclear@1
|
24 #include "OVR_Types.h"
|
nuclear@1
|
25 #include "OVR_RefCount.h"
|
nuclear@1
|
26
|
nuclear@1
|
27 namespace OVR {
|
nuclear@1
|
28
|
nuclear@1
|
29 //-------------------------------------------------------------------------------------
|
nuclear@1
|
30 // Constants for 3D world/axis definitions.
|
nuclear@1
|
31
|
nuclear@1
|
32 // Definitions of axes for coordinate and rotation conversions.
|
nuclear@1
|
33 enum Axis
|
nuclear@1
|
34 {
|
nuclear@1
|
35 Axis_X = 0, Axis_Y = 1, Axis_Z = 2
|
nuclear@1
|
36 };
|
nuclear@1
|
37
|
nuclear@1
|
38 // RotateDirection describes the rotation direction around an axis, interpreted as follows:
|
nuclear@1
|
39 // CW - Clockwise while looking "down" from positive axis towards the origin.
|
nuclear@1
|
40 // CCW - Counter-clockwise while looking from the positive axis towards the origin,
|
nuclear@1
|
41 // which is in the negative axis direction.
|
nuclear@1
|
42 // CCW is the default for the RHS coordinate system. Oculus standard RHS coordinate
|
nuclear@1
|
43 // system defines Y up, X right, and Z back (pointing out from the screen). In this
|
nuclear@1
|
44 // system Rotate_CCW around Z will specifies counter-clockwise rotation in XY plane.
|
nuclear@1
|
45 enum RotateDirection
|
nuclear@1
|
46 {
|
nuclear@1
|
47 Rotate_CCW = 1,
|
nuclear@1
|
48 Rotate_CW = -1
|
nuclear@1
|
49 };
|
nuclear@1
|
50
|
nuclear@1
|
51 enum HandedSystem
|
nuclear@1
|
52 {
|
nuclear@1
|
53 Handed_R = 1, Handed_L = -1
|
nuclear@1
|
54 };
|
nuclear@1
|
55
|
nuclear@1
|
56 // AxisDirection describes which way the axis points. Used by WorldAxes.
|
nuclear@1
|
57 enum AxisDirection
|
nuclear@1
|
58 {
|
nuclear@1
|
59 Axis_Up = 2,
|
nuclear@1
|
60 Axis_Down = -2,
|
nuclear@1
|
61 Axis_Right = 1,
|
nuclear@1
|
62 Axis_Left = -1,
|
nuclear@1
|
63 Axis_In = 3,
|
nuclear@1
|
64 Axis_Out = -3
|
nuclear@1
|
65 };
|
nuclear@1
|
66
|
nuclear@1
|
67 struct WorldAxes
|
nuclear@1
|
68 {
|
nuclear@1
|
69 AxisDirection XAxis, YAxis, ZAxis;
|
nuclear@1
|
70
|
nuclear@1
|
71 WorldAxes(AxisDirection x, AxisDirection y, AxisDirection z)
|
nuclear@1
|
72 : XAxis(x), YAxis(y), ZAxis(z)
|
nuclear@1
|
73 { OVR_ASSERT(abs(x) != abs(y) && abs(y) != abs(z) && abs(z) != abs(x));}
|
nuclear@1
|
74 };
|
nuclear@1
|
75
|
nuclear@1
|
76
|
nuclear@1
|
77 //-------------------------------------------------------------------------------------
|
nuclear@1
|
78 // ***** Math
|
nuclear@1
|
79
|
nuclear@1
|
80 // Math class contains constants and functions. This class is a template specialized
|
nuclear@1
|
81 // per type, with Math<float> and Math<double> being distinct.
|
nuclear@1
|
82 template<class Type>
|
nuclear@1
|
83 class Math
|
nuclear@1
|
84 {
|
nuclear@1
|
85 };
|
nuclear@1
|
86
|
nuclear@1
|
87 // Single-precision Math constants class.
|
nuclear@1
|
88 template<>
|
nuclear@1
|
89 class Math<float>
|
nuclear@1
|
90 {
|
nuclear@1
|
91 public:
|
nuclear@1
|
92 static const float Pi;
|
nuclear@1
|
93 static const float TwoPi;
|
nuclear@1
|
94 static const float PiOver2;
|
nuclear@1
|
95 static const float PiOver4;
|
nuclear@1
|
96 static const float E;
|
nuclear@1
|
97
|
nuclear@1
|
98 static const float MaxValue; // Largest positive float Value
|
nuclear@1
|
99 static const float MinPositiveValue; // Smallest possible positive value
|
nuclear@1
|
100
|
nuclear@1
|
101 static const float RadToDegreeFactor;
|
nuclear@1
|
102 static const float DegreeToRadFactor;
|
nuclear@1
|
103
|
nuclear@1
|
104 static const float Tolerance; // 0.00001f;
|
nuclear@1
|
105 static const float SingularityRadius; //0.00000000001f for Gimbal lock numerical problems
|
nuclear@1
|
106 };
|
nuclear@1
|
107
|
nuclear@1
|
108 // Double-precision Math constants class.
|
nuclear@1
|
109 template<>
|
nuclear@1
|
110 class Math<double>
|
nuclear@1
|
111 {
|
nuclear@1
|
112 public:
|
nuclear@1
|
113 static const double Pi;
|
nuclear@1
|
114 static const double TwoPi;
|
nuclear@1
|
115 static const double PiOver2;
|
nuclear@1
|
116 static const double PiOver4;
|
nuclear@1
|
117 static const double E;
|
nuclear@1
|
118
|
nuclear@1
|
119 static const double MaxValue; // Largest positive double Value
|
nuclear@1
|
120 static const double MinPositiveValue; // Smallest possible positive value
|
nuclear@1
|
121
|
nuclear@1
|
122 static const double RadToDegreeFactor;
|
nuclear@1
|
123 static const double DegreeToRadFactor;
|
nuclear@1
|
124
|
nuclear@1
|
125 static const double Tolerance; // 0.00001f;
|
nuclear@1
|
126 static const double SingularityRadius; //0.00000000001 for Gimbal lock numerical problems
|
nuclear@1
|
127 };
|
nuclear@1
|
128
|
nuclear@1
|
129 typedef Math<float> Mathf;
|
nuclear@1
|
130 typedef Math<double> Mathd;
|
nuclear@1
|
131
|
nuclear@1
|
132 // Conversion functions between degrees and radians
|
nuclear@1
|
133 template<class FT>
|
nuclear@1
|
134 FT RadToDegree(FT rads) { return rads * Math<FT>::RadToDegreeFactor; }
|
nuclear@1
|
135 template<class FT>
|
nuclear@1
|
136 FT DegreeToRad(FT rads) { return rads * Math<FT>::DegreeToRadFactor; }
|
nuclear@1
|
137
|
nuclear@1
|
138 template<class T>
|
nuclear@1
|
139 class Quat;
|
nuclear@1
|
140
|
nuclear@1
|
141 //-------------------------------------------------------------------------------------
|
nuclear@1
|
142 // ***** Vector2f - 2D Vector2f
|
nuclear@1
|
143
|
nuclear@1
|
144 // Vector2f represents a 2-dimensional vector or point in space,
|
nuclear@1
|
145 // consisting of coordinates x and y,
|
nuclear@1
|
146
|
nuclear@1
|
147 template<class T>
|
nuclear@1
|
148 class Vector2
|
nuclear@1
|
149 {
|
nuclear@1
|
150 public:
|
nuclear@1
|
151 T x, y;
|
nuclear@1
|
152
|
nuclear@1
|
153 Vector2() : x(0), y(0) { }
|
nuclear@1
|
154 Vector2(T x_, T y_) : x(x_), y(y_) { }
|
nuclear@1
|
155 explicit Vector2(T s) : x(s), y(s) { }
|
nuclear@1
|
156
|
nuclear@1
|
157 bool operator== (const Vector2& b) const { return x == b.x && y == b.y; }
|
nuclear@1
|
158 bool operator!= (const Vector2& b) const { return x != b.x || y != b.y; }
|
nuclear@1
|
159
|
nuclear@1
|
160 Vector2 operator+ (const Vector2& b) const { return Vector2(x + b.x, y + b.y); }
|
nuclear@1
|
161 Vector2& operator+= (const Vector2& b) { x += b.x; y += b.y; return *this; }
|
nuclear@1
|
162 Vector2 operator- (const Vector2& b) const { return Vector2(x - b.x, y - b.y); }
|
nuclear@1
|
163 Vector2& operator-= (const Vector2& b) { x -= b.x; y -= b.y; return *this; }
|
nuclear@1
|
164 Vector2 operator- () const { return Vector2(-x, -y); }
|
nuclear@1
|
165
|
nuclear@1
|
166 // Scalar multiplication/division scales vector.
|
nuclear@1
|
167 Vector2 operator* (T s) const { return Vector2(x*s, y*s); }
|
nuclear@1
|
168 Vector2& operator*= (T s) { x *= s; y *= s; return *this; }
|
nuclear@1
|
169
|
nuclear@1
|
170 Vector2 operator/ (T s) const { T rcp = T(1)/s;
|
nuclear@1
|
171 return Vector2(x*rcp, y*rcp); }
|
nuclear@1
|
172 Vector2& operator/= (T s) { T rcp = T(1)/s;
|
nuclear@1
|
173 x *= rcp; y *= rcp;
|
nuclear@1
|
174 return *this; }
|
nuclear@1
|
175
|
nuclear@1
|
176 // Compare two vectors for equality with tolerance. Returns true if vectors match withing tolerance.
|
nuclear@1
|
177 bool Compare(const Vector2&b, T tolerance = Mathf::Tolerance)
|
nuclear@1
|
178 {
|
nuclear@1
|
179 return (fabs(b.x-x) < tolerance) && (fabs(b.y-y) < tolerance);
|
nuclear@1
|
180 }
|
nuclear@1
|
181
|
nuclear@1
|
182 // Dot product overload.
|
nuclear@1
|
183 // Used to calculate angle q between two vectors among other things,
|
nuclear@1
|
184 // as (A dot B) = |a||b|cos(q).
|
nuclear@1
|
185 T operator* (const Vector2& b) const { return x*b.x + y*b.y; }
|
nuclear@1
|
186
|
nuclear@1
|
187 // Returns the angle from this vector to b, in radians.
|
nuclear@1
|
188 T Angle(const Vector2& b) const { return acos((*this * b)/(Length()*b.Length())); }
|
nuclear@1
|
189
|
nuclear@1
|
190 // Return Length of the vector squared.
|
nuclear@1
|
191 T LengthSq() const { return (x * x + y * y); }
|
nuclear@1
|
192 // Return vector length.
|
nuclear@1
|
193 T Length() const { return sqrt(LengthSq()); }
|
nuclear@1
|
194
|
nuclear@1
|
195 // Returns distance between two points represented by vectors.
|
nuclear@1
|
196 T Distance(Vector2& b) const { return (*this - b).Length(); }
|
nuclear@1
|
197
|
nuclear@1
|
198 // Determine if this a unit vector.
|
nuclear@1
|
199 bool IsNormalized() const { return fabs(LengthSq() - T(1)) < Math<T>::Tolerance; }
|
nuclear@1
|
200 // Normalize, convention vector length to 1.
|
nuclear@1
|
201 void Normalize() { *this /= Length(); }
|
nuclear@1
|
202 // Returns normalized (unit) version of the vector without modifying itself.
|
nuclear@1
|
203 Vector2 Normalized() const { return *this / Length(); }
|
nuclear@1
|
204
|
nuclear@1
|
205 // Linearly interpolates from this vector to another.
|
nuclear@1
|
206 // Factor should be between 0.0 and 1.0, with 0 giving full value to this.
|
nuclear@1
|
207 Vector2 Lerp(const Vector2& b, T f) const { return *this*(T(1) - f) + b*f; }
|
nuclear@1
|
208
|
nuclear@1
|
209 // Projects this vector onto the argument; in other words,
|
nuclear@1
|
210 // A.Project(B) returns projection of vector A onto B.
|
nuclear@1
|
211 Vector2 ProjectTo(const Vector2& b) const { return b * ((*this * b) / b.LengthSq()); }
|
nuclear@1
|
212 };
|
nuclear@1
|
213
|
nuclear@1
|
214
|
nuclear@1
|
215 typedef Vector2<float> Vector2f;
|
nuclear@1
|
216 typedef Vector2<double> Vector2d;
|
nuclear@1
|
217
|
nuclear@1
|
218 //-------------------------------------------------------------------------------------
|
nuclear@1
|
219 // ***** Vector3f - 3D Vector3f
|
nuclear@1
|
220
|
nuclear@1
|
221 // Vector3f represents a 3-dimensional vector or point in space,
|
nuclear@1
|
222 // consisting of coordinates x, y and z.
|
nuclear@1
|
223
|
nuclear@1
|
224 template<class T>
|
nuclear@1
|
225 class Vector3
|
nuclear@1
|
226 {
|
nuclear@1
|
227 public:
|
nuclear@1
|
228 T x, y, z;
|
nuclear@1
|
229
|
nuclear@1
|
230 Vector3() : x(0), y(0), z(0) { }
|
nuclear@1
|
231 Vector3(T x_, T y_, T z_ = 0) : x(x_), y(y_), z(z_) { }
|
nuclear@1
|
232 explicit Vector3(T s) : x(s), y(s), z(s) { }
|
nuclear@1
|
233
|
nuclear@1
|
234 bool operator== (const Vector3& b) const { return x == b.x && y == b.y && z == b.z; }
|
nuclear@1
|
235 bool operator!= (const Vector3& b) const { return x != b.x || y != b.y || z != b.z; }
|
nuclear@1
|
236
|
nuclear@1
|
237 Vector3 operator+ (const Vector3& b) const { return Vector3(x + b.x, y + b.y, z + b.z); }
|
nuclear@1
|
238 Vector3& operator+= (const Vector3& b) { x += b.x; y += b.y; z += b.z; return *this; }
|
nuclear@1
|
239 Vector3 operator- (const Vector3& b) const { return Vector3(x - b.x, y - b.y, z - b.z); }
|
nuclear@1
|
240 Vector3& operator-= (const Vector3& b) { x -= b.x; y -= b.y; z -= b.z; return *this; }
|
nuclear@1
|
241 Vector3 operator- () const { return Vector3(-x, -y, -z); }
|
nuclear@1
|
242
|
nuclear@1
|
243 // Scalar multiplication/division scales vector.
|
nuclear@1
|
244 Vector3 operator* (T s) const { return Vector3(x*s, y*s, z*s); }
|
nuclear@1
|
245 Vector3& operator*= (T s) { x *= s; y *= s; z *= s; return *this; }
|
nuclear@1
|
246
|
nuclear@1
|
247 Vector3 operator/ (T s) const { T rcp = T(1)/s;
|
nuclear@1
|
248 return Vector3(x*rcp, y*rcp, z*rcp); }
|
nuclear@1
|
249 Vector3& operator/= (T s) { T rcp = T(1)/s;
|
nuclear@1
|
250 x *= rcp; y *= rcp; z *= rcp;
|
nuclear@1
|
251 return *this; }
|
nuclear@1
|
252
|
nuclear@1
|
253 // Compare two vectors for equality with tolerance. Returns true if vectors match withing tolerance.
|
nuclear@1
|
254 bool Compare(const Vector3&b, T tolerance = Mathf::Tolerance)
|
nuclear@1
|
255 {
|
nuclear@1
|
256 return (fabs(b.x-x) < tolerance) && (fabs(b.y-y) < tolerance) && (fabs(b.z-z) < tolerance);
|
nuclear@1
|
257 }
|
nuclear@1
|
258
|
nuclear@1
|
259 // Dot product overload.
|
nuclear@1
|
260 // Used to calculate angle q between two vectors among other things,
|
nuclear@1
|
261 // as (A dot B) = |a||b|cos(q).
|
nuclear@1
|
262 T operator* (const Vector3& b) const { return x*b.x + y*b.y + z*b.z; }
|
nuclear@1
|
263
|
nuclear@1
|
264 // Compute cross product, which generates a normal vector.
|
nuclear@1
|
265 // Direction vector can be determined by right-hand rule: Pointing index finder in
|
nuclear@1
|
266 // direction a and middle finger in direction b, thumb will point in a.Cross(b).
|
nuclear@1
|
267 Vector3 Cross(const Vector3& b) const { return Vector3(y*b.z - z*b.y,
|
nuclear@1
|
268 z*b.x - x*b.z,
|
nuclear@1
|
269 x*b.y - y*b.x); }
|
nuclear@1
|
270
|
nuclear@1
|
271 // Returns the angle from this vector to b, in radians.
|
nuclear@1
|
272 T Angle(const Vector3& b) const { return acos((*this * b)/(Length()*b.Length())); }
|
nuclear@1
|
273
|
nuclear@1
|
274 // Return Length of the vector squared.
|
nuclear@1
|
275 T LengthSq() const { return (x * x + y * y + z * z); }
|
nuclear@1
|
276 // Return vector length.
|
nuclear@1
|
277 T Length() const { return sqrt(LengthSq()); }
|
nuclear@1
|
278
|
nuclear@1
|
279 // Returns distance between two points represented by vectors.
|
nuclear@1
|
280 T Distance(Vector3& b) const { return (*this - b).Length(); }
|
nuclear@1
|
281
|
nuclear@1
|
282 // Determine if this a unit vector.
|
nuclear@1
|
283 bool IsNormalized() const { return fabs(LengthSq() - T(1)) < Math<T>::Tolerance; }
|
nuclear@1
|
284 // Normalize, convention vector length to 1.
|
nuclear@1
|
285 void Normalize() { *this /= Length(); }
|
nuclear@1
|
286 // Returns normalized (unit) version of the vector without modifying itself.
|
nuclear@1
|
287 Vector3 Normalized() const { return *this / Length(); }
|
nuclear@1
|
288
|
nuclear@1
|
289 // Linearly interpolates from this vector to another.
|
nuclear@1
|
290 // Factor should be between 0.0 and 1.0, with 0 giving full value to this.
|
nuclear@1
|
291 Vector3 Lerp(const Vector3& b, T f) const { return *this*(T(1) - f) + b*f; }
|
nuclear@1
|
292
|
nuclear@1
|
293 // Projects this vector onto the argument; in other words,
|
nuclear@1
|
294 // A.Project(B) returns projection of vector A onto B.
|
nuclear@1
|
295 Vector3 ProjectTo(const Vector3& b) const { return b * ((*this * b) / b.LengthSq()); }
|
nuclear@1
|
296 };
|
nuclear@1
|
297
|
nuclear@1
|
298
|
nuclear@1
|
299 typedef Vector3<float> Vector3f;
|
nuclear@1
|
300 typedef Vector3<double> Vector3d;
|
nuclear@1
|
301
|
nuclear@1
|
302
|
nuclear@1
|
303 //-------------------------------------------------------------------------------------
|
nuclear@1
|
304 // ***** Matrix4f
|
nuclear@1
|
305
|
nuclear@1
|
306 // Matrix4f is a 4x4 matrix used for 3d transformations and projections.
|
nuclear@1
|
307 // Translation stored in the last column.
|
nuclear@1
|
308 // The matrix is stored in row-major order in memory, meaning that values
|
nuclear@1
|
309 // of the first row are stored before the next one.
|
nuclear@1
|
310 //
|
nuclear@1
|
311 // The arrangement of the matrix is chosen to be in Right-Handed
|
nuclear@1
|
312 // coordinate system and counterclockwise rotations when looking down
|
nuclear@1
|
313 // the axis
|
nuclear@1
|
314 //
|
nuclear@1
|
315 // Transformation Order:
|
nuclear@1
|
316 // - Transformations are applied from right to left, so the expression
|
nuclear@1
|
317 // M1 * M2 * M3 * V means that the vector V is transformed by M3 first,
|
nuclear@1
|
318 // followed by M2 and M1.
|
nuclear@1
|
319 //
|
nuclear@1
|
320 // Coordinate system: Right Handed
|
nuclear@1
|
321 //
|
nuclear@1
|
322 // Rotations: Counterclockwise when looking down the axis. All angles are in radians.
|
nuclear@1
|
323 //
|
nuclear@1
|
324 // | sx 01 02 tx | // First column (sx, 10, 20): Axis X basis vector.
|
nuclear@1
|
325 // | 10 sy 12 ty | // Second column (01, sy, 21): Axis Y basis vector.
|
nuclear@1
|
326 // | 20 21 sz tz | // Third columnt (02, 12, sz): Axis Z basis vector.
|
nuclear@1
|
327 // | 30 31 32 33 |
|
nuclear@1
|
328 //
|
nuclear@1
|
329 // The basis vectors are first three columns.
|
nuclear@1
|
330
|
nuclear@1
|
331 class Matrix4f
|
nuclear@1
|
332 {
|
nuclear@1
|
333 static Matrix4f IdentityValue;
|
nuclear@1
|
334
|
nuclear@1
|
335 public:
|
nuclear@1
|
336 float M[4][4];
|
nuclear@1
|
337
|
nuclear@1
|
338 enum NoInitType { NoInit };
|
nuclear@1
|
339
|
nuclear@1
|
340 // Construct with no memory initialization.
|
nuclear@1
|
341 Matrix4f(NoInitType) { }
|
nuclear@1
|
342
|
nuclear@1
|
343 // By default, we construct identity matrix.
|
nuclear@1
|
344 Matrix4f()
|
nuclear@1
|
345 {
|
nuclear@1
|
346 SetIdentity();
|
nuclear@1
|
347 }
|
nuclear@1
|
348
|
nuclear@1
|
349 Matrix4f(float m11, float m12, float m13, float m14,
|
nuclear@1
|
350 float m21, float m22, float m23, float m24,
|
nuclear@1
|
351 float m31, float m32, float m33, float m34,
|
nuclear@1
|
352 float m41, float m42, float m43, float m44)
|
nuclear@1
|
353 {
|
nuclear@1
|
354 M[0][0] = m11; M[0][1] = m12; M[0][2] = m13; M[0][3] = m14;
|
nuclear@1
|
355 M[1][0] = m21; M[1][1] = m22; M[1][2] = m23; M[1][3] = m24;
|
nuclear@1
|
356 M[2][0] = m31; M[2][1] = m32; M[2][2] = m33; M[2][3] = m34;
|
nuclear@1
|
357 M[3][0] = m41; M[3][1] = m42; M[3][2] = m43; M[3][3] = m44;
|
nuclear@1
|
358 }
|
nuclear@1
|
359
|
nuclear@1
|
360 Matrix4f(float m11, float m12, float m13,
|
nuclear@1
|
361 float m21, float m22, float m23,
|
nuclear@1
|
362 float m31, float m32, float m33)
|
nuclear@1
|
363 {
|
nuclear@1
|
364 M[0][0] = m11; M[0][1] = m12; M[0][2] = m13; M[0][3] = 0;
|
nuclear@1
|
365 M[1][0] = m21; M[1][1] = m22; M[1][2] = m23; M[1][3] = 0;
|
nuclear@1
|
366 M[2][0] = m31; M[2][1] = m32; M[2][2] = m33; M[2][3] = 0;
|
nuclear@1
|
367 M[3][0] = 0; M[3][1] = 0; M[3][2] = 0; M[3][3] = 1;
|
nuclear@1
|
368 }
|
nuclear@1
|
369
|
nuclear@1
|
370 static const Matrix4f& Identity() { return IdentityValue; }
|
nuclear@1
|
371
|
nuclear@1
|
372 void SetIdentity()
|
nuclear@1
|
373 {
|
nuclear@1
|
374 M[0][0] = M[1][1] = M[2][2] = M[3][3] = 1;
|
nuclear@1
|
375 M[0][1] = M[1][0] = M[2][3] = M[3][1] = 0;
|
nuclear@1
|
376 M[0][2] = M[1][2] = M[2][0] = M[3][2] = 0;
|
nuclear@1
|
377 M[0][3] = M[1][3] = M[2][1] = M[3][0] = 0;
|
nuclear@1
|
378 }
|
nuclear@1
|
379
|
nuclear@1
|
380 // Multiplies two matrices into destination with minimum copying.
|
nuclear@1
|
381 static Matrix4f& Multiply(Matrix4f* d, const Matrix4f& a, const Matrix4f& b)
|
nuclear@1
|
382 {
|
nuclear@1
|
383 OVR_ASSERT((d != &a) && (d != &b));
|
nuclear@1
|
384 int i = 0;
|
nuclear@1
|
385 do {
|
nuclear@1
|
386 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];
|
nuclear@1
|
387 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];
|
nuclear@1
|
388 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];
|
nuclear@1
|
389 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];
|
nuclear@1
|
390 } while((++i) < 4);
|
nuclear@1
|
391
|
nuclear@1
|
392 return *d;
|
nuclear@1
|
393 }
|
nuclear@1
|
394
|
nuclear@1
|
395 Matrix4f operator* (const Matrix4f& b) const
|
nuclear@1
|
396 {
|
nuclear@1
|
397 Matrix4f result(Matrix4f::NoInit);
|
nuclear@1
|
398 Multiply(&result, *this, b);
|
nuclear@1
|
399 return result;
|
nuclear@1
|
400 }
|
nuclear@1
|
401
|
nuclear@1
|
402 Matrix4f& operator*= (const Matrix4f& b)
|
nuclear@1
|
403 {
|
nuclear@1
|
404 return Multiply(this, Matrix4f(*this), b);
|
nuclear@1
|
405 }
|
nuclear@1
|
406
|
nuclear@1
|
407 Matrix4f operator* (float s) const
|
nuclear@1
|
408 {
|
nuclear@1
|
409 return Matrix4f(M[0][0] * s, M[0][1] * s, M[0][2] * s, M[0][3] * s,
|
nuclear@1
|
410 M[1][0] * s, M[1][1] * s, M[1][2] * s, M[1][3] * s,
|
nuclear@1
|
411 M[2][0] * s, M[2][1] * s, M[2][2] * s, M[2][3] * s,
|
nuclear@1
|
412 M[3][0] * s, M[3][1] * s, M[3][2] * s, M[3][3] * s);
|
nuclear@1
|
413 }
|
nuclear@1
|
414
|
nuclear@1
|
415 Matrix4f& operator*= (float s)
|
nuclear@1
|
416 {
|
nuclear@1
|
417 M[0][0] *= s; M[0][1] *= s; M[0][2] *= s; M[0][3] *= s;
|
nuclear@1
|
418 M[1][0] *= s; M[1][1] *= s; M[1][2] *= s; M[1][3] *= s;
|
nuclear@1
|
419 M[2][0] *= s; M[2][1] *= s; M[2][2] *= s; M[2][3] *= s;
|
nuclear@1
|
420 M[3][0] *= s; M[3][1] *= s; M[3][2] *= s; M[3][3] *= s;
|
nuclear@1
|
421 return *this;
|
nuclear@1
|
422 }
|
nuclear@1
|
423
|
nuclear@1
|
424 Vector3f Transform(const Vector3f& v) const
|
nuclear@1
|
425 {
|
nuclear@1
|
426 return Vector3f(M[0][0] * v.x + M[0][1] * v.y + M[0][2] * v.z + M[0][3],
|
nuclear@1
|
427 M[1][0] * v.x + M[1][1] * v.y + M[1][2] * v.z + M[1][3],
|
nuclear@1
|
428 M[2][0] * v.x + M[2][1] * v.y + M[2][2] * v.z + M[2][3]);
|
nuclear@1
|
429 }
|
nuclear@1
|
430
|
nuclear@1
|
431 Matrix4f Transposed() const
|
nuclear@1
|
432 {
|
nuclear@1
|
433 return Matrix4f(M[0][0], M[1][0], M[2][0], M[3][0],
|
nuclear@1
|
434 M[0][1], M[1][1], M[2][1], M[3][1],
|
nuclear@1
|
435 M[0][2], M[1][2], M[2][2], M[3][2],
|
nuclear@1
|
436 M[0][3], M[1][3], M[2][3], M[3][3]);
|
nuclear@1
|
437 }
|
nuclear@1
|
438
|
nuclear@1
|
439 void Transpose()
|
nuclear@1
|
440 {
|
nuclear@1
|
441 *this = Transposed();
|
nuclear@1
|
442 }
|
nuclear@1
|
443
|
nuclear@1
|
444
|
nuclear@1
|
445 float SubDet (const int* rows, const int* cols) const
|
nuclear@1
|
446 {
|
nuclear@1
|
447 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]])
|
nuclear@1
|
448 - 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]])
|
nuclear@1
|
449 + 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]]);
|
nuclear@1
|
450 }
|
nuclear@1
|
451
|
nuclear@1
|
452 float Cofactor(int I, int J) const
|
nuclear@1
|
453 {
|
nuclear@1
|
454 const int indices[4][3] = {{1,2,3},{0,2,3},{0,1,3},{0,1,2}};
|
nuclear@1
|
455 return ((I+J)&1) ? -SubDet(indices[I],indices[J]) : SubDet(indices[I],indices[J]);
|
nuclear@1
|
456 }
|
nuclear@1
|
457
|
nuclear@1
|
458 float Determinant() const
|
nuclear@1
|
459 {
|
nuclear@1
|
460 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);
|
nuclear@1
|
461 }
|
nuclear@1
|
462
|
nuclear@1
|
463 Matrix4f Adjugated() const
|
nuclear@1
|
464 {
|
nuclear@1
|
465 return Matrix4f(Cofactor(0,0), Cofactor(1,0), Cofactor(2,0), Cofactor(3,0),
|
nuclear@1
|
466 Cofactor(0,1), Cofactor(1,1), Cofactor(2,1), Cofactor(3,1),
|
nuclear@1
|
467 Cofactor(0,2), Cofactor(1,2), Cofactor(2,2), Cofactor(3,2),
|
nuclear@1
|
468 Cofactor(0,3), Cofactor(1,3), Cofactor(2,3), Cofactor(3,3));
|
nuclear@1
|
469 }
|
nuclear@1
|
470
|
nuclear@1
|
471 Matrix4f Inverted() const
|
nuclear@1
|
472 {
|
nuclear@1
|
473 float det = Determinant();
|
nuclear@1
|
474 assert(det != 0);
|
nuclear@1
|
475 return Adjugated() * (1.0f/det);
|
nuclear@1
|
476 }
|
nuclear@1
|
477
|
nuclear@1
|
478 void Invert()
|
nuclear@1
|
479 {
|
nuclear@1
|
480 *this = Inverted();
|
nuclear@1
|
481 }
|
nuclear@1
|
482
|
nuclear@1
|
483 //AnnaSteve:
|
nuclear@1
|
484 // a,b,c, are the YawPitchRoll angles to be returned
|
nuclear@1
|
485 // rotation a around axis A1
|
nuclear@1
|
486 // is followed by rotation b around axis A2
|
nuclear@1
|
487 // is followed by rotation c around axis A3
|
nuclear@1
|
488 // rotations are CCW or CW (D) in LH or RH coordinate system (S)
|
nuclear@1
|
489 template <Axis A1, Axis A2, Axis A3, RotateDirection D, HandedSystem S>
|
nuclear@1
|
490 void ToEulerAngles(float *a, float *b, float *c)
|
nuclear@1
|
491 {
|
nuclear@1
|
492 OVR_COMPILER_ASSERT((A1 != A2) && (A2 != A3) && (A1 != A3));
|
nuclear@1
|
493
|
nuclear@1
|
494 float psign = -1.0f;
|
nuclear@1
|
495 if (((A1 + 1) % 3 == A2) && ((A2 + 1) % 3 == A3)) // Determine whether even permutation
|
nuclear@1
|
496 psign = 1.0f;
|
nuclear@1
|
497
|
nuclear@1
|
498 float pm = psign*M[A1][A3];
|
nuclear@1
|
499 if (pm < -1.0f + Math<float>::SingularityRadius)
|
nuclear@1
|
500 { // South pole singularity
|
nuclear@1
|
501 *a = 0.0f;
|
nuclear@1
|
502 *b = -S*D*Math<float>::PiOver2;
|
nuclear@1
|
503 *c = S*D*atan2( psign*M[A2][A1], M[A2][A2] );
|
nuclear@1
|
504 }
|
nuclear@1
|
505 else if (pm > 1.0 - Math<float>::SingularityRadius)
|
nuclear@1
|
506 { // North pole singularity
|
nuclear@1
|
507 *a = 0.0f;
|
nuclear@1
|
508 *b = S*D*Math<float>::PiOver2;
|
nuclear@1
|
509 *c = S*D*atan2( psign*M[A2][A1], M[A2][A2] );
|
nuclear@1
|
510 }
|
nuclear@1
|
511 else
|
nuclear@1
|
512 { // Normal case (nonsingular)
|
nuclear@1
|
513 *a = S*D*atan2( -psign*M[A2][A3], M[A3][A3] );
|
nuclear@1
|
514 *b = S*D*asin(pm);
|
nuclear@1
|
515 *c = S*D*atan2( -psign*M[A1][A2], M[A1][A1] );
|
nuclear@1
|
516 }
|
nuclear@1
|
517
|
nuclear@1
|
518 return;
|
nuclear@1
|
519 }
|
nuclear@1
|
520
|
nuclear@1
|
521 //AnnaSteve:
|
nuclear@1
|
522 // a,b,c, are the YawPitchRoll angles to be returned
|
nuclear@1
|
523 // rotation a around axis A1
|
nuclear@1
|
524 // is followed by rotation b around axis A2
|
nuclear@1
|
525 // is followed by rotation c around axis A1
|
nuclear@1
|
526 // rotations are CCW or CW (D) in LH or RH coordinate system (S)
|
nuclear@1
|
527 template <Axis A1, Axis A2, RotateDirection D, HandedSystem S>
|
nuclear@1
|
528 void ToEulerAnglesABA(float *a, float *b, float *c)
|
nuclear@1
|
529 {
|
nuclear@1
|
530 OVR_COMPILER_ASSERT(A1 != A2);
|
nuclear@1
|
531
|
nuclear@1
|
532 // Determine the axis that was not supplied
|
nuclear@1
|
533 int m = 3 - A1 - A2;
|
nuclear@1
|
534
|
nuclear@1
|
535 float psign = -1.0f;
|
nuclear@1
|
536 if ((A1 + 1) % 3 == A2) // Determine whether even permutation
|
nuclear@1
|
537 psign = 1.0f;
|
nuclear@1
|
538
|
nuclear@1
|
539 float c2 = M[A1][A1];
|
nuclear@1
|
540 if (c2 < -1.0 + Math<float>::SingularityRadius)
|
nuclear@1
|
541 { // South pole singularity
|
nuclear@1
|
542 *a = 0.0f;
|
nuclear@1
|
543 *b = S*D*Math<float>::Pi;
|
nuclear@1
|
544 *c = S*D*atan2( -psign*M[A2][m],M[A2][A2]);
|
nuclear@1
|
545 }
|
nuclear@1
|
546 else if (c2 > 1.0 - Math<float>::SingularityRadius)
|
nuclear@1
|
547 { // North pole singularity
|
nuclear@1
|
548 *a = 0.0f;
|
nuclear@1
|
549 *b = 0.0f;
|
nuclear@1
|
550 *c = S*D*atan2( -psign*M[A2][m],M[A2][A2]);
|
nuclear@1
|
551 }
|
nuclear@1
|
552 else
|
nuclear@1
|
553 { // Normal case (nonsingular)
|
nuclear@1
|
554 *a = S*D*atan2( M[A2][A1],-psign*M[m][A1]);
|
nuclear@1
|
555 *b = S*D*acos(c2);
|
nuclear@1
|
556 *c = S*D*atan2( M[A1][A2],psign*M[A1][m]);
|
nuclear@1
|
557 }
|
nuclear@1
|
558 return;
|
nuclear@1
|
559 }
|
nuclear@1
|
560
|
nuclear@1
|
561 // Creates a matrix that converts the vertices from one coordinate system
|
nuclear@1
|
562 // to another.
|
nuclear@1
|
563 //
|
nuclear@1
|
564 static Matrix4f AxisConversion(const WorldAxes& to, const WorldAxes& from)
|
nuclear@1
|
565 {
|
nuclear@1
|
566 // Holds axis values from the 'to' structure
|
nuclear@1
|
567 int toArray[3] = { to.XAxis, to.YAxis, to.ZAxis };
|
nuclear@1
|
568
|
nuclear@1
|
569 // The inverse of the toArray
|
nuclear@1
|
570 int inv[4];
|
nuclear@1
|
571 inv[0] = inv[abs(to.XAxis)] = 0;
|
nuclear@1
|
572 inv[abs(to.YAxis)] = 1;
|
nuclear@1
|
573 inv[abs(to.ZAxis)] = 2;
|
nuclear@1
|
574
|
nuclear@1
|
575 Matrix4f m(0, 0, 0,
|
nuclear@1
|
576 0, 0, 0,
|
nuclear@1
|
577 0, 0, 0);
|
nuclear@1
|
578
|
nuclear@1
|
579 // Only three values in the matrix need to be changed to 1 or -1.
|
nuclear@1
|
580 m.M[inv[abs(from.XAxis)]][0] = float(from.XAxis/toArray[inv[abs(from.XAxis)]]);
|
nuclear@1
|
581 m.M[inv[abs(from.YAxis)]][1] = float(from.YAxis/toArray[inv[abs(from.YAxis)]]);
|
nuclear@1
|
582 m.M[inv[abs(from.ZAxis)]][2] = float(from.ZAxis/toArray[inv[abs(from.ZAxis)]]);
|
nuclear@1
|
583 return m;
|
nuclear@1
|
584 }
|
nuclear@1
|
585
|
nuclear@1
|
586
|
nuclear@1
|
587
|
nuclear@1
|
588 static Matrix4f Translation(const Vector3f& v)
|
nuclear@1
|
589 {
|
nuclear@1
|
590 Matrix4f t;
|
nuclear@1
|
591 t.M[0][3] = v.x;
|
nuclear@1
|
592 t.M[1][3] = v.y;
|
nuclear@1
|
593 t.M[2][3] = v.z;
|
nuclear@1
|
594 return t;
|
nuclear@1
|
595 }
|
nuclear@1
|
596
|
nuclear@1
|
597 static Matrix4f Translation(float x, float y, float z = 0.0f)
|
nuclear@1
|
598 {
|
nuclear@1
|
599 Matrix4f t;
|
nuclear@1
|
600 t.M[0][3] = x;
|
nuclear@1
|
601 t.M[1][3] = y;
|
nuclear@1
|
602 t.M[2][3] = z;
|
nuclear@1
|
603 return t;
|
nuclear@1
|
604 }
|
nuclear@1
|
605
|
nuclear@1
|
606 static Matrix4f Scaling(const Vector3f& v)
|
nuclear@1
|
607 {
|
nuclear@1
|
608 Matrix4f t;
|
nuclear@1
|
609 t.M[0][0] = v.x;
|
nuclear@1
|
610 t.M[1][1] = v.y;
|
nuclear@1
|
611 t.M[2][2] = v.z;
|
nuclear@1
|
612 return t;
|
nuclear@1
|
613 }
|
nuclear@1
|
614
|
nuclear@1
|
615 static Matrix4f Scaling(float x, float y, float z)
|
nuclear@1
|
616 {
|
nuclear@1
|
617 Matrix4f t;
|
nuclear@1
|
618 t.M[0][0] = x;
|
nuclear@1
|
619 t.M[1][1] = y;
|
nuclear@1
|
620 t.M[2][2] = z;
|
nuclear@1
|
621 return t;
|
nuclear@1
|
622 }
|
nuclear@1
|
623
|
nuclear@1
|
624 static Matrix4f Scaling(float s)
|
nuclear@1
|
625 {
|
nuclear@1
|
626 Matrix4f t;
|
nuclear@1
|
627 t.M[0][0] = s;
|
nuclear@1
|
628 t.M[1][1] = s;
|
nuclear@1
|
629 t.M[2][2] = s;
|
nuclear@1
|
630 return t;
|
nuclear@1
|
631 }
|
nuclear@1
|
632
|
nuclear@1
|
633
|
nuclear@1
|
634
|
nuclear@1
|
635 //AnnaSteve : Just for quick testing. Not for final API. Need to remove case.
|
nuclear@1
|
636 static Matrix4f RotationAxis(Axis A, float angle, RotateDirection d, HandedSystem s)
|
nuclear@1
|
637 {
|
nuclear@1
|
638 float sina = s * d *sin(angle);
|
nuclear@1
|
639 float cosa = cos(angle);
|
nuclear@1
|
640
|
nuclear@1
|
641 switch(A)
|
nuclear@1
|
642 {
|
nuclear@1
|
643 case Axis_X:
|
nuclear@1
|
644 return Matrix4f(1, 0, 0,
|
nuclear@1
|
645 0, cosa, -sina,
|
nuclear@1
|
646 0, sina, cosa);
|
nuclear@1
|
647 case Axis_Y:
|
nuclear@1
|
648 return Matrix4f(cosa, 0, sina,
|
nuclear@1
|
649 0, 1, 0,
|
nuclear@1
|
650 -sina, 0, cosa);
|
nuclear@1
|
651 case Axis_Z:
|
nuclear@1
|
652 return Matrix4f(cosa, -sina, 0,
|
nuclear@1
|
653 sina, cosa, 0,
|
nuclear@1
|
654 0, 0, 1);
|
nuclear@1
|
655 }
|
nuclear@1
|
656 }
|
nuclear@1
|
657
|
nuclear@1
|
658
|
nuclear@1
|
659 // Creates a rotation matrix rotating around the X axis by 'angle' radians.
|
nuclear@1
|
660 // Rotation direction is depends on the coordinate system:
|
nuclear@1
|
661 // RHS (Oculus default): Positive angle values rotate Counter-clockwise (CCW),
|
nuclear@1
|
662 // while looking in the negative axis direction. This is the
|
nuclear@1
|
663 // same as looking down from positive axis values towards origin.
|
nuclear@1
|
664 // LHS: Positive angle values rotate clock-wise (CW), while looking in the
|
nuclear@1
|
665 // negative axis direction.
|
nuclear@1
|
666 static Matrix4f RotationX(float angle)
|
nuclear@1
|
667 {
|
nuclear@1
|
668 float sina = sin(angle);
|
nuclear@1
|
669 float cosa = cos(angle);
|
nuclear@1
|
670 return Matrix4f(1, 0, 0,
|
nuclear@1
|
671 0, cosa, -sina,
|
nuclear@1
|
672 0, sina, cosa);
|
nuclear@1
|
673 }
|
nuclear@1
|
674
|
nuclear@1
|
675 // Creates a rotation matrix rotating around the Y axis by 'angle' radians.
|
nuclear@1
|
676 // Rotation direction is depends on the coordinate system:
|
nuclear@1
|
677 // RHS (Oculus default): Positive angle values rotate Counter-clockwise (CCW),
|
nuclear@1
|
678 // while looking in the negative axis direction. This is the
|
nuclear@1
|
679 // same as looking down from positive axis values towards origin.
|
nuclear@1
|
680 // LHS: Positive angle values rotate clock-wise (CW), while looking in the
|
nuclear@1
|
681 // negative axis direction.
|
nuclear@1
|
682 static Matrix4f RotationY(float angle)
|
nuclear@1
|
683 {
|
nuclear@1
|
684 float sina = sin(angle);
|
nuclear@1
|
685 float cosa = cos(angle);
|
nuclear@1
|
686 return Matrix4f(cosa, 0, sina,
|
nuclear@1
|
687 0, 1, 0,
|
nuclear@1
|
688 -sina, 0, cosa);
|
nuclear@1
|
689 }
|
nuclear@1
|
690
|
nuclear@1
|
691 // Creates a rotation matrix rotating around the Z axis by 'angle' radians.
|
nuclear@1
|
692 // Rotation direction is depends on the coordinate system:
|
nuclear@1
|
693 // RHS (Oculus default): Positive angle values rotate Counter-clockwise (CCW),
|
nuclear@1
|
694 // while looking in the negative axis direction. This is the
|
nuclear@1
|
695 // same as looking down from positive axis values towards origin.
|
nuclear@1
|
696 // LHS: Positive angle values rotate clock-wise (CW), while looking in the
|
nuclear@1
|
697 // negative axis direction.
|
nuclear@1
|
698 static Matrix4f RotationZ(float angle)
|
nuclear@1
|
699 {
|
nuclear@1
|
700 float sina = sin(angle);
|
nuclear@1
|
701 float cosa = cos(angle);
|
nuclear@1
|
702 return Matrix4f(cosa, -sina, 0,
|
nuclear@1
|
703 sina, cosa, 0,
|
nuclear@1
|
704 0, 0, 1);
|
nuclear@1
|
705 }
|
nuclear@1
|
706
|
nuclear@1
|
707
|
nuclear@1
|
708 // LookAtRH creates a View transformation matrix for right-handed coordinate system.
|
nuclear@1
|
709 // The resulting matrix points camera from 'eye' towards 'at' direction, with 'up'
|
nuclear@1
|
710 // specifying the up vector. The resulting matrix should be used with PerspectiveRH
|
nuclear@1
|
711 // projection.
|
nuclear@1
|
712 static Matrix4f LookAtRH(const Vector3f& eye, const Vector3f& at, const Vector3f& up);
|
nuclear@1
|
713
|
nuclear@1
|
714 // LookAtLH creates a View transformation matrix for left-handed coordinate system.
|
nuclear@1
|
715 // The resulting matrix points camera from 'eye' towards 'at' direction, with 'up'
|
nuclear@1
|
716 // specifying the up vector.
|
nuclear@1
|
717 static Matrix4f LookAtLH(const Vector3f& eye, const Vector3f& at, const Vector3f& up);
|
nuclear@1
|
718
|
nuclear@1
|
719
|
nuclear@1
|
720 // PerspectiveRH creates a right-handed perspective projection matrix that can be
|
nuclear@1
|
721 // used with the Oculus sample renderer.
|
nuclear@1
|
722 // yfov - Specifies vertical field of view in radians.
|
nuclear@1
|
723 // aspect - Screen aspect ration, which is usually width/height for square pixels.
|
nuclear@1
|
724 // Note that xfov = yfov * aspect.
|
nuclear@1
|
725 // znear - Absolute value of near Z clipping clipping range.
|
nuclear@1
|
726 // zfar - Absolute value of far Z clipping clipping range (larger then near).
|
nuclear@1
|
727 // Even though RHS usually looks in the direction of negative Z, positive values
|
nuclear@1
|
728 // are expected for znear and zfar.
|
nuclear@1
|
729 static Matrix4f PerspectiveRH(float yfov, float aspect, float znear, float zfar);
|
nuclear@1
|
730
|
nuclear@1
|
731
|
nuclear@1
|
732 // PerspectiveRH creates a left-handed perspective projection matrix that can be
|
nuclear@1
|
733 // used with the Oculus sample renderer.
|
nuclear@1
|
734 // yfov - Specifies vertical field of view in radians.
|
nuclear@1
|
735 // aspect - Screen aspect ration, which is usually width/height for square pixels.
|
nuclear@1
|
736 // Note that xfov = yfov * aspect.
|
nuclear@1
|
737 // znear - Absolute value of near Z clipping clipping range.
|
nuclear@1
|
738 // zfar - Absolute value of far Z clipping clipping range (larger then near).
|
nuclear@1
|
739 static Matrix4f PerspectiveLH(float yfov, float aspect, float znear, float zfar);
|
nuclear@1
|
740
|
nuclear@1
|
741
|
nuclear@1
|
742 static Matrix4f Ortho2D(float w, float h);
|
nuclear@1
|
743 };
|
nuclear@1
|
744
|
nuclear@1
|
745
|
nuclear@1
|
746 //-------------------------------------------------------------------------------------
|
nuclear@1
|
747 // ***** Quat
|
nuclear@1
|
748
|
nuclear@1
|
749 // Quatf represents a quaternion class used for rotations.
|
nuclear@1
|
750 //
|
nuclear@1
|
751 // Quaternion multiplications are done in right-to-left order, to match the
|
nuclear@1
|
752 // behavior of matrices.
|
nuclear@1
|
753
|
nuclear@1
|
754
|
nuclear@1
|
755 template<class T>
|
nuclear@1
|
756 class Quat
|
nuclear@1
|
757 {
|
nuclear@1
|
758 public:
|
nuclear@1
|
759 // w + Xi + Yj + Zk
|
nuclear@1
|
760 T x, y, z, w;
|
nuclear@1
|
761
|
nuclear@1
|
762 Quat() : x(0), y(0), z(0), w(1) {}
|
nuclear@1
|
763 Quat(T x_, T y_, T z_, T w_) : x(x_), y(y_), z(z_), w(w_) {}
|
nuclear@1
|
764
|
nuclear@1
|
765
|
nuclear@1
|
766 // Constructs rotation quaternion around the axis.
|
nuclear@1
|
767 Quat(const Vector3<T>& axis, T angle)
|
nuclear@1
|
768 {
|
nuclear@1
|
769 Vector3<T> unitAxis = axis.Normalized();
|
nuclear@1
|
770 T sinHalfAngle = sin(angle * T(0.5));
|
nuclear@1
|
771
|
nuclear@1
|
772 w = cos(angle * T(0.5));
|
nuclear@1
|
773 x = unitAxis.x * sinHalfAngle;
|
nuclear@1
|
774 y = unitAxis.y * sinHalfAngle;
|
nuclear@1
|
775 z = unitAxis.z * sinHalfAngle;
|
nuclear@1
|
776 }
|
nuclear@1
|
777
|
nuclear@1
|
778 //AnnaSteve:
|
nuclear@1
|
779 void AxisAngle(Axis A, T angle, RotateDirection d, HandedSystem s)
|
nuclear@1
|
780 {
|
nuclear@1
|
781 T sinHalfAngle = s * d *sin(angle * (T)0.5);
|
nuclear@1
|
782 T v[3];
|
nuclear@1
|
783 v[0] = v[1] = v[2] = (T)0;
|
nuclear@1
|
784 v[A] = sinHalfAngle;
|
nuclear@1
|
785 //return Quat(v[0], v[1], v[2], cos(angle * (T)0.5));
|
nuclear@1
|
786 w = cos(angle * (T)0.5);
|
nuclear@1
|
787 x = v[0];
|
nuclear@1
|
788 y = v[1];
|
nuclear@1
|
789 z = v[2];
|
nuclear@1
|
790 }
|
nuclear@1
|
791
|
nuclear@1
|
792
|
nuclear@1
|
793 void GetAxisAngle(Vector3<T>* axis, T* angle) const
|
nuclear@1
|
794 {
|
nuclear@1
|
795 if (LengthSq() > Math<T>::Tolerance * Math<T>::Tolerance)
|
nuclear@1
|
796 {
|
nuclear@1
|
797 *axis = Vector3<T>(x, y, z).Normalized();
|
nuclear@1
|
798 *angle = 2 * acos(w);
|
nuclear@1
|
799 }
|
nuclear@1
|
800 else
|
nuclear@1
|
801 {
|
nuclear@1
|
802 *axis = Vector3<T>(1, 0, 0);
|
nuclear@1
|
803 *angle= 0;
|
nuclear@1
|
804 }
|
nuclear@1
|
805 }
|
nuclear@1
|
806
|
nuclear@1
|
807 bool operator== (const Quat& b) const { return x == b.x && y == b.y && z == b.z && w == b.w; }
|
nuclear@1
|
808 bool operator!= (const Quat& b) const { return x != b.x || y != b.y || z != b.z || w != b.w; }
|
nuclear@1
|
809
|
nuclear@1
|
810 Quat operator+ (const Quat& b) const { return Quat(x + b.x, y + b.y, z + b.z, w + b.w); }
|
nuclear@1
|
811 Quat& operator+= (const Quat& b) { w += b.w; x += b.x; y += b.y; z += b.z; return *this; }
|
nuclear@1
|
812 Quat operator- (const Quat& b) const { return Quat(x - b.x, y - b.y, z - b.z, w - b.w); }
|
nuclear@1
|
813 Quat& operator-= (const Quat& b) { w -= b.w; x -= b.x; y -= b.y; z -= b.z; return *this; }
|
nuclear@1
|
814
|
nuclear@1
|
815 Quat operator* (T s) const { return Quat(x * s, y * s, z * s, w * s); }
|
nuclear@1
|
816 Quat& operator*= (T s) { w *= s; x *= s; y *= s; z *= s; return *this; }
|
nuclear@1
|
817 Quat operator/ (T s) const { T rcp = T(1)/s; return Quat(x * rcp, y * rcp, z * rcp, w *rcp); }
|
nuclear@1
|
818 Quat& operator/= (T s) { T rcp = T(1)/s; w *= rcp; x *= rcp; y *= rcp; z *= rcp; return *this; }
|
nuclear@1
|
819
|
nuclear@1
|
820 // Get Imaginary part vector
|
nuclear@1
|
821 Vector3<T> Imag() const { return Vector3<T>(x,y,z); }
|
nuclear@1
|
822
|
nuclear@1
|
823 // Get quaternion length.
|
nuclear@1
|
824 T Length() const { return sqrt(x * x + y * y + z * z + w * w); }
|
nuclear@1
|
825 // Get quaternion length squared.
|
nuclear@1
|
826 T LengthSq() const { return (x * x + y * y + z * z + w * w); }
|
nuclear@1
|
827 // Simple Eulidean distance in R^4 (not SLERP distance, but at least respects Haar measure)
|
nuclear@1
|
828 T Distance(const Quat& q) const
|
nuclear@1
|
829 {
|
nuclear@1
|
830 T d1 = (*this - q).Length();
|
nuclear@1
|
831 T d2 = (*this + q).Length(); // Antipoldal point check
|
nuclear@1
|
832 return (d1 < d2) ? d1 : d2;
|
nuclear@1
|
833 }
|
nuclear@1
|
834 T DistanceSq(const Quat& q) const
|
nuclear@1
|
835 {
|
nuclear@1
|
836 T d1 = (*this - q).LengthSq();
|
nuclear@1
|
837 T d2 = (*this + q).LengthSq(); // Antipoldal point check
|
nuclear@1
|
838 return (d1 < d2) ? d1 : d2;
|
nuclear@1
|
839 }
|
nuclear@1
|
840
|
nuclear@1
|
841 // Normalize
|
nuclear@1
|
842 bool IsNormalized() const { return fabs(LengthSq() - 1) < Math<T>::Tolerance; }
|
nuclear@1
|
843 void Normalize() { *this /= Length(); }
|
nuclear@1
|
844 Quat Normalized() const { return *this / Length(); }
|
nuclear@1
|
845
|
nuclear@1
|
846 // Returns conjugate of the quaternion. Produces inverse rotation if quaternion is normalized.
|
nuclear@1
|
847 Quat Conj() const { return Quat(-x, -y, -z, w); }
|
nuclear@1
|
848
|
nuclear@1
|
849 // AnnaSteve fixed: order of quaternion multiplication
|
nuclear@1
|
850 // Quaternion multiplication. Combines quaternion rotations, performing the one on the
|
nuclear@1
|
851 // right hand side first.
|
nuclear@1
|
852 Quat operator* (const Quat& b) const { return Quat(w * b.x + x * b.w + y * b.z - z * b.y,
|
nuclear@1
|
853 w * b.y - x * b.z + y * b.w + z * b.x,
|
nuclear@1
|
854 w * b.z + x * b.y - y * b.x + z * b.w,
|
nuclear@1
|
855 w * b.w - x * b.x - y * b.y - z * b.z); }
|
nuclear@1
|
856
|
nuclear@1
|
857 //
|
nuclear@1
|
858 // this^p normalized; same as rotating by this p times.
|
nuclear@1
|
859 Quat PowNormalized(T p) const
|
nuclear@1
|
860 {
|
nuclear@1
|
861 Vector3<T> v;
|
nuclear@1
|
862 T a;
|
nuclear@1
|
863 GetAxisAngle(&v, &a);
|
nuclear@1
|
864 return Quat(v, a * p);
|
nuclear@1
|
865 }
|
nuclear@1
|
866
|
nuclear@1
|
867 // Rotate transforms vector in a manner that matches Matrix rotations (counter-clockwise,
|
nuclear@1
|
868 // assuming negative direction of the axis). Standard formula: q(t) * V * q(t)^-1.
|
nuclear@1
|
869 Vector3<T> Rotate(const Vector3<T>& v) const
|
nuclear@1
|
870 {
|
nuclear@1
|
871 return ((*this * Quat<T>(v.x, v.y, v.z, 0)) * Inverted()).Imag();
|
nuclear@1
|
872 }
|
nuclear@1
|
873
|
nuclear@1
|
874
|
nuclear@1
|
875 // Inversed quaternion rotates in the opposite direction.
|
nuclear@1
|
876 Quat Inverted() const
|
nuclear@1
|
877 {
|
nuclear@1
|
878 return Quat(-x, -y, -z, w);
|
nuclear@1
|
879 }
|
nuclear@1
|
880
|
nuclear@1
|
881 // Sets this quaternion to the one rotates in the opposite direction.
|
nuclear@1
|
882 void Invert()
|
nuclear@1
|
883 {
|
nuclear@1
|
884 *this = Quat(-x, -y, -z, w);
|
nuclear@1
|
885 }
|
nuclear@1
|
886
|
nuclear@1
|
887 // Converting quaternion to matrix.
|
nuclear@1
|
888 operator Matrix4f() const
|
nuclear@1
|
889 {
|
nuclear@1
|
890 T ww = w*w;
|
nuclear@1
|
891 T xx = x*x;
|
nuclear@1
|
892 T yy = y*y;
|
nuclear@1
|
893 T zz = z*z;
|
nuclear@1
|
894
|
nuclear@1
|
895 return Matrix4f(float(ww + xx - yy - zz), float(T(2) * (x*y - w*z)), float(T(2) * (x*z + w*y)),
|
nuclear@1
|
896 float(T(2) * (x*y + w*z)), float(ww - xx + yy - zz), float(T(2) * (y*z - w*x)),
|
nuclear@1
|
897 float(T(2) * (x*z - w*y)), float(T(2) * (y*z + w*x)), float(ww - xx - yy + zz) );
|
nuclear@1
|
898 }
|
nuclear@1
|
899
|
nuclear@1
|
900
|
nuclear@1
|
901 // GetEulerAngles extracts Euler angles from the quaternion, in the specified order of
|
nuclear@1
|
902 // axis rotations and the specified coordinate system. Right-handed coordinate system
|
nuclear@1
|
903 // is the default, with CCW rotations while looking in the negative axis direction.
|
nuclear@1
|
904 // Here a,b,c, are the Yaw/Pitch/Roll angles to be returned.
|
nuclear@1
|
905 // rotation a around axis A1
|
nuclear@1
|
906 // is followed by rotation b around axis A2
|
nuclear@1
|
907 // is followed by rotation c around axis A3
|
nuclear@1
|
908 // rotations are CCW or CW (D) in LH or RH coordinate system (S)
|
nuclear@1
|
909 template <Axis A1, Axis A2, Axis A3, RotateDirection D, HandedSystem S>
|
nuclear@1
|
910 void GetEulerAngles(T *a, T *b, T *c)
|
nuclear@1
|
911 {
|
nuclear@1
|
912 OVR_COMPILER_ASSERT((A1 != A2) && (A2 != A3) && (A1 != A3));
|
nuclear@1
|
913
|
nuclear@1
|
914 T Q[3] = { x, y, z }; //Quaternion components x,y,z
|
nuclear@1
|
915
|
nuclear@1
|
916 T ww = w*w;
|
nuclear@1
|
917 T Q11 = Q[A1]*Q[A1];
|
nuclear@1
|
918 T Q22 = Q[A2]*Q[A2];
|
nuclear@1
|
919 T Q33 = Q[A3]*Q[A3];
|
nuclear@1
|
920
|
nuclear@1
|
921 T psign = T(-1.0);
|
nuclear@1
|
922 // Determine whether even permutation
|
nuclear@1
|
923 if (((A1 + 1) % 3 == A2) && ((A2 + 1) % 3 == A3))
|
nuclear@1
|
924 psign = T(1.0);
|
nuclear@1
|
925
|
nuclear@1
|
926 T s2 = psign * T(2.0) * (psign*w*Q[A2] + Q[A1]*Q[A3]);
|
nuclear@1
|
927
|
nuclear@1
|
928 if (s2 < (T)-1.0 + Math<T>::SingularityRadius)
|
nuclear@1
|
929 { // South pole singularity
|
nuclear@1
|
930 *a = T(0.0);
|
nuclear@1
|
931 *b = -S*D*Math<T>::PiOver2;
|
nuclear@1
|
932 *c = S*D*atan2((T)2.0*(psign*Q[A1]*Q[A2] + w*Q[A3]),
|
nuclear@1
|
933 ww + Q22 - Q11 - Q33 );
|
nuclear@1
|
934 }
|
nuclear@1
|
935 else if (s2 > (T)1.0 - Math<T>::SingularityRadius)
|
nuclear@1
|
936 { // North pole singularity
|
nuclear@1
|
937 *a = (T)0.0;
|
nuclear@1
|
938 *b = S*D*Math<T>::PiOver2;
|
nuclear@1
|
939 *c = S*D*atan2((T)2.0*(psign*Q[A1]*Q[A2] + w*Q[A3]),
|
nuclear@1
|
940 ww + Q22 - Q11 - Q33);
|
nuclear@1
|
941 }
|
nuclear@1
|
942 else
|
nuclear@1
|
943 {
|
nuclear@1
|
944 *a = -S*D*atan2((T)-2.0*(w*Q[A1] - psign*Q[A2]*Q[A3]),
|
nuclear@1
|
945 ww + Q33 - Q11 - Q22);
|
nuclear@1
|
946 *b = S*D*asin(s2);
|
nuclear@1
|
947 *c = S*D*atan2((T)2.0*(w*Q[A3] - psign*Q[A1]*Q[A2]),
|
nuclear@1
|
948 ww + Q11 - Q22 - Q33);
|
nuclear@1
|
949 }
|
nuclear@1
|
950 return;
|
nuclear@1
|
951 }
|
nuclear@1
|
952
|
nuclear@1
|
953 template <Axis A1, Axis A2, Axis A3, RotateDirection D>
|
nuclear@1
|
954 void GetEulerAngles(T *a, T *b, T *c)
|
nuclear@1
|
955 { GetEulerAngles<A1, A2, A3, D, Handed_R>(a, b, c); }
|
nuclear@1
|
956
|
nuclear@1
|
957 template <Axis A1, Axis A2, Axis A3>
|
nuclear@1
|
958 void GetEulerAngles(T *a, T *b, T *c)
|
nuclear@1
|
959 { GetEulerAngles<A1, A2, A3, Rotate_CCW, Handed_R>(a, b, c); }
|
nuclear@1
|
960
|
nuclear@1
|
961
|
nuclear@1
|
962 // GetEulerAnglesABA extracts Euler angles from the quaternion, in the specified order of
|
nuclear@1
|
963 // axis rotations and the specified coordinate system. Right-handed coordinate system
|
nuclear@1
|
964 // is the default, with CCW rotations while looking in the negative axis direction.
|
nuclear@1
|
965 // Here a,b,c, are the Yaw/Pitch/Roll angles to be returned.
|
nuclear@1
|
966 // rotation a around axis A1
|
nuclear@1
|
967 // is followed by rotation b around axis A2
|
nuclear@1
|
968 // is followed by rotation c around axis A1
|
nuclear@1
|
969 // Rotations are CCW or CW (D) in LH or RH coordinate system (S)
|
nuclear@1
|
970 template <Axis A1, Axis A2, RotateDirection D, HandedSystem S>
|
nuclear@1
|
971 void GetEulerAnglesABA(T *a, T *b, T *c)
|
nuclear@1
|
972 {
|
nuclear@1
|
973 OVR_COMPILER_ASSERT(A1 != A2);
|
nuclear@1
|
974
|
nuclear@1
|
975 T Q[3] = {x, y, z}; // Quaternion components
|
nuclear@1
|
976
|
nuclear@1
|
977 // Determine the missing axis that was not supplied
|
nuclear@1
|
978 int m = 3 - A1 - A2;
|
nuclear@1
|
979
|
nuclear@1
|
980 T ww = w*w;
|
nuclear@1
|
981 T Q11 = Q[A1]*Q[A1];
|
nuclear@1
|
982 T Q22 = Q[A2]*Q[A2];
|
nuclear@1
|
983 T Qmm = Q[m]*Q[m];
|
nuclear@1
|
984
|
nuclear@1
|
985 T psign = T(-1.0);
|
nuclear@1
|
986 if ((A1 + 1) % 3 == A2) // Determine whether even permutation
|
nuclear@1
|
987 {
|
nuclear@1
|
988 psign = (T)1.0;
|
nuclear@1
|
989 }
|
nuclear@1
|
990
|
nuclear@1
|
991 T c2 = ww + Q11 - Q22 - Qmm;
|
nuclear@1
|
992 if (c2 < (T)-1.0 + Math<T>::SingularityRadius)
|
nuclear@1
|
993 { // South pole singularity
|
nuclear@1
|
994 *a = (T)0.0;
|
nuclear@1
|
995 *b = S*D*Math<T>::Pi;
|
nuclear@1
|
996 *c = S*D*atan2( (T)2.0*(w*Q[A1] - psign*Q[A2]*Q[m]),
|
nuclear@1
|
997 ww + Q22 - Q11 - Qmm);
|
nuclear@1
|
998 }
|
nuclear@1
|
999 else if (c2 > (T)1.0 - Math<T>::SingularityRadius)
|
nuclear@1
|
1000 { // North pole singularity
|
nuclear@1
|
1001 *a = (T)0.0;
|
nuclear@1
|
1002 *b = (T)0.0;
|
nuclear@1
|
1003 *c = S*D*atan2( (T)2.0*(w*Q[A1] - psign*Q[A2]*Q[m]),
|
nuclear@1
|
1004 ww + Q22 - Q11 - Qmm);
|
nuclear@1
|
1005 }
|
nuclear@1
|
1006 else
|
nuclear@1
|
1007 {
|
nuclear@1
|
1008 *a = S*D*atan2( psign*w*Q[m] + Q[A1]*Q[A2],
|
nuclear@1
|
1009 w*Q[A2] -psign*Q[A1]*Q[m]);
|
nuclear@1
|
1010 *b = S*D*acos(c2);
|
nuclear@1
|
1011 *c = S*D*atan2( -psign*w*Q[m] + Q[A1]*Q[A2],
|
nuclear@1
|
1012 w*Q[A2] + psign*Q[A1]*Q[m]);
|
nuclear@1
|
1013 }
|
nuclear@1
|
1014 return;
|
nuclear@1
|
1015 }
|
nuclear@1
|
1016 };
|
nuclear@1
|
1017
|
nuclear@1
|
1018
|
nuclear@1
|
1019 typedef Quat<float> Quatf;
|
nuclear@1
|
1020 typedef Quat<double> Quatd;
|
nuclear@1
|
1021
|
nuclear@1
|
1022
|
nuclear@1
|
1023
|
nuclear@1
|
1024 //-------------------------------------------------------------------------------------
|
nuclear@1
|
1025 // ***** Angle
|
nuclear@1
|
1026
|
nuclear@1
|
1027 // Cleanly representing the algebra of 2D rotations.
|
nuclear@1
|
1028 // The operations maintain the angle between -Pi and Pi, the same range as atan2.
|
nuclear@1
|
1029 //
|
nuclear@1
|
1030
|
nuclear@1
|
1031 template<class T>
|
nuclear@1
|
1032 class Angle
|
nuclear@1
|
1033 {
|
nuclear@1
|
1034 public:
|
nuclear@1
|
1035 enum AngularUnits
|
nuclear@1
|
1036 {
|
nuclear@1
|
1037 Radians = 0,
|
nuclear@1
|
1038 Degrees = 1
|
nuclear@1
|
1039 };
|
nuclear@1
|
1040
|
nuclear@1
|
1041 Angle() : a(0) {}
|
nuclear@1
|
1042
|
nuclear@1
|
1043 // Fix the range to be between -Pi and Pi
|
nuclear@1
|
1044 Angle(T a_, AngularUnits u = Radians) : a((u == Radians) ? a_ : a_*Math<T>::DegreeToRadFactor) { FixRange(); }
|
nuclear@1
|
1045
|
nuclear@1
|
1046 T Get(AngularUnits u = Radians) const { return (u == Radians) ? a : a*Math<T>::RadToDegreeFactor; }
|
nuclear@1
|
1047 void Set(const T& x, AngularUnits u = Radians) { a = (u == Radians) ? x : x*Math<T>::DegreeToRadFactor; FixRange(); }
|
nuclear@1
|
1048 int Sign() const { if (a == 0) return 0; else return (a > 0) ? 1 : -1; }
|
nuclear@1
|
1049 T Abs() const { return (a > 0) ? a : -a; }
|
nuclear@1
|
1050
|
nuclear@1
|
1051 bool operator== (const Angle& b) const { return a == b.a; }
|
nuclear@1
|
1052 bool operator!= (const Angle& b) const { return a != b.a; }
|
nuclear@1
|
1053 // bool operator< (const Angle& b) const { return a < a.b; }
|
nuclear@1
|
1054 // bool operator> (const Angle& b) const { return a > a.b; }
|
nuclear@1
|
1055 // bool operator<= (const Angle& b) const { return a <= a.b; }
|
nuclear@1
|
1056 // bool operator>= (const Angle& b) const { return a >= a.b; }
|
nuclear@1
|
1057 // bool operator= (const T& x) { a = x; FixRange(); }
|
nuclear@1
|
1058
|
nuclear@1
|
1059 // These operations assume a is already between -Pi and Pi.
|
nuclear@1
|
1060 Angle operator+ (const Angle& b) const { return Angle(a + b.a); }
|
nuclear@1
|
1061 Angle operator+ (const T& x) const { return Angle(a + x); }
|
nuclear@1
|
1062 Angle& operator+= (const Angle& b) { a = a + b.a; FastFixRange(); return *this; }
|
nuclear@1
|
1063 Angle& operator+= (const T& x) { a = a + x; FixRange(); return *this; }
|
nuclear@1
|
1064 Angle operator- (const Angle& b) const { return Angle(a - b.a); }
|
nuclear@1
|
1065 Angle operator- (const T& x) const { return Angle(a - x); }
|
nuclear@1
|
1066 Angle& operator-= (const Angle& b) { a = a - b.a; FastFixRange(); return *this; }
|
nuclear@1
|
1067 Angle& operator-= (const T& x) { a = a - x; FixRange(); return *this; }
|
nuclear@1
|
1068
|
nuclear@1
|
1069 T Distance(const Angle& b) { T c = fabs(a - b.a); return (c <= Math<T>::Pi) ? c : Math<T>::TwoPi - c; }
|
nuclear@1
|
1070
|
nuclear@1
|
1071 private:
|
nuclear@1
|
1072
|
nuclear@1
|
1073 // The stored angle, which should be maintained between -Pi and Pi
|
nuclear@1
|
1074 T a;
|
nuclear@1
|
1075
|
nuclear@1
|
1076 // Fixes the angle range to [-Pi,Pi], but assumes no more than 2Pi away on either side
|
nuclear@1
|
1077 inline void FastFixRange()
|
nuclear@1
|
1078 {
|
nuclear@1
|
1079 if (a < -Math<T>::Pi)
|
nuclear@1
|
1080 a += Math<T>::TwoPi;
|
nuclear@1
|
1081 else if (a > Math<T>::Pi)
|
nuclear@1
|
1082 a -= Math<T>::TwoPi;
|
nuclear@1
|
1083 }
|
nuclear@1
|
1084
|
nuclear@1
|
1085 // Fixes the angle range to [-Pi,Pi] for any given range, but slower then the fast method
|
nuclear@1
|
1086 inline void FixRange()
|
nuclear@1
|
1087 {
|
nuclear@1
|
1088 a = fmod(a,Math<T>::TwoPi);
|
nuclear@1
|
1089 if (a < -Math<T>::Pi)
|
nuclear@1
|
1090 a += Math<T>::TwoPi;
|
nuclear@1
|
1091 else if (a > Math<T>::Pi)
|
nuclear@1
|
1092 a -= Math<T>::TwoPi;
|
nuclear@1
|
1093 }
|
nuclear@1
|
1094 };
|
nuclear@1
|
1095
|
nuclear@1
|
1096
|
nuclear@1
|
1097 typedef Angle<float> Anglef;
|
nuclear@1
|
1098 typedef Angle<double> Angled;
|
nuclear@1
|
1099
|
nuclear@1
|
1100
|
nuclear@1
|
1101 //-------------------------------------------------------------------------------------
|
nuclear@1
|
1102 // ***** Plane
|
nuclear@1
|
1103
|
nuclear@1
|
1104 // Consists of a normal vector and distance from the origin where the plane is located.
|
nuclear@1
|
1105
|
nuclear@1
|
1106 template<class T>
|
nuclear@1
|
1107 class Plane : public RefCountBase<Plane<T> >
|
nuclear@1
|
1108 {
|
nuclear@1
|
1109 public:
|
nuclear@1
|
1110 Vector3<T> N;
|
nuclear@1
|
1111 T D;
|
nuclear@1
|
1112
|
nuclear@1
|
1113 Plane() : D(0) {}
|
nuclear@1
|
1114
|
nuclear@1
|
1115 // Normals must already be normalized
|
nuclear@1
|
1116 Plane(const Vector3<T>& n, T d) : N(n), D(d) {}
|
nuclear@1
|
1117 Plane(T x, T y, T z, T d) : N(x,y,z), D(d) {}
|
nuclear@1
|
1118
|
nuclear@1
|
1119 // construct from a point on the plane and the normal
|
nuclear@1
|
1120 Plane(const Vector3<T>& p, const Vector3<T>& n) : N(n), D(-(p * n)) {}
|
nuclear@1
|
1121
|
nuclear@1
|
1122 // Find the point to plane distance. The sign indicates what side of the plane the point is on (0 = point on plane).
|
nuclear@1
|
1123 T TestSide(const Vector3<T>& p) const
|
nuclear@1
|
1124 {
|
nuclear@1
|
1125 return (N * p) + D;
|
nuclear@1
|
1126 }
|
nuclear@1
|
1127
|
nuclear@1
|
1128 Plane<T> Flipped() const
|
nuclear@1
|
1129 {
|
nuclear@1
|
1130 return Plane(-N, -D);
|
nuclear@1
|
1131 }
|
nuclear@1
|
1132
|
nuclear@1
|
1133 void Flip()
|
nuclear@1
|
1134 {
|
nuclear@1
|
1135 N = -N;
|
nuclear@1
|
1136 D = -D;
|
nuclear@1
|
1137 }
|
nuclear@1
|
1138
|
nuclear@1
|
1139 bool operator==(const Plane<T>& rhs) const
|
nuclear@1
|
1140 {
|
nuclear@1
|
1141 return (this->D == rhs.D && this->N == rhs.N);
|
nuclear@1
|
1142 }
|
nuclear@1
|
1143 };
|
nuclear@1
|
1144
|
nuclear@1
|
1145 typedef Plane<float> Planef;
|
nuclear@1
|
1146
|
nuclear@1
|
1147 }
|
nuclear@1
|
1148
|
nuclear@1
|
1149 #endif
|