mat4.h revision 595ea77f6bdb5e9d0ddd3305da7a44b56f326b2c
1/*
2 * Copyright 2013 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#ifndef UI_MAT4_H
18#define UI_MAT4_H
19
20#include <stdint.h>
21#include <sys/types.h>
22
23#include <ui/vec4.h>
24#include <utils/String8.h>
25
26#define TMAT_IMPLEMENTATION
27#include <ui/TMatHelpers.h>
28
29#define PURE __attribute__((pure))
30
31namespace android {
32// -------------------------------------------------------------------------------------
33
34template <typename T>
35class tmat44 :  public TVecUnaryOperators<tmat44, T>,
36                public TVecComparisonOperators<tmat44, T>
37{
38public:
39    enum no_init { NO_INIT };
40    typedef T value_type;
41    typedef T& reference;
42    typedef T const& const_reference;
43    typedef size_t size_type;
44    typedef tvec4<T> col_type;
45    typedef tvec4<T> row_type;
46
47    // size of a column (i.e.: number of rows)
48    enum { COL_SIZE = col_type::SIZE };
49    static inline size_t col_size() { return COL_SIZE; }
50
51    // size of a row (i.e.: number of columns)
52    enum { ROW_SIZE = row_type::SIZE };
53    static inline size_t row_size() { return ROW_SIZE; }
54    static inline size_t size()     { return row_size(); }  // for TVec*<>
55
56private:
57
58    /*
59     *  <--  N columns  -->
60     *
61     *  a00 a10 a20 ... aN0    ^
62     *  a01 a11 a21 ... aN1    |
63     *  a02 a12 a22 ... aN2  M rows
64     *  ...                    |
65     *  a0M a1M a2M ... aNM    v
66     *
67     *  COL_SIZE = M
68     *  ROW_SIZE = N
69     *  m[0] = [a00 a01 a02 ... a01M]
70     */
71
72    col_type mValue[ROW_SIZE];
73
74public:
75    // array access
76    inline col_type const& operator [] (size_t i) const { return mValue[i]; }
77    inline col_type&       operator [] (size_t i)       { return mValue[i]; }
78
79    T const* asArray() const { return &mValue[0][0]; }
80
81    // -----------------------------------------------------------------------
82    // we don't provide copy-ctor and operator= on purpose
83    // because we want the compiler generated versions
84
85    /*
86     *  constructors
87     */
88
89    // leaves object uninitialized. use with caution.
90    explicit tmat44(no_init) { }
91
92    // initialize to identity
93    tmat44();
94
95    // initialize to Identity*scalar.
96    template<typename U>
97    explicit tmat44(U v);
98
99    // sets the diagonal to the passed vector
100    template <typename U>
101    explicit tmat44(const tvec4<U>& rhs);
102
103    // construct from another matrix of the same size
104    template <typename U>
105    explicit tmat44(const tmat44<U>& rhs);
106
107    // construct from 4 column vectors
108    template <typename A, typename B, typename C, typename D>
109    tmat44(const tvec4<A>& v0, const tvec4<B>& v1, const tvec4<C>& v2, const tvec4<D>& v3);
110
111    // construct from a C array
112    template <typename U>
113    explicit tmat44(U const* rawArray);
114
115    /*
116     *  helpers
117     */
118
119    static tmat44 ortho(T left, T right, T bottom, T top, T near, T far);
120
121    static tmat44 frustum(T left, T right, T bottom, T top, T near, T far);
122
123    template <typename A, typename B, typename C>
124    static tmat44 lookAt(const tvec3<A>& eye, const tvec3<B>& center, const tvec3<C>& up);
125
126    template <typename A>
127    static tmat44 translate(const tvec4<A>& t);
128
129    template <typename A>
130    static tmat44 scale(const tvec4<A>& s);
131
132    template <typename A, typename B>
133    static tmat44 rotate(A radian, const tvec3<B>& about);
134
135
136    /*
137     * Compound assignment arithmetic operators
138     */
139
140    // add another matrix of the same size
141    template <typename U>
142    tmat44& operator += (const tmat44<U>& v);
143
144    // subtract another matrix of the same size
145    template <typename U>
146    tmat44& operator -= (const tmat44<U>& v);
147
148    // multiply by a scalar
149    template <typename U>
150    tmat44& operator *= (U v);
151
152    // divide by a scalar
153    template <typename U>
154    tmat44& operator /= (U v);
155
156    /*
157     * debugging
158     */
159
160    String8 asString() const;
161};
162
163// ----------------------------------------------------------------------------------------
164// Constructors
165// ----------------------------------------------------------------------------------------
166
167/*
168 * Since the matrix code could become pretty big quickly, we don't inline most
169 * operations.
170 */
171
172template <typename T>
173tmat44<T>::tmat44() {
174    mValue[0] = col_type(1,0,0,0);
175    mValue[1] = col_type(0,1,0,0);
176    mValue[2] = col_type(0,0,1,0);
177    mValue[3] = col_type(0,0,0,1);
178}
179
180template <typename T>
181template <typename U>
182tmat44<T>::tmat44(U v) {
183    mValue[0] = col_type(v,0,0,0);
184    mValue[1] = col_type(0,v,0,0);
185    mValue[2] = col_type(0,0,v,0);
186    mValue[3] = col_type(0,0,0,v);
187}
188
189template<typename T>
190template<typename U>
191tmat44<T>::tmat44(const tvec4<U>& v) {
192    mValue[0] = col_type(v.x,0,0,0);
193    mValue[1] = col_type(0,v.y,0,0);
194    mValue[2] = col_type(0,0,v.z,0);
195    mValue[3] = col_type(0,0,0,v.w);
196}
197
198template <typename T>
199template <typename U>
200tmat44<T>::tmat44(const tmat44<U>& rhs) {
201    for (size_t r=0 ; r<row_size() ; r++)
202        mValue[r] = rhs[r];
203}
204
205template <typename T>
206template <typename A, typename B, typename C, typename D>
207tmat44<T>::tmat44(const tvec4<A>& v0, const tvec4<B>& v1, const tvec4<C>& v2, const tvec4<D>& v3) {
208    mValue[0] = v0;
209    mValue[1] = v1;
210    mValue[2] = v2;
211    mValue[3] = v3;
212}
213
214template <typename T>
215template <typename U>
216tmat44<T>::tmat44(U const* rawArray) {
217    for (size_t r=0 ; r<row_size() ; r++)
218        for (size_t c=0 ; c<col_size() ; c++)
219            mValue[r][c] = *rawArray++;
220}
221
222// ----------------------------------------------------------------------------------------
223// Helpers
224// ----------------------------------------------------------------------------------------
225
226template <typename T>
227tmat44<T> tmat44<T>::ortho(T left, T right, T bottom, T top, T near, T far) {
228    tmat44<T> m;
229    m[0][0] =  2 / (right - left);
230    m[1][1] =  2 / (top   - bottom);
231    m[2][2] = -2 / (far   - near);
232    m[3][0] = -(right + left)   / (right - left);
233    m[3][1] = -(top   + bottom) / (top   - bottom);
234    m[3][2] = -(far   + near)   / (far   - near);
235    return m;
236}
237
238template <typename T>
239tmat44<T> tmat44<T>::frustum(T left, T right, T bottom, T top, T near, T far) {
240    tmat44<T> m;
241    T A = (right + left)   / (right - left);
242    T B = (top   + bottom) / (top   - bottom);
243    T C = (far   + near)   / (far   - near);
244    T D = (2 * far * near) / (far   - near);
245    m[0][0] = (2 * near) / (right - left);
246    m[1][1] = (2 * near) / (top   - bottom);
247    m[2][0] = A;
248    m[2][1] = B;
249    m[2][2] = C;
250    m[2][3] =-1;
251    m[3][2] = D;
252    m[3][3] = 0;
253    return m;
254}
255
256template <typename T>
257template <typename A, typename B, typename C>
258tmat44<T> tmat44<T>::lookAt(const tvec3<A>& eye, const tvec3<B>& center, const tvec3<C>& up) {
259    tvec3<T> L(normalize(center - eye));
260    tvec3<T> S(normalize( cross(L, up) ));
261    tvec3<T> U(cross(S, L));
262    return tmat44<T>(
263            tvec4<T>( S, 0),
264            tvec4<T>( U, 0),
265            tvec4<T>(-L, 0),
266            tvec4<T>(-eye, 1));
267}
268
269template <typename T>
270template <typename A>
271tmat44<T> tmat44<T>::translate(const tvec4<A>& t) {
272    tmat44<T> r;
273    r[3] = t;
274    return r;
275}
276
277template <typename T>
278template <typename A>
279tmat44<T> tmat44<T>::scale(const tvec4<A>& s) {
280    tmat44<T> r;
281    r[0][0] = s[0];
282    r[1][1] = s[1];
283    r[2][2] = s[2];
284    r[3][3] = s[3];
285    return r;
286}
287
288template <typename T>
289template <typename A, typename B>
290tmat44<T> tmat44<T>::rotate(A radian, const tvec3<B>& about) {
291    tmat44<T> rotation;
292    T* r = const_cast<T*>(rotation.asArray());
293    T c = cos(radian);
294    T s = sin(radian);
295    if (about.x==1 && about.y==0 && about.z==0) {
296        r[5] = c;   r[10]= c;
297        r[6] = s;   r[9] = -s;
298    } else if (about.x==0 && about.y==1 && about.z==0) {
299        r[0] = c;   r[10]= c;
300        r[8] = s;   r[2] = -s;
301    } else if (about.x==0 && about.y==0 && about.z==1) {
302        r[0] = c;   r[5] = c;
303        r[1] = s;   r[4] = -s;
304    } else {
305        tvec3<B> nabout = normalize(about);
306        B x = nabout.x;
307        B y = nabout.y;
308        B z = nabout.z;
309        T nc = 1 - c;
310        T xy = x * y;
311        T yz = y * z;
312        T zx = z * x;
313        T xs = x * s;
314        T ys = y * s;
315        T zs = z * s;
316        r[ 0] = x*x*nc +  c;    r[ 4] =  xy*nc - zs;    r[ 8] =  zx*nc + ys;
317        r[ 1] =  xy*nc + zs;    r[ 5] = y*y*nc +  c;    r[ 9] =  yz*nc - xs;
318        r[ 2] =  zx*nc - ys;    r[ 6] =  yz*nc + xs;    r[10] = z*z*nc +  c;
319    }
320}
321
322// ----------------------------------------------------------------------------------------
323// Compound assignment arithmetic operators
324// ----------------------------------------------------------------------------------------
325
326template <typename T>
327template <typename U>
328tmat44<T>& tmat44<T>::operator += (const tmat44<U>& v) {
329    for (size_t r=0 ; r<row_size() ; r++)
330        mValue[r] += v[r];
331    return *this;
332}
333
334template <typename T>
335template <typename U>
336tmat44<T>& tmat44<T>::operator -= (const tmat44<U>& v) {
337    for (size_t r=0 ; r<row_size() ; r++)
338        mValue[r] -= v[r];
339    return *this;
340}
341
342template <typename T>
343template <typename U>
344tmat44<T>& tmat44<T>::operator *= (U v) {
345    for (size_t r=0 ; r<row_size() ; r++)
346        mValue[r] *= v;
347    return *this;
348}
349
350template <typename T>
351template <typename U>
352tmat44<T>& tmat44<T>::operator /= (U v) {
353    for (size_t r=0 ; r<row_size() ; r++)
354        mValue[r] /= v;
355    return *this;
356}
357
358// ----------------------------------------------------------------------------------------
359// Arithmetic operators outside of class
360// ----------------------------------------------------------------------------------------
361
362/* We use non-friend functions here to prevent the compiler from using
363 * implicit conversions, for instance of a scalar to a vector. The result would
364 * not be what the caller expects.
365 *
366 * Also note that the order of the arguments in the inner loop is important since
367 * it determines the output type (only relevant when T != U).
368 */
369
370// matrix + matrix, result is a matrix of the same type than the lhs matrix
371template <typename T, typename U>
372tmat44<T> PURE operator +(const tmat44<T>& lhs, const tmat44<U>& rhs) {
373    tmat44<T> result(tmat44<T>::NO_INIT);
374    for (size_t r=0 ; r<tmat44<T>::row_size() ; r++)
375        result[r] = lhs[r] + rhs[r];
376    return result;
377}
378
379// matrix - matrix, result is a matrix of the same type than the lhs matrix
380template <typename T, typename U>
381tmat44<T> PURE operator -(const tmat44<T>& lhs, const tmat44<U>& rhs) {
382    tmat44<T> result(tmat44<T>::NO_INIT);
383    for (size_t r=0 ; r<tmat44<T>::row_size() ; r++)
384        result[r] = lhs[r] - rhs[r];
385    return result;
386}
387
388// matrix * vector, result is a vector of the same type than the input vector
389template <typename T, typename U>
390typename tmat44<U>::col_type PURE operator *(const tmat44<T>& lv, const tvec4<U>& rv) {
391    typename tmat44<U>::col_type result;
392    for (size_t r=0 ; r<tmat44<T>::row_size() ; r++)
393        result += rv[r]*lv[r];
394    return result;
395}
396
397// vector * matrix, result is a vector of the same type than the input vector
398template <typename T, typename U>
399typename tmat44<U>::row_type PURE operator *(const tvec4<U>& rv, const tmat44<T>& lv) {
400    typename tmat44<U>::row_type result(tmat44<U>::row_type::NO_INIT);
401    for (size_t r=0 ; r<tmat44<T>::row_size() ; r++)
402        result[r] = dot(rv, lv[r]);
403    return result;
404}
405
406// matrix * scalar, result is a matrix of the same type than the input matrix
407template <typename T, typename U>
408tmat44<T> PURE operator *(const tmat44<T>& lv, U rv) {
409    tmat44<T> result(tmat44<T>::NO_INIT);
410    for (size_t r=0 ; r<tmat44<T>::row_size() ; r++)
411        result[r] = lv[r]*rv;
412    return result;
413}
414
415// scalar * matrix, result is a matrix of the same type than the input matrix
416template <typename T, typename U>
417tmat44<T> PURE operator *(U rv, const tmat44<T>& lv) {
418    tmat44<T> result(tmat44<T>::NO_INIT);
419    for (size_t r=0 ; r<tmat44<T>::row_size() ; r++)
420        result[r] = lv[r]*rv;
421    return result;
422}
423
424// matrix * matrix, result is a matrix of the same type than the lhs matrix
425template <typename T, typename U>
426tmat44<T> PURE operator *(const tmat44<T>& lhs, const tmat44<U>& rhs) {
427    return matrix::multiply< tmat44<T> >(lhs, rhs);
428}
429
430// ----------------------------------------------------------------------------------------
431// Functions
432// ----------------------------------------------------------------------------------------
433
434// inverse a matrix
435template <typename T>
436tmat44<T> PURE inverse(const tmat44<T>& m) {
437    return matrix::inverse(m);
438}
439
440template <typename T>
441tmat44<T> PURE transpose(const tmat44<T>& m) {
442    return matrix::transpose(m);
443}
444
445template <typename T>
446T PURE trace(const tmat44<T>& m) {
447    return matrix::trace(m);
448}
449
450template <typename T>
451tvec4<T> PURE diag(const tmat44<T>& m) {
452    return matrix::diag(m);
453}
454
455// ----------------------------------------------------------------------------------------
456// Debugging
457// ----------------------------------------------------------------------------------------
458
459template <typename T>
460String8 tmat44<T>::asString() const {
461    return matrix::asString(*this);
462}
463
464// ----------------------------------------------------------------------------------------
465
466typedef tmat44<float> mat4;
467
468// ----------------------------------------------------------------------------------------
469}; // namespace android
470
471#undef PURE
472
473#endif /* UI_MAT4_H */
474