1 /*
2  * Copyright (C) 2011 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 #include "rsMatrix2x2.h"
18 #include "rsMatrix3x3.h"
19 #include "rsMatrix4x4.h"
20 
21 #include "stdlib.h"
22 #include "string.h"
23 #include "math.h"
24 
25 namespace android {
26 namespace renderscript {
27 
28 //////////////////////////////////////////////////////////////////////////////
29 // Heavy math functions
30 //////////////////////////////////////////////////////////////////////////////
31 
32 
33 
34 
35 
36 // Returns true if the matrix was successfully inversed
inverse()37 bool Matrix4x4::inverse() {
38     rs_matrix4x4 result;
39 
40     int i, j;
41     for (i = 0; i < 4; ++i) {
42         for (j = 0; j < 4; ++j) {
43             // computeCofactor for int i, int j
44             int c0 = (i+1) % 4;
45             int c1 = (i+2) % 4;
46             int c2 = (i+3) % 4;
47             int r0 = (j+1) % 4;
48             int r1 = (j+2) % 4;
49             int r2 = (j+3) % 4;
50 
51             float minor =
52                 (m[c0 + 4*r0] * (m[c1 + 4*r1] * m[c2 + 4*r2] - m[c1 + 4*r2] * m[c2 + 4*r1]))
53                 - (m[c0 + 4*r1] * (m[c1 + 4*r0] * m[c2 + 4*r2] - m[c1 + 4*r2] * m[c2 + 4*r0]))
54                 + (m[c0 + 4*r2] * (m[c1 + 4*r0] * m[c2 + 4*r1] - m[c1 + 4*r1] * m[c2 + 4*r0]));
55 
56             float cofactor = (i+j) & 1 ? -minor : minor;
57 
58             result.m[4*i + j] = cofactor;
59         }
60     }
61 
62     // Dot product of 0th column of source and 0th row of result
63     float det = m[0]*result.m[0] + m[4]*result.m[1] +
64                  m[8]*result.m[2] + m[12]*result.m[3];
65 
66     if (fabs(det) < 1e-6) {
67         return false;
68     }
69 
70     det = 1.0f / det;
71     for (i = 0; i < 16; ++i) {
72         m[i] = result.m[i] * det;
73     }
74 
75     return true;
76 }
77 
78 // Returns true if the matrix was successfully inversed
inverseTranspose()79 bool Matrix4x4::inverseTranspose() {
80     rs_matrix4x4 result;
81 
82     int i, j;
83     for (i = 0; i < 4; ++i) {
84         for (j = 0; j < 4; ++j) {
85             // computeCofactor for int i, int j
86             int c0 = (i+1) % 4;
87             int c1 = (i+2) % 4;
88             int c2 = (i+3) % 4;
89             int r0 = (j+1) % 4;
90             int r1 = (j+2) % 4;
91             int r2 = (j+3) % 4;
92 
93             float minor = (m[c0 + 4*r0] * (m[c1 + 4*r1] * m[c2 + 4*r2] - m[c1 + 4*r2] * m[c2 + 4*r1]))
94                          - (m[c0 + 4*r1] * (m[c1 + 4*r0] * m[c2 + 4*r2] - m[c1 + 4*r2] * m[c2 + 4*r0]))
95                          + (m[c0 + 4*r2] * (m[c1 + 4*r0] * m[c2 + 4*r1] - m[c1 + 4*r1] * m[c2 + 4*r0]));
96 
97             float cofactor = (i+j) & 1 ? -minor : minor;
98 
99             result.m[4*j + i] = cofactor;
100         }
101     }
102 
103     // Dot product of 0th column of source and 0th column of result
104     float det = m[0]*result.m[0] + m[4]*result.m[4] +
105                  m[8]*result.m[8] + m[12]*result.m[12];
106 
107     if (fabs(det) < 1e-6) {
108         return false;
109     }
110 
111     det = 1.0f / det;
112     for (i = 0; i < 16; ++i) {
113         m[i] = result.m[i] * det;
114     }
115 
116     return true;
117 }
118 
transpose()119 void Matrix4x4::transpose() {
120     int i, j;
121     float temp;
122     for (i = 0; i < 3; ++i) {
123         for (j = i + 1; j < 4; ++j) {
124             temp = m[i*4 + j];
125             m[i*4 + j] = m[j*4 + i];
126             m[j*4 + i] = temp;
127         }
128     }
129 }
130 
131 
132 ///////////////////////////////////////////////////////////////////////////////////
133 
loadIdentity()134 void Matrix4x4::loadIdentity() {
135     m[0] = 1.f;
136     m[1] = 0.f;
137     m[2] = 0.f;
138     m[3] = 0.f;
139     m[4] = 0.f;
140     m[5] = 1.f;
141     m[6] = 0.f;
142     m[7] = 0.f;
143     m[8] = 0.f;
144     m[9] = 0.f;
145     m[10] = 1.f;
146     m[11] = 0.f;
147     m[12] = 0.f;
148     m[13] = 0.f;
149     m[14] = 0.f;
150     m[15] = 1.f;
151 }
152 
load(const float * v)153 void Matrix4x4::load(const float *v) {
154     memcpy(m, v, sizeof(m));
155 }
156 
load(const rs_matrix4x4 * v)157 void Matrix4x4::load(const rs_matrix4x4 *v) {
158     memcpy(m, v->m, sizeof(m));
159 }
160 
load(const rs_matrix3x3 * v)161 void Matrix4x4::load(const rs_matrix3x3 *v) {
162     m[0] = v->m[0];
163     m[1] = v->m[1];
164     m[2] = v->m[2];
165     m[3] = 0.f;
166     m[4] = v->m[3];
167     m[5] = v->m[4];
168     m[6] = v->m[5];
169     m[7] = 0.f;
170     m[8] = v->m[6];
171     m[9] = v->m[7];
172     m[10] = v->m[8];
173     m[11] = 0.f;
174     m[12] = 0.f;
175     m[13] = 0.f;
176     m[14] = 0.f;
177     m[15] = 1.f;
178 }
179 
load(const rs_matrix2x2 * v)180 void Matrix4x4::load(const rs_matrix2x2 *v) {
181     m[0] = v->m[0];
182     m[1] = v->m[1];
183     m[2] = 0.f;
184     m[3] = 0.f;
185     m[4] = v->m[2];
186     m[5] = v->m[3];
187     m[6] = 0.f;
188     m[7] = 0.f;
189     m[8] = 0.f;
190     m[9] = 0.f;
191     m[10] = 1.f;
192     m[11] = 0.f;
193     m[12] = 0.f;
194     m[13] = 0.f;
195     m[14] = 0.f;
196     m[15] = 1.f;
197 }
198 
199 
loadRotate(float rot,float x,float y,float z)200 void Matrix4x4::loadRotate(float rot, float x, float y, float z) {
201     float c, s;
202     m[3] = 0;
203     m[7] = 0;
204     m[11]= 0;
205     m[12]= 0;
206     m[13]= 0;
207     m[14]= 0;
208     m[15]= 1;
209     rot *= float(M_PI / 180.0f);
210     c = cosf(rot);
211     s = sinf(rot);
212 
213     const float len = x*x + y*y + z*z;
214     if (len != 1) {
215         const float recipLen = 1.f / sqrtf(len);
216         x *= recipLen;
217         y *= recipLen;
218         z *= recipLen;
219     }
220     const float nc = 1.0f - c;
221     const float xy = x * y;
222     const float yz = y * z;
223     const float zx = z * x;
224     const float xs = x * s;
225     const float ys = y * s;
226     const float zs = z * s;
227     m[ 0] = x*x*nc +  c;
228     m[ 4] =  xy*nc - zs;
229     m[ 8] =  zx*nc + ys;
230     m[ 1] =  xy*nc + zs;
231     m[ 5] = y*y*nc +  c;
232     m[ 9] =  yz*nc - xs;
233     m[ 2] =  zx*nc - ys;
234     m[ 6] =  yz*nc + xs;
235     m[10] = z*z*nc +  c;
236 }
237 
loadScale(float x,float y,float z)238 void Matrix4x4::loadScale(float x, float y, float z) {
239     loadIdentity();
240     set(0, 0, x);
241     set(1, 1, y);
242     set(2, 2, z);
243 }
244 
loadTranslate(float x,float y,float z)245 void Matrix4x4::loadTranslate(float x, float y, float z) {
246     loadIdentity();
247     m[12] = x;
248     m[13] = y;
249     m[14] = z;
250 }
251 
loadMultiply(const rs_matrix4x4 * lhs,const rs_matrix4x4 * rhs)252 void Matrix4x4::loadMultiply(const rs_matrix4x4 *lhs, const rs_matrix4x4 *rhs) {
253     // Use a temporary variable to support the case where one of the inputs
254     // is also the destination, e.g. left.loadMultiply(left, right);
255     Matrix4x4 temp;
256     for (int i=0 ; i<4 ; i++) {
257         float ri0 = 0;
258         float ri1 = 0;
259         float ri2 = 0;
260         float ri3 = 0;
261         for (int j=0 ; j<4 ; j++) {
262             const float rhs_ij = ((const Matrix4x4 *)rhs)->get(i,j);
263             ri0 += ((const Matrix4x4 *)lhs)->get(j,0) * rhs_ij;
264             ri1 += ((const Matrix4x4 *)lhs)->get(j,1) * rhs_ij;
265             ri2 += ((const Matrix4x4 *)lhs)->get(j,2) * rhs_ij;
266             ri3 += ((const Matrix4x4 *)lhs)->get(j,3) * rhs_ij;
267         }
268         temp.set(i,0, ri0);
269         temp.set(i,1, ri1);
270         temp.set(i,2, ri2);
271         temp.set(i,3, ri3);
272     }
273     load(&temp);
274 }
275 
loadOrtho(float left,float right,float bottom,float top,float near,float far)276 void Matrix4x4::loadOrtho(float left, float right, float bottom, float top, float near, float far) {
277     loadIdentity();
278     m[0] = 2.f / (right - left);
279     m[5] = 2.f / (top - bottom);
280     m[10]= -2.f / (far - near);
281     m[12]= -(right + left) / (right - left);
282     m[13]= -(top + bottom) / (top - bottom);
283     m[14]= -(far + near) / (far - near);
284 }
285 
loadFrustum(float left,float right,float bottom,float top,float near,float far)286 void Matrix4x4::loadFrustum(float left, float right, float bottom, float top, float near, float far) {
287     loadIdentity();
288     m[0] = 2.f * near / (right - left);
289     m[5] = 2.f * near / (top - bottom);
290     m[8] = (right + left) / (right - left);
291     m[9] = (top + bottom) / (top - bottom);
292     m[10]= -(far + near) / (far - near);
293     m[11]= -1.f;
294     m[14]= -2.f * far * near / (far - near);
295     m[15]= 0.f;
296 }
297 
loadPerspective(float fovy,float aspect,float near,float far)298 void Matrix4x4::loadPerspective(float fovy, float aspect, float near, float far) {
299     float top = near * tan((float) (fovy * M_PI / 360.0f));
300     float bottom = -top;
301     float left = bottom * aspect;
302     float right = top * aspect;
303     loadFrustum(left, right, bottom, top, near, far);
304 }
305 
306 // Note: This assumes that the input vector (in) is of length 3.
vectorMultiply(float * out,const float * in) const307 void Matrix4x4::vectorMultiply(float *out, const float *in) const {
308     out[0] = (m[0] * in[0]) + (m[4] * in[1]) + (m[8] * in[2]) + m[12];
309     out[1] = (m[1] * in[0]) + (m[5] * in[1]) + (m[9] * in[2]) + m[13];
310     out[2] = (m[2] * in[0]) + (m[6] * in[1]) + (m[10] * in[2]) + m[14];
311     out[3] = (m[3] * in[0]) + (m[7] * in[1]) + (m[11] * in[2]) + m[15];
312 }
313 
logv(const char * s) const314 void Matrix4x4::logv(const char *s) const {
315     ALOGV("%s {%f, %f, %f, %f",  s, m[0], m[4], m[8], m[12]);
316     ALOGV("%s  %f, %f, %f, %f",  s, m[1], m[5], m[9], m[13]);
317     ALOGV("%s  %f, %f, %f, %f",  s, m[2], m[6], m[10], m[14]);
318     ALOGV("%s  %f, %f, %f, %f}", s, m[3], m[7], m[11], m[15]);
319 }
320 
321 } // namespace renderscript
322 } // namespace android
323