summaryrefslogtreecommitdiff
path: root/Runtime/Math/Vector3.h
blob: ea4bbc410fdb2d9afcc38a13c47354c5ce87e636 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
#ifndef VECTOR3_H
#define VECTOR3_H

#include <algorithm>
#include "FloatConversion.h"
#include "Runtime/Serialize/SerializeUtility.h"
#include "Runtime/Serialize/SerializationMetaFlags.h"
#include "Runtime/Utilities/LogAssert.h"
#include "Runtime/Modules/ExportModules.h"

class Vector3f
{
	public:

	float x, y, z;

	DEFINE_GET_TYPESTRING_IS_ANIMATION_CHANNEL (Vector3f)
	template<class TransferFunction> void Transfer (TransferFunction& transfer);

	Vector3f () : x(0.f), y(0.f), z(0.f) {}
	Vector3f (float inX, float inY, float inZ)	{ x = inX; y = inY; z = inZ; }
	explicit Vector3f (const float* array)	{ x = array[0]; y = array[1]; z = array[2]; }
	void Set (float inX, float inY, float inZ)	{ x = inX; y = inY; z = inZ; }
	void Set (const float* array)	{ x = array[0]; y = array[1]; z = array[2]; }

	float* GetPtr ()								{ return &x; }
	const float* GetPtr ()const						{ return &x; }
	float& operator[] (int i)						{ DebugAssertIf (i < 0 || i > 2); return (&x)[i]; }
	const float& operator[] (int i)const			{ DebugAssertIf (i < 0 || i > 2); return (&x)[i]; }

	bool operator == (const Vector3f& v)const		{ return x == v.x && y == v.y && z == v.z; }
	bool operator != (const Vector3f& v)const		{ return x != v.x || y != v.y || z != v.z; }

	Vector3f& operator += (const Vector3f& inV)		{ x += inV.x; y += inV.y; z += inV.z; return *this; }
	Vector3f& operator -= (const Vector3f& inV)		{ x -= inV.x; y -= inV.y; z -= inV.z; return *this; }
	Vector3f& operator *= (float s)					{ x *= s; y *= s; z *= s; return *this; }
	Vector3f& operator /= (float s);

	Vector3f operator - () const					{ return Vector3f (-x, -y, -z); }

	Vector3f& Scale (const Vector3f& inV)			{ x *= inV.x; y *= inV.y; z *= inV.z; return *this;}


	EXPORT_COREMODULE static const float		epsilon;
	EXPORT_COREMODULE static const float		infinity;
	EXPORT_COREMODULE static const Vector3f	infinityVec;
	EXPORT_COREMODULE static const Vector3f	zero;
	EXPORT_COREMODULE static const Vector3f	one;
	EXPORT_COREMODULE static const Vector3f	xAxis;
	EXPORT_COREMODULE static const Vector3f	yAxis;
	EXPORT_COREMODULE static const Vector3f	zAxis;
};

inline Vector3f Scale (const Vector3f& lhs, const Vector3f& rhs) { return Vector3f (lhs.x * rhs.x, lhs.y * rhs.y, lhs.z * rhs.z); }

inline Vector3f operator + (const Vector3f& lhs, const Vector3f& rhs)	{ return Vector3f (lhs.x + rhs.x, lhs.y + rhs.y, lhs.z + rhs.z); }
inline Vector3f operator - (const Vector3f& lhs, const Vector3f& rhs)	{ return Vector3f (lhs.x - rhs.x, lhs.y - rhs.y, lhs.z - rhs.z); }
inline Vector3f Cross (const Vector3f& lhs, const Vector3f& rhs);
inline float Dot (const Vector3f& lhs, const Vector3f& rhs)					{ return lhs.x * rhs.x + lhs.y * rhs.y + lhs.z * rhs.z; }

inline Vector3f operator * (const Vector3f& inV, const float s)			{ return Vector3f (inV.x * s, inV.y * s, inV.z * s); }
inline Vector3f operator * (const float s, const Vector3f& inV)			{ return Vector3f (inV.x * s, inV.y * s, inV.z * s); }
inline Vector3f operator / (const Vector3f& inV, const float s)			{ Vector3f temp (inV); temp /= s; return temp; }
inline Vector3f Inverse (const Vector3f& inVec)									{ return Vector3f (1.0F / inVec.x, 1.0F / inVec.y, 1.0F / inVec.z); }

inline float SqrMagnitude (const Vector3f& inV) 								{ return Dot (inV, inV); }
inline float Magnitude (const Vector3f& inV)							{return SqrtImpl(Dot (inV, inV));}

// Normalizes a vector, asserts if the vector can be normalized
inline Vector3f Normalize (const Vector3f& inV)									{ return inV / Magnitude (inV); }
// Normalizes a vector, returns default vector if it can't be normalized
inline Vector3f NormalizeSafe (const Vector3f& inV, const Vector3f& defaultV = Vector3f::zero);

inline Vector3f ReflectVector (const Vector3f& inDirection, const Vector3f& inNormal) 	{ return -2.0F * Dot (inNormal, inDirection) * inNormal + inDirection; }

inline Vector3f Lerp (const Vector3f& from, const Vector3f& to, float t) { return to * t + from * (1.0F - t); }
Vector3f Slerp (const Vector3f& from, const Vector3f& to, float t);

// Returns a vector with the smaller of every component from v0 and v1
inline Vector3f min (const Vector3f& lhs, const Vector3f& rhs) 			{ return Vector3f (FloatMin (lhs.x, rhs.x), FloatMin (lhs.y, rhs.y), FloatMin (lhs.z, rhs.z)); }
// Returns a vector with the larger  of every component from v0 and v1
inline Vector3f max (const Vector3f& lhs, const Vector3f& rhs)				{ return Vector3f (FloatMax (lhs.x, rhs.x), FloatMax (lhs.y, rhs.y), FloatMax (lhs.z, rhs.z)); }

/// Project one vector onto another.
inline Vector3f Project (const Vector3f& v1, const Vector3f& v2)	{ return v2* Dot (v1, v2)/ Dot (v2, v2); }


/// Returns the abs of every component of the vector
inline Vector3f Abs (const Vector3f& v) { return Vector3f (Abs (v.x), Abs (v.y), Abs (v.z)); }

bool CompareApproximately (const Vector3f& inV0, const Vector3f& inV1, const float inMaxDist = Vector3f::epsilon);
// Orthonormalizes the three vectors, assuming that a orthonormal basis can be formed
void OrthoNormalizeFast (Vector3f* inU, Vector3f* inV, Vector3f* inW);
// Orthonormalizes the three vectors, returns false if no orthonormal basis could be formed.
EXPORT_COREMODULE void OrthoNormalize (Vector3f* inU, Vector3f* inV, Vector3f* inW);
// Orthonormalizes the two vectors. inV is taken as a hint and will try to be as close as possible to inV.
EXPORT_COREMODULE void OrthoNormalize (Vector3f* inU, Vector3f* inV);

// Calculates a vector that is orthonormal to n.
// Assumes that n is normalized
Vector3f OrthoNormalVectorFast (const Vector3f& n);

// Rotates lhs towards rhs by no more than max Angle
// Moves the magnitude of lhs towards rhs by no more than maxMagnitude
Vector3f RotateTowards (const Vector3f& lhs, const Vector3f& rhs, float maxAngle, float maxMagnitude);

// Spherically interpolates the direction of two vectors
// and interpolates the magnitude of the two vectors
Vector3f Slerp (const Vector3f& lhs, const Vector3f& rhs, float t);

/// Returns a Vector3 that moves lhs towards rhs by a maximum of clampedDistance
Vector3f MoveTowards (const Vector3f& lhs, const Vector3f& rhs, float clampedDistance);

inline bool IsNormalized (const Vector3f& vec, float epsilon = Vector3f::epsilon)
{
	return CompareApproximately (SqrMagnitude (vec), 1.0F, epsilon);
}

inline Vector3f Cross (const Vector3f& lhs, const Vector3f& rhs)
{
	return Vector3f (
		lhs.y * rhs.z - lhs.z * rhs.y,
		lhs.z * rhs.x - lhs.x * rhs.z,
		lhs.x * rhs.y - lhs.y * rhs.x);
}

inline Vector3f NormalizeSafe (const Vector3f& inV, const Vector3f& defaultV)
{
	float mag = Magnitude (inV);
	if (mag > Vector3f::epsilon)
		return inV / Magnitude (inV);
	else
		return defaultV;
}

/// - Handles zero vector correclty
inline Vector3f NormalizeFast (const Vector3f& inV)
{
	float m = SqrMagnitude (inV);
	// GCC version of __frsqrte:
	//	static inline double __frsqrte (double x) {
	//		double y;
	//		asm ( "frsqrte %0, %1" : /*OUT*/ "=f" (y) : /*IN*/ "f" (x) );
	//		return y;
	//	}
	return inV * FastInvSqrt (m);
}

/// - low precision normalize
/// - nan for zero vector
inline Vector3f NormalizeFastest (const Vector3f& inV)
{
	float m = SqrMagnitude (inV);
	// GCC version of __frsqrte:
	//	static inline double __frsqrte (double x) {
	//		double y;
	//		asm ( "frsqrte %0, %1" : /*OUT*/ "=f" (y) : /*IN*/ "f" (x) );
	//		return y;
	//	}
	return inV * FastestInvSqrt (m);
}

inline bool IsFinite (const Vector3f& f)
{
	return IsFinite(f.x) & IsFinite(f.y) & IsFinite(f.z);
}



inline bool CompareApproximately (const Vector3f& inV0, const Vector3f& inV1, const float inMaxDist)
{
	return SqrMagnitude (inV1 - inV0) < inMaxDist * inMaxDist;
}

inline Vector3f& Vector3f::operator /= (float s)
{
	DebugAssertIf (CompareApproximately (s, 0.0F));
	x /= s;
	y /= s;
	z /= s;
	return *this;
}

template<class TransferFunction>
inline void Vector3f::Transfer (TransferFunction& t)
{
	t.AddMetaFlag (kTransferUsingFlowMappingStyle);
	t.Transfer (x, "x");
	t.Transfer (y, "y");
	t.Transfer (z, "z");
}

// this may be called for vectors `a' with extremely small magnitude, for
// example the result of a cross product on two nearly perpendicular vectors.
// we must be robust to these small vectors. to prevent numerical error,
// first find the component a[i] with the largest magnitude and then scale
// all the components by 1/a[i]. then we can compute the length of `a' and
// scale the components by 1/l. this has been verified to work with vectors
// containing the smallest representable numbers.
Vector3f NormalizeRobust (const Vector3f& a);
// This also returns vector's inverse original length, to avoid duplicate
// invSqrt calculations when needed. If a is a zero vector, invOriginalLength will be 0.
Vector3f NormalizeRobust (const Vector3f& a, float &invOriginalLength);

#endif