package com.glview.graphics;
public class Matrix44 {
private static ThreadLocal<Matrix44> sThreadLocal = new ThreadLocal<Matrix44>() {
protected Matrix44 initialValue() {
return new Matrix44();
};
};
private static ThreadLocal<Matrix44> sConcatTmp = new ThreadLocal<Matrix44>() {
protected Matrix44 initialValue() {
return new Matrix44();
};
};
private final float[] data = new float[16];
private final static int kScaleX = 0;
private final static int kSkewY = 1;
private final static int kPerspective0 = 3;
private final static int kSkewX = 4;
private final static int kScaleY = 5;
private final static int kPerspective1 = 7;
private final static int kScaleZ = 10;
private final static int kTranslateX = 12;
private final static int kTranslateY = 13;
private final static int kTranslateZ = 14;
private final static int kPerspective2 = 15;
public Matrix44() {
reset();
}
private void loadIdentity() {
data[kScaleX] = 1.0f;
data[kSkewY] = 0.0f;
data[2] = 0.0f;
data[kPerspective0] = 0.0f;
data[kSkewX] = 0.0f;
data[kScaleY] = 1.0f;
data[6] = 0.0f;
data[kPerspective1] = 0.0f;
data[8] = 0.0f;
data[9] = 0.0f;
data[kScaleZ] = 1.0f;
data[11] = 0.0f;
data[kTranslateX] = 0.0f;
data[kTranslateY] = 0.0f;
data[kTranslateZ] = 0.0f;
data[kPerspective2] = 1.0f;
}
private float get(int i, int j) {
return data[i * 4 + j];
}
private void set(int i, int j, float v) {
data[i * 4 + j] = v;
}
public void reset() {
loadIdentity();
}
public void load(Matrix44 v) {
System.arraycopy(v.data, 0, data, 0, data.length);
}
public void setConcat(Matrix44 a, Matrix44 b) {
Matrix44 tmp = sConcatTmp.get();
tmp.reset();
for (int i = 0 ; i < 4 ; i++) {
float x = 0;
float y = 0;
float z = 0;
float w = 0;
for (int j = 0 ; j < 4 ; j++) {
float e = a.get(i, j);
x += b.get(j, 0) * e;
y += b.get(j, 1) * e;
z += b.get(j, 2) * e;
w += b.get(j, 3) * e;
}
tmp.set(i, 0, x);
tmp.set(i, 1, y);
tmp.set(i, 2, z);
tmp.set(i, 3, w);
}
load(tmp);
}
public void postConcat(Matrix44 mat) {
this.setConcat(mat, this);
}
public void preConcat(Matrix44 mat) {
this.setConcat(this, mat);
}
public void setScale(float sx, float sy, float sz) {
loadIdentity();
data[kScaleX] = sx;
data[kScaleY] = sy;
data[kScaleZ] = sz;
}
public void preScale(float sx, float sy, float sz) {
if (1 == sx && 1 == sy && 1 == sz) {
return;
}
for (int i = 0 ; i < 4 ; i ++) {
data[ i] *= sx;
data[ 4 + i] *= sy;
data[ 8 + i] *= sz;
}
}
public void postScale(float sx, float sy, float sz) {
if (1 == sx && 1 == sy && 1 == sz) {
return;
}
Matrix44 m = sThreadLocal.get();
m.setScale(sx, sy, sz);
postConcat(m);
}
public void setTranslate(float dx, float dy, float dz) {
loadIdentity();
data[kTranslateX] = dx;
data[kTranslateY] = dy;
data[kTranslateZ] = dz;
}
public void preTranslate(float dx, float dy, float dz) {
if (dx == 0 && dy == 0 && dz == 0) {
return;
}
Matrix44 m = sThreadLocal.get();
m.setTranslate(dx, dy, dz);
preConcat(m);
}
public void postTranslate(float dx, float dy, float dz) {
if (dx == 0 && dy == 0 && dz == 0) {
return;
}
Matrix44 m = sThreadLocal.get();
m.setTranslate(dx, dy, dz);
postConcat(m);
}
public void setRotate(float degrees) {
setRotate(degrees, 0, 0, 1);
}
public void setRotate(float a, float x, float y, float z) {
data[3] = 0;
data[7] = 0;
data[11]= 0;
data[12]= 0;
data[13]= 0;
data[14]= 0;
data[15]= 1;
a *= (float) (Math.PI / 180.0f);
float s = (float) Math.sin(a);
float c = (float) Math.cos(a);
if (1.0f == x && 0.0f == y && 0.0f == z) {
data[5] = c; data[10]= c;
data[6] = s; data[9] = -s;
data[1] = 0; data[2] = 0;
data[4] = 0; data[8] = 0;
data[0] = 1;
} else if (0.0f == x && 1.0f == y && 0.0f == z) {
data[0] = c; data[10]= c;
data[8] = s; data[2] = -s;
data[1] = 0; data[4] = 0;
data[6] = 0; data[9] = 0;
data[5] = 1;
} else if (0.0f == x && 0.0f == y && 1.0f == z) {
data[0] = c; data[5] = c;
data[1] = s; data[4] = -s;
data[2] = 0; data[6] = 0;
data[8] = 0; data[9] = 0;
data[10]= 1;
} else {
float len = length(x, y, 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;
data[ 0] = x*x*nc + c;
data[ 4] = xy*nc - zs;
data[ 8] = zx*nc + ys;
data[ 1] = xy*nc + zs;
data[ 5] = y*y*nc + c;
data[ 9] = yz*nc - xs;
data[ 2] = zx*nc - ys;
data[ 6] = yz*nc + xs;
data[10] = z*z*nc + c;
}
}
public void preRotate(float degrees) {
Matrix44 m = sThreadLocal.get();
m.setRotate(degrees);
preConcat(m);
}
public void postRotate(float degrees) {
Matrix44 m = sThreadLocal.get();
m.setRotate(degrees);
postConcat(m);
}
public void preRotate(float a, float x, float y, float z) {
Matrix44 m = sThreadLocal.get();
m.setRotate(a, x, y, z);
preConcat(m);
}
public void postRotate(float a, float x, float y, float z) {
Matrix44 m = sThreadLocal.get();
m.setRotate(a, x, y, z);
postConcat(m);
}
/**
* Computes the length of a vector.
*
* @param x x coordinate of a vector
* @param y y coordinate of a vector
* @param z z coordinate of a vector
* @return the length of a vector
*/
public static float length(float x, float y, float z) {
return (float) Math.sqrt(x * x + y * y + z * z);
}
public PointF mapPoint(PointF dst, float x, float y) {
float dx = x * data[kScaleX] + y * data[kSkewX] + data[kTranslateX];
float dy = x * data[kSkewY] + y * data[kScaleY] + data[kTranslateY];
float dz = x * data[kPerspective0] + y * data[kPerspective1] + data[kPerspective2];
if (dz != 0) dz = 1.0f / dz;
dst.x = dx * dz;
dst.y = dy * dz;
return dst;
}
}