329 lines
8.3 KiB
C++
329 lines
8.3 KiB
C++
/*
|
|
* Copyright (C) 2013 The Android Open Source Project
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
|
|
* in compliance with the License. You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software distributed under the License
|
|
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
|
|
* or implied. See the License for the specific language governing permissions and limitations under
|
|
* the License.
|
|
*/
|
|
|
|
#include "Matrix.h"
|
|
#include <string.h>
|
|
#include <cmath>
|
|
|
|
#define LOG_TAG "CTS_OPENGL"
|
|
#define LOG_NDEBUG 0
|
|
#include "android/log.h"
|
|
|
|
Matrix::Matrix() {
|
|
identity();
|
|
}
|
|
|
|
Matrix::Matrix(const Matrix& src) {
|
|
loadWith(src);
|
|
}
|
|
|
|
void Matrix::print(const char* label) {
|
|
__android_log_print(ANDROID_LOG_INFO, LOG_TAG, "%c", *label);
|
|
for (int i = 0; i < 4; i++) {
|
|
const float* d = &(mData[i * 4]);
|
|
__android_log_print(ANDROID_LOG_INFO, LOG_TAG, "%f %f %f %f\n", d[0], d[1], d[2], d[3]);
|
|
}
|
|
}
|
|
|
|
bool Matrix::equals(const Matrix& src) {
|
|
bool equals = true;
|
|
const float* d = src.mData;
|
|
for (int i = 0; i < MATRIX_SIZE && equals; i++) {
|
|
if (mData[i] != d[i]) {
|
|
equals = false;
|
|
}
|
|
}
|
|
return equals;
|
|
}
|
|
|
|
void Matrix::loadWith(const Matrix& src) {
|
|
memcpy(mData, src.mData, MATRIX_SIZE * sizeof(float));
|
|
}
|
|
|
|
void Matrix::identity() {
|
|
mData[0] = 1.0f;
|
|
mData[1] = 0.0f;
|
|
mData[2] = 0.0f;
|
|
mData[3] = 0.0f;
|
|
|
|
mData[4] = 0.0f;
|
|
mData[5] = 1.0f;
|
|
mData[6] = 0.0f;
|
|
mData[7] = 0.0f;
|
|
|
|
mData[8] = 0.0f;
|
|
mData[9] = 0.0f;
|
|
mData[10] = 1.0f;
|
|
mData[11] = 0.0f;
|
|
|
|
mData[12] = 0.0f;
|
|
mData[13] = 0.0f;
|
|
mData[14] = 0.0f;
|
|
mData[15] = 1.0f;
|
|
}
|
|
|
|
void Matrix::translate(float x, float y, float z) {
|
|
Matrix* m = newTranslate(x, y, z);
|
|
Matrix* temp = new Matrix(*this);
|
|
if (m != NULL && temp != NULL) {
|
|
multiply(*temp, *m);
|
|
}
|
|
delete m;
|
|
delete temp;
|
|
}
|
|
|
|
void Matrix::scale(float x, float y, float z) {
|
|
Matrix* m = newScale(x, y, z);
|
|
Matrix* temp = new Matrix(*this);
|
|
if (m != NULL && temp != NULL) {
|
|
multiply(*temp, *m);
|
|
}
|
|
delete m;
|
|
delete temp;
|
|
}
|
|
|
|
void Matrix::rotate(float radians, float x, float y, float z) {
|
|
Matrix* m = newRotate(radians, x, y, z);
|
|
Matrix* temp = new Matrix(*this);
|
|
if (m != NULL && temp != NULL) {
|
|
multiply(*temp, *m);
|
|
}
|
|
delete m;
|
|
delete temp;
|
|
}
|
|
|
|
void Matrix::multiply(const Matrix& l, const Matrix& r) {
|
|
float const* const lhs = l.mData;
|
|
float const* const rhs = r.mData;
|
|
for (int i = 0; i < 4; i++) {
|
|
const int i4 = i * 4;
|
|
float x = 0;
|
|
float y = 0;
|
|
float z = 0;
|
|
float w = 0;
|
|
|
|
for (int j = 0; j < 4; j++) {
|
|
const int j4 = j * 4;
|
|
const float e = rhs[i4 + j];
|
|
x += lhs[j4 + 0] * e;
|
|
y += lhs[j4 + 1] * e;
|
|
z += lhs[j4 + 2] * e;
|
|
w += lhs[j4 + 3] * e;
|
|
}
|
|
|
|
mData[i4 + 0] = x;
|
|
mData[i4 + 1] = y;
|
|
mData[i4 + 2] = z;
|
|
mData[i4 + 3] = w;
|
|
}
|
|
}
|
|
|
|
Matrix* Matrix::newLookAt(float eyeX, float eyeY, float eyeZ, float centerX,
|
|
float centerY, float centerZ, float upX, float upY, float upZ) {
|
|
Matrix* m = new Matrix();
|
|
if (m != NULL) {
|
|
// See the OpenGL GLUT documentation for gluLookAt for a description
|
|
// of the algorithm. We implement it in a straightforward way:
|
|
|
|
float fx = centerX - eyeX;
|
|
float fy = centerY - eyeY;
|
|
float fz = centerZ - eyeZ;
|
|
|
|
// Normalize f
|
|
float rlf = 1.0f / (float) sqrt(fx * fx + fy * fy + fz * fz);
|
|
fx *= rlf;
|
|
fy *= rlf;
|
|
fz *= rlf;
|
|
|
|
// compute s = f x up (x means "cross product")
|
|
float sx = fy * upZ - fz * upY;
|
|
float sy = fz * upX - fx * upZ;
|
|
float sz = fx * upY - fy * upX;
|
|
|
|
// and normalize s
|
|
float rls = 1.0f / (float) sqrt(sx * sx + sy * sy + sz * sz);
|
|
sx *= rls;
|
|
sy *= rls;
|
|
sz *= rls;
|
|
|
|
// compute u = s x f
|
|
float ux = sy * fz - sz * fy;
|
|
float uy = sz * fx - sx * fz;
|
|
float uz = sx * fy - sy * fx;
|
|
|
|
float* d = m->mData;
|
|
d[0] = sx;
|
|
d[1] = ux;
|
|
d[2] = -fx;
|
|
d[3] = 0.0f;
|
|
|
|
d[4] = sy;
|
|
d[5] = uy;
|
|
d[6] = -fy;
|
|
d[7] = 0.0f;
|
|
|
|
d[8] = sz;
|
|
d[9] = uz;
|
|
d[10] = -fz;
|
|
d[11] = 0.0f;
|
|
|
|
d[12] = 0.0f;
|
|
d[13] = 0.0f;
|
|
d[14] = 0.0f;
|
|
d[15] = 1.0f;
|
|
|
|
m->translate(-eyeX, -eyeY, -eyeZ);
|
|
}
|
|
return m;
|
|
}
|
|
|
|
Matrix* Matrix::newFrustum(float left, float right, float bottom, float top,
|
|
float near, float far) {
|
|
const float r_width = 1.0f / (right - left);
|
|
const float r_height = 1.0f / (top - bottom);
|
|
const float r_depth = 1.0f / (near - far);
|
|
const float x = 2.0f * (near * r_width);
|
|
const float y = 2.0f * (near * r_height);
|
|
const float A = (right + left) * r_width;
|
|
const float B = (top + bottom) * r_height;
|
|
const float C = (far + near) * r_depth;
|
|
const float D = 2.0f * (far * near * r_depth);
|
|
Matrix* m = new Matrix();
|
|
if (m != NULL) {
|
|
float* d = m->mData;
|
|
d[0] = x;
|
|
d[5] = y;
|
|
d[8] = A;
|
|
d[9] = B;
|
|
d[10] = C;
|
|
d[14] = D;
|
|
d[11] = -1.0f;
|
|
d[1] = 0.0f;
|
|
d[2] = 0.0f;
|
|
d[3] = 0.0f;
|
|
d[4] = 0.0f;
|
|
d[6] = 0.0f;
|
|
d[7] = 0.0f;
|
|
d[12] = 0.0f;
|
|
d[13] = 0.0f;
|
|
d[15] = 0.0f;
|
|
}
|
|
return m;
|
|
}
|
|
|
|
Matrix* Matrix::newTranslate(float x, float y, float z) {
|
|
Matrix* m = new Matrix();
|
|
if (m != NULL) {
|
|
float* d = m->mData;
|
|
d[12] = x;
|
|
d[13] = y;
|
|
d[14] = z;
|
|
}
|
|
return m;
|
|
}
|
|
Matrix* Matrix::newScale(float x, float y, float z) {
|
|
Matrix* m = new Matrix();
|
|
if (m != NULL) {
|
|
float* d = m->mData;
|
|
d[0] = x;
|
|
d[5] = y;
|
|
d[10] = z;
|
|
}
|
|
return m;
|
|
}
|
|
Matrix* Matrix::newRotate(float radians, float x, float y, float z) {
|
|
Matrix* m = new Matrix();
|
|
if (m != NULL) {
|
|
float* d = m->mData;
|
|
d[3] = 0;
|
|
d[7] = 0;
|
|
d[11] = 0;
|
|
d[12] = 0;
|
|
d[13] = 0;
|
|
d[14] = 0;
|
|
d[15] = 1;
|
|
float s = (float) sinf(radians);
|
|
float c = (float) cosf(radians);
|
|
if (1.0f == x && 0.0f == y && 0.0f == z) {
|
|
d[5] = c;
|
|
d[10] = c;
|
|
d[6] = s;
|
|
d[9] = -s;
|
|
d[1] = 0;
|
|
d[2] = 0;
|
|
d[4] = 0;
|
|
d[8] = 0;
|
|
d[0] = 1;
|
|
} else if (0.0f == x && 1.0f == y && 0.0f == z) {
|
|
d[0] = c;
|
|
d[10] = c;
|
|
d[8] = s;
|
|
d[2] = -s;
|
|
d[1] = 0;
|
|
d[4] = 0;
|
|
d[6] = 0;
|
|
d[9] = 0;
|
|
d[5] = 1;
|
|
} else if (0.0f == x && 0.0f == y && 1.0f == z) {
|
|
d[0] = c;
|
|
d[5] = c;
|
|
d[1] = s;
|
|
d[4] = -s;
|
|
d[2] = 0;
|
|
d[6] = 0;
|
|
d[8] = 0;
|
|
d[9] = 0;
|
|
d[10] = 1;
|
|
} else {
|
|
float len = sqrt((x * x) + (y * y) + (z * z));
|
|
if (1.0f != len) {
|
|
float recipLen = 1.0f / len;
|
|
x *= recipLen;
|
|
y *= recipLen;
|
|
z *= recipLen;
|
|
}
|
|
float nc = 1.0f - c;
|
|
float xy = x * y;
|
|
float yz = y * z;
|
|
float zx = z * x;
|
|
float xs = x * s;
|
|
float ys = y * s;
|
|
float zs = z * s;
|
|
d[0] = x * x * nc + c;
|
|
d[4] = xy * nc - zs;
|
|
d[8] = zx * nc + ys;
|
|
d[1] = xy * nc + zs;
|
|
d[5] = y * y * nc + c;
|
|
d[9] = yz * nc - xs;
|
|
d[2] = zx * nc - ys;
|
|
d[6] = yz * nc + xs;
|
|
d[10] = z * z * nc + c;
|
|
}
|
|
}
|
|
return m;
|
|
}
|
|
|
|
void Matrix::multiplyVector(float* result, const Matrix& lhs,
|
|
const float* rhs) {
|
|
const float* d = lhs.mData;
|
|
const float x = rhs[0];
|
|
const float y = rhs[1];
|
|
const float z = rhs[2];
|
|
const float w = rhs[3];
|
|
for (int i = 0; i < 4; i++) {
|
|
const int j = i * 4;
|
|
result[i] = d[j + 0] * x + d[j + 1] * y + d[j + 2] * z + d[j + 3] * w;
|
|
}
|
|
}
|