1 // Copyright 2009-2021 Intel Corporation
2 // SPDX-License-Identifier: Apache-2.0
3 
4 #pragma once
5 
6 #include "../common.h"
7 #include "constants.h"
8 #include "rkmath.h"
9 
10 #include "../traits/rktraits.h"
11 
12 namespace rkcommon {
13 
14   // NOTE: only for identifying vec_t types at compile-time
15   struct vec_base
16   {
17   };
18 
19   // -------------------------------------------------------
20   // type traits relevant to vec_t<> type compile-time logic
21   // -------------------------------------------------------
22 
23   namespace traits {
24 
25     template <typename T>
26     using is_arithmetic_t = enable_if_t<std::is_arithmetic<T>::value>;
27 
28     template <typename T>
29     struct is_vec
30     {
31       const static bool value = std::is_base_of<vec_base, T>::value;
32     };
33 
34     template <typename VEC_ELEMENT_T, typename TYPE_IN_QUESTION>
35     struct is_valid_vec_constructor_type
36     {
37       const static bool value =
38           std::is_constructible<VEC_ELEMENT_T, TYPE_IN_QUESTION>::value &&
39           !std::is_same<TYPE_IN_QUESTION, VEC_ELEMENT_T>::value &&
40           !is_vec<TYPE_IN_QUESTION>::value;
41     };
42 
43     template <typename VEC_ELEMENT_T, typename TYPE_IN_QUESTION>
44     using is_valid_vec_constructor_type_t = enable_if_t<
45         is_valid_vec_constructor_type<VEC_ELEMENT_T, TYPE_IN_QUESTION>::value>;
46 
47   }  // namespace traits
48 
49   namespace math {
50 
51     // vec_t<> types //////////////////////////////////////////////////////////
52 
53     template <typename T, int N, bool ALIGN = false>
54     struct vec_t : public vec_base
55     {
56       using scalar_t = T;
57       using Scalar   = T;
58     };
59 
60     template <typename T>
61     struct vec_t<T, 2> : public vec_base
62     {
63       using scalar_t = T;
64       using Scalar   = T;
65 
66       vec_t() = default;
67 
68       vec_t(const scalar_t *v) : x(v[0]), y(v[1]) {}
69 
70       vec_t(scalar_t s) : x(s), y(s) {}
71 
72       template <typename OT,
73                 typename = traits::is_valid_vec_constructor_type_t<T, OT>>
74       vec_t(const OT &s) : x(s), y(s)
75       {
76       }
77 
78       vec_t(scalar_t x, scalar_t y) : x(x), y(y) {}
79 
80       template <typename OT, bool OA>
81       vec_t(const vec_t<OT, 2, OA> &o) : x(o.x), y(o.y)
82       {
83       }
84 
85       const T &operator[](const size_t idx) const
86       {
87         assert(idx < 2);
88         return (&x)[idx];
89       }
90 
91       T &operator[](const size_t idx)
92       {
93         assert(idx < 2);
94         return (&x)[idx];
95       }
96 
97       operator T *()
98       {
99         return &x;
100       }
101 
102       operator const T *() const
103       {
104         return &x;
105       }
106 
107       /*! return result of reduce_add() across all components */
108       scalar_t sum() const
109       {
110         return x + y;
111       }
112       /*! return result of reduce_mul() across all components */
113       scalar_t product() const
114       {
115         return x * y;
116       }
117 
118       size_t long_product() const
119       {
120         return size_t(x) * size_t(y);
121       }
122 
123       // conversion constructor to other types to enable static_cast
124       template <typename OT>
125       explicit operator vec_t<OT, 2>() const
126       {
127         return vec_t<OT, 2>(*this);
128       }
129 
130       T x, y;
131     };
132 
133     template <typename T>
134     struct vec_t<T, 3> : public vec_base
135     {
136       using scalar_t = T;
137       using Scalar   = T;
138 
139       vec_t() = default;
140 
141       vec_t(const scalar_t *v) : x(v[0]), y(v[1]), z(v[2]) {}
142 
143       vec_t(scalar_t s) : x(s), y(s), z(s) {}
144 
145       template <typename OT,
146                 typename = traits::is_valid_vec_constructor_type_t<T, OT>>
147       vec_t(const OT &s) : x(s), y(s), z(s)
148       {
149       }
150 
151       vec_t(scalar_t x, scalar_t y, scalar_t z) : x(x), y(y), z(z) {}
152 
153       template <typename OT, bool OA>
154       vec_t(const vec_t<OT, 2, OA> &o, scalar_t z) : x(o.x), y(o.y), z(z)
155       {
156       }
157 
158       template <typename OT, bool OA>
159       vec_t(const vec_t<OT, 3, OA> &o) : x(o.x), y(o.y), z(o.z)
160       {
161       }
162 
163       const T &operator[](const size_t axis) const
164       {
165         assert(axis < 3);
166         return (&x)[axis];
167       }
168 
169       T &operator[](const size_t axis)
170       {
171         assert(axis < 3);
172         return (&x)[axis];
173       }
174 
175       operator T *()
176       {
177         return &x;
178       }
179 
180       operator const T *() const
181       {
182         return &x;
183       }
184 
185       /*! return result of reduce_add() across all components */
186       scalar_t sum() const
187       {
188         return x + y + z;
189       }
190 
191       /*! return result of reduce_mul() across all components */
192       scalar_t product() const
193       {
194         return x * y * z;
195       }
196 
197       size_t long_product() const
198       {
199         return size_t(x) * size_t(y) * size_t(z);
200       }
201 
202       // conversion constructor to other types to enable static_cast
203       template <typename OT>
204       explicit operator vec_t<OT, 3>() const
205       {
206         return vec_t<OT, 3>(*this);
207       }
208 
209       T x, y, z;
210     };
211 
212     template <typename T>
213     struct vec_t<T, 3, true> : public vec_base
214     {
215       using scalar_t = T;
216       using Scalar   = T;
217 
218       vec_t() = default;
219 
220       vec_t(const scalar_t *v) : x(v[0]), y(v[1]), z(v[2]) {}
221 
222       vec_t(scalar_t s) : x(s), y(s), z(s) {}
223 
224       template <typename OT,
225                 typename = traits::is_valid_vec_constructor_type_t<T, OT>>
226       vec_t(const OT &s) : x(s), y(s), z(s)
227       {
228       }
229 
230       vec_t(scalar_t x, scalar_t y, scalar_t z) : x(x), y(y), z(z) {}
231 
232       template <typename OT, bool OA>
233       vec_t(const vec_t<OT, 2, OA> &o, scalar_t z) : x(o.x), y(o.y), z(z)
234       {
235       }
236 
237       template <typename OT, bool OA>
238       vec_t(const vec_t<OT, 3, OA> &o) : x(o.x), y(o.y), z(o.z)
239       {
240       }
241 
242       const T &operator[](const size_t axis) const
243       {
244         assert(axis < 3);
245         return (&x)[axis];
246       }
247       T &operator[](const size_t axis)
248       {
249         assert(axis < 3);
250         return (&x)[axis];
251       }
252 
253       operator T *()
254       {
255         return &x;
256       }
257 
258       operator const T *() const
259       {
260         return &x;
261       }
262 
263       /*! return result of reduce_add() across all components */
264       scalar_t sum() const
265       {
266         return x + y + z;
267       }
268       /*! return result of reduce_mul() across all components */
269       scalar_t product() const
270       {
271         return x * y * z;
272       }
273 
274       size_t long_product() const
275       {
276         return size_t(x) * size_t(y) * size_t(z);
277       }
278 
279       operator vec_t<T, 3>() const
280       {
281         return vec_t<T, 3>(x, y, z);
282       }
283 
284       // conversion constructor to other types to enable static_cast
285       template <typename OT>
286       explicit operator vec_t<OT, 3, true>() const
287       {
288         return vec_t<OT, 3, true>(*this);
289       }
290 
291       T x, y, z;
292       T padding_;
293     };
294 
295     template <typename T>
296     struct vec_t<T, 4> : public vec_base
297     {
298       using scalar_t = T;
299       using Scalar   = T;
300 
301       vec_t() = default;
302 
303       vec_t(const scalar_t *v) : x(v[0]), y(v[1]), z(v[2]), w(v[3]) {}
304 
305       vec_t(scalar_t s) : x(s), y(s), z(s), w(s) {}
306 
307       template <typename OT,
308                 typename = traits::is_valid_vec_constructor_type_t<T, OT>>
309       vec_t(const OT &s) : x(s), y(s), z(s), w(s)
310       {
311       }
312 
313       vec_t(scalar_t x, scalar_t y, scalar_t z, scalar_t w)
314           : x(x), y(y), z(z), w(w)
315       {
316       }
317 
318       template <typename OT, bool OA>
319       vec_t(const vec_t<OT, 2, OA> &o1, const vec_t<OT, 2, OA> &o2)
320           : x(o1.x), y(o1.y), z(o2.x), w(o2.y)
321       {
322       }
323 
324       template <typename OT, bool OA>
325       vec_t(const vec_t<OT, 3, OA> &o, scalar_t w)
326           : x(o.x), y(o.y), z(o.z), w(w)
327       {
328       }
329 
330       template <typename OT, bool OA>
331       vec_t(const vec_t<OT, 4, OA> &o) : x(o.x), y(o.y), z(o.z), w(o.w)
332       {
333       }
334 
335       const T &operator[](const size_t idx) const
336       {
337         assert(idx < 4);
338         return (&x)[idx];
339       }
340       T &operator[](const size_t idx)
341       {
342         assert(idx < 4);
343         return (&x)[idx];
344       }
345 
346       operator T *()
347       {
348         return &x;
349       }
350 
351       operator const T *() const
352       {
353         return &x;
354       }
355 
356       /*! return result of reduce_add() across all components */
357       scalar_t sum() const
358       {
359         return x + y + z + w;
360       }
361       /*! return result of reduce_mul() across all components */
362       scalar_t product() const
363       {
364         return x * y * z * w;
365       }
366 
367       size_t long_product() const
368       {
369         return size_t(x) * size_t(y) * size_t(z) * size_t(w);
370       }
371 
372       // conversion constructor to other types to enable static_cast
373       template <typename OT>
374       explicit operator vec_t<OT, 4>() const
375       {
376         return vec_t<OT, 4>(*this);
377       }
378 
379       T x, y, z, w;
380     };
381 
382     // -------------------------------------------------------
383     // unary operators
384     // -------------------------------------------------------
385     template <typename T>
386     inline vec_t<T, 2> operator-(const vec_t<T, 2> &v)
387     {
388       return vec_t<T, 2>(-v.x, -v.y);
389     }
390     template <typename T>
391     inline vec_t<T, 3> operator-(const vec_t<T, 3> &v)
392     {
393       return vec_t<T, 3>(-v.x, -v.y, -v.z);
394     }
395     template <typename T>
396     inline vec_t<T, 3, 1> operator-(const vec_t<T, 3, 1> &v)
397     {
398       return vec_t<T, 3, 1>(-v.x, -v.y, -v.z);
399     }
400     template <typename T>
401     inline vec_t<T, 4> operator-(const vec_t<T, 4> &v)
402     {
403       return vec_t<T, 4>(-v.x, -v.y, -v.z, -v.w);
404     }
405 
406     template <typename T>
407     inline vec_t<T, 2> operator+(const vec_t<T, 2> &v)
408     {
409       return vec_t<T, 2>(+v.x, +v.y);
410     }
411     template <typename T>
412     inline vec_t<T, 3> operator+(const vec_t<T, 3> &v)
413     {
414       return vec_t<T, 3>(+v.x, +v.y, +v.z);
415     }
416     template <typename T>
417     inline vec_t<T, 3, 1> operator+(const vec_t<T, 3, 1> &v)
418     {
419       return vec_t<T, 3, 1>(+v.x, +v.y, +v.z);
420     }
421     template <typename T>
422     inline vec_t<T, 4> operator+(const vec_t<T, 4> &v)
423     {
424       return vec_t<T, 4>(+v.x, +v.y, +v.z, +v.w);
425     }
426 
427     using std::abs;
428 
429 // -------------------------------------------------------
430 // unary functors
431 // -------------------------------------------------------
432 #define unary_functor(op)                                   \
433   template <typename T>                                     \
434   inline vec_t<T, 2> op(const vec_t<T, 2> &v)               \
435   {                                                         \
436     return vec_t<T, 2>(op(v.x), op(v.y));                   \
437   }                                                         \
438   template <typename T>                                     \
439   inline vec_t<T, 3> op(const vec_t<T, 3> &v)               \
440   {                                                         \
441     return vec_t<T, 3>(op(v.x), op(v.y), op(v.z));          \
442   }                                                         \
443   template <typename T>                                     \
444   inline vec_t<T, 3, true> op(const vec_t<T, 3, 1> &v)      \
445   {                                                         \
446     return vec_t<T, 3, 1>(op(v.x), op(v.y), op(v.z));       \
447   }                                                         \
448   template <typename T>                                     \
449   inline vec_t<T, 4> op(const vec_t<T, 4> &v)               \
450   {                                                         \
451     return vec_t<T, 4>(op(v.x), op(v.y), op(v.z), op(v.w)); \
452   }
453 
454     // clang-format off
455     unary_functor(rcp)
456     unary_functor(rcp_safe)
457     unary_functor(abs)
458     unary_functor(sin)
459     unary_functor(cos)
460     // clang-format on
461 #undef unary_functor
462 
463     // -------------------------------------------------------
464     // binary arithmetic operators
465     // -------------------------------------------------------
466 
467 #define binary_operator(name, op)                                           \
468   /* "vec op vec" */                                                        \
469   template <typename T>                                                     \
470   inline vec_t<T, 2> name(const vec_t<T, 2> &a, const vec_t<T, 2> &b)       \
471   {                                                                         \
472     return vec_t<T, 2>(a.x op b.x, a.y op b.y);                             \
473   }                                                                         \
474                                                                             \
475   template <typename T, bool A, bool B>                                     \
476   inline vec_t<T, 3> name(const vec_t<T, 3, A> &a, const vec_t<T, 3, B> &b) \
477   {                                                                         \
478     return vec_t<T, 3>(a.x op b.x, a.y op b.y, a.z op b.z);                 \
479   }                                                                         \
480                                                                             \
481   template <typename T>                                                     \
482   inline vec_t<T, 4> name(const vec_t<T, 4> &a, const vec_t<T, 4> &b)       \
483   {                                                                         \
484     return vec_t<T, 4>(a.x op b.x, a.y op b.y, a.z op b.z, a.w op b.w);     \
485   }                                                                         \
486                                                                             \
487   /* "vec<T, N> op vec<U, N>" (element types don't match) */                \
488   template <typename T,                                                     \
489             typename U,                                                     \
490             int N,                                                          \
491             bool A,                                                         \
492             typename = traits::is_not_same_t<T, U>>                         \
493   inline auto name(const vec_t<T, N, A> &a, const vec_t<U, N, A> &b)        \
494       ->vec_t<decltype(T() op U()), N, A>                                   \
495   {                                                                         \
496     using vector_t = vec_t<decltype(T() op U()), N, A>;                     \
497     return vector_t(vector_t(a) op vector_t(b));                            \
498   }                                                                         \
499                                                                             \
500   /* "vec op scalar" */                                                     \
501   template <typename T>                                                     \
502   inline vec_t<T, 2> name(const vec_t<T, 2> &a, const T &b)                 \
503   {                                                                         \
504     return vec_t<T, 2>(a.x op b, a.y op b);                                 \
505   }                                                                         \
506                                                                             \
507   template <typename T, bool A>                                             \
508   inline vec_t<T, 3> name(const vec_t<T, 3, A> &a, const T &b)              \
509   {                                                                         \
510     return vec_t<T, 3>(a.x op b, a.y op b, a.z op b);                       \
511   }                                                                         \
512                                                                             \
513   template <typename T>                                                     \
514   inline vec_t<T, 4> name(const vec_t<T, 4> &a, const T &b)                 \
515   {                                                                         \
516     return vec_t<T, 4>(a.x op b, a.y op b, a.z op b, a.w op b);             \
517   }                                                                         \
518                                                                             \
519   /* "vec<T, N> op U" (element types don't match) */                        \
520   template <typename T,                                                     \
521             typename U,                                                     \
522             int N,                                                          \
523             bool A,                                                         \
524             typename = traits::is_not_same_t<T, U>>                         \
525   inline auto name(const vec_t<T, N, A> &a, const U &b)                     \
526       ->vec_t<decltype(T() op U()), N, A>                                   \
527   {                                                                         \
528     using scalar_t = decltype(T() op U());                                  \
529     using vector_t = vec_t<scalar_t, N, A>;                                 \
530     return vector_t(vector_t(a) op scalar_t(b));                            \
531   }                                                                         \
532                                                                             \
533   /* "scalar op vec" */                                                     \
534   template <typename T>                                                     \
535   inline vec_t<T, 2> name(const T &a, const vec_t<T, 2> &b)                 \
536   {                                                                         \
537     return vec_t<T, 2>(a op b.x, a op b.y);                                 \
538   }                                                                         \
539                                                                             \
540   template <typename T, bool A>                                             \
541   inline vec_t<T, 3> name(const T &a, const vec_t<T, 3, A> &b)              \
542   {                                                                         \
543     return vec_t<T, 3>(a op b.x, a op b.y, a op b.z);                       \
544   }                                                                         \
545                                                                             \
546   template <typename T>                                                     \
547   inline vec_t<T, 4> name(const T &a, const vec_t<T, 4> &b)                 \
548   {                                                                         \
549     return vec_t<T, 4>(a op b.x, a op b.y, a op b.z, a op b.w);             \
550   }                                                                         \
551                                                                             \
552   /* "T op vec<U, N>" (element types don't match) */                        \
553   template <typename T,                                                     \
554             typename U,                                                     \
555             int N,                                                          \
556             bool A,                                                         \
557             typename = traits::is_not_same_t<T, U>>                         \
558   inline auto name(const T &a, const vec_t<U, N, A> &b)                     \
559       ->vec_t<decltype(T() op U()), N, A>                                   \
560   {                                                                         \
561     using scalar_t = decltype(T() op U());                                  \
562     using vector_t = vec_t<scalar_t, N, A>;                                 \
563     return vector_t(scalar_t(a) op vector_t(b));                            \
564   }
565 
566         // clang-format off
567     binary_operator(operator+, +)
568     binary_operator(operator-, -)
569     binary_operator(operator*, *)
570     binary_operator(operator/, /)
571     binary_operator(operator%, %)
572     // clang-format on
573 #undef binary_operator
574 
575 // -------------------------------------------------------
576 // binary arithmetic assignment operators
577 // -------------------------------------------------------
578 #define binary_operator(name, op)                                          \
579   /* "vec op vec" */                                                       \
580   template <typename T, typename U>                                        \
581   inline vec_t<T, 2> &name(vec_t<T, 2> &a, const vec_t<U, 2> &b)           \
582   {                                                                        \
583     a.x op b.x;                                                            \
584     a.y op b.y;                                                            \
585     return a;                                                              \
586   }                                                                        \
587                                                                            \
588   template <typename T, typename U, bool A, bool B>                        \
589   inline vec_t<T, 3, A> &name(vec_t<T, 3, A> &a, const vec_t<U, 3, B> &b)  \
590   {                                                                        \
591     a.x op b.x;                                                            \
592     a.y op b.y;                                                            \
593     a.z op b.z;                                                            \
594     return a;                                                              \
595   }                                                                        \
596                                                                            \
597   template <typename T, typename U>                                        \
598   inline vec_t<T, 4> &name(vec_t<T, 4> &a, const vec_t<U, 4> &b)           \
599   {                                                                        \
600     a.x op b.x;                                                            \
601     a.y op b.y;                                                            \
602     a.z op b.z;                                                            \
603     a.w op b.w;                                                            \
604     return a;                                                              \
605   }                                                                        \
606                                                                            \
607   /* "vec op scalar" */                                                    \
608   template <typename T, typename U, typename = traits::is_arithmetic_t<U>> \
609   inline vec_t<T, 2> &name(vec_t<T, 2> &a, const U &b)                     \
610   {                                                                        \
611     a.x op b;                                                              \
612     a.y op b;                                                              \
613     return a;                                                              \
614   }                                                                        \
615                                                                            \
616   template <typename T,                                                    \
617             typename U,                                                    \
618             bool A,                                                        \
619             typename = traits::is_arithmetic_t<U>>                         \
620   inline vec_t<T, 3, A> &name(vec_t<T, 3, A> &a, const U &b)               \
621   {                                                                        \
622     a.x op b;                                                              \
623     a.y op b;                                                              \
624     a.z op b;                                                              \
625     return a;                                                              \
626   }                                                                        \
627                                                                            \
628   template <typename T, typename U, typename = traits::is_arithmetic_t<U>> \
629   inline vec_t<T, 4> &name(vec_t<T, 4> &a, const U &b)                     \
630   {                                                                        \
631     a.x op b;                                                              \
632     a.y op b;                                                              \
633     a.z op b;                                                              \
634     a.w op b;                                                              \
635     return a;                                                              \
636   }
637 
638         // clang-format off
639     binary_operator(operator+=, +=)
640     binary_operator(operator-=, -=)
641     binary_operator(operator*=, *=)
642     binary_operator(operator/=, /=)
643     binary_operator(operator%=, %=)
644     // clang-format on
645 #undef binary_operator
646 
647         // -------------------------------------------------------
648         // ternary operators (just for compatibility with old embree
649         // -------------------------------------------------------
650         template <typename T, bool A>
651         inline vec_t<T, 3, A> madd(const vec_t<T, 3, A> &a,
652                                    const vec_t<T, 3, A> &b,
653                                    const vec_t<T, 3, A> &c)
654     {
655       return vec_t<T, 3, A>(
656           madd(a.x, b.x, c.x), madd(a.y, b.y, c.y), madd(a.z, b.z, c.z));
657     }
658 
659     // -------------------------------------------------------
660     // comparison operators
661     // -------------------------------------------------------
662     template <typename T>
663     inline bool operator==(const vec_t<T, 2> &a, const vec_t<T, 2> &b)
664     {
665       return a.x == b.x && a.y == b.y;
666     }
667 
668     template <typename T, bool A, bool B>
669     inline bool operator==(const vec_t<T, 3, A> &a, const vec_t<T, 3, B> &b)
670     {
671       return a.x == b.x && a.y == b.y && a.z == b.z;
672     }
673 
674     template <typename T>
675     inline bool operator==(const vec_t<T, 4> &a, const vec_t<T, 4> &b)
676     {
677       return a.x == b.x && a.y == b.y && a.z == b.z && a.w == b.w;
678     }
679 
680     template <typename T>
681     inline bool operator!=(const vec_t<T, 2> &a, const vec_t<T, 2> &b)
682     {
683       return !(a == b);
684     }
685 
686     template <typename T, bool A, bool B>
687     inline bool operator!=(const vec_t<T, 3, A> &a, const vec_t<T, 3, B> &b)
688     {
689       return !(a == b);
690     }
691 
692     template <typename T>
693     inline bool operator!=(const vec_t<T, 4> &a, const vec_t<T, 4> &b)
694     {
695       return !(a == b);
696     }
697 
698     // 'anyLessThan' - return true if any component is less than the other vec's
699     template <typename T>
700     inline bool anyLessThan(const vec_t<T, 2> &a, const vec_t<T, 2> &b)
701     {
702       return a.x < b.x || a.y < b.y;
703     }
704 
705     template <typename T, bool A, bool B>
706     inline bool anyLessThan(const vec_t<T, 3, A> &a, const vec_t<T, 3, B> &b)
707     {
708       return a.x < b.x || a.y < b.y || a.z < b.z;
709     }
710 
711     template <typename T>
712     inline bool anyLessThan(const vec_t<T, 4> &a, const vec_t<T, 4> &b)
713     {
714       return a.x < b.x || a.y < b.y || a.z < b.z || a.w < b.w;
715     }
716 
717     // -------------------------------------------------------
718     // dot functions
719     // -------------------------------------------------------
720     template <typename T>
721     inline T dot(const vec_t<T, 2> &a, const vec_t<T, 2> &b)
722     {
723       return a.x * b.x + a.y * b.y;
724     }
725     template <typename T>
726     inline T dot(const vec_t<T, 3> &a, const vec_t<T, 3> &b)
727     {
728       return a.x * b.x + a.y * b.y + a.z * b.z;
729     }
730     template <typename T>
731     inline T dot(const vec_t<T, 3, 1> &a, const vec_t<T, 3, 1> &b)
732     {
733       return a.x * b.x + a.y * b.y + a.z * b.z;
734     }
735     template <typename T>
736     inline T dot(const vec_t<T, 3> &a, const vec_t<T, 3, 1> &b)
737     {
738       return a.x * b.x + a.y * b.y + a.z * b.z;
739     }
740     template <typename T>
741     inline T dot(const vec_t<T, 3, 1> &a, const vec_t<T, 3> &b)
742     {
743       return a.x * b.x + a.y * b.y + a.z * b.z;
744     }
745     template <typename T>
746     inline T dot(const vec_t<T, 4> &a, const vec_t<T, 4> &b)
747     {
748       return a.x * b.x + a.y * b.y + a.z * b.z + a.w * b.w;
749     }
750 
751     // -------------------------------------------------------
752     // length functions
753     // -------------------------------------------------------
754     template <typename T, int N, bool A>
755     inline T length(const vec_t<T, N, A> &v)
756     {
757       return sqrt(dot(v, v));
758     }
759 
760     // -------------------------------------------------------
761     // cross product
762     // -------------------------------------------------------
763     template <typename T, bool A, bool B>
764     inline vec_t<T, 3> cross(const vec_t<T, 3, A> &a, const vec_t<T, 3, B> &b)
765     {
766       return vec_t<T, 3>(
767           a.y * b.z - a.z * b.y, a.z * b.x - a.x * b.z, a.x * b.y - a.y * b.x);
768     }
769 
770     // -------------------------------------------------------
771     // normalize()
772     // -------------------------------------------------------
773     template <typename T, int N, bool A>
774     inline vec_t<T, N, A> normalize(const vec_t<T, N, A> &v)
775     {
776       return v * rsqrt(dot(v, v));
777     }
778 
779     template <typename T, int N, bool A>
780     inline vec_t<T, N, A> safe_normalize(const vec_t<T, N, A> &v)
781     {
782       return v * rsqrt(max(T(1e-6), dot(v, v)));
783     }
784 
785     // -------------------------------------------------------
786     // interpolation
787     // -------------------------------------------------------
788 
789     // barycentric interpolation
790     template <typename T, int N, bool A>
791     inline vec_t<T, N, A> interpolate_uv(const vec_t<T, 3> &f,
792                                          const vec_t<T, N, A> &a,
793                                          const vec_t<T, N, A> &b,
794                                          const vec_t<T, N, A> &c)
795     {
796       return f.x * a + f.y * b + f.z * c;
797     }
798 
799     // -------------------------------------------------------
800     // ostream operators
801     // -------------------------------------------------------
802     template <typename T>
803     inline std::ostream &operator<<(std::ostream &o, const vec_t<T, 2> &v)
804     {
805       o << "(" << v.x << "," << v.y << ")";
806       return o;
807     }
808     template <typename T, bool A>
809     inline std::ostream &operator<<(std::ostream &o, const vec_t<T, 3, A> &v)
810     {
811       o << "(" << v.x << "," << v.y << "," << v.z << ")";
812       return o;
813     }
814     template <typename T>
815     inline std::ostream &operator<<(std::ostream &o, const vec_t<T, 4> &v)
816     {
817       o << "(" << v.x << "," << v.y << "," << v.z << "," << v.w << ")";
818       return o;
819     }
820 
821     // "inherit" std::min/max/etc for basic types
822     using std::max;
823     using std::min;
824 
825 // -------------------------------------------------------
826 // binary functors
827 // -------------------------------------------------------
828 #define define_functor(f)                                                   \
829   template <typename T>                                                     \
830   inline vec_t<T, 2> f(const vec_t<T, 2> &a, const vec_t<T, 2> &b)          \
831   {                                                                         \
832     return vec_t<T, 2>(f(a.x, b.x), f(a.y, b.y));                           \
833   }                                                                         \
834                                                                             \
835   template <typename T, bool A>                                             \
836   inline vec_t<T, 3, A> f(const vec_t<T, 3, A> &a, const vec_t<T, 3, A> &b) \
837   {                                                                         \
838     return vec_t<T, 3, A>(f(a.x, b.x), f(a.y, b.y), f(a.z, b.z));           \
839   }                                                                         \
840                                                                             \
841   template <typename T>                                                     \
842   inline vec_t<T, 4> f(const vec_t<T, 4> &a, const vec_t<T, 4> &b)          \
843   {                                                                         \
844     return vec_t<T, 4>(f(a.x, b.x), f(a.y, b.y), f(a.z, b.z), f(a.w, b.w)); \
845   }
846 
847     // clang-format off
848     define_functor(min)
849     define_functor(max)
850     define_functor(divRoundUp)
851     // clang-format on
852 #undef define_functor
853 
854         // -------------------------------------------------------
855         // reductions
856         // -------------------------------------------------------
857         template <typename T, bool A>
858         inline T reduce_add(const vec_t<T, 2, A> &v)
859     {
860       return v.x + v.y;
861     }
862     template <typename T, bool A>
863     inline T reduce_add(const vec_t<T, 3, A> &v)
864     {
865       return v.x + v.y + v.z;
866     }
867     template <typename T, bool A>
868     inline T reduce_add(const vec_t<T, 4, A> &v)
869     {
870       return v.x + v.y + v.z + v.w;
871     }
872 
873     template <typename T, bool A>
874     inline T reduce_mul(const vec_t<T, 2, A> &v)
875     {
876       return v.x * v.y;
877     }
878     template <typename T, bool A>
879     inline T reduce_mul(const vec_t<T, 3, A> &v)
880     {
881       return v.x * v.y * v.z;
882     }
883     template <typename T, bool A>
884     inline T reduce_mul(const vec_t<T, 4, A> &v)
885     {
886       return v.x * v.y * v.z * v.w;
887     }
888 
889     template <typename T, bool A>
890     inline T reduce_min(const vec_t<T, 2, A> &v)
891     {
892       return min(v.x, v.y);
893     }
894     template <typename T, bool A>
895     inline T reduce_min(const vec_t<T, 3, A> &v)
896     {
897       return min(min(v.x, v.y), v.z);
898     }
899     template <typename T, bool A>
900     inline T reduce_min(const vec_t<T, 4, A> &v)
901     {
902       return min(min(v.x, v.y), min(v.z, v.w));
903     }
904 
905     template <typename T, bool A>
906     inline T reduce_max(const vec_t<T, 2, A> &v)
907     {
908       return max(v.x, v.y);
909     }
910     template <typename T, bool A>
911     inline T reduce_max(const vec_t<T, 3, A> &v)
912     {
913       return max(max(v.x, v.y), v.z);
914     }
915     template <typename T, bool A>
916     inline T reduce_max(const vec_t<T, 4, A> &v)
917     {
918       return max(max(v.x, v.y), max(v.z, v.w));
919     }
920 
921     // -------------------------------------------------------
922     // all vec2 variants
923     // -------------------------------------------------------
924     typedef vec_t<uint8_t, 2> vec2uc;
925     typedef vec_t<int8_t, 2> vec2c;
926     typedef vec_t<uint16_t, 2> vec2us;
927     typedef vec_t<int16_t, 2> vec2s;
928     typedef vec_t<uint32_t, 2> vec2ui;
929     typedef vec_t<int32_t, 2> vec2i;
930     typedef vec_t<uint64_t, 2> vec2ul;
931     typedef vec_t<int64_t, 2> vec2l;
932     typedef vec_t<float, 2> vec2f;
933     typedef vec_t<double, 2> vec2d;
934 
935     // -------------------------------------------------------
936     // all vec3 variants
937     // -------------------------------------------------------
938     typedef vec_t<uint8_t, 3> vec3uc;
939     typedef vec_t<int8_t, 3> vec3c;
940     typedef vec_t<uint16_t, 3> vec3us;
941     typedef vec_t<int16_t, 3> vec3s;
942     typedef vec_t<uint32_t, 3> vec3ui;
943     typedef vec_t<int32_t, 3> vec3i;
944     typedef vec_t<uint64_t, 3> vec3ul;
945     typedef vec_t<int64_t, 3> vec3l;
946     typedef vec_t<float, 3> vec3f;
947     typedef vec_t<double, 3> vec3d;
948 
949     typedef vec_t<float, 3, 1> vec3fa;
950     typedef vec_t<int, 3, 1> vec3ia;
951 
952     // -------------------------------------------------------
953     // all vec4 variants
954     // -------------------------------------------------------
955     typedef vec_t<uint8_t, 4> vec4uc;
956     typedef vec_t<int8_t, 4> vec4c;
957     typedef vec_t<uint16_t, 4> vec4us;
958     typedef vec_t<int16_t, 4> vec4s;
959     typedef vec_t<uint32_t, 4> vec4ui;
960     typedef vec_t<int32_t, 4> vec4i;
961     typedef vec_t<uint64_t, 4> vec4ul;
962     typedef vec_t<int64_t, 4> vec4l;
963     typedef vec_t<float, 4> vec4f;
964     typedef vec_t<double, 4> vec4d;
965 
966     template <typename T, int N>
967     inline size_t arg_max(const vec_t<T, N> &v)
968     {
969       size_t maxIdx = 0;
970       for (size_t i = 1; i < N; i++)
971         if (v[i] > v[maxIdx])
972           maxIdx = i;
973       return maxIdx;
974     }
975 
976   }  // namespace math
977 }  // namespace rkcommon
978 
979 /*! template specialization for std::less comparison operator;
980  *  we need those to be able to put vec's in std::map etc @{ */
981 /* Defining just operator< is prone to bugs, because a definition of an
982  * ordering of vectors is a bit arbitrary and depends on the context.
983  * For example, in box::extend we certainly want the element-wise min/max and
984  * not the std::min/std::max made applicable by vec3f::operator<.
985  */
986 namespace std {
987   template <typename T>
988   struct less<rkcommon::math::vec_t<T, 2>>
989   {
990     inline bool operator()(const rkcommon::math::vec_t<T, 2> &a,
991                            const rkcommon::math::vec_t<T, 2> &b) const
992     {
993       return (a.x < b.x) || ((a.x == b.x) && (a.y < b.y));
994     }
995   };
996 
997   template <typename T, bool A>
998   struct less<rkcommon::math::vec_t<T, 3, A>>
999   {
1000     inline bool operator()(const rkcommon::math::vec_t<T, 3, A> &a,
1001                            const rkcommon::math::vec_t<T, 3, A> &b) const
1002     {
1003       return (a.x < b.x) ||
1004              ((a.x == b.x) && ((a.y < b.y) || ((a.y == b.y) && (a.z < b.z))));
1005     }
1006   };
1007 
1008   template <typename T>
1009   struct less<rkcommon::math::vec_t<T, 4>>
1010   {
1011     inline bool operator()(const rkcommon::math::vec_t<T, 4> &a,
1012                            const rkcommon::math::vec_t<T, 4> &b) const
1013     {
1014       return (a.x < b.x) ||
1015              ((a.x == b.x) &&
1016               ((a.y < b.y) ||
1017                ((a.y == b.y) &&
1018                 ((a.z < b.z) || ((a.z == b.z) && (a.w < b.w))))));
1019     }
1020   };
1021 
1022 }  // namespace std
1023