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
data()51 const Type *data() const { return mData; }
data()52 Type *data() { return mData; }
size()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
x()124 Type &x() { return this->mData[0]; }
y()125 Type &y() { return this->mData[1]; }
126
x()127 const Type &x() const { return this->mData[0]; }
y()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
x()145 Type &x() { return this->mData[0]; }
y()146 Type &y() { return this->mData[1]; }
z()147 Type &z() { return this->mData[2]; }
148
x()149 const Type &x() const { return this->mData[0]; }
y()150 const Type &y() const { return this->mData[1]; }
z()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
x()165 Type &x() { return this->mData[0]; }
y()166 Type &y() { return this->mData[1]; }
z()167 Type &z() { return this->mData[2]; }
w()168 Type &w() { return this->mData[3]; }
169
x()170 const Type &x() const { return this->mData[0]; }
y()171 const Type &y() const { return this->mData[1]; }
z()172 const Type &z() const { return this->mData[2]; }
w()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>
VectorBase(Type element)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>
VectorBase(const VectorBase<Dimension,Type2> & other)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>
VectorBase(const Arg1 & arg1,const Arg2 & arg2,const Args &...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>
initWithList(const Vector<OtherDimension,OtherType> & arg1,const Args &...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
initWithList(OtherType arg1,const Args &...args)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>
initWithList()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>
Load(const Type * source)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>
Store(const Vector<Dimension,Type> & source,Type * destination)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>
length()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>
lengthSquared()456 Type VectorBase<Dimension, Type>::lengthSquared() const
457 {
458 return dot(*this);
459 }
460
461 template <size_t Dimension, typename Type>
dot(const VectorBase<Dimension,Type> & other)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>
normalized()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>
cross(const Vector<3,Type> & other)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