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 | |
10 | namespace 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 */ |
425 | namespace 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 */ |