Project

General

Profile

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

library / src / main / java / org / distorted / library / program / DistortedProgram.java @ 94f6d472

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.GLES30;
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 String mAttributeStr;
39
  private int mAttributeLen;
40

    
41
  private int mProgramHandle;
42
  private int mNumAttributes;
43
  private String[] mAttributeName;
44

    
45
  public final int[] mAttribute;
46

    
47
///////////////////////////////////////////////////////////////////////////////////////////////////
48

    
49
  private int createAndLinkProgram(final int vertexShaderHandle, final int fragmentShaderHandle, final String[] attributes)
50
  throws LinkingException
51
    {
52
    int programHandle = GLES30.glCreateProgram();
53

    
54
    if (programHandle != 0)
55
      {
56
      GLES30.glAttachShader(programHandle, vertexShaderHandle);
57
      GLES30.glAttachShader(programHandle, fragmentShaderHandle);
58

    
59
      if (attributes != null)
60
        {
61
        final int size = attributes.length;
62

    
63
        for (int i = 0; i < size; i++)
64
          {
65
          GLES30.glBindAttribLocation(programHandle, i, attributes[i]);
66
          }
67
        }
68

    
69
      GLES30.glLinkProgram(programHandle);
70

    
71
      final int[] linkStatus = new int[1];
72
      GLES30.glGetProgramiv(programHandle, GLES30.GL_LINK_STATUS, linkStatus, 0);
73

    
74
      if (linkStatus[0] != GLES30.GL_TRUE )
75
        {
76
        String error = GLES30.glGetProgramInfoLog(programHandle);
77
        GLES30.glDeleteProgram(programHandle);
78
        throw new LinkingException(error);
79
        }
80

    
81
      final int[] numberOfUniforms = new int[1];
82
      GLES30.glGetProgramiv(programHandle, GLES30.GL_ACTIVE_UNIFORMS, numberOfUniforms, 0);
83

    
84
      //android.util.Log.d("program", "number of active uniforms="+numberOfUniforms[0]);
85
      }
86

    
87
    return programHandle;
88
    }
89

    
90
///////////////////////////////////////////////////////////////////////////////////////////////////
91

    
92
  private String parseOutAttribute(final String line)
93
    {
94
    int len = line.length();
95
    int whiteSpace, semicolon, nameBegin;
96
    char currChar;
97

    
98
    for(whiteSpace=0; whiteSpace<len; whiteSpace++)
99
      {
100
      currChar = line.charAt(whiteSpace);
101
      if( currChar!=' ' && currChar!='\t') break;
102
      }
103

    
104
    for(semicolon=whiteSpace; semicolon<len; semicolon++)
105
      {
106
      currChar = line.charAt(semicolon);
107
      if( currChar==';') break;
108
      }
109

    
110
    if( semicolon<len && semicolon-whiteSpace>=mAttributeLen+1 )
111
      {
112
      String subline = line.substring(whiteSpace,semicolon);
113
      int subLen = semicolon-whiteSpace;
114

    
115
      if( subline.startsWith(mAttributeStr))
116
        {
117
        //android.util.Log.e("program", "GOOD LINE: " +subline+" subLen="+subLen);
118

    
119
        for(nameBegin=subLen-1; nameBegin>mAttributeLen-2; nameBegin--)
120
          {
121
          currChar=subline.charAt(nameBegin);
122

    
123
          if( currChar==' ' || currChar=='\t' )
124
            {
125
            mNumAttributes++;
126
            return subline.substring(nameBegin+1,subLen);
127
            }
128
          }
129
        }
130
      }
131

    
132
    return null;
133
    }
134

    
135
///////////////////////////////////////////////////////////////////////////////////////////////////
136

    
137
  private String readTextFileFromRawResource(final InputStream inputStream, boolean doAttributes)
138
    {
139
    final InputStreamReader inputStreamReader = new InputStreamReader(inputStream);
140
    final BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
141

    
142
    String nextLine, attribute, attrList="";
143
    final StringBuilder body = new StringBuilder();
144

    
145
    try
146
      {
147
      while ((nextLine = bufferedReader.readLine()) != null)
148
        {
149
        body.append(nextLine);
150
        body.append('\n');
151

    
152
        if( doAttributes )
153
          {
154
          attribute = parseOutAttribute(nextLine);
155

    
156
          if( attribute!=null )
157
            {
158
            //android.util.Log.d("program", "new attribute: "+attribute);
159
            if( attrList.length()>0 ) attrList+=" ";
160
            attrList += attribute;
161
            }
162
          }
163
        }
164
      }
165
    catch (IOException e)
166
      {
167
      return null;
168
      }
169

    
170
    if( doAttributes )
171
      {
172
      mAttributeName = attrList.split(" ");
173
      }
174

    
175
    return body.toString();
176
    }
177

    
178
///////////////////////////////////////////////////////////////////////////////////////////////////
179

    
180
  private static void sanitizeMaxValues()
181
  throws VertexUniformsException,FragmentUniformsException
182
    {
183
    int maxV,maxF;
184
    int[] param = new int[1];
185

    
186
    GLES30.glGetIntegerv(GLES30.GL_MAX_VERTEX_UNIFORM_VECTORS, param, 0);
187
    maxV = param[0];
188
    GLES30.glGetIntegerv(GLES30.GL_MAX_FRAGMENT_UNIFORM_VECTORS, param, 0);
189
    maxF = param[0];
190

    
191
    //Log.d("program", "Max vectors in vertex shader: "+maxV);
192
    //Log.d("program", "Max vectors in fragment shader: "+maxF);
193

    
194
    if( !Build.FINGERPRINT.contains("generic") )
195
      {
196
      int realMaxV = (maxV-11)/4;   // adjust this in case of changes to the shaders...
197
      int realMaxF = (maxF- 2)/4;   //
198

    
199
      if( DistortedEffects.getMaxVertex()   > realMaxV )
200
        {
201
        throw new VertexUniformsException("Too many effects in the vertex shader, max is "+realMaxV, realMaxV);
202
        }
203
      if( DistortedEffects.getMaxFragment() > realMaxF )
204
        {
205
        throw new FragmentUniformsException("Too many effects in the fragment shader, max is "+realMaxF, realMaxF);
206
        }
207
      }
208
    }
209

    
210
///////////////////////////////////////////////////////////////////////////////////////////////////
211

    
212
  private static int compileShader(final int shaderType, final String shaderSource)
213
  throws FragmentCompilationException,VertexCompilationException
214
    {
215
    int shaderHandle = GLES30.glCreateShader(shaderType);
216

    
217
    if (shaderHandle != 0)
218
      {
219
      GLES30.glShaderSource(shaderHandle, shaderSource);
220
      GLES30.glCompileShader(shaderHandle);
221
      final int[] compileStatus = new int[1];
222
      GLES30.glGetShaderiv(shaderHandle, GLES30.GL_COMPILE_STATUS, compileStatus, 0);
223

    
224
      if (compileStatus[0] != GLES30.GL_TRUE )
225
        {
226
        GLES30.glDeleteShader(shaderHandle);
227
        shaderHandle = 0;
228
        }
229
      }
230

    
231
    if (shaderHandle == 0)
232
      {
233
      String error = GLES30.glGetShaderInfoLog(shaderHandle);
234

    
235
      //android.util.Log.e("Program", "error compiling :"+error);
236

    
237
      switch(shaderType)
238
        {
239
        case GLES30.GL_VERTEX_SHADER  : throw new VertexCompilationException(error);
240
        case GLES30.GL_FRAGMENT_SHADER: throw new FragmentCompilationException(error);
241
        default                       : throw new RuntimeException(error);
242
        }
243
      }
244

    
245
    return shaderHandle;
246
    }
247

    
248
///////////////////////////////////////////////////////////////////////////////////////////////////
249
// PUBLIC API
250
///////////////////////////////////////////////////////////////////////////////////////////////////
251
  /**
252
   * Create a new Shader Program from source stored in resource files.
253
   * <p>
254
   * Needs to be called from a thread holding the OpenGL context.
255
   *
256
   * @param vertex   InputStream containing the opened Resource file from where to read vertex shader code.
257
   * @param fragment InputStream containing the opened Resource file from where to read fragment shader code.
258
   * @throws FragmentCompilationException
259
   * @throws VertexCompilationException
260
   * @throws VertexUniformsException
261
   * @throws FragmentUniformsException
262
   * @throws LinkingException
263
   */
264

    
265
  public DistortedProgram(final InputStream vertex, final InputStream fragment, final String vertexHeader, final String fragmentHeader, int glslVersion)
266
  throws FragmentCompilationException,VertexCompilationException,VertexUniformsException,FragmentUniformsException,LinkingException
267
    {
268
    mAttributeStr = (glslVersion == 100 ? "attribute " : "in ");
269
    mAttributeLen = mAttributeStr.length();
270

    
271
    mNumAttributes = 0;
272

    
273
    final String vertexShader   = readTextFileFromRawResource(vertex  , true );
274
    final String fragmentShader = readTextFileFromRawResource(fragment, false);
275

    
276
    sanitizeMaxValues();
277

    
278
    final int vertexShaderHandle   = compileShader(GLES30.GL_VERTEX_SHADER  , vertexHeader   + vertexShader  );
279
    final int fragmentShaderHandle = compileShader(GLES30.GL_FRAGMENT_SHADER, fragmentHeader + fragmentShader);
280

    
281
    mProgramHandle = createAndLinkProgram(vertexShaderHandle, fragmentShaderHandle, mAttributeName);
282

    
283
    mAttribute = new int[mNumAttributes];
284

    
285
    for(int i=0; i<mNumAttributes; i++)
286
      {
287
      mAttribute[i] = GLES30.glGetAttribLocation( mProgramHandle, mAttributeName[i]);
288
      }
289
    }
290

    
291
///////////////////////////////////////////////////////////////////////////////////////////////////
292
/**
293
 * Return the handle of the created program so that we can later, say, call glUseProgram.
294
 */
295
  public int getProgramHandle()
296
    {
297
    return mProgramHandle;
298
    }
299

    
300
///////////////////////////////////////////////////////////////////////////////////////////////////
301
/**
302
 * Use the program and enable all vertex attribute arrays.
303
 *
304
 * Needs to be called from a thread holding the OpenGL context.
305
 */
306
  public void useProgram()
307
    {
308
    GLES30.glUseProgram(mProgramHandle);
309

    
310
    for(int i=0; i<mNumAttributes; i++)
311
      GLES30.glEnableVertexAttribArray(mAttribute[i]);
312
    }
313
  }
314

    
315

    
(1-1/6)