1 /*
2  * Copyright 2013 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #ifndef TNT_MATH_TVECHELPERS_H
18 #define TNT_MATH_TVECHELPERS_H
19 
20 #include "compiler.h"
21 
22 #include <cmath>            // for std:: namespace
23 #include <cstdint>
24 
25 #include <sys/types.h>
26 
27 namespace filament {
28 namespace math {
29 namespace details {
30 // -------------------------------------------------------------------------------------
31 
32 template<typename U>
min(U a,U b)33 inline constexpr U min(U a, U b) noexcept {
34     return a < b ? a : b;
35 }
36 
37 template<typename U>
max(U a,U b)38 inline constexpr U max(U a, U b) noexcept {
39     return a > b ? a : b;
40 }
41 
42 template<typename T, typename U>
43 struct arithmetic_result {
44     using type = decltype(std::declval<T>() + std::declval<U>());
45 };
46 
47 template<typename T, typename U>
48 using arithmetic_result_t = typename arithmetic_result<T, U>::type;
49 
50 template<typename A, typename B = int, typename C = int, typename D = int>
51 using enable_if_arithmetic_t = std::enable_if_t<
52         is_arithmetic<A>::value &&
53         is_arithmetic<B>::value &&
54         is_arithmetic<C>::value &&
55         is_arithmetic<D>::value>;
56 
57 /*
58  * No user serviceable parts here.
59  *
60  * Don't use this file directly, instead include math/vec{2|3|4}.h
61  */
62 
63 /*
64  * TVec{Add|Product}Operators implements basic arithmetic and basic compound assignments
65  * operators on a vector of type BASE<T>.
66  *
67  * BASE only needs to implement operator[] and size().
68  * By simply inheriting from TVec{Add|Product}Operators<BASE, T> BASE will automatically
69  * get all the functionality here.
70  */
71 
72 template<template<typename T> class VECTOR, typename T>
73 class TVecAddOperators {
74 public:
75     /* compound assignment from a another vector of the same size but different
76      * element type.
77      */
78     template<typename U>
79     constexpr VECTOR<T>& operator+=(const VECTOR<U>& v) {
80         VECTOR<T>& lhs = static_cast<VECTOR<T>&>(*this);
81         for (size_t i = 0; i < lhs.size(); i++) {
82             lhs[i] += v[i];
83         }
84         return lhs;
85     }
86 
87     template<typename U, typename = enable_if_arithmetic_t<U>>
88     constexpr VECTOR<T>& operator+=(U v) {
89         return operator+=(VECTOR<U>(v));
90     }
91 
92     template<typename U>
93     constexpr VECTOR<T>& operator-=(const VECTOR<U>& v) {
94         VECTOR<T>& lhs = static_cast<VECTOR<T>&>(*this);
95         for (size_t i = 0; i < lhs.size(); i++) {
96             lhs[i] -= v[i];
97         }
98         return lhs;
99     }
100 
101     template<typename U, typename = enable_if_arithmetic_t<U>>
102     constexpr VECTOR<T>& operator-=(U v) {
103         return operator-=(VECTOR<U>(v));
104     }
105 
106 private:
107     /*
108      * NOTE: the functions below ARE NOT member methods. They are friend functions
109      * with they definition inlined with their declaration. This makes these
110      * template functions available to the compiler when (and only when) this class
111      * is instantiated, at which point they're only templated on the 2nd parameter
112      * (the first one, BASE<T> being known).
113      */
114 
115     template<typename U>
116     friend inline constexpr
117     VECTOR<arithmetic_result_t<T, U>> MATH_PURE operator+(const VECTOR<T>& lv, const VECTOR<U>& rv)
118     {
119         VECTOR<arithmetic_result_t<T, U>> res(lv);
120         res += rv;
121         return res;
122     }
123 
124     template<typename U, typename = enable_if_arithmetic_t<U>>
125     friend inline constexpr
126     VECTOR<arithmetic_result_t<T, U>> MATH_PURE operator+(const VECTOR<T>& lv, U rv) {
127         return lv + VECTOR<U>(rv);
128     }
129 
130     template<typename U, typename = enable_if_arithmetic_t<U>>
131     friend inline constexpr
132     VECTOR<arithmetic_result_t<T, U>> MATH_PURE operator+(U lv, const VECTOR<T>& rv) {
133         return VECTOR<U>(lv) + rv;
134     }
135 
136     template<typename U>
137     friend inline constexpr
138     VECTOR<arithmetic_result_t<T, U>> MATH_PURE operator-(const VECTOR<T>& lv, const VECTOR<U>& rv)
139     {
140         VECTOR<arithmetic_result_t<T, U>> res(lv);
141         res -= rv;
142         return res;
143     }
144 
145     template<typename U, typename = enable_if_arithmetic_t<U>>
146     friend inline constexpr
147     VECTOR<arithmetic_result_t<T, U>> MATH_PURE operator-(const VECTOR<T>& lv, U rv) {
148         return lv - VECTOR<U>(rv);
149     }
150 
151     template<typename U, typename = enable_if_arithmetic_t<U>>
152     friend inline constexpr
153     VECTOR<arithmetic_result_t<T, U>> MATH_PURE operator-(U lv, const VECTOR<T>& rv) {
154         return VECTOR<U>(lv) - rv;
155     }
156 };
157 
158 template<template<typename T> class VECTOR, typename T>
159 class TVecProductOperators {
160 public:
161     /* compound assignment from a another vector of the same size but different
162      * element type.
163      */
164     template<typename U>
165     constexpr VECTOR<T>& operator*=(const VECTOR<U>& v) {
166         VECTOR<T>& lhs = static_cast<VECTOR<T>&>(*this);
167         for (size_t i = 0; i < lhs.size(); i++) {
168             lhs[i] *= v[i];
169         }
170         return lhs;
171     }
172 
173     template<typename U, typename = enable_if_arithmetic_t<U>>
174     constexpr VECTOR<T>& operator*=(U v) {
175         return operator*=(VECTOR<U>(v));
176     }
177 
178     template<typename U>
179     constexpr VECTOR<T>& operator/=(const VECTOR<U>& v) {
180         VECTOR<T>& lhs = static_cast<VECTOR<T>&>(*this);
181         for (size_t i = 0; i < lhs.size(); i++) {
182             lhs[i] /= v[i];
183         }
184         return lhs;
185     }
186 
187     template<typename U, typename = enable_if_arithmetic_t<U>>
188     constexpr VECTOR<T>& operator/=(U v) {
189         return operator/=(VECTOR<U>(v));
190     }
191 
192 private:
193     /*
194      * NOTE: the functions below ARE NOT member methods. They are friend functions
195      * with they definition inlined with their declaration. This makes these
196      * template functions available to the compiler when (and only when) this class
197      * is instantiated, at which point they're only templated on the 2nd parameter
198      * (the first one, BASE<T> being known).
199      */
200 
201     template<typename U>
202     friend inline constexpr
203     VECTOR<arithmetic_result_t<T, U>> MATH_PURE operator*(const VECTOR<T>& lv, const VECTOR<U>& rv)
204     {
205         VECTOR<arithmetic_result_t<T, U>> res(lv);
206         res *= rv;
207         return res;
208     }
209 
210     template<typename U, typename = enable_if_arithmetic_t<U>>
211     friend inline constexpr
212     VECTOR<arithmetic_result_t<T, U>> MATH_PURE operator*(const VECTOR<T>& lv, U rv) {
213         return lv * VECTOR<U>(rv);
214     }
215 
216     template<typename U, typename = enable_if_arithmetic_t<U>>
217     friend inline constexpr
218     VECTOR<arithmetic_result_t<T, U>> MATH_PURE operator*(U lv, const VECTOR<T>& rv) {
219         return VECTOR<U>(lv) * rv;
220     }
221 
222     template<typename U>
223     friend inline constexpr
224     VECTOR<arithmetic_result_t<T, U>> MATH_PURE operator/(const VECTOR<T>& lv, const VECTOR<U>& rv)
225     {
226         VECTOR<arithmetic_result_t<T, U>> res(lv);
227         res /= rv;
228         return res;
229     }
230 
231     template<typename U, typename = enable_if_arithmetic_t<U>>
232     friend inline constexpr
233     VECTOR<arithmetic_result_t<T, U>> MATH_PURE operator/(const VECTOR<T>& lv, U rv) {
234         return lv / VECTOR<U>(rv);
235     }
236 
237     template<typename U, typename = enable_if_arithmetic_t<U>>
238     friend inline constexpr
239     VECTOR<arithmetic_result_t<T, U>> MATH_PURE operator/(U lv, const VECTOR<T>& rv) {
240         return VECTOR<U>(lv) / rv;
241     }
242 };
243 
244 /*
245  * TVecUnaryOperators implements unary operators on a vector of type BASE<T>.
246  *
247  * BASE only needs to implement operator[] and size().
248  * By simply inheriting from TVecUnaryOperators<BASE, T> BASE will automatically
249  * get all the functionality here.
250  *
251  * These operators are implemented as friend functions of TVecUnaryOperators<BASE, T>
252  */
253 template<template<typename T> class VECTOR, typename T>
254 class TVecUnaryOperators {
255 public:
256     constexpr VECTOR<T> operator-() const {
257         VECTOR<T> r{};
258         VECTOR<T> const& rv(static_cast<VECTOR<T> const&>(*this));
259         for (size_t i = 0; i < r.size(); i++) {
260             r[i] = -rv[i];
261         }
262         return r;
263     }
264 };
265 
266 /*
267  * TVecComparisonOperators implements relational/comparison operators
268  * on a vector of type BASE<T>.
269  *
270  * BASE only needs to implement operator[] and size().
271  * By simply inheriting from TVecComparisonOperators<BASE, T> BASE will automatically
272  * get all the functionality here.
273  */
274 template<template<typename T> class VECTOR, typename T>
275 class TVecComparisonOperators {
276 private:
277     /*
278      * NOTE: the functions below ARE NOT member methods. They are friend functions
279      * with they definition inlined with their declaration. This makes these
280      * template functions available to the compiler when (and only when) this class
281      * is instantiated, at which point they're only templated on the 2nd parameter
282      * (the first one, BASE<T> being known).
283      */
284     template<typename U>
285     friend inline constexpr
286     bool MATH_PURE operator==(const VECTOR<T>& lv, const VECTOR<U>& rv) {
287         // w/ inlining we end-up with many branches that will pollute the BPU cache
288         MATH_NOUNROLL
289         for (size_t i = 0; i < lv.size(); i++) {
290             if (lv[i] != rv[i]) {
291                 return false;
292             }
293         }
294         return true;
295     }
296 
297     template<typename U>
298     friend inline constexpr
299     bool MATH_PURE operator!=(const VECTOR<T>& lv, const VECTOR<U>& rv) {
300         return !operator==(lv, rv);
301     }
302 
303     template<typename U>
304     friend inline constexpr
equal(const VECTOR<T> & lv,const VECTOR<U> & rv)305     VECTOR<bool> MATH_PURE equal(const VECTOR<T>& lv, const VECTOR<U>& rv) {
306         VECTOR<bool> r{};
307         for (size_t i = 0; i < lv.size(); i++) {
308             r[i] = lv[i] == rv[i];
309         }
310         return r;
311     }
312 
313     template<typename U>
314     friend inline constexpr
notEqual(const VECTOR<T> & lv,const VECTOR<U> & rv)315     VECTOR<bool> MATH_PURE notEqual(const VECTOR<T>& lv, const VECTOR<U>& rv) {
316         VECTOR<bool> r{};
317         for (size_t i = 0; i < lv.size(); i++) {
318             r[i] = lv[i] != rv[i];
319         }
320         return r;
321     }
322 
323     template<typename U>
324     friend inline constexpr
lessThan(const VECTOR<T> & lv,const VECTOR<U> & rv)325     VECTOR<bool> MATH_PURE lessThan(const VECTOR<T>& lv, const VECTOR<U>& rv) {
326         VECTOR<bool> r{};
327         for (size_t i = 0; i < lv.size(); i++) {
328             r[i] = lv[i] < rv[i];
329         }
330         return r;
331     }
332 
333     template<typename U>
334     friend inline constexpr
lessThanEqual(const VECTOR<T> & lv,const VECTOR<U> & rv)335     VECTOR<bool> MATH_PURE lessThanEqual(const VECTOR<T>& lv, const VECTOR<U>& rv) {
336         VECTOR<bool> r{};
337         for (size_t i = 0; i < lv.size(); i++) {
338             r[i] = lv[i] <= rv[i];
339         }
340         return r;
341     }
342 
343     template<typename U>
344     friend inline constexpr
greaterThan(const VECTOR<T> & lv,const VECTOR<U> & rv)345     VECTOR<bool> MATH_PURE greaterThan(const VECTOR<T>& lv, const VECTOR<U>& rv) {
346         VECTOR<bool> r;
347         for (size_t i = 0; i < lv.size(); i++) {
348             r[i] = lv[i] > rv[i];
349         }
350         return r;
351     }
352 
353     template<typename U>
354     friend inline
greaterThanEqual(const VECTOR<T> & lv,const VECTOR<U> & rv)355     VECTOR<bool> MATH_PURE greaterThanEqual(const VECTOR<T>& lv, const VECTOR<U>& rv) {
356         VECTOR<bool> r{};
357         for (size_t i = 0; i < lv.size(); i++) {
358             r[i] = lv[i] >= rv[i];
359         }
360         return r;
361     }
362 };
363 
364 /*
365  * TVecFunctions implements functions on a vector of type BASE<T>.
366  *
367  * BASE only needs to implement operator[] and size().
368  * By simply inheriting from TVecFunctions<BASE, T> BASE will automatically
369  * get all the functionality here.
370  */
371 template<template<typename T> class VECTOR, typename T>
372 class TVecFunctions {
373 private:
374     /*
375      * NOTE: the functions below ARE NOT member methods. They are friend functions
376      * with they definition inlined with their declaration. This makes these
377      * template functions available to the compiler when (and only when) this class
378      * is instantiated, at which point they're only templated on the 2nd parameter
379      * (the first one, BASE<T> being known).
380      */
381     template<typename U>
382     friend constexpr inline
dot(const VECTOR<T> & lv,const VECTOR<U> & rv)383     arithmetic_result_t<T, U> MATH_PURE dot(const VECTOR<T>& lv, const VECTOR<U>& rv) {
384         arithmetic_result_t<T, U> r{};
385         for (size_t i = 0; i < lv.size(); i++) {
386             r += lv[i] * rv[i];
387         }
388         return r;
389     }
390 
norm(const VECTOR<T> & lv)391     friend inline T MATH_PURE norm(const VECTOR<T>& lv) {
392         return std::sqrt(dot(lv, lv));
393     }
394 
length(const VECTOR<T> & lv)395     friend inline T MATH_PURE length(const VECTOR<T>& lv) {
396         return norm(lv);
397     }
398 
norm2(const VECTOR<T> & lv)399     friend inline constexpr T MATH_PURE norm2(const VECTOR<T>& lv) {
400         return dot(lv, lv);
401     }
402 
length2(const VECTOR<T> & lv)403     friend inline constexpr T MATH_PURE length2(const VECTOR<T>& lv) {
404         return norm2(lv);
405     }
406 
407     template<typename U>
408     friend inline constexpr
distance(const VECTOR<T> & lv,const VECTOR<U> & rv)409     arithmetic_result_t<T, U> MATH_PURE distance(const VECTOR<T>& lv, const VECTOR<U>& rv) {
410         return length(rv - lv);
411     }
412 
413     template<typename U>
414     friend inline constexpr
distance2(const VECTOR<T> & lv,const VECTOR<U> & rv)415     arithmetic_result_t<T, U> MATH_PURE distance2(const VECTOR<T>& lv, const VECTOR<U>& rv) {
416         return length2(rv - lv);
417     }
418 
normalize(const VECTOR<T> & lv)419     friend inline VECTOR<T> MATH_PURE normalize(const VECTOR<T>& lv) {
420         return lv * (T(1) / length(lv));
421     }
422 
rcp(VECTOR<T> v)423     friend inline VECTOR<T> MATH_PURE rcp(VECTOR<T> v) {
424         return T(1) / v;
425     }
426 
abs(VECTOR<T> v)427     friend inline constexpr VECTOR<T> MATH_PURE abs(VECTOR<T> v) {
428         for (size_t i = 0; i < v.size(); i++) {
429             v[i] = v[i] < 0 ? -v[i] : v[i];
430         }
431         return v;
432     }
433 
floor(VECTOR<T> v)434     friend inline VECTOR<T> MATH_PURE floor(VECTOR<T> v) {
435         for (size_t i = 0; i < v.size(); i++) {
436             v[i] = std::floor(v[i]);
437         }
438         return v;
439     }
440 
ceil(VECTOR<T> v)441     friend inline VECTOR<T> MATH_PURE ceil(VECTOR<T> v) {
442         for (size_t i = 0; i < v.size(); i++) {
443             v[i] = std::ceil(v[i]);
444         }
445         return v;
446     }
447 
round(VECTOR<T> v)448     friend inline VECTOR<T> MATH_PURE round(VECTOR<T> v) {
449         for (size_t i = 0; i < v.size(); i++) {
450             v[i] = std::round(v[i]);
451         }
452         return v;
453     }
454 
inversesqrt(VECTOR<T> v)455     friend inline VECTOR<T> MATH_PURE inversesqrt(VECTOR<T> v) {
456         for (size_t i = 0; i < v.size(); i++) {
457             v[i] = T(1) / std::sqrt(v[i]);
458         }
459         return v;
460     }
461 
sqrt(VECTOR<T> v)462     friend inline VECTOR<T> MATH_PURE sqrt(VECTOR<T> v) {
463         for (size_t i = 0; i < v.size(); i++) {
464             v[i] = std::sqrt(v[i]);
465         }
466         return v;
467     }
468 
cbrt(VECTOR<T> v)469     friend inline VECTOR<T> MATH_PURE cbrt(VECTOR<T> v) {
470         for (size_t i = 0; i < v.size(); i++) {
471             v[i] = std::cbrt(v[i]);
472         }
473         return v;
474     }
475 
exp(VECTOR<T> v)476     friend inline VECTOR<T> MATH_PURE exp(VECTOR<T> v) {
477         for (size_t i = 0; i < v.size(); i++) {
478             v[i] = std::exp(v[i]);
479         }
480         return v;
481     }
482 
pow(VECTOR<T> v,T p)483     friend inline VECTOR<T> MATH_PURE pow(VECTOR<T> v, T p) {
484         for (size_t i = 0; i < v.size(); i++) {
485             v[i] = std::pow(v[i], p);
486         }
487         return v;
488     }
489 
pow(T v,VECTOR<T> p)490     friend inline VECTOR<T> MATH_PURE pow(T v, VECTOR<T> p) {
491         for (size_t i = 0; i < p.size(); i++) {
492             p[i] = std::pow(v, p[i]);
493         }
494         return p;
495     }
496 
pow(VECTOR<T> v,VECTOR<T> p)497     friend inline VECTOR<T> MATH_PURE pow(VECTOR<T> v, VECTOR<T> p) {
498         for (size_t i = 0; i < v.size(); i++) {
499             v[i] = std::pow(v[i], p[i]);
500         }
501         return v;
502     }
503 
log(VECTOR<T> v)504     friend inline VECTOR<T> MATH_PURE log(VECTOR<T> v) {
505         for (size_t i = 0; i < v.size(); i++) {
506             v[i] = std::log(v[i]);
507         }
508         return v;
509     }
510 
log10(VECTOR<T> v)511     friend inline VECTOR<T> MATH_PURE log10(VECTOR<T> v) {
512         for (size_t i = 0; i < v.size(); i++) {
513             v[i] = std::log10(v[i]);
514         }
515         return v;
516     }
517 
log2(VECTOR<T> v)518     friend inline VECTOR<T> MATH_PURE log2(VECTOR<T> v) {
519         for (size_t i = 0; i < v.size(); i++) {
520             v[i] = std::log2(v[i]);
521         }
522         return v;
523     }
524 
saturate(const VECTOR<T> & lv)525     friend inline constexpr VECTOR<T> MATH_PURE saturate(const VECTOR<T>& lv) {
526         return clamp(lv, T(0), T(1));
527     }
528 
clamp(VECTOR<T> v,T min,T max)529     friend inline constexpr VECTOR<T> MATH_PURE clamp(VECTOR<T> v, T min, T max) {
530         for (size_t i = 0; i < v.size(); i++) {
531             v[i] = details::min(max, details::max(min, v[i]));
532         }
533         return v;
534     }
535 
clamp(VECTOR<T> v,VECTOR<T> min,VECTOR<T> max)536     friend inline constexpr VECTOR<T> MATH_PURE clamp(VECTOR<T> v, VECTOR<T> min, VECTOR<T> max) {
537         for (size_t i = 0; i < v.size(); i++) {
538             v[i] = details::min(max[i], details::max(min[i], v[i]));
539         }
540         return v;
541     }
542 
fma(const VECTOR<T> & lv,const VECTOR<T> & rv,VECTOR<T> a)543     friend inline constexpr VECTOR<T> MATH_PURE fma(const VECTOR<T>& lv, const VECTOR<T>& rv,
544             VECTOR<T> a) {
545         for (size_t i = 0; i < lv.size(); i++) {
546             a[i] += (lv[i] * rv[i]);
547         }
548         return a;
549     }
550 
min(const VECTOR<T> & u,VECTOR<T> v)551     friend inline constexpr VECTOR<T> MATH_PURE min(const VECTOR<T>& u, VECTOR<T> v) {
552         for (size_t i = 0; i < v.size(); i++) {
553             v[i] = details::min(u[i], v[i]);
554         }
555         return v;
556     }
557 
max(const VECTOR<T> & u,VECTOR<T> v)558     friend inline constexpr VECTOR<T> MATH_PURE max(const VECTOR<T>& u, VECTOR<T> v) {
559         for (size_t i = 0; i < v.size(); i++) {
560             v[i] = details::max(u[i], v[i]);
561         }
562         return v;
563     }
564 
max(const VECTOR<T> & v)565     friend inline constexpr T MATH_PURE max(const VECTOR<T>& v) {
566         T r(v[0]);
567         for (size_t i = 1; i < v.size(); i++) {
568             r = max(r, v[i]);
569         }
570         return r;
571     }
572 
min(const VECTOR<T> & v)573     friend inline constexpr T MATH_PURE min(const VECTOR<T>& v) {
574         T r(v[0]);
575         for (size_t i = 1; i < v.size(); i++) {
576             r = min(r, v[i]);
577         }
578         return r;
579     }
580 
mix(const VECTOR<T> & u,VECTOR<T> v,T a)581     friend inline constexpr VECTOR<T> MATH_PURE mix(const VECTOR<T>& u, VECTOR<T> v, T a) {
582         for (size_t i = 0; i < v.size(); i++) {
583             v[i] = u[i] * (T(1) - a) + v[i] * a;
584         }
585         return v;
586     }
587 
smoothstep(T edge0,T edge1,VECTOR<T> v)588     friend inline constexpr VECTOR<T> MATH_PURE smoothstep(T edge0, T edge1, VECTOR<T> v) {
589         VECTOR<T> t = saturate((v - edge0) / (edge1 - edge0));
590         return t * t * (T(3) - T(2) * t);
591     }
592 
step(T edge,VECTOR<T> v)593     friend inline constexpr VECTOR<T> MATH_PURE step(T edge, VECTOR<T> v) {
594         for (size_t i = 0; i < v.size(); i++) {
595             v[i] = v[i] < edge ? T(0) : T(1);
596         }
597         return v;
598     }
599 
step(VECTOR<T> edge,VECTOR<T> v)600     friend inline constexpr VECTOR<T> MATH_PURE step(VECTOR<T> edge, VECTOR<T> v) {
601         for (size_t i = 0; i < v.size(); i++) {
602             v[i] = v[i] < edge[i] ? T(0) : T(1);
603         }
604         return v;
605     }
606 
any(const VECTOR<T> & v)607     friend inline constexpr bool MATH_PURE any(const VECTOR<T>& v) {
608         for (size_t i = 0; i < v.size(); i++) {
609             if (v[i] != T(0)) return true;
610         }
611         return false;
612     }
613 
all(const VECTOR<T> & v)614     friend inline constexpr bool MATH_PURE all(const VECTOR<T>& v) {
615         bool result = true;
616         for (size_t i = 0; i < v.size(); i++) {
617             result &= (v[i] != T(0));
618         }
619         return result;
620     }
621 };
622 
623 // -------------------------------------------------------------------------------------
624 }  // namespace details
625 }  // namespace math
626 }  // namespace filament
627 
628 #endif  // TNT_MATH_TVECHELPERS_H
629