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 
31 namespace android {
32 // -------------------------------------------------------------------------------------
33 
34 template <typename T>
35 class 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 {
42 public:
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 };
col_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 };
row_size()57     static inline size_t row_size() { return ROW_SIZE; }
size()58     static inline size_t size()     { return row_size(); }  // for TVec*<>
59 
60 private:
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 
78 public:
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 
asArray()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.
tmat44(no_init)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 
160 template <typename T>
tmat44()161 tmat44<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 
168 template <typename T>
169 template <typename U>
tmat44(U v)170 tmat44<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 
177 template<typename T>
178 template<typename U>
tmat44(const tvec4<U> & v)179 tmat44<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
187 template<typename T>
188 template <
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>
tmat44(A m00,B m01,C m02,D m03,E m10,F m11,G m12,H m13,I m20,J m21,K m22,L m23,M m30,N m31,O m32,P m33)193 tmat44<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 
203 template <typename T>
204 template <typename U>
tmat44(const tmat44<U> & rhs)205 tmat44<T>::tmat44(const tmat44<U>& rhs) {
206     for (size_t r=0 ; r<row_size() ; r++)
207         mValue[r] = rhs[r];
208 }
209 
210 template <typename T>
211 template <typename A, typename B, typename C, typename D>
tmat44(const tvec4<A> & v0,const tvec4<B> & v1,const tvec4<C> & v2,const tvec4<D> & v3)212 tmat44<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 
219 template <typename T>
220 template <typename U>
tmat44(U const * rawArray)221 tmat44<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 
231 template <typename T>
ortho(T left,T right,T bottom,T top,T near,T far)232 tmat44<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 
243 template <typename T>
frustum(T left,T right,T bottom,T top,T near,T far)244 tmat44<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 
261 template <typename T>
262 template <typename A, typename B, typename C>
lookAt(const tvec3<A> & eye,const tvec3<B> & center,const tvec3<C> & up)263 tmat44<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 
274 template <typename T>
275 template <typename A>
translate(const tvec4<A> & t)276 tmat44<T> tmat44<T>::translate(const tvec4<A>& t) {
277     tmat44<T> r;
278     r[3] = t;
279     return r;
280 }
281 
282 template <typename T>
283 template <typename A>
scale(const tvec4<A> & s)284 tmat44<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 
293 template <typename T>
294 template <typename A, typename B>
rotate(A radian,const tvec3<B> & about)295 tmat44<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
341 template <typename T, typename U>
342 typename 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
350 template <typename T, typename U>
351 typename 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
359 template <typename T, typename U>
360 tmat44<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
368 template <typename T, typename U>
369 tmat44<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  */
381 template<typename T>
diag(const tmat44<T> & m)382 typename tmat44<T>::col_type PURE diag(const tmat44<T>& m) {
383     return matrix::diag(m);
384 }
385 
386 // ----------------------------------------------------------------------------------------
387 
388 typedef tmat44<float> mat4;
389 
390 // ----------------------------------------------------------------------------------------
391 }; // namespace android
392 
393 #undef PURE
394 
395 #endif /* UI_MAT4_H */
396