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                public TVecAddOperators<tmat44, T>,
38                public TMatProductOperators<tmat44, T>,
39                public TMatSquareFunctions<tmat44, T>,
40                public TMatDebug<tmat44, T>
41{
42public:
43    enum no_init { NO_INIT };
44    typedef T value_type;
45    typedef T& reference;
46    typedef T const& const_reference;
47    typedef size_t size_type;
48    typedef tvec4<T> col_type;
49    typedef tvec4<T> row_type;
50
51    // size of a column (i.e.: number of rows)
52    enum { COL_SIZE = col_type::SIZE };
53    static inline size_t col_size() { return COL_SIZE; }
54
55    // size of a row (i.e.: number of columns)
56    enum { ROW_SIZE = row_type::SIZE };
57    static inline size_t row_size() { return ROW_SIZE; }
58    static inline size_t size()     { return row_size(); }  // for TVec*<>
59
60private:
61
62    /*
63     *  <--  N columns  -->
64     *
65     *  a00 a10 a20 ... aN0    ^
66     *  a01 a11 a21 ... aN1    |
67     *  a02 a12 a22 ... aN2  M rows
68     *  ...                    |
69     *  a0M a1M a2M ... aNM    v
70     *
71     *  COL_SIZE = M
72     *  ROW_SIZE = N
73     *  m[0] = [a00 a01 a02 ... a01M]
74     */
75
76    col_type mValue[ROW_SIZE];
77
78public:
79    // array access
80    inline col_type const& operator [] (size_t i) const { return mValue[i]; }
81    inline col_type&       operator [] (size_t i)       { return mValue[i]; }
82
83    T const* asArray() const { return &mValue[0][0]; }
84
85    // -----------------------------------------------------------------------
86    // we don't provide copy-ctor and operator= on purpose
87    // because we want the compiler generated versions
88
89    /*
90     *  constructors
91     */
92
93    // leaves object uninitialized. use with caution.
94    explicit tmat44(no_init) { }
95
96    // initialize to identity
97    tmat44();
98
99    // initialize to Identity*scalar.
100    template<typename U>
101    explicit tmat44(U v);
102
103    // sets the diagonal to the passed vector
104    template <typename U>
105    explicit tmat44(const tvec4<U>& rhs);
106
107    // construct from another matrix of the same size
108    template <typename U>
109    explicit tmat44(const tmat44<U>& rhs);
110
111    // construct from 4 column vectors
112    template <typename A, typename B, typename C, typename D>
113    tmat44(const tvec4<A>& v0, const tvec4<B>& v1, const tvec4<C>& v2, const tvec4<D>& v3);
114
115    // construct from 16 scalars
116    template <
117        typename A, typename B, typename C, typename D,
118        typename E, typename F, typename G, typename H,
119        typename I, typename J, typename K, typename L,
120        typename M, typename N, typename O, typename P>
121    tmat44( A m00, B m01, C m02, D m03,
122            E m10, F m11, G m12, H m13,
123            I m20, J m21, K m22, L m23,
124            M m30, N m31, O m32, P m33);
125
126    // construct from a C array
127    template <typename U>
128    explicit tmat44(U const* rawArray);
129
130    /*
131     *  helpers
132     */
133
134    static tmat44 ortho(T left, T right, T bottom, T top, T near, T far);
135
136    static tmat44 frustum(T left, T right, T bottom, T top, T near, T far);
137
138    template <typename A, typename B, typename C>
139    static tmat44 lookAt(const tvec3<A>& eye, const tvec3<B>& center, const tvec3<C>& up);
140
141    template <typename A>
142    static tmat44 translate(const tvec4<A>& t);
143
144    template <typename A>
145    static tmat44 scale(const tvec4<A>& s);
146
147    template <typename A, typename B>
148    static tmat44 rotate(A radian, const tvec3<B>& about);
149};
150
151// ----------------------------------------------------------------------------------------
152// Constructors
153// ----------------------------------------------------------------------------------------
154
155/*
156 * Since the matrix code could become pretty big quickly, we don't inline most
157 * operations.
158 */
159
160template <typename T>
161tmat44<T>::tmat44() {
162    mValue[0] = col_type(1,0,0,0);
163    mValue[1] = col_type(0,1,0,0);
164    mValue[2] = col_type(0,0,1,0);
165    mValue[3] = col_type(0,0,0,1);
166}
167
168template <typename T>
169template <typename U>
170tmat44<T>::tmat44(U v) {
171    mValue[0] = col_type(v,0,0,0);
172    mValue[1] = col_type(0,v,0,0);
173    mValue[2] = col_type(0,0,v,0);
174    mValue[3] = col_type(0,0,0,v);
175}
176
177template<typename T>
178template<typename U>
179tmat44<T>::tmat44(const tvec4<U>& v) {
180    mValue[0] = col_type(v.x,0,0,0);
181    mValue[1] = col_type(0,v.y,0,0);
182    mValue[2] = col_type(0,0,v.z,0);
183    mValue[3] = col_type(0,0,0,v.w);
184}
185
186// construct from 16 scalars
187template<typename T>
188template <
189    typename A, typename B, typename C, typename D,
190    typename E, typename F, typename G, typename H,
191    typename I, typename J, typename K, typename L,
192    typename M, typename N, typename O, typename P>
193tmat44<T>::tmat44(  A m00, B m01, C m02, D m03,
194                    E m10, F m11, G m12, H m13,
195                    I m20, J m21, K m22, L m23,
196                    M m30, N m31, O m32, P m33) {
197    mValue[0] = col_type(m00, m01, m02, m03);
198    mValue[1] = col_type(m10, m11, m12, m13);
199    mValue[2] = col_type(m20, m21, m22, m23);
200    mValue[3] = col_type(m30, m31, m32, m33);
201}
202
203template <typename T>
204template <typename U>
205tmat44<T>::tmat44(const tmat44<U>& rhs) {
206    for (size_t r=0 ; r<row_size() ; r++)
207        mValue[r] = rhs[r];
208}
209
210template <typename T>
211template <typename A, typename B, typename C, typename D>
212tmat44<T>::tmat44(const tvec4<A>& v0, const tvec4<B>& v1, const tvec4<C>& v2, const tvec4<D>& v3) {
213    mValue[0] = v0;
214    mValue[1] = v1;
215    mValue[2] = v2;
216    mValue[3] = v3;
217}
218
219template <typename T>
220template <typename U>
221tmat44<T>::tmat44(U const* rawArray) {
222    for (size_t r=0 ; r<row_size() ; r++)
223        for (size_t c=0 ; c<col_size() ; c++)
224            mValue[r][c] = *rawArray++;
225}
226
227// ----------------------------------------------------------------------------------------
228// Helpers
229// ----------------------------------------------------------------------------------------
230
231template <typename T>
232tmat44<T> tmat44<T>::ortho(T left, T right, T bottom, T top, T near, T far) {
233    tmat44<T> m;
234    m[0][0] =  2 / (right - left);
235    m[1][1] =  2 / (top   - bottom);
236    m[2][2] = -2 / (far   - near);
237    m[3][0] = -(right + left)   / (right - left);
238    m[3][1] = -(top   + bottom) / (top   - bottom);
239    m[3][2] = -(far   + near)   / (far   - near);
240    return m;
241}
242
243template <typename T>
244tmat44<T> tmat44<T>::frustum(T left, T right, T bottom, T top, T near, T far) {
245    tmat44<T> m;
246    T A = (right + left)   / (right - left);
247    T B = (top   + bottom) / (top   - bottom);
248    T C = (far   + near)   / (far   - near);
249    T D = (2 * far * near) / (far   - near);
250    m[0][0] = (2 * near) / (right - left);
251    m[1][1] = (2 * near) / (top   - bottom);
252    m[2][0] = A;
253    m[2][1] = B;
254    m[2][2] = C;
255    m[2][3] =-1;
256    m[3][2] = D;
257    m[3][3] = 0;
258    return m;
259}
260
261template <typename T>
262template <typename A, typename B, typename C>
263tmat44<T> tmat44<T>::lookAt(const tvec3<A>& eye, const tvec3<B>& center, const tvec3<C>& up) {
264    tvec3<T> L(normalize(center - eye));
265    tvec3<T> S(normalize( cross(L, up) ));
266    tvec3<T> U(cross(S, L));
267    return tmat44<T>(
268            tvec4<T>( S, 0),
269            tvec4<T>( U, 0),
270            tvec4<T>(-L, 0),
271            tvec4<T>(-eye, 1));
272}
273
274template <typename T>
275template <typename A>
276tmat44<T> tmat44<T>::translate(const tvec4<A>& t) {
277    tmat44<T> r;
278    r[3] = t;
279    return r;
280}
281
282template <typename T>
283template <typename A>
284tmat44<T> tmat44<T>::scale(const tvec4<A>& s) {
285    tmat44<T> r;
286    r[0][0] = s[0];
287    r[1][1] = s[1];
288    r[2][2] = s[2];
289    r[3][3] = s[3];
290    return r;
291}
292
293template <typename T>
294template <typename A, typename B>
295tmat44<T> tmat44<T>::rotate(A radian, const tvec3<B>& about) {
296    tmat44<T> rotation;
297    T* r = const_cast<T*>(rotation.asArray());
298    T c = cos(radian);
299    T s = sin(radian);
300    if (about.x==1 && about.y==0 && about.z==0) {
301        r[5] = c;   r[10]= c;
302        r[6] = s;   r[9] = -s;
303    } else if (about.x==0 && about.y==1 && about.z==0) {
304        r[0] = c;   r[10]= c;
305        r[8] = s;   r[2] = -s;
306    } else if (about.x==0 && about.y==0 && about.z==1) {
307        r[0] = c;   r[5] = c;
308        r[1] = s;   r[4] = -s;
309    } else {
310        tvec3<B> nabout = normalize(about);
311        B x = nabout.x;
312        B y = nabout.y;
313        B z = nabout.z;
314        T nc = 1 - c;
315        T xy = x * y;
316        T yz = y * z;
317        T zx = z * x;
318        T xs = x * s;
319        T ys = y * s;
320        T zs = z * s;
321        r[ 0] = x*x*nc +  c;    r[ 4] =  xy*nc - zs;    r[ 8] =  zx*nc + ys;
322        r[ 1] =  xy*nc + zs;    r[ 5] = y*y*nc +  c;    r[ 9] =  yz*nc - xs;
323        r[ 2] =  zx*nc - ys;    r[ 6] =  yz*nc + xs;    r[10] = z*z*nc +  c;
324    }
325    return rotation;
326}
327
328// ----------------------------------------------------------------------------------------
329// Arithmetic operators outside of class
330// ----------------------------------------------------------------------------------------
331
332/* We use non-friend functions here to prevent the compiler from using
333 * implicit conversions, for instance of a scalar to a vector. The result would
334 * not be what the caller expects.
335 *
336 * Also note that the order of the arguments in the inner loop is important since
337 * it determines the output type (only relevant when T != U).
338 */
339
340// matrix * vector, result is a vector of the same type than the input vector
341template <typename T, typename U>
342typename tmat44<U>::col_type PURE operator *(const tmat44<T>& lv, const tvec4<U>& rv) {
343    typename tmat44<U>::col_type result;
344    for (size_t r=0 ; r<tmat44<T>::row_size() ; r++)
345        result += rv[r]*lv[r];
346    return result;
347}
348
349// vector * matrix, result is a vector of the same type than the input vector
350template <typename T, typename U>
351typename tmat44<U>::row_type PURE operator *(const tvec4<U>& rv, const tmat44<T>& lv) {
352    typename tmat44<U>::row_type result(tmat44<U>::row_type::NO_INIT);
353    for (size_t r=0 ; r<tmat44<T>::row_size() ; r++)
354        result[r] = dot(rv, lv[r]);
355    return result;
356}
357
358// matrix * scalar, result is a matrix of the same type than the input matrix
359template <typename T, typename U>
360tmat44<T> PURE operator *(const tmat44<T>& lv, U rv) {
361    tmat44<T> result(tmat44<T>::NO_INIT);
362    for (size_t r=0 ; r<tmat44<T>::row_size() ; r++)
363        result[r] = lv[r]*rv;
364    return result;
365}
366
367// scalar * matrix, result is a matrix of the same type than the input matrix
368template <typename T, typename U>
369tmat44<T> PURE operator *(U rv, const tmat44<T>& lv) {
370    tmat44<T> result(tmat44<T>::NO_INIT);
371    for (size_t r=0 ; r<tmat44<T>::row_size() ; r++)
372        result[r] = lv[r]*rv;
373    return result;
374}
375
376// ----------------------------------------------------------------------------------------
377
378/* FIXME: this should go into TMatSquareFunctions<> but for some reason
379 * BASE<T>::col_type is not accessible from there (???)
380 */
381template<typename T>
382typename tmat44<T>::col_type PURE diag(const tmat44<T>& m) {
383    return matrix::diag(m);
384}
385
386// ----------------------------------------------------------------------------------------
387
388typedef tmat44<float> mat4;
389
390// ----------------------------------------------------------------------------------------
391}; // namespace android
392
393#undef PURE
394
395#endif /* UI_MAT4_H */
396