1 | // |
2 | // Copyright 2016 The ANGLE Project Authors. All rights reserved. |
3 | // Use of this source code is governed by a BSD-style license that can be |
4 | // found in the LICENSE file. |
5 | // |
6 | // vector_utils.h: Utility classes implementing various vector operations |
7 | |
8 | #ifndef COMMON_VECTOR_UTILS_H_ |
9 | #define COMMON_VECTOR_UTILS_H_ |
10 | |
11 | #include <cmath> |
12 | #include <cstddef> |
13 | #include <ostream> |
14 | #include <type_traits> |
15 | |
16 | namespace angle |
17 | { |
18 | |
19 | template <size_t Dimension, typename Type> |
20 | class Vector; |
21 | |
22 | using Vector2 = Vector<2, float>; |
23 | using Vector3 = Vector<3, float>; |
24 | using Vector4 = Vector<4, float>; |
25 | |
26 | using Vector2I = Vector<2, int>; |
27 | using Vector3I = Vector<3, int>; |
28 | using Vector4I = Vector<4, int>; |
29 | |
30 | using Vector2U = Vector<2, unsigned int>; |
31 | using Vector3U = Vector<3, unsigned int>; |
32 | using Vector4U = Vector<4, unsigned int>; |
33 | |
34 | template <size_t Dimension, typename Type> |
35 | class VectorBase |
36 | { |
37 | public: |
38 | using VectorN = Vector<Dimension, Type>; |
39 | |
40 | // Constructors |
41 | VectorBase() = default; |
42 | explicit VectorBase(Type element); |
43 | |
44 | template <typename Type2> |
45 | VectorBase(const VectorBase<Dimension, Type2> &other); |
46 | |
47 | template <typename Arg1, typename Arg2, typename... Args> |
48 | VectorBase(const Arg1 &arg1, const Arg2 &arg2, const Args &... args); |
49 | |
50 | // Access the vector backing storage directly |
51 | const Type *data() const { return mData; } |
52 | Type *data() { return mData; } |
53 | constexpr size_t size() const { return Dimension; } |
54 | |
55 | // Load or store the pointer from / to raw data |
56 | static VectorN Load(const Type *source); |
57 | static void Store(const VectorN &source, Type *destination); |
58 | |
59 | // Index the vector |
60 | Type &operator[](size_t i) { return mData[i]; } |
61 | const Type &operator[](size_t i) const { return mData[i]; } |
62 | |
63 | // Basic arithmetic operations |
64 | VectorN operator+() const; |
65 | VectorN operator-() const; |
66 | VectorN operator+(const VectorN &other) const; |
67 | VectorN operator-(const VectorN &other) const; |
68 | VectorN operator*(const VectorN &other) const; |
69 | VectorN operator/(const VectorN &other) const; |
70 | VectorN operator*(Type other) const; |
71 | VectorN operator/(Type other) const; |
72 | friend VectorN operator*(Type a, const VectorN &b) { return b * a; } |
73 | |
74 | // Compound arithmetic operations |
75 | VectorN &operator+=(const VectorN &other); |
76 | VectorN &operator-=(const VectorN &other); |
77 | VectorN &operator*=(const VectorN &other); |
78 | VectorN &operator/=(const VectorN &other); |
79 | VectorN &operator*=(Type other); |
80 | VectorN &operator/=(Type other); |
81 | |
82 | // Comparison operators |
83 | bool operator==(const VectorN &other) const; |
84 | bool operator!=(const VectorN &other) const; |
85 | |
86 | // Other arithmetic operations |
87 | Type length() const; |
88 | Type lengthSquared() const; |
89 | Type dot(const VectorBase<Dimension, Type> &other) const; |
90 | VectorN normalized() const; |
91 | |
92 | protected: |
93 | template <size_t CurrentIndex, size_t OtherDimension, typename OtherType, typename... Args> |
94 | void initWithList(const Vector<OtherDimension, OtherType> &arg1, const Args &... args); |
95 | |
96 | // Some old compilers consider this function an alternative for initWithList(Vector) |
97 | // when the variant above is more precise. Use SFINAE on the return value to hide |
98 | // this variant for non-arithmetic types. The return value is still void. |
99 | template <size_t CurrentIndex, typename OtherType, typename... Args> |
100 | typename std::enable_if<std::is_arithmetic<OtherType>::value>::type initWithList( |
101 | OtherType arg1, |
102 | const Args &... args); |
103 | |
104 | template <size_t CurrentIndex> |
105 | void initWithList() const; |
106 | |
107 | template <size_t Dimension2, typename Type2> |
108 | friend class VectorBase; |
109 | |
110 | Type mData[Dimension]; |
111 | }; |
112 | |
113 | template <size_t Dimension, typename Type> |
114 | std::ostream &operator<<(std::ostream &ostream, const VectorBase<Dimension, Type> &vector); |
115 | |
116 | template <typename Type> |
117 | class Vector<2, Type> : public VectorBase<2, Type> |
118 | { |
119 | public: |
120 | // Import the constructors defined in VectorBase |
121 | using VectorBase<2, Type>::VectorBase; |
122 | |
123 | // Element shorthands |
124 | Type &x() { return this->mData[0]; } |
125 | Type &y() { return this->mData[1]; } |
126 | |
127 | const Type &x() const { return this->mData[0]; } |
128 | const Type &y() const { return this->mData[1]; } |
129 | }; |
130 | |
131 | template <typename Type> |
132 | std::ostream &operator<<(std::ostream &ostream, const Vector<2, Type> &vector); |
133 | |
134 | template <typename Type> |
135 | class Vector<3, Type> : public VectorBase<3, Type> |
136 | { |
137 | public: |
138 | // Import the constructors defined in VectorBase |
139 | using VectorBase<3, Type>::VectorBase; |
140 | |
141 | // Additional operations |
142 | Vector<3, Type> cross(const Vector<3, Type> &other) const; |
143 | |
144 | // Element shorthands |
145 | Type &x() { return this->mData[0]; } |
146 | Type &y() { return this->mData[1]; } |
147 | Type &z() { return this->mData[2]; } |
148 | |
149 | const Type &x() const { return this->mData[0]; } |
150 | const Type &y() const { return this->mData[1]; } |
151 | const Type &z() const { return this->mData[2]; } |
152 | }; |
153 | |
154 | template <typename Type> |
155 | std::ostream &operator<<(std::ostream &ostream, const Vector<3, Type> &vector); |
156 | |
157 | template <typename Type> |
158 | class Vector<4, Type> : public VectorBase<4, Type> |
159 | { |
160 | public: |
161 | // Import the constructors defined in VectorBase |
162 | using VectorBase<4, Type>::VectorBase; |
163 | |
164 | // Element shorthands |
165 | Type &x() { return this->mData[0]; } |
166 | Type &y() { return this->mData[1]; } |
167 | Type &z() { return this->mData[2]; } |
168 | Type &w() { return this->mData[3]; } |
169 | |
170 | const Type &x() const { return this->mData[0]; } |
171 | const Type &y() const { return this->mData[1]; } |
172 | const Type &z() const { return this->mData[2]; } |
173 | const Type &w() const { return this->mData[3]; } |
174 | }; |
175 | |
176 | template <typename Type> |
177 | std::ostream &operator<<(std::ostream &ostream, const Vector<4, Type> &vector); |
178 | |
179 | // Implementation of constructors and misc operations |
180 | |
181 | template <size_t Dimension, typename Type> |
182 | VectorBase<Dimension, Type>::VectorBase(Type element) |
183 | { |
184 | for (size_t i = 0; i < Dimension; ++i) |
185 | { |
186 | mData[i] = element; |
187 | } |
188 | } |
189 | |
190 | template <size_t Dimension, typename Type> |
191 | template <typename Type2> |
192 | VectorBase<Dimension, Type>::VectorBase(const VectorBase<Dimension, Type2> &other) |
193 | { |
194 | for (size_t i = 0; i < Dimension; ++i) |
195 | { |
196 | mData[i] = static_cast<Type>(other.mData[i]); |
197 | } |
198 | } |
199 | |
200 | // Ideally we would like to have only two constructors: |
201 | // - a scalar constructor that takes Type as a parameter |
202 | // - a compound constructor |
203 | // However if we define the compound constructor for when it has a single arguments, then calling |
204 | // Vector2(0.0) will be ambiguous. To solve this we take advantage of there being a single compound |
205 | // constructor with a single argument, which is the copy constructor. We end up with three |
206 | // constructors: |
207 | // - the scalar constructor |
208 | // - the copy constructor |
209 | // - the compound constructor for two or more arguments, hence the arg1, and arg2 here. |
210 | template <size_t Dimension, typename Type> |
211 | template <typename Arg1, typename Arg2, typename... Args> |
212 | VectorBase<Dimension, Type>::VectorBase(const Arg1 &arg1, const Arg2 &arg2, const Args &... args) |
213 | { |
214 | initWithList<0>(arg1, arg2, args...); |
215 | } |
216 | |
217 | template <size_t Dimension, typename Type> |
218 | template <size_t CurrentIndex, size_t OtherDimension, typename OtherType, typename... Args> |
219 | void VectorBase<Dimension, Type>::initWithList(const Vector<OtherDimension, OtherType> &arg1, |
220 | const Args &... args) |
221 | { |
222 | static_assert(CurrentIndex + OtherDimension <= Dimension, |
223 | "Too much data in the vector constructor." ); |
224 | for (size_t i = 0; i < OtherDimension; ++i) |
225 | { |
226 | mData[CurrentIndex + i] = static_cast<Type>(arg1.mData[i]); |
227 | } |
228 | initWithList<CurrentIndex + OtherDimension>(args...); |
229 | } |
230 | |
231 | template <size_t Dimension, typename Type> |
232 | template <size_t CurrentIndex, typename OtherType, typename... Args> |
233 | typename std::enable_if<std::is_arithmetic<OtherType>::value>::type |
234 | VectorBase<Dimension, Type>::initWithList(OtherType arg1, const Args &... args) |
235 | { |
236 | static_assert(CurrentIndex + 1 <= Dimension, "Too much data in the vector constructor." ); |
237 | mData[CurrentIndex] = static_cast<Type>(arg1); |
238 | initWithList<CurrentIndex + 1>(args...); |
239 | } |
240 | |
241 | template <size_t Dimension, typename Type> |
242 | template <size_t CurrentIndex> |
243 | void VectorBase<Dimension, Type>::initWithList() const |
244 | { |
245 | static_assert(CurrentIndex == Dimension, "Not enough data in the vector constructor." ); |
246 | } |
247 | |
248 | template <size_t Dimension, typename Type> |
249 | Vector<Dimension, Type> VectorBase<Dimension, Type>::Load(const Type *source) |
250 | { |
251 | Vector<Dimension, Type> result; |
252 | for (size_t i = 0; i < Dimension; ++i) |
253 | { |
254 | result.mData[i] = source[i]; |
255 | } |
256 | return result; |
257 | } |
258 | |
259 | template <size_t Dimension, typename Type> |
260 | void VectorBase<Dimension, Type>::Store(const Vector<Dimension, Type> &source, Type *destination) |
261 | { |
262 | for (size_t i = 0; i < Dimension; ++i) |
263 | { |
264 | destination[i] = source.mData[i]; |
265 | } |
266 | } |
267 | |
268 | // Implementation of basic arithmetic operations |
269 | template <size_t Dimension, typename Type> |
270 | Vector<Dimension, Type> VectorBase<Dimension, Type>::operator+() const |
271 | { |
272 | Vector<Dimension, Type> result; |
273 | for (size_t i = 0; i < Dimension; ++i) |
274 | { |
275 | result.mData[i] = +mData[i]; |
276 | } |
277 | return result; |
278 | } |
279 | |
280 | template <size_t Dimension, typename Type> |
281 | Vector<Dimension, Type> VectorBase<Dimension, Type>::operator-() const |
282 | { |
283 | Vector<Dimension, Type> result; |
284 | for (size_t i = 0; i < Dimension; ++i) |
285 | { |
286 | result.mData[i] = -mData[i]; |
287 | } |
288 | return result; |
289 | } |
290 | |
291 | template <size_t Dimension, typename Type> |
292 | Vector<Dimension, Type> VectorBase<Dimension, Type>::operator+( |
293 | const Vector<Dimension, Type> &other) const |
294 | { |
295 | Vector<Dimension, Type> result; |
296 | for (size_t i = 0; i < Dimension; ++i) |
297 | { |
298 | result.mData[i] = mData[i] + other.mData[i]; |
299 | } |
300 | return result; |
301 | } |
302 | |
303 | template <size_t Dimension, typename Type> |
304 | Vector<Dimension, Type> VectorBase<Dimension, Type>::operator-( |
305 | const Vector<Dimension, Type> &other) const |
306 | { |
307 | Vector<Dimension, Type> result; |
308 | for (size_t i = 0; i < Dimension; ++i) |
309 | { |
310 | result.mData[i] = mData[i] - other.mData[i]; |
311 | } |
312 | return result; |
313 | } |
314 | |
315 | template <size_t Dimension, typename Type> |
316 | Vector<Dimension, Type> VectorBase<Dimension, Type>::operator*( |
317 | const Vector<Dimension, Type> &other) const |
318 | { |
319 | Vector<Dimension, Type> result; |
320 | for (size_t i = 0; i < Dimension; ++i) |
321 | { |
322 | result.mData[i] = mData[i] * other.mData[i]; |
323 | } |
324 | return result; |
325 | } |
326 | |
327 | template <size_t Dimension, typename Type> |
328 | Vector<Dimension, Type> VectorBase<Dimension, Type>::operator/( |
329 | const Vector<Dimension, Type> &other) const |
330 | { |
331 | Vector<Dimension, Type> result; |
332 | for (size_t i = 0; i < Dimension; ++i) |
333 | { |
334 | result.mData[i] = mData[i] / other.mData[i]; |
335 | } |
336 | return result; |
337 | } |
338 | |
339 | template <size_t Dimension, typename Type> |
340 | Vector<Dimension, Type> VectorBase<Dimension, Type>::operator*(Type other) const |
341 | { |
342 | Vector<Dimension, Type> result; |
343 | for (size_t i = 0; i < Dimension; ++i) |
344 | { |
345 | result.mData[i] = mData[i] * other; |
346 | } |
347 | return result; |
348 | } |
349 | |
350 | template <size_t Dimension, typename Type> |
351 | Vector<Dimension, Type> VectorBase<Dimension, Type>::operator/(Type other) const |
352 | { |
353 | Vector<Dimension, Type> result; |
354 | for (size_t i = 0; i < Dimension; ++i) |
355 | { |
356 | result.mData[i] = mData[i] / other; |
357 | } |
358 | return result; |
359 | } |
360 | |
361 | // Implementation of compound arithmetic operations |
362 | template <size_t Dimension, typename Type> |
363 | Vector<Dimension, Type> &VectorBase<Dimension, Type>::operator+=( |
364 | const Vector<Dimension, Type> &other) |
365 | { |
366 | for (size_t i = 0; i < Dimension; ++i) |
367 | { |
368 | mData[i] += other.mData[i]; |
369 | } |
370 | return *static_cast<Vector<Dimension, Type> *>(this); |
371 | } |
372 | |
373 | template <size_t Dimension, typename Type> |
374 | Vector<Dimension, Type> &VectorBase<Dimension, Type>::operator-=( |
375 | const Vector<Dimension, Type> &other) |
376 | { |
377 | for (size_t i = 0; i < Dimension; ++i) |
378 | { |
379 | mData[i] -= other.mData[i]; |
380 | } |
381 | return *static_cast<Vector<Dimension, Type> *>(this); |
382 | } |
383 | |
384 | template <size_t Dimension, typename Type> |
385 | Vector<Dimension, Type> &VectorBase<Dimension, Type>::operator*=( |
386 | const Vector<Dimension, Type> &other) |
387 | { |
388 | for (size_t i = 0; i < Dimension; ++i) |
389 | { |
390 | mData[i] *= other.mData[i]; |
391 | } |
392 | return *static_cast<Vector<Dimension, Type> *>(this); |
393 | } |
394 | |
395 | template <size_t Dimension, typename Type> |
396 | Vector<Dimension, Type> &VectorBase<Dimension, Type>::operator/=( |
397 | const Vector<Dimension, Type> &other) |
398 | { |
399 | for (size_t i = 0; i < Dimension; ++i) |
400 | { |
401 | mData[i] /= other.mData[i]; |
402 | } |
403 | return *static_cast<Vector<Dimension, Type> *>(this); |
404 | } |
405 | |
406 | template <size_t Dimension, typename Type> |
407 | Vector<Dimension, Type> &VectorBase<Dimension, Type>::operator*=(Type other) |
408 | { |
409 | for (size_t i = 0; i < Dimension; ++i) |
410 | { |
411 | mData[i] *= other; |
412 | } |
413 | return *static_cast<Vector<Dimension, Type> *>(this); |
414 | } |
415 | |
416 | template <size_t Dimension, typename Type> |
417 | Vector<Dimension, Type> &VectorBase<Dimension, Type>::operator/=(Type other) |
418 | { |
419 | for (size_t i = 0; i < Dimension; ++i) |
420 | { |
421 | mData[i] /= other; |
422 | } |
423 | return *static_cast<Vector<Dimension, Type> *>(this); |
424 | } |
425 | |
426 | // Implementation of comparison operators |
427 | template <size_t Dimension, typename Type> |
428 | bool VectorBase<Dimension, Type>::operator==(const Vector<Dimension, Type> &other) const |
429 | { |
430 | for (size_t i = 0; i < Dimension; ++i) |
431 | { |
432 | if (mData[i] != other.mData[i]) |
433 | { |
434 | return false; |
435 | } |
436 | } |
437 | return true; |
438 | } |
439 | |
440 | template <size_t Dimension, typename Type> |
441 | bool VectorBase<Dimension, Type>::operator!=(const Vector<Dimension, Type> &other) const |
442 | { |
443 | return !(*this == other); |
444 | } |
445 | |
446 | // Implementation of other arithmetic operations |
447 | template <size_t Dimension, typename Type> |
448 | Type VectorBase<Dimension, Type>::length() const |
449 | { |
450 | static_assert(std::is_floating_point<Type>::value, |
451 | "VectorN::length is only defined for floating point vectors" ); |
452 | return std::sqrt(lengthSquared()); |
453 | } |
454 | |
455 | template <size_t Dimension, typename Type> |
456 | Type VectorBase<Dimension, Type>::lengthSquared() const |
457 | { |
458 | return dot(*this); |
459 | } |
460 | |
461 | template <size_t Dimension, typename Type> |
462 | Type VectorBase<Dimension, Type>::dot(const VectorBase<Dimension, Type> &other) const |
463 | { |
464 | Type sum = Type(); |
465 | for (size_t i = 0; i < Dimension; ++i) |
466 | { |
467 | sum += mData[i] * other.mData[i]; |
468 | } |
469 | return sum; |
470 | } |
471 | |
472 | template <size_t Dimension, typename Type> |
473 | std::ostream &operator<<(std::ostream &ostream, const VectorBase<Dimension, Type> &vector) |
474 | { |
475 | ostream << "[ " ; |
476 | for (size_t elementIdx = 0; elementIdx < Dimension; elementIdx++) |
477 | { |
478 | if (elementIdx > 0) |
479 | { |
480 | ostream << ", " ; |
481 | } |
482 | ostream << vector.data()[elementIdx]; |
483 | } |
484 | ostream << " ]" ; |
485 | return ostream; |
486 | } |
487 | |
488 | template <size_t Dimension, typename Type> |
489 | Vector<Dimension, Type> VectorBase<Dimension, Type>::normalized() const |
490 | { |
491 | static_assert(std::is_floating_point<Type>::value, |
492 | "VectorN::normalized is only defined for floating point vectors" ); |
493 | return *this / length(); |
494 | } |
495 | |
496 | template <typename Type> |
497 | std::ostream &operator<<(std::ostream &ostream, const Vector<2, Type> &vector) |
498 | { |
499 | return ostream << static_cast<const VectorBase<2, Type> &>(vector); |
500 | } |
501 | |
502 | template <typename Type> |
503 | Vector<3, Type> Vector<3, Type>::cross(const Vector<3, Type> &other) const |
504 | { |
505 | return Vector<3, Type>(y() * other.z() - z() * other.y(), z() * other.x() - x() * other.z(), |
506 | x() * other.y() - y() * other.x()); |
507 | } |
508 | |
509 | template <typename Type> |
510 | std::ostream &operator<<(std::ostream &ostream, const Vector<3, Type> &vector) |
511 | { |
512 | return ostream << static_cast<const VectorBase<3, Type> &>(vector); |
513 | } |
514 | |
515 | template <typename Type> |
516 | std::ostream &operator<<(std::ostream &ostream, const Vector<4, Type> &vector) |
517 | { |
518 | return ostream << static_cast<const VectorBase<4, Type> &>(vector); |
519 | } |
520 | |
521 | } // namespace angle |
522 | |
523 | #endif // COMMON_VECTOR_UTILS_H_ |
524 | |