16eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount/*
26eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount * Copyright (C) 2012 The Android Open Source Project
36eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount *
46eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount * Licensed under the Apache License, Version 2.0 (the "License");
56eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount * you may not use this file except in compliance with the License.
66eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount * You may obtain a copy of the License at
76eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount *
86eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount *      http://www.apache.org/licenses/LICENSE-2.0
96eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount *
106eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount * Unless required by applicable law or agreed to in writing, software
116eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount * distributed under the License is distributed on an "AS IS" BASIS,
126eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
136eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount * See the License for the specific language governing permissions and
146eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount * limitations under the License.
156eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount */
16a4eae1abb4f2547dfbda84301ee764ce35464881John Reckpackage com.android.gallery3d.glrenderer;
176eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount
186eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mountimport android.graphics.Bitmap;
1964072a071151b55fcbf97f6204d3c2258db386faGeorge Mountimport android.graphics.Rect;
206eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mountimport android.graphics.RectF;
216eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mountimport android.opengl.GLES20;
226eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mountimport android.opengl.GLUtils;
236eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mountimport android.opengl.Matrix;
246eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mountimport android.util.Log;
256eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount
266eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mountimport com.android.gallery3d.util.IntArray;
276eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount
286eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mountimport java.nio.Buffer;
296eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mountimport java.nio.ByteBuffer;
306eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mountimport java.nio.ByteOrder;
316eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mountimport java.nio.FloatBuffer;
326eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mountimport java.util.ArrayList;
336eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mountimport java.util.Arrays;
346eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount
3550b33abe053ccab7be3d1bca2328e792507963d4George Mountpublic class GLES20Canvas implements GLCanvas {
366eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    // ************** Constants **********************
376eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    private static final String TAG = GLES20Canvas.class.getSimpleName();
386eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    private static final int FLOAT_SIZE = Float.SIZE / Byte.SIZE;
396eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    private static final float OPAQUE_ALPHA = 0.95f;
406eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount
416eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    private static final int COORDS_PER_VERTEX = 2;
426eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    private static final int VERTEX_STRIDE = COORDS_PER_VERTEX * FLOAT_SIZE;
436eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount
446eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    private static final int COUNT_FILL_VERTEX = 4;
456eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    private static final int COUNT_LINE_VERTEX = 2;
466eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    private static final int COUNT_RECT_VERTEX = 4;
476eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    private static final int OFFSET_FILL_RECT = 0;
486eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    private static final int OFFSET_DRAW_LINE = OFFSET_FILL_RECT + COUNT_FILL_VERTEX;
496eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    private static final int OFFSET_DRAW_RECT = OFFSET_DRAW_LINE + COUNT_LINE_VERTEX;
506eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount
516eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    private static final float[] BOX_COORDINATES = {
526eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount            0, 0, // Fill rectangle
536eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount            1, 0,
546eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount            0, 1,
556eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount            1, 1,
566eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount            0, 0, // Draw line
576eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount            1, 1,
586eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount            0, 0, // Draw rectangle outline
596eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount            0, 1,
606eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount            1, 1,
616eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount            1, 0,
626eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    };
636eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount
6464072a071151b55fcbf97f6204d3c2258db386faGeorge Mount    private static final float[] BOUNDS_COORDINATES = {
6564072a071151b55fcbf97f6204d3c2258db386faGeorge Mount        0, 0, 0, 1,
6664072a071151b55fcbf97f6204d3c2258db386faGeorge Mount        1, 1, 0, 1,
6764072a071151b55fcbf97f6204d3c2258db386faGeorge Mount    };
6864072a071151b55fcbf97f6204d3c2258db386faGeorge Mount
696eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    private static final String POSITION_ATTRIBUTE = "aPosition";
706eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    private static final String COLOR_UNIFORM = "uColor";
716eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    private static final String MATRIX_UNIFORM = "uMatrix";
726eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    private static final String TEXTURE_MATRIX_UNIFORM = "uTextureMatrix";
736eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    private static final String TEXTURE_SAMPLER_UNIFORM = "uTextureSampler";
746eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    private static final String ALPHA_UNIFORM = "uAlpha";
756eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    private static final String TEXTURE_COORD_ATTRIBUTE = "aTextureCoordinate";
766eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount
776eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    private static final String DRAW_VERTEX_SHADER = ""
786eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount            + "uniform mat4 " + MATRIX_UNIFORM + ";\n"
796eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount            + "attribute vec2 " + POSITION_ATTRIBUTE + ";\n"
806eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount            + "void main() {\n"
816eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount            + "  vec4 pos = vec4(" + POSITION_ATTRIBUTE + ", 0.0, 1.0);\n"
826eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount            + "  gl_Position = " + MATRIX_UNIFORM + " * pos;\n"
836eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount            + "}\n";
846eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount
856eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    private static final String DRAW_FRAGMENT_SHADER = ""
866eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount            + "precision mediump float;\n"
876eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount            + "uniform vec4 " + COLOR_UNIFORM + ";\n"
886eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount            + "void main() {\n"
896eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount            + "  gl_FragColor = " + COLOR_UNIFORM + ";\n"
906eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount            + "}\n";
916eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount
926eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    private static final String TEXTURE_VERTEX_SHADER = ""
936eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount            + "uniform mat4 " + MATRIX_UNIFORM + ";\n"
946eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount            + "uniform mat4 " + TEXTURE_MATRIX_UNIFORM + ";\n"
956eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount            + "attribute vec2 " + POSITION_ATTRIBUTE + ";\n"
966eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount            + "varying vec2 vTextureCoord;\n"
976eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount            + "void main() {\n"
986eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount            + "  vec4 pos = vec4(" + POSITION_ATTRIBUTE + ", 0.0, 1.0);\n"
996eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount            + "  gl_Position = " + MATRIX_UNIFORM + " * pos;\n"
1006eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount            + "  vTextureCoord = (" + TEXTURE_MATRIX_UNIFORM + " * pos).xy;\n"
1016eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount            + "}\n";
1026eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount
1036eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    private static final String MESH_VERTEX_SHADER = ""
1046eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount            + "uniform mat4 " + MATRIX_UNIFORM + ";\n"
1056eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount            + "attribute vec2 " + POSITION_ATTRIBUTE + ";\n"
1066eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount            + "attribute vec2 " + TEXTURE_COORD_ATTRIBUTE + ";\n"
1076eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount            + "varying vec2 vTextureCoord;\n"
1086eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount            + "void main() {\n"
1096eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount            + "  vec4 pos = vec4(" + POSITION_ATTRIBUTE + ", 0.0, 1.0);\n"
1106eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount            + "  gl_Position = " + MATRIX_UNIFORM + " * pos;\n"
1116eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount            + "  vTextureCoord = " + TEXTURE_COORD_ATTRIBUTE + ";\n"
1126eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount            + "}\n";
1136eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount
1146eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    private static final String TEXTURE_FRAGMENT_SHADER = ""
1156eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount            + "precision mediump float;\n"
1166eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount            + "varying vec2 vTextureCoord;\n"
1176eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount            + "uniform float " + ALPHA_UNIFORM + ";\n"
1186eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount            + "uniform sampler2D " + TEXTURE_SAMPLER_UNIFORM + ";\n"
1196eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount            + "void main() {\n"
1206eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount            + "  gl_FragColor = texture2D(" + TEXTURE_SAMPLER_UNIFORM + ", vTextureCoord);\n"
121bdb71cc6acbd78d5aa02d2e142b792247fb6e0bdGeorge Mount            + "  gl_FragColor *= " + ALPHA_UNIFORM + ";\n"
1226eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount            + "}\n";
1236eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount
1246eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    private static final String OES_TEXTURE_FRAGMENT_SHADER = ""
1256eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount            + "#extension GL_OES_EGL_image_external : require\n"
1266eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount            + "precision mediump float;\n"
1276eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount            + "varying vec2 vTextureCoord;\n"
1286eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount            + "uniform float " + ALPHA_UNIFORM + ";\n"
1296eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount            + "uniform samplerExternalOES " + TEXTURE_SAMPLER_UNIFORM + ";\n"
1306eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount            + "void main() {\n"
1316eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount            + "  gl_FragColor = texture2D(" + TEXTURE_SAMPLER_UNIFORM + ", vTextureCoord);\n"
132bdb71cc6acbd78d5aa02d2e142b792247fb6e0bdGeorge Mount            + "  gl_FragColor *= " + ALPHA_UNIFORM + ";\n"
1336eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount            + "}\n";
1346eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount
1356eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    private static final int INITIAL_RESTORE_STATE_SIZE = 8;
1366eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    private static final int MATRIX_SIZE = 16;
1376eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount
1386eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    // Keep track of restore state
1396eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    private float[] mMatrices = new float[INITIAL_RESTORE_STATE_SIZE * MATRIX_SIZE];
1406eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    private float[] mAlphas = new float[INITIAL_RESTORE_STATE_SIZE];
1416eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    private IntArray mSaveFlags = new IntArray();
1426eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount
1436eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    private int mCurrentAlphaIndex = 0;
1446eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    private int mCurrentMatrixIndex = 0;
1456eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount
1466eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    // Viewport size
1476eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    private int mWidth;
1486eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    private int mHeight;
1496eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount
1506eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    // Projection matrix
1516eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    private float[] mProjectionMatrix = new float[MATRIX_SIZE];
1526eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount
1536eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    // Screen size for when we aren't bound to a texture
1546eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    private int mScreenWidth;
1556eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    private int mScreenHeight;
1566eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount
1576eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    // GL programs
1586eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    private int mDrawProgram;
1596eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    private int mTextureProgram;
1606eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    private int mOesTextureProgram;
1616eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    private int mMeshProgram;
1626eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount
1636eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    // GL buffer containing BOX_COORDINATES
1646eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    private int mBoxCoordinates;
1656eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount
1666eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    // Handle indices -- common
1676eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    private static final int INDEX_POSITION = 0;
1686eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    private static final int INDEX_MATRIX = 1;
1696eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount
1706eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    // Handle indices -- draw
1716eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    private static final int INDEX_COLOR = 2;
1726eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount
1736eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    // Handle indices -- texture
1746eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    private static final int INDEX_TEXTURE_MATRIX = 2;
1756eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    private static final int INDEX_TEXTURE_SAMPLER = 3;
1766eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    private static final int INDEX_ALPHA = 4;
1776eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount
1786eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    // Handle indices -- mesh
1796eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    private static final int INDEX_TEXTURE_COORD = 2;
1806eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount
1816eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    private abstract static class ShaderParameter {
1826eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        public int handle;
1836eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        protected final String mName;
1846eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount
1856eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        public ShaderParameter(String name) {
1866eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount            mName = name;
1876eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        }
1886eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount
1896eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        public abstract void loadHandle(int program);
1906eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    }
1916eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount
1926eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    private static class UniformShaderParameter extends ShaderParameter {
1936eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        public UniformShaderParameter(String name) {
1946eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount            super(name);
1956eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        }
1966eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount
1976eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        @Override
1986eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        public void loadHandle(int program) {
1996eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount            handle = GLES20.glGetUniformLocation(program, mName);
2006eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount            checkError();
2016eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        }
2026eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    }
2036eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount
2046eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    private static class AttributeShaderParameter extends ShaderParameter {
2056eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        public AttributeShaderParameter(String name) {
2066eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount            super(name);
2076eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        }
2086eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount
2096eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        @Override
2106eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        public void loadHandle(int program) {
2116eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount            handle = GLES20.glGetAttribLocation(program, mName);
2126eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount            checkError();
2136eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        }
2146eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    }
2156eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount
2166eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    ShaderParameter[] mDrawParameters = {
2176eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount            new AttributeShaderParameter(POSITION_ATTRIBUTE), // INDEX_POSITION
2186eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount            new UniformShaderParameter(MATRIX_UNIFORM), // INDEX_MATRIX
2196eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount            new UniformShaderParameter(COLOR_UNIFORM), // INDEX_COLOR
2206eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    };
2216eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    ShaderParameter[] mTextureParameters = {
2226eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount            new AttributeShaderParameter(POSITION_ATTRIBUTE), // INDEX_POSITION
2236eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount            new UniformShaderParameter(MATRIX_UNIFORM), // INDEX_MATRIX
2246eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount            new UniformShaderParameter(TEXTURE_MATRIX_UNIFORM), // INDEX_TEXTURE_MATRIX
2256eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount            new UniformShaderParameter(TEXTURE_SAMPLER_UNIFORM), // INDEX_TEXTURE_SAMPLER
2266eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount            new UniformShaderParameter(ALPHA_UNIFORM), // INDEX_ALPHA
2276eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    };
2286eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    ShaderParameter[] mOesTextureParameters = {
2296eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount            new AttributeShaderParameter(POSITION_ATTRIBUTE), // INDEX_POSITION
2306eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount            new UniformShaderParameter(MATRIX_UNIFORM), // INDEX_MATRIX
2316eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount            new UniformShaderParameter(TEXTURE_MATRIX_UNIFORM), // INDEX_TEXTURE_MATRIX
2326eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount            new UniformShaderParameter(TEXTURE_SAMPLER_UNIFORM), // INDEX_TEXTURE_SAMPLER
2336eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount            new UniformShaderParameter(ALPHA_UNIFORM), // INDEX_ALPHA
2346eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    };
2356eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    ShaderParameter[] mMeshParameters = {
2366eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount            new AttributeShaderParameter(POSITION_ATTRIBUTE), // INDEX_POSITION
2376eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount            new UniformShaderParameter(MATRIX_UNIFORM), // INDEX_MATRIX
2386eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount            new AttributeShaderParameter(TEXTURE_COORD_ATTRIBUTE), // INDEX_TEXTURE_COORD
2396eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount            new UniformShaderParameter(TEXTURE_SAMPLER_UNIFORM), // INDEX_TEXTURE_SAMPLER
2406eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount            new UniformShaderParameter(ALPHA_UNIFORM), // INDEX_ALPHA
2416eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    };
2426eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount
2436eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    private final IntArray mUnboundTextures = new IntArray();
2446eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    private final IntArray mDeleteBuffers = new IntArray();
2456eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount
2466eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    // Keep track of statistics for debugging
2476eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    private int mCountDrawMesh = 0;
2486eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    private int mCountTextureRect = 0;
2496eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    private int mCountFillRect = 0;
2506eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    private int mCountDrawLine = 0;
2516eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount
2526eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    // Buffer for framebuffer IDs -- we keep track so we can switch the attached
2536eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    // texture.
2546eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    private int[] mFrameBuffer = new int[1];
2556eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount
2566eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    // Bound textures.
2576eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    private ArrayList<RawTexture> mTargetTextures = new ArrayList<RawTexture>();
2586eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount
2596eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    // Temporary variables used within calculations
2606eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    private final float[] mTempMatrix = new float[32];
2616eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    private final float[] mTempColor = new float[4];
2626eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    private final RectF mTempSourceRect = new RectF();
2636eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    private final RectF mTempTargetRect = new RectF();
2646eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    private final float[] mTempTextureMatrix = new float[MATRIX_SIZE];
2656eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    private final int[] mTempIntArray = new int[1];
2666eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount
26750b33abe053ccab7be3d1bca2328e792507963d4George Mount    private static final GLId mGLId = new GLES20IdImpl();
26850b33abe053ccab7be3d1bca2328e792507963d4George Mount
2696eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    public GLES20Canvas() {
2706eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        Matrix.setIdentityM(mTempTextureMatrix, 0);
2716eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        Matrix.setIdentityM(mMatrices, mCurrentMatrixIndex);
2726eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        mAlphas[mCurrentAlphaIndex] = 1f;
2736eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        mTargetTextures.add(null);
2746eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount
2756eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        FloatBuffer boxBuffer = createBuffer(BOX_COORDINATES);
2766eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        mBoxCoordinates = uploadBuffer(boxBuffer);
2776eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount
2786eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        int drawVertexShader = loadShader(GLES20.GL_VERTEX_SHADER, DRAW_VERTEX_SHADER);
2796eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        int textureVertexShader = loadShader(GLES20.GL_VERTEX_SHADER, TEXTURE_VERTEX_SHADER);
2806eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        int meshVertexShader = loadShader(GLES20.GL_VERTEX_SHADER, MESH_VERTEX_SHADER);
2816eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        int drawFragmentShader = loadShader(GLES20.GL_FRAGMENT_SHADER, DRAW_FRAGMENT_SHADER);
2826eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        int textureFragmentShader = loadShader(GLES20.GL_FRAGMENT_SHADER, TEXTURE_FRAGMENT_SHADER);
2836eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        int oesTextureFragmentShader = loadShader(GLES20.GL_FRAGMENT_SHADER,
2846eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount                OES_TEXTURE_FRAGMENT_SHADER);
2856eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount
2866eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        mDrawProgram = assembleProgram(drawVertexShader, drawFragmentShader, mDrawParameters);
2876eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        mTextureProgram = assembleProgram(textureVertexShader, textureFragmentShader,
2886eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount                mTextureParameters);
2896eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        mOesTextureProgram = assembleProgram(textureVertexShader, oesTextureFragmentShader,
2906eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount                mOesTextureParameters);
2916eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        mMeshProgram = assembleProgram(meshVertexShader, textureFragmentShader, mMeshParameters);
292bdb71cc6acbd78d5aa02d2e142b792247fb6e0bdGeorge Mount        GLES20.glBlendFunc(GLES20.GL_ONE, GLES20.GL_ONE_MINUS_SRC_ALPHA);
293bdb71cc6acbd78d5aa02d2e142b792247fb6e0bdGeorge Mount        checkError();
2946eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    }
2956eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount
2966eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    private static FloatBuffer createBuffer(float[] values) {
2976eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        // First create an nio buffer, then create a VBO from it.
2986eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        int size = values.length * FLOAT_SIZE;
2996eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        FloatBuffer buffer = ByteBuffer.allocateDirect(size).order(ByteOrder.nativeOrder())
3006eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount                .asFloatBuffer();
3016eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        buffer.put(values, 0, values.length).position(0);
3026eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        return buffer;
3036eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    }
3046eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount
3056eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    private int assembleProgram(int vertexShader, int fragmentShader, ShaderParameter[] params) {
3066eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        int program = GLES20.glCreateProgram();
3076eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        checkError();
3086eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        if (program == 0) {
3096eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount            throw new RuntimeException("Cannot create GL program: " + GLES20.glGetError());
3106eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        }
3116eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        GLES20.glAttachShader(program, vertexShader);
3126eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        checkError();
3136eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        GLES20.glAttachShader(program, fragmentShader);
3146eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        checkError();
3156eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        GLES20.glLinkProgram(program);
3166eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        checkError();
3176eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        int[] mLinkStatus = mTempIntArray;
3186eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        GLES20.glGetProgramiv(program, GLES20.GL_LINK_STATUS, mLinkStatus, 0);
3196eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        if (mLinkStatus[0] != GLES20.GL_TRUE) {
3206eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount            Log.e(TAG, "Could not link program: ");
3216eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount            Log.e(TAG, GLES20.glGetProgramInfoLog(program));
3226eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount            GLES20.glDeleteProgram(program);
3236eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount            program = 0;
3246eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        }
3256eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        for (int i = 0; i < params.length; i++) {
3266eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount            params[i].loadHandle(program);
3276eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        }
3286eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        return program;
3296eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    }
3306eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount
3316eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    private static int loadShader(int type, String shaderCode) {
3326eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        // create a vertex shader type (GLES20.GL_VERTEX_SHADER)
3336eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        // or a fragment shader type (GLES20.GL_FRAGMENT_SHADER)
3346eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        int shader = GLES20.glCreateShader(type);
3356eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount
3366eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        // add the source code to the shader and compile it
3376eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        GLES20.glShaderSource(shader, shaderCode);
3386eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        checkError();
3396eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        GLES20.glCompileShader(shader);
3406eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        checkError();
3416eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount
3426eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        return shader;
3436eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    }
3446eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount
3456eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    @Override
3466eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    public void setSize(int width, int height) {
3476eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        mWidth = width;
3486eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        mHeight = height;
3496eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        GLES20.glViewport(0, 0, mWidth, mHeight);
3506eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        checkError();
3516eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        Matrix.setIdentityM(mMatrices, mCurrentMatrixIndex);
3526eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        Matrix.orthoM(mProjectionMatrix, 0, 0, width, 0, height, -1, 1);
3536eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        if (getTargetTexture() == null) {
3546eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount            mScreenWidth = width;
3556eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount            mScreenHeight = height;
3566eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount            Matrix.translateM(mMatrices, mCurrentMatrixIndex, 0, height, 0);
3576eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount            Matrix.scaleM(mMatrices, mCurrentMatrixIndex, 1, -1, 1);
3586eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        }
3596eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    }
3606eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount
3616eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    @Override
3626eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    public void clearBuffer() {
3636eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        GLES20.glClearColor(0f, 0f, 0f, 1f);
3646eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        checkError();
3656eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
3666eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        checkError();
3676eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    }
3686eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount
3696eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    @Override
3706eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    public void clearBuffer(float[] argb) {
3716eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        GLES20.glClearColor(argb[1], argb[2], argb[3], argb[0]);
3726eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        checkError();
3736eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
3746eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        checkError();
3756eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    }
3766eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount
3776eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    @Override
3786eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    public float getAlpha() {
3796eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        return mAlphas[mCurrentAlphaIndex];
3806eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    }
3816eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount
3826eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    @Override
3836eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    public void setAlpha(float alpha) {
3846eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        mAlphas[mCurrentAlphaIndex] = alpha;
3856eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    }
3866eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount
3876eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    @Override
3886eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    public void multiplyAlpha(float alpha) {
3896eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        setAlpha(getAlpha() * alpha);
3906eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    }
3916eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount
3926eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    @Override
3936eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    public void translate(float x, float y, float z) {
3946eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        Matrix.translateM(mMatrices, mCurrentMatrixIndex, x, y, z);
3956eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    }
3966eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount
3976eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    // This is a faster version of translate(x, y, z) because
3986eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    // (1) we knows z = 0, (2) we inline the Matrix.translateM call,
3996eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    // (3) we unroll the loop
4006eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    @Override
4016eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    public void translate(float x, float y) {
4026eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        int index = mCurrentMatrixIndex;
4036eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        float[] m = mMatrices;
4046eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        m[index + 12] += m[index + 0] * x + m[index + 4] * y;
4056eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        m[index + 13] += m[index + 1] * x + m[index + 5] * y;
4066eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        m[index + 14] += m[index + 2] * x + m[index + 6] * y;
4076eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        m[index + 15] += m[index + 3] * x + m[index + 7] * y;
4086eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    }
4096eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount
4106eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    @Override
4116eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    public void scale(float sx, float sy, float sz) {
4126eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        Matrix.scaleM(mMatrices, mCurrentMatrixIndex, sx, sy, sz);
4136eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    }
4146eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount
4156eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    @Override
4166eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    public void rotate(float angle, float x, float y, float z) {
4176eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        if (angle == 0f) {
4186eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount            return;
4196eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        }
4206eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        float[] temp = mTempMatrix;
4216eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        Matrix.setRotateM(temp, 0, angle, x, y, z);
4226eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        float[] matrix = mMatrices;
4236eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        int index = mCurrentMatrixIndex;
4246eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        Matrix.multiplyMM(temp, MATRIX_SIZE, matrix, index, temp, 0);
4256eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        System.arraycopy(temp, MATRIX_SIZE, matrix, index, MATRIX_SIZE);
4266eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    }
4276eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount
4286eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    @Override
4296eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    public void multiplyMatrix(float[] matrix, int offset) {
4306eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        float[] temp = mTempMatrix;
4316eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        float[] currentMatrix = mMatrices;
4326eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        int index = mCurrentMatrixIndex;
4336eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        Matrix.multiplyMM(temp, 0, currentMatrix, index, matrix, offset);
4346eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        System.arraycopy(temp, 0, currentMatrix, index, 16);
4356eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    }
4366eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount
4376eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    @Override
4386eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    public void save() {
4396eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        save(SAVE_FLAG_ALL);
4406eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    }
4416eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount
4426eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    @Override
4436eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    public void save(int saveFlags) {
4446eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        boolean saveAlpha = (saveFlags & SAVE_FLAG_ALPHA) == SAVE_FLAG_ALPHA;
4456eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        if (saveAlpha) {
4466eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount            float currentAlpha = getAlpha();
4476eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount            mCurrentAlphaIndex++;
4486eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount            if (mAlphas.length <= mCurrentAlphaIndex) {
4496eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount                mAlphas = Arrays.copyOf(mAlphas, mAlphas.length * 2);
4506eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount            }
4516eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount            mAlphas[mCurrentAlphaIndex] = currentAlpha;
4526eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        }
4536eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        boolean saveMatrix = (saveFlags & SAVE_FLAG_MATRIX) == SAVE_FLAG_MATRIX;
4546eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        if (saveMatrix) {
4556eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount            int currentIndex = mCurrentMatrixIndex;
4566eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount            mCurrentMatrixIndex += MATRIX_SIZE;
4576eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount            if (mMatrices.length <= mCurrentMatrixIndex) {
4586eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount                mMatrices = Arrays.copyOf(mMatrices, mMatrices.length * 2);
4596eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount            }
4606eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount            System.arraycopy(mMatrices, currentIndex, mMatrices, mCurrentMatrixIndex, MATRIX_SIZE);
4616eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        }
4626eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        mSaveFlags.add(saveFlags);
4636eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    }
4646eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount
4656eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    @Override
4666eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    public void restore() {
4676eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        int restoreFlags = mSaveFlags.removeLast();
4686eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        boolean restoreAlpha = (restoreFlags & SAVE_FLAG_ALPHA) == SAVE_FLAG_ALPHA;
4696eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        if (restoreAlpha) {
4706eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount            mCurrentAlphaIndex--;
4716eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        }
4726eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        boolean restoreMatrix = (restoreFlags & SAVE_FLAG_MATRIX) == SAVE_FLAG_MATRIX;
4736eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        if (restoreMatrix) {
4746eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount            mCurrentMatrixIndex -= MATRIX_SIZE;
4756eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        }
4766eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    }
4776eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount
4786eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    @Override
4796eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    public void drawLine(float x1, float y1, float x2, float y2, GLPaint paint) {
4806eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        draw(GLES20.GL_LINE_STRIP, OFFSET_DRAW_LINE, COUNT_LINE_VERTEX, x1, y1, x2 - x1, y2 - y1,
4816eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount                paint);
4826eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        mCountDrawLine++;
4836eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    }
4846eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount
4856eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    @Override
4866eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    public void drawRect(float x, float y, float width, float height, GLPaint paint) {
4876eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        draw(GLES20.GL_LINE_LOOP, OFFSET_DRAW_RECT, COUNT_RECT_VERTEX, x, y, width, height, paint);
4886eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        mCountDrawLine++;
4896eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    }
4906eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount
4916eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    private void draw(int type, int offset, int count, float x, float y, float width, float height,
4926eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount            GLPaint paint) {
4936eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        draw(type, offset, count, x, y, width, height, paint.getColor(), paint.getLineWidth());
4946eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    }
4956eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount
4966eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    private void draw(int type, int offset, int count, float x, float y, float width, float height,
4976eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount            int color, float lineWidth) {
4986eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        prepareDraw(offset, color, lineWidth);
4996eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        draw(mDrawParameters, type, count, x, y, width, height);
5006eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    }
5016eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount
5026eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    private void prepareDraw(int offset, int color, float lineWidth) {
5036eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        GLES20.glUseProgram(mDrawProgram);
5046eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        checkError();
5056eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        if (lineWidth > 0) {
5066eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount            GLES20.glLineWidth(lineWidth);
5076eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount            checkError();
5086eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        }
5096eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        float[] colorArray = getColor(color);
5106eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        boolean blendingEnabled = (colorArray[3] < 1f);
5116eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        enableBlending(blendingEnabled);
5126eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        if (blendingEnabled) {
5136eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount            GLES20.glBlendColor(colorArray[0], colorArray[1], colorArray[2], colorArray[3]);
5146eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount            checkError();
5156eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        }
5166eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount
5176eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        GLES20.glUniform4fv(mDrawParameters[INDEX_COLOR].handle, 1, colorArray, 0);
5186eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        setPosition(mDrawParameters, offset);
5196eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        checkError();
5206eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    }
5216eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount
5226eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    private float[] getColor(int color) {
5236eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        float alpha = ((color >>> 24) & 0xFF) / 255f * getAlpha();
5246eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        float red = ((color >>> 16) & 0xFF) / 255f * alpha;
5256eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        float green = ((color >>> 8) & 0xFF) / 255f * alpha;
5266eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        float blue = (color & 0xFF) / 255f * alpha;
5276eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        mTempColor[0] = red;
5286eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        mTempColor[1] = green;
5296eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        mTempColor[2] = blue;
5306eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        mTempColor[3] = alpha;
5316eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        return mTempColor;
5326eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    }
5336eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount
5346eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    private void enableBlending(boolean enableBlending) {
5356eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        if (enableBlending) {
5366eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount            GLES20.glEnable(GLES20.GL_BLEND);
5376eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount            checkError();
5386eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        } else {
5396eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount            GLES20.glDisable(GLES20.GL_BLEND);
5406eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount            checkError();
5416eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        }
5426eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    }
5436eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount
5446eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    private void setPosition(ShaderParameter[] params, int offset) {
5456eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, mBoxCoordinates);
5466eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        checkError();
5476eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        GLES20.glVertexAttribPointer(params[INDEX_POSITION].handle, COORDS_PER_VERTEX,
5486eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount                GLES20.GL_FLOAT, false, VERTEX_STRIDE, offset * VERTEX_STRIDE);
5496eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        checkError();
55064072a071151b55fcbf97f6204d3c2258db386faGeorge Mount        GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0);
55164072a071151b55fcbf97f6204d3c2258db386faGeorge Mount        checkError();
5526eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    }
5536eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount
5546eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    private void draw(ShaderParameter[] params, int type, int count, float x, float y, float width,
5556eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount            float height) {
5566eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        setMatrix(params, x, y, width, height);
5576eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        int positionHandle = params[INDEX_POSITION].handle;
5586eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        GLES20.glEnableVertexAttribArray(positionHandle);
5596eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        checkError();
5606eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        GLES20.glDrawArrays(type, 0, count);
5616eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        checkError();
5626eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        GLES20.glDisableVertexAttribArray(positionHandle);
5636eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        checkError();
5646eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    }
5656eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount
5666eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    private void setMatrix(ShaderParameter[] params, float x, float y, float width, float height) {
5676eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        Matrix.translateM(mTempMatrix, 0, mMatrices, mCurrentMatrixIndex, x, y, 0f);
5686eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        Matrix.scaleM(mTempMatrix, 0, width, height, 1f);
5696eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        Matrix.multiplyMM(mTempMatrix, MATRIX_SIZE, mProjectionMatrix, 0, mTempMatrix, 0);
5706eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        GLES20.glUniformMatrix4fv(params[INDEX_MATRIX].handle, 1, false, mTempMatrix, MATRIX_SIZE);
5716eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        checkError();
5726eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    }
5736eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount
5746eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    @Override
5756eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    public void fillRect(float x, float y, float width, float height, int color) {
5766eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        draw(GLES20.GL_TRIANGLE_STRIP, OFFSET_FILL_RECT, COUNT_FILL_VERTEX, x, y, width, height,
5776eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount                color, 0f);
5786eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        mCountFillRect++;
5796eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    }
5806eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount
5816eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    @Override
5826eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    public void drawTexture(BasicTexture texture, int x, int y, int width, int height) {
5836eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        if (width <= 0 || height <= 0) {
5846eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount            return;
5856eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        }
5866eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        copyTextureCoordinates(texture, mTempSourceRect);
5876eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        mTempTargetRect.set(x, y, x + width, y + height);
5886eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        convertCoordinate(mTempSourceRect, mTempTargetRect, texture);
5896eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        drawTextureRect(texture, mTempSourceRect, mTempTargetRect);
5906eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    }
5916eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount
5926eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    private static void copyTextureCoordinates(BasicTexture texture, RectF outRect) {
5936eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        int left = 0;
5946eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        int top = 0;
5956eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        int right = texture.getWidth();
5966eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        int bottom = texture.getHeight();
5976eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        if (texture.hasBorder()) {
5986eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount            left = 1;
5996eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount            top = 1;
6006eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount            right -= 1;
6016eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount            bottom -= 1;
6026eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        }
6036eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        outRect.set(left, top, right, bottom);
6046eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    }
6056eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount
6066eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    @Override
6076eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    public void drawTexture(BasicTexture texture, RectF source, RectF target) {
6086eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        if (target.width() <= 0 || target.height() <= 0) {
6096eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount            return;
6106eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        }
6116eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        mTempSourceRect.set(source);
6126eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        mTempTargetRect.set(target);
6136eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount
6146eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        convertCoordinate(mTempSourceRect, mTempTargetRect, texture);
6156eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        drawTextureRect(texture, mTempSourceRect, mTempTargetRect);
6166eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    }
6176eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount
6186eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    @Override
6196eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    public void drawTexture(BasicTexture texture, float[] textureTransform, int x, int y, int w,
6206eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount            int h) {
6216eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        if (w <= 0 || h <= 0) {
6226eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount            return;
6236eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        }
6246eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        mTempTargetRect.set(x, y, x + w, y + h);
6256eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        drawTextureRect(texture, textureTransform, mTempTargetRect);
6266eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    }
6276eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount
6286eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    private void drawTextureRect(BasicTexture texture, RectF source, RectF target) {
6296eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        setTextureMatrix(source);
6306eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        drawTextureRect(texture, mTempTextureMatrix, target);
6316eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    }
6326eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount
6336eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    private void setTextureMatrix(RectF source) {
6346eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        mTempTextureMatrix[0] = source.width();
6356eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        mTempTextureMatrix[5] = source.height();
6366eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        mTempTextureMatrix[12] = source.left;
6376eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        mTempTextureMatrix[13] = source.top;
6386eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    }
6396eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount
6406eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    // This function changes the source coordinate to the texture coordinates.
6416eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    // It also clips the source and target coordinates if it is beyond the
6426eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    // bound of the texture.
6436eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    private static void convertCoordinate(RectF source, RectF target, BasicTexture texture) {
6446eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        int width = texture.getWidth();
6456eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        int height = texture.getHeight();
6466eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        int texWidth = texture.getTextureWidth();
6476eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        int texHeight = texture.getTextureHeight();
6486eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        // Convert to texture coordinates
6496eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        source.left /= texWidth;
6506eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        source.right /= texWidth;
6516eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        source.top /= texHeight;
6526eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        source.bottom /= texHeight;
6536eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount
6546eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        // Clip if the rendering range is beyond the bound of the texture.
6556eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        float xBound = (float) width / texWidth;
6566eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        if (source.right > xBound) {
6576eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount            target.right = target.left + target.width() * (xBound - source.left) / source.width();
6586eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount            source.right = xBound;
6596eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        }
6606eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        float yBound = (float) height / texHeight;
6616eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        if (source.bottom > yBound) {
6626eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount            target.bottom = target.top + target.height() * (yBound - source.top) / source.height();
6636eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount            source.bottom = yBound;
6646eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        }
6656eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    }
6666eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount
6676eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    private void drawTextureRect(BasicTexture texture, float[] textureMatrix, RectF target) {
6686eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        ShaderParameter[] params = prepareTexture(texture);
6696eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        setPosition(params, OFFSET_FILL_RECT);
6706eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        GLES20.glUniformMatrix4fv(params[INDEX_TEXTURE_MATRIX].handle, 1, false, textureMatrix, 0);
6716eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        checkError();
67244a1b22eb7098819ac0251764b9fa686d8339d66George Mount        if (texture.isFlippedVertically()) {
67344a1b22eb7098819ac0251764b9fa686d8339d66George Mount            save(SAVE_FLAG_MATRIX);
67444a1b22eb7098819ac0251764b9fa686d8339d66George Mount            translate(0, target.centerY());
67544a1b22eb7098819ac0251764b9fa686d8339d66George Mount            scale(1, -1, 1);
67644a1b22eb7098819ac0251764b9fa686d8339d66George Mount            translate(0, -target.centerY());
67744a1b22eb7098819ac0251764b9fa686d8339d66George Mount        }
6786eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        draw(params, GLES20.GL_TRIANGLE_STRIP, COUNT_FILL_VERTEX, target.left, target.top,
6796eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount                target.width(), target.height());
68044a1b22eb7098819ac0251764b9fa686d8339d66George Mount        if (texture.isFlippedVertically()) {
68144a1b22eb7098819ac0251764b9fa686d8339d66George Mount            restore();
68244a1b22eb7098819ac0251764b9fa686d8339d66George Mount        }
6836eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        mCountTextureRect++;
6846eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    }
6856eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount
6866eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    private ShaderParameter[] prepareTexture(BasicTexture texture) {
6876eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        ShaderParameter[] params;
6886eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        int program;
6896eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        if (texture.getTarget() == GLES20.GL_TEXTURE_2D) {
6906eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount            params = mTextureParameters;
6916eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount            program = mTextureProgram;
6926eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        } else {
6936eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount            params = mOesTextureParameters;
6946eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount            program = mOesTextureProgram;
6956eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        }
6966eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        prepareTexture(texture, program, params);
6976eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        return params;
6986eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    }
6996eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount
7006eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    private void prepareTexture(BasicTexture texture, int program, ShaderParameter[] params) {
7016eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        GLES20.glUseProgram(program);
7026eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        checkError();
7036eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        enableBlending(!texture.isOpaque() || getAlpha() < OPAQUE_ALPHA);
7046eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
7056eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        checkError();
7066eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        texture.onBind(this);
7076eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        GLES20.glBindTexture(texture.getTarget(), texture.getId());
7086eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        checkError();
7096eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        GLES20.glUniform1i(params[INDEX_TEXTURE_SAMPLER].handle, 0);
7106eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        checkError();
7116eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        GLES20.glUniform1f(params[INDEX_ALPHA].handle, getAlpha());
7126eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        checkError();
7136eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    }
7146eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount
7156eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    @Override
7166eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    public void drawMesh(BasicTexture texture, int x, int y, int xyBuffer, int uvBuffer,
7176eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount            int indexBuffer, int indexCount) {
7186eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        prepareTexture(texture, mMeshProgram, mMeshParameters);
7196eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount
7206eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        GLES20.glBindBuffer(GLES20.GL_ELEMENT_ARRAY_BUFFER, indexBuffer);
7216eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        checkError();
7226eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount
7236eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, xyBuffer);
7246eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        checkError();
7256eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        int positionHandle = mMeshParameters[INDEX_POSITION].handle;
7266eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        GLES20.glVertexAttribPointer(positionHandle, COORDS_PER_VERTEX, GLES20.GL_FLOAT, false,
7276eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount                VERTEX_STRIDE, 0);
7286eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        checkError();
7296eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount
7306eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, uvBuffer);
7316eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        checkError();
7326eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        int texCoordHandle = mMeshParameters[INDEX_TEXTURE_COORD].handle;
7336eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        GLES20.glVertexAttribPointer(texCoordHandle, COORDS_PER_VERTEX, GLES20.GL_FLOAT,
7346eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount                false, VERTEX_STRIDE, 0);
7356eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        checkError();
73664072a071151b55fcbf97f6204d3c2258db386faGeorge Mount        GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0);
73764072a071151b55fcbf97f6204d3c2258db386faGeorge Mount        checkError();
7386eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount
7396eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        GLES20.glEnableVertexAttribArray(positionHandle);
7406eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        checkError();
7416eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        GLES20.glEnableVertexAttribArray(texCoordHandle);
7426eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        checkError();
7436eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount
7446eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        setMatrix(mMeshParameters, x, y, 1, 1);
7456eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        GLES20.glDrawElements(GLES20.GL_TRIANGLE_STRIP, indexCount, GLES20.GL_UNSIGNED_BYTE, 0);
7466eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        checkError();
7476eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount
7486eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        GLES20.glDisableVertexAttribArray(positionHandle);
7496eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        checkError();
7506eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        GLES20.glDisableVertexAttribArray(texCoordHandle);
7516eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        checkError();
7526eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        GLES20.glBindBuffer(GLES20.GL_ELEMENT_ARRAY_BUFFER, 0);
7536eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        checkError();
7546eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        mCountDrawMesh++;
7556eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    }
7566eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount
7576eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    @Override
7586eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    public void drawMixed(BasicTexture texture, int toColor, float ratio, int x, int y, int w, int h) {
7596eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        copyTextureCoordinates(texture, mTempSourceRect);
7606eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        mTempTargetRect.set(x, y, x + w, y + h);
7616eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        drawMixed(texture, toColor, ratio, mTempSourceRect, mTempTargetRect);
7626eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    }
7636eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount
7646eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    @Override
7656eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    public void drawMixed(BasicTexture texture, int toColor, float ratio, RectF source, RectF target) {
7666eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        if (target.width() <= 0 || target.height() <= 0) {
7676eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount            return;
7686eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        }
7696eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        save(SAVE_FLAG_ALPHA);
7706eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount
7716eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        float currentAlpha = getAlpha();
7726eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        float cappedRatio = Math.min(1f, Math.max(0f, ratio));
7736eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount
7746eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        float textureAlpha = (1f - cappedRatio) * currentAlpha;
7756eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        setAlpha(textureAlpha);
7766eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        drawTexture(texture, source, target);
7776eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount
7786eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        float colorAlpha = cappedRatio * currentAlpha;
7796eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        setAlpha(colorAlpha);
7806eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        fillRect(target.left, target.top, target.width(), target.height(), toColor);
7816eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount
7826eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        restore();
7836eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    }
7846eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount
7856eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    @Override
7866eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    public boolean unloadTexture(BasicTexture texture) {
7876eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        boolean unload = texture.isLoaded();
7886eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        if (unload) {
7896eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount            synchronized (mUnboundTextures) {
7906eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount                mUnboundTextures.add(texture.getId());
7916eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount            }
7926eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        }
7936eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        return unload;
7946eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    }
7956eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount
7966eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    @Override
7976eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    public void deleteBuffer(int bufferId) {
7986eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        synchronized (mUnboundTextures) {
7996eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount            mDeleteBuffers.add(bufferId);
8006eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        }
8016eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    }
8026eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount
8036eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    @Override
8046eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    public void deleteRecycledResources() {
8056eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        synchronized (mUnboundTextures) {
8066eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount            IntArray ids = mUnboundTextures;
8076eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount            if (mUnboundTextures.size() > 0) {
80850b33abe053ccab7be3d1bca2328e792507963d4George Mount                mGLId.glDeleteTextures(null, ids.size(), ids.getInternalArray(), 0);
8096eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount                ids.clear();
8106eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount            }
8116eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount
8126eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount            ids = mDeleteBuffers;
8136eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount            if (ids.size() > 0) {
81450b33abe053ccab7be3d1bca2328e792507963d4George Mount                mGLId.glDeleteBuffers(null, ids.size(), ids.getInternalArray(), 0);
8156eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount                ids.clear();
8166eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount            }
8176eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        }
8186eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    }
8196eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount
8206eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    @Override
8216eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    public void dumpStatisticsAndClear() {
8226eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        String line = String.format("MESH:%d, TEX_RECT:%d, FILL_RECT:%d, LINE:%d", mCountDrawMesh,
8236eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount                mCountTextureRect, mCountFillRect, mCountDrawLine);
8246eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        mCountDrawMesh = 0;
8256eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        mCountTextureRect = 0;
8266eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        mCountFillRect = 0;
8276eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        mCountDrawLine = 0;
8286eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        Log.d(TAG, line);
8296eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    }
8306eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount
8316eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    @Override
8326eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    public void endRenderTarget() {
8336eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        RawTexture oldTexture = mTargetTextures.remove(mTargetTextures.size() - 1);
8346eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        RawTexture texture = getTargetTexture();
8356eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        setRenderTarget(oldTexture, texture);
8366eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        restore(); // restore matrix and alpha
8376eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    }
8386eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount
8396eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    @Override
8406eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    public void beginRenderTarget(RawTexture texture) {
8416eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        save(); // save matrix and alpha and blending
8426eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        RawTexture oldTexture = getTargetTexture();
8436eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        mTargetTextures.add(texture);
8446eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        setRenderTarget(oldTexture, texture);
8456eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    }
8466eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount
8476eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    private RawTexture getTargetTexture() {
8486eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        return mTargetTextures.get(mTargetTextures.size() - 1);
8496eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    }
8506eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount
8516eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    private void setRenderTarget(BasicTexture oldTexture, RawTexture texture) {
8526eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        if (oldTexture == null && texture != null) {
8536eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount            GLES20.glGenFramebuffers(1, mFrameBuffer, 0);
8546eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount            checkError();
8556eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount            GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, mFrameBuffer[0]);
8566eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount            checkError();
8576eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        } else if (oldTexture != null && texture == null) {
8586eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount            GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, 0);
8596eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount            checkError();
8606eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount            GLES20.glDeleteFramebuffers(1, mFrameBuffer, 0);
8616eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount            checkError();
8626eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        }
8636eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount
8646eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        if (texture == null) {
8656eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount            setSize(mScreenWidth, mScreenHeight);
8666eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        } else {
8676eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount            setSize(texture.getWidth(), texture.getHeight());
8686eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount
8696eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount            if (!texture.isLoaded()) {
8706eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount                texture.prepare(this);
8716eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount            }
8726eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount
8736eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount            GLES20.glFramebufferTexture2D(GLES20.GL_FRAMEBUFFER, GLES20.GL_COLOR_ATTACHMENT0,
8746eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount                    texture.getTarget(), texture.getId(), 0);
8756eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount            checkError();
8766eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount
8776eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount            checkFramebufferStatus();
8786eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        }
8796eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    }
8806eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount
8816eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    private static void checkFramebufferStatus() {
8826eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        int status = GLES20.glCheckFramebufferStatus(GLES20.GL_FRAMEBUFFER);
8836eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        if (status != GLES20.GL_FRAMEBUFFER_COMPLETE) {
8846eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount            String msg = "";
8856eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount            switch (status) {
8866eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount                case GLES20.GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT:
8876eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount                    msg = "GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT";
8886eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount                    break;
8896eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount                case GLES20.GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS:
8906eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount                    msg = "GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS";
8916eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount                    break;
8926eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount                case GLES20.GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT:
8936eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount                    msg = "GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT";
8946eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount                    break;
8956eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount                case GLES20.GL_FRAMEBUFFER_UNSUPPORTED:
8966eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount                    msg = "GL_FRAMEBUFFER_UNSUPPORTED";
8976eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount                    break;
8986eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount            }
8996eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount            throw new RuntimeException(msg + ":" + Integer.toHexString(status));
9006eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        }
9016eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    }
9026eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount
9036eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    @Override
9046eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    public void setTextureParameters(BasicTexture texture) {
9056eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        int target = texture.getTarget();
9066eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        GLES20.glBindTexture(target, texture.getId());
9076eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        checkError();
9086eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        GLES20.glTexParameteri(target, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE);
9096eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        GLES20.glTexParameteri(target, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE);
9106eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        GLES20.glTexParameterf(target, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR);
9116eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        GLES20.glTexParameterf(target, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
9126eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    }
9136eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount
9146eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    @Override
9156eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    public void initializeTextureSize(BasicTexture texture, int format, int type) {
9166eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        int target = texture.getTarget();
9176eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        GLES20.glBindTexture(target, texture.getId());
9186eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        checkError();
9196eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        int width = texture.getTextureWidth();
9206eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        int height = texture.getTextureHeight();
9216eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        GLES20.glTexImage2D(target, 0, format, width, height, 0, format, type, null);
9226eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    }
9236eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount
9246eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    @Override
9256eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    public void initializeTexture(BasicTexture texture, Bitmap bitmap) {
9266eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        int target = texture.getTarget();
9276eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        GLES20.glBindTexture(target, texture.getId());
9286eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        checkError();
9296eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        GLUtils.texImage2D(target, 0, bitmap, 0);
9306eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    }
9316eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount
9326eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    @Override
9336eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    public void texSubImage2D(BasicTexture texture, int xOffset, int yOffset, Bitmap bitmap,
9346eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount            int format, int type) {
9356eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        int target = texture.getTarget();
9366eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        GLES20.glBindTexture(target, texture.getId());
9376eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        checkError();
9386eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        GLUtils.texSubImage2D(target, 0, xOffset, yOffset, bitmap, format, type);
9396eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    }
9406eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount
9416eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    @Override
9426eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    public int uploadBuffer(FloatBuffer buf) {
9436eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        return uploadBuffer(buf, FLOAT_SIZE);
9446eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    }
9456eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount
9466eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    @Override
9476eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    public int uploadBuffer(ByteBuffer buf) {
9486eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        return uploadBuffer(buf, 1);
9496eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    }
9506eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount
9516eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    private int uploadBuffer(Buffer buffer, int elementSize) {
95250b33abe053ccab7be3d1bca2328e792507963d4George Mount        mGLId.glGenBuffers(1, mTempIntArray, 0);
9536eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        checkError();
9546eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        int bufferId = mTempIntArray[0];
9556eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, bufferId);
9566eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        checkError();
9576eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        GLES20.glBufferData(GLES20.GL_ARRAY_BUFFER, buffer.capacity() * elementSize, buffer,
9586eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount                GLES20.GL_STATIC_DRAW);
9596eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        checkError();
9606eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        return bufferId;
9616eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    }
9626eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount
96364072a071151b55fcbf97f6204d3c2258db386faGeorge Mount    public static void checkError() {
9646eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        int error = GLES20.glGetError();
9656eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        if (error != 0) {
9666eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount            Throwable t = new Throwable();
9676eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount            Log.e(TAG, "GL error: " + error, t);
9686eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        }
9696eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    }
9706eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount
9716eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    @SuppressWarnings("unused")
9726eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    private static void printMatrix(String message, float[] m, int offset) {
9736eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        StringBuilder b = new StringBuilder(message);
9746eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        for (int i = 0; i < MATRIX_SIZE; i++) {
9756eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount            b.append(' ');
9766eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount            if (i % 4 == 0) {
9776eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount                b.append('\n');
9786eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount            }
9796eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount            b.append(m[offset + i]);
9806eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        }
9816eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount        Log.v(TAG, b.toString());
9826eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount    }
9836eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount
98464072a071151b55fcbf97f6204d3c2258db386faGeorge Mount    @Override
98564072a071151b55fcbf97f6204d3c2258db386faGeorge Mount    public void recoverFromLightCycle() {
98664072a071151b55fcbf97f6204d3c2258db386faGeorge Mount        GLES20.glViewport(0, 0, mWidth, mHeight);
98764072a071151b55fcbf97f6204d3c2258db386faGeorge Mount        GLES20.glDisable(GLES20.GL_DEPTH_TEST);
988bdb71cc6acbd78d5aa02d2e142b792247fb6e0bdGeorge Mount        GLES20.glBlendFunc(GLES20.GL_ONE, GLES20.GL_ONE_MINUS_SRC_ALPHA);
989bdb71cc6acbd78d5aa02d2e142b792247fb6e0bdGeorge Mount        checkError();
99064072a071151b55fcbf97f6204d3c2258db386faGeorge Mount    }
99164072a071151b55fcbf97f6204d3c2258db386faGeorge Mount
99264072a071151b55fcbf97f6204d3c2258db386faGeorge Mount    @Override
99364072a071151b55fcbf97f6204d3c2258db386faGeorge Mount    public void getBounds(Rect bounds, int x, int y, int width, int height) {
99464072a071151b55fcbf97f6204d3c2258db386faGeorge Mount        Matrix.translateM(mTempMatrix, 0, mMatrices, mCurrentMatrixIndex, x, y, 0f);
99564072a071151b55fcbf97f6204d3c2258db386faGeorge Mount        Matrix.scaleM(mTempMatrix, 0, width, height, 1f);
99664072a071151b55fcbf97f6204d3c2258db386faGeorge Mount        Matrix.multiplyMV(mTempMatrix, MATRIX_SIZE, mTempMatrix, 0, BOUNDS_COORDINATES, 0);
99764072a071151b55fcbf97f6204d3c2258db386faGeorge Mount        Matrix.multiplyMV(mTempMatrix, MATRIX_SIZE + 4, mTempMatrix, 0, BOUNDS_COORDINATES, 4);
99864072a071151b55fcbf97f6204d3c2258db386faGeorge Mount        bounds.left = Math.round(mTempMatrix[MATRIX_SIZE]);
99964072a071151b55fcbf97f6204d3c2258db386faGeorge Mount        bounds.right = Math.round(mTempMatrix[MATRIX_SIZE + 4]);
100064072a071151b55fcbf97f6204d3c2258db386faGeorge Mount        bounds.top = Math.round(mTempMatrix[MATRIX_SIZE + 1]);
100164072a071151b55fcbf97f6204d3c2258db386faGeorge Mount        bounds.bottom = Math.round(mTempMatrix[MATRIX_SIZE + 5]);
100264072a071151b55fcbf97f6204d3c2258db386faGeorge Mount        bounds.sort();
100364072a071151b55fcbf97f6204d3c2258db386faGeorge Mount    }
100450b33abe053ccab7be3d1bca2328e792507963d4George Mount
100550b33abe053ccab7be3d1bca2328e792507963d4George Mount    @Override
100650b33abe053ccab7be3d1bca2328e792507963d4George Mount    public GLId getGLId() {
100750b33abe053ccab7be3d1bca2328e792507963d4George Mount        return mGLId;
100850b33abe053ccab7be3d1bca2328e792507963d4George Mount    }
10096eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount}
1010