package com.glview.hwui; import android.opengl.Matrix; import com.glview.graphics.Rect; import com.glview.graphics.Region; abstract class StatefullBaseCanvas extends AbsGLCanvas { protected final float[] mTempMatrix = new float[32]; protected Snapshot mFirstSnapshot = new Snapshot(); protected Snapshot mSnapshot = mFirstSnapshot; protected int mSaveCount = 1; protected boolean mDirtyClip = false; int mWidth; int mHeight; @Override public void setSize(int width, int height) { super.setSize(width, height); mWidth = width; mHeight = height; mFirstSnapshot.setClip(0, 0, width, height); } //设置摄像机 public void setCamera ( float cx, //摄像机位置x float cy, //摄像机位置y float cz, //摄像机位置z float tx, //摄像机目标点x float ty, //摄像机目标点y float tz, //摄像机目标点z float upx, //摄像机UP向量X分量 float upy, //摄像机UP向量Y分量 float upz //摄像机UP向量Z分量 ) { Matrix.setLookAtM ( currentSnapshot().transform, 16, cx, cy, cz, tx, ty, tz, upx, upy, upz ); } //设置正交投影参数 public void setProjectOrtho ( float left, //near面的left float right, //near面的right float bottom, //near面的bottom float top, //near面的top float near, //near面距离 float far //far面距离 ) { Matrix.orthoM(currentSnapshot().transform, 32, left, right, bottom, top, near, far); } public void setProjectFrustum ( float left, //near面的left float right, //near面的right float bottom, //near面的bottom float top, //near面的top float near, //near面距离 float far //far面距离 ) { /* * android4.0的Matrix.frustumM方法实现有问题,会出现坐标往左偏一半的问题 * 参考4.4上面的代码自己来实现透视投影 */ // Matrix.frustumM(mProjMatrix, 0, left, right, bottom, top, near, far); frustumM(currentSnapshot().transform, 32, left, right, bottom, top, near, far); } /** * Defines a projection matrix in terms of six clip planes. * * @param m the float array that holds the output perspective matrix * @param offset the offset into float array m where the perspective * matrix data is written * @param left * @param right * @param bottom * @param top * @param near * @param far */ public static void frustumM(float[] m, int offset, float left, float right, float bottom, float top, float near, float far) { if (left == right) { throw new IllegalArgumentException("left == right"); } if (top == bottom) { throw new IllegalArgumentException("top == bottom"); } if (near == far) { throw new IllegalArgumentException("near == far"); } if (near <= 0.0f) { throw new IllegalArgumentException("near <= 0.0f"); } if (far <= 0.0f) { throw new IllegalArgumentException("far <= 0.0f"); } final float r_width = 1.0f / (right - left); final float r_height = 1.0f / (top - bottom); final float r_depth = 1.0f / (near - far); final float x = 2.0f * (near * r_width); final float y = 2.0f * (near * r_height); final float A = (right + left) * r_width; final float B = (top + bottom) * r_height; final float C = (far + near) * r_depth; final float D = 2.0f * (far * near * r_depth); m[offset + 0] = x; m[offset + 5] = y; m[offset + 8] = A; m[offset + 9] = B; m[offset + 10] = C; m[offset + 14] = D; m[offset + 11] = -1.0f; m[offset + 1] = 0.0f; m[offset + 2] = 0.0f; m[offset + 3] = 0.0f; m[offset + 4] = 0.0f; m[offset + 6] = 0.0f; m[offset + 7] = 0.0f; m[offset + 12] = 0.0f; m[offset + 13] = 0.0f; m[offset + 15] = 0.0f; } //获取具体物体的总变换矩阵 public float[] getFinalMatrix(float[] outPut, float[] spec) { float[] mMVPMatrix = outPut; Matrix.multiplyMM(mMVPMatrix, 0, currentSnapshot().transform, 16, spec, 0); Matrix.multiplyMM(mMVPMatrix, 0, currentSnapshot().transform, 32, mMVPMatrix, 0); return mMVPMatrix; } @Override public int getWidth() { return mWidth; } @Override public int getHeight() { return mHeight; } Rect currentClipRect() { return currentSnapshot().clipRect; } Snapshot currentSnapshot() { return mSnapshot; } @Override public void translate(float x, float y) { translate(x, y, 0); } @Override public void translate(float x, float y, float z) { if (z == 0) { float[] m = mSnapshot.transform; m[12] += m[0] * x + m[4] * y; m[13] += m[1] * x + m[5] * y; m[14] += m[2] * x + m[6] * y; m[15] += m[3] * x + m[7] * y; } else { Matrix.translateM(mSnapshot.transform, 0, x, y, z); } } @Override public void scale(float sx, float sy, float sz) { Matrix.scaleM(mSnapshot.transform, 0, sx, sy, sz); } @Override public void rotate(float degrees, float x, float y, float z) { if (degrees == 0) return; float[] temp = mTempMatrix; Matrix.setRotateM(temp, 0, degrees, x, y, z); Matrix.multiplyMM(temp, 16, mSnapshot.transform, 0, temp, 0); System.arraycopy(temp, 16, mSnapshot.transform, 0, 16); } @Override public void multiplyMatrix(float[] matrix, int offset) { float[] temp = mTempMatrix; Matrix.multiplyMM(temp, 0, mSnapshot.transform, 0, matrix, offset); System.arraycopy(temp, 0, mSnapshot.transform, 0, 16); } public void setAlpha(float alpha) { mSnapshot.alpha = alpha < 0 ? 0 : (alpha > 1 ? 1 : alpha); } public float getAlpha() { return mSnapshot.alpha; } public void multiplyAlpha(float alpha) { mSnapshot.alpha *= alpha < 0 ? 0 : (alpha > 1 ? 1 : alpha); } @Override public int save(int saveFlags) { return saveSnapshot(saveFlags); } public void saveViewport() { currentSnapshot().flags |= Snapshot.kFlagIsFboLayer; } private int saveSnapshot(int saveFlags) { Snapshot snapshot = Snapshot.obtain(mSnapshot, saveFlags); mSnapshot = snapshot; return mSaveCount++; } @Override public void clipRect(Rect r) { clipRect(r.left, r.top, r.right, r.bottom); } @Override public void clipRect(float left, float top, float right, float bottom) { mDirtyClip |= currentSnapshot().clip(left, top, right, bottom, Region.Op.INTERSECT); } protected void dirtyClip() { mDirtyClip = true; } @Override public void restore() { if (mSaveCount > 1) { restoreSnapshot(); } } public void restoreToCount(int saveCount) { if (saveCount < 1) saveCount = 1; while (mSaveCount > saveCount) { restoreSnapshot(); } } private void restoreSnapshot() { Snapshot toRemove = mSnapshot; Snapshot toRestore = mSnapshot.previous; mSaveCount--; mSnapshot = toRestore; // subclass handles restore implementation onSnapshotRestored(toRemove, toRestore); toRemove.recycle(); } protected void onSnapshotRestored(Snapshot removed, Snapshot toRestore) { } public void drawRenderNode(RenderNode renderNode) { renderNode.replay(this); } }