1//************************************ bs::framework - Copyright 2018 Marko Pintera **************************************//
2//*********** Licensed under the MIT license. See LICENSE.md for full terms. This notice is not to be removed. ***********//
3#pragma once
4
5#include <cmath>
6
7#include "Prerequisites/BsPrerequisitesUtil.h"
8#include "Math/BsRadian.h"
9
10namespace bs
11{
12 /** @addtogroup Math
13 * @{
14 */
15
16 /** A three dimensional vector. */
17 class BS_UTILITY_EXPORT Vector3
18 {
19 public:
20 float x, y, z;
21
22 public:
23 Vector3() = default;
24
25 constexpr Vector3(BS_ZERO)
26 :x(0.0f), y(0.0f), z(0.0f)
27 { }
28
29 constexpr Vector3(float x, float y, float z)
30 :x(x), y(y), z(z)
31 { }
32
33 explicit Vector3(const Vector4& vec);
34
35 /** Exchange the contents of this vector with another. */
36 void swap(Vector3& other)
37 {
38 std::swap(x, other.x);
39 std::swap(y, other.y);
40 std::swap(z, other.z);
41 }
42
43 float operator[] (UINT32 i) const
44 {
45 assert(i < 3);
46
47 return *(&x + i);
48 }
49
50 float& operator[] (UINT32 i)
51 {
52 assert(i < 3);
53
54 return *(&x + i);
55 }
56
57 /** Pointer accessor for direct copying. */
58 float* ptr()
59 {
60 return &x;
61 }
62
63 /** Pointer accessor for direct copying. */
64 const float* ptr() const
65 {
66 return &x;
67 }
68
69 Vector3& operator= (float rhs)
70 {
71 x = rhs;
72 y = rhs;
73 z = rhs;
74
75 return *this;
76 }
77
78 bool operator== (const Vector3& rhs) const
79 {
80 return (x == rhs.x && y == rhs.y && z == rhs.z);
81 }
82
83 bool operator!= (const Vector3& rhs) const
84 {
85 return (x != rhs.x || y != rhs.y || z != rhs.z);
86 }
87
88 Vector3 operator+ (const Vector3& rhs) const
89 {
90 return Vector3(x + rhs.x, y + rhs.y, z + rhs.z);
91 }
92
93 Vector3 operator- (const Vector3& rhs) const
94 {
95 return Vector3(x - rhs.x, y - rhs.y, z - rhs.z);
96 }
97
98 Vector3 operator* (float rhs) const
99 {
100 return Vector3(x * rhs, y * rhs, z * rhs);
101 }
102
103 Vector3 operator* (const Vector3& rhs) const
104 {
105 return Vector3(x * rhs.x, y * rhs.y, z * rhs.z);
106 }
107
108 Vector3 operator/ (float val) const
109 {
110 assert(val != 0.0);
111
112 float fInv = 1.0f / val;
113 return Vector3(x * fInv, y * fInv, z * fInv);
114 }
115
116 Vector3 operator/ (const Vector3& rhs) const
117 {
118 return Vector3(x / rhs.x, y / rhs.y, z / rhs.z);
119 }
120
121 const Vector3& operator+ () const
122 {
123 return *this;
124 }
125
126 Vector3 operator- () const
127 {
128 return Vector3(-x, -y, -z);
129 }
130
131 friend Vector3 operator* (float lhs, const Vector3& rhs)
132 {
133 return Vector3(lhs * rhs.x, lhs * rhs.y, lhs * rhs.z);
134 }
135
136 friend Vector3 operator/ (float lhs, const Vector3& rhs)
137 {
138 return Vector3(lhs / rhs.x, lhs / rhs.y, lhs / rhs.z);
139 }
140
141 friend Vector3 operator+ (const Vector3& lhs, float rhs)
142 {
143 return Vector3(lhs.x + rhs, lhs.y + rhs, lhs.z + rhs);
144 }
145
146 friend Vector3 operator+ (float lhs, const Vector3& rhs)
147 {
148 return Vector3(lhs + rhs.x, lhs + rhs.y, lhs + rhs.z);
149 }
150
151 friend Vector3 operator- (const Vector3& lhs, float rhs)
152 {
153 return Vector3(lhs.x - rhs, lhs.y - rhs, lhs.z - rhs);
154 }
155
156 friend Vector3 operator- (float lhs, const Vector3& rhs)
157 {
158 return Vector3(lhs - rhs.x, lhs - rhs.y, lhs - rhs.z);
159 }
160
161 Vector3& operator+= (const Vector3& rhs)
162 {
163 x += rhs.x;
164 y += rhs.y;
165 z += rhs.z;
166
167 return *this;
168 }
169
170 Vector3& operator+= (float rhs)
171 {
172 x += rhs;
173 y += rhs;
174 z += rhs;
175
176 return *this;
177 }
178
179 Vector3& operator-= (const Vector3& rhs)
180 {
181 x -= rhs.x;
182 y -= rhs.y;
183 z -= rhs.z;
184
185 return *this;
186 }
187
188 Vector3& operator-= (float rhs)
189 {
190 x -= rhs;
191 y -= rhs;
192 z -= rhs;
193
194 return *this;
195 }
196
197 Vector3& operator*= (float rhs)
198 {
199 x *= rhs;
200 y *= rhs;
201 z *= rhs;
202
203 return *this;
204 }
205
206 Vector3& operator*= (const Vector3& rhs)
207 {
208 x *= rhs.x;
209 y *= rhs.y;
210 z *= rhs.z;
211
212 return *this;
213 }
214
215 Vector3& operator/= (float rhs)
216 {
217 assert(rhs != 0.0f);
218
219 float inv = 1.0f / rhs;
220
221 x *= inv;
222 y *= inv;
223 z *= inv;
224
225 return *this;
226 }
227
228 Vector3& operator/= (const Vector3& rhs)
229 {
230 x /= rhs.x;
231 y /= rhs.y;
232 z /= rhs.z;
233
234 return *this;
235 }
236
237 /** Returns the length (magnitude) of the vector. */
238 float length() const
239 {
240 return std::sqrt(x * x + y * y + z * z);
241 }
242
243 /** Returns the square of the length(magnitude) of the vector. */
244 float squaredLength() const
245 {
246 return x * x + y * y + z * z;
247 }
248
249 /** Returns the distance to another vector. */
250 float distance(const Vector3& rhs) const
251 {
252 return (*this - rhs).length();
253 }
254
255 /** Returns the square of the distance to another vector. */
256 float squaredDistance(const Vector3& rhs) const
257 {
258 return (*this - rhs).squaredLength();
259 }
260
261 /** Calculates the dot (scalar) product of this vector with another. */
262 float dot(const Vector3& vec) const
263 {
264 return x * vec.x + y * vec.y + z * vec.z;
265 }
266
267 /** Normalizes the vector. */
268 float normalize()
269 {
270 float len = length();
271
272 // Will also work for zero-sized vectors, but will change nothing
273 if (len > 1e-08f)
274 {
275 float invLen = 1.0f / len;
276 x *= invLen;
277 y *= invLen;
278 z *= invLen;
279 }
280 return len;
281 }
282
283
284 /** Calculates the cross-product of 2 vectors, that is, the vector that lies perpendicular to them both. */
285 Vector3 cross(const Vector3& other) const
286 {
287 return Vector3(
288 y * other.z - z * other.y,
289 z * other.x - x * other.z,
290 x * other.y - y * other.x);
291 }
292
293 /** Sets this vector's components to the minimum of its own and the ones of the passed in vector. */
294 void min(const Vector3& cmp)
295 {
296 if (cmp.x < x) x = cmp.x;
297 if (cmp.y < y) y = cmp.y;
298 if (cmp.z < z) z = cmp.z;
299 }
300
301 /** Sets this vector's components to the maximum of its own and the ones of the passed in vector. */
302 void max(const Vector3& cmp)
303 {
304 if (cmp.x > x) x = cmp.x;
305 if (cmp.y > y) y = cmp.y;
306 if (cmp.z > z) z = cmp.z;
307 }
308
309 /** Generates a vector perpendicular to this vector. */
310 Vector3 perpendicular() const
311 {
312 static const float squareZero = (float)(1e-06 * 1e-06);
313
314 Vector3 perp = this->cross(Vector3::UNIT_X);
315
316 if (perp.squaredLength() < squareZero)
317 perp = this->cross(Vector3::UNIT_Y);
318
319 perp.normalize();
320 return perp;
321 }
322
323 /** Gets the angle between 2 vectors. */
324 inline Radian angleBetween(const Vector3& dest) const;
325
326 /** Returns true if this vector is zero length. */
327 bool isZeroLength() const
328 {
329 float sqlen = (x * x) + (y * y) + (z * z);
330 return (sqlen < (1e-06f * 1e-06f));
331 }
332
333 /** Calculates a reflection vector to the plane with the given normal. */
334 Vector3 reflect(const Vector3& normal) const
335 {
336 return Vector3(*this - (2 * this->dot(normal) * normal));
337 }
338
339 /** Calculates two vectors orthonormal to the current vector, and normalizes the current vector if not already. */
340 void orthogonalComplement(Vector3& a, Vector3& b)
341 {
342 if (std::abs(x) > std::abs(y))
343 a = Vector3(-z, 0, x);
344 else
345 a = Vector3(0, z, -y);
346
347 b = cross(a);
348
349 orthonormalize(*this, a, b);
350 }
351
352 /** Performs Gram-Schmidt orthonormalization. */
353 static void orthonormalize(Vector3& vec0, Vector3& vec1, Vector3& vec2)
354 {
355 vec0.normalize();
356
357 float dot0 = vec0.dot(vec1);
358 vec1 -= dot0*vec0;
359 vec1.normalize();
360
361 float dot1 = vec1.dot(vec2);
362 dot0 = vec0.dot(vec2);
363 vec2 -= dot0*vec0 + dot1*vec1;
364 vec2.normalize();
365 }
366
367 /** Calculates the dot (scalar) product of two vectors. */
368 static float dot(const Vector3& a, const Vector3& b)
369 {
370 return a.x * b.x + a.y * b.y + a.z * b.z;
371 }
372
373 /** Normalizes the provided vector and returns a new normalized instance. */
374 static Vector3 normalize(const Vector3& val);
375
376 /** Calculates the cross-product of 2 vectors, that is, the vector that lies perpendicular to them both. */
377 static Vector3 cross(const Vector3& a, const Vector3& b)
378 {
379 return Vector3(
380 a.y * b.z - a.z * b.y,
381 a.z * b.x - a.x * b.z,
382 a.x * b.y - a.y * b.x);
383 }
384
385 /**
386 * Linearly interpolates between the two vectors using @p t. t should be in [0, 1] range, where t = 0 corresponds
387 * to the left vector, while t = 1 corresponds to the right vector.
388 */
389 static Vector3 lerp(float t, const Vector3& a, const Vector3& b)
390 {
391 return (1.0f - t) * a + t * b;
392 }
393
394 /** Checks are any of the vector components not a number. */
395 inline bool isNaN() const;
396
397 /** Returns the minimum of all the vector components as a new vector. */
398 static Vector3 min(const Vector3& a, const Vector3& b)
399 {
400 return Vector3(std::min(a.x, b.x), std::min(a.y, b.y), std::min(a.z, b.z));
401 }
402
403 /** Returns the maximum of all the vector components as a new vector. */
404 static Vector3 max(const Vector3& a, const Vector3& b)
405 {
406 return Vector3(std::max(a.x, b.x), std::max(a.y, b.y), std::max(a.z, b.z));
407 }
408
409 static const Vector3 ZERO;
410 static const Vector3 ONE;
411 static const Vector3 INF;
412 static const Vector3 UNIT_X;
413 static const Vector3 UNIT_Y;
414 static const Vector3 UNIT_Z;
415 };
416
417 /** @} */
418
419 /** @cond SPECIALIZATIONS */
420 BS_ALLOW_MEMCPY_SERIALIZATION(Vector3);
421 /** @endcond */
422}
423
424/** @cond SPECIALIZATIONS */
425namespace std
426{
427 template<> class numeric_limits<bs::Vector3>
428 {
429 public:
430 constexpr static bs::Vector3 infinity()
431 {
432 return bs::Vector3(
433 std::numeric_limits<float>::infinity(),
434 std::numeric_limits<float>::infinity(),
435 std::numeric_limits<float>::infinity());
436 }
437 };
438}
439/** @endcond */