Project

General

Profile

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

library / src / main / java / org / distorted / library / program / DistortedProgram.java @ 81a0b906

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 194ab46f Leszek Koltunski
import android.opengl.GLES30;
23 432442f9 Leszek Koltunski
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 194ab46f Leszek Koltunski
    int programHandle = GLES30.glCreateProgram();
51 432442f9 Leszek Koltunski
52
    if (programHandle != 0)
53
      {
54 194ab46f Leszek Koltunski
      GLES30.glAttachShader(programHandle, vertexShaderHandle);
55
      GLES30.glAttachShader(programHandle, fragmentShaderHandle);
56 432442f9 Leszek Koltunski
57
      if (attributes != null)
58
        {
59
        final int size = attributes.length;
60
61
        for (int i = 0; i < size; i++)
62
          {
63 194ab46f Leszek Koltunski
          GLES30.glBindAttribLocation(programHandle, i, attributes[i]);
64 432442f9 Leszek Koltunski
          }
65
        }
66
67 194ab46f Leszek Koltunski
      GLES30.glLinkProgram(programHandle);
68 432442f9 Leszek Koltunski
69
      final int[] linkStatus = new int[1];
70 194ab46f Leszek Koltunski
      GLES30.glGetProgramiv(programHandle, GLES30.GL_LINK_STATUS, linkStatus, 0);
71 432442f9 Leszek Koltunski
72 194ab46f Leszek Koltunski
      if (linkStatus[0] != GLES30.GL_TRUE )
73 432442f9 Leszek Koltunski
        {
74 194ab46f Leszek Koltunski
        String error = GLES30.glGetProgramInfoLog(programHandle);
75
        GLES30.glDeleteProgram(programHandle);
76 432442f9 Leszek Koltunski
        throw new LinkingException(error);
77
        }
78
79
      final int[] numberOfUniforms = new int[1];
80 194ab46f Leszek Koltunski
      GLES30.glGetProgramiv(programHandle, GLES30.GL_ACTIVE_UNIFORMS, numberOfUniforms, 0);
81 432442f9 Leszek Koltunski
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 194ab46f Leszek Koltunski
    GLES30.glGetIntegerv(GLES30.GL_MAX_VERTEX_UNIFORM_VECTORS, param, 0);
185 432442f9 Leszek Koltunski
    maxV = param[0];
186 194ab46f Leszek Koltunski
    GLES30.glGetIntegerv(GLES30.GL_MAX_FRAGMENT_UNIFORM_VECTORS, param, 0);
187 432442f9 Leszek Koltunski
    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 194ab46f Leszek Koltunski
    int shaderHandle = GLES30.glCreateShader(shaderType);
214 432442f9 Leszek Koltunski
215
    if (shaderHandle != 0)
216
      {
217 194ab46f Leszek Koltunski
      GLES30.glShaderSource(shaderHandle, shaderSource);
218
      GLES30.glCompileShader(shaderHandle);
219 432442f9 Leszek Koltunski
      final int[] compileStatus = new int[1];
220 194ab46f Leszek Koltunski
      GLES30.glGetShaderiv(shaderHandle, GLES30.GL_COMPILE_STATUS, compileStatus, 0);
221 432442f9 Leszek Koltunski
222 194ab46f Leszek Koltunski
      if (compileStatus[0] != GLES30.GL_TRUE )
223 432442f9 Leszek Koltunski
        {
224 194ab46f Leszek Koltunski
        GLES30.glDeleteShader(shaderHandle);
225 432442f9 Leszek Koltunski
        shaderHandle = 0;
226
        }
227
      }
228
229
    if (shaderHandle == 0)
230
      {
231 194ab46f Leszek Koltunski
      String error = GLES30.glGetShaderInfoLog(shaderHandle);
232 432442f9 Leszek Koltunski
233 81a0b906 leszek
      //android.util.Log.e("Program", "error compiling :"+error);
234
235 432442f9 Leszek Koltunski
      switch(shaderType)
236
        {
237 194ab46f Leszek Koltunski
        case GLES30.GL_VERTEX_SHADER  : throw new VertexCompilationException(error);
238
        case GLES30.GL_FRAGMENT_SHADER: throw new FragmentCompilationException(error);
239 432442f9 Leszek Koltunski
        default                       : throw new RuntimeException(error);
240
        }
241
      }
242
243
    return shaderHandle;
244
    }
245
246
///////////////////////////////////////////////////////////////////////////////////////////////////
247
// PUBLIC API
248
///////////////////////////////////////////////////////////////////////////////////////////////////
249
  /**
250
   * Create a new Shader Program from source stored in resource files.
251
   * <p>
252
   * Needs to be called from a thread holding the OpenGL context.
253
   *
254
   * @param vertex   InputStream containing the opened Resource file from where to read vertex shader code.
255
   * @param fragment InputStream containing the opened Resource file from where to read fragment shader code.
256 3d804c91 Leszek Koltunski
   * @throws FragmentCompilationException
257
   * @throws VertexCompilationException
258
   * @throws VertexUniformsException
259
   * @throws FragmentUniformsException
260
   * @throws LinkingException
261 432442f9 Leszek Koltunski
   */
262
263 47d838ca Leszek Koltunski
  public DistortedProgram(final InputStream vertex, final InputStream fragment, final String vertexHeader, final String fragmentHeader)
264 432442f9 Leszek Koltunski
  throws FragmentCompilationException,VertexCompilationException,VertexUniformsException,FragmentUniformsException,LinkingException
265
    {
266
    mNumAttributes = 0;
267
268
    final String vertexShader   = readTextFileFromRawResource(vertex  , true );
269
    final String fragmentShader = readTextFileFromRawResource(fragment, false);
270
271
    sanitizeMaxValues();
272
273 194ab46f Leszek Koltunski
    final int vertexShaderHandle   = compileShader(GLES30.GL_VERTEX_SHADER  , vertexHeader   + vertexShader  );
274
    final int fragmentShaderHandle = compileShader(GLES30.GL_FRAGMENT_SHADER, fragmentHeader + fragmentShader);
275 432442f9 Leszek Koltunski
276
    mProgramHandle = createAndLinkProgram(vertexShaderHandle, fragmentShaderHandle, mAttributeName);
277
278 02de77c9 Leszek Koltunski
    mAttribute = new int[mNumAttributes];
279 432442f9 Leszek Koltunski
280 02de77c9 Leszek Koltunski
    for(int i=0; i<mNumAttributes; i++)
281
      {
282 194ab46f Leszek Koltunski
      mAttribute[i] = GLES30.glGetAttribLocation( mProgramHandle, mAttributeName[i]);
283 02de77c9 Leszek Koltunski
      }
284 432442f9 Leszek Koltunski
    }
285
286
///////////////////////////////////////////////////////////////////////////////////////////////////
287 3d804c91 Leszek Koltunski
/**
288
 * Return the handle of the created program so that we can later, say, call glUseProgram.
289
 */
290 432442f9 Leszek Koltunski
  public int getProgramHandle()
291
    {
292
    return mProgramHandle;
293
    }
294
295
///////////////////////////////////////////////////////////////////////////////////////////////////
296 3d804c91 Leszek Koltunski
/**
297 02de77c9 Leszek Koltunski
 * Use the program and enable all vertex attribute arrays.
298
 *
299 3d804c91 Leszek Koltunski
 * Needs to be called from a thread holding the OpenGL context.
300
 */
301 02de77c9 Leszek Koltunski
  public void useProgram()
302 432442f9 Leszek Koltunski
    {
303 194ab46f Leszek Koltunski
    GLES30.glUseProgram(mProgramHandle);
304 02de77c9 Leszek Koltunski
305 432442f9 Leszek Koltunski
    for(int i=0; i<mNumAttributes; i++)
306 194ab46f Leszek Koltunski
      GLES30.glEnableVertexAttribArray(mAttribute[i]);
307 432442f9 Leszek Koltunski
    }
308
  }
309 02de77c9 Leszek Koltunski