1227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks/*
2227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * Copyright (C) 2012 The Android Open Source Project
3227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks *
4227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * Licensed under the Apache License, Version 2.0 (the "License");
5227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * you may not use this file except in compliance with the License.
6227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * You may obtain a copy of the License at
7227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks *
8227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks *      http://www.apache.org/licenses/LICENSE-2.0
9227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks *
10227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * Unless required by applicable law or agreed to in writing, software
11227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * distributed under the License is distributed on an "AS IS" BASIS,
12227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * See the License for the specific language governing permissions and
14227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * limitations under the License.
15227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks */
16227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
17227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendrickspackage androidx.media.filterfw;
18227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
19227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricksimport android.graphics.RectF;
20227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricksimport android.opengl.GLES20;
21227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricksimport android.util.Log;
22227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
23227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricksimport androidx.media.filterfw.geometry.Quad;
24227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
25227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricksimport java.nio.ByteBuffer;
26227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricksimport java.nio.ByteOrder;
27227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricksimport java.nio.FloatBuffer;
28227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricksimport java.util.Arrays;
29227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricksimport java.util.HashMap;
30227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
31227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks/**
32227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * Convenience class to perform GL shader operations on image data.
33227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * <p>
34227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * The ImageShader class greatly simplifies the task of running GL shader language kernels over
35227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * Frame data buffers that contain RGBA image data.
36227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * </p><p>
37227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * TODO: More documentation
38227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * </p>
39227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks */
40227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendrickspublic class ImageShader {
41227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
42227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    private int mProgram = 0;
43227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    private boolean mClearsOutput = false;
44227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    private float[] mClearColor = { 0f, 0f, 0f, 0f };
45227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    private boolean mBlendEnabled = false;
46227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    private int mSFactor = GLES20.GL_SRC_ALPHA;
47227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    private int mDFactor = GLES20.GL_ONE_MINUS_SRC_ALPHA;
48227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    private int mDrawMode = GLES20.GL_TRIANGLE_STRIP;
49227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    private int mVertexCount = 4;
50227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    private int mBaseTexUnit = GLES20.GL_TEXTURE0;
51227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    private int mClearBuffers = GLES20.GL_COLOR_BUFFER_BIT;
52227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    private float[] mSourceCoords = new float[] { 0f, 0f, 1f, 0f, 0f, 1f, 1f, 1f };
53227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    private float[] mTargetCoords = new float[] { -1f, -1f, 1f, -1f, -1f, 1f, 1f, 1f };
54227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
55227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    private HashMap<String, ProgramUniform> mUniforms;
56227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    private HashMap<String, VertexAttribute> mAttributes = new HashMap<String, VertexAttribute>();
57227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
58227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    private final static int FLOAT_SIZE = 4;
59227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
60227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    private final static String mDefaultVertexShader =
61227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        "attribute vec4 a_position;\n" +
62227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        "attribute vec2 a_texcoord;\n" +
63227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        "varying vec2 v_texcoord;\n" +
64227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        "void main() {\n" +
65227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        "  gl_Position = a_position;\n" +
66227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        "  v_texcoord = a_texcoord;\n" +
67227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        "}\n";
68227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
69227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    private final static String mIdentityShader =
70227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        "precision mediump float;\n" +
71227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        "uniform sampler2D tex_sampler_0;\n" +
72227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        "varying vec2 v_texcoord;\n" +
73227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        "void main() {\n" +
74227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        "  gl_FragColor = texture2D(tex_sampler_0, v_texcoord);\n" +
75227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        "}\n";
76227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
77227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    private static class VertexAttribute {
78227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        private String mName;
79227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        private boolean mIsConst;
80227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        private int mIndex;
81227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        private boolean mShouldNormalize;
82227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        private int mOffset;
83227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        private int mStride;
84227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        private int mComponents;
85227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        private int mType;
86227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        private int mVbo;
87227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        private int mLength;
88227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        private FloatBuffer mValues;
89227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
90227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        public VertexAttribute(String name, int index) {
91227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            mName = name;
92227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            mIndex = index;
93227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            mLength = -1;
94227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        }
95227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
96227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        public void set(boolean normalize, int stride, int components, int type, float[] values) {
97227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            mIsConst = false;
98227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            mShouldNormalize = normalize;
99227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            mStride = stride;
100227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            mComponents = components;
101227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            mType = type;
102227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            mVbo = 0;
103227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            if (mLength != values.length){
104227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                initBuffer(values);
105227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                mLength = values.length;
106227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            }
107227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            copyValues(values);
108227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        }
109227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
110227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        public void set(boolean normalize, int offset, int stride, int components, int type,
111227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                int vbo){
112227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            mIsConst = false;
113227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            mShouldNormalize = normalize;
114227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            mOffset = offset;
115227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            mStride = stride;
116227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            mComponents = components;
117227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            mType = type;
118227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            mVbo = vbo;
119227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            mValues = null;
120227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        }
121227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
122227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        public boolean push() {
123227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            if (mIsConst) {
124227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                switch (mComponents) {
125227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                    case 1:
126227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                        GLES20.glVertexAttrib1fv(mIndex, mValues);
127227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                        break;
128227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                    case 2:
129227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                        GLES20.glVertexAttrib2fv(mIndex, mValues);
130227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                        break;
131227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                    case 3:
132227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                        GLES20.glVertexAttrib3fv(mIndex, mValues);
133227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                        break;
134227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                    case 4:
135227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                        GLES20.glVertexAttrib4fv(mIndex, mValues);
136227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                        break;
137227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                    default:
138227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                        return false;
139227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                }
140227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                GLES20.glDisableVertexAttribArray(mIndex);
141227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            } else {
142227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                if (mValues != null) {
143227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                    // Note that we cannot do any size checking here, as the correct component
144227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                    // count depends on the drawing step. GL should catch such errors then, and
145227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                    // we will report them to the user.
146227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                    GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0);
147227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                    GLES20.glVertexAttribPointer(mIndex,
148227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                                                 mComponents,
149227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                                                 mType,
150227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                                                 mShouldNormalize,
151227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                                                 mStride,
152227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                                                 mValues);
153227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                } else {
154227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                    GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, mVbo);
155227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                    GLES20.glVertexAttribPointer(mIndex,
156227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                                                 mComponents,
157227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                                                 mType,
158227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                                                 mShouldNormalize,
159227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                                                 mStride,
160227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                                                 mOffset);
161227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                }
162227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                GLES20.glEnableVertexAttribArray(mIndex);
163227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            }
164227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            GLToolbox.checkGlError("Set vertex-attribute values");
165227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            return true;
166227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        }
167227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
168227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        @Override
169227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        public String toString() {
170227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            return mName;
171227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        }
172227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
173227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        private void initBuffer(float[] values) {
174227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            mValues = ByteBuffer.allocateDirect(values.length * FLOAT_SIZE)
175227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                .order(ByteOrder.nativeOrder()).asFloatBuffer();
176227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        }
177227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
178227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        private void copyValues(float[] values) {
179227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            mValues.put(values).position(0);
180227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        }
181227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
182227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
183227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
184227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    private static final class ProgramUniform {
185227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        private String mName;
186227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        private int mLocation;
187227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        private int mType;
188227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        private int mSize;
189227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
190227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        public ProgramUniform(int program, int index) {
191227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            int[] len = new int[1];
192227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            GLES20.glGetProgramiv(program, GLES20.GL_ACTIVE_UNIFORM_MAX_LENGTH, len, 0);
193227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
194227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            int[] type = new int[1];
195227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            int[] size = new int[1];
196227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            byte[] name = new byte[len[0]];
197227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            int[] ignore = new int[1];
198227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
199227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            GLES20.glGetActiveUniform(program, index, len[0], ignore, 0, size, 0, type, 0, name, 0);
200227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            mName = new String(name, 0, strlen(name));
201227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            mLocation = GLES20.glGetUniformLocation(program, mName);
202227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            mType = type[0];
203227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            mSize = size[0];
204227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            GLToolbox.checkGlError("Initializing uniform");
205227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        }
206227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
207227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        public String getName() {
208227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            return mName;
209227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        }
210227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
211227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        public int getType() {
212227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            return mType;
213227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        }
214227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
215227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        public int getLocation() {
216227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            return mLocation;
217227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        }
218227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
219227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        public int getSize() {
220227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            return mSize;
221227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        }
222227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
223227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
224227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    public ImageShader(String fragmentShader) {
225227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        mProgram = createProgram(mDefaultVertexShader, fragmentShader);
226227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        scanUniforms();
227227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
228227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
229227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    public ImageShader(String vertexShader, String fragmentShader) {
230227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        mProgram = createProgram(vertexShader, fragmentShader);
231227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        scanUniforms();
232227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
233227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
234227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    public static ImageShader createIdentity() {
235227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        return new ImageShader(mIdentityShader);
236227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
237227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
238227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    public static ImageShader createIdentity(String vertexShader) {
239227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        return new ImageShader(vertexShader, mIdentityShader);
240227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
241227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
242227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    public static void renderTextureToTarget(TextureSource texture,
243227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                                             RenderTarget target,
244227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                                             int width,
245227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                                             int height) {
246227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        ImageShader shader = RenderTarget.currentTarget().getIdentityShader();
247227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        shader.process(texture, target, width, height);
248227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
249227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
250227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    public void process(FrameImage2D input, FrameImage2D output) {
251227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        TextureSource texSource = input.lockTextureSource();
252227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        RenderTarget renderTarget = output.lockRenderTarget();
253227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        processMulti(new TextureSource[] { texSource },
254227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                     renderTarget,
255227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                     output.getWidth(),
256227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                     output.getHeight());
257227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        input.unlock();
258227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        output.unlock();
259227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
260227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
261227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    public void processMulti(FrameImage2D[] inputs, FrameImage2D output) {
262227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        TextureSource[] texSources = new TextureSource[inputs.length];
263227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        for (int i = 0; i < inputs.length; ++i) {
264227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            texSources[i] = inputs[i].lockTextureSource();
265227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        }
266227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        RenderTarget renderTarget = output.lockRenderTarget();
267227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        processMulti(texSources,
268227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                     renderTarget,
269227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                     output.getWidth(),
270227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                     output.getHeight());
271227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        for (FrameImage2D input : inputs) {
272227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            input.unlock();
273227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        }
274227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        output.unlock();
275227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
276227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
277227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    public void process(TextureSource texture, RenderTarget target, int width, int height) {
278227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        processMulti(new TextureSource[] { texture }, target, width, height);
279227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
280227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
281227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    public void processMulti(TextureSource[] sources, RenderTarget target, int width, int height) {
282227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        GLToolbox.checkGlError("Unknown Operation");
283227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        checkExecutable();
284227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        checkTexCount(sources.length);
285227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        focusTarget(target, width, height);
286227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        pushShaderState();
287227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        bindInputTextures(sources);
288227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        render();
289227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
290227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
291227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    public void processNoInput(FrameImage2D output) {
292227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        RenderTarget renderTarget = output.lockRenderTarget();
293227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        processNoInput(renderTarget, output.getWidth(), output.getHeight());
294227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        output.unlock();
295227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
296227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
297227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    public void processNoInput(RenderTarget target, int width, int height) {
298227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        processMulti(new TextureSource[] {}, target, width, height);
299227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
300227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
301227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    public int getUniformLocation(String name) {
302227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        return getProgramUniform(name, true).getLocation();
303227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
304227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
305227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    public int getAttributeLocation(String name) {
306227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        if (name.equals(positionAttributeName()) || name.equals(texCoordAttributeName())) {
307227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            Log.w("ImageShader", "Attempting to access internal attribute '" + name
308227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                + "' directly!");
309227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        }
310227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        int loc = GLES20.glGetAttribLocation(mProgram, name);
311227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        if (loc < 0) {
312227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            throw new RuntimeException("Unknown attribute '" + name + "' in shader program!");
313227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        }
314227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        return loc;
315227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
316227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
317227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    public void setUniformValue(String uniformName, int value) {
318227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        useProgram();
319227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        int uniformHandle = getUniformLocation(uniformName);
320227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        GLES20.glUniform1i(uniformHandle, value);
321227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        GLToolbox.checkGlError("Set uniform value (" + uniformName + ")");
322227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
323227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
324227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    public void setUniformValue(String uniformName, float value) {
325227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        useProgram();
326227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        int uniformHandle = getUniformLocation(uniformName);
327227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        GLES20.glUniform1f(uniformHandle, value);
328227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        GLToolbox.checkGlError("Set uniform value (" + uniformName + ")");
329227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
330227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
331227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    public void setUniformValue(String uniformName, int[] values) {
332227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        ProgramUniform uniform = getProgramUniform(uniformName, true);
333227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        useProgram();
334227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        int len = values.length;
335227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        switch (uniform.getType()) {
336227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            case GLES20.GL_INT:
337227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                checkUniformAssignment(uniform, len, 1);
338227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                GLES20.glUniform1iv(uniform.getLocation(), len, values, 0);
339227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                break;
340227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            case GLES20.GL_INT_VEC2:
341227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                checkUniformAssignment(uniform, len, 2);
342227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                GLES20.glUniform2iv(uniform.getLocation(), len / 2, values, 0);
343227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                break;
344227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            case GLES20.GL_INT_VEC3:
345227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                checkUniformAssignment(uniform, len, 3);
346227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                GLES20.glUniform2iv(uniform.getLocation(), len / 3, values, 0);
347227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                break;
348227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            case GLES20.GL_INT_VEC4:
349227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                checkUniformAssignment(uniform, len, 4);
350227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                GLES20.glUniform2iv(uniform.getLocation(), len / 4, values, 0);
351227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                break;
352227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            default:
353227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                throw new RuntimeException("Cannot assign int-array to incompatible uniform type "
354227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                    + "for uniform '" + uniformName + "'!");
355227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        }
356227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        GLToolbox.checkGlError("Set uniform value (" + uniformName + ")");
357227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
358227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
359227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
360227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    public void setUniformValue(String uniformName, float[] values) {
361227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        ProgramUniform uniform = getProgramUniform(uniformName, true);
362227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        useProgram();
363227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        int len = values.length;
364227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        switch (uniform.getType()) {
365227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            case GLES20.GL_FLOAT:
366227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                checkUniformAssignment(uniform, len, 1);
367227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                GLES20.glUniform1fv(uniform.getLocation(), len, values, 0);
368227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                break;
369227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            case GLES20.GL_FLOAT_VEC2:
370227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                checkUniformAssignment(uniform, len, 2);
371227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                GLES20.glUniform2fv(uniform.getLocation(), len / 2, values, 0);
372227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                break;
373227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            case GLES20.GL_FLOAT_VEC3:
374227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                checkUniformAssignment(uniform, len, 3);
375227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                GLES20.glUniform3fv(uniform.getLocation(), len / 3, values, 0);
376227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                break;
377227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            case GLES20.GL_FLOAT_VEC4:
378227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                checkUniformAssignment(uniform, len, 4);
379227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                GLES20.glUniform4fv(uniform.getLocation(), len / 4, values, 0);
380227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                break;
381227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            case GLES20.GL_FLOAT_MAT2:
382227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                checkUniformAssignment(uniform, len, 4);
383227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                GLES20.glUniformMatrix2fv(uniform.getLocation(), len / 4, false, values, 0);
384227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                break;
385227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            case GLES20.GL_FLOAT_MAT3:
386227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                checkUniformAssignment(uniform, len, 9);
387227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                GLES20.glUniformMatrix3fv(uniform.getLocation(), len / 9, false, values, 0);
388227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                break;
389227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            case GLES20.GL_FLOAT_MAT4:
390227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                checkUniformAssignment(uniform, len, 16);
391227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                GLES20.glUniformMatrix4fv(uniform.getLocation(), len / 16, false, values, 0);
392227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                break;
393227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            default:
394227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                throw new RuntimeException("Cannot assign float-array to incompatible uniform type "
395227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                    + "for uniform '" + uniformName + "'!");
396227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        }
397227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        GLToolbox.checkGlError("Set uniform value (" + uniformName + ")");
398227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
399227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
400227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    public void setAttributeValues(String attributeName, float[] data, int components) {
401227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        VertexAttribute attr = getProgramAttribute(attributeName, true);
402227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        attr.set(false, FLOAT_SIZE * components, components, GLES20.GL_FLOAT, data);
403227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
404227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
405227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    public void setAttributeValues(String attributeName, int vbo, int type, int components,
406227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                                   int stride, int offset, boolean normalize) {
407227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        VertexAttribute attr = getProgramAttribute(attributeName, true);
408227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        attr.set(normalize, offset, stride, components, type, vbo);
409227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
410227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
411227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    public void setSourceRect(float x, float y, float width, float height) {
412227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        setSourceCoords(new float[] { x, y, x + width, y, x, y + height, x + width, y + height });
413227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
414227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
415227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    public void setSourceRect(RectF rect) {
416227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        setSourceRect(rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top);
417227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
418227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
419227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    public void setSourceQuad(Quad quad) {
420227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        setSourceCoords(new float[] { quad.topLeft().x,     quad.topLeft().y,
421227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                                      quad.topRight().x,    quad.topRight().y,
422227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                                      quad.bottomLeft().x,  quad.bottomLeft().y,
423227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                                      quad.bottomRight().x, quad.bottomRight().y });
424227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
425227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
426227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    public void setSourceCoords(float[] coords) {
427227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        if (coords.length != 8) {
428227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            throw new IllegalArgumentException("Expected 8 coordinates as source coordinates but "
429227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                + "got " + coords.length + " coordinates!");
430227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        }
431227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        mSourceCoords = Arrays.copyOf(coords, 8);
432227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
433227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
434227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    public void setSourceTransform(float[] matrix) {
435227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        if (matrix.length != 16) {
436227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            throw new IllegalArgumentException("Expected 4x4 matrix for source transform!");
437227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        }
438227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        setSourceCoords(new float[] {
439227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            matrix[12],
440227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            matrix[13],
441227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
442227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            matrix[0] + matrix[12],
443227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            matrix[1] + matrix[13],
444227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
445227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            matrix[4] + matrix[12],
446227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            matrix[5] + matrix[13],
447227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
448227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            matrix[0] + matrix[4] + matrix[12],
449227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            matrix[1] + matrix[5] + matrix[13],
450227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        });
451227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
452227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
453227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    public void setTargetRect(float x, float y, float width, float height) {
454227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        setTargetCoords(new float[] { x, y,
455227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                                      x + width, y,
456227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                                      x, y + height,
457227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                                      x + width, y + height });
458227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
459227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
460227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    public void setTargetRect(RectF rect) {
461227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        setTargetCoords(new float[] { rect.left,    rect.top,
462227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                                      rect.right,   rect.top,
463227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                                      rect.left,    rect.bottom,
464227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                                      rect.right,   rect.bottom });
465227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
466227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
467227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    public void setTargetQuad(Quad quad) {
468227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        setTargetCoords(new float[] { quad.topLeft().x,     quad.topLeft().y,
469227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                                      quad.topRight().x,    quad.topRight().y,
470227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                                      quad.bottomLeft().x,  quad.bottomLeft().y,
471227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                                      quad.bottomRight().x, quad.bottomRight().y });
472227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
473227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
474227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    public void setTargetCoords(float[] coords) {
475227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        if (coords.length != 8) {
476227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            throw new IllegalArgumentException("Expected 8 coordinates as target coordinates but "
477227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                + "got " + coords.length + " coordinates!");
478227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        }
479227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        mTargetCoords = new float[8];
480227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        for (int i = 0; i < 8; ++i) {
481227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            mTargetCoords[i] = coords[i] * 2f - 1f;
482227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        }
483227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
484227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
485227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    public void setTargetTransform(float[] matrix) {
486227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        if (matrix.length != 16) {
487227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            throw new IllegalArgumentException("Expected 4x4 matrix for target transform!");
488227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        }
489227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        setTargetCoords(new float[] {
490227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            matrix[12],
491227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            matrix[13],
492227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
493227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            matrix[0] + matrix[12],
494227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            matrix[1] + matrix[13],
495227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
496227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            matrix[4] + matrix[12],
497227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            matrix[5] + matrix[13],
498227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
499227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            matrix[0] + matrix[4] + matrix[12],
500227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            matrix[1] + matrix[5] + matrix[13],
501227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        });
502227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
503227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
504227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    public void setClearsOutput(boolean clears) {
505227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        mClearsOutput = clears;
506227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
507227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
508227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    public boolean getClearsOutput() {
509227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        return mClearsOutput;
510227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
511227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
512227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    public void setClearColor(float[] rgba) {
513227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        mClearColor = rgba;
514227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
515227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
516227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    public float[] getClearColor() {
517227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        return mClearColor;
518227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
519227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
520227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    public void setClearBufferMask(int bufferMask) {
521227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        mClearBuffers = bufferMask;
522227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
523227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
524227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    public int getClearBufferMask() {
525227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        return mClearBuffers;
526227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
527227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
528227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    public void setBlendEnabled(boolean enable) {
529227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        mBlendEnabled = enable;
530227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
531227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
532227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    public boolean getBlendEnabled() {
533227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        return mBlendEnabled;
534227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
535227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
536227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    public void setBlendFunc(int sFactor, int dFactor) {
537227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        mSFactor = sFactor;
538227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        mDFactor = dFactor;
539227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
540227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
541227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    public void setDrawMode(int drawMode) {
542227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        mDrawMode = drawMode;
543227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
544227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
545227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    public int getDrawMode() {
546227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        return mDrawMode;
547227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
548227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
549227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    public void setVertexCount(int count) {
550227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        mVertexCount = count;
551227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
552227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
553227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    public int getVertexCount() {
554227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        return mVertexCount;
555227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
556227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
557227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    public void setBaseTextureUnit(int baseTexUnit) {
558227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        mBaseTexUnit = baseTexUnit;
559227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
560227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
561227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    public int baseTextureUnit() {
562227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        return mBaseTexUnit;
563227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
564227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
565227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    public String texCoordAttributeName() {
566227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        return "a_texcoord";
567227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
568227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
569227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    public String positionAttributeName() {
570227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        return "a_position";
571227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
572227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
573227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    public String inputTextureUniformName(int index) {
574227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        return "tex_sampler_" + index;
575227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
576227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
577227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    public static int maxTextureUnits() {
578227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        return GLES20.GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS;
579227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
580227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
581227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    @Override
582227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    protected void finalize() throws Throwable {
583227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        GLES20.glDeleteProgram(mProgram);
584227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
585227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
586227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    protected void pushShaderState() {
587227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        useProgram();
588227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        updateSourceCoordAttribute();
589227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        updateTargetCoordAttribute();
590227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        pushAttributes();
591227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        if (mClearsOutput) {
592227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            GLES20.glClearColor(mClearColor[0], mClearColor[1], mClearColor[2], mClearColor[3]);
593227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            GLES20.glClear(mClearBuffers);
594227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        }
595227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        if (mBlendEnabled) {
596227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            GLES20.glEnable(GLES20.GL_BLEND);
597227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            GLES20.glBlendFunc(mSFactor, mDFactor);
598227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        } else {
599227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            GLES20.glDisable(GLES20.GL_BLEND);
600227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        }
601227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        GLToolbox.checkGlError("Set render variables");
602227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
603227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
604227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    private void focusTarget(RenderTarget target, int width, int height) {
605227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        target.focus();
606227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        GLES20.glViewport(0, 0, width, height);
607227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        GLToolbox.checkGlError("glViewport");
608227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
609227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
610227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    private void bindInputTextures(TextureSource[] sources) {
611227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        for (int i = 0; i < sources.length; ++i) {
612227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            // Activate texture unit i
613227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            GLES20.glActiveTexture(baseTextureUnit() + i);
614227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
615227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            // Bind texture
616227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            sources[i].bind();
617227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
618227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            // Assign the texture uniform in the shader to unit i
619227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            int texUniform = GLES20.glGetUniformLocation(mProgram, inputTextureUniformName(i));
620227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            if (texUniform >= 0) {
621227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                GLES20.glUniform1i(texUniform, i);
622227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            } else {
623227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                throw new RuntimeException("Shader does not seem to support " + sources.length
624227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                    + " number of input textures! Missing uniform " + inputTextureUniformName(i)
625227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                    + "!");
626227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            }
627227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            GLToolbox.checkGlError("Binding input texture " + i);
628227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        }
629227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
630227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
631227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    private void pushAttributes() {
632227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        for (VertexAttribute attr : mAttributes.values()) {
633227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            if (!attr.push()) {
634227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                throw new RuntimeException("Unable to assign attribute value '" + attr + "'!");
635227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            }
636227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        }
637227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        GLToolbox.checkGlError("Push Attributes");
638227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
639227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
640227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    private void updateSourceCoordAttribute() {
641227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        // If attribute does not exist, simply do nothing (may be custom shader).
642227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        VertexAttribute attr = getProgramAttribute(texCoordAttributeName(), false);
643227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        // A non-null value of mSourceCoords indicates new values to be set.
644227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        if (mSourceCoords != null && attr != null) {
645227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            // Upload new source coordinates to GPU
646227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            attr.set(false, FLOAT_SIZE * 2, 2, GLES20.GL_FLOAT, mSourceCoords);
647227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        }
648227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        // Do not set again (even if failed, to not cause endless attempts)
649227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        mSourceCoords = null;
650227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
651227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
652227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    private void updateTargetCoordAttribute() {
653227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        // If attribute does not exist, simply do nothing (may be custom shader).
654227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        VertexAttribute attr = getProgramAttribute(positionAttributeName(), false);
655227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        // A non-null value of mTargetCoords indicates new values to be set.
656227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        if (mTargetCoords != null && attr != null) {
657227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            // Upload new target coordinates to GPU
658227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            attr.set(false, FLOAT_SIZE * 2, 2, GLES20.GL_FLOAT, mTargetCoords);
659227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        }
660227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        // Do not set again (even if failed, to not cause endless attempts)
661227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        mTargetCoords = null;
662227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
663227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
664227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    private void render() {
665227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        GLES20.glDrawArrays(mDrawMode, 0, mVertexCount);
666227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        GLToolbox.checkGlError("glDrawArrays");
667227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
668227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
669227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    private void checkExecutable() {
670227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        if (mProgram == 0) {
671227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            throw new RuntimeException("Attempting to execute invalid shader-program!");
672227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        }
673227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
674227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
675227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    private void useProgram() {
676227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        GLES20.glUseProgram(mProgram);
677227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        GLToolbox.checkGlError("glUseProgram");
678227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
679227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
680227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    private static void checkTexCount(int count) {
681227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        if (count > maxTextureUnits()) {
682227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            throw new RuntimeException("Number of textures passed (" + count + ") exceeds the "
683227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                + "maximum number of allowed texture units (" + maxTextureUnits() + ")!");
684227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        }
685227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
686227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
687227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    private static int loadShader(int shaderType, String source) {
688227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        int shader = GLES20.glCreateShader(shaderType);
689227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        if (shader != 0) {
690227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            GLES20.glShaderSource(shader, source);
691227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            GLES20.glCompileShader(shader);
692227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            int[] compiled = new int[1];
693227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            GLES20.glGetShaderiv(shader, GLES20.GL_COMPILE_STATUS, compiled, 0);
694227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            if (compiled[0] == 0) {
695227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                String info = GLES20.glGetShaderInfoLog(shader);
696227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                GLES20.glDeleteShader(shader);
697227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                shader = 0;
698227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                throw new RuntimeException("Could not compile shader " + shaderType + ":" + info);
699227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            }
700227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        }
701227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        return shader;
702227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
703227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
704227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    private static int createProgram(String vertexSource, String fragmentSource) {
705227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        int vertexShader = loadShader(GLES20.GL_VERTEX_SHADER, vertexSource);
706227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        if (vertexShader == 0) {
707227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            throw new RuntimeException("Could not create shader-program as vertex shader "
708227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                + "could not be compiled!");
709227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        }
710227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        int pixelShader = loadShader(GLES20.GL_FRAGMENT_SHADER, fragmentSource);
711227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        if (pixelShader == 0) {
712227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            throw new RuntimeException("Could not create shader-program as fragment shader "
713227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                + "could not be compiled!");
714227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        }
715227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
716227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        int program = GLES20.glCreateProgram();
717227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        if (program != 0) {
718227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            GLES20.glAttachShader(program, vertexShader);
719227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            GLToolbox.checkGlError("glAttachShader");
720227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            GLES20.glAttachShader(program, pixelShader);
721227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            GLToolbox.checkGlError("glAttachShader");
722227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            GLES20.glLinkProgram(program);
723227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            int[] linkStatus = new int[1];
724227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            GLES20.glGetProgramiv(program, GLES20.GL_LINK_STATUS, linkStatus, 0);
725227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            if (linkStatus[0] != GLES20.GL_TRUE) {
726227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                String info = GLES20.glGetProgramInfoLog(program);
727227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                GLES20.glDeleteProgram(program);
728227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                program = 0;
729227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                throw new RuntimeException("Could not link program: " + info);
730227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            }
731227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        }
732227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
733227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        GLES20.glDeleteShader(vertexShader);
734227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        GLES20.glDeleteShader(pixelShader);
735227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
736227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        return program;
737227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
738227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
739227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    private void scanUniforms() {
740227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        int uniformCount[] = new int [1];
741227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        GLES20.glGetProgramiv(mProgram, GLES20.GL_ACTIVE_UNIFORMS, uniformCount, 0);
742227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        if (uniformCount[0] > 0) {
743227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            mUniforms = new HashMap<String, ProgramUniform>(uniformCount[0]);
744227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            for (int i = 0; i < uniformCount[0]; ++i) {
745227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                ProgramUniform uniform = new ProgramUniform(mProgram, i);
746227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                mUniforms.put(uniform.getName(), uniform);
747227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            }
748227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        }
749227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
750227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
751227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    private ProgramUniform getProgramUniform(String name, boolean required) {
752227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        ProgramUniform result = mUniforms.get(name);
753227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        if (result == null && required) {
754227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            throw new IllegalArgumentException("Unknown uniform '" + name + "'!");
755227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        }
756227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        return result;
757227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
758227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
759227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    private VertexAttribute getProgramAttribute(String name, boolean required) {
760227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        VertexAttribute result = mAttributes.get(name);
761227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        if (result == null) {
762227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            int handle = GLES20.glGetAttribLocation(mProgram, name);
763227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            if (handle >= 0) {
764227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                result = new VertexAttribute(name, handle);
765227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                mAttributes.put(name, result);
766227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            } else if (required) {
767227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                throw new IllegalArgumentException("Unknown attribute '" + name + "'!");
768227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            }
769227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        }
770227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        return result;
771227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
772227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
773227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    private void checkUniformAssignment(ProgramUniform uniform, int values, int components) {
774227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        if (values % components != 0) {
775227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            throw new RuntimeException("Size mismatch: Attempting to assign values of size "
776227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                + values + " to uniform '" + uniform.getName() + "' (must be multiple of "
777227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                + components + ")!");
778227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        } else if (uniform.getSize() != values / components) {
779227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            throw new RuntimeException("Size mismatch: Cannot assign " + values + " values to "
780227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                + "uniform '" + uniform.getName() + "'!");
781227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        }
782227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
783227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
784227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    private static int strlen(byte[] strVal) {
785227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        for (int i = 0; i < strVal.length; ++i) {
786227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            if (strVal[i] == '\0') {
787227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                return i;
788227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            }
789227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        }
790227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        return strVal.length;
791227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
792227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks}
793227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
794