Project

General

Profile

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

library / src / main / java / org / distorted / library / program / DistortedProgram.java @ 4782b4e6

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, final String[] feedbackVaryings)
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( feedbackVaryings!=null )
60
        {
61
        GLES30.glTransformFeedbackVaryings(programHandle, feedbackVaryings, GLES30.GL_INTERLEAVED_ATTRIBS);
62
        }
63

    
64
      if (attributes != null)
65
        {
66
        final int size = attributes.length;
67

    
68
        for (int i = 0; i < size; i++)
69
          {
70
          GLES30.glBindAttribLocation(programHandle, i, attributes[i]);
71
          }
72
        }
73

    
74
      GLES30.glLinkProgram(programHandle);
75

    
76
      final int[] linkStatus = new int[1];
77
      GLES30.glGetProgramiv(programHandle, GLES30.GL_LINK_STATUS, linkStatus, 0);
78

    
79
      if (linkStatus[0] != GLES30.GL_TRUE )
80
        {
81
        String error = GLES30.glGetProgramInfoLog(programHandle);
82
        GLES30.glDeleteProgram(programHandle);
83
        throw new LinkingException(error);
84
        }
85

    
86
      final int[] numberOfUniforms = new int[1];
87
      GLES30.glGetProgramiv(programHandle, GLES30.GL_ACTIVE_UNIFORMS, numberOfUniforms, 0);
88

    
89
      //android.util.Log.d("program", "number of active uniforms="+numberOfUniforms[0]);
90
      }
91

    
92
    return programHandle;
93
    }
94

    
95
///////////////////////////////////////////////////////////////////////////////////////////////////
96

    
97
  private String parseOutAttribute(final String line)
98
    {
99
    int len = line.length();
100
    int whiteSpace, semicolon, nameBegin;
101
    char currChar;
102

    
103
    for(whiteSpace=0; whiteSpace<len; whiteSpace++)
104
      {
105
      currChar = line.charAt(whiteSpace);
106
      if( currChar!=' ' && currChar!='\t') break;
107
      }
108

    
109
    for(semicolon=whiteSpace; semicolon<len; semicolon++)
110
      {
111
      currChar = line.charAt(semicolon);
112
      if( currChar==';') break;
113
      }
114

    
115
    if( semicolon<len && semicolon-whiteSpace>=mAttributeLen+1 )
116
      {
117
      String subline = line.substring(whiteSpace,semicolon);
118
      int subLen = semicolon-whiteSpace;
119

    
120
      if( subline.startsWith(mAttributeStr))
121
        {
122
        //android.util.Log.e("program", "GOOD LINE: " +subline+" subLen="+subLen);
123

    
124
        for(nameBegin=subLen-1; nameBegin>mAttributeLen-2; nameBegin--)
125
          {
126
          currChar=subline.charAt(nameBegin);
127

    
128
          if( currChar==' ' || currChar=='\t' )
129
            {
130
            mNumAttributes++;
131
            return subline.substring(nameBegin+1,subLen);
132
            }
133
          }
134
        }
135
      }
136

    
137
    return null;
138
    }
139

    
140
///////////////////////////////////////////////////////////////////////////////////////////////////
141

    
142
  private String readTextFileFromRawResource(final InputStream inputStream, boolean doAttributes)
143
    {
144
    final InputStreamReader inputStreamReader = new InputStreamReader(inputStream);
145
    final BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
146

    
147
    String nextLine, attribute, attrList="";
148
    final StringBuilder body = new StringBuilder();
149

    
150
    try
151
      {
152
      while ((nextLine = bufferedReader.readLine()) != null)
153
        {
154
        body.append(nextLine);
155
        body.append('\n');
156

    
157
        if( doAttributes )
158
          {
159
          attribute = parseOutAttribute(nextLine);
160

    
161
          if( attribute!=null )
162
            {
163
            //android.util.Log.d("program", "new attribute: "+attribute);
164
            if( attrList.length()>0 ) attrList+=" ";
165
            attrList += attribute;
166
            }
167
          }
168
        }
169
      }
170
    catch (IOException e)
171
      {
172
      return null;
173
      }
174

    
175
    if( doAttributes )
176
      {
177
      mAttributeName = attrList.split(" ");
178
      }
179

    
180
    return body.toString();
181
    }
182

    
183
///////////////////////////////////////////////////////////////////////////////////////////////////
184

    
185
  private static void sanitizeMaxValues()
186
  throws VertexUniformsException,FragmentUniformsException
187
    {
188
    int maxV,maxF;
189
    int[] param = new int[1];
190

    
191
    GLES30.glGetIntegerv(GLES30.GL_MAX_VERTEX_UNIFORM_VECTORS, param, 0);
192
    maxV = param[0];
193
    GLES30.glGetIntegerv(GLES30.GL_MAX_FRAGMENT_UNIFORM_VECTORS, param, 0);
194
    maxF = param[0];
195

    
196
    //Log.d("program", "Max vectors in vertex shader: "+maxV);
197
    //Log.d("program", "Max vectors in fragment shader: "+maxF);
198

    
199
    if( !Build.FINGERPRINT.contains("generic") )
200
      {
201
      int realMaxV = (maxV-11)/4;   // adjust this in case of changes to the shaders...
202
      int realMaxF = (maxF- 2)/4;   //
203

    
204
      if( DistortedEffects.getMaxVertex()   > realMaxV )
205
        {
206
        throw new VertexUniformsException("Too many effects in the vertex shader, max is "+realMaxV, realMaxV);
207
        }
208
      if( DistortedEffects.getMaxFragment() > realMaxF )
209
        {
210
        throw new FragmentUniformsException("Too many effects in the fragment shader, max is "+realMaxF, realMaxF);
211
        }
212
      }
213
    }
214

    
215
///////////////////////////////////////////////////////////////////////////////////////////////////
216

    
217
  private static int compileShader(final int shaderType, final String shaderSource)
218
  throws FragmentCompilationException,VertexCompilationException
219
    {
220
    int shaderHandle = GLES30.glCreateShader(shaderType);
221

    
222
    if (shaderHandle != 0)
223
      {
224
      GLES30.glShaderSource(shaderHandle, shaderSource);
225
      GLES30.glCompileShader(shaderHandle);
226
      final int[] compileStatus = new int[1];
227
      GLES30.glGetShaderiv(shaderHandle, GLES30.GL_COMPILE_STATUS, compileStatus, 0);
228

    
229
      if (compileStatus[0] != GLES30.GL_TRUE )
230
        {
231
        GLES30.glDeleteShader(shaderHandle);
232
        shaderHandle = 0;
233
        }
234
      }
235

    
236
    if (shaderHandle == 0)
237
      {
238
      String error = GLES30.glGetShaderInfoLog(shaderHandle);
239

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

    
242
      switch(shaderType)
243
        {
244
        case GLES30.GL_VERTEX_SHADER  : throw new VertexCompilationException(error);
245
        case GLES30.GL_FRAGMENT_SHADER: throw new FragmentCompilationException(error);
246
        default                       : throw new RuntimeException(error);
247
        }
248
      }
249

    
250
    return shaderHandle;
251
    }
252

    
253
///////////////////////////////////////////////////////////////////////////////////////////////////
254
// feedback: List of 'out' variables (OpenGL ES >= 3.0 only!) that will be transferred back to CPU
255
// using Transform Feedback.
256

    
257
  public DistortedProgram(final InputStream vertex, final InputStream fragment, final String vertexHeader, final String fragmentHeader, int glslVersion, final String[] feedback )
258
  throws FragmentCompilationException,VertexCompilationException,VertexUniformsException,FragmentUniformsException,LinkingException
259
    {
260
    mAttributeStr = (glslVersion == 100 ? "attribute " : "in ");
261
    mAttributeLen = mAttributeStr.length();
262

    
263
    mNumAttributes = 0;
264

    
265
    final String vertexShader   = readTextFileFromRawResource(vertex  , true );
266
    final String fragmentShader = readTextFileFromRawResource(fragment, false);
267

    
268
    sanitizeMaxValues();
269

    
270
    final int vertexShaderHandle   = compileShader(GLES30.GL_VERTEX_SHADER  , vertexHeader   + vertexShader  );
271
    final int fragmentShaderHandle = compileShader(GLES30.GL_FRAGMENT_SHADER, fragmentHeader + fragmentShader);
272

    
273
    mProgramHandle = createAndLinkProgram(vertexShaderHandle, fragmentShaderHandle, mAttributeName, feedback);
274

    
275
    mAttribute = new int[mNumAttributes];
276

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

    
283
///////////////////////////////////////////////////////////////////////////////////////////////////
284
// PUBLIC API
285
///////////////////////////////////////////////////////////////////////////////////////////////////
286
  /**
287
   * Create a new Shader Program from source stored in resource files.
288
   * <p>
289
   * Needs to be called from a thread holding the OpenGL context.
290
   *
291
   * @param vertex   InputStream containing the opened Resource file from where to read vertex shader code.
292
   * @param fragment InputStream containing the opened Resource file from where to read fragment shader code.
293
   * @throws FragmentCompilationException
294
   * @throws VertexCompilationException
295
   * @throws VertexUniformsException
296
   * @throws FragmentUniformsException
297
   * @throws LinkingException
298
   */
299

    
300
  public DistortedProgram(final InputStream vertex, final InputStream fragment, final String vertexHeader, final String fragmentHeader, int glslVersion )
301
  throws FragmentCompilationException,VertexCompilationException,VertexUniformsException,FragmentUniformsException,LinkingException
302
    {
303
    this(vertex,fragment,vertexHeader,fragmentHeader,glslVersion,null);
304
    }
305

    
306
///////////////////////////////////////////////////////////////////////////////////////////////////
307
/**
308
 * Return the handle of the created program so that we can later, say, call glUseProgram.
309
 */
310
  public int getProgramHandle()
311
    {
312
    return mProgramHandle;
313
    }
314

    
315
///////////////////////////////////////////////////////////////////////////////////////////////////
316
/**
317
 * Use the program and enable all vertex attribute arrays.
318
 *
319
 * Needs to be called from a thread holding the OpenGL context.
320
 */
321
  public void useProgram()
322
    {
323
    GLES30.glUseProgram(mProgramHandle);
324

    
325
    for(int i=0; i<mNumAttributes; i++)
326
      GLES30.glEnableVertexAttribArray(mAttribute[i]);
327
    }
328
  }
329

    
330

    
(1-1/6)