Project

General

Profile

Download (10.7 KB) Statistics
| Branch: | Revision:

library / src / main / java / org / distorted / library / program / DistortedProgram.java @ 02de77c9

1 432442f9 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
2
// Copyright 2016 Leszek Koltunski                                                               //
3
//                                                                                               //
4
// This file is part of Distorted.                                                               //
5
//                                                                                               //
6
// Distorted is free software: you can redistribute it and/or modify                             //
7
// it under the terms of the GNU General Public License as published by                          //
8
// the Free Software Foundation, either version 2 of the License, or                             //
9
// (at your option) any later version.                                                           //
10
//                                                                                               //
11
// Distorted is distributed in the hope that it will be useful,                                  //
12
// but WITHOUT ANY WARRANTY; without even the implied warranty of                                //
13
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the                                 //
14
// GNU General Public License for more details.                                                  //
15
//                                                                                               //
16
// You should have received a copy of the GNU General Public License                             //
17
// along with Distorted.  If not, see <http://www.gnu.org/licenses/>.                            //
18
///////////////////////////////////////////////////////////////////////////////////////////////////
19
20
package org.distorted.library.program;
21
22
import android.opengl.GLES20;
23
import android.os.Build;
24
25
import org.distorted.library.DistortedEffects;
26
27
import java.io.BufferedReader;
28
import java.io.IOException;
29
import java.io.InputStream;
30
import java.io.InputStreamReader;
31
32
///////////////////////////////////////////////////////////////////////////////////////////////////
33
/**
34
 * An object which encapsulates a vertex/fragment shader combo, aka Shader Program.
35
 */
36
public class DistortedProgram
37
  {
38
  private int mProgramHandle;
39
40
  private int mNumAttributes;
41
  private String[] mAttributeName;
42
43 02de77c9 Leszek Koltunski
  public final int[] mAttribute;
44
45 432442f9 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
46
47
  private int createAndLinkProgram(final int vertexShaderHandle, final int fragmentShaderHandle, final String[] attributes)
48
  throws LinkingException
49
    {
50
    int programHandle = GLES20.glCreateProgram();
51
52
    if (programHandle != 0)
53
      {
54
      GLES20.glAttachShader(programHandle, vertexShaderHandle);
55
      GLES20.glAttachShader(programHandle, fragmentShaderHandle);
56
57
      if (attributes != null)
58
        {
59
        final int size = attributes.length;
60
61
        for (int i = 0; i < size; i++)
62
          {
63
          GLES20.glBindAttribLocation(programHandle, i, attributes[i]);
64
          }
65
        }
66
67
      GLES20.glLinkProgram(programHandle);
68
69
      final int[] linkStatus = new int[1];
70
      GLES20.glGetProgramiv(programHandle, GLES20.GL_LINK_STATUS, linkStatus, 0);
71
72
      if (linkStatus[0] != GLES20.GL_TRUE )
73
        {
74
        String error = GLES20.glGetProgramInfoLog(programHandle);
75
        GLES20.glDeleteProgram(programHandle);
76
        throw new LinkingException(error);
77
        }
78
79
      final int[] numberOfUniforms = new int[1];
80
      GLES20.glGetProgramiv(programHandle, GLES20.GL_ACTIVE_UNIFORMS, numberOfUniforms, 0);
81
82
      //android.util.Log.d("program", "number of active uniforms="+numberOfUniforms[0]);
83
      }
84
85
    return programHandle;
86
    }
87
88
///////////////////////////////////////////////////////////////////////////////////////////////////
89
90 3d804c91 Leszek Koltunski
  private String parseOutAttribute(final String line)
91 432442f9 Leszek Koltunski
    {
92
    int len = line.length();
93
    int whiteSpace, semicolon, nameBegin;
94
    char currChar;
95
96
    for(whiteSpace=0; whiteSpace<len; whiteSpace++)
97
      {
98
      currChar = line.charAt(whiteSpace);
99
      if( currChar!=' ' && currChar!='\t') break;
100
      }
101
102
    for(semicolon=whiteSpace; semicolon<len; semicolon++)
103
      {
104
      currChar = line.charAt(semicolon);
105
      if( currChar==';') break;
106
      }
107
108
    if( semicolon<len && semicolon-whiteSpace>=11 )   // "attribute a;" --> 11
109
      {
110
      String subline = line.substring(whiteSpace,semicolon);
111
      int subLen = semicolon-whiteSpace;
112
113
      if( subline.startsWith("attribute"))
114
        {
115
        //android.util.Log.e("program", "GOOD LINE: " +subline+" subLen="+subLen);
116
117
        for(nameBegin=subLen-1; nameBegin>8; nameBegin--)
118
          {
119
          currChar=subline.charAt(nameBegin);
120
121
          if( currChar==' ' || currChar=='\t' )
122
            {
123
            mNumAttributes++;
124 3d804c91 Leszek Koltunski
            return subline.substring(nameBegin+1,subLen);
125 432442f9 Leszek Koltunski
            }
126
          }
127
        }
128
      }
129 3d804c91 Leszek Koltunski
130
    return null;
131 432442f9 Leszek Koltunski
    }
132
133
///////////////////////////////////////////////////////////////////////////////////////////////////
134
135
  private String readTextFileFromRawResource(final InputStream inputStream, boolean doAttributes)
136
    {
137
    final InputStreamReader inputStreamReader = new InputStreamReader(inputStream);
138
    final BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
139
140 3d804c91 Leszek Koltunski
    String nextLine, attribute, attrList="";
141 432442f9 Leszek Koltunski
    final StringBuilder body = new StringBuilder();
142
143
    try
144
      {
145
      while ((nextLine = bufferedReader.readLine()) != null)
146
        {
147
        body.append(nextLine);
148
        body.append('\n');
149
150 3d804c91 Leszek Koltunski
        if( doAttributes )
151
          {
152
          attribute = parseOutAttribute(nextLine);
153
154
          if( attribute!=null )
155
            {
156
            //android.util.Log.d("program", "new attribute: "+attribute);
157
            if( attrList.length()>0 ) attrList+=" ";
158
            attrList += attribute;
159
            }
160
          }
161 432442f9 Leszek Koltunski
        }
162
      }
163
    catch (IOException e)
164
      {
165
      return null;
166
      }
167
168
    if( doAttributes )
169
      {
170 3d804c91 Leszek Koltunski
      mAttributeName = attrList.split(" ");
171 432442f9 Leszek Koltunski
      }
172
173
    return body.toString();
174
    }
175
176
///////////////////////////////////////////////////////////////////////////////////////////////////
177
178
  private static void sanitizeMaxValues()
179
  throws VertexUniformsException,FragmentUniformsException
180
    {
181
    int maxV,maxF;
182
    int[] param = new int[1];
183
184
    GLES20.glGetIntegerv(GLES20.GL_MAX_VERTEX_UNIFORM_VECTORS, param, 0);
185
    maxV = param[0];
186
    GLES20.glGetIntegerv(GLES20.GL_MAX_FRAGMENT_UNIFORM_VECTORS, param, 0);
187
    maxF = param[0];
188
189
    //Log.d("program", "Max vectors in vertex shader: "+maxV);
190
    //Log.d("program", "Max vectors in fragment shader: "+maxF);
191
192
    if( !Build.FINGERPRINT.contains("generic") )
193
      {
194
      int realMaxV = (maxV-11)/4;   // adjust this in case of changes to the shaders...
195
      int realMaxF = (maxF- 2)/4;   //
196
197
      if( DistortedEffects.getMaxVertex()   > realMaxV )
198
        {
199
        throw new VertexUniformsException("Too many effects in the vertex shader, max is "+realMaxV, realMaxV);
200
        }
201
      if( DistortedEffects.getMaxFragment() > realMaxF )
202
        {
203
        throw new FragmentUniformsException("Too many effects in the fragment shader, max is "+realMaxF, realMaxF);
204
        }
205
      }
206
    }
207
208
///////////////////////////////////////////////////////////////////////////////////////////////////
209
210
  private static int compileShader(final int shaderType, final String shaderSource)
211
  throws FragmentCompilationException,VertexCompilationException
212
    {
213
    int shaderHandle = GLES20.glCreateShader(shaderType);
214
215
    if (shaderHandle != 0)
216
      {
217 47d838ca Leszek Koltunski
      GLES20.glShaderSource(shaderHandle, shaderSource);
218 432442f9 Leszek Koltunski
      GLES20.glCompileShader(shaderHandle);
219
      final int[] compileStatus = new int[1];
220
      GLES20.glGetShaderiv(shaderHandle, GLES20.GL_COMPILE_STATUS, compileStatus, 0);
221
222
      if (compileStatus[0] != GLES20.GL_TRUE )
223
        {
224
        GLES20.glDeleteShader(shaderHandle);
225
        shaderHandle = 0;
226
        }
227
      }
228
229
    if (shaderHandle == 0)
230
      {
231
      String error = GLES20.glGetShaderInfoLog(shaderHandle);
232
233
      switch(shaderType)
234
        {
235
        case GLES20.GL_VERTEX_SHADER  : throw new VertexCompilationException(error);
236
        case GLES20.GL_FRAGMENT_SHADER: throw new FragmentCompilationException(error);
237
        default                       : throw new RuntimeException(error);
238
        }
239
      }
240
241
    return shaderHandle;
242
    }
243
244
///////////////////////////////////////////////////////////////////////////////////////////////////
245
// PUBLIC API
246
///////////////////////////////////////////////////////////////////////////////////////////////////
247
  /**
248
   * Create a new Shader Program from source stored in resource files.
249
   * <p>
250
   * Needs to be called from a thread holding the OpenGL context.
251
   *
252
   * @param vertex   InputStream containing the opened Resource file from where to read vertex shader code.
253
   * @param fragment InputStream containing the opened Resource file from where to read fragment shader code.
254 3d804c91 Leszek Koltunski
   * @throws FragmentCompilationException
255
   * @throws VertexCompilationException
256
   * @throws VertexUniformsException
257
   * @throws FragmentUniformsException
258
   * @throws LinkingException
259 432442f9 Leszek Koltunski
   */
260
261 47d838ca Leszek Koltunski
  public DistortedProgram(final InputStream vertex, final InputStream fragment, final String vertexHeader, final String fragmentHeader)
262 432442f9 Leszek Koltunski
  throws FragmentCompilationException,VertexCompilationException,VertexUniformsException,FragmentUniformsException,LinkingException
263
    {
264
    mNumAttributes = 0;
265
266
    final String vertexShader   = readTextFileFromRawResource(vertex  , true );
267
    final String fragmentShader = readTextFileFromRawResource(fragment, false);
268
269
    sanitizeMaxValues();
270
271 47d838ca Leszek Koltunski
    final int vertexShaderHandle   = compileShader(GLES20.GL_VERTEX_SHADER  , vertexHeader   + vertexShader  );
272
    final int fragmentShaderHandle = compileShader(GLES20.GL_FRAGMENT_SHADER, fragmentHeader + fragmentShader);
273 432442f9 Leszek Koltunski
274
    mProgramHandle = createAndLinkProgram(vertexShaderHandle, fragmentShaderHandle, mAttributeName);
275
276 02de77c9 Leszek Koltunski
    mAttribute = new int[mNumAttributes];
277 432442f9 Leszek Koltunski
278 02de77c9 Leszek Koltunski
    for(int i=0; i<mNumAttributes; i++)
279
      {
280
      mAttribute[i] = GLES20.glGetAttribLocation( mProgramHandle, mAttributeName[i]);
281
      }
282 432442f9 Leszek Koltunski
    }
283
284
///////////////////////////////////////////////////////////////////////////////////////////////////
285 3d804c91 Leszek Koltunski
/**
286
 * Return the handle of the created program so that we can later, say, call glUseProgram.
287
 */
288 432442f9 Leszek Koltunski
  public int getProgramHandle()
289
    {
290
    return mProgramHandle;
291
    }
292
293
///////////////////////////////////////////////////////////////////////////////////////////////////
294 3d804c91 Leszek Koltunski
/**
295 02de77c9 Leszek Koltunski
 * Use the program and enable all vertex attribute arrays.
296
 *
297 3d804c91 Leszek Koltunski
 * Needs to be called from a thread holding the OpenGL context.
298
 */
299 02de77c9 Leszek Koltunski
  public void useProgram()
300 432442f9 Leszek Koltunski
    {
301 02de77c9 Leszek Koltunski
    GLES20.glUseProgram(mProgramHandle);
302
303 432442f9 Leszek Koltunski
    for(int i=0; i<mNumAttributes; i++)
304
      GLES20.glEnableVertexAttribArray(mAttribute[i]);
305
    }
306
  }
307 02de77c9 Leszek Koltunski