// Copyright 2008 Google Inc. // // 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. package com.google.android.stardroid.util; import com.google.android.stardroid.units.Vector3; public class Matrix4x4 { public Matrix4x4() {} public Matrix4x4(float[] contents) { assert(contents.length == 16); for (int i = 0; i < 16; ++i) { mValues[i] = contents[i]; } } public static Matrix4x4 createIdentity() { return createScaling(1, 1, 1); } public static Matrix4x4 createScaling(float x, float y, float z) { return new Matrix4x4(new float[] { x, 0, 0, 0, 0, y, 0, 0, 0, 0, z, 0, 0, 0, 0, 1}); } public static Matrix4x4 createTranslation(float x, float y, float z) { return new Matrix4x4(new float[] { 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, x, y, z, 1}); } // axis MUST be normalized. public static Matrix4x4 createRotation(float angle, Vector3 axis) { float[] m = new float[16]; float xSqr = axis.x * axis.x; float ySqr = axis.y * axis.y; float zSqr = axis.z * axis.z; float sinAngle = MathUtil.sin(angle); float cosAngle = MathUtil.cos(angle); float oneMinusCosAngle = 1 - cosAngle; float xSinAngle = axis.x * sinAngle; float ySinAngle = axis.y * sinAngle; float zSinAngle = axis.z * sinAngle; float zOneMinusCosAngle = axis.z * oneMinusCosAngle; float xyOneMinusCosAngle = axis.x * axis.y * oneMinusCosAngle; float xzOneMinusCosAngle = axis.x * zOneMinusCosAngle; float yzOneMinusCosAngle = axis.y * zOneMinusCosAngle; m[0] = xSqr + (ySqr + zSqr) * cosAngle; m[1] = xyOneMinusCosAngle + zSinAngle; m[2] = xzOneMinusCosAngle - ySinAngle; m[3] = 0; m[4] = xyOneMinusCosAngle - zSinAngle; m[5] = ySqr + (xSqr + zSqr) * cosAngle; m[6] = yzOneMinusCosAngle + xSinAngle; m[7] = 0; m[8] = xzOneMinusCosAngle + ySinAngle; m[9] = yzOneMinusCosAngle - xSinAngle; m[10] = zSqr + (xSqr + ySqr) * cosAngle; m[11] = 0; m[12] = 0; m[13] = 0; m[14] = 0; m[15] = 1; return new Matrix4x4(m); } public static Matrix4x4 createPerspectiveProjection(float width, float height, float fovyInRadians) { float near = 0.01f; float far = 10000.0f; float inverseAspectRatio = height / width; float oneOverTanHalfRadiusOfView = 1.0f / MathUtil.tan(fovyInRadians); return new Matrix4x4(new float[]{ inverseAspectRatio * oneOverTanHalfRadiusOfView, 0, 0, 0, 0, oneOverTanHalfRadiusOfView, 0, 0, 0, 0, -(far + near) / (far - near), -1, 0, 0, -2*far*near / (far - near), 0}); } public static Matrix4x4 createView(Vector3 lookDir, Vector3 up, Vector3 right) { return new Matrix4x4(new float[] { right.x, up.x, -lookDir.x, 0, right.y, up.y, -lookDir.y, 0, right.z, up.z, -lookDir.z, 0, 0, 0, 0, 1,}); } public static Matrix4x4 multiplyMM(Matrix4x4 mat1, Matrix4x4 mat2) { float[] m = mat1.mValues; float[] n = mat2.mValues; return new Matrix4x4(new float[] { m[0]*n[0] + m[4]*n[1] + m[8]*n[2] + m[12]*n[3], m[1]*n[0] + m[5]*n[1] + m[9]*n[2] + m[13]*n[3], m[2]*n[0] + m[6]*n[1] + m[10]*n[2] + m[14]*n[3], m[3]*n[0] + m[7]*n[1] + m[11]*n[2] + m[15]*n[3], m[0]*n[4] + m[4]*n[5] + m[8]*n[6] + m[12]*n[7], m[1]*n[4] + m[5]*n[5] + m[9]*n[6] + m[13]*n[7], m[2]*n[4] + m[6]*n[5] + m[10]*n[6] + m[14]*n[7], m[3]*n[4] + m[7]*n[5] + m[11]*n[6] + m[15]*n[7], m[0]*n[8] + m[4]*n[9] + m[8]*n[10] + m[12]*n[11], m[1]*n[8] + m[5]*n[9] + m[9]*n[10] + m[13]*n[11], m[2]*n[8] + m[6]*n[9] + m[10]*n[10] + m[14]*n[11], m[3]*n[8] + m[7]*n[9] + m[11]*n[10] + m[15]*n[11], m[0]*n[12] + m[4]*n[13] + m[8]*n[14] + m[12]*n[15], m[1]*n[12] + m[5]*n[13] + m[9]*n[14] + m[13]*n[15], m[2]*n[12] + m[6]*n[13] + m[10]*n[14] + m[14]*n[15], m[3]*n[12] + m[7]*n[13] + m[11]*n[14] + m[15]*n[15]}); } public static Vector3 multiplyMV(Matrix4x4 mat, Vector3 v) { float[] m = mat.mValues; return new Vector3( m[0]*v.x + m[4]*v.y + m[8]*v.z + m[12], m[1]*v.x + m[5]*v.y + m[9]*v.z + m[13], m[2]*v.x + m[6]*v.y + m[10]*v.z + m[14]); } /** * Used to perform a perspective transformation. This multiplies the given * vector by the matrix, but also divides the x and y components by the w * component of the result, as needed when doing perspective projections. */ public static Vector3 transformVector(Matrix4x4 mat, Vector3 v) { Vector3 trans = multiplyMV(mat, v); float[] m = mat.mValues; float w = m[3]*v.x + m[7]*v.y + m[11]*v.z + m[15]; float oneOverW = 1.0f / w; trans.x *= oneOverW; trans.y *= oneOverW; // Don't transform z, we just leave it as a "pseudo-depth". return trans; } public float[] getFloatArray() { return mValues; } private float[] mValues = new float[16]; }