Leonetienne/Eule
Homemade math library, mainly targetted towards computer graphics
Vector4.cpp
Go to the documentation of this file.
1 #include "Vector4.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 Vector4<double>::SqrMagnitude() const
23 {
24  return (x * x) +
25  (y * y) +
26  (z * z) +
27  (w * w);
28 }
29 
30 // Slow, lame version for intcels
32 {
33  int iSqrMag = x*x + y*y + z*z + w*w;
34  return (double)iSqrMag;
35 }
36 
37 template<typename T>
38 double Vector4<T>::Magnitude() const
39 {
40  return sqrt(SqrMagnitude());
41 }
42 
43 
45 {
46  #ifndef _EULE_NO_INTRINSICS_
47 
48  // Load vectors into registers
49  __m256d __vector_self = _mm256_set_pd(w, z, y, x);
50  __m256d __vector_scalar = _mm256_set_pd(scalar.w, scalar.z, scalar.y, scalar.x);
51 
52  // Multiply them
53  __m256d __product = _mm256_mul_pd(__vector_self, __vector_scalar);
54 
55  // Retrieve result
56  double result[4];
57  _mm256_storeu_pd(result, __product);
58 
59  // Return value
60  return Vector4<double>(
61  result[0],
62  result[1],
63  result[2],
64  result[3]
65  );
66 
67  #else
68 
69  return Vector4<double>(
70  x * scalar.x,
71  y * scalar.y,
72  z * scalar.z,
73  w * scalar.w
74  );
75  #endif
76 }
77 
78 
80 {
81  return Vector4<int>(
82  x * scalar.x,
83  y * scalar.y,
84  z * scalar.z,
85  w * scalar.w
86  );
87 }
88 
89 
90 
91 template<typename T>
93 {
94  Vector4<double> norm(x, y, z, w);
95  norm.NormalizeSelf();
96 
97  return norm;
98 }
99 
100 // Method to normalize a Vector43d
102 {
103  double length = Magnitude();
104 
105  // Prevent division by 0
106  if (length == 0)
107  {
108  x = 0;
109  y = 0;
110  z = 0;
111  w = 0;
112  }
113  else
114  {
115  #ifndef _EULE_NO_INTRINSICS_
116 
117  // Load vector and length into registers
118  __m256d __vec = _mm256_set_pd(w, z, y, x);
119  __m256d __len = _mm256_set1_pd(length);
120 
121  // Divide
122  __m256d __prod = _mm256_div_pd(__vec, __len);
123 
124  // Extract and set values
125  double prod[4];
126  _mm256_storeu_pd(prod, __prod);
127 
128  x = prod[0];
129  y = prod[1];
130  z = prod[2];
131  w = prod[3];
132 
133  #else
134 
135  x /= length;
136  y /= length;
137  z /= length;
138  w /= length;
139 
140  #endif
141  }
142 
143  return;
144 }
145 
146 // You can't normalize an int vector, ffs!
147 // But we need an implementation for T=int
149 {
150  std::cerr << "Stop normalizing int-vectors!!" << std::endl;
151  x = 0;
152  y = 0;
153  z = 0;
154  w = 0;
155 
156  return;
157 }
158 
159 
160 
161 template<typename T>
162 bool Vector4<T>::Similar(const Vector4<T>& other, double epsilon) const
163 {
164  return
165  (::Math::Similar(x, other.x, epsilon)) &&
166  (::Math::Similar(y, other.y, epsilon)) &&
167  (::Math::Similar(z, other.z, epsilon)) &&
168  (::Math::Similar(w, other.w, epsilon))
169  ;
170 }
171 
172 template<typename T>
174 {
175  return Vector4<int>((int)x, (int)y, (int)z, (int)w);
176 }
177 
178 template<typename T>
180 {
181  return Vector4<double>((double)x, (double)y, (double)z, (double)w);
182 }
183 
184 template<typename T>
185 T& Vector4<T>::operator[](std::size_t idx)
186 {
187  switch (idx)
188  {
189  case 0:
190  return x;
191  case 1:
192  return y;
193  case 2:
194  return z;
195  case 3:
196  return w;
197  default:
198  throw std::out_of_range("Array descriptor on Vector4<T> out of range!");
199  }
200 }
201 
202 template<typename T>
203 const T& Vector4<T>::operator[](std::size_t idx) const
204 {
205  switch (idx)
206  {
207  case 0:
208  return x;
209  case 1:
210  return y;
211  case 2:
212  return z;
213  case 3:
214  return w;
215  default:
216  throw std::out_of_range("Array descriptor on Vector4<T> out of range!");
217  }
218 }
219 
220 
221 
222 // Good, optimized chad version for doubles
223 void Vector4<double>::LerpSelf(const Vector4<double>& other, double t)
224 {
225  const double it = 1.0 - t; // Inverse t
226 
227  #ifndef _EULE_NO_INTRINSICS_
228 
229  // Move vector components and factors into registers
230  __m256d __vector_self = _mm256_set_pd(w, z, y, x);
231  __m256d __vector_other = _mm256_set_pd(other.w, other.z, other.y, other.x);
232  __m256d __t = _mm256_set1_pd(t);
233  __m256d __it = _mm256_set1_pd(it); // Inverse t
234 
235  // Procedure:
236  // (__vector_self * __it) + (__vector_other * __t)
237 
238  __m256d __sum = _mm256_set1_pd(0); // this will hold the sum of the two multiplications
239 
240  __sum = _mm256_fmadd_pd(__vector_self, __it, __sum);
241  __sum = _mm256_fmadd_pd(__vector_other, __t, __sum);
242 
243  // Retrieve result, and apply it
244  double sum[4];
245  _mm256_storeu_pd(sum, __sum);
246 
247  x = sum[0];
248  y = sum[1];
249  z = sum[2];
250  w = sum[3];
251 
252  #else
253 
254  x = it * x + t * other.x;
255  y = it * y + t * other.y;
256  z = it * z + t * other.z;
257  w = it * w + t * other.w;
258 
259  #endif
260 
261  return;
262 }
263 
264 
265 
266 // Slow, lame version for intcels
267 void Vector4<int>::LerpSelf(const Vector4<int>& other, double t)
268 {
269  const double it = 1.0 - t;
270 
271  x = (int)(it * (double)x + t * (double)other.x);
272  y = (int)(it * (double)y + t * (double)other.y);
273  z = (int)(it * (double)z + t * (double)other.z);
274  w = (int)(it * (double)w + t * (double)other.w);
275 
276  return;
277 }
278 
279 Vector4<double> Vector4<double>::Lerp(const Vector4<double>& other, double t) const
280 {
281  Vector4d copy(*this);
282  copy.LerpSelf(other, t);
283 
284  return copy;
285 }
286 
287 Vector4<double> Vector4<int>::Lerp(const Vector4<int>& other, double t) const
288 {
289  Vector4d copy(this->ToDouble());
290  copy.LerpSelf(other.ToDouble(), t);
291 
292  return copy;
293 }
294 
295 
296 
298 {
299  #ifndef _EULE_NO_INTRINSICS_
300 
301  // Move vector components and factors into registers
302  __m256d __vector_self = _mm256_set_pd(w, z, y, x);
303  __m256d __vector_other = _mm256_set_pd(other.w, other.z, other.y, other.x);
304 
305  // Add the components
306  __m256d __sum = _mm256_add_pd(__vector_self, __vector_other);
307 
308  // Retrieve and return these values
309  double sum[4];
310  _mm256_storeu_pd(sum, __sum);
311 
312  return Vector4<double>(
313  sum[0],
314  sum[1],
315  sum[2],
316  sum[3]
317  );
318 
319  #else
320 
321  return Vector4<double>(
322  x + other.x,
323  y + other.y,
324  z + other.z,
325  w + other.w
326  );
327  #endif
328 }
329 
330 template<typename T>
332 {
333  return Vector4<T>(
334  x + other.x,
335  y + other.y,
336  z + other.z,
337  w + other.w
338  );
339 }
340 
341 
342 
344 {
345  #ifndef _EULE_NO_INTRINSICS_
346 
347  // Move vector components and factors into registers
348  __m256d __vector_self = _mm256_set_pd(w, z, y, x);
349  __m256d __vector_other = _mm256_set_pd(other.w, other.z, other.y, other.x);
350 
351  // Add the components
352  __m256d __sum = _mm256_add_pd(__vector_self, __vector_other);
353 
354  // Retrieve and apply these values
355  double sum[4];
356  _mm256_storeu_pd(sum, __sum);
357 
358  x = sum[0];
359  y = sum[1];
360  z = sum[2];
361  w = sum[3];
362 
363  #else
364 
365  x += other.x;
366  y += other.y;
367  z += other.z;
368  w += other.w;
369 
370  #endif
371 
372  return;
373 }
374 
375 template<typename T>
377 {
378  x += other.x;
379  y += other.y;
380  z += other.z;
381  w += other.w;
382  return;
383 }
384 
385 
386 
388 {
389  #ifndef _EULE_NO_INTRINSICS_
390 
391  // Move vector components and factors into registers
392  __m256d __vector_self = _mm256_set_pd(w, z, y, x);
393  __m256d __vector_other = _mm256_set_pd(other.w, other.z, other.y, other.x);
394 
395  // Subtract the components
396  __m256d __diff = _mm256_sub_pd(__vector_self, __vector_other);
397 
398  // Retrieve and return these values
399  double diff[4];
400  _mm256_storeu_pd(diff, __diff);
401 
402  return Vector4<double>(
403  diff[0],
404  diff[1],
405  diff[2],
406  diff[3]
407  );
408 
409  #else
410 
411  return Vector4<double>(
412  x - other.x,
413  y - other.y,
414  z - other.z,
415  w - other.w
416  );
417  #endif
418 }
419 
420 template<typename T>
422 {
423  return Vector4<T>(
424  x - other.x,
425  y - other.y,
426  z - other.z,
427  w - other.w
428  );
429 }
430 
431 
432 
434 {
435  #ifndef _EULE_NO_INTRINSICS_
436 
437  // Move vector components and factors into registers
438  __m256d __vector_self = _mm256_set_pd(w, z, y, x);
439  __m256d __vector_other = _mm256_set_pd(other.w, other.z, other.y, other.x);
440 
441  // Subtract the components
442  __m256d __diff = _mm256_sub_pd(__vector_self, __vector_other);
443 
444  // Retrieve and apply these values
445  double diff[4];
446  _mm256_storeu_pd(diff, __diff);
447 
448  x = diff[0];
449  y = diff[1];
450  z = diff[2];
451  w = diff[3];
452 
453  #else
454 
455  x -= other.x;
456  y -= other.y;
457  z -= other.z;
458  w -= other.w;
459 
460  #endif
461 
462  return;
463 }
464 
465 template<typename T>
467 {
468  x -= other.x;
469  y -= other.y;
470  z -= other.z;
471  w -= other.w;
472  return;
473 }
474 
475 
476 
477 Vector4<double> Vector4<double>::operator*(const double scale) const
478 {
479  #ifndef _EULE_NO_INTRINSICS_
480 
481  // Move vector components and factors into registers
482  __m256d __vector_self = _mm256_set_pd(w, z, y, x);
483  __m256d __scalar = _mm256_set1_pd(scale);
484 
485  // Multiply the components
486  __m256d __prod = _mm256_mul_pd(__vector_self, __scalar);
487 
488  // Retrieve and return these values
489  double prod[4];
490  _mm256_storeu_pd(prod, __prod);
491 
492  return Vector4<double>(
493  prod[0],
494  prod[1],
495  prod[2],
496  prod[3]
497  );
498 
499  #else
500 
501  return Vector4<double>(
502  x * scale,
503  y * scale,
504  z * scale,
505  w * scale
506  );
507 
508  #endif
509 }
510 
511 template<typename T>
512 Vector4<T> Vector4<T>::operator*(const T scale) const
513 {
514  return Vector4<T>(
515  x * scale,
516  y * scale,
517  z * scale,
518  w * scale
519  );
520 }
521 
522 
523 
524 void Vector4<double>::operator*=(const double scale)
525 {
526  #ifndef _EULE_NO_INTRINSICS_
527 
528  // Move vector components and factors into registers
529  __m256d __vector_self = _mm256_set_pd(w, z, y, x);
530  __m256d __scalar = _mm256_set1_pd(scale);
531 
532  // Multiply the components
533  __m256d __prod = _mm256_mul_pd(__vector_self, __scalar);
534 
535  // Retrieve and apply these values
536  double prod[4];
537  _mm256_storeu_pd(prod, __prod);
538 
539  x = prod[0];
540  y = prod[1];
541  z = prod[2];
542  w = prod[3];
543 
544  #else
545 
546  x *= scale;
547  y *= scale;
548  z *= scale;
549  w *= scale;
550 
551  #endif
552 
553  return;
554 }
555 
556 template<typename T>
557 void Vector4<T>::operator*=(const T scale)
558 {
559  x *= scale;
560  y *= scale;
561  z *= scale;
562  w *= scale;
563  return;
564 }
565 
566 
567 
568 Vector4<double> Vector4<double>::operator/(const double scale) const
569 {
570  #ifndef _EULE_NO_INTRINSICS_
571 
572  // Move vector components and factors into registers
573  __m256d __vector_self = _mm256_set_pd(w, z, y, x);
574  __m256d __scalar = _mm256_set1_pd(scale);
575 
576  // Divide the components
577  __m256d __prod = _mm256_div_pd(__vector_self, __scalar);
578 
579  // Retrieve and return these values
580  double prod[4];
581  _mm256_storeu_pd(prod, __prod);
582 
583  return Vector4<double>(
584  prod[0],
585  prod[1],
586  prod[2],
587  prod[3]
588  );
589 
590  #else
591 
592  return Vector4<double>(
593  x / scale,
594  y / scale,
595  z / scale,
596  w / scale
597  );
598 
599  #endif
600 }
601 
602 template<typename T>
603 Vector4<T> Vector4<T>::operator/(const T scale) const
604 {
605  return Vector4<T>(
606  x / scale,
607  y / scale,
608  z / scale,
609  w / scale
610  );
611 }
612 
613 
614 
615 void Vector4<double>::operator/=(const double scale)
616 {
617  #ifndef _EULE_NO_INTRINSICS_
618 
619  // Move vector components and factors into registers
620  __m256d __vector_self = _mm256_set_pd(w, z, y, x);
621  __m256d __scalar = _mm256_set1_pd(scale);
622 
623  // Divide the components
624  __m256d __prod = _mm256_div_pd(__vector_self, __scalar);
625 
626  // Retrieve and apply these values
627  double prod[4];
628  _mm256_storeu_pd(prod, __prod);
629 
630  x = prod[0];
631  y = prod[1];
632  z = prod[2];
633  w = prod[3];
634 
635  #else
636 
637  x /= scale;
638  y /= scale;
639  z /= scale;
640  w /= scale;
641 
642  #endif
643  return;
644 }
645 
646 template<typename T>
647 void Vector4<T>::operator/=(const T scale)
648 {
649  x /= scale;
650  y /= scale;
651  z /= scale;
652  w /= scale;
653  return;
654 }
655 
656 
657 
658 template<typename T>
659 bool Vector4<T>::operator==(const Vector4<T>& other) const
660 {
661  return
662  (x == other.x) &&
663  (y == other.y) &&
664  (z == other.z) &&
665  (w == other.w);
666 }
667 
668 
669 
670 // Good, optimized chad version for doubles
672 {
673  Vector4<double> newVec;
674 
675  newVec.x = (mat[0][0] * x) + (mat[0][1] * y) + (mat[0][2] * z) + (mat[0][3] * w);
676  newVec.y = (mat[1][0] * x) + (mat[1][1] * y) + (mat[1][2] * z) + (mat[1][3] * w);
677  newVec.z = (mat[2][0] * x) + (mat[2][1] * y) + (mat[2][2] * z) + (mat[2][3] * w);
678  newVec.w = (mat[3][0] * x) + (mat[3][1] * y) + (mat[3][2] * z) + (mat[3][3] * w);
679 
680  return newVec;
681 }
682 
683 // Slow, lame version for intcels
685 {
686  Vector4<double> newVec;
687 
688  newVec.x = (mat[0][0] * x) + (mat[0][1] * y) + (mat[0][2] * z) + (mat[0][3] * w);
689  newVec.y = (mat[1][0] * x) + (mat[1][1] * y) + (mat[1][2] * z) + (mat[1][3] * w);
690  newVec.z = (mat[2][0] * x) + (mat[2][1] * y) + (mat[2][2] * z) + (mat[2][3] * w);
691  newVec.w = (mat[3][0] * x) + (mat[3][1] * y) + (mat[3][2] * z) + (mat[3][3] * w);
692 
693  return Vector4<int>(
694  (int)newVec.x,
695  (int)newVec.y,
696  (int)newVec.z,
697  (int)newVec.w
698  );
699 }
700 
701 
702 
703 // Good, optimized chad version for doubles
704 void Vector4<double>::operator*=(const Matrix4x4& mat)
705 {
706  Vector4<double> buffer = *this;
707 
708  // Should this still be reversed...? like, instead of mat[x][y], use mat[y][m]
709  // idk right now. check that if something doesn't work
710  x = (mat[0][0] * buffer.x) + (mat[0][1] * buffer.y) + (mat[0][2] * buffer.z) + (mat[0][3] * buffer.w);
711  y = (mat[1][0] * buffer.x) + (mat[1][1] * buffer.y) + (mat[1][2] * buffer.z) + (mat[1][3] * buffer.w);
712  z = (mat[2][0] * buffer.x) + (mat[2][1] * buffer.y) + (mat[2][2] * buffer.z) + (mat[2][3] * buffer.w);
713  w = (mat[3][0] * buffer.x) + (mat[3][1] * buffer.y) + (mat[3][2] * buffer.z) + (mat[3][3] * buffer.w);
714 
715  return;
716 }
717 
718 template<typename T>
720 {
721  return Vector4<T>(
722  -x,
723  -y,
724  -z,
725  -w
726  );
727 }
728 
729 template<typename T>
731 {
732  x = other.x;
733  y = other.y;
734  z = other.z;
735  w = other.w;
736 
737  return;
738 }
739 
740 template<typename T>
741 void Vector4<T>::operator=(Vector4<T>&& other) noexcept
742 {
743  x = std::move(other.x);
744  y = std::move(other.y);
745  z = std::move(other.z);
746  w = std::move(other.w);
747 
748  return;
749 }
750 
751 // Slow, lame version for intcels
753 {
754  Vector4<double> buffer(x, y, z, w);
755 
756  // Should this still be reversed...? like, instead of mat[x][y], use mat[y][m]
757  // idk right now. check that if something doesn't work
758  x = (int)((mat[0][0] * buffer.x) + (mat[0][1] * buffer.y) + (mat[0][2] * buffer.z) + (mat[0][3] * buffer.w));
759  y = (int)((mat[1][0] * buffer.x) + (mat[1][1] * buffer.y) + (mat[1][2] * buffer.z) + (mat[1][3] * buffer.w));
760  z = (int)((mat[2][0] * buffer.x) + (mat[2][1] * buffer.y) + (mat[2][2] * buffer.z) + (mat[2][3] * buffer.w));
761  w = (int)((mat[3][0] * buffer.x) + (mat[3][1] * buffer.y) + (mat[3][2] * buffer.z) + (mat[3][3] * buffer.w));
762 
763  return;
764 }
765 
766 template<typename T>
767 bool Vector4<T>::operator!=(const Vector4<T>& other) const
768 {
769  return !operator==(other);
770 }
771 
772 #include "Vector2.h"
773 #include "Vector3.h"
774 template<typename T>
776 {
777  return Vector2<T>(x, y);
778 }
779 
780 template<typename T>
782 {
783  return Vector3<T>(x, y, z);
784 }
785 
786 template class Vector4<int>;
787 template class Vector4<double>;
788 
789 // Some handy predefines
790 template <typename T>
791 const Vector4<double> Vector4<T>::up(0, 1, 0, 0);
792 template <typename T>
793 const Vector4<double> Vector4<T>::down(0, -1, 0, 0);
794 template <typename T>
795 const Vector4<double> Vector4<T>::right(1, 0, 0, 0);
796 template <typename T>
797 const Vector4<double> Vector4<T>::left(-1, 0, 0, 0);
798 template <typename T>
799 const Vector4<double> Vector4<T>::forward(1, 0, 0, 0);
800 template <typename T>
801 const Vector4<double> Vector4<T>::backward(-1, 0, 0, 0);
802 template <typename T>
803 const Vector4<double> Vector4<T>::future(0, 0, 0, 1);
804 template <typename T>
805 const Vector4<double> Vector4<T>::past(0, 0, 0, -1);
806 template <typename T>
807 const Vector4<double> Vector4<T>::one(1, 1, 1, 1);
808 template <typename T>
809 const Vector4<double> Vector4<T>::zero(0, 0, 0, 0);
Eule::Vector4::NormalizeSelf
void NormalizeSelf()
Will normalize this vector.
Definition: Vector4.cpp:148
Eule::Vector3
Representation of a 3d vector.
Definition: Matrix4x4.h:9
Eule::Vector4::x
T x
Definition: Vector4.h:88
Eule::Vector4::z
T z
Definition: Vector4.h:90
Math.h
Eule::Vector4::LerpSelf
void LerpSelf(const Vector4< T > &other, double t)
Will lerp itself towards other by t.
Definition: Vector4.cpp:267
Eule::Vector4::w
T w
Definition: Vector4.h:91
Vector2.h
Eule::Matrix4x4
A matrix 4x4 class representing a 3d transformation.
Definition: Matrix4x4.h:36
Eule::Vector4::ToDouble
Vector4< double > ToDouble() const
Will convert this vector to a Vector4d.
Definition: Vector4.cpp:179
Vector4.h
Eule::Vector2
Representation of a 2d vector.
Definition: Vector2.h:14
Eule::Vector4::SqrMagnitude
double SqrMagnitude() const
Will compute the square magnitude.
Definition: Vector4.cpp:31
Vector3.h
Eule::Vector4::y
T y
Definition: Vector4.h:89
Eule
Definition: Collider.h:4
Eule::Vector4
Representation of a 4d vector.
Definition: Vector2.h:8