Project

General

Profile

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

library / src / main / java / org / distorted / library / program / DistortedProgram.java @ d23592bb

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