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
16namespace angle
17{
18
19template <size_t Dimension, typename Type>
20class Vector;
21
22using Vector2 = Vector<2, float>;
23using Vector3 = Vector<3, float>;
24using Vector4 = Vector<4, float>;
25
26using Vector2I = Vector<2, int>;
27using Vector3I = Vector<3, int>;
28using Vector4I = Vector<4, int>;
29
30using Vector2U = Vector<2, unsigned int>;
31using Vector3U = Vector<3, unsigned int>;
32using Vector4U = Vector<4, unsigned int>;
33
34template <size_t Dimension, typename Type>
35class 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
113template <size_t Dimension, typename Type>
114std::ostream &operator<<(std::ostream &ostream, const VectorBase<Dimension, Type> &vector);
115
116template <typename Type>
117class 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
131template <typename Type>
132std::ostream &operator<<(std::ostream &ostream, const Vector<2, Type> &vector);
133
134template <typename Type>
135class 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
154template <typename Type>
155std::ostream &operator<<(std::ostream &ostream, const Vector<3, Type> &vector);
156
157template <typename Type>
158class 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
176template <typename Type>
177std::ostream &operator<<(std::ostream &ostream, const Vector<4, Type> &vector);
178
179// Implementation of constructors and misc operations
180
181template <size_t Dimension, typename Type>
182VectorBase<Dimension, Type>::VectorBase(Type element)
183{
184 for (size_t i = 0; i < Dimension; ++i)
185 {
186 mData[i] = element;
187 }
188}
189
190template <size_t Dimension, typename Type>
191template <typename Type2>
192VectorBase<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.
210template <size_t Dimension, typename Type>
211template <typename Arg1, typename Arg2, typename... Args>
212VectorBase<Dimension, Type>::VectorBase(const Arg1 &arg1, const Arg2 &arg2, const Args &... args)
213{
214 initWithList<0>(arg1, arg2, args...);
215}
216
217template <size_t Dimension, typename Type>
218template <size_t CurrentIndex, size_t OtherDimension, typename OtherType, typename... Args>
219void 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
231template <size_t Dimension, typename Type>
232template <size_t CurrentIndex, typename OtherType, typename... Args>
233typename std::enable_if<std::is_arithmetic<OtherType>::value>::type
234VectorBase<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
241template <size_t Dimension, typename Type>
242template <size_t CurrentIndex>
243void VectorBase<Dimension, Type>::initWithList() const
244{
245 static_assert(CurrentIndex == Dimension, "Not enough data in the vector constructor.");
246}
247
248template <size_t Dimension, typename Type>
249Vector<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
259template <size_t Dimension, typename Type>
260void 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
269template <size_t Dimension, typename Type>
270Vector<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
280template <size_t Dimension, typename Type>
281Vector<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
291template <size_t Dimension, typename Type>
292Vector<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
303template <size_t Dimension, typename Type>
304Vector<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
315template <size_t Dimension, typename Type>
316Vector<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
327template <size_t Dimension, typename Type>
328Vector<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
339template <size_t Dimension, typename Type>
340Vector<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
350template <size_t Dimension, typename Type>
351Vector<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
362template <size_t Dimension, typename Type>
363Vector<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
373template <size_t Dimension, typename Type>
374Vector<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
384template <size_t Dimension, typename Type>
385Vector<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
395template <size_t Dimension, typename Type>
396Vector<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
406template <size_t Dimension, typename Type>
407Vector<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
416template <size_t Dimension, typename Type>
417Vector<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
427template <size_t Dimension, typename Type>
428bool 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
440template <size_t Dimension, typename Type>
441bool VectorBase<Dimension, Type>::operator!=(const Vector<Dimension, Type> &other) const
442{
443 return !(*this == other);
444}
445
446// Implementation of other arithmetic operations
447template <size_t Dimension, typename Type>
448Type 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
455template <size_t Dimension, typename Type>
456Type VectorBase<Dimension, Type>::lengthSquared() const
457{
458 return dot(*this);
459}
460
461template <size_t Dimension, typename Type>
462Type 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
472template <size_t Dimension, typename Type>
473std::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
488template <size_t Dimension, typename Type>
489Vector<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
496template <typename Type>
497std::ostream &operator<<(std::ostream &ostream, const Vector<2, Type> &vector)
498{
499 return ostream << static_cast<const VectorBase<2, Type> &>(vector);
500}
501
502template <typename Type>
503Vector<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
509template <typename Type>
510std::ostream &operator<<(std::ostream &ostream, const Vector<3, Type> &vector)
511{
512 return ostream << static_cast<const VectorBase<3, Type> &>(vector);
513}
514
515template <typename Type>
516std::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