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