Project

General

Profile

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

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

1
///////////////////////////////////////////////////////////////////////////////////////////////////
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
  public final int[] mAttribute;
44

    
45
///////////////////////////////////////////////////////////////////////////////////////////////////
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
  private String parseOutAttribute(final String line)
91
    {
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
            return subline.substring(nameBegin+1,subLen);
125
            }
126
          }
127
        }
128
      }
129

    
130
    return null;
131
    }
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
    String nextLine, attribute, attrList="";
141
    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
        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
        }
162
      }
163
    catch (IOException e)
164
      {
165
      return null;
166
      }
167

    
168
    if( doAttributes )
169
      {
170
      mAttributeName = attrList.split(" ");
171
      }
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
      GLES20.glShaderSource(shaderHandle, shaderSource);
218
      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
   * @throws FragmentCompilationException
255
   * @throws VertexCompilationException
256
   * @throws VertexUniformsException
257
   * @throws FragmentUniformsException
258
   * @throws LinkingException
259
   */
260

    
261
  public DistortedProgram(final InputStream vertex, final InputStream fragment, final String vertexHeader, final String fragmentHeader)
262
  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
    final int vertexShaderHandle   = compileShader(GLES20.GL_VERTEX_SHADER  , vertexHeader   + vertexShader  );
272
    final int fragmentShaderHandle = compileShader(GLES20.GL_FRAGMENT_SHADER, fragmentHeader + fragmentShader);
273

    
274
    mProgramHandle = createAndLinkProgram(vertexShaderHandle, fragmentShaderHandle, mAttributeName);
275

    
276
    mAttribute = new int[mNumAttributes];
277

    
278
    for(int i=0; i<mNumAttributes; i++)
279
      {
280
      mAttribute[i] = GLES20.glGetAttribLocation( mProgramHandle, mAttributeName[i]);
281
      }
282
    }
283

    
284
///////////////////////////////////////////////////////////////////////////////////////////////////
285
/**
286
 * Return the handle of the created program so that we can later, say, call glUseProgram.
287
 */
288
  public int getProgramHandle()
289
    {
290
    return mProgramHandle;
291
    }
292

    
293
///////////////////////////////////////////////////////////////////////////////////////////////////
294
/**
295
 * Use the program and enable all vertex attribute arrays.
296
 *
297
 * Needs to be called from a thread holding the OpenGL context.
298
 */
299
  public void useProgram()
300
    {
301
    GLES20.glUseProgram(mProgramHandle);
302

    
303
    for(int i=0; i<mNumAttributes; i++)
304
      GLES20.glEnableVertexAttribArray(mAttribute[i]);
305
    }
306
  }
307

    
308

    
(1-1/6)