1f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin/*
2f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * Copyright (C) 2010 The Android Open Source Project
3f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin *
4f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * Licensed under the Apache License, Version 2.0 (the "License");
5f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * you may not use this file except in compliance with the License.
6f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * You may obtain a copy of the License at
7f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin *
8f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin *      http://www.apache.org/licenses/LICENSE-2.0
9f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin *
10f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * Unless required by applicable law or agreed to in writing, software
11f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * distributed under the License is distributed on an "AS IS" BASIS,
12f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * See the License for the specific language governing permissions and
14f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * limitations under the License.
15f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin */
16f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
17a4eae1abb4f2547dfbda84301ee764ce35464881John Reckpackage com.android.gallery3d.glrenderer;
18f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
197da54d7e41e04ea5122009b40de19be0724e1ca4George Mountimport android.graphics.Bitmap;
2064072a071151b55fcbf97f6204d3c2258db386faGeorge Mountimport android.graphics.Rect;
21f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport android.graphics.RectF;
22f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport android.opengl.GLU;
237da54d7e41e04ea5122009b40de19be0724e1ca4George Mountimport android.opengl.GLUtils;
24f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport android.opengl.Matrix;
25a4eae1abb4f2547dfbda84301ee764ce35464881John Reckimport android.util.Log;
26f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
272b3ee0ea07246b859a5b75d8a6102a7cce7ec838Owen Linimport com.android.gallery3d.common.Utils;
282b3ee0ea07246b859a5b75d8a6102a7cce7ec838Owen Linimport com.android.gallery3d.util.IntArray;
292b3ee0ea07246b859a5b75d8a6102a7cce7ec838Owen Lin
30a4eae1abb4f2547dfbda84301ee764ce35464881John Reckimport junit.framework.Assert;
31a4eae1abb4f2547dfbda84301ee764ce35464881John Reck
327da54d7e41e04ea5122009b40de19be0724e1ca4George Mountimport java.nio.Buffer;
33f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport java.nio.ByteBuffer;
34f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport java.nio.ByteOrder;
35f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport java.nio.FloatBuffer;
36cfa105d3934c4dfa14f02b693bfa97c8d17d56a9Chih-Chung Changimport java.util.ArrayList;
372b3ee0ea07246b859a5b75d8a6102a7cce7ec838Owen Lin
38f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport javax.microedition.khronos.opengles.GL10;
39f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport javax.microedition.khronos.opengles.GL11;
40f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport javax.microedition.khronos.opengles.GL11Ext;
418ac2e8630f33f4d5f65731dc56efa9bfb3570cd7Owen Linimport javax.microedition.khronos.opengles.GL11ExtensionPack;
42f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
4350b33abe053ccab7be3d1bca2328e792507963d4George Mountpublic class GLES11Canvas implements GLCanvas {
44f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    @SuppressWarnings("unused")
45f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private static final String TAG = "GLCanvasImp";
46f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
47f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private static final float OPAQUE_ALPHA = 0.95f;
48f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
49f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private static final int OFFSET_FILL_RECT = 0;
50f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private static final int OFFSET_DRAW_LINE = 4;
51f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private static final int OFFSET_DRAW_RECT = 6;
52f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private static final float[] BOX_COORDINATES = {
53f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            0, 0, 1, 0, 0, 1, 1, 1,  // used for filling a rectangle
54f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            0, 0, 1, 1,              // used for drawing a line
55f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            0, 0, 0, 1, 1, 1, 1, 0}; // used for drawing the outline of a rectangle
56f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
576eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    private GL11 mGL;
58f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
59f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private final float mMatrixValues[] = new float[16];
60f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private final float mTextureMatrixValues[] = new float[16];
61f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
62174cac8f92029fc2829c94f274e70793ae948931Chih-Chung Chang    // The results of mapPoints are stored in this buffer, and the order is
63174cac8f92029fc2829c94f274e70793ae948931Chih-Chung Chang    // x1, y1, x2, y2.
64174cac8f92029fc2829c94f274e70793ae948931Chih-Chung Chang    private final float mMapPointsBuffer[] = new float[4];
65f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
66f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private final float mTextureColor[] = new float[4];
67f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
68f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private int mBoxCoords;
69f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
706eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    private GLState mGLState;
718ac2e8630f33f4d5f65731dc56efa9bfb3570cd7Owen Lin    private final ArrayList<RawTexture> mTargetStack = new ArrayList<RawTexture>();
72f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
73f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private float mAlpha;
748ac2e8630f33f4d5f65731dc56efa9bfb3570cd7Owen Lin    private final ArrayList<ConfigState> mRestoreStack = new ArrayList<ConfigState>();
75f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private ConfigState mRecycledRestoreAction;
76f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
77f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private final RectF mDrawTextureSourceRect = new RectF();
78f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private final RectF mDrawTextureTargetRect = new RectF();
79f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private final float[] mTempMatrix = new float[32];
80f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private final IntArray mUnboundTextures = new IntArray();
81f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private final IntArray mDeleteBuffers = new IntArray();
828ac2e8630f33f4d5f65731dc56efa9bfb3570cd7Owen Lin    private int mScreenWidth;
838ac2e8630f33f4d5f65731dc56efa9bfb3570cd7Owen Lin    private int mScreenHeight;
84f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private boolean mBlendEnabled = true;
858ac2e8630f33f4d5f65731dc56efa9bfb3570cd7Owen Lin    private int mFrameBuffer[] = new int[1];
867da54d7e41e04ea5122009b40de19be0724e1ca4George Mount    private static float[] sCropRect = new float[4];
878ac2e8630f33f4d5f65731dc56efa9bfb3570cd7Owen Lin
888ac2e8630f33f4d5f65731dc56efa9bfb3570cd7Owen Lin    private RawTexture mTargetTexture;
89f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
90f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    // Drawing statistics
91f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    int mCountDrawLine;
92f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    int mCountFillRect;
93f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    int mCountDrawMesh;
94f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    int mCountTextureRect;
95f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    int mCountTextureOES;
96f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
9750b33abe053ccab7be3d1bca2328e792507963d4George Mount    private static GLId mGLId = new GLES11IdImpl();
9850b33abe053ccab7be3d1bca2328e792507963d4George Mount
9950b33abe053ccab7be3d1bca2328e792507963d4George Mount    public GLES11Canvas(GL11 gl) {
10050b33abe053ccab7be3d1bca2328e792507963d4George Mount        mGL = gl;
10150b33abe053ccab7be3d1bca2328e792507963d4George Mount        mGLState = new GLState(gl);
10250b33abe053ccab7be3d1bca2328e792507963d4George Mount        // First create an nio buffer, then create a VBO from it.
10350b33abe053ccab7be3d1bca2328e792507963d4George Mount        int size = BOX_COORDINATES.length * Float.SIZE / Byte.SIZE;
10450b33abe053ccab7be3d1bca2328e792507963d4George Mount        FloatBuffer xyBuffer = allocateDirectNativeOrderBuffer(size).asFloatBuffer();
10550b33abe053ccab7be3d1bca2328e792507963d4George Mount        xyBuffer.put(BOX_COORDINATES, 0, BOX_COORDINATES.length).position(0);
10650b33abe053ccab7be3d1bca2328e792507963d4George Mount
10750b33abe053ccab7be3d1bca2328e792507963d4George Mount        int[] name = new int[1];
10850b33abe053ccab7be3d1bca2328e792507963d4George Mount        mGLId.glGenBuffers(1, name, 0);
10950b33abe053ccab7be3d1bca2328e792507963d4George Mount        mBoxCoords = name[0];
11050b33abe053ccab7be3d1bca2328e792507963d4George Mount
11150b33abe053ccab7be3d1bca2328e792507963d4George Mount        gl.glBindBuffer(GL11.GL_ARRAY_BUFFER, mBoxCoords);
11250b33abe053ccab7be3d1bca2328e792507963d4George Mount        gl.glBufferData(GL11.GL_ARRAY_BUFFER, xyBuffer.capacity() * (Float.SIZE / Byte.SIZE),
11350b33abe053ccab7be3d1bca2328e792507963d4George Mount                xyBuffer, GL11.GL_STATIC_DRAW);
11450b33abe053ccab7be3d1bca2328e792507963d4George Mount
11550b33abe053ccab7be3d1bca2328e792507963d4George Mount        gl.glVertexPointer(2, GL11.GL_FLOAT, 0, 0);
11650b33abe053ccab7be3d1bca2328e792507963d4George Mount        gl.glTexCoordPointer(2, GL11.GL_FLOAT, 0, 0);
11750b33abe053ccab7be3d1bca2328e792507963d4George Mount
11850b33abe053ccab7be3d1bca2328e792507963d4George Mount        // Enable the texture coordinate array for Texture 1
11950b33abe053ccab7be3d1bca2328e792507963d4George Mount        gl.glClientActiveTexture(GL11.GL_TEXTURE1);
12050b33abe053ccab7be3d1bca2328e792507963d4George Mount        gl.glTexCoordPointer(2, GL11.GL_FLOAT, 0, 0);
12150b33abe053ccab7be3d1bca2328e792507963d4George Mount        gl.glClientActiveTexture(GL11.GL_TEXTURE0);
12250b33abe053ccab7be3d1bca2328e792507963d4George Mount        gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
12350b33abe053ccab7be3d1bca2328e792507963d4George Mount
12450b33abe053ccab7be3d1bca2328e792507963d4George Mount        // mMatrixValues and mAlpha will be initialized in setSize()
125f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
126f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
1277817979db0c52ffeacb951625b1e821eba303285Ahbong Chang    @Override
128f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    public void setSize(int width, int height) {
129a4eae1abb4f2547dfbda84301ee764ce35464881John Reck        Assert.assertTrue(width >= 0 && height >= 0);
1308ac2e8630f33f4d5f65731dc56efa9bfb3570cd7Owen Lin
1318ac2e8630f33f4d5f65731dc56efa9bfb3570cd7Owen Lin        if (mTargetTexture == null) {
1328ac2e8630f33f4d5f65731dc56efa9bfb3570cd7Owen Lin            mScreenWidth = width;
1338ac2e8630f33f4d5f65731dc56efa9bfb3570cd7Owen Lin            mScreenHeight = height;
1348ac2e8630f33f4d5f65731dc56efa9bfb3570cd7Owen Lin        }
1358ac2e8630f33f4d5f65731dc56efa9bfb3570cd7Owen Lin        mAlpha = 1.0f;
136f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
137f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        GL11 gl = mGL;
138f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        gl.glViewport(0, 0, width, height);
139f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        gl.glMatrixMode(GL11.GL_PROJECTION);
140f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        gl.glLoadIdentity();
141f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        GLU.gluOrtho2D(gl, 0, width, 0, height);
142f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
143f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        gl.glMatrixMode(GL11.GL_MODELVIEW);
144f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        gl.glLoadIdentity();
145f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
1468ac2e8630f33f4d5f65731dc56efa9bfb3570cd7Owen Lin        float matrix[] = mMatrixValues;
147f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        Matrix.setIdentityM(matrix, 0);
1488ac2e8630f33f4d5f65731dc56efa9bfb3570cd7Owen Lin        // to match the graphic coordinate system in android, we flip it vertically.
1498ac2e8630f33f4d5f65731dc56efa9bfb3570cd7Owen Lin        if (mTargetTexture == null) {
1508ac2e8630f33f4d5f65731dc56efa9bfb3570cd7Owen Lin            Matrix.translateM(matrix, 0, 0, height, 0);
1518ac2e8630f33f4d5f65731dc56efa9bfb3570cd7Owen Lin            Matrix.scaleM(matrix, 0, 1, -1, 1);
1528ac2e8630f33f4d5f65731dc56efa9bfb3570cd7Owen Lin        }
153f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
154f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
1557817979db0c52ffeacb951625b1e821eba303285Ahbong Chang    @Override
156f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    public void setAlpha(float alpha) {
157a4eae1abb4f2547dfbda84301ee764ce35464881John Reck        Assert.assertTrue(alpha >= 0 && alpha <= 1);
158f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        mAlpha = alpha;
159f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
160f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
1617817979db0c52ffeacb951625b1e821eba303285Ahbong Chang    @Override
1627b83fb8e3a8978b33a6b9bfc56d85fe2c1a9cf06Chih-Chung Chang    public float getAlpha() {
1637b83fb8e3a8978b33a6b9bfc56d85fe2c1a9cf06Chih-Chung Chang        return mAlpha;
1647b83fb8e3a8978b33a6b9bfc56d85fe2c1a9cf06Chih-Chung Chang    }
1657b83fb8e3a8978b33a6b9bfc56d85fe2c1a9cf06Chih-Chung Chang
1667817979db0c52ffeacb951625b1e821eba303285Ahbong Chang    @Override
167f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    public void multiplyAlpha(float alpha) {
168a4eae1abb4f2547dfbda84301ee764ce35464881John Reck        Assert.assertTrue(alpha >= 0 && alpha <= 1);
169f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        mAlpha *= alpha;
170f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
171f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
172f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private static ByteBuffer allocateDirectNativeOrderBuffer(int size) {
173f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        return ByteBuffer.allocateDirect(size).order(ByteOrder.nativeOrder());
174f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
175f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
1766eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    @Override
177f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    public void drawRect(float x, float y, float width, float height, GLPaint paint) {
178f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        GL11 gl = mGL;
179f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
180f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        mGLState.setColorMode(paint.getColor(), mAlpha);
181f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        mGLState.setLineWidth(paint.getLineWidth());
182f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
183f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        saveTransform();
184174cac8f92029fc2829c94f274e70793ae948931Chih-Chung Chang        translate(x, y);
185f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        scale(width, height, 1);
186f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
187f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        gl.glLoadMatrixf(mMatrixValues, 0);
188f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        gl.glDrawArrays(GL11.GL_LINE_LOOP, OFFSET_DRAW_RECT, 4);
189f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
190f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        restoreTransform();
191f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        mCountDrawLine++;
192f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
193f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
1947817979db0c52ffeacb951625b1e821eba303285Ahbong Chang    @Override
195f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    public void drawLine(float x1, float y1, float x2, float y2, GLPaint paint) {
196f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        GL11 gl = mGL;
197f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
198f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        mGLState.setColorMode(paint.getColor(), mAlpha);
199f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        mGLState.setLineWidth(paint.getLineWidth());
200f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
201f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        saveTransform();
202174cac8f92029fc2829c94f274e70793ae948931Chih-Chung Chang        translate(x1, y1);
203f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        scale(x2 - x1, y2 - y1, 1);
204f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
205f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        gl.glLoadMatrixf(mMatrixValues, 0);
206f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        gl.glDrawArrays(GL11.GL_LINE_STRIP, OFFSET_DRAW_LINE, 2);
207f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
208f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        restoreTransform();
209f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        mCountDrawLine++;
210f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
211f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
2127817979db0c52ffeacb951625b1e821eba303285Ahbong Chang    @Override
213f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    public void fillRect(float x, float y, float width, float height, int color) {
214f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        mGLState.setColorMode(color, mAlpha);
215f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        GL11 gl = mGL;
216f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
217f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        saveTransform();
218174cac8f92029fc2829c94f274e70793ae948931Chih-Chung Chang        translate(x, y);
219f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        scale(width, height, 1);
220f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
221f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        gl.glLoadMatrixf(mMatrixValues, 0);
222f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        gl.glDrawArrays(GL11.GL_TRIANGLE_STRIP, OFFSET_FILL_RECT, 4);
223f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
224f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        restoreTransform();
225f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        mCountFillRect++;
226f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
227f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
2287817979db0c52ffeacb951625b1e821eba303285Ahbong Chang    @Override
229f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    public void translate(float x, float y, float z) {
230f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        Matrix.translateM(mMatrixValues, 0, x, y, z);
231f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
232f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
233174cac8f92029fc2829c94f274e70793ae948931Chih-Chung Chang    // This is a faster version of translate(x, y, z) because
234174cac8f92029fc2829c94f274e70793ae948931Chih-Chung Chang    // (1) we knows z = 0, (2) we inline the Matrix.translateM call,
235174cac8f92029fc2829c94f274e70793ae948931Chih-Chung Chang    // (3) we unroll the loop
2367817979db0c52ffeacb951625b1e821eba303285Ahbong Chang    @Override
237174cac8f92029fc2829c94f274e70793ae948931Chih-Chung Chang    public void translate(float x, float y) {
238174cac8f92029fc2829c94f274e70793ae948931Chih-Chung Chang        float[] m = mMatrixValues;
239174cac8f92029fc2829c94f274e70793ae948931Chih-Chung Chang        m[12] += m[0] * x + m[4] * y;
240174cac8f92029fc2829c94f274e70793ae948931Chih-Chung Chang        m[13] += m[1] * x + m[5] * y;
241174cac8f92029fc2829c94f274e70793ae948931Chih-Chung Chang        m[14] += m[2] * x + m[6] * y;
242174cac8f92029fc2829c94f274e70793ae948931Chih-Chung Chang        m[15] += m[3] * x + m[7] * y;
243174cac8f92029fc2829c94f274e70793ae948931Chih-Chung Chang    }
244174cac8f92029fc2829c94f274e70793ae948931Chih-Chung Chang
2457817979db0c52ffeacb951625b1e821eba303285Ahbong Chang    @Override
246f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    public void scale(float sx, float sy, float sz) {
247f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        Matrix.scaleM(mMatrixValues, 0, sx, sy, sz);
248f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
249f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
2507817979db0c52ffeacb951625b1e821eba303285Ahbong Chang    @Override
251f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    public void rotate(float angle, float x, float y, float z) {
252cfa105d3934c4dfa14f02b693bfa97c8d17d56a9Chih-Chung Chang        if (angle == 0) return;
253f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        float[] temp = mTempMatrix;
254f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        Matrix.setRotateM(temp, 0, angle, x, y, z);
255f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        Matrix.multiplyMM(temp, 16, mMatrixValues, 0, temp, 0);
256f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        System.arraycopy(temp, 16, mMatrixValues, 0, 16);
257f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
258f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
2597817979db0c52ffeacb951625b1e821eba303285Ahbong Chang    @Override
260f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    public void multiplyMatrix(float matrix[], int offset) {
261f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        float[] temp = mTempMatrix;
262532d93caddc91a7aa33ca113adbc0b8255d498ebChih-Chung Chang        Matrix.multiplyMM(temp, 0, mMatrixValues, 0, matrix, offset);
263f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        System.arraycopy(temp, 0, mMatrixValues, 0, 16);
264f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
265f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
266f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private void textureRect(float x, float y, float width, float height) {
267f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        GL11 gl = mGL;
268f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
269f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        saveTransform();
270174cac8f92029fc2829c94f274e70793ae948931Chih-Chung Chang        translate(x, y);
271f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        scale(width, height, 1);
272f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
273f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        gl.glLoadMatrixf(mMatrixValues, 0);
274f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        gl.glDrawArrays(GL11.GL_TRIANGLE_STRIP, OFFSET_FILL_RECT, 4);
275f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
276f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        restoreTransform();
277f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        mCountTextureRect++;
278f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
279f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
2807817979db0c52ffeacb951625b1e821eba303285Ahbong Chang    @Override
281f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    public void drawMesh(BasicTexture tex, int x, int y, int xyBuffer,
282f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            int uvBuffer, int indexBuffer, int indexCount) {
283f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        float alpha = mAlpha;
284f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        if (!bindTexture(tex)) return;
285f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
286f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        mGLState.setBlendEnabled(mBlendEnabled
287f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                && (!tex.isOpaque() || alpha < OPAQUE_ALPHA));
288f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        mGLState.setTextureAlpha(alpha);
289f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
290f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        // Reset the texture matrix. We will set our own texture coordinates
291f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        // below.
292f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        setTextureCoords(0, 0, 1, 1);
293f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
294f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        saveTransform();
295174cac8f92029fc2829c94f274e70793ae948931Chih-Chung Chang        translate(x, y);
296f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
297f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        mGL.glLoadMatrixf(mMatrixValues, 0);
298f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
299f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        mGL.glBindBuffer(GL11.GL_ARRAY_BUFFER, xyBuffer);
300f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        mGL.glVertexPointer(2, GL11.GL_FLOAT, 0, 0);
301f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
302f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        mGL.glBindBuffer(GL11.GL_ARRAY_BUFFER, uvBuffer);
303f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        mGL.glTexCoordPointer(2, GL11.GL_FLOAT, 0, 0);
304f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
305f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        mGL.glBindBuffer(GL11.GL_ELEMENT_ARRAY_BUFFER, indexBuffer);
306f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        mGL.glDrawElements(GL11.GL_TRIANGLE_STRIP,
307f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                indexCount, GL11.GL_UNSIGNED_BYTE, 0);
308f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
309f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        mGL.glBindBuffer(GL11.GL_ARRAY_BUFFER, mBoxCoords);
310f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        mGL.glVertexPointer(2, GL11.GL_FLOAT, 0, 0);
311f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        mGL.glTexCoordPointer(2, GL11.GL_FLOAT, 0, 0);
312f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
313f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        restoreTransform();
314f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        mCountDrawMesh++;
315f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
316f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
317174cac8f92029fc2829c94f274e70793ae948931Chih-Chung Chang    // Transforms two points by the given matrix m. The result
318174cac8f92029fc2829c94f274e70793ae948931Chih-Chung Chang    // {x1', y1', x2', y2'} are stored in mMapPointsBuffer and also returned.
319174cac8f92029fc2829c94f274e70793ae948931Chih-Chung Chang    private float[] mapPoints(float m[], int x1, int y1, int x2, int y2) {
320174cac8f92029fc2829c94f274e70793ae948931Chih-Chung Chang        float[] r = mMapPointsBuffer;
321174cac8f92029fc2829c94f274e70793ae948931Chih-Chung Chang
322174cac8f92029fc2829c94f274e70793ae948931Chih-Chung Chang        // Multiply m and (x1 y1 0 1) to produce (x3 y3 z3 w3). z3 is unused.
323174cac8f92029fc2829c94f274e70793ae948931Chih-Chung Chang        float x3 = m[0] * x1 + m[4] * y1 + m[12];
324174cac8f92029fc2829c94f274e70793ae948931Chih-Chung Chang        float y3 = m[1] * x1 + m[5] * y1 + m[13];
325174cac8f92029fc2829c94f274e70793ae948931Chih-Chung Chang        float w3 = m[3] * x1 + m[7] * y1 + m[15];
326174cac8f92029fc2829c94f274e70793ae948931Chih-Chung Chang        r[0] = x3 / w3;
327174cac8f92029fc2829c94f274e70793ae948931Chih-Chung Chang        r[1] = y3 / w3;
328174cac8f92029fc2829c94f274e70793ae948931Chih-Chung Chang
329174cac8f92029fc2829c94f274e70793ae948931Chih-Chung Chang        // Same for x2 y2.
330174cac8f92029fc2829c94f274e70793ae948931Chih-Chung Chang        float x4 = m[0] * x2 + m[4] * y2 + m[12];
331174cac8f92029fc2829c94f274e70793ae948931Chih-Chung Chang        float y4 = m[1] * x2 + m[5] * y2 + m[13];
332174cac8f92029fc2829c94f274e70793ae948931Chih-Chung Chang        float w4 = m[3] * x2 + m[7] * y2 + m[15];
333174cac8f92029fc2829c94f274e70793ae948931Chih-Chung Chang        r[2] = x4 / w4;
334174cac8f92029fc2829c94f274e70793ae948931Chih-Chung Chang        r[3] = y4 / w4;
335174cac8f92029fc2829c94f274e70793ae948931Chih-Chung Chang
336174cac8f92029fc2829c94f274e70793ae948931Chih-Chung Chang        return r;
337f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
338f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
339f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private void drawBoundTexture(
340f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            BasicTexture texture, int x, int y, int width, int height) {
341f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        // Test whether it has been rotated or flipped, if so, glDrawTexiOES
342f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        // won't work
343f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        if (isMatrixRotatedOrFlipped(mMatrixValues)) {
3441a088db165c138f57d9445ca0b7e50fe90d3ad1dChih-Chung Chang            if (texture.hasBorder()) {
3451a088db165c138f57d9445ca0b7e50fe90d3ad1dChih-Chung Chang                setTextureCoords(
3461a088db165c138f57d9445ca0b7e50fe90d3ad1dChih-Chung Chang                        1.0f / texture.getTextureWidth(),
3471a088db165c138f57d9445ca0b7e50fe90d3ad1dChih-Chung Chang                        1.0f / texture.getTextureHeight(),
3481a088db165c138f57d9445ca0b7e50fe90d3ad1dChih-Chung Chang                        (texture.getWidth() - 1.0f) / texture.getTextureWidth(),
3491a088db165c138f57d9445ca0b7e50fe90d3ad1dChih-Chung Chang                        (texture.getHeight() - 1.0f) / texture.getTextureHeight());
3501a088db165c138f57d9445ca0b7e50fe90d3ad1dChih-Chung Chang            } else {
3511a088db165c138f57d9445ca0b7e50fe90d3ad1dChih-Chung Chang                setTextureCoords(0, 0,
3521a088db165c138f57d9445ca0b7e50fe90d3ad1dChih-Chung Chang                        (float) texture.getWidth() / texture.getTextureWidth(),
3531a088db165c138f57d9445ca0b7e50fe90d3ad1dChih-Chung Chang                        (float) texture.getHeight() / texture.getTextureHeight());
3541a088db165c138f57d9445ca0b7e50fe90d3ad1dChih-Chung Chang            }
355f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            textureRect(x, y, width, height);
356f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        } else {
357f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            // draw the rect from bottom-left to top-right
358f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            float points[] = mapPoints(
359f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                    mMatrixValues, x, y + height, x + width, y);
360cfa105d3934c4dfa14f02b693bfa97c8d17d56a9Chih-Chung Chang            x = (int) (points[0] + 0.5f);
361cfa105d3934c4dfa14f02b693bfa97c8d17d56a9Chih-Chung Chang            y = (int) (points[1] + 0.5f);
362cfa105d3934c4dfa14f02b693bfa97c8d17d56a9Chih-Chung Chang            width = (int) (points[2] + 0.5f) - x;
363cfa105d3934c4dfa14f02b693bfa97c8d17d56a9Chih-Chung Chang            height = (int) (points[3] + 0.5f) - y;
364f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            if (width > 0 && height > 0) {
365f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                ((GL11Ext) mGL).glDrawTexiOES(x, y, 0, width, height);
366f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                mCountTextureOES++;
367f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            }
368f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        }
369f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
370f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
3717817979db0c52ffeacb951625b1e821eba303285Ahbong Chang    @Override
372f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    public void drawTexture(
373f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            BasicTexture texture, int x, int y, int width, int height) {
374f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        drawTexture(texture, x, y, width, height, mAlpha);
375f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
376f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
3777b83fb8e3a8978b33a6b9bfc56d85fe2c1a9cf06Chih-Chung Chang    private void drawTexture(BasicTexture texture,
378f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            int x, int y, int width, int height, float alpha) {
379f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        if (width <= 0 || height <= 0) return;
380f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
381f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        mGLState.setBlendEnabled(mBlendEnabled
382f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                && (!texture.isOpaque() || alpha < OPAQUE_ALPHA));
383f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        if (!bindTexture(texture)) return;
384f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        mGLState.setTextureAlpha(alpha);
385f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        drawBoundTexture(texture, x, y, width, height);
386f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
387f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
3887817979db0c52ffeacb951625b1e821eba303285Ahbong Chang    @Override
389f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    public void drawTexture(BasicTexture texture, RectF source, RectF target) {
390f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        if (target.width() <= 0 || target.height() <= 0) return;
391f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
392f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        // Copy the input to avoid changing it.
393f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        mDrawTextureSourceRect.set(source);
394f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        mDrawTextureTargetRect.set(target);
395f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        source = mDrawTextureSourceRect;
396f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        target = mDrawTextureTargetRect;
397f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
398f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        mGLState.setBlendEnabled(mBlendEnabled
399f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                && (!texture.isOpaque() || mAlpha < OPAQUE_ALPHA));
400f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        if (!bindTexture(texture)) return;
401f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        convertCoordinate(source, target, texture);
402f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        setTextureCoords(source);
403f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        mGLState.setTextureAlpha(mAlpha);
404f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        textureRect(target.left, target.top, target.width(), target.height());
405f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
406f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
4077817979db0c52ffeacb951625b1e821eba303285Ahbong Chang    @Override
408b29a27f475a2c449abdda8d4e03d30914feed8c6Chih-Chung Chang    public void drawTexture(BasicTexture texture, float[] mTextureTransform,
409b29a27f475a2c449abdda8d4e03d30914feed8c6Chih-Chung Chang            int x, int y, int w, int h) {
410b29a27f475a2c449abdda8d4e03d30914feed8c6Chih-Chung Chang        mGLState.setBlendEnabled(mBlendEnabled
411b29a27f475a2c449abdda8d4e03d30914feed8c6Chih-Chung Chang                && (!texture.isOpaque() || mAlpha < OPAQUE_ALPHA));
412b29a27f475a2c449abdda8d4e03d30914feed8c6Chih-Chung Chang        if (!bindTexture(texture)) return;
413b29a27f475a2c449abdda8d4e03d30914feed8c6Chih-Chung Chang        setTextureCoords(mTextureTransform);
414b29a27f475a2c449abdda8d4e03d30914feed8c6Chih-Chung Chang        mGLState.setTextureAlpha(mAlpha);
415b29a27f475a2c449abdda8d4e03d30914feed8c6Chih-Chung Chang        textureRect(x, y, w, h);
416b29a27f475a2c449abdda8d4e03d30914feed8c6Chih-Chung Chang    }
417b29a27f475a2c449abdda8d4e03d30914feed8c6Chih-Chung Chang
418f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    // This function changes the source coordinate to the texture coordinates.
419f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    // It also clips the source and target coordinates if it is beyond the
420f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    // bound of the texture.
421a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin    private static void convertCoordinate(RectF source, RectF target,
422f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            BasicTexture texture) {
423f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
424f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        int width = texture.getWidth();
425f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        int height = texture.getHeight();
426f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        int texWidth = texture.getTextureWidth();
427f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        int texHeight = texture.getTextureHeight();
428f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        // Convert to texture coordinates
429f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        source.left /= texWidth;
430f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        source.right /= texWidth;
431f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        source.top /= texHeight;
432f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        source.bottom /= texHeight;
433f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
434f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        // Clip if the rendering range is beyond the bound of the texture.
435f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        float xBound = (float) width / texWidth;
436f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        if (source.right > xBound) {
437f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            target.right = target.left + target.width() *
438f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                    (xBound - source.left) / source.width();
439f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            source.right = xBound;
440f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        }
441f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        float yBound = (float) height / texHeight;
442f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        if (source.bottom > yBound) {
443f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            target.bottom = target.top + target.height() *
444f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                    (yBound - source.top) / source.height();
445f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            source.bottom = yBound;
446f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        }
447f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
448f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
4497817979db0c52ffeacb951625b1e821eba303285Ahbong Chang    @Override
450f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    public void drawMixed(BasicTexture from,
451f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            int toColor, float ratio, int x, int y, int w, int h) {
452f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        drawMixed(from, toColor, ratio, x, y, w, h, mAlpha);
453f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
454f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
455f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private boolean bindTexture(BasicTexture texture) {
456f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        if (!texture.onBind(this)) return false;
457b29a27f475a2c449abdda8d4e03d30914feed8c6Chih-Chung Chang        int target = texture.getTarget();
458b29a27f475a2c449abdda8d4e03d30914feed8c6Chih-Chung Chang        mGLState.setTextureTarget(target);
459b29a27f475a2c449abdda8d4e03d30914feed8c6Chih-Chung Chang        mGL.glBindTexture(target, texture.getId());
460f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        return true;
461f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
462f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
463f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private void setTextureColor(float r, float g, float b, float alpha) {
464f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        float[] color = mTextureColor;
465f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        color[0] = r;
466f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        color[1] = g;
467f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        color[2] = b;
468f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        color[3] = alpha;
469f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
470f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
471a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin    private void setMixedColor(int toColor, float ratio, float alpha) {
472f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        //
473f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        // The formula we want:
474f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        //     alpha * ((1 - ratio) * from + ratio * to)
475fc7efade75629450c0c160329fb42b3dbd5361f4Owen Lin        //
476f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        // The formula that GL supports is in the form of:
477fc7efade75629450c0c160329fb42b3dbd5361f4Owen Lin        //     combo * from + (1 - combo) * to * scale
478f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        //
479fc7efade75629450c0c160329fb42b3dbd5361f4Owen Lin        // So, we have combo = alpha * (1 - ratio)
480fc7efade75629450c0c160329fb42b3dbd5361f4Owen Lin        //     and     scale = alpha * ratio / (1 - combo)
481f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        //
482fc7efade75629450c0c160329fb42b3dbd5361f4Owen Lin        float combo = alpha * (1 - ratio);
483fc7efade75629450c0c160329fb42b3dbd5361f4Owen Lin        float scale = alpha * ratio / (1 - combo);
484f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
485f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        // Specify the interpolation factor via the alpha component of
486f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        // GL_TEXTURE_ENV_COLORs.
487f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        // RGB component are get from toColor and will used as SRC1
488fc7efade75629450c0c160329fb42b3dbd5361f4Owen Lin        float colorScale = scale * (toColor >>> 24) / (0xff * 0xff);
489fc7efade75629450c0c160329fb42b3dbd5361f4Owen Lin        setTextureColor(((toColor >>> 16) & 0xff) * colorScale,
490fc7efade75629450c0c160329fb42b3dbd5361f4Owen Lin                ((toColor >>> 8) & 0xff) * colorScale,
491fc7efade75629450c0c160329fb42b3dbd5361f4Owen Lin                (toColor & 0xff) * colorScale, combo);
492a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin        GL11 gl = mGL;
493f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        gl.glTexEnvfv(GL11.GL_TEXTURE_ENV, GL11.GL_TEXTURE_ENV_COLOR, mTextureColor, 0);
494f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
495f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        gl.glTexEnvf(GL11.GL_TEXTURE_ENV, GL11.GL_COMBINE_RGB, GL11.GL_INTERPOLATE);
496f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        gl.glTexEnvf(GL11.GL_TEXTURE_ENV, GL11.GL_COMBINE_ALPHA, GL11.GL_INTERPOLATE);
497f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        gl.glTexEnvf(GL11.GL_TEXTURE_ENV, GL11.GL_SRC1_RGB, GL11.GL_CONSTANT);
498f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        gl.glTexEnvf(GL11.GL_TEXTURE_ENV, GL11.GL_OPERAND1_RGB, GL11.GL_SRC_COLOR);
499f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        gl.glTexEnvf(GL11.GL_TEXTURE_ENV, GL11.GL_SRC1_ALPHA, GL11.GL_CONSTANT);
500f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        gl.glTexEnvf(GL11.GL_TEXTURE_ENV, GL11.GL_OPERAND1_ALPHA, GL11.GL_SRC_ALPHA);
501f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
502f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        // Wire up the interpolation factor for RGB.
503f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        gl.glTexEnvf(GL11.GL_TEXTURE_ENV, GL11.GL_SRC2_RGB, GL11.GL_CONSTANT);
504f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        gl.glTexEnvf(GL11.GL_TEXTURE_ENV, GL11.GL_OPERAND2_RGB, GL11.GL_SRC_ALPHA);
505f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
506f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        // Wire up the interpolation factor for alpha.
507f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        gl.glTexEnvf(GL11.GL_TEXTURE_ENV, GL11.GL_SRC2_ALPHA, GL11.GL_CONSTANT);
508f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        gl.glTexEnvf(GL11.GL_TEXTURE_ENV, GL11.GL_OPERAND2_ALPHA, GL11.GL_SRC_ALPHA);
509f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
510a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin    }
511a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin
512a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin    @Override
513a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin    public void drawMixed(BasicTexture from, int toColor, float ratio,
514a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin            RectF source, RectF target) {
515a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin        if (target.width() <= 0 || target.height() <= 0) return;
516a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin
517a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin        if (ratio <= 0.01f) {
518a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin            drawTexture(from, source, target);
519a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin            return;
520a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin        } else if (ratio >= 1) {
521a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin            fillRect(target.left, target.top, target.width(), target.height(), toColor);
522a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin            return;
523a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin        }
524a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin
525a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin        float alpha = mAlpha;
526a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin
527a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin        // Copy the input to avoid changing it.
528a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin        mDrawTextureSourceRect.set(source);
529a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin        mDrawTextureTargetRect.set(target);
530a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin        source = mDrawTextureSourceRect;
531a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin        target = mDrawTextureTargetRect;
532a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin
533a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin        mGLState.setBlendEnabled(mBlendEnabled && (!from.isOpaque()
534a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin                || !Utils.isOpaque(toColor) || alpha < OPAQUE_ALPHA));
535a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin
536a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin        if (!bindTexture(from)) return;
537a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin
538a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin        // Interpolate the RGB and alpha values between both textures.
539a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin        mGLState.setTexEnvMode(GL11.GL_COMBINE);
540a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin        setMixedColor(toColor, ratio, alpha);
541a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin        convertCoordinate(source, target, from);
542a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin        setTextureCoords(source);
543a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin        textureRect(target.left, target.top, target.width(), target.height());
544a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin        mGLState.setTexEnvMode(GL11.GL_REPLACE);
545a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin    }
546a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin
547a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin    private void drawMixed(BasicTexture from, int toColor,
548a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin            float ratio, int x, int y, int width, int height, float alpha) {
549a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin        // change from 0 to 0.01f to prevent getting divided by zero below
550a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin        if (ratio <= 0.01f) {
551a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin            drawTexture(from, x, y, width, height, alpha);
552a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin            return;
553a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin        } else if (ratio >= 1) {
554a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin            fillRect(x, y, width, height, toColor);
555a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin            return;
556a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin        }
557a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin
558a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin        mGLState.setBlendEnabled(mBlendEnabled && (!from.isOpaque()
559a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin                || !Utils.isOpaque(toColor) || alpha < OPAQUE_ALPHA));
560a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin
561a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin        final GL11 gl = mGL;
562a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin        if (!bindTexture(from)) return;
563a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin
564a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin        // Interpolate the RGB and alpha values between both textures.
565a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin        mGLState.setTexEnvMode(GL11.GL_COMBINE);
566a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin        setMixedColor(toColor, ratio, alpha);
567a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin
568f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        drawBoundTexture(from, x, y, width, height);
569f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        mGLState.setTexEnvMode(GL11.GL_REPLACE);
570f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
571f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
572f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    // TODO: the code only work for 2D should get fixed for 3D or removed
573f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private static final int MSKEW_X = 4;
574f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private static final int MSKEW_Y = 1;
575f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private static final int MSCALE_X = 0;
576f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private static final int MSCALE_Y = 5;
577f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
578f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private static boolean isMatrixRotatedOrFlipped(float matrix[]) {
579f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        final float eps = 1e-5f;
580f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        return Math.abs(matrix[MSKEW_X]) > eps
581f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                || Math.abs(matrix[MSKEW_Y]) > eps
582f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                || matrix[MSCALE_X] < -eps
583f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                || matrix[MSCALE_Y] > eps;
584f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
585f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
586f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private static class GLState {
587f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
588f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        private final GL11 mGL;
589f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
590f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        private int mTexEnvMode = GL11.GL_REPLACE;
591f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        private float mTextureAlpha = 1.0f;
5921cbde8f63a4862e814078da9b7cefce0c6291dabOwen Lin        private int mTextureTarget = GL11.GL_TEXTURE_2D;
593f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        private boolean mBlendEnabled = true;
594f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        private float mLineWidth = 1.0f;
595f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        private boolean mLineSmooth = false;
596f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
597f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        public GLState(GL11 gl) {
598f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            mGL = gl;
599f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
600f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            // Disable unused state
601f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            gl.glDisable(GL11.GL_LIGHTING);
602f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
603f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            // Enable used features
604f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            gl.glEnable(GL11.GL_DITHER);
605f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
606f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
607f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
608f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            gl.glEnable(GL11.GL_TEXTURE_2D);
609f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
610f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            gl.glTexEnvf(GL11.GL_TEXTURE_ENV,
611f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                    GL11.GL_TEXTURE_ENV_MODE, GL11.GL_REPLACE);
612f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
613f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            // Set the background color
614f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            gl.glClearColor(0f, 0f, 0f, 0f);
615f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
616f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            gl.glEnable(GL11.GL_BLEND);
617f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            gl.glBlendFunc(GL11.GL_ONE, GL11.GL_ONE_MINUS_SRC_ALPHA);
618f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
619f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            // We use 565 or 8888 format, so set the alignment to 2 bytes/pixel.
620f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            gl.glPixelStorei(GL11.GL_UNPACK_ALIGNMENT, 2);
621f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        }
622f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
623f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        public void setTexEnvMode(int mode) {
624f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            if (mTexEnvMode == mode) return;
625f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            mTexEnvMode = mode;
626f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            mGL.glTexEnvf(GL11.GL_TEXTURE_ENV, GL11.GL_TEXTURE_ENV_MODE, mode);
627f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        }
628f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
629f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        public void setLineWidth(float width) {
630f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            if (mLineWidth == width) return;
631f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            mLineWidth = width;
632f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            mGL.glLineWidth(width);
633f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        }
634f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
635f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        public void setTextureAlpha(float alpha) {
636f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            if (mTextureAlpha == alpha) return;
637f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            mTextureAlpha = alpha;
638f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            if (alpha >= OPAQUE_ALPHA) {
639f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                // The alpha is need for those texture without alpha channel
640f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                mGL.glColor4f(1, 1, 1, 1);
641f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                setTexEnvMode(GL11.GL_REPLACE);
642f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            } else {
643f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                mGL.glColor4f(alpha, alpha, alpha, alpha);
644f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                setTexEnvMode(GL11.GL_MODULATE);
645f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            }
646f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        }
647f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
648f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        public void setColorMode(int color, float alpha) {
649f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            setBlendEnabled(!Utils.isOpaque(color) || alpha < OPAQUE_ALPHA);
650f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
651f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            // Set mTextureAlpha to an invalid value, so that it will reset
652f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            // again in setTextureAlpha(float) later.
653f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            mTextureAlpha = -1.0f;
654f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
655b29a27f475a2c449abdda8d4e03d30914feed8c6Chih-Chung Chang            setTextureTarget(0);
656f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
657f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            float prealpha = (color >>> 24) * alpha * 65535f / 255f / 255f;
658f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            mGL.glColor4x(
659f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                    Math.round(((color >> 16) & 0xFF) * prealpha),
660f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                    Math.round(((color >> 8) & 0xFF) * prealpha),
661f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                    Math.round((color & 0xFF) * prealpha),
662f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                    Math.round(255 * prealpha));
663f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        }
664f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
665b29a27f475a2c449abdda8d4e03d30914feed8c6Chih-Chung Chang        // target is a value like GL_TEXTURE_2D. If target = 0, texturing is disabled.
666b29a27f475a2c449abdda8d4e03d30914feed8c6Chih-Chung Chang        public void setTextureTarget(int target) {
667b29a27f475a2c449abdda8d4e03d30914feed8c6Chih-Chung Chang            if (mTextureTarget == target) return;
668b29a27f475a2c449abdda8d4e03d30914feed8c6Chih-Chung Chang            if (mTextureTarget != 0) {
669b29a27f475a2c449abdda8d4e03d30914feed8c6Chih-Chung Chang                mGL.glDisable(mTextureTarget);
670b29a27f475a2c449abdda8d4e03d30914feed8c6Chih-Chung Chang            }
671b29a27f475a2c449abdda8d4e03d30914feed8c6Chih-Chung Chang            mTextureTarget = target;
672b29a27f475a2c449abdda8d4e03d30914feed8c6Chih-Chung Chang            if (mTextureTarget != 0) {
673b29a27f475a2c449abdda8d4e03d30914feed8c6Chih-Chung Chang                mGL.glEnable(mTextureTarget);
674f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            }
675f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        }
676f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
677f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        public void setBlendEnabled(boolean enabled) {
678f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            if (mBlendEnabled == enabled) return;
679f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            mBlendEnabled = enabled;
680f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            if (enabled) {
681f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                mGL.glEnable(GL11.GL_BLEND);
682f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            } else {
683f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                mGL.glDisable(GL11.GL_BLEND);
684f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            }
685f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        }
686f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
687f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
6887817979db0c52ffeacb951625b1e821eba303285Ahbong Chang    @Override
689915c2c5b2c367df71599370613af0924bd7c4887Bobby Georgescu    public void clearBuffer(float[] argb) {
690915c2c5b2c367df71599370613af0924bd7c4887Bobby Georgescu        if(argb != null && argb.length == 4) {
691915c2c5b2c367df71599370613af0924bd7c4887Bobby Georgescu            mGL.glClearColor(argb[1], argb[2], argb[3], argb[0]);
692915c2c5b2c367df71599370613af0924bd7c4887Bobby Georgescu        } else {
693915c2c5b2c367df71599370613af0924bd7c4887Bobby Georgescu            mGL.glClearColor(0, 0, 0, 1);
694915c2c5b2c367df71599370613af0924bd7c4887Bobby Georgescu        }
695f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        mGL.glClear(GL10.GL_COLOR_BUFFER_BIT);
696f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
697f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
698c90a116a7fd65d41e8258dc7b9a14218649697e6Bobby Georgescu    @Override
699c90a116a7fd65d41e8258dc7b9a14218649697e6Bobby Georgescu    public void clearBuffer() {
700915c2c5b2c367df71599370613af0924bd7c4887Bobby Georgescu        clearBuffer(null);
701c90a116a7fd65d41e8258dc7b9a14218649697e6Bobby Georgescu    }
702c90a116a7fd65d41e8258dc7b9a14218649697e6Bobby Georgescu
703f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private void setTextureCoords(RectF source) {
704f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        setTextureCoords(source.left, source.top, source.right, source.bottom);
705f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
706f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
707f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private void setTextureCoords(float left, float top,
708f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            float right, float bottom) {
709f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        mGL.glMatrixMode(GL11.GL_TEXTURE);
710f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        mTextureMatrixValues[0] = right - left;
711f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        mTextureMatrixValues[5] = bottom - top;
712f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        mTextureMatrixValues[10] = 1;
713f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        mTextureMatrixValues[12] = left;
714f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        mTextureMatrixValues[13] = top;
715f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        mTextureMatrixValues[15] = 1;
716f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        mGL.glLoadMatrixf(mTextureMatrixValues, 0);
717f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        mGL.glMatrixMode(GL11.GL_MODELVIEW);
718f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
719f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
720b29a27f475a2c449abdda8d4e03d30914feed8c6Chih-Chung Chang    private void setTextureCoords(float[] mTextureTransform) {
721b29a27f475a2c449abdda8d4e03d30914feed8c6Chih-Chung Chang        mGL.glMatrixMode(GL11.GL_TEXTURE);
722b29a27f475a2c449abdda8d4e03d30914feed8c6Chih-Chung Chang        mGL.glLoadMatrixf(mTextureTransform, 0);
723b29a27f475a2c449abdda8d4e03d30914feed8c6Chih-Chung Chang        mGL.glMatrixMode(GL11.GL_MODELVIEW);
724b29a27f475a2c449abdda8d4e03d30914feed8c6Chih-Chung Chang    }
725b29a27f475a2c449abdda8d4e03d30914feed8c6Chih-Chung Chang
726f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    // unloadTexture and deleteBuffer can be called from the finalizer thread,
727f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    // so we synchronized on the mUnboundTextures object.
7287817979db0c52ffeacb951625b1e821eba303285Ahbong Chang    @Override
729f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    public boolean unloadTexture(BasicTexture t) {
730f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        synchronized (mUnboundTextures) {
73137c605949219b8bf54c165c34d6405f5f2989f50Owen Lin            if (!t.isLoaded()) return false;
732f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            mUnboundTextures.add(t.mId);
733f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            return true;
734f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        }
735f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
736f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
7377817979db0c52ffeacb951625b1e821eba303285Ahbong Chang    @Override
738f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    public void deleteBuffer(int bufferId) {
739f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        synchronized (mUnboundTextures) {
740f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            mDeleteBuffers.add(bufferId);
741f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        }
742f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
743f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
7447817979db0c52ffeacb951625b1e821eba303285Ahbong Chang    @Override
745f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    public void deleteRecycledResources() {
746f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        synchronized (mUnboundTextures) {
747f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            IntArray ids = mUnboundTextures;
748f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            if (ids.size() > 0) {
74950b33abe053ccab7be3d1bca2328e792507963d4George Mount                mGLId.glDeleteTextures(mGL, ids.size(), ids.getInternalArray(), 0);
750f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                ids.clear();
751f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            }
752f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
753f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            ids = mDeleteBuffers;
754f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            if (ids.size() > 0) {
75550b33abe053ccab7be3d1bca2328e792507963d4George Mount                mGLId.glDeleteBuffers(mGL, ids.size(), ids.getInternalArray(), 0);
756f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                ids.clear();
757f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            }
758f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        }
759f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
760f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
7617817979db0c52ffeacb951625b1e821eba303285Ahbong Chang    @Override
762cfa105d3934c4dfa14f02b693bfa97c8d17d56a9Chih-Chung Chang    public void save() {
763cfa105d3934c4dfa14f02b693bfa97c8d17d56a9Chih-Chung Chang        save(SAVE_FLAG_ALL);
764f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
765f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
7667817979db0c52ffeacb951625b1e821eba303285Ahbong Chang    @Override
767cfa105d3934c4dfa14f02b693bfa97c8d17d56a9Chih-Chung Chang    public void save(int saveFlags) {
768f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        ConfigState config = obtainRestoreConfig();
769f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
770f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        if ((saveFlags & SAVE_FLAG_ALPHA) != 0) {
771f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            config.mAlpha = mAlpha;
772f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        } else {
773f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            config.mAlpha = -1;
774f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        }
775f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
776f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        if ((saveFlags & SAVE_FLAG_MATRIX) != 0) {
777f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            System.arraycopy(mMatrixValues, 0, config.mMatrix, 0, 16);
778f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        } else {
779f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            config.mMatrix[0] = Float.NEGATIVE_INFINITY;
780f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        }
781f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
782cfa105d3934c4dfa14f02b693bfa97c8d17d56a9Chih-Chung Chang        mRestoreStack.add(config);
783f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
784f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
7857817979db0c52ffeacb951625b1e821eba303285Ahbong Chang    @Override
786f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    public void restore() {
787f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        if (mRestoreStack.isEmpty()) throw new IllegalStateException();
788cfa105d3934c4dfa14f02b693bfa97c8d17d56a9Chih-Chung Chang        ConfigState config = mRestoreStack.remove(mRestoreStack.size() - 1);
789f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        config.restore(this);
790f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        freeRestoreConfig(config);
791f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
792f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
793f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private void freeRestoreConfig(ConfigState action) {
794f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        action.mNextFree = mRecycledRestoreAction;
795f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        mRecycledRestoreAction = action;
796f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
797f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
798f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private ConfigState obtainRestoreConfig() {
799f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        if (mRecycledRestoreAction != null) {
800f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            ConfigState result = mRecycledRestoreAction;
801f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            mRecycledRestoreAction = result.mNextFree;
802f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            return result;
803f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        }
804f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        return new ConfigState();
805f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
806f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
807f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private static class ConfigState {
808f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        float mAlpha;
809f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        float mMatrix[] = new float[16];
810f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        ConfigState mNextFree;
811f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
812a4eae1abb4f2547dfbda84301ee764ce35464881John Reck        public void restore(GLES11Canvas canvas) {
813f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            if (mAlpha >= 0) canvas.setAlpha(mAlpha);
814f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            if (mMatrix[0] != Float.NEGATIVE_INFINITY) {
815f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                System.arraycopy(mMatrix, 0, canvas.mMatrixValues, 0, 16);
816f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            }
817f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        }
818f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
819f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
8207817979db0c52ffeacb951625b1e821eba303285Ahbong Chang    @Override
821f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    public void dumpStatisticsAndClear() {
822f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        String line = String.format(
823f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                "MESH:%d, TEX_OES:%d, TEX_RECT:%d, FILL_RECT:%d, LINE:%d",
824f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                mCountDrawMesh, mCountTextureRect, mCountTextureOES,
825f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                mCountFillRect, mCountDrawLine);
826f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        mCountDrawMesh = 0;
827f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        mCountTextureRect = 0;
828f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        mCountTextureOES = 0;
829f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        mCountFillRect = 0;
830f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        mCountDrawLine = 0;
831f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        Log.d(TAG, line);
832f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
833f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
834f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private void saveTransform() {
835f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        System.arraycopy(mMatrixValues, 0, mTempMatrix, 0, 16);
836f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
837f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
838f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private void restoreTransform() {
839f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        System.arraycopy(mTempMatrix, 0, mMatrixValues, 0, 16);
840f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
8418ac2e8630f33f4d5f65731dc56efa9bfb3570cd7Owen Lin
8428ac2e8630f33f4d5f65731dc56efa9bfb3570cd7Owen Lin    private void setRenderTarget(RawTexture texture) {
8438ac2e8630f33f4d5f65731dc56efa9bfb3570cd7Owen Lin        GL11ExtensionPack gl11ep = (GL11ExtensionPack) mGL;
8448ac2e8630f33f4d5f65731dc56efa9bfb3570cd7Owen Lin
8458ac2e8630f33f4d5f65731dc56efa9bfb3570cd7Owen Lin        if (mTargetTexture == null && texture != null) {
84650b33abe053ccab7be3d1bca2328e792507963d4George Mount            mGLId.glGenBuffers(1, mFrameBuffer, 0);
8478ac2e8630f33f4d5f65731dc56efa9bfb3570cd7Owen Lin            gl11ep.glBindFramebufferOES(
8488ac2e8630f33f4d5f65731dc56efa9bfb3570cd7Owen Lin                    GL11ExtensionPack.GL_FRAMEBUFFER_OES, mFrameBuffer[0]);
8498ac2e8630f33f4d5f65731dc56efa9bfb3570cd7Owen Lin        }
8508ac2e8630f33f4d5f65731dc56efa9bfb3570cd7Owen Lin        if (mTargetTexture != null && texture  == null) {
8518ac2e8630f33f4d5f65731dc56efa9bfb3570cd7Owen Lin            gl11ep.glBindFramebufferOES(GL11ExtensionPack.GL_FRAMEBUFFER_OES, 0);
8528ac2e8630f33f4d5f65731dc56efa9bfb3570cd7Owen Lin            gl11ep.glDeleteFramebuffersOES(1, mFrameBuffer, 0);
8538ac2e8630f33f4d5f65731dc56efa9bfb3570cd7Owen Lin        }
8548ac2e8630f33f4d5f65731dc56efa9bfb3570cd7Owen Lin
8558ac2e8630f33f4d5f65731dc56efa9bfb3570cd7Owen Lin        mTargetTexture = texture;
8568ac2e8630f33f4d5f65731dc56efa9bfb3570cd7Owen Lin        if (texture == null) {
8578ac2e8630f33f4d5f65731dc56efa9bfb3570cd7Owen Lin            setSize(mScreenWidth, mScreenHeight);
8588ac2e8630f33f4d5f65731dc56efa9bfb3570cd7Owen Lin        } else {
8598ac2e8630f33f4d5f65731dc56efa9bfb3570cd7Owen Lin            setSize(texture.getWidth(), texture.getHeight());
8608ac2e8630f33f4d5f65731dc56efa9bfb3570cd7Owen Lin
86137c605949219b8bf54c165c34d6405f5f2989f50Owen Lin            if (!texture.isLoaded()) texture.prepare(this);
8628ac2e8630f33f4d5f65731dc56efa9bfb3570cd7Owen Lin
8638ac2e8630f33f4d5f65731dc56efa9bfb3570cd7Owen Lin            gl11ep.glFramebufferTexture2DOES(
8648ac2e8630f33f4d5f65731dc56efa9bfb3570cd7Owen Lin                    GL11ExtensionPack.GL_FRAMEBUFFER_OES,
8658ac2e8630f33f4d5f65731dc56efa9bfb3570cd7Owen Lin                    GL11ExtensionPack.GL_COLOR_ATTACHMENT0_OES,
8668ac2e8630f33f4d5f65731dc56efa9bfb3570cd7Owen Lin                    GL11.GL_TEXTURE_2D, texture.getId(), 0);
8678ac2e8630f33f4d5f65731dc56efa9bfb3570cd7Owen Lin
8688ac2e8630f33f4d5f65731dc56efa9bfb3570cd7Owen Lin            checkFramebufferStatus(gl11ep);
8698ac2e8630f33f4d5f65731dc56efa9bfb3570cd7Owen Lin        }
8708ac2e8630f33f4d5f65731dc56efa9bfb3570cd7Owen Lin    }
8718ac2e8630f33f4d5f65731dc56efa9bfb3570cd7Owen Lin
8728ac2e8630f33f4d5f65731dc56efa9bfb3570cd7Owen Lin    @Override
8738ac2e8630f33f4d5f65731dc56efa9bfb3570cd7Owen Lin    public void endRenderTarget() {
8748ac2e8630f33f4d5f65731dc56efa9bfb3570cd7Owen Lin        RawTexture texture = mTargetStack.remove(mTargetStack.size() - 1);
8758ac2e8630f33f4d5f65731dc56efa9bfb3570cd7Owen Lin        setRenderTarget(texture);
8768ac2e8630f33f4d5f65731dc56efa9bfb3570cd7Owen Lin        restore(); // restore matrix and alpha
8778ac2e8630f33f4d5f65731dc56efa9bfb3570cd7Owen Lin    }
8788ac2e8630f33f4d5f65731dc56efa9bfb3570cd7Owen Lin
8798ac2e8630f33f4d5f65731dc56efa9bfb3570cd7Owen Lin    @Override
8808ac2e8630f33f4d5f65731dc56efa9bfb3570cd7Owen Lin    public void beginRenderTarget(RawTexture texture) {
8818ac2e8630f33f4d5f65731dc56efa9bfb3570cd7Owen Lin        save(); // save matrix and alpha
8828ac2e8630f33f4d5f65731dc56efa9bfb3570cd7Owen Lin        mTargetStack.add(mTargetTexture);
8838ac2e8630f33f4d5f65731dc56efa9bfb3570cd7Owen Lin        setRenderTarget(texture);
8848ac2e8630f33f4d5f65731dc56efa9bfb3570cd7Owen Lin    }
8858ac2e8630f33f4d5f65731dc56efa9bfb3570cd7Owen Lin
8868ac2e8630f33f4d5f65731dc56efa9bfb3570cd7Owen Lin    private static void checkFramebufferStatus(GL11ExtensionPack gl11ep) {
8878ac2e8630f33f4d5f65731dc56efa9bfb3570cd7Owen Lin        int status = gl11ep.glCheckFramebufferStatusOES(GL11ExtensionPack.GL_FRAMEBUFFER_OES);
8888ac2e8630f33f4d5f65731dc56efa9bfb3570cd7Owen Lin        if (status != GL11ExtensionPack.GL_FRAMEBUFFER_COMPLETE_OES) {
8898ac2e8630f33f4d5f65731dc56efa9bfb3570cd7Owen Lin            String msg = "";
8908ac2e8630f33f4d5f65731dc56efa9bfb3570cd7Owen Lin            switch (status) {
8918ac2e8630f33f4d5f65731dc56efa9bfb3570cd7Owen Lin                case GL11ExtensionPack.GL_FRAMEBUFFER_INCOMPLETE_FORMATS_OES:
8928ac2e8630f33f4d5f65731dc56efa9bfb3570cd7Owen Lin                    msg = "FRAMEBUFFER_FORMATS";
8938ac2e8630f33f4d5f65731dc56efa9bfb3570cd7Owen Lin                    break;
8948ac2e8630f33f4d5f65731dc56efa9bfb3570cd7Owen Lin                case GL11ExtensionPack.GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_OES:
8958ac2e8630f33f4d5f65731dc56efa9bfb3570cd7Owen Lin                    msg = "FRAMEBUFFER_ATTACHMENT";
8968ac2e8630f33f4d5f65731dc56efa9bfb3570cd7Owen Lin                    break;
8978ac2e8630f33f4d5f65731dc56efa9bfb3570cd7Owen Lin                case GL11ExtensionPack.GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_OES:
8988ac2e8630f33f4d5f65731dc56efa9bfb3570cd7Owen Lin                    msg = "FRAMEBUFFER_MISSING_ATTACHMENT";
8998ac2e8630f33f4d5f65731dc56efa9bfb3570cd7Owen Lin                    break;
9008ac2e8630f33f4d5f65731dc56efa9bfb3570cd7Owen Lin                case GL11ExtensionPack.GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_OES:
9018ac2e8630f33f4d5f65731dc56efa9bfb3570cd7Owen Lin                    msg = "FRAMEBUFFER_DRAW_BUFFER";
9028ac2e8630f33f4d5f65731dc56efa9bfb3570cd7Owen Lin                    break;
9038ac2e8630f33f4d5f65731dc56efa9bfb3570cd7Owen Lin                case GL11ExtensionPack.GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_OES:
9048ac2e8630f33f4d5f65731dc56efa9bfb3570cd7Owen Lin                    msg = "FRAMEBUFFER_READ_BUFFER";
9058ac2e8630f33f4d5f65731dc56efa9bfb3570cd7Owen Lin                    break;
9068ac2e8630f33f4d5f65731dc56efa9bfb3570cd7Owen Lin                case GL11ExtensionPack.GL_FRAMEBUFFER_UNSUPPORTED_OES:
9078ac2e8630f33f4d5f65731dc56efa9bfb3570cd7Owen Lin                    msg = "FRAMEBUFFER_UNSUPPORTED";
9088ac2e8630f33f4d5f65731dc56efa9bfb3570cd7Owen Lin                    break;
9098ac2e8630f33f4d5f65731dc56efa9bfb3570cd7Owen Lin                case GL11ExtensionPack.GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_OES:
9108ac2e8630f33f4d5f65731dc56efa9bfb3570cd7Owen Lin                    msg = "FRAMEBUFFER_INCOMPLETE_DIMENSIONS";
9118ac2e8630f33f4d5f65731dc56efa9bfb3570cd7Owen Lin                    break;
9128ac2e8630f33f4d5f65731dc56efa9bfb3570cd7Owen Lin            }
9138ac2e8630f33f4d5f65731dc56efa9bfb3570cd7Owen Lin            throw new RuntimeException(msg + ":" + Integer.toHexString(status));
9148ac2e8630f33f4d5f65731dc56efa9bfb3570cd7Owen Lin        }
9158ac2e8630f33f4d5f65731dc56efa9bfb3570cd7Owen Lin    }
9167da54d7e41e04ea5122009b40de19be0724e1ca4George Mount
9177da54d7e41e04ea5122009b40de19be0724e1ca4George Mount    @Override
9187da54d7e41e04ea5122009b40de19be0724e1ca4George Mount    public void setTextureParameters(BasicTexture texture) {
9197da54d7e41e04ea5122009b40de19be0724e1ca4George Mount        int width = texture.getWidth();
9207da54d7e41e04ea5122009b40de19be0724e1ca4George Mount        int height = texture.getHeight();
9217da54d7e41e04ea5122009b40de19be0724e1ca4George Mount        // Define a vertically flipped crop rectangle for OES_draw_texture.
9227da54d7e41e04ea5122009b40de19be0724e1ca4George Mount        // The four values in sCropRect are: left, bottom, width, and
9237da54d7e41e04ea5122009b40de19be0724e1ca4George Mount        // height. Negative value of width or height means flip.
9247da54d7e41e04ea5122009b40de19be0724e1ca4George Mount        sCropRect[0] = 0;
9257da54d7e41e04ea5122009b40de19be0724e1ca4George Mount        sCropRect[1] = height;
9267da54d7e41e04ea5122009b40de19be0724e1ca4George Mount        sCropRect[2] = width;
9277da54d7e41e04ea5122009b40de19be0724e1ca4George Mount        sCropRect[3] = -height;
9287da54d7e41e04ea5122009b40de19be0724e1ca4George Mount
9297da54d7e41e04ea5122009b40de19be0724e1ca4George Mount        // Set texture parameters.
9307da54d7e41e04ea5122009b40de19be0724e1ca4George Mount        int target = texture.getTarget();
9317da54d7e41e04ea5122009b40de19be0724e1ca4George Mount        mGL.glBindTexture(target, texture.getId());
9327da54d7e41e04ea5122009b40de19be0724e1ca4George Mount        mGL.glTexParameterfv(target, GL11Ext.GL_TEXTURE_CROP_RECT_OES, sCropRect, 0);
9337da54d7e41e04ea5122009b40de19be0724e1ca4George Mount        mGL.glTexParameteri(target, GL11.GL_TEXTURE_WRAP_S, GL11.GL_CLAMP_TO_EDGE);
9347da54d7e41e04ea5122009b40de19be0724e1ca4George Mount        mGL.glTexParameteri(target, GL11.GL_TEXTURE_WRAP_T, GL11.GL_CLAMP_TO_EDGE);
9357da54d7e41e04ea5122009b40de19be0724e1ca4George Mount        mGL.glTexParameterf(target, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_LINEAR);
9367da54d7e41e04ea5122009b40de19be0724e1ca4George Mount        mGL.glTexParameterf(target, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_LINEAR);
9377da54d7e41e04ea5122009b40de19be0724e1ca4George Mount    }
9387da54d7e41e04ea5122009b40de19be0724e1ca4George Mount
9397da54d7e41e04ea5122009b40de19be0724e1ca4George Mount    @Override
9407da54d7e41e04ea5122009b40de19be0724e1ca4George Mount    public void initializeTextureSize(BasicTexture texture, int format, int type) {
9417da54d7e41e04ea5122009b40de19be0724e1ca4George Mount        int target = texture.getTarget();
9427da54d7e41e04ea5122009b40de19be0724e1ca4George Mount        mGL.glBindTexture(target, texture.getId());
9437da54d7e41e04ea5122009b40de19be0724e1ca4George Mount        int width = texture.getTextureWidth();
9447da54d7e41e04ea5122009b40de19be0724e1ca4George Mount        int height = texture.getTextureHeight();
9457da54d7e41e04ea5122009b40de19be0724e1ca4George Mount        mGL.glTexImage2D(target, 0, format, width, height, 0, format, type, null);
9467da54d7e41e04ea5122009b40de19be0724e1ca4George Mount    }
9477da54d7e41e04ea5122009b40de19be0724e1ca4George Mount
9487da54d7e41e04ea5122009b40de19be0724e1ca4George Mount    @Override
9497da54d7e41e04ea5122009b40de19be0724e1ca4George Mount    public void initializeTexture(BasicTexture texture, Bitmap bitmap) {
9507da54d7e41e04ea5122009b40de19be0724e1ca4George Mount        int target = texture.getTarget();
9517da54d7e41e04ea5122009b40de19be0724e1ca4George Mount        mGL.glBindTexture(target, texture.getId());
9527da54d7e41e04ea5122009b40de19be0724e1ca4George Mount        GLUtils.texImage2D(target, 0, bitmap, 0);
9537da54d7e41e04ea5122009b40de19be0724e1ca4George Mount    }
9547da54d7e41e04ea5122009b40de19be0724e1ca4George Mount
9557da54d7e41e04ea5122009b40de19be0724e1ca4George Mount    @Override
9567da54d7e41e04ea5122009b40de19be0724e1ca4George Mount    public void texSubImage2D(BasicTexture texture, int xOffset, int yOffset, Bitmap bitmap,
9577da54d7e41e04ea5122009b40de19be0724e1ca4George Mount            int format, int type) {
9587da54d7e41e04ea5122009b40de19be0724e1ca4George Mount        int target = texture.getTarget();
9597da54d7e41e04ea5122009b40de19be0724e1ca4George Mount        mGL.glBindTexture(target, texture.getId());
9607da54d7e41e04ea5122009b40de19be0724e1ca4George Mount        GLUtils.texSubImage2D(target, 0, xOffset, yOffset, bitmap, format, type);
9617da54d7e41e04ea5122009b40de19be0724e1ca4George Mount    }
9627da54d7e41e04ea5122009b40de19be0724e1ca4George Mount
9637da54d7e41e04ea5122009b40de19be0724e1ca4George Mount    @Override
9646eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    public int uploadBuffer(FloatBuffer buf) {
9656eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        return uploadBuffer(buf, Float.SIZE / Byte.SIZE);
9666eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    }
9677da54d7e41e04ea5122009b40de19be0724e1ca4George Mount
9686eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    @Override
9696eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    public int uploadBuffer(ByteBuffer buf) {
9706eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        return uploadBuffer(buf, 1);
9716eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    }
9727da54d7e41e04ea5122009b40de19be0724e1ca4George Mount
9736eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    private int uploadBuffer(Buffer buf, int elementSize) {
9746eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        int[] bufferIds = new int[1];
97550b33abe053ccab7be3d1bca2328e792507963d4George Mount        mGLId.glGenBuffers(bufferIds.length, bufferIds, 0);
9766eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        int bufferId = bufferIds[0];
9776eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        mGL.glBindBuffer(GL11.GL_ARRAY_BUFFER, bufferId);
9786eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        mGL.glBufferData(GL11.GL_ARRAY_BUFFER, buf.capacity() * elementSize, buf,
9796eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount                GL11.GL_STATIC_DRAW);
9806eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        return bufferId;
9817da54d7e41e04ea5122009b40de19be0724e1ca4George Mount    }
9827da54d7e41e04ea5122009b40de19be0724e1ca4George Mount
9837da54d7e41e04ea5122009b40de19be0724e1ca4George Mount    @Override
98464072a071151b55fcbf97f6204d3c2258db386faGeorge Mount    public void recoverFromLightCycle() {
98564072a071151b55fcbf97f6204d3c2258db386faGeorge Mount        // This is only required for GLES20
98664072a071151b55fcbf97f6204d3c2258db386faGeorge Mount    }
98764072a071151b55fcbf97f6204d3c2258db386faGeorge Mount
98864072a071151b55fcbf97f6204d3c2258db386faGeorge Mount    @Override
98964072a071151b55fcbf97f6204d3c2258db386faGeorge Mount    public void getBounds(Rect bounds, int x, int y, int width, int height) {
99064072a071151b55fcbf97f6204d3c2258db386faGeorge Mount        // This is only required for GLES20
99164072a071151b55fcbf97f6204d3c2258db386faGeorge Mount    }
99250b33abe053ccab7be3d1bca2328e792507963d4George Mount
99350b33abe053ccab7be3d1bca2328e792507963d4George Mount    @Override
99450b33abe053ccab7be3d1bca2328e792507963d4George Mount    public GLId getGLId() {
99550b33abe053ccab7be3d1bca2328e792507963d4George Mount        return mGLId;
99650b33abe053ccab7be3d1bca2328e792507963d4George Mount    }
997f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin}
998