-
-
Notifications
You must be signed in to change notification settings - Fork 36
/
Copy pathegl_math.h
12516 lines (11300 loc) · 471 KB
/
egl_math.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
//============================================================================
// EmberGL
//
// Copyright (c) 2022, Jarkko Lempiainen
// All rights reserved.
//============================================================================
#ifndef EGL_MATH_H
#define EGL_MATH_H
//----------------------------------------------------------------------------
//============================================================================
// interface
//============================================================================
// external
#include "egl_core.h"
#ifdef ARDUINO
#include <math.h>
#define MATH_NAMESPACE
#else
#include <cmath>
#define MATH_NAMESPACE std
#endif
EGL_NAMESPACE_BEGIN
// new
#ifdef abs
#undef abs
#endif
template<typename> struct math; // math constants
template<typename> struct vec2; // 2d vector
template<typename> struct vec3; // 3d vector
template<typename> struct vec4; // 4d vector
template<typename> struct mat22; // 2x2 matrix
template<typename> struct mat33; // 3x3 matrix
template<typename> struct mat44; // 4x4 matrix
template<typename> struct quat; // quaternion
template<typename> struct complex; // complex number
struct vec32s_t;
struct vec32u_t;
typedef math<float> mathf;
typedef math<double> mathd;
typedef vec2<float> vec2f;
typedef vec2<double> vec2d;
typedef vec2<int> vec2i;
typedef vec2<unsigned> vec2u;
typedef vec2<int16_t> vec2i16;
typedef vec2<uint16_t> vec2u16;
typedef vec2<int32_t> vec2i32;
typedef vec2<uint32_t> vec2u32;
typedef vec3<float> vec3f;
typedef vec3<double> vec3d;
typedef vec3<int> vec3i;
typedef vec3<unsigned> vec3u;
typedef vec3<int16_t> vec3i16;
typedef vec3<uint16_t> vec3u16;
typedef vec3<int32_t> vec3i32;
typedef vec3<uint32_t> vec3u32;
typedef vec3<vec32s_t> vec3_32s;
typedef vec3<vec32u_t> vec3_32u;
typedef vec4<float> vec4f;
typedef vec4<double> vec4d;
typedef vec4<int> vec4i;
typedef vec4<unsigned> vec4u;
typedef vec4<int16_t> vec4i16;
typedef vec4<uint16_t> vec4u16;
typedef vec4<int32_t> vec4i32;
typedef vec4<uint32_t> vec4u32;
typedef vec4<vec32s_t> vec4_32s;
typedef vec4<vec32u_t> vec4_32u;
typedef mat22<float> mat22f;
typedef mat22<double> mat22d;
typedef mat22<int> mat22i;
typedef mat22<unsigned> mat22u;
typedef mat22<int16_t> mat22i16;
typedef mat22<uint16_t> mat22u16;
typedef mat22<int32_t> mat22i32;
typedef mat22<uint32_t> mat22u32;
typedef mat33<float> mat33f;
typedef mat33<double> mat33d;
typedef mat33<int> mat33i;
typedef mat33<unsigned> mat33u;
typedef mat33<int16_t> mat33i16;
typedef mat33<uint16_t> mat33u16;
typedef mat33<int32_t> mat33i32;
typedef mat33<uint32_t> mat33u32;
typedef mat44<float> mat44f;
typedef mat44<double> mat44d;
typedef mat44<int> mat44i;
typedef mat44<unsigned> mat44u;
typedef mat44<int16_t> mat44i16;
typedef mat44<uint16_t> mat44u16;
typedef mat44<int32_t> mat44i32;
typedef mat44<uint32_t> mat44u32;
typedef quat<float> quatf;
typedef quat<double> quatd;
typedef quat<int> quati;
typedef quat<unsigned> quatu;
typedef quat<int16_t> quati16;
typedef quat<uint16_t> quatu16;
typedef quat<int32_t> quati32;
typedef quat<uint32_t> quatu32;
typedef quat<vec32s_t> quat_32s;
typedef quat<vec32u_t> quat_32u;
typedef complex<float> complexf;
typedef complex<double> complexd;
typedef complex<int> complexi;
typedef complex<unsigned> complexu;
typedef complex<int16_t> complexi16;
typedef complex<uint16_t> complexu16;
typedef complex<int32_t> complexi32;
typedef complex<uint32_t> complexu32;
// traits
template<typename> struct is_type_vec {enum {res=false};};
template<typename> struct is_type_mat {enum {res=false};};
template<typename> struct is_type_quat {enum {res=false};};
template<typename> struct is_type_complex {enum {res=false};};
// macro to prefer egl free math functions in function scope, i.e. use EGL_NAMESPACE_PREFIX acos() instead of ::acos() when writing: float a=acos(b);
#define EGL_FUNC_PREFER_MATH_LIB\
EGL_USING_NAMESPACE\
using EGL_NAMESPACE_PREFIX mul; using EGL_NAMESPACE_PREFIX madd; using EGL_NAMESPACE_PREFIX rcp; using EGL_NAMESPACE_PREFIX rcp_z; using EGL_NAMESPACE_PREFIX floor; using EGL_NAMESPACE_PREFIX ceil; using EGL_NAMESPACE_PREFIX trunc; using EGL_NAMESPACE_PREFIX frc; using EGL_NAMESPACE_PREFIX mod;\
using EGL_NAMESPACE_PREFIX cycle; using EGL_NAMESPACE_PREFIX cycle1; using EGL_NAMESPACE_PREFIX sat; using EGL_NAMESPACE_PREFIX ssat; using EGL_NAMESPACE_PREFIX clamp; using EGL_NAMESPACE_PREFIX abs; using EGL_NAMESPACE_PREFIX sgn; using EGL_NAMESPACE_PREFIX sgn_zp; using EGL_NAMESPACE_PREFIX sqr; using EGL_NAMESPACE_PREFIX cubic;\
using EGL_NAMESPACE_PREFIX sqrt; using EGL_NAMESPACE_PREFIX sqrt_z; using EGL_NAMESPACE_PREFIX cbrt; using EGL_NAMESPACE_PREFIX rsqrt; using EGL_NAMESPACE_PREFIX rsqrt_z; using EGL_NAMESPACE_PREFIX rcbrt; using EGL_NAMESPACE_PREFIX rcbrt_z; using EGL_NAMESPACE_PREFIX norm;\
using EGL_NAMESPACE_PREFIX rnorm; using EGL_NAMESPACE_PREFIX rnorm_z; using EGL_NAMESPACE_PREFIX rnorm_z; using EGL_NAMESPACE_PREFIX norm2; using EGL_NAMESPACE_PREFIX rnorm2; using EGL_NAMESPACE_PREFIX rnorm2_z; using EGL_NAMESPACE_PREFIX norm_l1; using EGL_NAMESPACE_PREFIX rnorm_l1;\
using EGL_NAMESPACE_PREFIX rnorm_l1_z; using EGL_NAMESPACE_PREFIX exp; using EGL_NAMESPACE_PREFIX exp2; using EGL_NAMESPACE_PREFIX ln; using EGL_NAMESPACE_PREFIX log2; using EGL_NAMESPACE_PREFIX log10; using EGL_NAMESPACE_PREFIX pow; using EGL_NAMESPACE_PREFIX smoothstep; using EGL_NAMESPACE_PREFIX smootherstep; using EGL_NAMESPACE_PREFIX lerp; using EGL_NAMESPACE_PREFIX dot;\
using EGL_NAMESPACE_PREFIX sin; using EGL_NAMESPACE_PREFIX cos; using EGL_NAMESPACE_PREFIX sincos; using EGL_NAMESPACE_PREFIX tan; using EGL_NAMESPACE_PREFIX csc; using EGL_NAMESPACE_PREFIX sec; using EGL_NAMESPACE_PREFIX cot; using EGL_NAMESPACE_PREFIX asin; using EGL_NAMESPACE_PREFIX acos;\
using EGL_NAMESPACE_PREFIX atan; using EGL_NAMESPACE_PREFIX atan2; using EGL_NAMESPACE_PREFIX acsc; using EGL_NAMESPACE_PREFIX asec; using EGL_NAMESPACE_PREFIX acot; using EGL_NAMESPACE_PREFIX sinh; using EGL_NAMESPACE_PREFIX cosh; using EGL_NAMESPACE_PREFIX tanh; using EGL_NAMESPACE_PREFIX csch;\
using EGL_NAMESPACE_PREFIX sech; using EGL_NAMESPACE_PREFIX coth; using EGL_NAMESPACE_PREFIX asinh; using EGL_NAMESPACE_PREFIX acosh; using EGL_NAMESPACE_PREFIX atanh; using EGL_NAMESPACE_PREFIX acsch; using EGL_NAMESPACE_PREFIX asech; using EGL_NAMESPACE_PREFIX acoth;
// scalar functions
template<typename T> EGL_INLINE T mul(T a_, T b_); // a_*b_
template<typename T> EGL_INLINE T madd(T a_, T b_, T c_); // a_*b_+c_
template<typename T> EGL_INLINE T rcp(T); // reciprocal: 1/x
template<typename T> EGL_INLINE T rcp_z(T); // reciprocal: 1/x, if x=0 returns 0
template<typename T> EGL_INLINE T floor(T v_); // greatest integer less than or equal to the value
template<typename T> EGL_INLINE T ceil(T v_); // smallest integer greater than or equal to the value
template<typename T> EGL_INLINE T trunc(T v_); // truncate decimal part from the value
template<typename T> EGL_INLINE T frc(T v_); // fractional part (for negative values returns 1-fractional part)
template<typename T> EGL_INLINE T mod(T v_, T div_); // remainder of v_/div_
template<typename T> EGL_INLINE T cycle(T v_, T cycle_); // same as mod() except for negative result returns: cycle_+mod(v_, cycle_)
template<typename T> EGL_INLINE T cycle1(T v_); // same as frc() but for negative results returns: 1+frc(v_)
template<typename T> EGL_INLINE T sat(T); // saturate scalar to range [0, 1]
template<typename T> EGL_INLINE T ssat(T); // saturate scalar to range [-1, 1]
template<typename T> EGL_INLINE T clamp(T v_, T min_, T max_); // clamp scalar to range [min, max]
template<typename T> EGL_INLINE T abs(T); // absolute: |x|
template<typename T> EGL_INLINE T sgn(T); // signum (neg=-1, pos=+1, zero=0)
template<typename T> EGL_INLINE T sgn_zp(T); // signum (neg=-1, pos&zero=+1)
template<typename T> EGL_INLINE T sqr(T); // square: x*x
template<typename T> EGL_INLINE T cubic(T); // cubic: x*x*x
template<typename T> EGL_INLINE T sqrt(T); // square root
template<typename T> EGL_INLINE T sqrt_z(T); // square root (set to 0 if the value is less than zero)
template<typename T> EGL_INLINE T cbrt(T); // cubic root
template<typename T> EGL_INLINE T rsqrt(T); // reciprocal square root: 1/sqrt(x)
template<typename T> EGL_INLINE T rsqrt_z(T); // reciprocal square root: 1/sqrt(x). set to 0 if the value is less than or equal to zero
template<typename T> EGL_INLINE T rcbrt(T); // reciprocal cubic root: 1/cbrt(x)
template<typename T> EGL_INLINE T rcbrt_z(T); // reciprocal cubic root: 1/cbrt(x). set to 0 if the value is zero
template<typename T> EGL_INLINE T norm(T); // absolute: |x|
template<typename T> EGL_INLINE T rnorm(T); // absolute reciprocal: 1/|x|
template<typename T> EGL_INLINE T rnorm_z(T); // absolute reciprocal: 1/|x| (if x=0, returns 0)
template<typename T> EGL_INLINE T norm2(T); // square: x*x
template<typename T> EGL_INLINE T rnorm2(T); // square reciprocal: 1/(x*x)
template<typename T> EGL_INLINE T rnorm2_z(T); // square reciprocal: 1/(x*x) (if x=0, returns 0)
template<typename T> EGL_INLINE T norm_l1(T); // absolute: |x|
template<typename T> EGL_INLINE T rnorm_l1(T); // absolute reciprocal: 1/|x|
template<typename T> EGL_INLINE T rnorm_l1_z(T); // absolute reciprocal: 1/|x| (if x=0, returns 0)
template<typename T> EGL_INLINE T exp(T); // natural exponent: e^x
template<typename T> EGL_INLINE T exp2(T); // 2^x
template<typename T> EGL_INLINE T ln(T); // natural logarithm
template<typename T> EGL_INLINE T log2(T); // base-2 logarithm
template<typename T> EGL_INLINE T log10(T); // base-10 logarithm
template<typename T> EGL_INLINE T pow(T, T); // power
template<typename T> EGL_INLINE T smoothstep(T t_); // smoothstep function: t=[0, 1]
template<typename T> EGL_INLINE T smootherstep(T t_); // smootherstep function: t=[0, 1]
template<typename T> EGL_INLINE T lerp(T a_, T b_, T t_); // linear interpolation of scalars: f(t=0)=a_, f(t=1)=b_
template<typename T> EGL_INLINE T dot(T x_, T y_); // x_*y_
EGL_INLINE float32_t u16f_to_fp32(uint16_t u16f_); // convert unsigned 16-bit float to 32-bit float
EGL_INLINE float32_t s16f_to_fp32(uint16_t s16f_); // convert signed 16-bit float to 32-bit float
EGL_INLINE uint16_t fp32_to_u16f(float32_t v_); // convert 32-bit float to unsigned 16-bit float
EGL_INLINE uint16_t fp32_to_s16f(float32_t v_); // convert 32-bit float to signed 16-bit float
// trigonometric scalar functions
template<typename T> EGL_INLINE T sin(T); // sine
template<typename T> EGL_INLINE T cos(T); // cosine
template<typename T> EGL_INLINE void sincos(T &sin_, T &cos_, T); // sine & cosine
template<typename T> EGL_INLINE T tan(T); // tangent
template<typename T> EGL_INLINE T csc(T); // cosecant: 1/sin(x)
template<typename T> EGL_INLINE T sec(T); // secant: 1/cos(x)
template<typename T> EGL_INLINE T cot(T); // cotangent: 1/tan(x)
template<typename T> EGL_INLINE T asin(T); // arcus sine
template<typename T> EGL_INLINE T acos(T); // arcus cosine
template<typename T> EGL_INLINE T atan(T); // arcus tangent
template<typename T> EGL_INLINE T atan2(T y_, T x_); // arcus tangent
template<typename T> EGL_INLINE T acsc(T); // arcus cosecant
template<typename T> EGL_INLINE T asec(T); // arcus secant
template<typename T> EGL_INLINE T acot(T); // arcus cotangent
template<typename T> EGL_INLINE T sinh(T); // hyperbolic sine
template<typename T> EGL_INLINE T cosh(T); // hyperbolic cosine
template<typename T> EGL_INLINE T tanh(T); // hyperbolic tangent
template<typename T> EGL_INLINE T csch(T); // hyperbolic cosecant
template<typename T> EGL_INLINE T sech(T); // hyperbolic secant
template<typename T> EGL_INLINE T coth(T); // hyperbolic cotangent
template<typename T> EGL_INLINE T asinh(T); // arcus hyperbolic sine
template<typename T> EGL_INLINE T acosh(T); // arcus hyperbolic cosine
template<typename T> EGL_INLINE T atanh(T); // arcus hyperbolic tangent
template<typename T> EGL_INLINE T acsch(T); // arcus hyperbolic cosecant
template<typename T> EGL_INLINE T asech(T); // arcus hyperbolic secant
template<typename T> EGL_INLINE T acoth(T); // arcus hyperbolic cotangent
// 2d vector ops
template<typename T> EGL_INLINE bool is_zero(const vec2<T>&); // test for zero-vector, i.e. all components equal zero (exact)
template<typename T> EGL_INLINE bool is_sat(const vec2<T>&); // test for saturated vector, i.e. all components are in range [0, 1]
template<typename T> EGL_INLINE bool is_ssat(const vec2<T>&); // test for signed saturated vector, i.e. all components are in range [-1, 1]
template<typename T> EGL_INLINE bool operator==(const vec2<T>&, const vec2<T>&); // test for equality of vectors, i.e. all components of the vectors are equal (exact)
template<typename T> EGL_INLINE bool operator==(const vec2<T>&, typename math<T>::scalar_t); // test for equality of vector and scalar, i.e. all components of the vector equals the scalar (exact)
template<typename T> EGL_INLINE bool operator==(typename math<T>::scalar_t, const vec2<T>&); // test for equality of vector and scalar, i.e. all components of the vector equals the scalar (exact)
template<typename T> EGL_INLINE bool operator!=(const vec2<T>&, const vec2<T>&); // test for inequality of vectors, i.e. any of the components of the vectors are unequal (exact)
template<typename T> EGL_INLINE bool operator!=(const vec2<T>&, typename math<T>::scalar_t); // test for inequality of vector and scalar, i.e. any of the components of the vector is unequal to the scalar (exact)
template<typename T> EGL_INLINE bool operator!=(typename math<T>::scalar_t, const vec2<T>&); // test for inequality of vector and scalar, i.e. any of the components of the vector is unequal to the scalar (exact)
template<typename T> EGL_INLINE vec2<T> operator<(const vec2<T>&, const vec2<T>&); // component-wise vector less-than comparison (false=0, true=1)
template<typename T> EGL_INLINE vec2<T> operator<(const vec2<T>&, typename math<T>::scalar_t); // component-wise vector less-than comparison (false=0, true=1)
template<typename T> EGL_INLINE vec2<T> operator<(typename math<T>::scalar_t, const vec2<T>&); // component-wise vector less-than comparison (false=0, true=1)
template<typename T> EGL_INLINE vec2<T> operator>(const vec2<T>&, const vec2<T>&); // component-wise vector greater-than comparison (false=0, true=1)
template<typename T> EGL_INLINE vec2<T> operator>(const vec2<T>&, typename math<T>::scalar_t); // component-wise vector greater-than comparison (false=0, true=1)
template<typename T> EGL_INLINE vec2<T> operator>(typename math<T>::scalar_t, const vec2<T>&); // component-wise vector greater-than comparison (false=0, true=1)
template<typename T> EGL_INLINE vec2<T> operator<=(const vec2<T>&, const vec2<T>&); // component-wise vector less-or-equal comparison (false=0, true=1)
template<typename T> EGL_INLINE vec2<T> operator<=(const vec2<T>&, typename math<T>::scalar_t); // component-wise vector less-or-equal comparison (false=0, true=1)
template<typename T> EGL_INLINE vec2<T> operator<=(typename math<T>::scalar_t, const vec2<T>&); // component-wise vector less-or-equal comparison (false=0, true=1)
template<typename T> EGL_INLINE vec2<T> operator>=(const vec2<T>&, const vec2<T>&); // component-wise vector greater-or-equal comparison (false=0, true=1)
template<typename T> EGL_INLINE vec2<T> operator>=(const vec2<T>&, typename math<T>::scalar_t); // component-wise vector greater-or-equal comparison (false=0, true=1)
template<typename T> EGL_INLINE vec2<T> operator>=(typename math<T>::scalar_t, const vec2<T>&); // component-wise vector greater-or-equal comparison (false=0, true=1)
template<typename T> EGL_INLINE vec2<T> sel_eq(const vec2<T> &t0_, const vec2<T> &t1_, // component-wise equal vector select (t0_==t1_?v0_:v1_)
const vec2<T> &v0_, const vec2<T> &v1_);
template<typename T> EGL_INLINE vec2<T> sel_lt(const vec2<T> &t0_, const vec2<T> &t1_, // component-wise less-than vector select (t0_<t1_?v0_:v1_)
const vec2<T> &v0_, const vec2<T> &v1_);
template<typename T> EGL_INLINE vec2<T> sel_le(const vec2<T> &t0_, const vec2<T> &t1_, // component-wise less-or-equal vector select (t0_<=t1_?v0_:v1_)
const vec2<T> &v0_, const vec2<T> &v1_);
template<typename T> EGL_INLINE vec2<T> sel_eqz(const vec2<T> &t_, // component-wise equal-to-zero vector select (t_==0?v0_:v1_)
const vec2<T> &v0_, const vec2<T> &v1_);
template<typename T> EGL_INLINE vec2<T> sel_ltz(const vec2<T> &t_, // component-wise less-than-zero vector select (t_<0?v0_:v1_)
const vec2<T> &v0_, const vec2<T> &v1_);
template<typename T> EGL_INLINE vec2<T> sel_lez(const vec2<T> &t_, // component-wise less-or-equal-to-zero vector select (t_<=0?v0_:v1_)
const vec2<T> &v0_, const vec2<T> &v1_);
template<typename T> EGL_INLINE void operator+=(vec2<T>&, const vec2<T>&); // add vector to vector
template<typename T> EGL_INLINE void operator+=(vec2<T>&, typename math<T>::scalar_t); // add scalar to each component of the vector
template<typename T> EGL_INLINE void operator-=(vec2<T>&, const vec2<T>&); // subtract vector from vector
template<typename T> EGL_INLINE void operator-=(vec2<T>&, typename math<T>::scalar_t); // subtract scalar from each component of the vector
template<typename T> EGL_INLINE void operator*=(vec2<T>&, const vec2<T>&); // component-wise vector by vector multiplication
template<typename T> EGL_INLINE void operator*=(vec2<T>&, typename math<T>::scalar_t); // vector by scalar multiplication
template<typename T> EGL_INLINE void operator*=(vec2<T>&, const mat22<T>&); // vector by matrix multiplication
template<typename T> EGL_INLINE void operator/=(vec2<T>&, const vec2<T>&); // component-wise vector by vector division
template<typename T> EGL_INLINE void operator/=(vec2<T>&, typename math<T>::scalar_t); // vector by scalar division
template<typename T> EGL_INLINE vec2<T> operator+(const vec2<T>&, const vec2<T>&); // add vector to vector
template<typename T> EGL_INLINE vec2<T> operator+(const vec2<T>&, typename math<T>::scalar_t); // add scalar to each component of the vector
template<typename T> EGL_INLINE vec2<T> operator+(typename math<T>::scalar_t, const vec2<T>&); // add each component of the vector to a scalar vector
template<typename T> EGL_INLINE vec2<T> operator-(const vec2<T>&, const vec2<T>&); // subtract vector from vector
template<typename T> EGL_INLINE vec2<T> operator-(const vec2<T>&, typename math<T>::scalar_t); // subtract scalar from each component of the vector
template<typename T> EGL_INLINE vec2<T> operator-(typename math<T>::scalar_t, const vec2<T>&); // subtract each component of the vector from a scalar vector
template<typename T> EGL_INLINE vec2<T> operator-(const vec2<T>&); // negate the vector
template<typename T> EGL_INLINE vec2<T> operator*(const vec2<T>&, const vec2<T>&); // component-wise vector by vector multiplication
template<typename T> EGL_INLINE vec2<T> operator*(const vec2<T>&, typename math<T>::scalar_t); // vector by scalar multiplication
template<typename T> EGL_INLINE vec2<T> operator*(typename math<T>::scalar_t, const vec2<T>&); // vector by scalar multiplication
template<typename T> EGL_INLINE vec2<T> operator*(const vec2<T>&, const mat22<T>&); // vector by matrix multiplication
template<typename T> EGL_INLINE vec2<T> operator*(const mat22<T>&, const vec2<T>&); // matrix by transposed vector multiplication
template<typename T> EGL_INLINE vec2<T> operator/(const vec2<T>&, const vec2<T>&); // component-wise vector by vector division
template<typename T> EGL_INLINE vec2<T> operator/(const vec2<T>&, typename math<T>::scalar_t); // vector by scalar division
template<typename T> EGL_INLINE typename math<T>::scalar_t min(const vec2<T>&); // minimum component value
template<typename T> EGL_INLINE vec2<T> min(const vec2<T>&, const vec2<T>&); // component-wise minimum of the vectors
template<typename T> EGL_INLINE vec2<T> min(const vec2<T>&, const vec2<T>&, const vec2<T>&);
template<typename T> EGL_INLINE vec2<T> min(const vec2<T>&, const vec2<T>&, const vec2<T>&, const vec2<T>&);
template<typename T> EGL_INLINE vec2<T> min(const vec2<T>&, typename math<T>::scalar_t); // component-wise minimum of the vector and scalar
template<typename T> EGL_INLINE vec2<T> min(typename math<T>::scalar_t, const vec2<T>&); // component-wise minimum of the vector and scalar
template<typename T> EGL_INLINE typename math<T>::scalar_t max(const vec2<T>&); // maximum component value
template<typename T> EGL_INLINE vec2<T> max(const vec2<T>&, const vec2<T>&); // component-wise maximum of the vectors
template<typename T> EGL_INLINE vec2<T> max(const vec2<T>&, const vec2<T>&, const vec2<T>&);
template<typename T> EGL_INLINE vec2<T> max(const vec2<T>&, const vec2<T>&, const vec2<T>&, const vec2<T>&);
template<typename T> EGL_INLINE vec2<T> max(const vec2<T>&, typename math<T>::scalar_t); // component-wise maximum of the vector and scalar
template<typename T> EGL_INLINE vec2<T> max(typename math<T>::scalar_t, const vec2<T>&); // component-wise maximum of the vector and scalar
template<typename T> EGL_INLINE vec2<T> mul(const vec2<T> &v0_, const vec2<T> &v1_); // component-wise multiply: v0_*v1_
template<typename T> EGL_INLINE vec2<T> madd(const vec2<T> &v0_, // component-wise multiply-add: v0_*v1+v2_
const vec2<T> &v1_,
const vec2<T> &v2_);
template<typename T> EGL_INLINE vec2<T> madd(const vec2<T> &v_, // vector-scalar-scalar multiply-add: v_*mul_+add_
typename math<T>::scalar_t mul_,
typename math<T>::scalar_t add_);
template<typename T> EGL_INLINE vec2<T> madd(const vec2<T> &v_, // vector-vector-scalar multiply-add: v_*mul_+add_
const vec2<T> &mul_,
typename math<T>::scalar_t add_);
template<typename T> EGL_INLINE vec2<T> madd(const vec2<T> &v_, // vector-scalar-vector multiply-add: v_*mul_+add_
typename math<T>::scalar_t mul_,
const vec2<T> &add_);
template<typename T> EGL_INLINE vec2<T> rcp(const vec2<T>&); // component-wise vector reciprocal
template<typename T> EGL_INLINE vec2<T> rcp_z(const vec2<T>&); // component-wise vector reciprocal (set 0 for 0 components)
template<typename T> EGL_INLINE vec2<T> floor(const vec2<T>&); // component-wise greatest integer less than or equal to the value
template<typename T> EGL_INLINE vec2<T> ceil(const vec2<T>&); // component-wise smallest integer greater than or equal to the value
template<typename T> EGL_INLINE vec2<T> trunc(const vec2<T>&); // component-wise truncate decimal part from the value
template<typename T> EGL_INLINE vec2<T> frc(const vec2<T>&); // component-wise fractional part (for negative values returns 1-fractional part)
template<typename T> EGL_INLINE vec2<T> mod(const vec2<T>&, typename math<T>::scalar_t div_); // component-wise modulo
template<typename T> EGL_INLINE vec2<T> cycle(const vec2<T>&, typename math<T>::scalar_t cycle_); // component-wise cycle
template<typename T> EGL_INLINE vec2<T> cycle1(const vec2<T>&); // component-wise cycle1
template<typename T> EGL_INLINE vec2<T> sat(const vec2<T>&); // component-wise vector saturate
template<typename T> EGL_INLINE vec2<T> ssat(const vec2<T>&); // component-wise vector signed saturate
template<typename T> EGL_INLINE vec2<T> clamp(const vec2<T>&, // component-wise clamp of the vector
const vec2<T> &min_,
const vec2<T> &max_);
template<typename T> EGL_INLINE vec2<T> clamp(const vec2<T>&, // component-wise clamp of the vector with scalars
typename math<T>::scalar_t min_,
typename math<T>::scalar_t max_);
template<typename T> EGL_INLINE vec2<T> abs(const vec2<T>&); // component-wise vector absolute
template<typename T> EGL_INLINE vec2<T> sgn(const vec2<T>&); // component-wise signum (neg=-1, pos=+1, zero=0)
template<typename T> EGL_INLINE vec2<T> sgn_zp(const vec2<T>&); // component-wise signum (neg=-1, pos&zero=+1)
template<typename T> EGL_INLINE vec2<T> sqr(const vec2<T>&); // component-wise square: x*x
template<typename T> EGL_INLINE vec2<T> cubic(const vec2<T>&); // component-wise cubic: x*x*x
template<typename T> EGL_INLINE vec2<T> sqrt(const vec2<T>&); // component-wise square root
template<typename T> EGL_INLINE vec2<T> sqrt_z(const vec2<T>&); // component-wise square root (set 0 for components less than zero)
template<typename T> EGL_INLINE vec2<T> cbrt(const vec2<T>&); // component-wise cubic root
template<typename T> EGL_INLINE vec2<T> rsqrt(const vec2<T>&); // component-wise vector reciprocal square root
template<typename T> EGL_INLINE vec2<T> rsqrt_z(const vec2<T>&); // component-wise vector reciprocal square root (set 0 for components less than or equal to zero)
template<typename T> EGL_INLINE vec2<T> rcbrt(const vec2<T>&); // component-wise reciprocal cubic root
template<typename T> EGL_INLINE vec2<T> rcbrt_z(const vec2<T>&); // component-wise reciprocal cubic root (set 0 for components that are 0)
template<typename T> EGL_INLINE typename math<T>::scalar_t norm(const vec2<T>&); // vector norm (length): |v|
template<typename T> EGL_INLINE typename math<T>::scalar_t rnorm(const vec2<T>&); // reciprocal of the vector norm: 1/|v|
template<typename T> EGL_INLINE typename math<T>::scalar_t rnorm_z(const vec2<T>&); // reciprocal of the vector norm: 1/|v| (if |v|=0, return 0)
template<typename T> EGL_INLINE typename math<T>::scalar_t norm2(const vec2<T>&); // squared vector norm: |v|^2
template<typename T> EGL_INLINE typename math<T>::scalar_t rnorm2(const vec2<T>&); // reciprocal of the squared vector norm: 1/|v|^2
template<typename T> EGL_INLINE typename math<T>::scalar_t rnorm2_z(const vec2<T>&); // reciprocal of the squared vector norm: 1/|v|^2 (if |v|=0, return 0)
template<typename T> EGL_INLINE typename math<T>::scalar_t norm_l1(const vec2<T>&); // vector L1-norm (Manhattan norm)
template<typename T> EGL_INLINE typename math<T>::scalar_t rnorm_l1(const vec2<T>&); // reciprocal of the vector L1-norm
template<typename T> EGL_INLINE typename math<T>::scalar_t rnorm_l1_z(const vec2<T>&); // reciprocal of the vector L1-norm (if |v|=0, return 0)
template<typename T> EGL_INLINE vec2<T> exp(const vec2<T>&); // component-wise natural exponent: e^x
template<typename T> EGL_INLINE vec2<T> exp2(const vec2<T>&); // component-wise 2^x
template<typename T> EGL_INLINE vec2<T> ln(const vec2<T>&); // component-wise natural logarithm
template<typename T> EGL_INLINE vec2<T> log2(const vec2<T>&); // component-wise base-2 logarithm
template<typename T> EGL_INLINE vec2<T> log10(const vec2<T>&); // component-wise base-10 logarithm
template<typename T> EGL_INLINE vec2<T> pow(const vec2<T>&, typename math<T>::scalar_t); // component-wise power
template<typename T> EGL_INLINE vec2<T> unit(const vec2<T>&); // unit vector of the vector: v/|v|
template<typename T> EGL_INLINE vec2<T> unit_z(const vec2<T>&); // unit vector of the vector (if |v|=0, return v=[0, 0])
template<typename T> EGL_INLINE typename math<T>::scalar_t cross(const vec2<T>&, const vec2<T>&); // 2d vector cross-product
template<typename T> EGL_INLINE typename math<T>::scalar_t dot(const vec2<T>&, const vec2<T>&); // vector dot-product
template<typename T> EGL_INLINE typename math<T>::scalar_t dot1(const vec2<T>&); // vector dot-product with vector [1, 1] (component sum)
template<typename T> EGL_INLINE void neg(vec2<T>&); // negate the vector
template<typename T, class Rng> EGL_INLINE void rand_u(vec2<T>&, Rng&); // random unit vector
template<typename T, class Rng> EGL_INLINE void rand_real1(vec2<T>&, Rng&); // random vector where each component is in range [-1, 1]
template<typename T, class Rng> EGL_INLINE void rand_ureal1(vec2<T>&, Rng&); // random vector where each component is in range [0, 1]
template<typename T> EGL_INLINE vec2<T> smoothstep(const vec2<T>&); // component-wise smoothstep function
template<typename T> EGL_INLINE vec2<T> smootherstep(const vec2<T>&); // component-wise smootherstep function
template<typename T> EGL_INLINE vec2<T> lerp(const vec2<T> &v0_, // linear interpolation of vectors: f(t=0)=v0, f(t=1)=v1
const vec2<T> &v1_,
typename math<T>::scalar_t t_);
template<typename T> EGL_INLINE vec2<T> reflect(const vec2<T> &v_, const vec2<T> &n_); // reflect vector about normal
template<typename T> EGL_INLINE vec2<T> reflect_u(const vec2<T> &v_, const vec2<T> &n_); // reflect vector about unit normal
template<typename T> EGL_INLINE typename math<T>::scalar_t perspective_project(const vec2<T>&); // perspective project vector (divide by last component)
template<typename T, typename U> EGL_INLINE vec2<T> to_vec2(const vec2<U>&); // convert between vec2 types
template<unsigned shuffle_, typename T> EGL_INLINE vec2<T> shuffle(const vec2<T>&); // shuffle vector components (e.g. shuffle<11>(v_) == vec2f(v_.y, v_.y))
// 3d vector ops
template<typename T> EGL_INLINE bool is_zero(const vec3<T>&); // test for zero-vector, i.e. all components equal zero (exact)
template<typename T> EGL_INLINE bool is_sat(const vec3<T>&); // test for saturated vector, i.e. all components are in range [0, 1]
template<typename T> EGL_INLINE bool is_ssat(const vec3<T>&); // test for signed saturated vector, i.e. all components are in range [-1, 1]
template<typename T> EGL_INLINE bool operator==(const vec3<T>&, const vec3<T>&); // test for equality of vectors, i.e. all components of the vectors are equal (exact)
template<typename T> EGL_INLINE bool operator==(const vec3<T>&, typename math<T>::scalar_t); // test for equality of vector and scalar, i.e. all components of the vector equals the scalar (exact)
template<typename T> EGL_INLINE bool operator==(typename math<T>::scalar_t, const vec3<T>&); // test for equality of vector and scalar, i.e. all components of the vector equals the scalar (exact)
template<typename T> EGL_INLINE bool operator!=(const vec3<T>&, const vec3<T>&); // test for inequality of vectors, i.e. any of the components of the vectors are unequal (exact)
template<typename T> EGL_INLINE bool operator!=(const vec3<T>&, typename math<T>::scalar_t); // test for inequality of vector and scalar, i.e. any of the components of the vector is unequal to the scalar (exact)
template<typename T> EGL_INLINE bool operator!=(typename math<T>::scalar_t, const vec3<T>&); // test for inequality of vector and scalar, i.e. any of the components of the vector is unequal to the scalar (exact)
template<typename T> EGL_INLINE vec3<T> operator<(const vec3<T>&, const vec3<T>&); // component-wise vector less-than comparison (false=0, true=1)
template<typename T> EGL_INLINE vec3<T> operator<(const vec3<T>&, typename math<T>::scalar_t); // component-wise vector less-than comparison (false=0, true=1)
template<typename T> EGL_INLINE vec3<T> operator<(typename math<T>::scalar_t, const vec3<T>&); // component-wise vector less-than comparison (false=0, true=1)
template<typename T> EGL_INLINE vec3<T> operator>(const vec3<T>&, const vec3<T>&); // component-wise vector greater-than comparison (false=0, true=1)
template<typename T> EGL_INLINE vec3<T> operator>(const vec3<T>&, typename math<T>::scalar_t); // component-wise vector greater-than comparison (false=0, true=1)
template<typename T> EGL_INLINE vec3<T> operator>(typename math<T>::scalar_t, const vec3<T>&); // component-wise vector greater-than comparison (false=0, true=1)
template<typename T> EGL_INLINE vec3<T> operator<=(const vec3<T>&, const vec3<T>&); // component-wise vector less-or-equal comparison (false=0, true=1)
template<typename T> EGL_INLINE vec3<T> operator<=(const vec3<T>&, typename math<T>::scalar_t); // component-wise vector less-or-equal comparison (false=0, true=1)
template<typename T> EGL_INLINE vec3<T> operator<=(typename math<T>::scalar_t, const vec3<T>&); // component-wise vector less-or-equal comparison (false=0, true=1)
template<typename T> EGL_INLINE vec3<T> operator>=(const vec3<T>&, const vec3<T>&); // component-wise vector greater-or-equal comparison (false=0, true=1)
template<typename T> EGL_INLINE vec3<T> operator>=(const vec3<T>&, typename math<T>::scalar_t); // component-wise vector greater-or-equal comparison (false=0, true=1)
template<typename T> EGL_INLINE vec3<T> operator>=(typename math<T>::scalar_t, const vec3<T>&); // component-wise vector greater-or-equal comparison (false=0, true=1)
template<typename T> EGL_INLINE vec3<T> sel_eq(const vec3<T> &t0_, const vec3<T> &t1_, // component-wise equal vector select (t0_==t1_?v0_:v1_)
const vec3<T> &v0_, const vec3<T> &v1_);
template<typename T> EGL_INLINE vec3<T> sel_lt(const vec3<T> &t0_, const vec3<T> &t1_, // component-wise less-than vector select (t0_<t1_?v0_:v1_)
const vec3<T> &v0_, const vec3<T> &v1_);
template<typename T> EGL_INLINE vec3<T> sel_le(const vec3<T> &t0_, const vec3<T> &t1_, // component-wise less-or-equal vector select (t0_<=t1_?v0_:v1_)
const vec3<T> &v0_, const vec3<T> &v1_);
template<typename T> EGL_INLINE vec3<T> sel_eqz(const vec3<T> &t_, // component-wise equal-to-zero vector select (t_==0?v0_:v1_)
const vec3<T> &v0_, const vec3<T> &v1_);
template<typename T> EGL_INLINE vec3<T> sel_ltz(const vec3<T> &t_, // component-wise less-than-zero vector select (t_<0?v0_:v1_)
const vec3<T> &v0_, const vec3<T> &v1_);
template<typename T> EGL_INLINE vec3<T> sel_lez(const vec3<T> &t_, // component-wise less-or-equal-to-zero vector select (t_<=0?v0_:v1_)
const vec3<T> &v0_, const vec3<T> &v1_);
template<typename T> EGL_INLINE void operator+=(vec3<T>&, const vec3<T>&); // add vector to vector
template<typename T> EGL_INLINE void operator+=(vec3<T>&, typename math<T>::scalar_t); // add scalar to each component of the vector
template<typename T> EGL_INLINE void operator-=(vec3<T>&, const vec3<T>&); // subtract vector from vector
template<typename T> EGL_INLINE void operator-=(vec3<T>&, typename math<T>::scalar_t); // subtract scalar from each component of the vector
template<typename T> EGL_INLINE void operator*=(vec3<T>&, const vec3<T>&); // component-wise vector by vector multiplication
template<typename T> EGL_INLINE void operator*=(vec3<T>&, typename math<T>::scalar_t); // vector by scalar multiplication
template<typename T> EGL_INLINE void operator*=(vec3<T>&, const mat33<T>&); // vector by matrix multiplication
template<typename T> EGL_INLINE void operator*=(vec3<T>&, const mat44<T>&); // vector by matrix multiplication (assume vector w=1)
template<typename T> EGL_INLINE void operator*=(vec3<T>&, const quat<T>&); // vector by quaternion multiplication
template<typename T> EGL_INLINE void operator/=(vec3<T>&, const vec3<T>&); // component-wise vector by vector division
template<typename T> EGL_INLINE void operator/=(vec3<T>&, typename math<T>::scalar_t); // vector by scalar division
template<typename T> EGL_INLINE vec3<T> operator+(const vec3<T>&, const vec3<T>&); // add vector to vector
template<typename T> EGL_INLINE vec3<T> operator+(const vec3<T>&, typename math<T>::scalar_t); // add scalar to each component of the vector
template<typename T> EGL_INLINE vec3<T> operator+(typename math<T>::scalar_t, const vec3<T>&); // add each component of the vector to a scalar vector
template<typename T> EGL_INLINE vec3<T> operator-(const vec3<T>&, const vec3<T>&); // subtract vector from vector
template<typename T> EGL_INLINE vec3<T> operator-(const vec3<T>&, typename math<T>::scalar_t); // subtract scalar from each component of the vector
template<typename T> EGL_INLINE vec3<T> operator-(typename math<T>::scalar_t, const vec3<T>&); // subtract each component of the vector from a scalar vector
template<typename T> EGL_INLINE vec3<T> operator-(const vec3<T>&); // negate the vector
template<typename T> EGL_INLINE vec3<T> operator*(const vec3<T>&, const vec3<T>&); // component-wise vector by vector multiplication
template<typename T> EGL_INLINE vec3<T> operator*(const vec3<T>&, typename math<T>::scalar_t); // vector by scalar multiplication
template<typename T> EGL_INLINE vec3<T> operator*(typename math<T>::scalar_t, const vec3<T>&); // vector by scalar multiplication
template<typename T> EGL_INLINE vec3<T> operator*(const vec3<T>&, const mat33<T>&); // vector by matrix multiplication
template<typename T> EGL_INLINE vec3<T> operator*(const mat33<T>&, const vec3<T>&); // matrix by transposed vector multiplication
template<typename T> EGL_INLINE vec3<T> operator*(const vec3<T>&, const mat44<T>&); // vector by matrix multiplication (assume vector w=1)
template<typename T> EGL_INLINE vec3<T> operator*(const mat44<T>&, const vec3<T>&); // matrix by transposed vector multiplication (assume vector w=1)
template<typename T> EGL_INLINE vec3<T> operator*(const vec3<T>&, const quat<T>&); // vector by quaternion multiplication
template<typename T> EGL_INLINE vec3<T> operator/(const vec3<T>&, const vec3<T>&); // component-wise vector by vector division
template<typename T> EGL_INLINE vec3<T> operator/(const vec3<T>&, typename math<T>::scalar_t); // vector by scalar division
template<typename T> EGL_INLINE typename math<T>::scalar_t min(const vec3<T>&); // minimum component value
template<typename T> EGL_INLINE vec3<T> min(const vec3<T>&, const vec3<T>&); // component-wise minimum of the vectors
template<typename T> EGL_INLINE vec3<T> min(const vec3<T>&, const vec3<T>&, const vec3<T>&);
template<typename T> EGL_INLINE vec3<T> min(const vec3<T>&, const vec3<T>&, const vec3<T>&, const vec3<T>&);
template<typename T> EGL_INLINE vec3<T> min(const vec3<T>&, typename math<T>::scalar_t); // component-wise minimum of the vector and scalar
template<typename T> EGL_INLINE vec3<T> min(typename math<T>::scalar_t, const vec3<T>&); // component-wise minimum of the vector and scalar
template<typename T> EGL_INLINE typename math<T>::scalar_t max(const vec3<T>&); // maximum component value
template<typename T> EGL_INLINE vec3<T> max(const vec3<T>&, const vec3<T>&); // component-wise maximum of the vectors
template<typename T> EGL_INLINE vec3<T> max(const vec3<T>&, const vec3<T>&, const vec3<T>&);
template<typename T> EGL_INLINE vec3<T> max(const vec3<T>&, const vec3<T>&, const vec3<T>&, const vec3<T>&);
template<typename T> EGL_INLINE vec3<T> max(const vec3<T>&, typename math<T>::scalar_t); // component-wise maximum of the vector and scalar
template<typename T> EGL_INLINE vec3<T> max(typename math<T>::scalar_t, const vec3<T>&); // component-wise maximum of the vector and scalar
template<typename T> EGL_INLINE vec3<T> mul(const vec3<T> &v0_, const vec3<T> &v1_); // component-wise vector multiply: v0_*v1_
template<typename T> EGL_INLINE vec3<T> madd(const vec3<T> &v0_, // component-wise multiply-add: v0_*v1+v2_
const vec3<T> &v1_,
const vec3<T> &v2_);
template<typename T> EGL_INLINE vec3<T> madd(const vec3<T> &v_, // vector-scalar-scalar multiply-add: v_*mul_+add_
typename math<T>::scalar_t mul_,
typename math<T>::scalar_t add_);
template<typename T> EGL_INLINE vec3<T> madd(const vec3<T> &v_, // vector-vector-scalar multiply-add: v_*mul_+add_
const vec3<T> &mul_,
typename math<T>::scalar_t add_);
template<typename T> EGL_INLINE vec3<T> madd(const vec3<T> &v_, // vector-scalar-vector multiply-add: v_*mul_+add_
typename math<T>::scalar_t mul_,
const vec3<T> &add_);
template<typename T> EGL_INLINE vec3<T> rcp(const vec3<T>&); // component-wise vector reciprocal
template<typename T> EGL_INLINE vec3<T> rcp_z(const vec3<T>&); // component-wise vector reciprocal (set 0 for 0 components)
template<typename T> EGL_INLINE vec3<T> floor(const vec3<T>&); // component-wise greatest integer less than or equal to the value
template<typename T> EGL_INLINE vec3<T> ceil(const vec3<T>&); // component-wise smallest integer greater than or equal to the value
template<typename T> EGL_INLINE vec3<T> trunc(const vec3<T>&); // component-wise truncate decimal part from the value
template<typename T> EGL_INLINE vec3<T> frc(const vec3<T>&); // component-wise fractional part (for negative values returns 1-fractional part)
template<typename T> EGL_INLINE vec3<T> mod(const vec3<T>&, typename math<T>::scalar_t div_); // component-wise modulo
template<typename T> EGL_INLINE vec3<T> cycle(const vec3<T>&, typename math<T>::scalar_t cycle_); // component-wise cycle
template<typename T> EGL_INLINE vec3<T> cycle1(const vec3<T>&); // component-wise cycle1
template<typename T> EGL_INLINE vec3<T> sat(const vec3<T>&); // component-wise vector saturate
template<typename T> EGL_INLINE vec3<T> ssat(const vec3<T>&); // component-wise vector signed saturate
template<typename T> EGL_INLINE vec3<T> clamp(const vec3<T>&, // component-wise clamp of the vector
const vec3<T> &min_,
const vec3<T> &max_);
template<typename T> EGL_INLINE vec3<T> clamp(const vec3<T>&, // component-wise clamp of the vector with scalars
typename math<T>::scalar_t min_,
typename math<T>::scalar_t max_);
template<typename T> EGL_INLINE vec3<T> abs(const vec3<T>&); // component-wise vector absolute
template<typename T> EGL_INLINE vec3<T> sgn(const vec3<T>&); // component-wise signum (neg=-1, pos=+1, zero=0)
template<typename T> EGL_INLINE vec3<T> sgn_zp(const vec3<T>&); // component-wise signum (neg=-1, pos&zero=+1)
template<typename T> EGL_INLINE vec3<T> sqr(const vec3<T>&); // component-wise square: x*x
template<typename T> EGL_INLINE vec3<T> cubic(const vec3<T>&); // component-wise cubic: x*x*x
template<typename T> EGL_INLINE vec3<T> sqrt(const vec3<T>&); // component-wise vector square root
template<typename T> EGL_INLINE vec3<T> sqrt_z(const vec3<T>&); // component-wise vector square root (set 0 for components less than zero)
template<typename T> EGL_INLINE vec2<T> cbrt(const vec2<T>&); // component-wise cubic root
template<typename T> EGL_INLINE vec3<T> rsqrt(const vec3<T>&); // component-wise vector reciprocal square root
template<typename T> EGL_INLINE vec3<T> rsqrt_z(const vec3<T>&); // component-wise vector reciprocal square root (set 0 for components less than or equal to zero)
template<typename T> EGL_INLINE vec3<T> rcbrt(const vec3<T>&); // component-wise reciprocal cubic root
template<typename T> EGL_INLINE vec3<T> rcbrt_z(const vec3<T>&); // component-wise reciprocal cubic root (set 0 for components that are 0)
template<typename T> EGL_INLINE typename math<T>::scalar_t norm(const vec3<T>&); // vector norm (length): |v|
template<typename T> EGL_INLINE typename math<T>::scalar_t rnorm(const vec3<T>&); // reciprocal of the vector norm: 1/|v|
template<typename T> EGL_INLINE typename math<T>::scalar_t rnorm_z(const vec3<T>&); // reciprocal of the vector norm: 1/|v| (return 0, if |v|=0)
template<typename T> EGL_INLINE typename math<T>::scalar_t norm2(const vec3<T>&); // squared vector norm: |v|^2
template<typename T> EGL_INLINE typename math<T>::scalar_t rnorm2(const vec3<T>&); // reciprocal of the squared vector norm: 1/|v|^2
template<typename T> EGL_INLINE typename math<T>::scalar_t rnorm2_z(const vec3<T>&); // reciprocal of the squared vector norm: 1/|v|^2 (return 0, if |v|=0)
template<typename T> EGL_INLINE typename math<T>::scalar_t norm_l1(const vec3<T>&); // vector L1-norm (Manhattan norm)
template<typename T> EGL_INLINE typename math<T>::scalar_t rnorm_l1(const vec3<T>&); // reciprocal of the vector L1-norm
template<typename T> EGL_INLINE typename math<T>::scalar_t rnorm_l1_z(const vec3<T>&); // reciprocal of the vector L1-norm (if |v|=0, return 0)
template<typename T> EGL_INLINE vec3<T> exp(const vec3<T>&); // component-wise natural exponent
template<typename T> EGL_INLINE vec3<T> exp2(const vec3<T>&); // component-wise 2^x
template<typename T> EGL_INLINE vec3<T> ln(const vec3<T>&); // component-wise natural logarithm
template<typename T> EGL_INLINE vec3<T> log2(const vec3<T>&); // component-wise base-2 logarithm
template<typename T> EGL_INLINE vec3<T> log10(const vec3<T>&); // component-wise base-10 logarithm
template<typename T> EGL_INLINE vec3<T> pow(const vec3<T>&, typename math<T>::scalar_t); // component-wise power
template<typename T> EGL_INLINE vec3<T> unit(const vec3<T>&); // unit vector of the vector: v/|v|
template<typename T> EGL_INLINE vec3<T> unit_z(const vec3<T>&); // unit vector of the vector (if |v|=0, return v=[0, 0, 0])
template<typename T> EGL_INLINE vec3<T> cross(const vec3<T>&, const vec3<T>&); // vector cross-product
template<typename T> EGL_INLINE typename math<T>::scalar_t dot(const vec3<T>&, const vec3<T>&); // vector dot-product
template<typename T> EGL_INLINE typename math<T>::scalar_t dot1(const vec3<T>&); // vector dot-product with vector [1, 1, 1] (component sum)
template<typename T> EGL_INLINE void neg(vec3<T>&); // negate the vector
template<typename T, class Rng> EGL_INLINE void rand_u(vec3<T>&, Rng&); // random unit vector
template<typename T, class Rng> EGL_INLINE void rand_real1(vec3<T>&, Rng&); // random vector where each component is in range [-1, 1]
template<typename T, class Rng> EGL_INLINE void rand_ureal1(vec3<T>&, Rng&); // random vector where each component is in range [0, 1]
template<typename T> EGL_INLINE vec3<T> smoothstep(const vec3<T>&); // component-wise smoothstep function
template<typename T> EGL_INLINE vec3<T> smootherstep(const vec3<T>&); // component-wise smootherstep function
template<typename T> EGL_INLINE vec3<T> lerp(const vec3<T> &v0_, // linear interpolation of vectors: f(t=0)=v0, f(t=1)=v1
const vec3<T> &v1_,
typename math<T>::scalar_t t_);
template<typename T> EGL_INLINE vec3<T> reflect(const vec3<T> &v_, const vec3<T> &n_); // reflect vector about normal
template<typename T> EGL_INLINE vec3<T> reflect_u(const vec3<T> &v_, const vec3<T> &n_); // reflect vector about unit normal
template<typename T> EGL_INLINE vec2<T> perspective_project(const vec3<T>&); // perspective project vector (divide by last component)
template<typename T, typename U> EGL_INLINE vec3<T> to_vec3(const vec3<U>&); // convert between vec3 types
template<unsigned shuffle_, typename T> EGL_INLINE vec3<T> shuffle(const vec3<T>&); // shuffle vector components (e.g. shuffle<211>(v_) == vec3f(v_.z, v_.y, v_.y))
template<typename T> EGL_INLINE void pack_s1(vec3_32s&, const vec3<T>&); // pack 3d vector (components in range [-1, 1]) to 32-bit 3d vector
template<typename T> EGL_INLINE void pack_u1(vec3_32u&, const vec3<T>&); // pack 3d vector (components in range [0, 1]) to 32-bit 3d vector
template<typename T> EGL_INLINE void unpack_s1(vec3<T>&, const vec3_32s&); // unpack 32-bit 3d vector to 3d vector (components in range [-1, 1])
template<typename T> EGL_INLINE void unpack_u1(vec3<T>&, const vec3_32u&); // unpack 32-bit 3d vector to 3d vector (components in range [0, 1])
// 4d vector ops
template<typename T> EGL_INLINE bool is_zero(const vec4<T>&); // test for zero-vector, i.e. all components equal zero (exact)
template<typename T> EGL_INLINE bool is_sat(const vec4<T>&); // test for saturated vector, i.e. all components are in range [0, 1]
template<typename T> EGL_INLINE bool is_ssat(const vec4<T>&); // test for signed saturated vector, i.e. all components are in range [-1, 1]
template<typename T> EGL_INLINE bool operator==(const vec4<T>&, const vec4<T>&); // test for equality of vectors, i.e. all components of the vectors are equal (exact)
template<typename T> EGL_INLINE bool operator==(const vec4<T>&, typename math<T>::scalar_t); // test for equality of vector and scalar, i.e. all components of the vector equals the scalar (exact)
template<typename T> EGL_INLINE bool operator==(typename math<T>::scalar_t, const vec4<T>&); // test for equality of vector and scalar, i.e. all components of the vector equals the scalar (exact)
template<typename T> EGL_INLINE bool operator!=(const vec4<T>&, const vec4<T>&); // test for inequality of vectors, i.e. any of the components of the vectors are unequal (exact)
template<typename T> EGL_INLINE bool operator!=(const vec4<T>&, typename math<T>::scalar_t); // test for inequality of vector and scalar, i.e. any of the components of the vector is unequal to the scalar (exact)
template<typename T> EGL_INLINE bool operator!=(typename math<T>::scalar_t, const vec4<T>&); // test for inequality of vector and scalar, i.e. any of the components of the vector is unequal to the scalar (exact)
template<typename T> EGL_INLINE vec4<T> operator<(const vec4<T>&, const vec4<T>&); // component-wise vector less-than comparison (false=0, true=1)
template<typename T> EGL_INLINE vec4<T> operator<(const vec4<T>&, typename math<T>::scalar_t); // component-wise vector less-than comparison (false=0, true=1)
template<typename T> EGL_INLINE vec4<T> operator<(typename math<T>::scalar_t, const vec4<T>&); // component-wise vector less-than comparison (false=0, true=1)
template<typename T> EGL_INLINE vec4<T> operator>(const vec4<T>&, const vec4<T>&); // component-wise vector greater-than comparison (false=0, true=1)
template<typename T> EGL_INLINE vec4<T> operator>(const vec4<T>&, typename math<T>::scalar_t); // component-wise vector greater-than comparison (false=0, true=1)
template<typename T> EGL_INLINE vec4<T> operator>(typename math<T>::scalar_t, const vec4<T>&); // component-wise vector greater-than comparison (false=0, true=1)
template<typename T> EGL_INLINE vec4<T> operator<=(const vec4<T>&, const vec4<T>&); // component-wise vector less-or-equal comparison (false=0, true=1)
template<typename T> EGL_INLINE vec4<T> operator<=(const vec4<T>&, typename math<T>::scalar_t); // component-wise vector less-or-equal comparison (false=0, true=1)
template<typename T> EGL_INLINE vec4<T> operator<=(typename math<T>::scalar_t, const vec4<T>&); // component-wise vector less-or-equal comparison (false=0, true=1)
template<typename T> EGL_INLINE vec4<T> operator>=(const vec4<T>&, const vec4<T>&); // component-wise vector greater-or-equal comparison (false=0, true=1)
template<typename T> EGL_INLINE vec4<T> operator>=(const vec4<T>&, typename math<T>::scalar_t); // component-wise vector greater-or-equal comparison (false=0, true=1)
template<typename T> EGL_INLINE vec4<T> operator>=(typename math<T>::scalar_t, const vec4<T>&); // component-wise vector greater-or-equal comparison (false=0, true=1)
template<typename T> EGL_INLINE vec4<T> sel_eq(const vec4<T> &t0_, const vec4<T> &t1_, // component-wise equal vector select (t0_==t1_?v0_:v1_)
const vec4<T> &v0_, const vec4<T> &v1_);
template<typename T> EGL_INLINE vec4<T> sel_lt(const vec4<T> &t0_, const vec4<T> &t1_, // component-wise less-than vector select (t0_<t1_?v0_:v1_)
const vec4<T> &v0_, const vec4<T> &v1_);
template<typename T> EGL_INLINE vec4<T> sel_le(const vec4<T> &t0_, const vec4<T> &t1_, // component-wise less-or-equal vector select (t0_<=t1_?v0_:v1_)
const vec4<T> &v0_, const vec4<T> &v1_);
template<typename T> EGL_INLINE vec4<T> sel_eqz(const vec4<T> &t_, // component-wise equal-to-zero vector select (t_==0?v0_:v1_)
const vec4<T> &v0_, const vec4<T> &v1_);
template<typename T> EGL_INLINE vec4<T> sel_ltz(const vec4<T> &t_, // component-wise less-than-zero vector select (t_<0?v0_:v1_)
const vec4<T> &v0_, const vec4<T> &v1_);
template<typename T> EGL_INLINE vec4<T> sel_lez(const vec4<T> &t_, // component-wise less-or-equal-to-zero vector select (t_<=0?v0_:v1_)
const vec4<T> &v0_, const vec4<T> &v1_);
template<typename T> EGL_INLINE void operator+=(vec4<T>&, const vec4<T>&); // add vector to vector
template<typename T> EGL_INLINE void operator+=(vec4<T>&, typename math<T>::scalar_t); // add scalar to each component of the vector
template<typename T> EGL_INLINE void operator-=(vec4<T>&, const vec4<T>&); // subtract vector from vector
template<typename T> EGL_INLINE void operator-=(vec4<T>&, typename math<T>::scalar_t); // subtract scalar from each component of the vector
template<typename T> EGL_INLINE void operator*=(vec4<T>&, const vec4<T>&); // component-wise vector by vector multiplication
template<typename T> EGL_INLINE void operator*=(vec4<T>&, typename math<T>::scalar_t); // vector by scalar multiplication
template<typename T> EGL_INLINE void operator*=(vec4<T>&, const mat44<T>&); // vector by matrix multiplication
template<typename T> EGL_INLINE void operator/=(vec4<T>&, const vec4<T>&); // component-wise vector by vector division
template<typename T> EGL_INLINE void operator/=(vec4<T>&, typename math<T>::scalar_t); // vector by scalar division
template<typename T> EGL_INLINE vec4<T> operator+(const vec4<T>&, const vec4<T>&); // add vector to vector
template<typename T> EGL_INLINE vec4<T> operator+(const vec4<T>&, typename math<T>::scalar_t); // add scalar to each component of the vector
template<typename T> EGL_INLINE vec4<T> operator+(typename math<T>::scalar_t, const vec4<T>&); // add each component of the vector to a scalar vector
template<typename T> EGL_INLINE vec4<T> operator-(const vec4<T>&, const vec4<T>&); // subtract vector from vector
template<typename T> EGL_INLINE vec4<T> operator-(const vec4<T>&, typename math<T>::scalar_t); // subtract scalar from each component of the vector
template<typename T> EGL_INLINE vec4<T> operator-(typename math<T>::scalar_t, const vec4<T>&); // subtract each component of the vector from a scalar vector
template<typename T> EGL_INLINE vec4<T> operator-(const vec4<T>&); // negate the vector
template<typename T> EGL_INLINE vec4<T> operator*(const vec4<T>&, const vec4<T>&); // component-wise vector by vector multiplication
template<typename T> EGL_INLINE vec4<T> operator*(const vec4<T>&, typename math<T>::scalar_t); // vector by scalar multiplication
template<typename T> EGL_INLINE vec4<T> operator*(typename math<T>::scalar_t, const vec4<T>&); // vector by scalar multiplication
template<typename T> EGL_INLINE vec4<T> operator*(const vec4<T>&, const mat44<T>&); // vector by matrix multiplication
template<typename T> EGL_INLINE vec4<T> operator*(const mat44<T>&, const vec4<T>&); // matrix by transposed vector multiplication
template<typename T> EGL_INLINE vec4<T> operator/(const vec4<T>&, const vec4<T>&); // component-wise vector by vector division
template<typename T> EGL_INLINE vec4<T> operator/(const vec4<T>&, typename math<T>::scalar_t); // vector by scalar division
template<typename T> EGL_INLINE typename math<T>::scalar_t min(const vec4<T>&); // minimum component value
template<typename T> EGL_INLINE vec4<T> min(const vec4<T>&, const vec4<T>&); // component-wise minimum of the vectors
template<typename T> EGL_INLINE vec4<T> min(const vec4<T>&, const vec4<T>&, const vec4<T>&);
template<typename T> EGL_INLINE vec4<T> min(const vec4<T>&, const vec4<T>&, const vec4<T>&, const vec4<T>&);
template<typename T> EGL_INLINE vec4<T> min(const vec4<T>&, typename math<T>::scalar_t); // component-wise minimum of the vector and scalar
template<typename T> EGL_INLINE vec4<T> min(typename math<T>::scalar_t, const vec4<T>&); // component-wise minimum of the vector and scalar
template<typename T> EGL_INLINE typename math<T>::scalar_t max(const vec4<T>&); // maximum component value
template<typename T> EGL_INLINE vec4<T> max(const vec4<T>&, const vec4<T>&); // component-wise maximum of the vectors
template<typename T> EGL_INLINE vec4<T> max(const vec4<T>&, const vec4<T>&, const vec4<T>&);
template<typename T> EGL_INLINE vec4<T> max(const vec4<T>&, const vec4<T>&, const vec4<T>&, const vec4<T>&);
template<typename T> EGL_INLINE vec4<T> max(const vec4<T>&, typename math<T>::scalar_t); // component-wise maximum of the vector and scalar
template<typename T> EGL_INLINE vec4<T> max(typename math<T>::scalar_t, const vec4<T>&); // component-wise maximum of the vector and scalar
template<typename T> EGL_INLINE vec4<T> mul(const vec4<T> &v0_, const vec4<T> &v1_); // component-wise multiply: v0_*v1_
template<typename T> EGL_INLINE vec4<T> madd(const vec4<T> &v0_, // component-wise multiply-add: v0_*v1+v2_
const vec4<T> &v1_,
const vec4<T> &v2_);
template<typename T> EGL_INLINE vec4<T> madd(const vec4<T> &v_, // vector-scalar-scalar multiply-add: v_*mul_+add_
typename math<T>::scalar_t mul_,
typename math<T>::scalar_t add_);
template<typename T> EGL_INLINE vec4<T> madd(const vec4<T> &v_, // vector-vector-scalar multiply-add: v_*mul_+add_
const vec4<T> &mul_,
typename math<T>::scalar_t add_);
template<typename T> EGL_INLINE vec4<T> madd(const vec4<T> &v_, // vector-scalar-vector multiply-add: v_*mul_+add_
typename math<T>::scalar_t mul_,
const vec4<T> &add_);
template<typename T> EGL_INLINE vec4<T> rcp(const vec4<T>&); // component-wise vector reciprocal
template<typename T> EGL_INLINE vec4<T> rcp_z(const vec4<T>&); // component-wise vector reciprocal (set 0 for 0 components)
template<typename T> EGL_INLINE vec4<T> floor(const vec4<T>&); // component-wise greatest integer less than or equal to the value
template<typename T> EGL_INLINE vec4<T> ceil(const vec4<T>&); // component-wise smallest integer greater than or equal to the value
template<typename T> EGL_INLINE vec4<T> trunc(const vec4<T>&); // component-wise truncate decimal part from the value
template<typename T> EGL_INLINE vec4<T> frc(const vec4<T>&); // component-wise fractional part (for negative values returns 1-fractional part)
template<typename T> EGL_INLINE vec4<T> mod(const vec4<T>&, typename math<T>::scalar_t div_); // component-wise modulo
template<typename T> EGL_INLINE vec4<T> cycle(const vec4<T>&, typename math<T>::scalar_t cycle_); // component-wise cycle
template<typename T> EGL_INLINE vec4<T> cycle1(const vec4<T>&); // component-wise cycle1
template<typename T> EGL_INLINE vec4<T> sat(const vec4<T>&); // component-wise vector saturate
template<typename T> EGL_INLINE vec4<T> ssat(const vec4<T>&); // component-wise vector signed saturate
template<typename T> EGL_INLINE vec4<T> clamp(const vec4<T>&, // component-wise clamp of the vector
const vec4<T> &min_,
const vec4<T> &max_);
template<typename T> EGL_INLINE vec4<T> clamp(const vec4<T>&, // component-wise clamp of the vector with scalars
typename math<T>::scalar_t min_,
typename math<T>::scalar_t max_);
template<typename T> EGL_INLINE vec4<T> abs(const vec4<T>&); // component-wise vector absolute
template<typename T> EGL_INLINE vec4<T> sgn(const vec4<T>&); // component-wise signum (neg=-1, pos=+1, zero=0)
template<typename T> EGL_INLINE vec4<T> sgn_zp(const vec4<T>&); // component-wise signum (neg=-1, pos&zero=+1)
template<typename T> EGL_INLINE vec4<T> sqr(const vec4<T>&); // component-wise square: x*x
template<typename T> EGL_INLINE vec4<T> cubic(const vec4<T>&); // component-wise cubic: x*x*x
template<typename T> EGL_INLINE vec4<T> sqrt(const vec4<T>&); // component-wise vector square root
template<typename T> EGL_INLINE vec4<T> sqrt_z(const vec4<T>&); // component-wise vector square root (set 0 for components less than zero)
template<typename T> EGL_INLINE vec4<T> cbrt(const vec4<T>&); // component-wise cubic root
template<typename T> EGL_INLINE vec4<T> rsqrt(const vec4<T>&); // component-wise vector reciprocal square root
template<typename T> EGL_INLINE vec4<T> rsqrt_z(const vec4<T>&); // component-wise vector reciprocal square root (set 0 for components less than or equal to zero)
template<typename T> EGL_INLINE vec4<T> rcbrt(const vec4<T>&); // component-wise reciprocal cubic root
template<typename T> EGL_INLINE vec4<T> rcbrt_z(const vec4<T>&); // component-wise reciprocal cubic root (set 0 for components that are 0)
template<typename T> EGL_INLINE typename math<T>::scalar_t norm(const vec4<T>&); // vector norm (length): |v|
template<typename T> EGL_INLINE typename math<T>::scalar_t rnorm(const vec4<T>&); // reciprocal of the vector norm: 1/|v|
template<typename T> EGL_INLINE typename math<T>::scalar_t rnorm_z(const vec4<T>&); // reciprocal of the vector norm: 1/|v| (return 0, if |v|=0)
template<typename T> EGL_INLINE typename math<T>::scalar_t norm2(const vec4<T>&); // squared vector norm: |v|^2
template<typename T> EGL_INLINE typename math<T>::scalar_t rnorm2(const vec4<T>&); // reciprocal of the squared vector norm: 1/|v|^2
template<typename T> EGL_INLINE typename math<T>::scalar_t rnorm2_z(const vec4<T>&); // reciprocal of the squared vector norm: 1/|v|^2 (return 0, if |v|=0)
template<typename T> EGL_INLINE typename math<T>::scalar_t norm_l1(const vec4<T>&); // vector L1-norm (Manhattan norm)
template<typename T> EGL_INLINE typename math<T>::scalar_t rnorm_l1(const vec4<T>&); // reciprocal of the vector L1-norm
template<typename T> EGL_INLINE typename math<T>::scalar_t rnorm_l1_z(const vec4<T>&); // reciprocal of the vector L1-norm (if |v|=0, return 0)
template<typename T> EGL_INLINE vec4<T> exp(const vec4<T>&); // component-wise natural exponent
template<typename T> EGL_INLINE vec4<T> exp2(const vec4<T>&); // component-wise 2^x
template<typename T> EGL_INLINE vec4<T> ln(const vec4<T>&); // component-wise natural logarithm
template<typename T> EGL_INLINE vec4<T> log2(const vec4<T>&); // component-wise base-2 logarithm
template<typename T> EGL_INLINE vec4<T> log10(const vec4<T>&); // component-wise base-10 logarithm
template<typename T> EGL_INLINE vec4<T> pow(const vec4<T>&, typename math<T>::scalar_t); // component-wise power
template<typename T> EGL_INLINE vec4<T> unit(const vec4<T>&); // unit vector of the vector: v/|v|
template<typename T> EGL_INLINE vec4<T> unit_z(const vec4<T>&); // unit vector of the vector (if |v|=0, return v=[0, 0, 0, 0])
template<typename T> EGL_INLINE typename math<T>::scalar_t dot(const vec4<T>&, const vec4<T>&); // vector dot-product
template<typename T> EGL_INLINE typename math<T>::scalar_t dot1(const vec4<T>&); // vector dot-product with vector [1, 1, 1, 1] (component sum)
template<typename T> EGL_INLINE void neg(vec4<T>&); // negate the vector
template<typename T, class Rng> EGL_INLINE void rand_u(vec4<T>&, Rng&); // random unit vector
template<typename T, class Rng> EGL_INLINE void rand_real1(vec4<T>&, Rng&); // random vector where each component is in range [-1, 1]
template<typename T, class Rng> EGL_INLINE void rand_ureal1(vec4<T>&, Rng&); // random vector where each component is in range [0, 1]
template<typename T> EGL_INLINE vec4<T> smoothstep(const vec4<T>&); // component-wise smoothstep function
template<typename T> EGL_INLINE vec4<T> smootherstep(const vec4<T>&); // component-wise smootherstep function
template<typename T> EGL_INLINE vec4<T> lerp(const vec4<T> &v0_, // linear interpolation of vectors: f(t=0)=v0, f(t=1)=v1
const vec4<T> &v1_,
typename math<T>::scalar_t t_);
template<typename T> EGL_INLINE vec4<T> reflect(const vec4<T> &v_, const vec4<T> &n_); // reflect vector about normal
template<typename T> EGL_INLINE vec4<T> reflect_u(const vec4<T> &v_, const vec4<T> &n_); // reflect vector about unit normal
template<typename T> EGL_INLINE vec3<T> perspective_project(const vec4<T>&); // perspective project vector (divide by last component)
template<typename T, typename U> EGL_INLINE vec4<T> to_vec4(const vec4<U>&); // convert between vec4 types
template<unsigned shuffle_, typename T> EGL_INLINE vec4<T> shuffle(const vec4<T>&); // shuffle vector components (e.g. shuffle<2311>(v_) == vec4f(v_.z, v_.w, v_.y, v_.y))
template<typename T> EGL_INLINE void pack_s1(vec4_32u&, const vec4<T>&); // pack 4d vector (components in range [-1, 1]) to 32-bit 4d vector
template<typename T> EGL_INLINE void pack_u1(vec4_32u&, const vec4<T>&); // pack 4d vector (components in range [0, 1]) to 32-bit 4d vector
template<typename T> EGL_INLINE void unpack_s1(vec4<T>&, const vec4_32s&); // unpack 32-bit 4d vector to 4d vector (components in range [-1, 1])
template<typename T> EGL_INLINE void unpack_u1(vec4<T>&, const vec4_32u&); // unpack 32-bit 4d vector to 4d vector (components in range [0, 1])
// 2x2 matrix ops
template<typename T> EGL_INLINE bool is_zero(const mat22<T>&); // test for zero-matrix, i.e. all components equal zero (exact)
template<typename T> EGL_INLINE bool is_sat(const mat22<T>&); // test for saturated matrix, i.e. all components are in range [0, 1]
template<typename T> EGL_INLINE bool is_ssat(const mat22<T>&); // test for signed saturated matrix, i.e. all components are in range [-1, 1]
template<typename T> EGL_INLINE bool operator==(const mat22<T>&, const mat22<T>&); // test for equality of matrices, i.e. all components of the matrices are equal (exact)
template<typename T> EGL_INLINE bool operator==(const mat22<T>&, typename math<T>::scalar_t); // test for equality of matrix and scalar, i.e. all components of the matrix equals the scalar (exact)
template<typename T> EGL_INLINE bool operator==(typename math<T>::scalar_t, const mat22<T>&); // test for equality of matrix and scalar, i.e. all components of the matrix equals the scalar (exact)
template<typename T> EGL_INLINE bool operator!=(const mat22<T>&, const mat22<T>&); // test for inequality of matrices, i.e. any of the components of the vectors are unequal (exact)
template<typename T> EGL_INLINE bool operator!=(const mat22<T>&, typename math<T>::scalar_t); // test for inequality of matrix and scalar, i.e. any of the components of the matrix is unequal to the scalar (exact)
template<typename T> EGL_INLINE bool operator!=(typename math<T>::scalar_t, const mat22<T>&); // test for inequality of matrix and scalar, i.e. any of the components of the matrix is unequal to the scalar (exact)
template<typename T> EGL_INLINE void operator+=(mat22<T>&, const mat22<T>&); // add matrix to matrix
template<typename T> EGL_INLINE void operator+=(mat22<T>&, typename math<T>::scalar_t); // add scalar to matrix
template<typename T> EGL_INLINE void operator-=(mat22<T>&, const mat22<T>&); // subtract matrix from matrix
template<typename T> EGL_INLINE void operator-=(mat22<T>&, typename math<T>::scalar_t); // subtract scalar from matrix
template<typename T> EGL_INLINE void operator*=(mat22<T>&, const mat22<T>&); // multiply matrix by matrix
template<typename T> EGL_INLINE void operator*=(mat22<T>&, typename math<T>::scalar_t); // multiply matrix by scalar
template<typename T> EGL_INLINE void operator/=(mat22<T>&, typename math<T>::scalar_t); // divide matrix by scalar
template<typename T> EGL_INLINE mat22<T> operator+(const mat22<T>&, const mat22<T>&); // add matrix to matrix
template<typename T> EGL_INLINE mat22<T> operator+(const mat22<T>&, typename math<T>::scalar_t); // add scalar to matrix
template<typename T> EGL_INLINE mat22<T> operator+(typename math<T>::scalar_t, const mat22<T>&); // add matrix to scalar
template<typename T> EGL_INLINE mat22<T> operator-(const mat22<T>&, const mat22<T>&); // subtract matrix from matrix
template<typename T> EGL_INLINE mat22<T> operator-(const mat22<T>&, typename math<T>::scalar_t); // subtract scalar from matrix
template<typename T> EGL_INLINE mat22<T> operator-(typename math<T>::scalar_t, const mat22<T>&); // subtract matrix from scalar
template<typename T> EGL_INLINE mat22<T> operator-(const mat22<T>&); // negate the matrix
template<typename T> EGL_INLINE mat22<T> operator*(const mat22<T>&, const mat22<T>&); // multiply matrix by matrix
template<typename T> EGL_INLINE mat22<T> operator*(const mat22<T>&, typename math<T>::scalar_t); // multiply matrix by scalar
template<typename T> EGL_INLINE mat22<T> operator*(typename math<T>::scalar_t, const mat22<T>&); // multiply matrix by scalar
template<typename T> EGL_INLINE mat22<T> operator/(const mat22<T>&, typename math<T>::scalar_t); // divide matrix by scalar
template<typename T> EGL_INLINE mat22<T> mul(const mat22<T> &m0_, const mat22<T> &m1_); // component-wise multiply: m0_*m1_
template<typename T> EGL_INLINE mat22<T> madd(const mat22<T> &m0_, // component-wise multiply-add: m0_*m1+m2_
const mat22<T> &m1_,
const mat22<T> &m2_);
template<typename T> EGL_INLINE mat22<T> madd(const mat22<T> &m_, // matrix-scalar-scalar multiply-add: m_*mul_+add_
typename math<T>::scalar_t mul_,
typename math<T>::scalar_t add_);
template<typename T> EGL_INLINE mat22<T> madd(const mat22<T> &m_, // matrix-matrix-scalar multiply-add: m_*mul_+add_
const mat22<T> &mul_,
typename math<T>::scalar_t add_);
template<typename T> EGL_INLINE mat22<T> madd(const mat22<T> &m_, // matrix-scalar-matrix multiply-add: m_*mul_+add_
typename math<T>::scalar_t mul_,
const mat22<T> &add_);
template<typename T> EGL_INLINE typename math<T>::scalar_t det(const mat22<T>&); // determinant of the matrix
template<typename T> EGL_INLINE mat22<T> inv(const mat22<T>&, typename math<T>::scalar_t *det_=0);// inverse of the matrix
template<typename T> EGL_INLINE typename math<T>::scalar_t tr(const mat22<T>&); // trace of the matrix
template<typename T> EGL_INLINE void identity(mat22<T>&); // set matrix to identity
template<typename T> EGL_INLINE void transpose(mat22<T>&); // transpose of the matrix
template<typename T> EGL_INLINE void transpose(mat22<T> &res_, const mat22<T>&); // transpose of the matrix
template<typename T> EGL_INLINE void neg(mat22<T>&); // negate the matrix
template<typename T> EGL_INLINE mat22<T> lerp(const mat22<T> &m0_, // linear interpolation of matrices: f(t=0)=m0, f(t=1)=m1
const mat22<T> &m1_,
typename math<T>::scalar_t t_);
template<typename T> EGL_INLINE void lerp(mat22<T> &res_, // linear interpolation of matrices: f(t=0)=m0, f(t=1)=m1
const mat22<T> &m0_,
const mat22<T> &m1_,
typename math<T>::scalar_t t_);
template<typename T, typename U> EGL_INLINE mat22<T> to_mat22(const mat22<U>&); // convert between mat22 types
template<typename T> EGL_INLINE void normalize(mat22<T>&); // normalize matrix vectors
// 3x3 matrix ops
template<typename T> EGL_INLINE bool is_zero(const mat33<T>&); // test for zero-matrix, i.e. all components equal zero (exact)
template<typename T> EGL_INLINE bool is_orthogonal(const mat33<T>&); // test for orthogonal matrix
template<typename T> EGL_INLINE bool is_sat(const mat33<T>&); // test for saturated matrix, i.e. all components are in range [0, 1]
template<typename T> EGL_INLINE bool is_ssat(const mat33<T>&); // test for signed saturated matrix, i.e. all components are in range [-1, 1]
template<typename T> EGL_INLINE bool operator==(const mat33<T>&, const mat33<T>&); // test for equality of matrices, i.e. all components of the matrices are equal (exact)
template<typename T> EGL_INLINE bool operator==(const mat33<T>&, typename math<T>::scalar_t); // test for equality of matrix and scalar, i.e. all components of the matrix equals the scalar (exact)
template<typename T> EGL_INLINE bool operator==(typename math<T>::scalar_t, const mat33<T>&); // test for equality of matrix and scalar, i.e. all components of the matrix equals the scalar (exact)
template<typename T> EGL_INLINE bool operator!=(const mat33<T>&, const mat33<T>&); // test for inequality of matrices, i.e. any of the components of the vectors are unequal (exact)
template<typename T> EGL_INLINE bool operator!=(const mat33<T>&, typename math<T>::scalar_t); // test for inequality of matrix and scalar, i.e. any of the components of the matrix is unequal to the scalar (exact)
template<typename T> EGL_INLINE bool operator!=(typename math<T>::scalar_t, const mat33<T>&); // test for inequality of matrix and scalar, i.e. any of the components of the matrix is unequal to the scalar (exact)
template<typename T> EGL_INLINE void operator+=(mat33<T>&, const mat33<T>&); // add matrix to matrix
template<typename T> EGL_INLINE void operator+=(mat33<T>&, typename math<T>::scalar_t); // add scalar to matrix
template<typename T> EGL_INLINE void operator-=(mat33<T>&, const mat33<T>&); // subtract matrix from matrix
template<typename T> EGL_INLINE void operator-=(mat33<T>&, typename math<T>::scalar_t); // subtract scalar from matrix
template<typename T> EGL_INLINE void operator*=(mat33<T>&, const mat33<T>&); // multiply matrix by matrix
template<typename T> EGL_INLINE void operator*=(mat33<T>&, const quat<T>&); // multiply matrix by quaternion
template<typename T> EGL_INLINE void operator*=(mat33<T>&, typename math<T>::scalar_t); // multiply matrix by scalar
template<typename T> EGL_INLINE void operator/=(mat33<T>&, typename math<T>::scalar_t); // divide matrix by scalar
template<typename T> EGL_INLINE mat33<T> operator+(const mat33<T>&, const mat33<T>&); // add matrix to matrix
template<typename T> EGL_INLINE mat33<T> operator+(const mat33<T>&, typename math<T>::scalar_t); // add scalar to matrix
template<typename T> EGL_INLINE mat33<T> operator+(typename math<T>::scalar_t, const mat33<T>&); // add matrix to scalar
template<typename T> EGL_INLINE mat33<T> operator-(const mat33<T>&, const mat33<T>&); // subtract matrix from matrix
template<typename T> EGL_INLINE mat33<T> operator-(const mat33<T>&, typename math<T>::scalar_t); // subtract scalar from matrix
template<typename T> EGL_INLINE mat33<T> operator-(typename math<T>::scalar_t, const mat33<T>&); // subtract matrix from scalar
template<typename T> EGL_INLINE mat33<T> operator-(const mat33<T>&); // negate the matrix
template<typename T> EGL_INLINE mat33<T> operator*(const mat33<T>&, const mat33<T>&); // multiply matrix by matrix
template<typename T> EGL_INLINE mat33<T> operator*(const mat33<T>&, const quat<T>&); // multiply matrix by quaternion
template<typename T> EGL_INLINE mat33<T> operator*(const quat<T>&, const mat33<T>&); // multiply quaternion by matrix
template<typename T> EGL_INLINE mat33<T> operator*(const mat33<T>&, typename math<T>::scalar_t); // multiply matrix by scalar
template<typename T> EGL_INLINE mat33<T> operator*(typename math<T>::scalar_t, const mat33<T>&); // multiply matrix by scalar
template<typename T> EGL_INLINE mat33<T> operator/(const mat33<T>&, typename math<T>::scalar_t); // divide matrix by scalar
template<typename T> EGL_INLINE mat33<T> mul(const mat33<T> &m0_, const mat33<T> &m1_); // component-wise multiply: m0_*m1_
template<typename T> EGL_INLINE mat33<T> madd(const mat33<T> &m0_, // component-wise multiply-add: m0_*m1+m2_
const mat33<T> &m1_,
const mat33<T> &m2_);
template<typename T> EGL_INLINE mat33<T> madd(const mat33<T> &m_, // matrix-scalar-scalar multiply-add: m_*mul_+add_
typename math<T>::scalar_t mul_,
typename math<T>::scalar_t add_);
template<typename T> EGL_INLINE mat33<T> madd(const mat33<T> &m_, // matrix-matrix-scalar multiply-add: m_*mul_+add_
const mat33<T> &mul_,
typename math<T>::scalar_t add_);
template<typename T> EGL_INLINE mat33<T> madd(const mat33<T> &m_, // matrix-scalar-matrix multiply-add: m_*mul_+add_
typename math<T>::scalar_t mul_,
const mat33<T> &add_);
template<typename T> EGL_INLINE typename math<T>::scalar_t det(const mat33<T>&); // determinant of the matrix
template<typename T> EGL_INLINE mat33<T> inv(const mat33<T>&, typename math<T>::scalar_t *det_=0);// inverse of the matrix
template<typename T> EGL_INLINE typename math<T>::scalar_t tr(const mat33<T>&); // trace of the matrix
template<typename T> EGL_INLINE void identity(mat33<T>&); // set matrix to identity
template<typename T> EGL_INLINE void transpose(mat33<T>&); // transpose of the matrix
template<typename T> EGL_INLINE void transpose(mat33<T> &res_, const mat33<T>&); // transpose of the matrix
template<typename T> EGL_INLINE void neg(mat33<T>&); // negate the matrix
template<typename T> EGL_INLINE mat33<T> lerp(const mat33<T> &m0_, // linear interpolation of matrices: f(t=0)=m0, f(t=1)=m1
const mat33<T> &m1_,
typename math<T>::scalar_t t_);
template<typename T> EGL_INLINE void lerp(mat33<T> &res_, // linear interpolation of matrices: f(t=0)=m0, f(t=1)=m1
const mat33<T> &m0_,
const mat33<T> &m1_,
typename math<T>::scalar_t t_);
template<typename T, typename U> EGL_INLINE mat33<T> to_mat33(const mat33<U>&); // convert between mat33 types
template<typename T> EGL_INLINE void normalize(mat33<T>&); // normalize matrix vectors
template<typename T> EGL_INLINE void orthonormalize(mat33<T>&); // ortho-normalize the matrix
template<typename T> EGL_INLINE void set_rotation_xyz(mat33<T>&, // set rotation matrix with angles in order Rx*Ry*Rz
typename math<T>::scalar_t x_,
typename math<T>::scalar_t y_,
typename math<T>::scalar_t z_);
template<typename T> EGL_INLINE void set_rotation_zyx(mat33<T>&, // set rotation matrix with angles in order Rz*Ry*Rx
typename math<T>::scalar_t x_,
typename math<T>::scalar_t y_,
typename math<T>::scalar_t z_);
template<typename T> EGL_INLINE void set_rotation_zxz(mat33<T>&, // set rotation matrix with angles in order Rz*Rx*Rz (Euler)
typename math<T>::scalar_t x_,
typename math<T>::scalar_t z_);
// 4x4 matrix ops
template<typename T> EGL_INLINE bool is_zero(const mat44<T>&); // test for zero-matrix, i.e. all components equal zero (exact)
template<typename T> EGL_INLINE bool is_sat(const mat44<T>&); // test for saturated matrix, i.e. all components are in range [0, 1]
template<typename T> EGL_INLINE bool is_ssat(const mat44<T>&); // test for signed saturated matrix, i.e. all components are in range [-1, 1]
template<typename T> EGL_INLINE bool operator==(const mat44<T>&, const mat44<T>&); // test for equality of matrices, i.e. all components of the matrices are equal (exact)
template<typename T> EGL_INLINE bool operator==(const mat44<T>&, typename math<T>::scalar_t); // test for equality of matrix and scalar, i.e. all components of the matrix equals the scalar (exact)
template<typename T> EGL_INLINE bool operator==(typename math<T>::scalar_t, const mat44<T>&); // test for equality of matrix and scalar, i.e. all components of the matrix equals the scalar (exact)
template<typename T> EGL_INLINE bool operator!=(const mat44<T>&, const mat44<T>&); // test for inequality of matrices, i.e. any of the components of the vectors are unequal (exact)
template<typename T> EGL_INLINE bool operator!=(const mat44<T>&, typename math<T>::scalar_t); // test for inequality of matrix and scalar, i.e. any of the components of the matrix is unequal to the scalar (exact)
template<typename T> EGL_INLINE bool operator!=(typename math<T>::scalar_t, const mat44<T>&); // test for inequality of matrix and scalar, i.e. any of the components of the matrix is unequal to the scalar (exact)
template<typename T> EGL_INLINE void operator+=(mat44<T>&, const mat44<T>&); // add matrix to matrix
template<typename T> EGL_INLINE void operator+=(mat44<T>&, typename math<T>::scalar_t); // add scalar to matrix
template<typename T> EGL_INLINE void operator-=(mat44<T>&, const mat44<T>&); // subtract matrix from matrix
template<typename T> EGL_INLINE void operator-=(mat44<T>&, typename math<T>::scalar_t); // subtract scalar from matrix
template<typename T> EGL_INLINE void operator*=(mat44<T>&, const mat44<T>&); // multiply matrix by matrix
template<typename T> EGL_INLINE void operator*=(mat44<T>&, typename math<T>::scalar_t); // multiply matrix by scalar
template<typename T> EGL_INLINE void operator/=(mat44<T>&, typename math<T>::scalar_t); // divide matrix by scalar
template<typename T> EGL_INLINE mat44<T> operator+(const mat44<T>&, const mat44<T>&); // add matrix to matrix
template<typename T> EGL_INLINE mat44<T> operator+(const mat44<T>&, typename math<T>::scalar_t); // add scalar to matrix
template<typename T> EGL_INLINE mat44<T> operator+(typename math<T>::scalar_t, const mat44<T>&); // add matrix to scalar
template<typename T> EGL_INLINE mat44<T> operator-(const mat44<T>&, const mat44<T>&); // subtract matrix from matrix
template<typename T> EGL_INLINE mat44<T> operator-(const mat44<T>&, typename math<T>::scalar_t); // subtract scalar from matrix
template<typename T> EGL_INLINE mat44<T> operator-(typename math<T>::scalar_t, const mat44<T>&); // subtract matrix from scalar
template<typename T> EGL_INLINE mat44<T> operator-(const mat44<T>&); // negate the matrix
template<typename T> EGL_INLINE mat44<T> operator*(const mat44<T>&, const mat44<T>&); // multiply matrix by matrix
template<typename T> EGL_INLINE mat44<T> operator*(const mat44<T>&, typename math<T>::scalar_t); // multiply matrix by scalar
template<typename T> EGL_INLINE mat44<T> operator*(typename math<T>::scalar_t, const mat44<T>&); // multiply matrix by scalar
template<typename T> EGL_INLINE mat44<T> operator/(const mat44<T>&, typename math<T>::scalar_t); // divide matrix by scalar
template<typename T> EGL_INLINE mat44<T> mul(const mat44<T> &m0_, const mat44<T> &m1_); // component-wise multiply: m0_*m1_
template<typename T> EGL_INLINE mat44<T> madd(const mat44<T> &m0_, // component-wise multiply-add: m0_*m1+m2_
const mat44<T> &m1_,
const mat44<T> &m2_);
template<typename T> EGL_INLINE mat44<T> madd(const mat44<T> &m_, // matrix scalar multiply-add: v_*mul_+add_
typename math<T>::scalar_t mul_,
typename math<T>::scalar_t add_);
template<typename T> EGL_INLINE mat44<T> madd(const mat44<T> &m_, // matrix-matrix-scalar multiply-add: m_*mul_+add_
const mat44<T> &mul_,
typename math<T>::scalar_t add_);
template<typename T> EGL_INLINE mat44<T> madd(const mat44<T> &m_, // matrix-scalar-matrix multiply-add: m_*mul_+add_
typename math<T>::scalar_t mul_,
const mat44<T> &add_);
template<typename T> EGL_INLINE typename math<T>::scalar_t det(const mat44<T>&); // determinant of the matrix
template<typename T> EGL_INLINE mat44<T> inv(const mat44<T>&, typename math<T>::scalar_t *det_=0);// inverse of the matrix
template<typename T> EGL_INLINE typename math<T>::scalar_t tr(const mat44<T>&); // trace of the matrix
template<typename T> EGL_INLINE void identity(mat44<T>&); // set matrix to identity
template<typename T> EGL_INLINE void transpose(mat44<T>&); // transpose of the matrix
template<typename T> EGL_INLINE void transpose(mat44<T> &res_, const mat44<T>&); // transpose of the matrix
template<typename T> EGL_INLINE void neg(mat44<T>&); // negate the matrix
template<typename T> EGL_INLINE mat44<T> lerp(const mat44<T> &m0_, // linear interpolation of matrices: f(t=0)=m0, f(t=1)=m1
const mat44<T> &m1_,
typename math<T>::scalar_t t_);
template<typename T> EGL_INLINE void lerp(mat44<T> &res_, // linear interpolation of matrices: f(t=0)=m0, f(t=1)=m1
const mat44<T> &m0_,
const mat44<T> &m1_,
typename math<T>::scalar_t t_);
template<typename T> EGL_INLINE void normalize(mat44<T>&); // normalize matrix vectors
template<typename T, typename U> EGL_INLINE mat44<T> to_mat44(const mat44<U>&); // convert between mat44 types
// quaternion ops
template<typename T> EGL_INLINE bool is_zero(const quat<T>&); // test for zero-quaternion, i.e. all components equal zero (exact)
template<typename T> EGL_INLINE bool is_sat(const quat<T>&); // test for saturated quaternion, i.e. all components are in range [0, 1]
template<typename T> EGL_INLINE bool is_ssat(const quat<T>&); // test for signed saturated quaternion, i.e. all components are in range [-1, 1]
template<typename T> EGL_INLINE bool operator==(const quat<T>&, const quat<T>&); // test for equality of quaternions, i.e. all components of the quaternions are equal (exact)
template<typename T> EGL_INLINE bool operator==(const quat<T>&, typename math<T>::scalar_t); // test for equality of quaternion and scalar, i.e. all components of the quaternion equals the scalar (exact)
template<typename T> EGL_INLINE bool operator==(typename math<T>::scalar_t, const quat<T>&); // test for equality of quaternion and scalar, i.e. all components of the quaternion equals the scalar (exact)
template<typename T> EGL_INLINE bool operator!=(const quat<T>&, const quat<T>&); // test for inequality of quaternions, i.e. any of the components of the quaternions are unequal (exact)
template<typename T> EGL_INLINE bool operator!=(const quat<T>&, typename math<T>::scalar_t); // test for inequality of quaternion and scalar, i.e. any of the components of the quaternion is unequal to the scalar (exact)
template<typename T> EGL_INLINE bool operator!=(typename math<T>::scalar_t, const quat<T>&); // test for inequality of quaternion and scalar, i.e. any of the components of the quaternion is unequal to the scalar (exact)
template<typename T> EGL_INLINE quat<T> operator<(const quat<T>&, const quat<T>&); // component-wise quaternion less-than comparison (false=0, true=1)
template<typename T> EGL_INLINE quat<T> operator<(const quat<T>&, typename math<T>::scalar_t); // component-wise quaternion less-than comparison (false=0, true=1)
template<typename T> EGL_INLINE quat<T> operator<(typename math<T>::scalar_t, const quat<T>&); // component-wise quaternion less-than comparison (false=0, true=1)
template<typename T> EGL_INLINE quat<T> operator>(const quat<T>&, const quat<T>&); // component-wise quaternion greater-than comparison (false=0, true=1)
template<typename T> EGL_INLINE quat<T> operator>(const quat<T>&, typename math<T>::scalar_t); // component-wise quaternion greater-than comparison (false=0, true=1)
template<typename T> EGL_INLINE quat<T> operator>(typename math<T>::scalar_t, const quat<T>&); // component-wise quaternion greater-than comparison (false=0, true=1)
template<typename T> EGL_INLINE quat<T> operator<=(const quat<T>&, const quat<T>&); // component-wise quaternion less-or-equal comparison (false=0, true=1)
template<typename T> EGL_INLINE quat<T> operator<=(const quat<T>&, typename math<T>::scalar_t); // component-wise quaternion less-or-equal comparison (false=0, true=1)
template<typename T> EGL_INLINE quat<T> operator<=(typename math<T>::scalar_t, const quat<T>&); // component-wise quaternion less-or-equal comparison (false=0, true=1)
template<typename T> EGL_INLINE quat<T> operator>=(const quat<T>&, const quat<T>&); // component-wise quaternion greater-or-equal comparison (false=0, true=1)
template<typename T> EGL_INLINE quat<T> operator>=(const quat<T>&, typename math<T>::scalar_t); // component-wise quaternion greater-or-equal comparison (false=0, true=1)
template<typename T> EGL_INLINE quat<T> operator>=(typename math<T>::scalar_t, const quat<T>&); // component-wise quaternion greater-or-equal comparison (false=0, true=1)
template<typename T> EGL_INLINE quat<T> sel_eq(const quat<T> &t0_, const quat<T> &t1_, // component-wise equal quaternion select (t0_==t1_?q0_:q1_)
const quat<T> &q0_, const quat<T> &q1_);
template<typename T> EGL_INLINE quat<T> sel_lt(const quat<T> &t0_, const quat<T> &t1_, // component-wise less-than quaternion select (t0_<t1_?q0_:q1_)
const quat<T> &q0_, const quat<T> &q1_);
template<typename T> EGL_INLINE quat<T> sel_le(const quat<T> &t0_, const quat<T> &t1_, // component-wise less-or-equal quaternion select (t0_<=t1_?q0_:q1_)
const quat<T> &q0_, const quat<T> &q1_);
template<typename T> EGL_INLINE quat<T> sel_eqz(const quat<T> &t_, // component-wise equal-to-zero quaternion select (t_==0?q0_:q1_)
const quat<T> &q0_, const quat<T> &q1_);
template<typename T> EGL_INLINE quat<T> sel_ltz(const quat<T> &t_, // component-wise less-than-zero quaternion select (t_<0?q0_:q1_)
const quat<T> &q0_, const quat<T> &q1_);
template<typename T> EGL_INLINE quat<T> sel_lez(const quat<T> &t_, // component-wise less-or-equal-to-zero quaternion select (t_<=0?q0_:q1_)
const quat<T> &q0_, const quat<T> &q1_);
template<typename T> EGL_INLINE void operator+=(quat<T>&, const quat<T>&); // add quaternion to quaternion
template<typename T> EGL_INLINE void operator+=(quat<T>&, typename math<T>::scalar_t); // add scalar to each component of the quaternion
template<typename T> EGL_INLINE void operator-=(quat<T>&, const quat<T>&); // subtract quaternion from quaternion
template<typename T> EGL_INLINE void operator-=(quat<T>&, typename math<T>::scalar_t); // subtract scalar from each component of the quaternion
template<typename T> EGL_INLINE void operator*=(quat<T>&, const quat<T>&); // multiply quaternion by quaternion
template<typename T> EGL_INLINE void operator*=(quat<T>&, typename math<T>::scalar_t); // quaternion by scalar multiplication
template<typename T> EGL_INLINE void operator/=(quat<T>&, typename math<T>::scalar_t); // quaternion by scalar division
template<typename T> EGL_INLINE quat<T> operator+(const quat<T>&, const quat<T>&); // add quaternion to quaternion
template<typename T> EGL_INLINE quat<T> operator+(const quat<T>&, typename math<T>::scalar_t); // add scalar to each component of the quaternion
template<typename T> EGL_INLINE quat<T> operator+(typename math<T>::scalar_t, const quat<T>&); // add each component of the quaternion to a scalar quaternion
template<typename T> EGL_INLINE quat<T> operator-(const quat<T>&, const quat<T>&); // subtract quaternion from quaternion
template<typename T> EGL_INLINE quat<T> operator-(const quat<T>&, typename math<T>::scalar_t); // subtract scalar from each component of the quaternion
template<typename T> EGL_INLINE quat<T> operator-(typename math<T>::scalar_t, const quat<T>&); // subtract each component of the quaternion from a scalar quaternion
template<typename T> EGL_INLINE quat<T> operator-(const quat<T>&); // negate the quaternion
template<typename T> EGL_INLINE quat<T> operator*(const quat<T>&, const quat<T>&); // multiply quaternion by quaternion
template<typename T> EGL_INLINE quat<T> operator*(const quat<T>&, typename math<T>::scalar_t); // quaternion by scalar multiplication
template<typename T> EGL_INLINE quat<T> operator*(typename math<T>::scalar_t, const quat<T>&); // quaternion by scalar multiplication
template<typename T> EGL_INLINE quat<T> operator/(const quat<T>&, typename math<T>::scalar_t); // quaternion by scalar division
template<typename T> EGL_INLINE typename math<T>::scalar_t min(const quat<T>&); // minimum component value
template<typename T> EGL_INLINE quat<T> min(const quat<T>&, const quat<T>&); // component-wise minimum of the quaternions
template<typename T> EGL_INLINE quat<T> min(const quat<T>&, const quat<T>&, const quat<T>&);
template<typename T> EGL_INLINE quat<T> min(const quat<T>&, const quat<T>&, const quat<T>&, const quat<T>&);
template<typename T> EGL_INLINE quat<T> min(const quat<T>&, typename math<T>::scalar_t); // component-wise minimum of the quaternion and scalar
template<typename T> EGL_INLINE quat<T> min(typename math<T>::scalar_t, const quat<T>&); // component-wise minimum of the quaternion and scalar
template<typename T> EGL_INLINE typename math<T>::scalar_t max(const quat<T>&); // maximum component value
template<typename T> EGL_INLINE quat<T> max(const quat<T>&, const quat<T>&); // component-wise maximum of the quaternions
template<typename T> EGL_INLINE quat<T> max(const quat<T>&, const quat<T>&, const quat<T>&);
template<typename T> EGL_INLINE quat<T> max(const quat<T>&, const quat<T>&, const quat<T>&, const quat<T>&);
template<typename T> EGL_INLINE quat<T> max(const quat<T>&, typename math<T>::scalar_t); // component-wise maximum of the quaternion and scalar
template<typename T> EGL_INLINE quat<T> max(typename math<T>::scalar_t, const quat<T>&); // component-wise maximum of the quaternion and scalar
template<typename T> EGL_INLINE quat<T> mul(const quat<T> &q0_, const quat<T> &q1_); // component-wise multiply: q0_*q1_
template<typename T> EGL_INLINE quat<T> madd(const quat<T> &q0_, // component-wise multiply-add: q0_*q1+q2_
const quat<T> &q1_,
const quat<T> &q2_);
template<typename T> EGL_INLINE quat<T> madd(const quat<T> &q_, // quaternion-scalar-scalar multiply-add: q_*mul_+add_
typename math<T>::scalar_t mul_,
typename math<T>::scalar_t add_);
template<typename T> EGL_INLINE quat<T> madd(const quat<T> &q_, // quaternion-quaternion-scalar multiply-add: q_*mul_+add_
const quat<T> &mul_,
typename math<T>::scalar_t add_);
template<typename T> EGL_INLINE quat<T> madd(const quat<T> &q_, // quaternion-scalar-quaternion multiply-add: q_*mul_+add_
typename math<T>::scalar_t mul_,
const quat<T> &add_);
template<typename T> EGL_INLINE quat<T> rcp(const quat<T>&); // component-wise quaternion reciprocal
template<typename T> EGL_INLINE quat<T> rcp_z(const quat<T>&); // component-wise quaternion reciprocal (set 0 for 0 components)
template<typename T> EGL_INLINE quat<T> floor(const quat<T>&); // component-wise greatest integer less than or equal to the value
template<typename T> EGL_INLINE quat<T> ceil(const quat<T>&); // component-wise smallest integer greater than or equal to the value
template<typename T> EGL_INLINE quat<T> trunc(const quat<T>&); // component-wise truncate decimal part from the value
template<typename T> EGL_INLINE quat<T> frc(const quat<T>&); // component-wise fractional part (for negative values returns 1-fractional part)
template<typename T> EGL_INLINE quat<T> mod(const quat<T>&, typename math<T>::scalar_t div_); // component-wise modulo
template<typename T> EGL_INLINE quat<T> cycle(const quat<T>&, typename math<T>::scalar_t cycle_); // component-wise cycle
template<typename T> EGL_INLINE quat<T> cycle1(const quat<T>&); // component-wise cycle1
template<typename T> EGL_INLINE quat<T> sat(const quat<T>&); // component-wise quaternion saturate
template<typename T> EGL_INLINE quat<T> ssat(const quat<T>&); // component-wise quaternion signed saturate
template<typename T> EGL_INLINE quat<T> clamp(const quat<T>&, // component-wise clamp of the quaternion
const quat<T> &min_,
const quat<T> &max_);
template<typename T> EGL_INLINE quat<T> clamp(const quat<T>&, // component-wise clamp of the quaternion with scalars
typename math<T>::scalar_t min_,
typename math<T>::scalar_t max_);
template<typename T> EGL_INLINE quat<T> abs(const quat<T>&); // component-wise quaternion absolute
template<typename T> EGL_INLINE quat<T> sgn(const quat<T>&); // component-wise signum (neg=-1, pos=+1, zero=0)
template<typename T> EGL_INLINE quat<T> sgn_zp(const quat<T>&); // component-wise signum (neg=-1, pos&zero=+1)
template<typename T> EGL_INLINE quat<T> sqr(const quat<T>&); // component-wise square: x*x
template<typename T> EGL_INLINE quat<T> cubic(const quat<T>&); // component-wise cubic: x*x*x
template<typename T> EGL_INLINE quat<T> sqrt(const quat<T>&); // component-wise quaternion square root
template<typename T> EGL_INLINE quat<T> sqrt_z(const quat<T>&); // component-wise quaternion square root (set 0 for components less than zero)
template<typename T> EGL_INLINE quat<T> cbrt(const quat<T>&); // component-wise cubic root
template<typename T> EGL_INLINE quat<T> rsqrt(const quat<T>&); // component-wise quaternion reciprocal square root
template<typename T> EGL_INLINE quat<T> rsqrt_z(const quat<T>&); // component-wise quaternion reciprocal square root (set 0 for components less than or equal to zero)
template<typename T> EGL_INLINE quat<T> rcbrt(const quat<T>&); // component-wise reciprocal cubic root
template<typename T> EGL_INLINE quat<T> rcbrt_z(const quat<T>&); // component-wise reciprocal cubic root (set 0 for components that are 0)
template<typename T> EGL_INLINE typename math<T>::scalar_t norm(const quat<T>&); // quaternion norm (length): |q|
template<typename T> EGL_INLINE typename math<T>::scalar_t rnorm(const quat<T>&); // reciprocal of the quaternion norm: 1/|q|
template<typename T> EGL_INLINE typename math<T>::scalar_t rnorm_z(const quat<T>&); // reciprocal of the quaternion norm: 1/|q| (return 0 if |q|=0)
template<typename T> EGL_INLINE typename math<T>::scalar_t norm2(const quat<T>&); // squared quaternion norm: |q|^2
template<typename T> EGL_INLINE typename math<T>::scalar_t rnorm2(const quat<T>&); // reciprocal of the squared vector norm: 1/|q|^2
template<typename T> EGL_INLINE typename math<T>::scalar_t rnorm2_z(const quat<T>&); // reciprocal of the squared vector norm: 1/|q|^2 (return 0 if |q|=0)
template<typename T> EGL_INLINE quat<T> unit(const quat<T>&); // unit quaternion of the quaternion: q/|q|
template<typename T> EGL_INLINE quat<T> unit_z(const quat<T>&); // unit quaternion of the quaternion (if |q|=0, return q=[v=0, w=1])
template<typename T> EGL_INLINE typename math<T>::scalar_t dot(const quat<T>&, const quat<T>&); // quaternion dot-product
template<typename T> EGL_INLINE typename math<T>::scalar_t dot1(const quat<T>&); // quaternion dot-product with quaternion [1, 1, 1, 1] (component sum)
template<typename T> EGL_INLINE quat<T> cross(const quat<T>&, const quat<T>&); // cross-product of quaternions (or odd/Grassman outer product): q=[v0 x v1, 0]
template<typename T> EGL_INLINE quat<T> outer(const quat<T>&, const quat<T>&); // Euclidean outer-product of quaternions: q=[w0*v1-w1*v0-(v0 x v1), 0]
template<typename T> EGL_INLINE quat<T> even(const quat<T>&, const quat<T>&); // even-product (Grassman inner product) of quaternions: q=[w0*v1+w1*v0, w0*w1-dot(v0, v1)]
template<typename T> EGL_INLINE quat<T> conj(const quat<T>&); // conjugate of the quaternion
template<typename T> EGL_INLINE quat<T> inv(const quat<T>&); // inverse of the quaternion
template<typename T> EGL_INLINE quat<T> inv_u(const quat<T>&); // inverse of the unit quaternion
template<typename T> EGL_INLINE quat<T> exp(const quat<T>&); // natural exponent of the quaternion
template<typename T> EGL_INLINE quat<T> exp_u(const quat<T>&); // natural exponent of the unit quaternion
template<typename T> EGL_INLINE quat<T> ln(const quat<T>&); // natural logarithm of the quaternion
template<typename T> EGL_INLINE quat<T> ln_u(const quat<T>&); // natural logarithm of the unit quaternion
template<typename T> EGL_INLINE quat<T> pow(const quat<T>&, typename math<T>::scalar_t); // rise quaternion to a power
template<typename T> EGL_INLINE quat<T> pow_u(const quat<T>&, typename math<T>::scalar_t); // rise unit quaternion to a power
template<typename T> EGL_INLINE typename math<T>::scalar_t arg(const quat<T>&); // argument of the quaternion
template<typename T> EGL_INLINE typename math<T>::scalar_t arg_u(const quat<T>&); // argument of the unit quaternion
template<typename T> EGL_INLINE void neg(quat<T>&); // negate the quaternion
template<typename T, class Rng> EGL_INLINE void rand_u(quat<T>&, Rng&); // random unit quaternion
template<typename T, class Rng> EGL_INLINE void rand_real1(quat<T>&, Rng&); // random quaternion where each component is in range [-1, 1]
template<typename T, class Rng> EGL_INLINE void rand_ureal1(quat<T>&, Rng&); // random quaternion where each component is in range [0, 1]
template<typename T> EGL_INLINE quat<T> smoothstep(const quat<T>&); // component-wise smoothstep function
template<typename T> EGL_INLINE quat<T> smootherstep(const quat<T>&); // component-wise smootherstep function
template<typename T> EGL_INLINE quat<T> lerp(const quat<T> &q0_, // linear interpolation of quaternions: f(t=0)=v0, f(t=1)=v1
const quat<T> &q1_,
typename math<T>::scalar_t t_);
template<typename T> EGL_INLINE quat<T> nlerp(const quat<T> &q0_, // normalized linear quaternion interpolation: f(t=0)=q0/|q0|, f(t=1)=q1/|q1|
const quat<T> &q1_,
typename math<T>::scalar_t t_);
template<typename T> EGL_INLINE quat<T> nlerp_z(const quat<T> &q0_, // normalized linear quaternion interpolation: f(t=0)=q0/|q0|, f(t=1)=q1/|q1|. if |q|=0, return q=[v=0, w=1]
const quat<T> &q1_,
typename math<T>::scalar_t t_);
template<typename T> EGL_INLINE quat<T> slerp(const quat<T> &q0_, // spherical linear quaternion interpolation: f(t=0)=q0, f(t=1)=q1
const quat<T> &q1_,
typename math<T>::scalar_t t_);
template<typename T> EGL_INLINE quat<T> rot_u(const vec3<T> &src_, const vec3<T> &dst_); // generate quaternion rotation from unit source direction to unit destination direction
template<typename T> EGL_INLINE quat<T> zrot_u(const vec3<T> &dst_); // generate quaternion rotation from z-direction to unit destination direction
template<typename T> EGL_INLINE quat<T> axis_rot(const vec3<T> &axis_, // generate quaternion rotation from axis and angle (radians)
typename math<T>::scalar_t angle_);
template<typename T> EGL_INLINE quat<T> axis_rot_u(const vec3<T> &axis_, // generate quaternion rotation from unit axis and angle (radians)
typename math<T>::scalar_t angle_);
template<typename T> void convert_u(mat33<T>&, const quat<T>&); // convert unit quaternion to left handed row-major 3x3 rotation matrix
template<typename T> void convert(mat33<T>&, const quat<T>&); // convert (possibly non-unit) quaternion to left handed row-major 3x3 rotation matrix
template<typename T> void convert(quat<T>&, const mat33<T>&); // convert left handed row-major 3x3 rotation matrix to quaternion
template<typename T, typename U> EGL_INLINE quat<T> to_quat(const quat<U>&); // convert between quat types
template<unsigned shuffle_, typename T> EGL_INLINE quat<T> shuffle(const quat<T>&); // shuffle quaternion components (e.g. shuffle<2311>(q_) == quatf(v_.z, v_.w, v_.y, v_.y))
template<typename T> EGL_INLINE void pack_s1(quat_32s&, const quat<T>&); // pack quat (components in range [-1, 1]) to 32-bit quat