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