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 *reinterpret_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 *reinterpret_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 *reinterpret_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 *reinterpret_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 *reinterpret_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 *reinterpret_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