1 /*
2  * Copyright (C) 2013 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
5  * in compliance with the License. You may obtain a copy of the License at
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software distributed under the License
10  * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
11  * or implied. See the License for the specific language governing permissions and limitations under
12  * the License.
13  */
14 
15 #include "Matrix.h"
16 #include <string.h>
17 #include <cmath>
18 
19 #define LOG_TAG "CTS_OPENGL"
20 #define LOG_NDEBUG 0
21 #include "android/log.h"
22 
Matrix()23 Matrix::Matrix() {
24     identity();
25 }
26 
Matrix(const Matrix & src)27 Matrix::Matrix(const Matrix& src) {
28     loadWith(src);
29 }
30 
print(const char * label)31 void Matrix::print(const char* label) {
32     __android_log_print(ANDROID_LOG_INFO, LOG_TAG, "%c", *label);
33     for (int i = 0; i < 4; i++) {
34         const float* d = &(mData[i * 4]);
35         __android_log_print(ANDROID_LOG_INFO, LOG_TAG, "%f %f %f %f\n", d[0], d[1], d[2], d[3]);
36     }
37 }
38 
equals(const Matrix & src)39 bool Matrix::equals(const Matrix& src) {
40     bool equals = true;
41     const float* d = src.mData;
42     for (int i = 0; i < MATRIX_SIZE && equals; i++) {
43         if (mData[i] != d[i]) {
44             equals = false;
45         }
46     }
47     return equals;
48 }
49 
loadWith(const Matrix & src)50 void Matrix::loadWith(const Matrix& src) {
51     memcpy(mData, src.mData, MATRIX_SIZE * sizeof(float));
52 }
53 
identity()54 void Matrix::identity() {
55     mData[0] = 1.0f;
56     mData[1] = 0.0f;
57     mData[2] = 0.0f;
58     mData[3] = 0.0f;
59 
60     mData[4] = 0.0f;
61     mData[5] = 1.0f;
62     mData[6] = 0.0f;
63     mData[7] = 0.0f;
64 
65     mData[8] = 0.0f;
66     mData[9] = 0.0f;
67     mData[10] = 1.0f;
68     mData[11] = 0.0f;
69 
70     mData[12] = 0.0f;
71     mData[13] = 0.0f;
72     mData[14] = 0.0f;
73     mData[15] = 1.0f;
74 }
75 
translate(float x,float y,float z)76 void Matrix::translate(float x, float y, float z) {
77     Matrix* m = newTranslate(x, y, z);
78     Matrix* temp = new Matrix(*this);
79     if (m != NULL && temp != NULL) {
80         multiply(*temp, *m);
81     }
82     delete m;
83     delete temp;
84 }
85 
scale(float x,float y,float z)86 void Matrix::scale(float x, float y, float z) {
87     Matrix* m = newScale(x, y, z);
88     Matrix* temp = new Matrix(*this);
89     if (m != NULL && temp != NULL) {
90         multiply(*temp, *m);
91     }
92     delete m;
93     delete temp;
94 }
95 
rotate(float radians,float x,float y,float z)96 void Matrix::rotate(float radians, float x, float y, float z) {
97     Matrix* m = newRotate(radians, x, y, z);
98     Matrix* temp = new Matrix(*this);
99     if (m != NULL && temp != NULL) {
100         multiply(*temp, *m);
101     }
102     delete m;
103     delete temp;
104 }
105 
multiply(const Matrix & l,const Matrix & r)106 void Matrix::multiply(const Matrix& l, const Matrix& r) {
107     float const* const lhs = l.mData;
108     float const* const rhs = r.mData;
109     for (int i = 0; i < 4; i++) {
110         const int i4 = i * 4;
111         float x = 0;
112         float y = 0;
113         float z = 0;
114         float w = 0;
115 
116         for (int j = 0; j < 4; j++) {
117             const int j4 = j * 4;
118             const float e = rhs[i4 + j];
119             x += lhs[j4 + 0] * e;
120             y += lhs[j4 + 1] * e;
121             z += lhs[j4 + 2] * e;
122             w += lhs[j4 + 3] * e;
123         }
124 
125         mData[i4 + 0] = x;
126         mData[i4 + 1] = y;
127         mData[i4 + 2] = z;
128         mData[i4 + 3] = w;
129     }
130 }
131 
newLookAt(float eyeX,float eyeY,float eyeZ,float centerX,float centerY,float centerZ,float upX,float upY,float upZ)132 Matrix* Matrix::newLookAt(float eyeX, float eyeY, float eyeZ, float centerX,
133         float centerY, float centerZ, float upX, float upY, float upZ) {
134     Matrix* m = new Matrix();
135     if (m != NULL) {
136         // See the OpenGL GLUT documentation for gluLookAt for a description
137         // of the algorithm. We implement it in a straightforward way:
138 
139         float fx = centerX - eyeX;
140         float fy = centerY - eyeY;
141         float fz = centerZ - eyeZ;
142 
143         // Normalize f
144         float rlf = 1.0f / (float) sqrt(fx * fx + fy * fy + fz * fz);
145         fx *= rlf;
146         fy *= rlf;
147         fz *= rlf;
148 
149         // compute s = f x up (x means "cross product")
150         float sx = fy * upZ - fz * upY;
151         float sy = fz * upX - fx * upZ;
152         float sz = fx * upY - fy * upX;
153 
154         // and normalize s
155         float rls = 1.0f / (float) sqrt(sx * sx + sy * sy + sz * sz);
156         sx *= rls;
157         sy *= rls;
158         sz *= rls;
159 
160         // compute u = s x f
161         float ux = sy * fz - sz * fy;
162         float uy = sz * fx - sx * fz;
163         float uz = sx * fy - sy * fx;
164 
165         float* d = m->mData;
166         d[0] = sx;
167         d[1] = ux;
168         d[2] = -fx;
169         d[3] = 0.0f;
170 
171         d[4] = sy;
172         d[5] = uy;
173         d[6] = -fy;
174         d[7] = 0.0f;
175 
176         d[8] = sz;
177         d[9] = uz;
178         d[10] = -fz;
179         d[11] = 0.0f;
180 
181         d[12] = 0.0f;
182         d[13] = 0.0f;
183         d[14] = 0.0f;
184         d[15] = 1.0f;
185 
186         m->translate(-eyeX, -eyeY, -eyeZ);
187     }
188     return m;
189 }
190 
newFrustum(float left,float right,float bottom,float top,float near,float far)191 Matrix* Matrix::newFrustum(float left, float right, float bottom, float top,
192         float near, float far) {
193     const float r_width = 1.0f / (right - left);
194     const float r_height = 1.0f / (top - bottom);
195     const float r_depth = 1.0f / (near - far);
196     const float x = 2.0f * (near * r_width);
197     const float y = 2.0f * (near * r_height);
198     const float A = (right + left) * r_width;
199     const float B = (top + bottom) * r_height;
200     const float C = (far + near) * r_depth;
201     const float D = 2.0f * (far * near * r_depth);
202     Matrix* m = new Matrix();
203     if (m != NULL) {
204         float* d = m->mData;
205         d[0] = x;
206         d[5] = y;
207         d[8] = A;
208         d[9] = B;
209         d[10] = C;
210         d[14] = D;
211         d[11] = -1.0f;
212         d[1] = 0.0f;
213         d[2] = 0.0f;
214         d[3] = 0.0f;
215         d[4] = 0.0f;
216         d[6] = 0.0f;
217         d[7] = 0.0f;
218         d[12] = 0.0f;
219         d[13] = 0.0f;
220         d[15] = 0.0f;
221     }
222     return m;
223 }
224 
newTranslate(float x,float y,float z)225 Matrix* Matrix::newTranslate(float x, float y, float z) {
226     Matrix* m = new Matrix();
227     if (m != NULL) {
228         float* d = m->mData;
229         d[12] = x;
230         d[13] = y;
231         d[14] = z;
232     }
233     return m;
234 }
newScale(float x,float y,float z)235 Matrix* Matrix::newScale(float x, float y, float z) {
236     Matrix* m = new Matrix();
237     if (m != NULL) {
238         float* d = m->mData;
239         d[0] = x;
240         d[5] = y;
241         d[10] = z;
242     }
243     return m;
244 }
newRotate(float radians,float x,float y,float z)245 Matrix* Matrix::newRotate(float radians, float x, float y, float z) {
246     Matrix* m = new Matrix();
247     if (m != NULL) {
248         float* d = m->mData;
249         d[3] = 0;
250         d[7] = 0;
251         d[11] = 0;
252         d[12] = 0;
253         d[13] = 0;
254         d[14] = 0;
255         d[15] = 1;
256         float s = (float) sinf(radians);
257         float c = (float) cosf(radians);
258         if (1.0f == x && 0.0f == y && 0.0f == z) {
259             d[5] = c;
260             d[10] = c;
261             d[6] = s;
262             d[9] = -s;
263             d[1] = 0;
264             d[2] = 0;
265             d[4] = 0;
266             d[8] = 0;
267             d[0] = 1;
268         } else if (0.0f == x && 1.0f == y && 0.0f == z) {
269             d[0] = c;
270             d[10] = c;
271             d[8] = s;
272             d[2] = -s;
273             d[1] = 0;
274             d[4] = 0;
275             d[6] = 0;
276             d[9] = 0;
277             d[5] = 1;
278         } else if (0.0f == x && 0.0f == y && 1.0f == z) {
279             d[0] = c;
280             d[5] = c;
281             d[1] = s;
282             d[4] = -s;
283             d[2] = 0;
284             d[6] = 0;
285             d[8] = 0;
286             d[9] = 0;
287             d[10] = 1;
288         } else {
289             float len = sqrt((x * x) + (y * y) + (z * z));
290             if (1.0f != len) {
291                 float recipLen = 1.0f / len;
292                 x *= recipLen;
293                 y *= recipLen;
294                 z *= recipLen;
295             }
296             float nc = 1.0f - c;
297             float xy = x * y;
298             float yz = y * z;
299             float zx = z * x;
300             float xs = x * s;
301             float ys = y * s;
302             float zs = z * s;
303             d[0] = x * x * nc + c;
304             d[4] = xy * nc - zs;
305             d[8] = zx * nc + ys;
306             d[1] = xy * nc + zs;
307             d[5] = y * y * nc + c;
308             d[9] = yz * nc - xs;
309             d[2] = zx * nc - ys;
310             d[6] = yz * nc + xs;
311             d[10] = z * z * nc + c;
312         }
313     }
314     return m;
315 }
316 
multiplyVector(float * result,const Matrix & lhs,const float * rhs)317 void Matrix::multiplyVector(float* result, const Matrix& lhs,
318         const float* rhs) {
319     const float* d = lhs.mData;
320     const float x = rhs[0];
321     const float y = rhs[1];
322     const float z = rhs[2];
323     const float w = rhs[3];
324     for (int i = 0; i < 4; i++) {
325         const int j = i * 4;
326         result[i] = d[j + 0] * x + d[j + 1] * y + d[j + 2] * z + d[j + 3] * w;
327     }
328 }
329