Project

General

Profile

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

library / src / main / java / org / distorted / library / program / DistortedProgram.java @ 3a54358a

1 432442f9 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
2 3a54358a Leszek Koltunski
// Copyright 2016 Leszek Koltunski  leszek@koltunski.pl                                          //
3 432442f9 Leszek Koltunski
//                                                                                               //
4 46b572b5 Leszek Koltunski
// This file is part of Distorted.                                                               //
5 432442f9 Leszek Koltunski
//                                                                                               //
6 3a54358a Leszek Koltunski
// This library is free software; you can redistribute it and/or                                 //
7
// modify it under the terms of the GNU Lesser General Public                                    //
8
// License as published by the Free Software Foundation; either                                  //
9
// version 2.1 of the License, or (at your option) any later version.                            //
10 432442f9 Leszek Koltunski
//                                                                                               //
11 3a54358a Leszek Koltunski
// This library is distributed in the hope that it will be useful,                               //
12 432442f9 Leszek Koltunski
// but WITHOUT ANY WARRANTY; without even the implied warranty of                                //
13 3a54358a Leszek Koltunski
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU                             //
14
// Lesser General Public License for more details.                                               //
15 432442f9 Leszek Koltunski
//                                                                                               //
16 3a54358a Leszek Koltunski
// You should have received a copy of the GNU Lesser General Public                              //
17
// License along with this library; if not, write to the Free Software                           //
18
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA                //
19 432442f9 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
20
21
package org.distorted.library.program;
22
23 b7074bc6 Leszek Koltunski
import android.opengl.GLES30;
24 432442f9 Leszek Koltunski
25
import java.io.BufferedReader;
26
import java.io.IOException;
27
import java.io.InputStream;
28
import java.io.InputStreamReader;
29
30
///////////////////////////////////////////////////////////////////////////////////////////////////
31
/**
32
 * An object which encapsulates a vertex/fragment shader combo, aka Shader Program.
33
 */
34
public class DistortedProgram
35
  {
36 041b6dee Leszek Koltunski
  private String mAttributeStr, mUniformStr, mUniList;
37
  private int mAttributeLen, mUniformLen;
38 432442f9 Leszek Koltunski
  private int mNumAttributes;
39 041b6dee Leszek Koltunski
  private int mNumUniforms;
40 432442f9 Leszek Koltunski
  private String[] mAttributeName;
41 041b6dee Leszek Koltunski
  private String[] mUniformName;
42 5b567bb4 Leszek Koltunski
  private final int mProgramHandle;
43 432442f9 Leszek Koltunski
44 faa3ff56 Leszek Koltunski
/**
45 f81ebc3f Leszek Koltunski
 * List of Attributes (OpenGL ES 3.0: 'in' variables), in the same order as declared in the shader source.
46 faa3ff56 Leszek Koltunski
 */
47 b11171e8 Leszek Koltunski
  public int[] mAttribute;
48 faa3ff56 Leszek Koltunski
/**
49 f81ebc3f Leszek Koltunski
 * List of Uniforms, in the same order as declared in the shader source.
50 faa3ff56 Leszek Koltunski
 */
51 b11171e8 Leszek Koltunski
  public int[] mUniform;
52 02de77c9 Leszek Koltunski
53 432442f9 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
54
55 4782b4e6 Leszek Koltunski
  private int createAndLinkProgram(final int vertexShaderHandle, final int fragmentShaderHandle, final String[] attributes, final String[] feedbackVaryings)
56 432442f9 Leszek Koltunski
  throws LinkingException
57
    {
58 b7074bc6 Leszek Koltunski
    int programHandle = GLES30.glCreateProgram();
59 432442f9 Leszek Koltunski
60
    if (programHandle != 0)
61
      {
62 b7074bc6 Leszek Koltunski
      GLES30.glAttachShader(programHandle, vertexShaderHandle);
63
      GLES30.glAttachShader(programHandle, fragmentShaderHandle);
64 432442f9 Leszek Koltunski
65 4782b4e6 Leszek Koltunski
      if( feedbackVaryings!=null )
66
        {
67 b7074bc6 Leszek Koltunski
        GLES30.glTransformFeedbackVaryings(programHandle, feedbackVaryings, GLES30.GL_INTERLEAVED_ATTRIBS);
68 4782b4e6 Leszek Koltunski
        }
69
70 432442f9 Leszek Koltunski
      if (attributes != null)
71
        {
72
        final int size = attributes.length;
73
74 b6947445 Leszek Koltunski
        for(int i=0; i<size; i++)
75 432442f9 Leszek Koltunski
          {
76 b7074bc6 Leszek Koltunski
          GLES30.glBindAttribLocation(programHandle, i, attributes[i]);
77 432442f9 Leszek Koltunski
          }
78
        }
79
80 b7074bc6 Leszek Koltunski
      GLES30.glLinkProgram(programHandle);
81 432442f9 Leszek Koltunski
82
      final int[] linkStatus = new int[1];
83 b7074bc6 Leszek Koltunski
      GLES30.glGetProgramiv(programHandle, GLES30.GL_LINK_STATUS, linkStatus, 0);
84 432442f9 Leszek Koltunski
85 b7074bc6 Leszek Koltunski
      if (linkStatus[0] != GLES30.GL_TRUE )
86 432442f9 Leszek Koltunski
        {
87 b7074bc6 Leszek Koltunski
        String error = GLES30.glGetProgramInfoLog(programHandle);
88
        GLES30.glDeleteProgram(programHandle);
89 432442f9 Leszek Koltunski
        throw new LinkingException(error);
90
        }
91
92
      final int[] numberOfUniforms = new int[1];
93 b7074bc6 Leszek Koltunski
      GLES30.glGetProgramiv(programHandle, GLES30.GL_ACTIVE_UNIFORMS, numberOfUniforms, 0);
94 432442f9 Leszek Koltunski
95
      //android.util.Log.d("program", "number of active uniforms="+numberOfUniforms[0]);
96
      }
97
98
    return programHandle;
99
    }
100
101 041b6dee Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
102
103
  private void init(int glslVersion)
104
    {
105
    mAttributeStr  = (glslVersion == 100 ? "attribute " : "in ");
106
    mAttributeLen  = mAttributeStr.length();
107
    mNumAttributes = 0;
108
    mUniformStr    = "uniform ";
109
    mUniformLen    = mUniformStr.length();
110
    mNumUniforms   = 0;
111
    mUniList       = "";
112
    }
113
114
///////////////////////////////////////////////////////////////////////////////////////////////////
115
116
  private String parseOutUniform(final String line)
117
    {
118
    int len = line.length();
119
    int whiteSpace, semicolon, nameBegin;
120
    char currChar;
121
122
    for(whiteSpace=0; whiteSpace<len; whiteSpace++)
123
      {
124
      currChar = line.charAt(whiteSpace);
125
      if( currChar!=' ' && currChar!='\t') break;
126
      }
127
128
    for(semicolon=whiteSpace; semicolon<len; semicolon++)
129
      {
130
      currChar = line.charAt(semicolon);
131
      if( currChar==';') break;
132
      }
133
134
    if( semicolon<len && semicolon-whiteSpace>=mUniformLen+1 )
135
      {
136
      String subline = line.substring(whiteSpace,semicolon);
137
      int subLen = semicolon-whiteSpace;
138
139
      if( subline.startsWith(mUniformStr))
140
        {
141
        //android.util.Log.e("program", "GOOD LINE: " +subline+" subLen="+subLen);
142
143
        for(nameBegin=subLen-1; nameBegin>mUniformLen-2; nameBegin--)
144
          {
145
          currChar=subline.charAt(nameBegin);
146
147
          if( currChar==' ' || currChar=='\t' )
148
            {
149
            mNumUniforms++;
150
            String uniform = subline.substring(nameBegin+1,subLen);
151
            int brace = uniform.indexOf("[");
152
153
            return brace>=0 ? uniform.substring(0,brace) : uniform;
154
            }
155
          }
156
        }
157
      }
158
159
    return null;
160
    }
161
162 432442f9 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
163
164 3d804c91 Leszek Koltunski
  private String parseOutAttribute(final String line)
165 432442f9 Leszek Koltunski
    {
166
    int len = line.length();
167
    int whiteSpace, semicolon, nameBegin;
168
    char currChar;
169
170
    for(whiteSpace=0; whiteSpace<len; whiteSpace++)
171
      {
172
      currChar = line.charAt(whiteSpace);
173
      if( currChar!=' ' && currChar!='\t') break;
174
      }
175
176
    for(semicolon=whiteSpace; semicolon<len; semicolon++)
177
      {
178
      currChar = line.charAt(semicolon);
179
      if( currChar==';') break;
180
      }
181
182 94f6d472 Leszek Koltunski
    if( semicolon<len && semicolon-whiteSpace>=mAttributeLen+1 )
183 432442f9 Leszek Koltunski
      {
184
      String subline = line.substring(whiteSpace,semicolon);
185
      int subLen = semicolon-whiteSpace;
186
187 94f6d472 Leszek Koltunski
      if( subline.startsWith(mAttributeStr))
188 432442f9 Leszek Koltunski
        {
189 94f6d472 Leszek Koltunski
        for(nameBegin=subLen-1; nameBegin>mAttributeLen-2; nameBegin--)
190 432442f9 Leszek Koltunski
          {
191
          currChar=subline.charAt(nameBegin);
192
193
          if( currChar==' ' || currChar=='\t' )
194
            {
195
            mNumAttributes++;
196 3d804c91 Leszek Koltunski
            return subline.substring(nameBegin+1,subLen);
197 432442f9 Leszek Koltunski
            }
198
          }
199
        }
200
      }
201 3d804c91 Leszek Koltunski
202
    return null;
203 432442f9 Leszek Koltunski
    }
204
205 041b6dee Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
206
207
  private void doAttributes(final String shader, boolean doAttributes)
208
    {
209
    String attribute, attrList="", uniform;
210
    String[] lines = shader.split("\n");
211
212 36d65d88 Leszek Koltunski
    for (String line : lines)
213 041b6dee Leszek Koltunski
      {
214 36d65d88 Leszek Koltunski
      if (doAttributes)
215 041b6dee Leszek Koltunski
        {
216 36d65d88 Leszek Koltunski
        attribute = parseOutAttribute(line);
217 041b6dee Leszek Koltunski
218 36d65d88 Leszek Koltunski
        if (attribute != null)
219 041b6dee Leszek Koltunski
          {
220 36d65d88 Leszek Koltunski
          if (attrList.length() > 0) attrList += " ";
221 041b6dee Leszek Koltunski
          attrList += attribute;
222
          }
223
        }
224
225 36d65d88 Leszek Koltunski
      uniform = parseOutUniform(line);
226 041b6dee Leszek Koltunski
227 36d65d88 Leszek Koltunski
      if (uniform != null)
228 041b6dee Leszek Koltunski
        {
229 36d65d88 Leszek Koltunski
        if (mUniList.length() > 0) mUniList += " ";
230 041b6dee Leszek Koltunski
        mUniList += uniform;
231
        }
232
      }
233
234
    if( doAttributes ) mAttributeName = attrList.split(" ");
235
    }
236
237 432442f9 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
238
239
  private String readTextFileFromRawResource(final InputStream inputStream, boolean doAttributes)
240
    {
241
    final InputStreamReader inputStreamReader = new InputStreamReader(inputStream);
242
    final BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
243
244 3d804c91 Leszek Koltunski
    String nextLine, attribute, attrList="";
245 432442f9 Leszek Koltunski
    final StringBuilder body = new StringBuilder();
246
247
    try
248
      {
249
      while ((nextLine = bufferedReader.readLine()) != null)
250
        {
251
        body.append(nextLine);
252
        body.append('\n');
253
254 3d804c91 Leszek Koltunski
        if( doAttributes )
255
          {
256
          attribute = parseOutAttribute(nextLine);
257
258
          if( attribute!=null )
259
            {
260
            //android.util.Log.d("program", "new attribute: "+attribute);
261
            if( attrList.length()>0 ) attrList+=" ";
262
            attrList += attribute;
263
            }
264
          }
265 432442f9 Leszek Koltunski
        }
266
      }
267
    catch (IOException e)
268
      {
269
      return null;
270
      }
271
272 041b6dee Leszek Koltunski
    if( doAttributes ) mAttributeName = attrList.split(" ");
273 432442f9 Leszek Koltunski
274
    return body.toString();
275
    }
276
277
///////////////////////////////////////////////////////////////////////////////////////////////////
278
279
  private static int compileShader(final int shaderType, final String shaderSource)
280
  throws FragmentCompilationException,VertexCompilationException
281
    {
282 b7074bc6 Leszek Koltunski
    int shaderHandle = GLES30.glCreateShader(shaderType);
283 432442f9 Leszek Koltunski
284
    if (shaderHandle != 0)
285
      {
286 b7074bc6 Leszek Koltunski
      GLES30.glShaderSource(shaderHandle, shaderSource);
287
      GLES30.glCompileShader(shaderHandle);
288 432442f9 Leszek Koltunski
      final int[] compileStatus = new int[1];
289 b7074bc6 Leszek Koltunski
      GLES30.glGetShaderiv(shaderHandle, GLES30.GL_COMPILE_STATUS, compileStatus, 0);
290 432442f9 Leszek Koltunski
291 b7074bc6 Leszek Koltunski
      if (compileStatus[0] != GLES30.GL_TRUE)
292 432442f9 Leszek Koltunski
        {
293 b7074bc6 Leszek Koltunski
        String error = GLES30.glGetShaderInfoLog(shaderHandle);
294 432442f9 Leszek Koltunski
295 b7074bc6 Leszek Koltunski
        GLES30.glDeleteShader(shaderHandle);
296 81a0b906 leszek
297 341151fc Leszek Koltunski
        switch (shaderType)
298
          {
299 b7074bc6 Leszek Koltunski
          case GLES30.GL_VERTEX_SHADER:   throw new VertexCompilationException(error);
300
          case GLES30.GL_FRAGMENT_SHADER: throw new FragmentCompilationException(error);
301 341151fc Leszek Koltunski
          default:                        throw new RuntimeException(error);
302
          }
303 432442f9 Leszek Koltunski
        }
304
      }
305
306
    return shaderHandle;
307
    }
308
309 7cd24173 leszek
///////////////////////////////////////////////////////////////////////////////////////////////////
310
311
  private static String insertEnabledEffects(String code, final String effects)
312
    {
313
    final String marker = "// ENABLED EFFECTS WILL BE INSERTED HERE";
314
    int length = marker.length();
315
316
    int place = code.indexOf(marker);
317
318
    if( place>=0 )
319
      {
320
      String begin = code.substring(0,place-1);
321
      String end   = code.substring(place+length);
322
323
      return begin + effects + end;
324
      }
325
    else
326
      {
327
      android.util.Log.e("Program", "Error: marker string not found in SHADER!");
328
      }
329
330
    return null;
331
    }
332
333 432442f9 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
334 7cd24173 leszek
335 b11171e8 Leszek Koltunski
  private void setUpAttributes()
336
    {
337 7cd24173 leszek
    mAttribute = new int[mNumAttributes];
338
339
    for(int i=0; i<mNumAttributes; i++)
340
      {
341 b7074bc6 Leszek Koltunski
      mAttribute[i] = GLES30.glGetAttribLocation( mProgramHandle, mAttributeName[i]);
342 7cd24173 leszek
      }
343 041b6dee Leszek Koltunski
344 b11171e8 Leszek Koltunski
    int emptyAttrs = 0;
345
346
    for(int i=0; i<mNumAttributes; i++)
347
      {
348
      if( mAttribute[i] < 0 )
349
        {
350
        emptyAttrs++;
351
352
        for(int j=i; j<mNumAttributes-1; j++)
353
          {
354
          mAttribute[j] = mAttribute[j+1];
355
          mAttributeName[j] = mAttributeName[j+1];
356
          }
357
        }
358
      }
359
360
    mNumAttributes -= emptyAttrs;
361
    }
362
363
///////////////////////////////////////////////////////////////////////////////////////////////////
364
365
  private void setUpUniforms()
366
    {
367 041b6dee Leszek Koltunski
    if( mNumUniforms>0 )
368
      {
369
      mUniform = new int[mNumUniforms];
370
      mUniformName = mUniList.split(" ");
371
372
      for(int i=0; i<mNumUniforms; i++)
373
        {
374 b7074bc6 Leszek Koltunski
        mUniform[i] = GLES30.glGetUniformLocation( mProgramHandle, mUniformName[i]);
375 041b6dee Leszek Koltunski
        }
376
      }
377
    else mUniform = null;
378
    }
379
380 b11171e8 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
381
/**
382
 * Only for use by the library itself.
383
 *
384
 * @y.exclude
385
 */
386
  public DistortedProgram(final InputStream vert, final InputStream frag, final String vertHeader, final String fragHeader,
387
                          int glslVersion, final String[] feedback )
388
  throws FragmentCompilationException,VertexCompilationException,LinkingException
389
    {
390
    init(glslVersion);
391
392
    final String vertShader = readTextFileFromRawResource(vert, true );
393
    final String fragShader = readTextFileFromRawResource(frag, false);
394
395
    final int vertShaderHandle = compileShader(GLES30.GL_VERTEX_SHADER  , vertHeader + vertShader);
396
    final int fragShaderHandle = compileShader(GLES30.GL_FRAGMENT_SHADER, fragHeader + fragShader);
397
398
    mProgramHandle = createAndLinkProgram(vertShaderHandle, fragShaderHandle, mAttributeName, glslVersion>= 300 ? feedback:null );
399
400
    setUpAttributes();
401
    setUpUniforms();
402
    }
403
404 041b6dee Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
405 faa3ff56 Leszek Koltunski
/**
406
 * Only for use by the library itself.
407
 *
408
 * @y.exclude
409
 */
410 a13dde77 Leszek Koltunski
  public DistortedProgram(final InputStream vert, final InputStream frag, final String vertHeader, final String fragHeader,
411
                          final String enabledVert, final String enabledFrag, int glslVersion, final String[] feedback )
412
  throws FragmentCompilationException,VertexCompilationException,LinkingException
413 041b6dee Leszek Koltunski
    {
414 faa3ff56 Leszek Koltunski
    init(glslVersion);
415 041b6dee Leszek Koltunski
416 a13dde77 Leszek Koltunski
    String vertShader = readTextFileFromRawResource( vert, true );
417
    String fragShader = readTextFileFromRawResource( frag, false);
418 041b6dee Leszek Koltunski
419 a13dde77 Leszek Koltunski
    if( enabledVert!=null ) vertShader = insertEnabledEffects(vertShader,enabledVert);
420
    if( enabledFrag!=null ) fragShader = insertEnabledEffects(fragShader,enabledFrag);
421 041b6dee Leszek Koltunski
422 b7074bc6 Leszek Koltunski
    final int vertShaderHandle = compileShader(GLES30.GL_VERTEX_SHADER  , vertHeader + vertShader);
423
    final int fragShaderHandle = compileShader(GLES30.GL_FRAGMENT_SHADER, fragHeader + fragShader);
424 faa3ff56 Leszek Koltunski
425 a13dde77 Leszek Koltunski
    mProgramHandle = createAndLinkProgram(vertShaderHandle, fragShaderHandle, mAttributeName, glslVersion>= 300 ? feedback:null );
426 041b6dee Leszek Koltunski
427 b11171e8 Leszek Koltunski
    setUpAttributes();
428
    setUpUniforms();
429 7cd24173 leszek
    }
430
431
///////////////////////////////////////////////////////////////////////////////////////////////////
432 faa3ff56 Leszek Koltunski
/**
433
 * Only for use by the library itself.
434
 *
435
 * @y.exclude
436
 */
437
  public DistortedProgram(final InputStream vertex, final InputStream fragment, final String vertexHeader, final String fragmentHeader, int glslVersion )
438 f046b159 Leszek Koltunski
  throws FragmentCompilationException,VertexCompilationException,LinkingException
439 7cd24173 leszek
    {
440 faa3ff56 Leszek Koltunski
    this(vertex,fragment,vertexHeader,fragmentHeader,glslVersion,null);
441
    }
442 7cd24173 leszek
443 faa3ff56 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
444
// PUBLIC API
445
///////////////////////////////////////////////////////////////////////////////////////////////////
446
/**
447
 * Create a new Shader Program from two source strings.
448
 * <p>
449
 * Needs to be called from a thread holding the OpenGL context.
450
 *
451
 * @param vertex   Vertex shader code.
452
 * @param fragment Fragment shader code.
453 b11171e8 Leszek Koltunski
 * @throws FragmentCompilationException fragment shader failed to compile
454
 * @throws VertexCompilationException vertex shader failed to compile
455
 * @throws LinkingException shaders failed to link
456 faa3ff56 Leszek Koltunski
 */
457
  public DistortedProgram(final String vertex, final String fragment)
458 f046b159 Leszek Koltunski
  throws FragmentCompilationException,VertexCompilationException,LinkingException
459 faa3ff56 Leszek Koltunski
    {
460
    init(300);
461 7cd24173 leszek
462 faa3ff56 Leszek Koltunski
    doAttributes(vertex  , true );
463
    doAttributes(fragment, false);
464 7cd24173 leszek
465 b7074bc6 Leszek Koltunski
    final int vertexShaderHandle   = compileShader(GLES30.GL_VERTEX_SHADER  , vertex  );
466
    final int fragmentShaderHandle = compileShader(GLES30.GL_FRAGMENT_SHADER, fragment);
467 7cd24173 leszek
468 faa3ff56 Leszek Koltunski
    mProgramHandle = createAndLinkProgram(vertexShaderHandle, fragmentShaderHandle, mAttributeName, null );
469 432442f9 Leszek Koltunski
470 b11171e8 Leszek Koltunski
    setUpAttributes();
471
    setUpUniforms();
472 432442f9 Leszek Koltunski
    }
473
474
///////////////////////////////////////////////////////////////////////////////////////////////////
475 3d804c91 Leszek Koltunski
/**
476
 * Return the handle of the created program so that we can later, say, call glUseProgram.
477
 */
478 432442f9 Leszek Koltunski
  public int getProgramHandle()
479
    {
480
    return mProgramHandle;
481
    }
482
483
///////////////////////////////////////////////////////////////////////////////////////////////////
484 3d804c91 Leszek Koltunski
/**
485 02de77c9 Leszek Koltunski
 * Use the program and enable all vertex attribute arrays.
486
 *
487 3d804c91 Leszek Koltunski
 * Needs to be called from a thread holding the OpenGL context.
488
 */
489 02de77c9 Leszek Koltunski
  public void useProgram()
490 432442f9 Leszek Koltunski
    {
491 b7074bc6 Leszek Koltunski
    GLES30.glUseProgram(mProgramHandle);
492 02de77c9 Leszek Koltunski
493 432442f9 Leszek Koltunski
    for(int i=0; i<mNumAttributes; i++)
494 b11171e8 Leszek Koltunski
      {
495 b7074bc6 Leszek Koltunski
      GLES30.glEnableVertexAttribArray(mAttribute[i]);
496 b11171e8 Leszek Koltunski
      }
497
    }
498
499
///////////////////////////////////////////////////////////////////////////////////////////////////
500
/**
501
 * Disable all vertex attribute arrays.
502
 *
503
 * Needs to be called from a thread holding the OpenGL context.
504
 */
505
  public void stopUsingProgram()
506
    {
507
    GLES30.glUseProgram(0);
508
509
    for(int i=0; i<mNumAttributes; i++)
510
      {
511
      GLES30.glDisableVertexAttribArray(mAttribute[i]);
512
      }
513 432442f9 Leszek Koltunski
    }
514
  }
515 02de77c9 Leszek Koltunski