source: trunk/src/lol/math/matrix.h @ 1117

Last change on this file since 1117 was 1117, checked in by sam, 11 years ago

math: move the Remez algorithm implementation to the core.

  • Property svn:keywords set to Id
File size: 16.7 KB
Line 
1//
2// Lol Engine
3//
4// Copyright: (c) 2010-2011 Sam Hocevar <sam@hocevar.net>
5//   This program is free software; you can redistribute it and/or
6//   modify it under the terms of the Do What The Fuck You Want To
7//   Public License, Version 2, as published by Sam Hocevar. See
8//   http://sam.zoy.org/projects/COPYING.WTFPL for more details.
9//
10
11//
12// The Matrix classes
13// ------------------
14//
15
16#if !defined __LOL_MATH_MATRIX_H__
17#define __LOL_MATH_MATRIX_H__
18
19#include <cmath>
20#if !defined __ANDROID__
21#   include <iostream>
22#endif
23
24namespace lol
25{
26
27class half;
28class real;
29
30#define VECTOR_TYPES(tname, suffix) \
31    template <typename T> struct tname; \
32    typedef tname<half> f16##suffix; \
33    typedef tname<float> suffix; \
34    typedef tname<double> f64##suffix; \
35    typedef tname<int8_t> i8##suffix; \
36    typedef tname<uint8_t> u8##suffix; \
37    typedef tname<int16_t> i16##suffix; \
38    typedef tname<uint16_t> u16##suffix; \
39    typedef tname<int32_t> i##suffix; \
40    typedef tname<uint32_t> u##suffix; \
41    typedef tname<int64_t> i64##suffix; \
42    typedef tname<uint64_t> u64##suffix;
43
44VECTOR_TYPES(Vec2, vec2)
45VECTOR_TYPES(Cmplx, cmplx)
46VECTOR_TYPES(Vec3, vec3)
47VECTOR_TYPES(Vec4, vec4)
48VECTOR_TYPES(Quat, quat)
49VECTOR_TYPES(Mat4, mat4)
50
51#define VECTOR_OP(op) \
52    inline type_t operator op(type_t const &val) const \
53    { \
54        type_t ret; \
55        for (size_t n = 0; n < sizeof(*this) / sizeof(T); n++) \
56            ret[n] = (*this)[n] op val[n]; \
57        return ret; \
58    } \
59    \
60    inline type_t operator op##=(type_t const &val) \
61    { \
62        return *this = (*this) op val; \
63    }
64
65#define BOOL_OP(op, op2, ret) \
66    inline bool operator op(type_t const &val) const \
67    { \
68        for (size_t n = 0; n < sizeof(*this) / sizeof(T); n++) \
69            if (!((*this)[n] op2 val[n])) \
70                return !ret; \
71        return ret; \
72    }
73
74#define SCALAR_OP(op) \
75    inline type_t operator op(T const &val) const \
76    { \
77        type_t ret; \
78        for (size_t n = 0; n < sizeof(*this) / sizeof(T); n++) \
79            ret[n] = (*this)[n] op val; \
80        return ret; \
81    } \
82    \
83    inline type_t operator op##=(T const &val) \
84    { \
85        return *this = (*this) op val; \
86    }
87
88#define LINEAR_OPS() \
89    inline T& operator[](int n) { return *(&x + n); } \
90    inline T const& operator[](int n) const { return *(&x + n); } \
91    \
92    VECTOR_OP(-) \
93    VECTOR_OP(+) \
94    \
95    BOOL_OP(==, ==, true) \
96    BOOL_OP(!=, ==, false) \
97    \
98    SCALAR_OP(*) \
99    SCALAR_OP(/) \
100    \
101    inline type_t operator -() const \
102    { \
103        type_t ret; \
104        for (size_t n = 0; n < sizeof(*this) / sizeof(T); n++) \
105            ret[n] = -(*this)[n]; \
106        return ret; \
107    } \
108    \
109    inline T sqlen() const \
110    { \
111        T acc = 0; \
112        for (size_t n = 0; n < sizeof(*this) / sizeof(T); n++) \
113            acc += (*this)[n] * (*this)[n]; \
114        return acc; \
115    } \
116    \
117    inline double len() const \
118    { \
119        using namespace std; \
120        return sqrt((double)sqlen()); \
121    } \
122    \
123    void printf() const;
124
125#define COMPLEX_OPS() \
126    inline type_t operator *(type_t const &val) const \
127    { \
128        return type_t(x * val.x - y * val.y, x * val.y + y * val.x); \
129    } \
130    \
131    inline type_t operator *=(type_t const &val) \
132    { \
133        return *this = (*this) * val; \
134    } \
135    \
136    inline type_t operator ~() const \
137    { \
138        return type_t(x, -y); \
139    } \
140    \
141    inline T norm() const { return len(); }
142
143#define QUATERNION_OPS() \
144    inline type_t operator *(type_t const &val) const \
145    { \
146        type_t ret; \
147        Vec3<T> v1(x, y, z); \
148        Vec3<T> v2(val.x, val.y, val.z); \
149        Vec3<T> v3 = cross(v1, v2) + w * v2 + val.w * v1; \
150        ret.x = v3.x; \
151        ret.y = v3.y; \
152        ret.z = v3.z; \
153        ret.w = w * val.w - dot(v1, v2); \
154        return ret; \
155    } \
156    \
157    inline type_t operator *=(type_t const &val) \
158    { \
159        return *this = (*this) * val; \
160    } \
161    \
162    inline type_t operator ~() const \
163    { \
164        type_t ret; \
165        for (int n = 0; n < 3; n++) \
166            ret[n] = -(*this)[n]; \
167        ret[3] = (*this)[3]; \
168        return ret; \
169    } \
170    \
171    inline T norm() const { return sqlen(); }
172
173#define OTHER_OPS(tname) \
174    VECTOR_OP(*) \
175    VECTOR_OP(/) \
176    \
177    BOOL_OP(<=, <=, true) \
178    BOOL_OP(>=, >=, true) \
179    BOOL_OP(<, <, true) \
180    BOOL_OP(>, >, true) \
181    \
182    template<typename U> \
183    inline operator tname<U>() const \
184    { \
185        tname<U> ret; \
186        for (size_t n = 0; n < sizeof(*this) / sizeof(T); n++) \
187            ret[n] = static_cast<U>((*this)[n]); \
188        return ret; \
189    } \
190    \
191    template<typename U> \
192    friend U dot(tname<U>, tname<U>);
193
194#define SWIZZLE2(e1, e2) \
195    inline Vec2<T> e1##e2() const \
196    { \
197        return Vec2<T>(this->e1, this->e2); \
198    }
199
200#define SWIZZLE3(e1, e2, e3) \
201    inline Vec3<T> e1##e2##e3() const \
202    { \
203        return Vec3<T>(this->e1, this->e2, this->e3); \
204    }
205
206#define SWIZZLE4(e1, e2, e3, e4) \
207    inline Vec4<T> e1##e2##e3##e4() const \
208    { \
209        return Vec4<T>(this->e1, this->e2, this->e3, this->e4); \
210    }
211
212#define SWIZZLE22(e1) \
213    SWIZZLE2(e1, x); SWIZZLE2(e1, y);
214#define SWIZZLE23(e1) \
215    SWIZZLE2(e1, x); SWIZZLE2(e1, y); SWIZZLE2(e1, z);
216#define SWIZZLE24(e1) \
217    SWIZZLE2(e1, x); SWIZZLE2(e1, y); SWIZZLE2(e1, z); SWIZZLE2(e1, w);
218
219#define SWIZZLE32(e1, e2) \
220    SWIZZLE3(e1, e2, x); SWIZZLE3(e1, e2, y);
221#define SWIZZLE322(e1) \
222    SWIZZLE32(e1, x); SWIZZLE32(e1, y);
223#define SWIZZLE33(e1, e2) \
224    SWIZZLE3(e1, e2, x); SWIZZLE3(e1, e2, y); SWIZZLE3(e1, e2, z);
225#define SWIZZLE333(e1) \
226    SWIZZLE33(e1, x); SWIZZLE33(e1, y); SWIZZLE33(e1, z);
227#define SWIZZLE34(e1, e2) \
228    SWIZZLE3(e1, e2, x); SWIZZLE3(e1, e2, y); \
229    SWIZZLE3(e1, e2, z); SWIZZLE3(e1, e2, w);
230#define SWIZZLE344(e1) \
231    SWIZZLE34(e1, x); SWIZZLE34(e1, y); \
232    SWIZZLE34(e1, z); SWIZZLE34(e1, w);
233
234#define SWIZZLE42(e1, e2, e3) \
235    SWIZZLE4(e1, e2, e3, x); SWIZZLE4(e1, e2, e3, y);
236#define SWIZZLE422(e1, e2) \
237    SWIZZLE42(e1, e2, x); SWIZZLE42(e1, e2, y);
238#define SWIZZLE4222(e1) \
239    SWIZZLE422(e1, x); SWIZZLE422(e1, y);
240#define SWIZZLE43(e1, e2, e3) \
241    SWIZZLE4(e1, e2, e3, x); SWIZZLE4(e1, e2, e3, y); SWIZZLE4(e1, e2, e3, z);
242#define SWIZZLE433(e1, e2) \
243    SWIZZLE43(e1, e2, x); SWIZZLE43(e1, e2, y); SWIZZLE43(e1, e2, z);
244#define SWIZZLE4333(e1) \
245    SWIZZLE433(e1, x); SWIZZLE433(e1, y); SWIZZLE433(e1, z);
246#define SWIZZLE44(e1, e2, e3) \
247    SWIZZLE4(e1, e2, e3, x); SWIZZLE4(e1, e2, e3, y); \
248    SWIZZLE4(e1, e2, e3, z); SWIZZLE4(e1, e2, e3, w);
249#define SWIZZLE444(e1, e2) \
250    SWIZZLE44(e1, e2, x); SWIZZLE44(e1, e2, y); \
251    SWIZZLE44(e1, e2, z); SWIZZLE44(e1, e2, w);
252#define SWIZZLE4444(e1) \
253    SWIZZLE444(e1, x); SWIZZLE444(e1, y); SWIZZLE444(e1, z); SWIZZLE444(e1, w);
254
255/*
256 * 2-element vectors
257 */
258
259template <typename T> struct Vec2
260{
261    typedef Vec2<T> type_t;
262
263    inline Vec2() { }
264    explicit inline Vec2(T val) { x = y = val; }
265    inline Vec2(T _x, T _y) { x = _x; y = _y; }
266
267    LINEAR_OPS()
268    OTHER_OPS(Vec2)
269
270    SWIZZLE22(x); SWIZZLE22(y);
271    SWIZZLE322(x); SWIZZLE322(y);
272    SWIZZLE4222(x); SWIZZLE4222(y);
273
274#if !defined __ANDROID__
275    template<typename U>
276    friend std::ostream &operator<<(std::ostream &stream, Vec2<U> const &v);
277#endif
278
279    union { T x; T a; T i; };
280    union { T y; T b; T j; };
281};
282
283/*
284 * 2-element complexes
285 */
286
287template <typename T> struct Cmplx
288{
289    typedef Cmplx<T> type_t;
290
291    inline Cmplx() { }
292    inline Cmplx(T val) : x(val), y(0) { }
293    inline Cmplx(T _x, T _y) : x(_x), y(_y) { }
294
295    LINEAR_OPS()
296    COMPLEX_OPS()
297
298#if !defined __ANDROID__
299    template<typename U>
300    friend std::ostream &operator<<(std::ostream &stream, Cmplx<U> const &v);
301#endif
302
303    T x, y;
304};
305
306template<typename T>
307static inline Cmplx<T> re(Cmplx<T> const &val)
308{
309    return ~val / val.sqlen();
310}
311
312template<typename T>
313static inline Cmplx<T> operator /(T x, Cmplx<T> const &y)
314{
315    return x * re(y);
316}
317
318template<typename T>
319static inline Cmplx<T> operator /(Cmplx<T> x, Cmplx<T> const &y)
320{
321    return x * re(y);
322}
323
324/*
325 * 3-element vectors
326 */
327
328template <typename T> struct Vec3
329{
330    typedef Vec3<T> type_t;
331
332    inline Vec3() { }
333    explicit inline Vec3(T val) { x = y = z = val; }
334    inline Vec3(T _x, T _y, T _z) { x = _x; y = _y; z = _z; }
335    inline Vec3(Vec2<T> _xy, T _z) { x = _xy.x; y = _xy.y; z = _z; }
336    inline Vec3(T _x, Vec2<T> _yz) { x = _x; y = _yz.x; z = _yz.y; }
337
338    LINEAR_OPS()
339    OTHER_OPS(Vec3)
340
341    SWIZZLE23(x); SWIZZLE23(y); SWIZZLE23(z);
342    SWIZZLE333(x); SWIZZLE333(y); SWIZZLE333(z);
343    SWIZZLE4333(x); SWIZZLE4333(y); SWIZZLE4333(z);
344
345    template<typename U>
346    friend Vec3<U> cross(Vec3<U>, Vec3<U>);
347
348#if !defined __ANDROID__
349    template<typename U>
350    friend std::ostream &operator<<(std::ostream &stream, Vec3<U> const &v);
351#endif
352
353    union { T x; T a; T i; };
354    union { T y; T b; T j; };
355    union { T z; T c; T k; };
356};
357
358/*
359 * 4-element vectors
360 */
361
362template <typename T> struct Vec4
363{
364    typedef Vec4<T> type_t;
365
366    inline Vec4() { }
367    explicit inline Vec4(T val) : x(val), y(val), z(val), w(val) { }
368    inline Vec4(T _x, T _y, T _z, T _w) : x(_x), y(_y), z(_z), w(_w) { }
369    inline Vec4(Vec2<T> _xy, T _z, T _w) : x(_xy.x), y(_xy.y), z(_z), w(_w) { }
370    inline Vec4(T _x, Vec2<T> _yz, T _w) : x(_x), y(_yz.x), z(_yz.y), w(_w) { }
371    inline Vec4(T _x, T _y, Vec2<T> _zw) : x(_x), y(_y), z(_zw.x), w(_zw.y) { }
372    inline Vec4(Vec2<T> _xy, Vec2<T> _zw) : x(_xy.x), y(_xy.y), z(_zw.x), w(_zw.y) { }
373    inline Vec4(Vec3<T> _xyz, T _w) : x(_xyz.x), y(_xyz.y), z(_xyz.z), w(_w) { }
374    inline Vec4(T _x, Vec3<T> _yzw) : x(_x), y(_yzw.x), z(_yzw.y), w(_yzw.z) { }
375
376    LINEAR_OPS()
377    OTHER_OPS(Vec4)
378
379    SWIZZLE24(x); SWIZZLE24(y); SWIZZLE24(z); SWIZZLE24(w);
380    SWIZZLE344(x); SWIZZLE344(y); SWIZZLE344(z); SWIZZLE344(w);
381    SWIZZLE4444(x); SWIZZLE4444(y); SWIZZLE4444(z); SWIZZLE4444(w);
382
383#if !defined __ANDROID__
384    template<typename U>
385    friend std::ostream &operator<<(std::ostream &stream, Vec4<U> const &v);
386#endif
387
388    union { T x; T a; T i; };
389    union { T y; T b; T j; };
390    union { T z; T c; T k; };
391    union { T w; T d; T l; };
392};
393
394/*
395 * 4-element quaternions
396 */
397
398template <typename T> struct Quat
399{
400    typedef Quat<T> type_t;
401
402    inline Quat() { }
403    inline Quat(T val) : x(0), y(0), z(0), w(val) { }
404    inline Quat(T _x, T _y, T _z, T _w) : x(_x), y(_y), z(_z), w(_w) { }
405
406    Quat(Mat4<T> const &m);
407
408    LINEAR_OPS()
409    QUATERNION_OPS()
410
411#if !defined __ANDROID__
412    template<typename U>
413    friend std::ostream &operator<<(std::ostream &stream, Quat<U> const &v);
414#endif
415
416    T x, y, z, w;
417};
418
419template<typename T>
420static inline Quat<T> re(Quat<T> const &val)
421{
422    return ~val / val.norm();
423}
424
425template<typename T>
426static inline Quat<T> operator /(T x, Quat<T> const &y)
427{
428    return x * re(y);
429}
430
431template<typename T>
432static inline Quat<T> operator /(Quat<T> x, Quat<T> const &y)
433{
434    return x * re(y);
435}
436
437/*
438 * Common operators for all vector types, including quaternions
439 */
440
441#define SCALAR_GLOBAL(tname, op, U) \
442    template<typename T> \
443    static inline tname<U> operator op(U const &val, tname<T> const &that) \
444    { \
445        tname<U> ret; \
446        for (size_t n = 0; n < sizeof(that) / sizeof(that[0]); n++) \
447            ret[n] = val op that[n]; \
448        return ret; \
449    }
450
451#define SCALAR_GLOBAL2(tname, op) \
452    SCALAR_GLOBAL(tname, op, int) \
453    SCALAR_GLOBAL(tname, op, float) \
454    SCALAR_GLOBAL(tname, op, double)
455
456#define GLOBALS(tname) \
457    SCALAR_GLOBAL2(tname, *) \
458    \
459    template<typename T> \
460    static inline tname<T> normalize(tname<T> const &val) \
461    { \
462        T norm = val.len(); \
463        return norm ? val / norm : val * 0; \
464    }
465
466GLOBALS(Vec2)
467GLOBALS(Cmplx)
468GLOBALS(Vec3)
469GLOBALS(Vec4)
470GLOBALS(Quat)
471
472/*
473 * 4×4-element matrices
474 */
475
476template <typename T> struct Mat4
477{
478    typedef Mat4<T> type_t;
479
480    inline Mat4() { }
481    explicit inline Mat4(T val)
482    {
483        for (int j = 0; j < 4; j++)
484            for (int i = 0; i < 4; i++)
485                v[i][j] = (i == j) ? val : 0;
486    }
487    inline Mat4(Vec4<T> v0, Vec4<T> v1, Vec4<T> v2, Vec4<T> v3)
488    {
489        v[0] = v0; v[1] = v1; v[2] = v2; v[3] = v3;
490    }
491
492    inline Vec4<T>& operator[](int n) { return v[n]; }
493    inline Vec4<T> const& operator[](int n) const { return v[n]; }
494
495    T det() const;
496    Mat4<T> invert() const;
497
498    /* Helpers for transformation matrices */
499    static Mat4<T> translate(T x, T y, T z);
500    static Mat4<T> translate(Vec3<T> v);
501    static Mat4<T> rotate(T angle, T x, T y, T z);
502    static Mat4<T> rotate(T angle, Vec3<T> v);
503    static Mat4<T> rotate(Quat<T> q);
504
505    static inline Mat4<T> translate(Mat4<T> mat, Vec3<T> v)
506    {
507        return translate(v) * mat;
508    }
509
510    static inline Mat4<T> rotate(Mat4<T> mat, T angle, Vec3<T> v)
511    {
512        return rotate(angle, v) * mat;
513    }
514
515    /* Helpers for view matrices */
516    static Mat4<T> lookat(Vec3<T> eye, Vec3<T> center, Vec3<T> up);
517
518    /* Helpers for projection matrices */
519    static Mat4<T> ortho(T left, T right, T bottom, T top, T near, T far);
520    static Mat4<T> frustum(T left, T right, T bottom, T top, T near, T far);
521    static Mat4<T> perspective(T fov_y, T width, T height, T near, T far);
522
523    void printf() const;
524
525#if !defined __ANDROID__
526    template<class U>
527    friend std::ostream &operator<<(std::ostream &stream, Mat4<U> const &m);
528#endif
529
530    inline Mat4<T> operator +(Mat4<T> const val) const
531    {
532        Mat4<T> ret;
533        for (int j = 0; j < 4; j++)
534            for (int i = 0; i < 4; i++)
535                ret[i][j] = v[i][j] + val[i][j];
536        return ret;
537    }
538
539    inline Mat4<T> operator +=(Mat4<T> const val)
540    {
541        return *this = *this + val;
542    }
543
544    inline Mat4<T> operator -(Mat4<T> const val) const
545    {
546        Mat4<T> ret;
547        for (int j = 0; j < 4; j++)
548            for (int i = 0; i < 4; i++)
549                ret[i][j] = v[i][j] - val[i][j];
550        return ret;
551    }
552
553    inline Mat4<T> operator -=(Mat4<T> const val)
554    {
555        return *this = *this - val;
556    }
557
558    inline Mat4<T> operator *(Mat4<T> const val) const
559    {
560        Mat4<T> ret;
561        for (int j = 0; j < 4; j++)
562            for (int i = 0; i < 4; i++)
563            {
564                T tmp = 0;
565                for (int k = 0; k < 4; k++)
566                    tmp += v[k][j] * val[i][k];
567                ret[i][j] = tmp;
568            }
569        return ret;
570    }
571
572    inline Mat4<T> operator *=(Mat4<T> const val)
573    {
574        return *this = *this * val;
575    }
576
577    inline Vec4<T> operator *(Vec4<T> const val) const
578    {
579        Vec4<T> ret;
580        for (int j = 0; j < 4; j++)
581        {
582            T tmp = 0;
583            for (int i = 0; i < 4; i++)
584                tmp += v[i][j] * val[i];
585            ret[j] = tmp;
586        }
587        return ret;
588    }
589
590    Vec4<T> v[4];
591};
592
593/*
594 * Arbitrarily-sized square matrices; for now this only supports
595 * naive inversion and is used for the Remez inversion method.
596 */
597
598template<int N, typename T> struct Mat
599{
600    inline Mat<N, T>() {}
601
602    Mat(T x)
603    {
604        for (int j = 0; j < N; j++)
605            for (int i = 0; i < N; i++)
606                if (i == j)
607                    m[i][j] = x;
608                else
609                    m[i][j] = 0;
610    }
611
612    /* Naive matrix inversion */
613    Mat<N, T> inv() const
614    {
615        Mat a = *this, b((T)1);
616
617        /* Inversion method: iterate through all columns and make sure
618         * all the terms are 1 on the diagonal and 0 everywhere else */
619        for (int i = 0; i < N; i++)
620        {
621            /* If the expected coefficient is zero, add one of
622             * the other lines. The first we meet will do. */
623            if (!a.m[i][i])
624            {
625                for (int j = i + 1; j < N; j++)
626                {
627                    if (!a.m[i][j])
628                        continue;
629                    /* Add row j to row i */
630                    for (int n = 0; n < N; n++)
631                    {
632                        a.m[n][i] += a.m[n][j];
633                        b.m[n][i] += b.m[n][j];
634                    }
635                    break;
636                }
637            }
638
639            /* Now we know the diagonal term is non-zero. Get its inverse
640             * and use that to nullify all other terms in the column */
641            T x = (T)1 / a.m[i][i];
642            for (int j = 0; j < N; j++)
643            {
644                if (j == i)
645                    continue;
646                T mul = x * a.m[i][j];
647                for (int n = 0; n < N; n++)
648                {
649                    a.m[n][j] -= mul * a.m[n][i];
650                    b.m[n][j] -= mul * b.m[n][i];
651                }
652            }
653
654            /* Finally, ensure the diagonal term is 1 */
655            for (int n = 0; n < N; n++)
656            {
657                a.m[n][i] *= x;
658                b.m[n][i] *= x;
659            }
660        }
661
662        return b;
663    }
664
665    T m[N][N];
666};
667
668} /* namespace lol */
669
670#endif // __LOL_MATH_MATRIX_H__
671
Note: See TracBrowser for help on using the repository browser.