Leonetienne/Eule
Homemade math library, mainly targetted towards computer graphics
Vector2.cpp
Go to the documentation of this file.
1 #include "Vector2.h"
2 #include "Math.h"
3 #include <iostream>
4 
5 //#define _EULE_NO_INTRINSICS_
6 #ifndef _EULE_NO_INTRINSICS_
7 #include <immintrin.h>
8 #endif
9 
10 using namespace Eule;
11 
12 /*
13  NOTE:
14  Here you will find bad, unoptimized methods for T=int.
15  This is because the compiler needs a method for each type in each instantiation of the template!
16  I can't generalize the methods when heavily optimizing for doubles.
17  These functions will get called VERY rarely, if ever at all, for T=int, so it's ok.
18  The T=int instantiation only exists to store a value-pair of two ints. Not so-much as a vector in terms of vector calculus.
19 */
20 
21 // Good, optimized chad version for doubles
22 double Vector2<double>::DotProduct(const Vector2<double>& other) const
23 {
24  #ifndef _EULE_NO_INTRINSICS_
25 
26  // Move vector components into registers
27  __m256 __vector_self = _mm256_set_ps(0,0,0,0,0,0, (float)y, (float)x);
28  __m256 __vector_other = _mm256_set_ps(0,0,0,0,0,0, (float)other.y, (float)other.x);
29 
30  // Define bitmask, and execute computation
31  const int mask = 0x31; // -> 0011 1000 -> use positions 0011 (last 2) of the vectors supplied, and place them in 1000 (first only) element of __dot
32  __m256 __dot = _mm256_dp_ps(__vector_self, __vector_other, mask);
33 
34  // Retrieve result, and return it
35  float result[8];
36  _mm256_storeu_ps(result, __dot);
37 
38  return result[0];
39 
40  #else
41  return (x * other.x) +
42  (y * other.y);
43  #endif
44 }
45 
46 // Slow, lame version for intcels
47 double Vector2<int>::DotProduct(const Vector2<int>& other) const
48 {
49  int iDot = (x * other.x) +
50  (y * other.y);
51 
52  return (double)iDot;
53 }
54 
55 
56 
57 // Good, optimized chad version for doubles
58 double Vector2<double>::CrossProduct(const Vector2<double>& other) const
59 {
60  return (x * other.y) -
61  (y * other.x);
62 }
63 
64 // Slow, lame version for intcels
65 double Vector2<int>::CrossProduct(const Vector2<int>& other) const
66 {
67  int iCross = (x * other.y) -
68  (y * other.x);
69 
70  return (double)iCross;
71 }
72 
73 
74 
75 // Good, optimized chad version for doubles
76 double Vector2<double>::SqrMagnitude() const
77 {
78  // x.DotProduct(x) == x.SqrMagnitude()
79  return DotProduct(*this);
80 }
81 
82 // Slow, lame version for intcels
84 {
85  int iSqrMag = x*x + y*y;
86  return (double)iSqrMag;
87 }
88 
89 template<typename T>
90 double Vector2<T>::Magnitude() const
91 {
92  return sqrt(SqrMagnitude());
93 }
94 
95 
96 
98 {
99  #ifndef _EULE_NO_INTRINSICS_
100 
101  // Load vectors into registers
102  __m256d __vector_self = _mm256_set_pd(0, 0, y, x);
103  __m256d __vector_scalar = _mm256_set_pd(0, 0, scalar.y, scalar.x);
104 
105  // Multiply them
106  __m256d __product = _mm256_mul_pd(__vector_self, __vector_scalar);
107 
108  // Retrieve result
109  double result[4];
110  _mm256_storeu_pd(result, __product);
111 
112  // Return value
113  return Vector2<double>(
114  result[0],
115  result[1]
116  );
117 
118  #else
119 
120  return Vector2<double>(
121  x * scalar.x,
122  y * scalar.y
123  );
124  #endif
125 }
126 
128 {
129  return Vector2<int>(
130  x * scalar.x,
131  y * scalar.y
132  );
133 }
134 
135 
136 template<typename T>
138 {
139  Vector2<double> norm(x, y);
140  norm.NormalizeSelf();
141 
142  return norm;
143 }
144 
145 // Method to normalize a Vector2d
147 {
148  double length = Magnitude();
149 
150  // Prevent division by 0
151  if (length == 0)
152  {
153  x = 0;
154  y = 0;
155  }
156  else
157  {
158  #ifndef _EULE_NO_INTRINSICS_
159 
160  // Load vector and length into registers
161  __m256d __vec = _mm256_set_pd(0, 0, y, x);
162  __m256d __len = _mm256_set1_pd(length);
163 
164  // Divide
165  __m256d __prod = _mm256_div_pd(__vec, __len);
166 
167  // Extract and set values
168  double prod[4];
169  _mm256_storeu_pd(prod, __prod);
170 
171  x = prod[0];
172  y = prod[1];
173 
174  #else
175 
176  x /= length;
177  y /= length;
178 
179  #endif
180  }
181 
182  return;
183 }
184 
185 // You can't normalize an int vector, ffs!
186 // But we need an implementation for T=int
188 {
189  std::cerr << "Stop normalizing int-vectors!!" << std::endl;
190  x = 0;
191  y = 0;
192 
193  return;
194 }
195 
196 
197 // Good, optimized chad version for doubles
198 void Vector2<double>::LerpSelf(const Vector2<double>& other, double t)
199 {
200  const double it = 1.0 - t; // Inverse t
201 
202  #ifndef _EULE_NO_INTRINSICS_
203 
204  // Move vector components and factors into registers
205  __m256d __vector_self = _mm256_set_pd(0, 0, y, x);
206  __m256d __vector_other = _mm256_set_pd(0, 0, other.y, other.x);
207  __m256d __t = _mm256_set1_pd(t);
208  __m256d __it = _mm256_set1_pd(it); // Inverse t
209 
210  // Procedure:
211  // (__vector_self * __it) + (__vector_other * __t)
212 
213  __m256d __sum = _mm256_set1_pd(0); // this will hold the sum of the two multiplications
214 
215  __sum = _mm256_fmadd_pd(__vector_self, __it, __sum);
216  __sum = _mm256_fmadd_pd(__vector_other, __t, __sum);
217 
218  // Retrieve result, and apply it
219  double sum[4];
220  _mm256_storeu_pd(sum, __sum);
221 
222  x = sum[0];
223  y = sum[1];
224 
225  #else
226 
227  x = it * x + t * other.x;
228  y = it * y + t * other.y;
229 
230  #endif
231 
232  return;
233 }
234 
235 
236 
237 // Slow, lame version for intcels
238 void Vector2<int>::LerpSelf(const Vector2<int>& other, double t)
239 {
240  const double it = 1.0 - t; // Inverse t
241 
242  x = (int)(it * (double)x + t * (double)other.x);
243  y = (int)(it * (double)y + t * (double)other.y);
244 
245  return;
246 }
247 
248 Vector2<double> Vector2<double>::Lerp(const Vector2<double>& other, double t) const
249 {
250  Vector2d copy(*this);
251  copy.LerpSelf(other, t);
252 
253  return copy;
254 }
255 
256 Vector2<double> Vector2<int>::Lerp(const Vector2<int>& other, double t) const
257 {
258  Vector2d copy(this->ToDouble());
259  copy.LerpSelf(other.ToDouble(), t);
260 
261  return copy;
262 }
263 
264 
265 
266 template<typename T>
267 T& Vector2<T>::operator[](std::size_t idx)
268 {
269  switch (idx)
270  {
271  case 0:
272  return x;
273  case 1:
274  return y;
275  default:
276  throw std::out_of_range("Array descriptor on Vector2<T> out of range!");
277  }
278 }
279 
280 template<typename T>
281 const T& Vector2<T>::operator[](std::size_t idx) const
282 {
283  switch (idx)
284  {
285  case 0:
286  return x;
287  case 1:
288  return y;
289  default:
290  throw std::out_of_range("Array descriptor on Vector2<T> out of range!");
291  }
292 }
293 
294 template<typename T>
295 bool Vector2<T>::Similar(const Vector2<T>& other, double epsilon) const
296 {
297  return
298  (::Math::Similar(x, other.x, epsilon)) &&
299  (::Math::Similar(y, other.y, epsilon))
300  ;
301 }
302 
303 template<typename T>
305 {
306  return Vector2<int>((int)x, (int)y);
307 }
308 
309 template<typename T>
311 {
312  return Vector2<double>((double)x, (double)y);
313 }
314 
315 
317 {
318  #ifndef _EULE_NO_INTRINSICS_
319 
320  // Move vector components and factors into registers
321  __m256d __vector_self = _mm256_set_pd(0, 0, y, x);
322  __m256d __vector_other = _mm256_set_pd(0, 0, other.y, other.x);
323 
324  // Add the components
325  __m256d __sum = _mm256_add_pd(__vector_self, __vector_other);
326 
327  // Retrieve and return these values
328  double sum[4];
329  _mm256_storeu_pd(sum, __sum);
330 
331  return Vector2<double>(
332  sum[0],
333  sum[1]
334  );
335 
336  #else
337 
338  return Vector2<double>(
339  x + other.x,
340  y + other.y
341  );
342  #endif
343 }
344 
345 template<typename T>
347 {
348  return Vector2<T>(
349  x + other.x,
350  y + other.y
351  );
352 }
353 
354 
355 
357 {
358  #ifndef _EULE_NO_INTRINSICS_
359 
360  // Move vector components and factors into registers
361  __m256d __vector_self = _mm256_set_pd(0, 0, y, x);
362  __m256d __vector_other = _mm256_set_pd(0, 0, other.y, other.x);
363 
364  // Add the components
365  __m256d __sum = _mm256_add_pd(__vector_self, __vector_other);
366 
367  // Retrieve and apply these values
368  double sum[4];
369  _mm256_storeu_pd(sum, __sum);
370 
371  x = sum[0];
372  y = sum[1];
373 
374  #else
375 
376  x += other.x;
377  y += other.y;
378 
379  #endif
380 
381  return;
382 }
383 
384 template<typename T>
386 {
387  x += other.x;
388  y += other.y;
389  return;
390 }
391 
392 
393 
395 {
396  #ifndef _EULE_NO_INTRINSICS_
397 
398  // Move vector components and factors into registers
399  __m256d __vector_self = _mm256_set_pd(0, 0, y, x);
400  __m256d __vector_other = _mm256_set_pd(0, 0, other.y, other.x);
401 
402  // Subtract the components
403  __m256d __diff = _mm256_sub_pd(__vector_self, __vector_other);
404 
405  // Retrieve and return these values
406  double diff[4];
407  _mm256_storeu_pd(diff, __diff);
408 
409  return Vector2<double>(
410  diff[0],
411  diff[1]
412  );
413 
414  #else
415 
416  return Vector2<double>(
417  x - other.x,
418  y - other.y
419  );
420  #endif
421 }
422 
423 template<typename T>
425 {
426  return Vector2<T>(
427  x - other.x,
428  y - other.y
429  );
430 }
431 
432 
433 
435 {
436  #ifndef _EULE_NO_INTRINSICS_
437 
438  // Move vector components and factors into registers
439  __m256d __vector_self = _mm256_set_pd(0, 0, y, x);
440  __m256d __vector_other = _mm256_set_pd(0, 0, other.y, other.x);
441 
442  // Subtract the components
443  __m256d __diff = _mm256_sub_pd(__vector_self, __vector_other);
444 
445  // Retrieve and apply these values
446  double diff[4];
447  _mm256_storeu_pd(diff, __diff);
448 
449  x = diff[0];
450  y = diff[1];
451 
452  #else
453 
454  x -= other.x;
455  y -= other.y;
456 
457  #endif
458 
459  return;
460 }
461 
462 template<typename T>
464 {
465  x -= other.x;
466  y -= other.y;
467  return;
468 }
469 
470 
471 
472 Vector2<double> Vector2<double>::operator*(const double scale) const
473 {
474  #ifndef _EULE_NO_INTRINSICS_
475 
476  // Move vector components and factors into registers
477  __m256d __vector_self = _mm256_set_pd(0, 0, y, x);
478  __m256d __scalar = _mm256_set1_pd(scale);
479 
480  // Multiply the components
481  __m256d __prod = _mm256_mul_pd(__vector_self, __scalar);
482 
483  // Retrieve and return these values
484  double prod[4];
485  _mm256_storeu_pd(prod, __prod);
486 
487  return Vector2<double>(
488  prod[0],
489  prod[1]
490  );
491 
492  #else
493 
494  return Vector2<double>(
495  x * scale,
496  y * scale
497  );
498 
499  #endif
500 }
501 
502 template<typename T>
503 Vector2<T> Vector2<T>::operator*(const T scale) const
504 {
505  return Vector2<T>(
506  x * scale,
507  y * scale
508  );
509 }
510 
511 
512 
513 void Vector2<double>::operator*=(const double scale)
514 {
515  #ifndef _EULE_NO_INTRINSICS_
516 
517  // Move vector components and factors into registers
518  __m256d __vector_self = _mm256_set_pd(0, 0, y, x);
519  __m256d __scalar = _mm256_set1_pd(scale);
520 
521  // Multiply the components
522  __m256d __prod = _mm256_mul_pd(__vector_self, __scalar);
523 
524  // Retrieve and apply these values
525  double prod[4];
526  _mm256_storeu_pd(prod, __prod);
527 
528  x = prod[0];
529  y = prod[1];
530 
531  #else
532 
533  x *= scale;
534  y *= scale;
535 
536  #endif
537 
538  return;
539 }
540 
541 template<typename T>
542 void Vector2<T>::operator*=(const T scale)
543 {
544  x *= scale;
545  y *= scale;
546  return;
547 }
548 
549 
550 
551 Vector2<double> Vector2<double>::operator/(const double scale) const
552 {
553  #ifndef _EULE_NO_INTRINSICS_
554 
555  // Move vector components and factors into registers
556  __m256d __vector_self = _mm256_set_pd(0, 0, y, x);
557  __m256d __scalar = _mm256_set1_pd(scale);
558 
559  // Divide the components
560  __m256d __prod = _mm256_div_pd(__vector_self, __scalar);
561 
562  // Retrieve and return these values
563  double prod[4];
564  _mm256_storeu_pd(prod, __prod);
565 
566  return Vector2<double>(
567  prod[0],
568  prod[1]
569  );
570 
571  #else
572 
573  return Vector2<double>(
574  x / scale,
575  y / scale
576  );
577 
578  #endif
579 }
580 
581 template<typename T>
582 Vector2<T> Vector2<T>::operator/(const T scale) const
583 {
584  return Vector2<T>(
585  x / scale,
586  y / scale
587  );
588 }
589 
590 
591 
592 void Vector2<double>::operator/=(const double scale)
593 {
594  #ifndef _EULE_NO_INTRINSICS_
595 
596  // Move vector components and factors into registers
597  __m256d __vector_self = _mm256_set_pd(0, 0, y, x);
598  __m256d __scalar = _mm256_set1_pd(scale);
599 
600  // Divide the components
601  __m256d __prod = _mm256_div_pd(__vector_self, __scalar);
602 
603  // Retrieve and apply these values
604  double prod[4];
605  _mm256_storeu_pd(prod, __prod);
606 
607  x = prod[0];
608  y = prod[1];
609 
610  #else
611 
612  x /= scale;
613  y /= scale;
614 
615  #endif
616  return;
617 }
618 
619 template<typename T>
620 void Vector2<T>::operator/=(const T scale)
621 {
622  x /= scale;
623  y /= scale;
624  return;
625 }
626 
627 
628 
629 template<typename T>
631 {
632  x = other.x;
633  y = other.y;
634 
635  return;
636 }
637 
638 template<typename T>
639 void Vector2<T>::operator=(Vector2<T>&& other) noexcept
640 {
641  x = std::move(other.x);
642  y = std::move(other.y);
643 
644  return;
645 }
646 
647 template<typename T>
648 bool Vector2<T>::operator==(const Vector2<T>& other) const
649 {
650  return
651  (x == other.x) &&
652  (y == other.y);
653 }
654 
655 template<typename T>
656 bool Vector2<T>::operator!=(const Vector2<T>& other) const
657 {
658  return !operator==(other);
659 }
660 
661 template<typename T>
663 {
664  return Vector2<T>(
665  -x,
666  -y
667  );
668 }
669 
670 // Don't want these includes above the other stuff
671 #include "Vector3.h"
672 #include "Vector4.h"
673 template<typename T>
675 {
676  return Vector3<T>(x, y, 0);
677 }
678 
679 template<typename T>
681 {
682  return Vector4<T>(x, y, 0, 0);
683 }
684 
685 template class Vector2<int>;
686 template class Vector2<double>;
687 
688 // Some handy predefines
689 template <typename T>
690 const Vector2<double> Vector2<T>::up(0, 1);
691 template <typename T>
692 const Vector2<double> Vector2<T>::down(0, -1);
693 template <typename T>
695 template <typename T>
696 const Vector2<double> Vector2<T>::left(-1, 0);
697 template <typename T>
698 const Vector2<double> Vector2<T>::one(1, 1);
699 template <typename T>
Eule::Vector2::DotProduct
double DotProduct(const Vector2< T > &other) const
Will compute the dot product to another Vector2.
Definition: Vector2.cpp:47
Eule::Vector3
Representation of a 3d vector.
Definition: Matrix4x4.h:9
Math.h
Eule::Vector2::ToDouble
Vector2< double > ToDouble() const
Will convert this vector to a Vector2d.
Definition: Vector2.cpp:310
Vector2.h
Eule::Vector2::NormalizeSelf
void NormalizeSelf()
Will normalize this vector.
Definition: Vector2.cpp:187
Vector4.h
Eule::Vector2< double >
Eule::Vector2::x
T x
Definition: Vector2.h:89
Eule::Vector2::y
T y
Definition: Vector2.h:90
Vector3.h
Eule
Definition: Collider.h:4
Eule::Vector2::LerpSelf
void LerpSelf(const Vector2< T > &other, double t)
Will lerp itself towards other by t.
Definition: Vector2.cpp:238
Eule::Vector4
Representation of a 4d vector.
Definition: Vector2.h:8