package rajawali; import rajawali.math.MathUtil; import rajawali.math.Number3D; import rajawali.math.Number3D.Axis; import rajawali.math.Quaternion; import android.opengl.Matrix; public class Camera extends ATransformable3D { protected float[] mVMatrix = new float[16]; protected float[] mInvVMatrix = new float[16]; protected float[] mRotationMatrix = new float[16]; protected float[] mProjMatrix = new float[16]; protected float mNearPlane = 1.0f; protected float mFarPlane = 120.0f; protected float mFieldOfView = 45; protected Number3D mUpAxis; protected boolean mUseRotationMatrix = false; protected float[] mRotateMatrixTmp = new float[16]; protected float[] mTmpMatrix = new float[16]; protected float[] mCombinedMatrix=new float[16]; public Frustum mFrustum; protected int mFogColor = 0xdddddd; protected float mFogNear = 5; protected float mFogFar = 25; protected boolean mFogEnabled = false; // Camera's localized vectors protected Number3D mRightVector; protected Number3D mUpVector; protected Number3D mLookVector; protected Quaternion mLocalOrientation; public Camera() { super(); mLocalOrientation = Quaternion.getIdentity(); mUpAxis = new Number3D(0, 1, 0); mIsCamera = true; mFrustum = new Frustum(); } public float[] getViewMatrix() { if (mLookAt != null) { Matrix.setLookAtM(mVMatrix, 0, mPosition.x, mPosition.y, mPosition.z, mLookAt.x, mLookAt.y, mLookAt.z, mUpAxis.x, mUpAxis.y, mUpAxis.z); mLocalOrientation.fromEuler(mRotation.y, mRotation.z, mRotation.x); mLocalOrientation.toRotationMatrix(mRotationMatrix); Matrix.multiplyMM(mVMatrix, 0, mRotationMatrix, 0, mVMatrix, 0); } else { if (mUseRotationMatrix == false && mRotationDirty) { setOrientation(); mOrientation.toRotationMatrix(mRotationMatrix); mRotationDirty = false; } Matrix.setIdentityM(mTmpMatrix, 0); Matrix.setIdentityM(mVMatrix, 0); Matrix.translateM(mTmpMatrix, 0, -mPosition.x, -mPosition.y, -mPosition.z); Matrix.multiplyMM(mVMatrix, 0, mRotationMatrix, 0, mTmpMatrix, 0); } return mVMatrix; } public void updateFrustum(float[] pMatrix,float[] vMatrix) { Matrix.multiplyMM(mCombinedMatrix, 0, pMatrix, 0, vMatrix, 0); invertM(mTmpMatrix, 0, mCombinedMatrix, 0); mFrustum.update(mCombinedMatrix); } protected void rotateM(float[] m, int mOffset, float a, float x, float y, float z) { Matrix.setIdentityM(mRotateMatrixTmp, 0); Matrix.setRotateM(mRotateMatrixTmp, 0, a, x, y, z); System.arraycopy(m, 0, mTmpMatrix, 0, 16); Matrix.multiplyMM(m, mOffset, mTmpMatrix, mOffset, mRotateMatrixTmp, 0); } public void setRotationMatrix(float[] m) { mRotationMatrix = m; } public void setProjectionMatrix(int width, int height) { float ratio = (float) width / height; float frustumH = MathUtil.tan(getFieldOfView() / 360.0f * MathUtil.PI) * getNearPlane(); float frustumW = frustumH * ratio; Matrix.frustumM(mProjMatrix, 0, -frustumW, frustumW, -frustumH, frustumH, getNearPlane(), getFarPlane()); } /** * Inverts a 4 x 4 matrix. * * @param mInv the array that holds the output inverted matrix * @param mInvOffset an offset into mInv where the inverted matrix is * stored. * @param m the input array * @param mOffset an offset into m where the matrix is stored. * @return true if the matrix could be inverted, false if it could not. */ public static boolean invertM(float[] mInv, int mInvOffset, float[] m, int mOffset) { // Invert a 4 x 4 matrix using Cramer's Rule // transpose matrix final float src0 = m[mOffset + 0]; final float src4 = m[mOffset + 1]; final float src8 = m[mOffset + 2]; final float src12 = m[mOffset + 3]; final float src1 = m[mOffset + 4]; final float src5 = m[mOffset + 5]; final float src9 = m[mOffset + 6]; final float src13 = m[mOffset + 7]; final float src2 = m[mOffset + 8]; final float src6 = m[mOffset + 9]; final float src10 = m[mOffset + 10]; final float src14 = m[mOffset + 11]; final float src3 = m[mOffset + 12]; final float src7 = m[mOffset + 13]; final float src11 = m[mOffset + 14]; final float src15 = m[mOffset + 15]; // calculate pairs for first 8 elements (cofactors) final float atmp0 = src10 * src15; final float atmp1 = src11 * src14; final float atmp2 = src9 * src15; final float atmp3 = src11 * src13; final float atmp4 = src9 * src14; final float atmp5 = src10 * src13; final float atmp6 = src8 * src15; final float atmp7 = src11 * src12; final float atmp8 = src8 * src14; final float atmp9 = src10 * src12; final float atmp10 = src8 * src13; final float atmp11 = src9 * src12; // calculate first 8 elements (cofactors) final float dst0 = (atmp0 * src5 + atmp3 * src6 + atmp4 * src7) - (atmp1 * src5 + atmp2 * src6 + atmp5 * src7); final float dst1 = (atmp1 * src4 + atmp6 * src6 + atmp9 * src7) - (atmp0 * src4 + atmp7 * src6 + atmp8 * src7); final float dst2 = (atmp2 * src4 + atmp7 * src5 + atmp10 * src7) - (atmp3 * src4 + atmp6 * src5 + atmp11 * src7); final float dst3 = (atmp5 * src4 + atmp8 * src5 + atmp11 * src6) - (atmp4 * src4 + atmp9 * src5 + atmp10 * src6); final float dst4 = (atmp1 * src1 + atmp2 * src2 + atmp5 * src3) - (atmp0 * src1 + atmp3 * src2 + atmp4 * src3); final float dst5 = (atmp0 * src0 + atmp7 * src2 + atmp8 * src3) - (atmp1 * src0 + atmp6 * src2 + atmp9 * src3); final float dst6 = (atmp3 * src0 + atmp6 * src1 + atmp11 * src3) - (atmp2 * src0 + atmp7 * src1 + atmp10 * src3); final float dst7 = (atmp4 * src0 + atmp9 * src1 + atmp10 * src2) - (atmp5 * src0 + atmp8 * src1 + atmp11 * src2); // calculate pairs for second 8 elements (cofactors) final float btmp0 = src2 * src7; final float btmp1 = src3 * src6; final float btmp2 = src1 * src7; final float btmp3 = src3 * src5; final float btmp4 = src1 * src6; final float btmp5 = src2 * src5; final float btmp6 = src0 * src7; final float btmp7 = src3 * src4; final float btmp8 = src0 * src6; final float btmp9 = src2 * src4; final float btmp10 = src0 * src5; final float btmp11 = src1 * src4; // calculate second 8 elements (cofactors) final float dst8 = (btmp0 * src13 + btmp3 * src14 + btmp4 * src15) - (btmp1 * src13 + btmp2 * src14 + btmp5 * src15); final float dst9 = (btmp1 * src12 + btmp6 * src14 + btmp9 * src15) - (btmp0 * src12 + btmp7 * src14 + btmp8 * src15); final float dst10 = (btmp2 * src12 + btmp7 * src13 + btmp10 * src15) - (btmp3 * src12 + btmp6 * src13 + btmp11 * src15); final float dst11 = (btmp5 * src12 + btmp8 * src13 + btmp11 * src14) - (btmp4 * src12 + btmp9 * src13 + btmp10 * src14); final float dst12 = (btmp2 * src10 + btmp5 * src11 + btmp1 * src9 ) - (btmp4 * src11 + btmp0 * src9 + btmp3 * src10); final float dst13 = (btmp8 * src11 + btmp0 * src8 + btmp7 * src10) - (btmp6 * src10 + btmp9 * src11 + btmp1 * src8 ); final float dst14 = (btmp6 * src9 + btmp11 * src11 + btmp3 * src8 ) - (btmp10 * src11 + btmp2 * src8 + btmp7 * src9 ); final float dst15 = (btmp10 * src10 + btmp4 * src8 + btmp9 * src9 ) - (btmp8 * src9 + btmp11 * src10 + btmp5 * src8 ); // calculate determinant final float det = src0 * dst0 + src1 * dst1 + src2 * dst2 + src3 * dst3; if (det == 0.0f) { return false; } // calculate matrix inverse final float invdet = 1.0f / det; mInv[ mInvOffset] = dst0 * invdet; mInv[ 1 + mInvOffset] = dst1 * invdet; mInv[ 2 + mInvOffset] = dst2 * invdet; mInv[ 3 + mInvOffset] = dst3 * invdet; mInv[ 4 + mInvOffset] = dst4 * invdet; mInv[ 5 + mInvOffset] = dst5 * invdet; mInv[ 6 + mInvOffset] = dst6 * invdet; mInv[ 7 + mInvOffset] = dst7 * invdet; mInv[ 8 + mInvOffset] = dst8 * invdet; mInv[ 9 + mInvOffset] = dst9 * invdet; mInv[10 + mInvOffset] = dst10 * invdet; mInv[11 + mInvOffset] = dst11 * invdet; mInv[12 + mInvOffset] = dst12 * invdet; mInv[13 + mInvOffset] = dst13 * invdet; mInv[14 + mInvOffset] = dst14 * invdet; mInv[15 + mInvOffset] = dst15 * invdet; return true; } public void setUpAxis(float x, float y, float z) { mUpAxis.setAll(x, y, z); } public void setUpAxis(Number3D upAxis) { mUpAxis.setAllFrom(upAxis); } public void setUpAxis(Axis upAxis) { if(upAxis == Axis.X) mUpAxis.setAll(1, 0, 0); else if(upAxis == Axis.Y) mUpAxis.setAll(0, 1, 0); else mUpAxis.setAll(0, 0, 1); } public float[] getProjectionMatrix() { return mProjMatrix; } public float getNearPlane() { return mNearPlane; } public void setNearPlane(float nearPlane) { this.mNearPlane = nearPlane; } public float getFarPlane() { return mFarPlane; } public void setFarPlane(float farPlane) { this.mFarPlane = farPlane; } public float getFieldOfView() { return mFieldOfView; } public void setFieldOfView(float fieldOfView) { this.mFieldOfView = fieldOfView; } public boolean getUseRotationMatrix() { return mUseRotationMatrix; } public void setUseRotationMatrix(boolean useRotationMatrix) { this.mUseRotationMatrix = useRotationMatrix; } public int getFogColor() { return mFogColor; } public void setFogColor(int fogColor) { this.mFogColor = fogColor; } public float getFogNear() { return mFogNear; } public void setFogNear(float fogNear) { this.mFogNear = fogNear; } public float getFogFar() { return mFogFar; } public void setFogFar(float fogFar) { this.mFogFar = fogFar; } public boolean isFogEnabled() { return mFogEnabled; } public void setFogEnabled(boolean fogEnabled) { this.mFogEnabled = fogEnabled; } }